深入解析Android關(guān)機(jī)
Android 關(guān)機(jī)順序
- 當(dāng)我們長(zhǎng)按電源按鈕時(shí),手機(jī)里究竟發(fā)了什么?
 - 什么又是關(guān)機(jī)順序?
 - Android的關(guān)機(jī)順序與Linux桌面系統(tǒng)有何不同?
 - 如何更改關(guān)機(jī)菜單?
 
當(dāng)我們說(shuō)起Android的關(guān)機(jī)順序時(shí),許多諸如此類的問(wèn)題便會(huì)涌進(jìn)我們的腦袋。 不過(guò),在繼續(xù)閱讀之前,建議您首先能對(duì)開(kāi)機(jī)順序有一個(gè)了解開(kāi)機(jī)順序文章。
Android是基于Linux內(nèi)核的開(kāi)源操作系統(tǒng)。盡管x86(x86 是一系列計(jì)算機(jī)微處理器指令集及其架構(gòu)的統(tǒng)稱,這種架構(gòu)基于Intel 8086 CPU)是大多數(shù)Linux系統(tǒng)所采用的處理器架構(gòu),然而絕大多數(shù)Android系統(tǒng)卻運(yùn)行于ARM架構(gòu)之上(ARM,又稱Advanced RISC Machine,其前身為Acorn RISC Machine),除了來(lái)自Intel的Xolo設(shè)備。這種移動(dòng)設(shè)備使用了Atom 1. 6Ghz x86處理器。 但不論哪種架構(gòu),Android的關(guān)機(jī)順序都區(qū)別于Linux的桌面系統(tǒng),如Ubuntu、Fedora等。 本文主要介紹Android的關(guān)機(jī)順序, 如果想更多地了解Linux桌面系統(tǒng)的關(guān)機(jī)順序,請(qǐng)參考Linux的啟動(dòng)與關(guān)閉流程。
下圖詳細(xì)闡釋了Android的關(guān)機(jī)順序。
第一步: 按住電源按鈕半秒鐘(500ms)。
第二步: 之后,PhoneWindowManager.java 將捕獲長(zhǎng)按電源按鈕這一事件并調(diào)用“interceptKeyBeforeQueueing”方法。
下面是處理長(zhǎng)按電源鍵事件的代碼片段
- /** {@inheritDoc} */
 - @Override
 - public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {
 - ....
 - ....
 - ....
 - case KeyEvent.KEYCODE_POWER: {
 - result &= ~ACTION_PASS_TO_USER;
 - if (down) {
 - if (isScreenOn && !mPowerKeyTriggered
 - && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
 - mPowerKeyTriggered = true;
 - mPowerKeyTime = event.getDownTime();
 - interceptScreenshotChord();
 - }
 - ITelephony telephonyService = getTelephonyService();
 - boolean hungUp = false;
 - if (telephonyService != null) {
 - try {
 - if (telephonyService.isRinging()) {
 - // 如果在來(lái)電響鈴時(shí)按下電源鍵,則系統(tǒng)將關(guān)閉來(lái)電提示
 - telephonyService.silenceRinger();
 - } else if ((mIncallPowerBehavior
 - & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
 - && telephonyService.isOffhook()) {
 - // 如果處在通話中且電源鍵掛斷選項(xiàng)已啟用,則按下電源鍵會(huì)結(jié)束當(dāng)前通話
 - hungUp = telephonyService.endCall();
 - }
 - } catch (RemoteException ex) {
 - Log.w(TAG, "ITelephony threw RemoteException", ex);
 - }
 - }
 - interceptPowerKeyDown(!isScreenOn || hungUp
 - || mVolumeDownKeyTriggered || mVolumeUpKeyTriggered);
 - } else {
 - mPowerKeyTriggered = false;
 - cancelPendingScreenshotChordAction();
 - if (interceptPowerKeyUp(canceled || mPendingPowerKeyUpCanceled)) {
 - result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP;
 - }
 - mPendingPowerKeyUpCanceled = false;
 - }
 - break;
 - }
 - ....
 - ....
 - ....
 - }
 
上面的代碼包含了對(duì)多種情形下對(duì)長(zhǎng)按電源鍵時(shí)間的處理,例如靜默來(lái)電響鈴、屏幕截圖以及關(guān)閉電源等。 系統(tǒng)將根據(jù)電源鍵被按住的時(shí)間長(zhǎng)短以及相關(guān)按鍵的使用情況來(lái)決定如何恰當(dāng)?shù)靥幚懋?dāng)前的用戶操作。 當(dāng)電源鍵被按下且沒(méi)有截屏操作觸發(fā)時(shí)interceptPowerKeyDown 將被調(diào)用,這時(shí)其他的按鍵響應(yīng)(其他按鍵響應(yīng)指 interceptKeyBeforeQueueing 中其他cases)將不會(huì)被觸發(fā)。
下面的代碼展示了 interceptPowerKeyDown 函數(shù)內(nèi)容, 函數(shù)將注冊(cè)一個(gè)回調(diào)函數(shù),在500毫秒超時(shí)事件(ViewConfiguration#getGlobalActionKeyTimeout())觸發(fā)時(shí)啟動(dòng) mPowerLongPress 線程。
- private void interceptPowerKeyDown(boolean handled) {
 - mPowerKeyHandled = handled;
 - if (!handled) {
 - mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
 - }
 - }
 
mPowerLongPress 線程的實(shí)現(xiàn)如下:
- private final Runnable mPowerLongPress = new Runnable() {
 - @Override
 - public void run() {
 - // The context isn't read
 - if (mLongPressOnPowerBehavior < 0) {
 - mLongPressOnPowerBehavior = mContext.getResources().getInteger(
 - com.android.internal.R.integer.config_longPressOnPowerBehavior);
 - }
 - int resolvedBehavior = mLongPressOnPowerBehavior;
 - if (FactoryTest.isLongPressOnPowerOffEnabled()) {
 - resolvedBehavior = LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM;
 - }
 - switch (resolvedBehavior) {
 - case LONG_PRESS_POWER_NOTHING:
 - break;
 - case LONG_PRESS_POWER_GLOBAL_ACTIONS:
 - mPowerKeyHandled = true;
 - if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
 - performAuditoryFeedbackForAccessibilityIfNeed();
 - }
 - sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
 - showGlobalActionsDialog();
 - 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(resolvedBehavior == LONG_PRESS_POWER_SHUT_OFF);
 - break;
 - }
 - }
 - };
 
