# 前言

由于源码分析的代码量比较大,大部分博客网站的内容显示页面都比较窄,显示出来的效果都异常丑陋,所以您也可以直接查看 《 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 {@Overridepublic 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 shortcutcancelPendingAccessibilityShortcutAction();result &= ~ACTION_PASS_TO_USER;isWakeKey = false; // wake-up will be handled separatelyif (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:    // 原生的会走这个 casemPowerKeyHandled = 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.xml<!-- Control the behavior when the user long presses the power button.0 - Nothing                             // 表示直接关机1 - Global actions menu                 // 关机要显示 Global actions2 - Power off (with confirmation)       // 关机要弹出对话框再次确认3 - Power off (without confirmation)    // 关机不需要弹出对话框4 - Go to voice assist
-->
<integer name="config_longPressOnPowerBehavior">1</integer>    // 可设置默认值

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 completesmHandler.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);}}}}

当点击 dialogpower off 时,会调用 PowerActiononPress() 方法。

2.9 PowerAction.onPress()

// frameworks/base/services/core/java/com/android/server/policy/PowerAction.javapublic final class PowerAction extends SinglePressAction implements LongPressAction {@Overridepublic 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.Stubimplements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {// Called by window manager policy.  Not exposed externally.@Overridepublic 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();}// 创建关机 DialogsConfirmDialog = 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 threadprivate 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();// ShutdownActivityManagermetricEnded(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 downVibrator 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 powerLog.i(TAG, "Performing low-level shutdown...");PowerManagerService.lowLevelShutdown(reason);}}

【 Android 10 系统启动 】系列 -- ShutdownThread(关机流程)相关推荐

  1. android power 按键,Android Framework层Power键关机流程(一,Power长按键操作处理)

    一:Android处理Power按键长按操作 在Framework层中,Android4.x对Power键(KeyEvent.KEYCODE_POWER)的操作,我们从PhoneWindowManag ...

  2. android power键测试,Android Framework层Power键关机流程(一,Power长按键操作处理)...

    一:Android处理Power按键长按操作 在Framework层中,Android4.x对Power键(KeyEvent.KEYCODE_POWER)的操作,我们从PhoneWindowManag ...

  3. Android Framework层Power键关机流程(二,关机流程)

    二,关机流程 从前一篇博文我们知道,当用户长按Power键时会弹出(关机.重启,飞行模式等选项)对话框,我们点击关机,则会弹出关机确认对话框.那么从选项对话框到关机确认对话框又是一个什么流程呢.下面我 ...

  4. android launcher目录,【 Android 10 系统启动 】系列 -- Launcher(应用门户)

    前言 由于源码分析的代码量比较大,大部分博客网站的内容显示页面都比较窄,显示出来的效果都异常丑陋,所以您也可以直接查看 < Thinking in Android > 来阅读这边文章,希望 ...

  5. Android 10.0 系统启动之SystemServer进程-[Android取经之路]

    摘要:上一节讲解了Zygote进程的整个启动流程.Zygote是所有应用的鼻祖.SystemServer和其他所有Dalivik虚拟机进程都是由Zygote fork而来.Zygote fork的第一 ...

  6. Android 10.0 PackageManagerService(一)工作原理及启动流程-[Android取经之路]

    摘要:PackageManagerService是Android系统核心服务之一,在Android中的非常重要,主要负责APK.jar包等的管理. 阅读本文大约需要花费50分钟. 文章的内容主要还是从 ...

  7. Android 10.0 系统服务之ActivityMnagerService-AMS启动流程-[Android取经之路]

    摘要:上一节我们讲完了SystemServer的启动过程,这一节接着上一节的步骤,来讲解ActivityManagerService的启动过程. ActivityManagerService简称AMS ...

  8. Android 10.0系统启动之init进程-[Android取经之路]

    摘要:init进程是linux系统中用户空间的第一个进程,进程号为1.当bootloader启动后,启动kernel,kernel启动完后,在用户空间启动init进程,再通过init进程,来读取ini ...

  9. Android系统启动系列----init进程

    Android系统启动系列 Android系统启动系列----init进程 Android系统启动系列----Zygote进程 引言 在开发app的过程中,是不是会有疑问: java程序的运行不是从m ...

最新文章

  1. 专访 Christian Posta:Istio 1.7 将成为生产可用的最稳定版本
  2. LeetCode 101对称二叉树-简单
  3. 485通讯转换器产品功能特点介绍
  4. 【ZOJ - 2836 】Number Puzzle (容斥原理)
  5. CYQ.Data V4.5.5 版本发布[顺带开源Emit编写的快速反射转实体类FastToT类]
  6. 人工神经网络理论、设计及应用_红层软岩大直径素混凝土置换桩复合地基设计理论及应用研究——以成都 ICON云端项目为例...
  7. (转)以太坊的 Merkle 树
  8. 凯文·凯利写给年轻人的99条人生建议(99 Additional Bits of Unsolicited Advice)
  9. 传时珍医药伟业谱本草科学新篇——访李时珍医药集团董事长林朝辉
  10. 2016公众号快速涨粉方法汇总—北京高端网站制作
  11. IPGuard文档加密基本设置步骤
  12. 1. 大数据实时计算介绍
  13. 闲置资源组建NAS存储服务器
  14. vue指令-v-for
  15. [RabbitMQ]Windows环境下rabbitmqclt(Command Line Tools)出现Erlang distribution failed错误的解决方法...
  16. 11个超好用的SVG编辑工具
  17. vbs教程《文件操作》
  18. Python对json数据的提取
  19. 使用SAF Spectrum Compact频谱仪MASK MODE功能观察天线交叉极化鉴别率
  20. 计算机科学世界排名前5的著名错误

热门文章

  1. Vertical roller mill lead blast furnace slag processing equipment
  2. netkeeper代理服务器未响应,使用netkeeper创翼网速慢解决方案(C13)
  3. 你知道各调的特点吗?
  4. html如何实现统计访客功能,JS 实时网站访客(用户)统计
  5. Godaddy美国主机推荐
  6. Arduino白泽四足机器人——matlab逆运动学求解
  7. 【Tableau 设计提示11 】- 仪表板布局提示
  8. 开源项目之:SharpDevelop
  9. Presto Cannot write to non-managed Hive table
  10. 关于判断力-兼谈IT评论界冥顽不化的愚蠢