[关闭]
@guhuizaifeiyang 2017-09-04T09:46:21.000000Z 字数 10737 阅读 3059

Android7.0 关机流程分析

开关机流程


Android7.0关机流程分析
android L 关机流程图

关机流程的时序图

PhoneWindowManager

当长按电源键时,按键消息被分发到PhoneWindowManager的interceptKeyBeforeQueueing函数中处理:

Step 1. interceptKeyBeforeDispatching

PhoneWindowManager.java->interceptKeyBeforeDispatching

  1. public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
  2. case KeyEvent.KEYCODE_POWER: {
  3. result &= ~ACTION_PASS_TO_USER;
  4. isWakeKey = false; // wake-up will be handled separately
  5. if (down) {
  6. interceptPowerKeyDown(event, interactive);
  7. } else {
  8. interceptPowerKeyUp(event, interactive, canceled);
  9. }
  10. break;
  11. }
  12. }

Step 2. interceptPowerKeyDown

PhoneWindowManager.java->interceptPowerKeyDown

  1. private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
  2. //..........
  3. // When interactive, we're already awake.
  4. // Wait for a long press or for the button to be released to decide what to do.
  5. if (hasLongPressOnPowerBehavior()) {
  6. // 如果存在长按事件,就发送MSG_POWER_LONG_PRESS。
  7. Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
  8. msg.setAsynchronous(true);
  9. mHandler.sendMessageDelayed(msg, ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
  10. }
  11. //........
  12. }

Step 3. powerLongPress

MSG_POWER_LONG_PRESS消息最终在PolicyHandler中被处理:
PhoneWindowManager$PolicyHandler->handleMessage

  1. private class PolicyHandler extends Handler {
  2. @Override
  3. public void handleMessage(Message msg) {
  4. // ......
  5. case MSG_POWER_LONG_PRESS:
  6. powerLongPress(); //处理长按事件
  7. break;
  8. // ......
  9. }
  10. }
  11. }

PhoneWindowManager.java->powerLongPress

  1. static final int LONG_PRESS_POWER_NOTHING = 0; //长按power键什么都不做
  2. static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1; //为全局动作, 显示关机dialog
  3. static final int LONG_PRESS_POWER_SHUT_OFF = 2; //只有关机一个选项
  4. static final int LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM = 3; //直接关机不用确认
  5. private void powerLongPress() {
  6. final int behavior = getResolvedLongPressOnPowerBehavior();
  7. switch (behavior) {
  8. case LONG_PRESS_POWER_NOTHING:
  9. break;
  10. case LONG_PRESS_POWER_GLOBAL_ACTIONS:
  11. mPowerKeyHandled = true;
  12. if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
  13. performAuditoryFeedbackForAccessibilityIfNeed();
  14. }
  15. // 我们直接看显示Dialog这一条分支
  16. showGlobalActionsInternal();
  17. break;
  18. case LONG_PRESS_POWER_SHUT_OFF:
  19. case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
  20. mPowerKeyHandled = true;
  21. performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
  22. sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
  23. mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF);
  24. break;
  25. }
  26. }

Step 4. showGlobalActionsInternal

PhoneWindowManager.java->showGlobalActionsInternal

  1. void showGlobalActionsInternal() {
  2. // 关闭系统dialogs
  3. sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
  4. if (mGlobalActions == null) {
  5. // 创建GlobalActions
  6. mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
  7. }
  8. final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();
  9. // 重点看showDialog
  10. mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
  11. if (keyguardShowing) {
  12. // since it took two seconds of long press to bring this up,
  13. // poke the wake lock so they have some time to see the dialog.
  14. mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
  15. }
  16. }

GlobalActions

Step 5. showDialog

  1. /**
  2. * Show the global actions dialog (creating if necessary)
  3. * @param keyguardShowing True if keyguard is showing
  4. */
  5. public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {
  6. mKeyguardShowing = keyguardShowing;
  7. mDeviceProvisioned = isDeviceProvisioned;
  8. if (mDialog != null) {
  9. mDialog.dismiss();
  10. mDialog = null;
  11. // Show delayed, so that the dismiss of the previous dialog completes
  12. mHandler.sendEmptyMessage(MESSAGE_SHOW);
  13. } else {
  14. handleShow();
  15. }
  16. // 最后都会调用handleShow()
  17. }

Step 6. handleShow

  1. private void handleShow() {
  2. awakenIfNecessary();
  3. mDialog = createDialog(); //创建mDialog对象
  4. prepareDialog(); //准备dialog
  5. // If we only have 1 item and it's a simple press action, just do this action.
  6. if (mAdapter.getCount() == 1
  7. && mAdapter.getItem(0) instanceof SinglePressAction
  8. && !(mAdapter.getItem(0) instanceof LongPressAction)) {
  9. ((SinglePressAction) mAdapter.getItem(0)).onPress(); //调用onPress函数
  10. } else {
  11. WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
  12. attrs.setTitle("GlobalActions");
  13. mDialog.getWindow().setAttributes(attrs);
  14. mDialog.show(); //显示dialog
  15. mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
  16. }
  17. }