第三步: 由上面代碼的Switch分支可知,當(dāng)程序進(jìn)去Long_Press_Power_Global_Options時(shí)控制將移交給 GlobalActions 類, 該模塊則負(fù)責(zé)顯示關(guān)機(jī)選項(xiàng)的對(duì)話框,這些選項(xiàng)在各Android發(fā)行版(各OEM廠商定制的Android系統(tǒng), 不同的手機(jī)型號(hào)和不同版本的Android系統(tǒng))中不盡相同,通常包括關(guān)閉電源、飛行模式和屏幕截圖。也可能包括其他一些選項(xiàng)按鍵。GlobalActions 類實(shí)現(xiàn)了一個(gè)showdialog方法,該方法將根據(jù)當(dāng)前系統(tǒng)支持的菜單內(nèi)容來(lái)創(chuàng)建這個(gè)對(duì)話框。
- void showGlobalActionsDialog() {
 - if (mGlobalActions == null) {
 - mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);
 - }
 - final boolean keyguardShowing = keyguardIsShowingTq();
 - mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());
 - if (keyguardShowing) {
 - // 由于激活關(guān)機(jī)對(duì)話框需要長(zhǎng)按電源鍵兩秒以上,所以當(dāng)對(duì)話框顯示之后,屏幕的喚醒狀態(tài)將被鎖定,以方便用戶瀏覽對(duì)話框中內(nèi)容
 - mKeyguardMediator.userActivity();
 - }
 - }
 
