Android 通過power鍵關(guān)機重啟的流程(Android層)
一、結(jié)論,android系統(tǒng)的關(guān)機和重啟最終都是通過修改SystemProperties的屬性來完成的。
二、屬性名稱?
關(guān)機:name:sys.powerctl? value:shutdown+reason? reason可以為空;所以完全可以在三方應(yīng)用中通過SystemProperties.set("sys.powerctl", "shutdown,"
+ reason);來進行關(guān)機;同事你也可以通過adb shell setprop
sys.powerctl shutdown來進行關(guān)機。
重啟:name:sys.powerctl? value:reboot+reason? 同樣reason可以為空;如果你需要重啟到recovery,那么value對應(yīng)的為reboot,recovery。
?三、說明:長按的關(guān)機和重啟是在如下幾個xml中進行聲明定義,完了之后在GlobalActions中進行對應(yīng)的處理
frameworks/base/core/res/res/values/config.xm
frameworks/base/core/res/res/values/strings.xml
frameworks/base/core/res/res/values-zh-rCN/strings.xml
frameworks/base/policy/src/com/Android/internal/policy/impl/GlobalActions.Java
代碼比較簡單,不是本文的重點。這就不貼了。
?四、代碼流程分析:
1、首先在GlobalActions中有處理onPress()和onLongPress(),很簡單,對應(yīng)的就是關(guān)機和重啟;
//關(guān)機
????public void onPress() {
???????????// shutdown by making sure radio and power are handled accordingly.
???????????mWindowManagerFuncs.shutdown(false /* confirm */);
???????}
??? }
? //重啟
?? ?public boolean onLongPress() {
?? ????UserManager um = (UserManager)mContext.getSystemService(Context.USER_SERVICE);
???????????if (!um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
???????????????mWindowManagerFuncs.rebootSafeMode(true);
??????????????? return true;
???????????}
???????????return false;
???????}
2、為了方便說明,以關(guān)機流程為例進行說明,重啟的類似。可以看到在代碼中直接調(diào)用mWindowManagerFuncs對應(yīng)的方法。mWindowManagerFuncs是抽象類WindowManagerFuncs的對象,WindowManagerFuncs是WindowManagerPolicy內(nèi)部一個抽象內(nèi)部類,最終是由WindowManagerService來實現(xiàn)的,所以理所當然的接下來代碼會進入到WindowManagerService中的shutdown方法中;
??public void shutdown(boolean confirm) {
???????ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED,confirm);
}
沒什么好說的,代碼關(guān)鍵點就一句,直接進入ShutdownThread
3、進入ShutdownThread的方法中,看具體做了什么處理
???public static void shutdown(final Context context, String reason,boolean confirm) {
//省略如果
//接下來這個是一個注意點,那么就是為什么再跑monkey時手動關(guān)機關(guān)不了。原
//因就在這里,可以看到如果在monkey的時候直接return了。注意,這并不是說你
//無法關(guān)掉設(shè)備,只是無法通過按鍵關(guān),你同樣可以采用文章開頭的方式進行關(guān)機。
???????if (SystemProperties.getBoolean("ro.monkey", false)) {
???????????Log.d(TAG, "Cannot request to shutdown when Monkey is running,returning.");
???????????return;
???????}
?//真正關(guān)機的重點流程在這
???????shutdownInner(context, confirm);
}
4、shutdownInner的內(nèi)部處理
static void shutdownInner(final Contextcontext, boolean confirm) {
??????//省略
? //在這部分代碼中會構(gòu)造處確定是否關(guān)機的dialog,并處理起對應(yīng)的事件,篇幅過長
? ? ? ?//這里就省略了。關(guān)機對應(yīng)的處理在下面這個方法
???????????beginShutdownSequence(context);
}
private static void
beginShutdownSequence(Context context) {
// 省略
// sInstance是shutdownThread的實例,shutdownThread是一個Thread,所以接下來run()
sInstance.start();
}
5、shutdownThread線程的處理
??public void run() {
???????checkShutdownFlow();
???????while (mShutdownFlow == IPO_SHUTDOWN_FLOW) {
???????????mShutdownManager.saveStates(mContext);
???????????mShutdownManager.enterShutdown(mContext);
???????????switchToLauncher();
???????????running();
???????}
???????if (mShutdownFlow != IPO_SHUTDOWN_FLOW) {
???????????mShutdownManager.enterShutdown(mContext);
???????????switchToLauncher();
???????????running();
???????}
}
6、
private void running() {
?????//省略
???????/*
????????* Write a system property in case the system_server reboots before we
????????* get to the actual hardware restart. If that happens, we'll retry at
????????* the beginning of the SystemServer startup.
????????*/
???????{
???????????String reason = (mReboot ? "1" : "0") + (mReason !=null ? mReason : "");
???????????SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
???????}
???????/*
????????* If we are rebooting into safe mode, write a system property
????????* indicating so.
????????*/
???????if (mRebootSafeMode) {
???????????SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
???????}
? //關(guān)機的廣播在這里發(fā)出去的
???????/// M:2012-05-20ALPS00286063 @{
???????mContext.sendBroadcast(new Intent(ACTION_PRE_SHUTDOWN));
???????/// @}2012-05-20
???????Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
???????intent.putExtra("_mode", mShutdownFlow);
???????intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
???????mContext.sendOrderedBroadcastAsUser(intent,
???????????UserHandle.ALL, null, br, mHandler, 0, null, null);
????//關(guān)閉radio,包括藍牙wifi telephony等
? ????????// Shutdown radios.
???????Log.i(TAG, "Shutting down radios...");
???????shutdownRadios(MAX_RADIO_WAIT_TIME);
???????if (mRebootHasProgressBar) {
???????????sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);
???????}
?? //…………
???????????rebootOrShutdown(mContext, mReboot, mReason);
???????}
}
7、在rebootOrShutdown這個方法中直接調(diào)用
PowerManagerService.lowLevelShutdown(reason);
完了之后在lowLevelShutdown中直接通過SystemProperties.set("sys.powerctl", "shutdown,"
+ reason);關(guān)機。
往下之后的處理會進入到kernel進行。后續(xù)在整理。
五、另外,上面說的是按power鍵彈dialog關(guān)機重啟的流程,關(guān)于一直長按power鍵關(guān)機是在PhoneWindowManager中調(diào)用powerLongPress處理的。
?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();
???????????}
???????????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);
//原理一樣,也是調(diào)用?? mWindowManagerFuncs.shutdown方法
???????????break;
???????}
??? }