共计 13916 个字符,预计需要花费 35 分钟才能阅读完成。
前言
因为源码剖析的代码量比拟大,大部分博客网站的内容显示页面都比拟窄,显示进去的成果都异样俊俏,所以您也能够间接查看《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() & 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.java
public 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.java
public 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 actions
2 - 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.java
public 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.java
class 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.java
class 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.java
class 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.java
public 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.java
public 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.java
public 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.java
public 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.java
public 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.java
public 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.java
public 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);
}
}
正文完