@guhuizaifeiyang
2017-09-04T17:46:21.000000Z
字数 10737
阅读 3177
开关机流程
Android7.0关机流程分析
android L 关机流程图
当长按电源键时,按键消息被分发到PhoneWindowManager的interceptKeyBeforeQueueing函数中处理:
PhoneWindowManager.java->interceptKeyBeforeDispatching
public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) {
case KeyEvent.KEYCODE_POWER: {
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down) {
interceptPowerKeyDown(event, interactive);
} else {
interceptPowerKeyUp(event, interactive, canceled);
}
break;
}
}
PhoneWindowManager.java->interceptPowerKeyDown
private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
//..........
// When interactive, we're already awake.
// Wait for a long press or for the button to be released to decide what to do.
if (hasLongPressOnPowerBehavior()) {
// 如果存在长按事件,就发送MSG_POWER_LONG_PRESS。
Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg, ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());
}
//........
}
MSG_POWER_LONG_PRESS消息最终在PolicyHandler中被处理:
PhoneWindowManager$PolicyHandler->handleMessage
private class PolicyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
// ......
case MSG_POWER_LONG_PRESS:
powerLongPress(); //处理长按事件
break;
// ......
}
}
}
PhoneWindowManager.java->powerLongPress
static final int LONG_PRESS_POWER_NOTHING = 0; //长按power键什么都不做
static final int LONG_PRESS_POWER_GLOBAL_ACTIONS = 1; //为全局动作, 显示关机dialog
static final int LONG_PRESS_POWER_SHUT_OFF = 2; //只有关机一个选项
static final int LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM = 3; //直接关机不用确认
private void powerLongPress() {
final int behavior = getResolvedLongPressOnPowerBehavior();
switch (behavior) {
case LONG_PRESS_POWER_NOTHING:
break;
case LONG_PRESS_POWER_GLOBAL_ACTIONS:
mPowerKeyHandled = true;
if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
performAuditoryFeedbackForAccessibilityIfNeed();
}
// 我们直接看显示Dialog这一条分支
showGlobalActionsInternal();
break;
case LONG_PRESS_POWER_SHUT_OFF:
case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:
mPowerKeyHandled = true;
performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF);
break;
}
}
PhoneWindowManager.java->showGlobalActionsInternal
void showGlobalActionsInternal() {
// 关闭系统dialogs
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
if (mGlobalActions == null) {
// 创建GlobalActions
mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
}
final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();
// 重点看showDialog
mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
if (keyguardShowing) {
// 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);
}
}
/**
* Show the global actions dialog (creating if necessary)
* @param keyguardShowing True if keyguard is showing
*/
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();
}
// 最后都会调用handleShow()
}
private void handleShow() {
awakenIfNecessary();
mDialog = createDialog(); //创建mDialog对象
prepareDialog(); //准备dialog
// 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 {
WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();
attrs.setTitle("GlobalActions");
mDialog.getWindow().setAttributes(attrs);
mDialog.show(); //显示dialog
mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);
}
}
@Override
public void onPress() {
// shutdown by making sure radio and power are handled accordingly.
mWindowManagerFuncs.shutdown(false /* confirm */); //关机
}
由于WindowManagerService实现了接口WindowManagerFuncs, 所以就会调用到WMS中的shutdown函数. 进而调用ShutdownThread中去实现关机功能.
@Override
public void shutdown(boolean confirm) {
ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm);
}
关机过程的主要实现在ShutdownThread.java中
public static void shutdown(final Context context, String reason, boolean confirm) {
mReboot = false;
mRebootSafeMode = false; //不是重启
mReason = reason; //记录关机的原因
shutdownInner(context, confirm);
}
static void shutdownInner(final Context context, boolean confirm) {
// ensure that only one thread is trying to power down.
// any additional calls are just returned
synchronized (sIsStartedGuard) { //保证只有一个关机线程
if (sIsStarted) {
Log.d(TAG, "Request to shutdown already running, returning.");
return;
}
}
final int longPressBehavior = context.getResources().getInteger(
com.android.internal.R.integer.config_longPressOnPowerBehavior); //获取长按资源id
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();
}
sConfirmDialog = new AlertDialog.Builder(context)//需要再次确认关机, 创建dialog
.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); //确认关机
}
})
.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); //如果不需要确认就直接关机
}
}
private static void beginShutdownSequence(Context context) {
// ...
if (PowerManager.REBOOT_RECOVERY_UPDATE.equals(mReason)) {
// ...
} else if (PowerManager.REBOOT_RECOVERY.equals(mReason)) {
// ...
} else {
pd.setTitle(context.getText(com.android.internal.R.string.power_off));
pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
pd.setIndeterminate(true);
}
pd.setCancelable(false);
pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
pd.show();
sInstance.mProgressDialog = pd;
sInstance.mContext = context;
sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
// make sure we never fall asleep again
sInstance.mCpuWakeLock = null;
try {
sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");
sInstance.mCpuWakeLock.setReferenceCounted(false);
sInstance.mCpuWakeLock.acquire();
} catch (SecurityException e) {
Log.w(TAG, "No permission to acquire wake lock", e);
sInstance.mCpuWakeLock = null;
}
// also make sure the screen stays on for better user experience
sInstance.mScreenWakeLock = null;
if (sInstance.mPowerManager.isScreenOn()) {
try {
sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
PowerManager.FULL_WAKE_LOCK, TAG + "-screen");
sInstance.mScreenWakeLock.setReferenceCounted(false);
sInstance.mScreenWakeLock.acquire();
} catch (SecurityException e) {
Log.w(TAG, "No permission to acquire wake lock", e);
sInstance.mScreenWakeLock = null;
}
}
// start the thread that initiates shutdown
sInstance.mHandler = new Handler() {
};
// 开始启动ShutdownThread
sInstance.start();
}
public void run() {
// ...
// First send the high-level shut down broadcast.
// (1) 启动PowerOffHandlerActivity,显示关机动画。
mActionDone = false;
Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mContext.sendOrderedBroadcastAsUser(intent,
UserHandle.ALL, null, br, mHandler, 0, null, null);
// (2) 关闭activity manager
Log.i(TAG, "Shutting down activity manager...");
final IActivityManager am =
ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
if (am != null) {
try {
am.shutdown(MAX_BROADCAST_TIME);
} catch (RemoteException e) {
}
}
// ...
// (3) 关闭package manager
Log.i(TAG, "Shutting down package manager...");
final PackageManagerService pm = (PackageManagerService)
ServiceManager.getService("package");
if (pm != null) {
pm.shutdown();
}
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
}
// (4) 关闭radios.
shutdownRadios(MAX_RADIO_WAIT_TIME);
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);
}
// (5) 关闭MountService
// Shutdown MountService to ensure media is in a safe state
IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {
public void onShutDownComplete(int statusCode) throws RemoteException {
Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");
actionDone();
}
};
Log.i(TAG, "Shutting down MountService");
// ...
// (6) 处理关机闹钟和加密
// If it is alarm boot and encryption status, power off alarm status will
// be set to handled when device go to shutdown or reboot.
boolean isAlarmBoot = SystemProperties.getBoolean("ro.alarm_boot", false);
String cryptState = SystemProperties.get("vold.decrypt");
if (isAlarmBoot &&
("trigger_restart_min_framework".equals(cryptState) ||
"1".equals(cryptState))) {
AlarmManager.writePowerOffAlarmFile(AlarmManager.POWER_OFF_ALARM_HANDLE_FILE,
AlarmManager.POWER_OFF_ALARM_HANDLED);
}
// ...
// (7) 重启或关机
rebootOrShutdown(mContext, mReboot, mReason);
}
这个步骤处理的任务主要是:
1. 发送关机广播Intent.ACTION_SHUTDOWN
2. 关闭activity manager
3. 关闭package manager
4. 关闭radios
5. 关闭MountService
6. 处理关机闹钟
public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
// Call oem shutdown handler
deviceRebootOrShutdown(reboot, reason);
if (reboot) {
// 重启
// 如果是重启,就不会走到后面lowLevelShutdown
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);
}
public static void lowLevelShutdown(String reason) {
if (reason == null) {
reason = "";
}
SystemProperties.set("sys.powerctl", "shutdown," + reason);
}
正是这个动作触发关机流程往下走,执行Builtins.c的do_powerctl函数,最终通过bionic的reboot.cpp,调用kernel中kernel_power_off进行关机。
// TODO
该部分后续再补充