赞
踩
android中的重启或者关机操作有很多种情况,包括Power键长按关机/重启、恢复出厂设置重启、低电量关机等等,这些事件经过一系列的判断处理最终都会通过调用PowerManagerService.java类然后调入到ShutdownThread.java类里面,最终都是从这个类的shutdownInner()方法开始的;
shutdownInner()这个方法很长,主要的作用是创建弹出框,根据传入参数confirm来判断是否显示需要用户确认关机或者重启的Dialog,然后调用beginShutdownSequence()方法去开线程执行关机或者重启操作。
- static void shutdownInner(final Context context, boolean confirm) {
- // ensure that only one thread is trying to power down.
- // any additional calls are just returned
- synchronized (sIsStartedGuard) {
- if (sIsStarted) {
- Log.d(TAG, "Request to shutdown already running, returning.");
- return;
- }
- }
-
- boolean showRebootOption = false;
- String[] defaultActions = context.getResources().getStringArray(
- com.android.internal.R.array.config_globalActionsList);
- for (int i = 0; i < defaultActions.length; i++) {
- if (defaultActions[i].equals("reboot")) {
- showRebootOption = true;
- break;
- }
- }
- final int longPressBehavior = context.getResources().getInteger(
- com.android.internal.R.integer.config_longPressOnPowerBehavior);
- int resourceId = mRebootSafeMode
- ? com.android.internal.R.string.reboot_safemode_confirm
- : (longPressBehavior == 2
- ? com.android.internal.R.string.shutdown_confirm_question
- : com.android.internal.R.string.shutdown_confirm);
- if (showRebootOption && !mRebootSafeMode) {
- resourceId = com.android.internal.R.string.reboot_confirm;
- }
-
- Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);
-
- if (confirm) {
- final CloseDialogReceiver closer = new CloseDialogReceiver(context);
- if (sConfirmDialog != null) {
- sConfirmDialog.dismiss();
- }
- sConfirmDialog = new AlertDialog.Builder(context)
- .setTitle(mRebootSafeMode
- ? com.android.internal.R.string.reboot_safemode_title
- : showRebootOption
- ? com.android.internal.R.string.reboot_title
- : com.android.internal.R.string.power_off)
- .setMessage(resourceId)
- .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int which) {
- beginShutdownSequence(context);
- }
- })
- .setNegativeButton(com.android.internal.R.string.no, null)
- .create();
- closer.dialog = sConfirmDialog;
- sConfirmDialog.setOnDismissListener(closer);
- sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
- sConfirmDialog.show();
- } else {
- beginShutdownSequence(context);
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
beginShutdownSequence()方法的篇幅也比较长:
- private static void beginShutdownSequence(Context context) {
- synchronized (sIsStartedGuard) {
- if (sIsStarted) {
- Log.d(TAG, "Shutdown sequence already running, returning.");
- return;
- }
- sIsStarted = true;
- }
-
- // Throw up a system dialog to indicate the device is rebooting / shutting down.
- ProgressDialog pd = new ProgressDialog(context);
-
- // Path 1: Reboot to recovery and install the update
- // Condition: mRebootReason == REBOOT_RECOVERY and mRebootUpdate == True
- // (mRebootUpdate is set by checking if /cache/recovery/uncrypt_file exists.)
- // UI: progress bar
- //
- // Path 2: Reboot to recovery for factory reset
- // Condition: mRebootReason == REBOOT_RECOVERY
- // UI: spinning circle only (no progress bar)
- //
- // Path 3: Regular reboot / shutdown
- // Condition: Otherwise
- // UI: spinning circle only (no progress bar)
- if (PowerManager.REBOOT_RECOVERY.equals(mRebootReason)) {
- mRebootUpdate = new File(UNCRYPT_PACKAGE_FILE).exists();
- if (mRebootUpdate) {
- pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_update_title));
- pd.setMessage(context.getText(
- com.android.internal.R.string.reboot_to_update_prepare));
- pd.setMax(100);
- pd.setProgressNumberFormat(null);
- pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
- pd.setProgress(0);
- pd.setIndeterminate(false);
- } else {
- // Factory reset path. Set the dialog message accordingly.
- pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_reset_title));
- pd.setMessage(context.getText(
- com.android.internal.R.string.reboot_to_reset_message));
- pd.setIndeterminate(true);
- }
- } else {
- pd.setTitle(context.getText(com.android.internal.R.string.power_off));
- pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
- pd.setIndeterminate(true);
- }
- pd.setCancelable(false);
- pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-
- pd.show();
-
- sInstance.mProgressDialog = pd;
- sInstance.mContext = context;
- sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
-
- // make sure we never fall asleep again
- sInstance.mCpuWakeLock = null;
- try {
- sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
- PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");
- sInstance.mCpuWakeLock.setReferenceCounted(false);
- sInstance.mCpuWakeLock.acquire();
- } catch (SecurityException e) {
- Log.w(TAG, "No permission to acquire wake lock", e);
- sInstance.mCpuWakeLock = null;
- }
-
- // also make sure the screen stays on for better user experience
- sInstance.mScreenWakeLock = null;
- if (sInstance.mPowerManager.isScreenOn()) {
- try {
- sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
- PowerManager.FULL_WAKE_LOCK, TAG + "-screen");
- sInstance.mScreenWakeLock.setReferenceCounted(false);
- sInstance.mScreenWakeLock.acquire();
- } catch (SecurityException e) {
- Log.w(TAG, "No permission to acquire wake lock", e);
- sInstance.mScreenWakeLock = null;
- }
- }
-
- // start the thread that initiates shutdown
- sInstance.mHandler = new Handler() {
- };
- sInstance.start();
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
1、显示一个系统进度dialog表示当前设备正在关机/重启;
2、持CPU锁、屏幕锁,保持设备处于唤醒态、屏幕处于亮屏态;
3、最后启动线程,执行run方法,这个线程指的是ShutThread.java,执行的run()方法,也是这个类的run()方法。
run()方法的篇幅更长,不适合贴代码,接下来分块来分析:
- BroadcastReceiver br = new BroadcastReceiver() {
- @Override public void onReceive(Context context, Intent intent) {
- // We don't allow apps to cancel this, so ignore the result.
- actionDone();
- }
- };
- void actionDone() {
- synchronized (mActionDoneSync) {
- mActionDone = true;
- mActionDoneSync.notifyAll();
- }
- }
- // First send the high-level shut down broadcast.
- mActionDone = false;
- Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
- intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- mContext.sendOrderedBroadcastAsUser(intent,
- UserHandle.ALL, null, br, mHandler, 0, null, null);
-
- final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
- synchronized (mActionDoneSync) {
- while (!mActionDone) {
- long delay = endTime - SystemClock.elapsedRealtime();
- if (delay <= 0) {
- Log.w(TAG, "Shutdown broadcast timed out");
- break;
- } else if (mRebootUpdate) {
- int status = (int)((MAX_BROADCAST_TIME - delay) * 1.0 *
- BROADCAST_STOP_PERCENT / MAX_BROADCAST_TIME);
- sInstance.setRebootProgress(status, null);
- }
- try {
- mActionDoneSync.wait(Math.min(delay, PHONE_STATE_POLL_SLEEP_MSEC));
- } catch (InterruptedException e) {
- }
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
1、首先发送有序广播Intent.ACTION_SHUTDOWN;
ActivityManagerService执行shutdown()操作,保存一些相关状态(比如battery).
- final IActivityManager am =
- ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
- if (am != null) {
- try {
- am.shutdown(MAX_BROADCAST_TIME);
- } catch (RemoteException e) {
- }
- }
PackageManagerService执行shutdonw,将当前的package Name写入data/system/package-usage.list文件中;
- final PackageManagerService pm = (PackageManagerService)
- ServiceManager.getService("package");
- if (pm != null) {
- pm.shutdown();
- }
nfc、电话服务相关、蓝牙等无线模块执行Shutdown;
- // Shutdown radios.
- shutdownRadios(MAX_RADIO_WAIT_TIME);
中断线程,等待文件系统挂载服务卸载完成后再继续执行;
- // Shutdown MountService to ensure media is in a safe state
- IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {
- public void onShutDownComplete(int statusCode) throws RemoteException {
- Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");
- actionDone();
- }
- };
-
- Log.i(TAG, "Shutting down MountService");
-
- // Set initial variables and time out time.
- mActionDone = false;
- final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
- synchronized (mActionDoneSync) {
- try {
- final IMountService mount = IMountService.Stub.asInterface(
- ServiceManager.checkService("mount"));
- if (mount != null) {
- mount.shutdown(observer);
- } else {
- Log.w(TAG, "MountService unavailable for shutdown");
- }
- } catch (Exception e) {
- Log.e(TAG, "Exception during MountService shutdown", e);
- }
- while (!mActionDone) {
- long delay = endShutTime - SystemClock.elapsedRealtime();
- if (delay <= 0) {
- Log.w(TAG, "Shutdown wait timed out");
- break;
- } else if (mRebootUpdate) {
- int status = (int)((MAX_SHUTDOWN_WAIT_TIME - delay) * 1.0 *
- (MOUNT_SERVICE_STOP_PERCENT - RADIO_STOP_PERCENT) /
- MAX_SHUTDOWN_WAIT_TIME);
- status += RADIO_STOP_PERCENT;
- sInstance.setRebootProgress(status, null);
- }
- try {
- mActionDoneSync.wait(Math.min(delay, PHONE_STATE_POLL_SLEEP_MSEC));
- } catch (InterruptedException e) {
- }
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
开始重启/关机;
rebootOrShutdown(mContext, mReboot, mRebootReason);
至此ShutdownThread.java类的run()方法分析完成,接下来调用rebootOrShutdown()方法;
- /**
- * Do not call this directly. Use {@link #reboot(Context, String, boolean)}
- * or {@link #shutdown(Context, boolean)} instead.
- *
- * @param context Context used to vibrate or null without vibration
- * @param reboot true to reboot or false to shutdown
- * @param reason reason for reboot
- */
- public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
- if (reboot) {
- Log.i(TAG, "Rebooting, reason: " + reason);
- PowerManagerService.lowLevelReboot(reason);
- Log.e(TAG, "Reboot failed, will attempt shutdown instead");
- } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {
- // vibrate before shutting down
- Vibrator vibrator = new SystemVibrator(context);
- try {
- vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);
- } catch (Exception e) {
- // Failure to vibrate shouldn't interrupt shutdown. Just log it.
- Log.w(TAG, "Failed to vibrate during shutdown.", e);
- }
-
- // vibrator is asynchronous so we need to wait to avoid shutting down too soon.
- try {
- Thread.sleep(SHUTDOWN_VIBRATE_MS);
- } catch (InterruptedException unused) {
- }
- }
-
- // Shutdown power
- Log.i(TAG, "Performing low-level shutdown...");
- PowerManagerService.lowLevelShutdown();
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
判断是否是重启,如果是重启的话则调用:
PowerManagerService.lowLevelReboot(reason);
是关机命令的话,线程会先sleep500ms等待手机震动500ms完成,再执行:
PowerManagerService.lowLevelShutdown();
也就是说最终关机操作还是会回到PowerManagerService.java中:
先来看lowLevelShutdown()方法:
- /**
- * Low-level function turn the device off immediately, without trying
- * to be clean. Most people should use {@link ShutdownThread} for a clean shutdown.
- */
- public static void lowLevelShutdown() {
- SystemProperties.set("sys.powerctl", "shutdown");
- }
使用系统属性服务类SystemProperties传入cmd命令触发shutdown的相关操作,到这里java层的关机流程结束,进入native层;
再来看lowLevelReboot()方法:
- /**
- * Low-level function to reboot the device. On success, this
- * function doesn't return. If more than 20 seconds passes from
- * the time a reboot is requested, this method returns.
- *
- * @param reason code to pass to the kernel (e.g. "recovery"), or null.
- */
- public static void lowLevelReboot(String reason) {
- if (reason == null) {
- reason = "";
- }
- if (reason.equals(PowerManager.REBOOT_RECOVERY)) {
- // If we are rebooting to go into recovery, instead of
- // setting sys.powerctl directly we'll start the
- // pre-recovery service which will do some preparation for
- // recovery and then reboot for us.
- SystemProperties.set("ctl.start", "pre-recovery");
- } else {
- SystemProperties.set("sys.powerctl", "reboot," + reason);
- }
- try {
- Thread.sleep(20 * 1000L);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- Slog.wtf(TAG, "Unexpected return from lowLevelReboot!");
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
首先判断重启原因,根据reason的不同,传入不同的命令参数进入native层,开始重启操作且必须在20s内完成;
reboot & shutdown流程总结:
1、不管是reboot还是shutdown最终都会调入到ShutdownThread.java类里的shutdownInner()方法;
2、ShutdownThread.java继承于Thread.java,这个类的核心方法还是run()方法;
3、在run()方法内,发起有序shutdown广播;执行ActivityManagerService,PackageManagerService,nfc、电话服务相关、蓝牙等无线模块,文件系统挂载服务等的shutdown工作;
4、shutdown操作会导致设备震动500ms;
5、java层的最终实现是在PowerManagerService.java,从这里进入native层;通过系统属性类SystemProperties.java触发shutdown & reboot的相关操作。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。