@guhuizaifeiyang
2017-09-04T09:46:21.000000Z
字数 10737
阅读 3366
开关机流程
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 separatelyif (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 {@Overridepublic 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; //为全局动作, 显示关机dialogstatic 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() {// 关闭系统dialogssendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);if (mGlobalActions == null) {// 创建GlobalActionsmGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);}final boolean keyguardShowing = isKeyguardShowingAndNotOccluded();// 重点看showDialogmGlobalActions.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 completesmHandler.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(); //显示dialogmDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);}}
@Overridepublic void onPress() {// shutdown by making sure radio and power are handled accordingly.mWindowManagerFuncs.shutdown(false /* confirm */); //关机}
由于WindowManagerService实现了接口WindowManagerFuncs, 所以就会调用到WMS中的shutdown函数. 进而调用ShutdownThread中去实现关机功能.
@Overridepublic 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 returnedsynchronized (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); //获取长按资源idfinal 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 againsInstance.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 experiencesInstance.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 shutdownsInstance.mHandler = new Handler() {};// 开始启动ShutdownThreadsInstance.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 managerLog.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 managerLog.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 stateIMountShutdownObserver 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 handlerdeviceRebootOrShutdown(reboot, reason);if (reboot) {// 重启// 如果是重启,就不会走到后面lowLevelShutdownLog.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);}
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
该部分后续再补充