Android本地升级原理及流程(一,上层)
1.首先,我们了解一下进入进入系统更新的操作步骤;设置-->关于手机-->系统更新
<com.android.settings.XXUpdatePreference android:key="system_update_settings"
android:title="@string/system_update_settings_list_item_title"
android:summary="@string/system_update_settings_list_item_summary">
<intent android:action="android.settings.SYSTEM_UPDATE_SETTINGS" />
</com.android.settings.XXUpdatePreference>
②我们在DeviceInfoSettings.java中对该preference进行监听,当用户触发点击事件时发出广播,XXX应用会接收该广播并启动XXX做出下一步处理。如下所示:
else if (preference.getKey().equals(KEY_DMSW_UPDATE)) {
// /M: for DMSW to broadcast @{
Intent i = new Intent();
i.setAction("com.mediatek.DMSWUPDATE");
getActivity().sendBroadcast(i);
// /@}
}
2.一般来说,由于Android原生态的系统更新体验一般,我们手机中的系统更新应用都是厂商定制的,也就是说我们点击系统更新时一般进入的都是厂商定制的系统更新应用,这里我们先不赘述,随后的博文中会针对原生中的系统更新应用进行一个分析。
case R.id.okButton:
if (!hasSDCard()) {
showToast(R.string.no_sd_card);
return;
}
if (file == null || !file.exists()) {
showToast(R.string.no_update_file);
return;
}
Intent intent = new Intent(SystemUpgradeChooserActivity.this,UpdateToStart.class);
startActivity(intent);
break;
②此时我们通过intent进入到升级提醒界面UpdateToStart.java,这里我们点击确定开始安装更新包,详细代码如下:
buttonOkUp.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
try {
if (!hasSDCard()) {
showToast(R.string.no_sd_card);
return;
}
if (file == null || !file.exists()) {
showToast(R.string.no_update_file);
return;
}
RecoverySystem.installPackage(getApplicationContext(), file);
}
catch (Exception e) {
//
}
}
});
3.上面我们了解了,通过调用RecoverySystem.installPackage()方法尽心安装更新包。具体方法如下:
/***为了安装更新包将会重启设备,此外要调用该方法需要在清单文件中增加REBOOT权限
* 参数 context 上下文
* 参数 packageFile 封装更新包路径等信息的file对象.
*/
public static void installPackage(Context context, File packageFile)
throws IOException {
String filename = packageFile.getCanonicalPath();
Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
"\n--locale=" + Locale.getDefault().toString();
bootCommand(context, arg);
}
4.下面是对bootCommand进行分析。
private static void bootCommand(Context context, String arg) throws IOException {
RECOVERY_DIR.mkdirs(); // 创建/cache/recovery目录
COMMAND_FILE.delete(); // 删除command文件,进行初始化
LOG_FILE.delete();//删除log文件,进行初始化
Log.d(TAG,"Preapre to write command: " + arg +"\n");
WriteByFdSync(COMMAND_FILE,arg);//将参数写入到command文件中
Log.d(TAG,"Success to write command: " + arg +"\n");
Log.d(TAG,"Current build type is: " + Build.TYPE +"\n");
ReadInAndPrint(COMMAND_FILE);//读取command文件,并打印log
// Having written the command file, go ahead and reboot
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);//从系统服务中获得PowerManager实例
pm.reboot("recovery");//重启
Log.d(TAG,"!!! pm.reboot failed !!!\n");
throw new IOException("Reboot failed (no permissions?)");
}
下面的方法调用流程为PowerManager:reboot("recovery")-->PowerManagerService:reboot(reason)
-->PowerManagerService:shtudownOrRebootInternal(false,confirm,reason,wait)
-->PowerManagerService:shutdownOrRebootInternal(...)
-->ShutdownThread:reboot(mContext, reason, confirm);
-->ShutdownThread:run():running()......
@Override // Binder call
public void reboot(boolean confirm, String reason, boolean wait) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
Slog.i(TAG, "reboot call pid: " + Binder.getCallingPid() + " uid: " + Binder.getCallingUid());
final long ident = Binder.clearCallingIdentity();
try {
shutdownOrRebootInternal(false, confirm, reason, wait);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private void shutdownOrRebootInternal(final boolean shutdown, final boolean confirm,
final String reason, boolean wait) {
if (mHandler == null || !mSystemReady) {
throw new IllegalStateException("Too early to call shutdown() or reboot()");
}
Runnable runnable = new Runnable() {
@Override
public void run() {
synchronized (this) {
if (shutdown) {
ShutdownThread.shutdown(mContext, confirm);
} else {
ShutdownThread.reboot(mContext, reason, confirm);
}
}
}
};
// ShutdownThread must run on a looper capable of displaying the UI.
Message msg = Message.obtain(mHandler, runnable);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
// PowerManager.reboot() is documented not to return so just wait for the inevitable.
if (wait) {
synchronized (runnable) {
while (true) {
try {
runnable.wait();
} catch (InterruptedException e) {
}
}
}
}
}
public static void reboot(final Context context, String reason, boolean confirm) {
mReboot = true;
mRebootSafeMode = false;
mRebootReason = reason;
Log.d(TAG, "reboot");
if (mSpew) {
StackTraceElement[] stack = new Throwable().getStackTrace();
for (StackTraceElement element : stack)
{
Log.d(TAG, " |----" + element.toString());
}
}
shutdownInner(context, confirm);
}
这里在run方法下的,running方法中将重启原因写入系统属性文件中去。
。。。。。。
{
String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");
SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
}
。。。。。。
最后,重启设备。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。