PowerAction

Step 7. onPress

  1. @Override
  2. public void onPress() {
  3. // shutdown by making sure radio and power are handled accordingly.
  4. mWindowManagerFuncs.shutdown(false /* confirm */); //关机
  5. }

WindowManagerService

Step 8. shutdown

由于WindowManagerService实现了接口WindowManagerFuncs, 所以就会调用到WMS中的shutdown函数. 进而调用ShutdownThread中去实现关机功能.

  1. @Override
  2. public void shutdown(boolean confirm) {
  3. ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm);
  4. }

关机过程的主要实现在ShutdownThread.java中

ShutdownThread

Step 9. shutdown

  1. public static void shutdown(final Context context, String reason, boolean confirm) {
  2. mReboot = false;
  3. mRebootSafeMode = false; //不是重启
  4. mReason = reason; //记录关机的原因
  5. shutdownInner(context, confirm);
  6. }
  7. static void shutdownInner(final Context context, boolean confirm) {
  8. // ensure that only one thread is trying to power down.
  9. // any additional calls are just returned
  10. synchronized (sIsStartedGuard) { //保证只有一个关机线程
  11. if (sIsStarted) {
  12. Log.d(TAG, "Request to shutdown already running, returning.");
  13. return;
  14. }
  15. }
  16. final int longPressBehavior = context.getResources().getInteger(
  17. com.android.internal.R.integer.config_longPressOnPowerBehavior); //获取长按资源id
  18. final int resourceId = mRebootSafeMode
  19. ? com.android.internal.R.string.reboot_safemode_confirm
  20. : (longPressBehavior == 2 //关机确认信息
  21. ? com.android.internal.R.string.shutdown_confirm_question
  22. : com.android.internal.R.string.shutdown_confirm);
  23. Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);
  24. if (confirm) {
  25. final CloseDialogReceiver closer = new CloseDialogReceiver(context);
  26. if (sConfirmDialog != null) {
  27. sConfirmDialog.dismiss();
  28. }
  29. sConfirmDialog = new AlertDialog.Builder(context)//需要再次确认关机, 创建dialog
  30. .setTitle(mRebootSafeMode
  31. ? com.android.internal.R.string.reboot_safemode_title
  32. : com.android.internal.R.string.power_off)
  33. .setMessage(resourceId)
  34. .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
  35. public void onClick(DialogInterface dialog, int which) {
  36. beginShutdownSequence(context); //确认关机
  37. }
  38. })
  39. .setNegativeButton(com.android.internal.R.string.no, null) //不关机了
  40. .create();
  41. closer.dialog = sConfirmDialog;
  42. sConfirmDialog.setOnDismissListener(closer);
  43. sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
  44. sConfirmDialog.show();
  45. } else {
  46. beginShutdownSequence(context); //如果不需要确认就直接关机
  47. }
  48. }

Step 10. beginShutdownSequence

  1. private static void beginShutdownSequence(Context context) {
  2. // ...
  3. if (PowerManager.REBOOT_RECOVERY_UPDATE.equals(mReason)) {
  4. // ...
  5. } else if (PowerManager.REBOOT_RECOVERY.equals(mReason)) {
  6. // ...
  7. } else {
  8. pd.setTitle(context.getText(com.android.internal.R.string.power_off));
  9. pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
  10. pd.setIndeterminate(true);
  11. }
  12. pd.setCancelable(false);
  13. pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
  14. pd.show();
  15. sInstance.mProgressDialog = pd;
  16. sInstance.mContext = context;
  17. sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
  18. // make sure we never fall asleep again
  19. sInstance.mCpuWakeLock = null;
  20. try {
  21. sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
  22. PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");
  23. sInstance.mCpuWakeLock.setReferenceCounted(false);
  24. sInstance.mCpuWakeLock.acquire();
  25. } catch (SecurityException e) {
  26. Log.w(TAG, "No permission to acquire wake lock", e);
  27. sInstance.mCpuWakeLock = null;
  28. }
  29. // also make sure the screen stays on for better user experience
  30. sInstance.mScreenWakeLock = null;
  31. if (sInstance.mPowerManager.isScreenOn()) {
  32. try {
  33. sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
  34. PowerManager.FULL_WAKE_LOCK, TAG + "-screen");
  35. sInstance.mScreenWakeLock.setReferenceCounted(false);
  36. sInstance.mScreenWakeLock.acquire();
  37. } catch (SecurityException e) {
  38. Log.w(TAG, "No permission to acquire wake lock", e);
  39. sInstance.mScreenWakeLock = null;
  40. }
  41. }
  42. // start the thread that initiates shutdown
  43. sInstance.mHandler = new Handler() {
  44. };
  45. // 开始启动ShutdownThread
  46. sInstance.start();
  47. }

