深入解析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)我們說起Android的關(guān)機(jī)順序時(shí),許多諸如此類的問題便會(huì)涌進(jìn)我們的腦袋。 不過,在繼續(xù)閱讀之前,建議您首先能對(duì)開機(jī)順序有一個(gè)了解開機(jī)順序文章。
Android是基于Linux內(nè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),除了來自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()) {
- // 如果在來電響鈴時(shí)按下電源鍵,則系統(tǒng)將關(guān)閉來電提示
- 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í)間的處理,例如靜默來電響鈴、屏幕截圖以及關(guān)閉電源等。 系統(tǒng)將根據(jù)電源鍵被按住的時(shí)間長(zhǎng)短以及相關(guān)按鍵的使用情況來決定如何恰當(dāng)?shù)靥幚懋?dāng)前的用戶操作。 當(dāng)電源鍵被按下且沒有截屏操作觸發(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)容來創(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ī)過程起始于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();
- }
- };
- /*
- * 寫入一個(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);
- }
- /*
- * 寫入一個(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中)來完成整個(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