关机流程

一、核心源码

关键类 路径
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

二、关机流程

Android 系统的关机流程是从用户按 power 键开始的,

所有的按键处理都是通过 PhoneWindowManager.interceptKeyBeforeQueueing 方法进行处理。

2.1 interceptKeyBeforeQueueing

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
... ...
// Handle special keys.
switch (keyCode) {
... ...
case KeyEvent.KEYCODE_POWER: {
// 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;
}

return result;
}

2.2 interceptPowerKeyDown

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

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 powerLongPress

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

private void powerLongPress() {
// 得到长按电源键的行为
final int behavior = getResolvedLongPressOnPowerBehavior();
switch (behavior) {
case LONG_PRESS_POWER_NOTHING:
break;
// 原生的会走这个 case
case LONG_PRESS_POWER_GLOBAL_ACTIONS:
mPowerKeyHandled = true;
performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
// 调用 showGlobalActionsInternal 方法
showGlobalActionsInternal();
break;
case LONG_PRESS_POWER_SHUT_OFF:
... ...
}
}

powerLongPress 有两个核心方法,getResolvedLongPressOnPowerBehaviorshowGlobalActionsInternal,我们分别看下。

2.4 getResolvedLongPressOnPowerBehavior

1
2
3
4
5
6
7
8
// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

private int getResolvedLongPressOnPowerBehavior() {
if (FactoryTest.isLongPressOnPowerOffEnabled()) {
return LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM;
}
return mLongPressOnPowerBehavior;
}

最终返回了 mLongPressOnPowerBehavior

1
2
3
4
// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

mLongPressOnPowerBehavior = mContext.getResources().getInteger(
com.android.internal.R.integer.config_longPressOnPowerBehavior);

其实就是获取 config_longPressOnPowerBehavior 的值,这个值是什么?

1
2
3
4
5
6
7
8
9
10
// 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 actions
2 - Power off (with confirmation) // 关机要弹出对话框再次确认
3 - Power off (without confirmation) // 关机不需要弹出对话框
4 - Go to voice assist
-->
<integer name="config_longPressOnPowerBehavior">1</integer> // 可设置默认值

2.5 showGlobalActionsInternal

1
2
3
4
5
6
7
8
9
10
11
12
13
// frameworks/base/services/core/java/com/android/server/policy/PhoneWindowManager.java

void showGlobalActionsInternal() {
if (mGlobalActions == null) {
mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
}
final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();
// 弹出关机的对话框
mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
if (keyguardShowing) {
mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
}
}

2.6 GlobalActions.showDialog

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// frameworks/base/services/core/java/com/android/server/policy/GlobalActions.java

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();
mLegacyGlobalActions.showDialog(mKeyguardShowing, mDeviceProvisioned);
}
}

2.7 LegacyGlobalActions.showDialog

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// frameworks/base/services/core/java/com/android/server/policy/LegacyGlobalActions.java

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 {
// 如果 Dialog 不为空,则创建
handleShow();
}
}

2.8 handleShow

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// frameworks/base/services/core/java/com/android/server/policy/LegacyGlobalActions.java

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)) {
// 调用 onPress 方法
((SinglePressAction) mAdapter.getItem(0)).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 时,会调用 PowerActiononPress 方法。

2.9 onPress

1
2
3
4
5
6
7
// frameworks/base/services/core/java/com/android/server/policy/PowerAction.java

@Override
public void onPress() {
// 调用 WindowManagerService.shutdown 方法
mWindowManagerFuncs.shutdown(false /* confirm */);
}

2.10 shutdown

1
2
3
4
5
6
7
8
9
// frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

// Called by window manager policy. Not exposed externally.
@Override
public void shutdown(boolean confirm) {
// 调用 ShutdownThread.shutdown 方法
ShutdownThread.shutdown(ActivityThread.currentActivityThread().getSystemUiContext(),
PowerManager.SHUTDOWN_USER_REQUESTED, confirm);
}

三、ShutdownThread

Android 关机的流程最终是通过 ShutdownThread 线程实现。

3.1 shutdown

1
2
3
4
5
6
7
8
9
// frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java

public static void shutdown(final Context context, String reason, boolean confirm) {
mReboot = false;
mRebootSafeMode = false;
mReason = reason;
// 内部调用 shutdownInner 方法
shutdownInner(context, confirm);
}

3.2 shutdownInner

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java

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();
}
// 创建关机 Dialg
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 方法,开始一系列的关机流程
beginShutdownSequence(context);
}
})
.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 beginShutdownSequence

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java

// 我们一般可以在这个方法里面添加关机动画
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);
... ...
// 启动 关机线程 ,执行 Run 方法
sInstance.mHandler = new Handler() {
};
sInstance.start();
}

3.4 run

启动关机线程,执行 run();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
// frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java

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");
}

metricStarted(METRIC_SEND_BROADCAST);
shutdownTimingLog.traceBegin("SendShutdownBroadcast");
Log.i(TAG, "Sending shutdown 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;
synchronized (mActionDoneSync) {
while (!mActionDone) {
long delay = endTime - SystemClock.elapsedRealtime();
if (delay <= 0) {
Log.w(TAG, "Shutdown broadcast timed out");
break;
} else if (mRebootHasProgressBar) {
int status = (int)((MAX_BROADCAST_TIME - delay) * 1.0 *
BROADCAST_STOP_PERCENT / MAX_BROADCAST_TIME);
sInstance.setRebootProgress(status, null);
}
try {
mActionDoneSync.wait(Math.min(delay, ACTION_DONE_POLL_WAIT_MS));
} catch (InterruptedException e) {
}
}
}
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null);
}
// 关机广播所用的时间
shutdownTimingLog.traceEnd(); // SendShutdownBroadcast
metricEnded(METRIC_SEND_BROADCAST);

Log.i(TAG, "Shutting down activity manager...");
shutdownTimingLog.traceBegin("ShutdownActivityManager");
metricStarted(METRIC_AM);

final IActivityManager am =
IActivityManager.Stub.asInterface(ServiceManager.checkService("activity"));
if (am != null) {
try {
// 关闭 ActivityManagerService 服务
am.shutdown(MAX_BROADCAST_TIME);
} 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 服务
}
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
}
shutdownTimingLog.traceEnd(); // ShutdownPackageManager
metricEnded(METRIC_PM);

// Shutdown radios.
shutdownTimingLog.traceBegin("ShutdownRadios");
metricStarted(METRIC_RADIOS);
shutdownRadios(MAX_RADIO_WAIT_TIME);
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);
}
shutdownTimingLog.traceEnd(); // ShutdownRadios
metricEnded(METRIC_RADIOS);

if (mRebootHasProgressBar) {
sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);

uncrypt();
}

shutdownTimingLog.traceEnd(); // SystemServerShutdown
metricEnded(METRIC_SYSTEM_SERVER);
saveMetrics(mReboot, mReason);
// 执行 rebootOrShutdown 方法
rebootOrShutdown(mContext, mReboot, mReason);
}

3.5 rebootOrShutdown

rebootOrShutdown 方法决定 关机 还是 重启

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java

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) {
// 关机之前震动
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);
}

自此,”关机流程”源码分析完毕。