Step 11. run

  1. public void run() {
  2. // ...
  3. // First send the high-level shut down broadcast.
  4. // (1) 启动PowerOffHandlerActivity,显示关机动画。
  5. mActionDone = false;
  6. Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
  7. intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
  8. mContext.sendOrderedBroadcastAsUser(intent,
  9. UserHandle.ALL, null, br, mHandler, 0, null, null);
  10. // (2) 关闭activity manager
  11. Log.i(TAG, "Shutting down activity manager...");
  12. final IActivityManager am =
  13. ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
  14. if (am != null) {
  15. try {
  16. am.shutdown(MAX_BROADCAST_TIME);
  17. } catch (RemoteException e) {
  18. }
  19. }
  20. // ...
  21. // (3) 关闭package manager
  22. Log.i(TAG, "Shutting down package manager...");
  23. final PackageManagerService pm = (PackageManagerService)
  24. ServiceManager.getService("package");
  25. if (pm != null) {
  26. pm.shutdown();
  27. }
  28. if (mRebootHasProgressBar) {
  29. sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
  30. }
  31. // (4) 关闭radios.
  32. shutdownRadios(MAX_RADIO_WAIT_TIME);
  33. if (mRebootHasProgressBar) {
  34. sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);
  35. }
  36. // (5) 关闭MountService
  37. // Shutdown MountService to ensure media is in a safe state
  38. IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {
  39. public void onShutDownComplete(int statusCode) throws RemoteException {
  40. Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");
  41. actionDone();
  42. }
  43. };
  44. Log.i(TAG, "Shutting down MountService");
  45. // ...
  46. // (6) 处理关机闹钟和加密
  47. // If it is alarm boot and encryption status, power off alarm status will
  48. // be set to handled when device go to shutdown or reboot.
  49. boolean isAlarmBoot = SystemProperties.getBoolean("ro.alarm_boot", false);
  50. String cryptState = SystemProperties.get("vold.decrypt");
  51. if (isAlarmBoot &&
  52. ("trigger_restart_min_framework".equals(cryptState) ||
  53. "1".equals(cryptState))) {
  54. AlarmManager.writePowerOffAlarmFile(AlarmManager.POWER_OFF_ALARM_HANDLE_FILE,
  55. AlarmManager.POWER_OFF_ALARM_HANDLED);
  56. }
  57. // ...
  58. // (7) 重启或关机
  59. rebootOrShutdown(mContext, mReboot, mReason);
  60. }

这个步骤处理的任务主要是:
1. 发送关机广播Intent.ACTION_SHUTDOWN
2. 关闭activity manager
3. 关闭package manager
4. 关闭radios
5. 关闭MountService
6. 处理关机闹钟

Step 12. rebootOrShutdown

  1. public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
  2. // Call oem shutdown handler
  3. deviceRebootOrShutdown(reboot, reason);
  4. if (reboot) {
  5. // 重启
  6. // 如果是重启,就不会走到后面lowLevelShutdown
  7. Log.i(TAG, "Rebooting, reason: " + reason);
  8. PowerManagerService.lowLevelReboot(reason);
  9. Log.e(TAG, "Reboot failed, will attempt shutdown instead");
  10. reason = null;
  11. } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {
  12. // 关机
  13. // vibrate before shutting down
  14. Vibrator vibrator = new SystemVibrator(context);
  15. try {
  16. vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);
  17. } catch (Exception e) {
  18. // Failure to vibrate shouldn't interrupt shutdown. Just log it.
  19. Log.w(TAG, "Failed to vibrate during shutdown.", e);
  20. }
  21. // vibrator is asynchronous so we need to wait to avoid shutting down too soon.
  22. try {
  23. Thread.sleep(SHUTDOWN_VIBRATE_MS);
  24. } catch (InterruptedException unused) {
  25. }
  26. }
  27. // 关闭电源
  28. // Shutdown power
  29. Log.i(TAG, "Performing low-level shutdown...");
  30. PowerManagerService.lowLevelShutdown(reason);
  31. }

Step 13. lowLevelShutdown

  1. public static void lowLevelShutdown(String reason) {
  2. if (reason == null) {
  3. reason = "";
  4. }
  5. SystemProperties.set("sys.powerctl", "shutdown," + reason);
  6. }

正是这个动作触发关机流程往下走,执行Builtins.c的do_powerctl函数,最终通过bionic的reboot.cpp,调用kernel中kernel_power_off进行关机。
// TODO
该部分后续再补充

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注