【 Android 10 系统启动 】系列 -- ShutdownThread(关机流程)
# 前言
由于源码分析的代码量比较大,大部分博客网站的内容显示页面都比较窄,显示出来的效果都异常丑陋,所以您也可以直接查看 《 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);}}}}
当点击 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 {@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(关机流程)相关推荐
- android power 按键,Android Framework层Power键关机流程(一,Power长按键操作处理)
一:Android处理Power按键长按操作 在Framework层中,Android4.x对Power键(KeyEvent.KEYCODE_POWER)的操作,我们从PhoneWindowManag ...
- android power键测试,Android Framework层Power键关机流程(一,Power长按键操作处理)...
一:Android处理Power按键长按操作 在Framework层中,Android4.x对Power键(KeyEvent.KEYCODE_POWER)的操作,我们从PhoneWindowManag ...
- Android Framework层Power键关机流程(二,关机流程)
二,关机流程 从前一篇博文我们知道,当用户长按Power键时会弹出(关机.重启,飞行模式等选项)对话框,我们点击关机,则会弹出关机确认对话框.那么从选项对话框到关机确认对话框又是一个什么流程呢.下面我 ...
- android launcher目录,【 Android 10 系统启动 】系列 -- Launcher(应用门户)
前言 由于源码分析的代码量比较大,大部分博客网站的内容显示页面都比较窄,显示出来的效果都异常丑陋,所以您也可以直接查看 < Thinking in Android > 来阅读这边文章,希望 ...
- Android 10.0 系统启动之SystemServer进程-[Android取经之路]
摘要:上一节讲解了Zygote进程的整个启动流程.Zygote是所有应用的鼻祖.SystemServer和其他所有Dalivik虚拟机进程都是由Zygote fork而来.Zygote fork的第一 ...
- Android 10.0 PackageManagerService(一)工作原理及启动流程-[Android取经之路]
摘要:PackageManagerService是Android系统核心服务之一,在Android中的非常重要,主要负责APK.jar包等的管理. 阅读本文大约需要花费50分钟. 文章的内容主要还是从 ...
- Android 10.0 系统服务之ActivityMnagerService-AMS启动流程-[Android取经之路]
摘要:上一节我们讲完了SystemServer的启动过程,这一节接着上一节的步骤,来讲解ActivityManagerService的启动过程. ActivityManagerService简称AMS ...
- Android 10.0系统启动之init进程-[Android取经之路]
摘要:init进程是linux系统中用户空间的第一个进程,进程号为1.当bootloader启动后,启动kernel,kernel启动完后,在用户空间启动init进程,再通过init进程,来读取ini ...
- Android系统启动系列----init进程
Android系统启动系列 Android系统启动系列----init进程 Android系统启动系列----Zygote进程 引言 在开发app的过程中,是不是会有疑问: java程序的运行不是从m ...
最新文章
- 专访 Christian Posta:Istio 1.7 将成为生产可用的最稳定版本
- LeetCode 101对称二叉树-简单
- 485通讯转换器产品功能特点介绍
- 【ZOJ - 2836 】Number Puzzle (容斥原理)
- CYQ.Data V4.5.5 版本发布[顺带开源Emit编写的快速反射转实体类FastToT类]
- 人工神经网络理论、设计及应用_红层软岩大直径素混凝土置换桩复合地基设计理论及应用研究——以成都 ICON云端项目为例...
- (转)以太坊的 Merkle 树
- 凯文·凯利写给年轻人的99条人生建议(99 Additional Bits of Unsolicited Advice)
- 传时珍医药伟业谱本草科学新篇——访李时珍医药集团董事长林朝辉
- 2016公众号快速涨粉方法汇总—北京高端网站制作
- IPGuard文档加密基本设置步骤
- 1. 大数据实时计算介绍
- 闲置资源组建NAS存储服务器
- vue指令-v-for
- [RabbitMQ]Windows环境下rabbitmqclt(Command Line Tools)出现Erlang distribution failed错误的解决方法...
- 11个超好用的SVG编辑工具
- vbs教程《文件操作》
- Python对json数据的提取
- 使用SAF Spectrum Compact频谱仪MASK MODE功能观察天线交叉极化鉴别率
- 计算机科学世界排名前5的著名错误
热门文章
- Vertical roller mill lead blast furnace slag processing equipment
- netkeeper代理服务器未响应,使用netkeeper创翼网速慢解决方案(C13)
- 你知道各调的特点吗?
- html如何实现统计访客功能,JS 实时网站访客(用户)统计
- Godaddy美国主机推荐
- Arduino白泽四足机器人——matlab逆运动学求解
- 【Tableau 设计提示11 】- 仪表板布局提示
- 开源项目之:SharpDevelop
- Presto Cannot write to non-managed Hive table
- 关于判断力-兼谈IT评论界冥顽不化的愚蠢