第四步: 若用戶選擇“關(guān)閉電源“,則對(duì)系統(tǒng)的控制將交回給 PhoneWindowManager, 然后由PhoneWindowManager 啟動(dòng)關(guān)閉流程。
第五步: 整個(gè)關(guān)機(jī)過(guò)程起始于ShutdownThread模塊中的shutdowninner方法。該方法首先創(chuàng)建一個(gè)確認(rèn)對(duì)話框給用戶, 用戶可以選擇確認(rèn)關(guān)機(jī)或是取消關(guān)機(jī)操作。 如果用戶選擇確認(rèn),則系統(tǒng)將真正進(jìn)入關(guān)機(jī)流程。
第六步: 如上所述,當(dāng)用戶點(diǎn)擊確認(rèn)按鈕后beginShutdownSequence方法將被調(diào)用以啟動(dòng)關(guān)機(jī)順序。
- private static void beginShutdownSequence(Context context) {
 - synchronized (sIsStartedGuard) {
 - if (sIsStarted) {
 - Log.d(TAG, "Shutdown sequence already running, returning.");
 - return;
 - }
 - sIsStarted = true;
 - }
 - // 顯示正在關(guān)閉電源的對(duì)話框
 - ProgressDialog pd = new ProgressDialog(context);
 - 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.mContext = context;
 - sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
 - // 阻止CPU進(jìn)入休眠狀態(tài)
 - 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;
 - }
 - // 電源關(guān)閉前一直保持屏幕喚醒狀態(tài),以便提升用戶體驗(yàn)
 - 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;
 - }
 - }
 - // 啟動(dòng)負(fù)責(zé)關(guān)機(jī)順序的線程
 - sInstance.mHandler = new Handler() {
 - };
 - sInstance.start();
 - }
 
運(yùn)行函數(shù),啟動(dòng)實(shí)際的關(guān)機(jī)流程
- public void run() {
 - BroadcastReceiver br = new BroadcastReceiver() {
 - @Override public void onReceive(Context context, Intent intent) {
 - // We don't allow apps to cancel this, so ignore the result.
 - actionDone();
 - }
 - };
 - /*
 - * 寫(xiě)入一個(gè)系統(tǒng)參數(shù),以防Android系統(tǒng)中的System Server
 - * (一個(gè)運(yùn)行于Dalvik虛擬機(jī)與真實(shí)系統(tǒng)內(nèi)核間的server,負(fù)責(zé)虛擬機(jī)與內(nèi)核的通信)在真實(shí)硬件重啟前完成重啟。
 - * 當(dāng)上述情況發(fā)生時(shí), 則在System Server完成啟動(dòng)后重試之前的重啟操作。
 - */
 - {
 - String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");
 - SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
 - }
 - /*
 - * 寫(xiě)入一個(gè)系統(tǒng)參數(shù)以便重啟后進(jìn)入安全模式
 - */
 - if (mRebootSafeMode) {
 - SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
 - }
 - Log.i(TAG, "Sending shutdown broadcast...");
 - // 關(guān)閉移動(dòng)通信
 - 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);
 - 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;
 - }
 - try {
 - mActionDoneSync.wait(delay);
 - } catch (InterruptedException e) {
 - }
 - }
 - }
 - 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) {
 - }
 - }
 - // 關(guān)閉移動(dòng)通信
 - shutdownRadios(MAX_RADIO_WAIT_TIME);
 - // 安全移除外部存儲(chǔ)卡
 - 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");
 - // 初始化變量,并設(shè)置關(guān)機(jī)超時(shí)時(shí)限
 - mActionDone = false;
 - final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
 - synchronized (mActionDoneSync) {
 - try {
 - final IMountService mount = IMountService.Stub.asInterface(
 - ServiceManager.checkService("mount"));
 - if (mount != null) {
 - mount.shutdown(observer);
 - } else {
 - Log.w(TAG, "MountService unavailable for shutdown");
 - }
 - } catch (Exception e) {
 - Log.e(TAG, "Exception during MountService shutdown", e);
 - }
 - while (!mActionDone) {
 - long delay = endShutTime - SystemClock.elapsedRealtime();
 - if (delay <= 0) {
 - Log.w(TAG, "Shutdown wait timed out");
 - break;
 - }
 - try {
 - mActionDoneSync.wait(delay);
 - } catch (InterruptedException e) {
 - }
 - }
 - }
 - rebootOrShutdown(mReboot, mRebootReason);
 - }
 
第七步: 當(dāng)rebootOrShutdown方法被調(diào)用時(shí),系統(tǒng)控制權(quán)首先轉(zhuǎn)至底層函數(shù) nativeShutdown(在com_android_server_power_PowerManagerService。cpp中定義) 并最終調(diào)用android_reboot函數(shù)(定義于android_reboot.c中)來(lái)完成整個(gè)關(guān)機(jī)順序
- static void nativeShutdown(JNIEnv *env, jclass clazz) {
 - android_reboot(ANDROID_RB_POWEROFF, 0, 0);
 - }
 
原文鏈接: javacodegeeks    翻譯:  ImportNew.com  - 靳禹
譯文鏈接: http://www.importnew.com/6356.html


















 
 
 





 
 
 
 