【 Android(安卓)10 系统启动 】系列 -- ShutdownThread(关机流程)
16lz
2021-12-04
前言
由于源码分析的代码量比较大,大部分博客网站的内容显示页面都比较窄,显示出来的效果都异常丑陋,所以您也可以直接查看 《 Thinking in Android 》 来阅读这边文章,希望这篇文章能帮你梳理清楚 “Android 关机流程”。
核心源码
关键类 | 路径 |
---|---|
GlobalActions.java | frameworks/base/services/core/java/com/android/server/policy/GlobalActions.java |
LegacyGlobalActions.java | frameworks/base/services/core/java/com/android/server/policy/LegacyGlobalActions.java |
PhoneWindowManager.java | frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java |
PowerManagerService.java | frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java |
ShutdownThread.java | frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java |
WindowManagerService.java | frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java |
一、PhoneWindowManager
Android 系统的关机流程是从用户按 power
键开始的,所有的按键处理都是通过 PhoneWindowManager.interceptKeyBeforeQueueing()
方法进行处理。
2.1 PhoneWindowManager.interceptKeyBeforeQueueing()
// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.javapublic class PhoneWindowManager implements WindowManagerPolicy { @Override public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { ... ... // Handle special keys. switch (keyCode) { ... ... case KeyEvent.KEYCODE_POWER: { EventLogTags.writeInterceptPower( KeyEvent.actionToString(event.getAction()), mPowerKeyHandled ? 1 : 0, mPowerKeyPressCounter); // Any activity on the power button stops the accessibility shortcut cancelPendingAccessibilityShortcutAction(); result &= ~ACTION_PASS_TO_USER; isWakeKey = false; // wake-up will be handled separately if (down) { // down 为 true,代表按下 power 键,走 interceptPowerKeyDown() 方法 interceptPowerKeyDown(event, interactive); } else { interceptPowerKeyUp(event, interactive, canceled); } break; } ... ... }}
2.2 PhoneWindowManager.interceptPowerKeyDown()
// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.javapublic class PhoneWindowManager implements WindowManagerPolicy { private void interceptPowerKeyDown(KeyEvent event, boolean interactive) { ... ... // 截屏功能 if (interactive && !mScreenshotChordPowerKeyTriggered && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { mScreenshotChordPowerKeyTriggered = true; mScreenshotChordPowerKeyTime = event.getDownTime(); interceptScreenshotChord(); interceptRingerToggleChord(); } TelecomManager telecomManager = getTelecommService(); boolean hungUp = false; if (telecomManager != null) { if (telecomManager.isRinging()) { telecomManager.silenceRinger(); // 如果来电时,按 Power 则静音 } else if ((mIncallPowerBehavior & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0 && telecomManager.isInCall() && interactive) { hungUp = telecomManager.endCall(); } } ... ... mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered || mA11yShortcutChordVolumeUpKeyTriggered || gesturedServiceIntercepted; if (!mPowerKeyHandled) { if (interactive) { if (hasLongPressOnPowerBehavior()) { if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) { powerLongPress(); // 长按 Power 键,核心方法 } else { ... ... } } } else { wakeUpFromPowerKey(event.getDownTime()); if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) { if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) { powerLongPress(); // 长按 Power 键,核心方法 } else { ... ... } mBeganFromNonInteractive = true; } else { ... ... } } } }}
2.3 PhoneWindowManager.powerLongPress()
// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.javapublic class PhoneWindowManager implements WindowManagerPolicy { private void powerLongPress() { final int behavior = getResolvedLongPressOnPowerBehavior(); // 得到长按电源键的行为 switch (behavior) { case LONG_PRESS_POWER_NOTHING: break; case LONG_PRESS_POWER_GLOBAL_ACTIONS: // 原生的会走这个 case mPowerKeyHandled = true; performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); showGlobalActionsInternal(); // 调用 showGlobalActionsInternal() 方法 break; ... ... } }}
powerLongPress()
有两个核心方法,getResolvedLongPressOnPowerBehavior()
和 showGlobalActionsInternal()
,我们分别看下。
2.4 PhoneWindowManager.getResolvedLongPressOnPowerBehavior()
// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.javapublic class PhoneWindowManager implements WindowManagerPolicy { int mLongPressOnPowerBehavior; mLongPressOnPowerBehavior = mContext.getResources().getInteger( com.android.internal.R.integer.config_longPressOnPowerBehavior); private int getResolvedLongPressOnPowerBehavior() { if (FactoryTest.isLongPressOnPowerOffEnabled()) { return LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM; } return mLongPressOnPowerBehavior; // 返回 config_longPressOnPowerBehavior 的值 }}
其实就是获取 config_longPressOnPowerBehavior
的值,这个值是什么?
// frameworks/base/core/res/res/values/config.xml1 // 可设置默认值
2.5 PhoneWindowManager.showGlobalActionsInternal()
// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.javapublic class PhoneWindowManager implements WindowManagerPolicy { void showGlobalActionsInternal() { if (mGlobalActions == null) { mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs); } final boolean keyguardShowing = isKeyguardShowingAndNotOccluded(); mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned()); // 弹出关机的对话框 // since it took two seconds of long press to bring this up, // poke the wake lock so they have some time to see the dialog. mPowerManager.userActivity(SystemClock.uptimeMillis(), false); }}
2.6 GlobalActions.showDialog()
// frameworks/base/services/core/java/com/android/server/policy/GlobalActions.javaclass GlobalActions implements GlobalActionsProvider.GlobalActionsListener { private LegacyGlobalActions mLegacyGlobalActions; public void showDialog(boolean keyguardShowing, boolean deviceProvisioned) { if (DEBUG) Slog.d(TAG, "showDialog " + keyguardShowing + " " + deviceProvisioned); if (mGlobalActionsProvider != null && mGlobalActionsProvider.isGlobalActionsDisabled()) { return; } mKeyguardShowing = keyguardShowing; mDeviceProvisioned = deviceProvisioned; mShowing = true; if (mGlobalActionsAvailable) { mHandler.postDelayed(mShowTimeout, 5000); mGlobalActionsProvider.showGlobalActions(); } else { // SysUI isn't alive, show legacy menu. ensureLegacyCreated(); // 调用 LegacyGlobalActions.showDialog() 方法 mLegacyGlobalActions.showDialog(mKeyguardShowing, mDeviceProvisioned); } }}
2.7 LegacyGlobalActions.showDialog()
// frameworks/base/services/core/java/com/android/server/policy/LegacyGlobalActions.javaclass LegacyGlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener { public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) { mKeyguardShowing = keyguardShowing; mDeviceProvisioned = isDeviceProvisioned; if (mDialog != null) { mDialog.dismiss(); mDialog = null; // Show delayed, so that the dismiss of the previous dialog completes mHandler.sendEmptyMessage(MESSAGE_SHOW); } else { handleShow(); // 如果 Dialog 不为空,则创建 } }}
2.8 LegacyGlobalActions.handleShow()
// frameworks/base/services/core/java/com/android/server/policy/LegacyGlobalActions.javaclass LegacyGlobalActions implements DialogInterface.OnDismissListener, DialogInterface.OnClickListener { private void handleShow() { awakenIfNecessary(); mDialog = createDialog(); prepareDialog(); // If we only have 1 item and it's a simple press action, just do this action. if (mAdapter.getCount() == 1 && mAdapter.getItem(0) instanceof SinglePressAction && !(mAdapter.getItem(0) instanceof LongPressAction)) { ((SinglePressAction) mAdapter.getItem(0)).onPress(); // 调用 onPress() 方法 } else { if (mDialog != null) { WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes(); attrs.setTitle("LegacyGlobalActions"); mDialog.getWindow().setAttributes(attrs); mDialog.show(); mDialog.getWindow().getDecorView().setSystemUiVisibility( View.STATUS_BAR_DISABLE_EXPAND); } } }}
当点击 dialog
的 power off
时,会调用 PowerAction
的 onPress()
方法。
2.9 PowerAction.onPress()
// frameworks/base/services/core/java/com/android/server/policy/PowerAction.javapublic final class PowerAction extends SinglePressAction implements LongPressAction { @Override public void onPress() { // shutdown by making sure radio and power are handled accordingly. mWindowManagerFuncs.shutdown(false /* confirm */); // 调用 WindowManagerService.shutdown() 方法 }}
2.10 WindowManagerService.shutdown()
// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.javapublic class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs { // Called by window manager policy. Not exposed externally. @Override public void shutdown(boolean confirm) { // Pass in the UI context, since ShutdownThread requires it (to show UI). // 调用 ShutdownThread.shutdown() 方法 ShutdownThread.shutdown(ActivityThread.currentActivityThread().getSystemUiContext(), PowerManager.SHUTDOWN_USER_REQUESTED, confirm); }}
三、ShutdownThread
Android 关机的流程最终是通过 ShutdownThread
线程实现。
3.1 ShutdownThread.shutdown()
// frameworks/base/services/core/java/com/android/server/power/ShutdownThread.javapublic final class ShutdownThread extends Thread { public static void shutdown(final Context context, String reason, boolean confirm) { mReboot = false; mRebootSafeMode = false; mReason = reason; shutdownInner(context, confirm); // 内部调用 shutdownInner() 方法 }}
3.2 ShutdownThread.shutdownInner()
// frameworks/base/services/core/java/com/android/server/power/ShutdownThread.javapublic final class ShutdownThread extends Thread { private static void shutdownInner(final Context context, boolean confirm) { context.assertRuntimeOverlayThemable(); synchronized (sIsStartedGuard) { if (sIsStarted) { Log.d(TAG, "Request to shutdown already running, returning."); return; } } // 获取用户长按 Power 键的处理行为 final int longPressBehavior = context.getResources().getInteger( com.android.internal.R.integer.config_longPressOnPowerBehavior); final 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); Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior); if (confirm) { // 弹出关机、重启对话框,供用户选择 final CloseDialogReceiver closer = new CloseDialogReceiver(context); // 注册关机对话框广播 if (sConfirmDialog != null) { sConfirmDialog.dismiss(); } // 创建关机 Dialog sConfirmDialog = new AlertDialog.Builder(context) .setTitle(mRebootSafeMode ? com.android.internal.R.string.reboot_safemode_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); // 执行 beginShutdownSequence() 方法,开始关机流程 } }) .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); } }}
3.3 ShutdownThread.beginShutdownSequence()
// frameworks/base/services/core/java/com/android/server/power/ShutdownThread.javapublic final class ShutdownThread extends Thread { // static instance of this thread private static final ShutdownThread sInstance = new ShutdownThread(); // 我们一般可以在这个方法里面添加关机动画 private static void beginShutdownSequence(Context context) { synchronized (sIsStartedGuard) { if (sIsStarted) { Log.d(TAG, "Shutdown sequence already running, returning."); return; } sIsStarted = true; } sInstance.mProgressDialog = showShutdownDialog(context); // 显示关机进度对话框 sInstance.mContext = context; sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); ... ... // // start the thread that initiates shutdown -- 启动关机线程 ,执行 Run 方法 sInstance.mHandler = new Handler() { }; sInstance.start(); }}
3.4 ShutdownThread.run()
启动关机线程,执行 run()
;
// frameworks/base/services/core/java/com/android/server/power/ShutdownThread.javapublic final class ShutdownThread extends Thread { public void run() { ... ... { String reason = (mReboot ? "1" : "0") + (mReason != null ? mReason : ""); SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason); // 保存关机的原因 } if (mRebootSafeMode) { SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1"); } ... ... // First send the high-level shut down broadcast. mActionDone = false; Intent intent = new Intent(Intent.ACTION_SHUTDOWN); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY); // 发送关机广播 mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL, null, br, mHandler, 0, null, null); final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME; ... ... if (mRebootHasProgressBar) { sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null); } shutdownTimingLog.traceEnd(); // SendShutdownBroadcast -- 关机广播所用的时间 ... ... final IActivityManager am = IActivityManager.Stub.asInterface(ServiceManager.checkService("activity")); if (am != null) { try { am.shutdown(MAX_BROADCAST_TIME); // 关闭 ActivityManagerService 服务 } catch (RemoteException e) { } } if (mRebootHasProgressBar) { sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null); } shutdownTimingLog.traceEnd();// ShutdownActivityManager metricEnded(METRIC_AM); Log.i(TAG, "Shutting down package manager..."); shutdownTimingLog.traceBegin("ShutdownPackageManager"); metricStarted(METRIC_PM); final PackageManagerService pm = (PackageManagerService) ServiceManager.getService("package"); if (pm != null) { pm.shutdown(); // 关闭 PackageManagerService 服务 } ... ... // 关闭一系列核心服务 saveMetrics(mReboot, mReason); rebootOrShutdown(mContext, mReboot, mReason); // 执行 rebootOrShutdown() 方法 }}
3.5 ShutdownThread.rebootOrShutdown()
rebootOrShutdown()
方法决定 关机
还是 重启
。
// frameworks/base/services/core/java/com/android/server/power/ShutdownThread.javapublic final class ShutdownThread extends Thread { 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"); reason = null; } 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(reason); }}
更多相关文章
- 浅谈Java中Collections.sort对List排序的两种方法
- Python list sort方法的具体使用
- python list.sort()根据多个关键字排序的方法实现
- Android(安卓)8.1 中Systemui中的常见修改(六)NavigationBar加载流
- Android中如何像 360 一样优雅的杀死后台服务而不启动
- android调用第三方软件打开下载的附件
- 自定义View系列教程07--详解ViewGroup分发Touch事件
- Android(安卓)Menu学习
- android:configChanges属性