前言
由于源码分析的代码量比较大,大部分博客网站的内容显示页面都比较窄,显示出来的效果都异常丑陋,所以您也可以直接查看 《 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.java
public 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.java
public 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() & Ke