自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

深入解析Android關(guān)機(jī)

移動(dòng)開發(fā) Android
最后關(guān)機(jī)一定是在Linux kernel完成,說到底層其實(shí)就是Linux。所有的調(diào)用是為了停掉運(yùn)行Android的虛擬機(jī)Dalvik和Dalvik與Kernel交互用的Server,至于關(guān)機(jī)按鈕怎么用,就是改改系統(tǒng)調(diào)用的事情。

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)按電源鍵事件的代碼片段

  1. /** {@inheritDoc} */ 
  2. @Override 
  3. public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) { 
  4. .... 
  5. .... 
  6. .... 
  7. case KeyEvent.KEYCODE_POWER: { 
  8.      result &= ~ACTION_PASS_TO_USER; 
  9.        if (down) { 
  10.          if (isScreenOn && !mPowerKeyTriggered 
  11.                && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { 
  12.                    mPowerKeyTriggered = true
  13.                    mPowerKeyTime = event.getDownTime(); 
  14.                    interceptScreenshotChord(); 
  15.             } 
  16.                ITelephony telephonyService = getTelephonyService(); 
  17.                 boolean hungUp = false
  18.                if (telephonyService != null) { 
  19.                    try { 
  20.                        if (telephonyService.isRinging()) { 
  21.                            // 如果在來電響鈴時(shí)按下電源鍵,則系統(tǒng)將關(guān)閉來電提示 
  22.                             telephonyService.silenceRinger(); 
  23.                        } else if ((mIncallPowerBehavior 
  24.                                 & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0 
  25.                                && telephonyService.isOffhook()) { 
  26.                             // 如果處在通話中且電源鍵掛斷選項(xiàng)已啟用,則按下電源鍵會(huì)結(jié)束當(dāng)前通話 
  27.                             hungUp = telephonyService.endCall(); 
  28.                        } 
  29.                    } catch (RemoteException ex) { 
  30.                         Log.w(TAG, "ITelephony threw RemoteException", ex); 
  31.                    } 
  32.                } 
  33.                interceptPowerKeyDown(!isScreenOn || hungUp 
  34.                        || mVolumeDownKeyTriggered || mVolumeUpKeyTriggered); 
  35.            } else { 
  36.                mPowerKeyTriggered = false
  37.                cancelPendingScreenshotChordAction(); 
  38.                if (interceptPowerKeyUp(canceled || mPendingPowerKeyUpCanceled)) { 
  39.                    result = (result & ~ACTION_WAKE_UP) | ACTION_GO_TO_SLEEP; 
  40.                } 
  41.                mPendingPowerKeyUpCanceled = false
  42.            } 
  43.           break
  44.       } 
  45. .... 
  46. .... 
  47. .... 

上面的代碼包含了對(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 線程。

  1. private void interceptPowerKeyDown(boolean handled) { 
  2.   mPowerKeyHandled = handled; 
  3.   if (!handled) { 
  4.        mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout()); 
  5.   } 

mPowerLongPress 線程的實(shí)現(xiàn)如下:

  1. private final Runnable mPowerLongPress = new Runnable() { 
  2.         @Override 
  3.         public void run() { 
  4.             // The context isn't read 
  5.             if (mLongPressOnPowerBehavior < 0) { 
  6.                 mLongPressOnPowerBehavior = mContext.getResources().getInteger( 
  7.                         com.android.internal.R.integer.config_longPressOnPowerBehavior); 
  8.             } 
  9.             int resolvedBehavior = mLongPressOnPowerBehavior; 
  10.             if (FactoryTest.isLongPressOnPowerOffEnabled()) { 
  11.                 resolvedBehavior = LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM; 
  12.             } 
  13.   
  14.             switch (resolvedBehavior) { 
  15.             case LONG_PRESS_POWER_NOTHING: 
  16.                 break
  17.             case LONG_PRESS_POWER_GLOBAL_ACTIONS: 
  18.                 mPowerKeyHandled = true
  19.                 if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) { 
  20.                     performAuditoryFeedbackForAccessibilityIfNeed(); 
  21.                 } 
  22.                 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); 
  23.                 showGlobalActionsDialog(); 
  24.                 break
  25.             case LONG_PRESS_POWER_SHUT_OFF: 
  26.             case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM: 
  27.                 mPowerKeyHandled = true
  28.                 performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); 
  29.                 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); 
  30.                 mWindowManagerFuncs.shutdown(resolvedBehavior == LONG_PRESS_POWER_SHUT_OFF); 
  31.                 break
  32.             } 
  33.         } 
  34.     }; 

第三步: 由上面代碼的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ì)話框。

  1. void showGlobalActionsDialog() { 
  2.     if (mGlobalActions == null) { 
  3.         mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs); 
  4.     } 
  5.     final boolean keyguardShowing = keyguardIsShowingTq(); 
  6.     mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned()); 
  7.     if (keyguardShowing) { 
  8.          // 由于激活關(guān)機(jī)對(duì)話框需要長(zhǎng)按電源鍵兩秒以上,所以當(dāng)對(duì)話框顯示之后,屏幕的喚醒狀態(tài)將被鎖定,以方便用戶瀏覽對(duì)話框中內(nèi)容 
  9.         mKeyguardMediator.userActivity(); 
  10.     } 

第四步: 若用戶選擇“關(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ī)順序。

  1. private static void beginShutdownSequence(Context context) { 
  2.         synchronized (sIsStartedGuard) { 
  3.             if (sIsStarted) { 
  4.                 Log.d(TAG, "Shutdown sequence already running, returning."); 
  5.                 return
  6.             } 
  7.             sIsStarted = true
  8.         } 
  9.   
  10.         // 顯示正在關(guān)閉電源的對(duì)話框 
  11.         ProgressDialog pd = new ProgressDialog(context); 
  12.         pd.setTitle(context.getText(com.android.internal.R.string.power_off)); 
  13.         pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress)); 
  14.         pd.setIndeterminate(true); 
  15.         pd.setCancelable(false); 
  16.  
  17. pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); 
  18.         pd.show(); 
  19.         sInstance.mContext = context; 
  20.         sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 
  21.         // 阻止CPU進(jìn)入休眠狀態(tài) 
  22.         sInstance.mCpuWakeLock = null
  23.         try { 
  24.             sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock( 
  25.                     PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu"); 
  26.             sInstance.mCpuWakeLock.setReferenceCounted(false); 
  27.             sInstance.mCpuWakeLock.acquire(); 
  28.         } catch (SecurityException e) { 
  29.             Log.w(TAG, "No permission to acquire wake lock", e); 
  30.             sInstance.mCpuWakeLock = null
  31.         } 
  32.         // 電源關(guān)閉前一直保持屏幕喚醒狀態(tài),以便提升用戶體驗(yàn) 
  33.         sInstance.mScreenWakeLock = null
  34.         if (sInstance.mPowerManager.isScreenOn()) { 
  35.             try { 
  36.                 sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock( 
  37.                         PowerManager.FULL_WAKE_LOCK, TAG + "-screen"); 
  38.                sInstance.mScreenWakeLock.setReferenceCounted(false); 
  39.                 sInstance.mScreenWakeLock.acquire(); 
  40.             } catch (SecurityException e) { 
  41.                 Log.w(TAG, "No permission to acquire wake lock", e); 
  42.                 sInstance.mScreenWakeLock = null
  43.             } 
  44.         } 
  45.         // 啟動(dòng)負(fù)責(zé)關(guān)機(jī)順序的線程 
  46.         sInstance.mHandler = new Handler() { 
  47.         }; 
  48.         sInstance.start(); 
  49.     } 

運(yùn)行函數(shù),啟動(dòng)實(shí)際的關(guān)機(jī)流程

  1. public void run() { 
  2.         BroadcastReceiver br = new BroadcastReceiver() { 
  3.             @Override public void onReceive(Context context, Intent intent) { 
  4.                 // We don't allow apps to cancel this, so ignore the result. 
  5.                 actionDone(); 
  6.             } 
  7.         }; 
  8.   
  9.         /* 
  10.          *  寫入一個(gè)系統(tǒng)參數(shù),以防Android系統(tǒng)中的System Server 
  11.          * (一個(gè)運(yùn)行于Dalvik虛擬機(jī)與真實(shí)系統(tǒng)內(nèi)核間的server,負(fù)責(zé)虛擬機(jī)與內(nèi)核的通信)在真實(shí)硬件重啟前完成重啟。 
  12.          * 當(dāng)上述情況發(fā)生時(shí), 則在System Server完成啟動(dòng)后重試之前的重啟操作。 
  13.          */ 
  14.         { 
  15.             String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : ""); 
  16.             SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason); 
  17.         } 
  18.   
  19.         /* 
  20.          * 寫入一個(gè)系統(tǒng)參數(shù)以便重啟后進(jìn)入安全模式 
  21.          */ 
  22.         if (mRebootSafeMode) { 
  23.             SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1"); 
  24.         } 
  25.   
  26.         Log.i(TAG, "Sending shutdown broadcast..."); 
  27.   
  28.         // 關(guān)閉移動(dòng)通信 
  29.         mActionDone = false
  30.         Intent intent = new Intent(Intent.ACTION_SHUTDOWN); 
  31.         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 
  32.         mContext.sendOrderedBroadcastAsUser(intent, 
  33.                 UserHandle.ALL, null, br, mHandler, 0nullnull); 
  34.   
  35.         final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME; 
  36.         synchronized (mActionDoneSync) { 
  37.             while (!mActionDone) { 
  38.                 long delay = endTime - SystemClock.elapsedRealtime(); 
  39.                 if (delay <= 0) { 
  40.                     Log.w(TAG, "Shutdown broadcast timed out"); 
  41.                     break
  42.                 } 
  43.                 try { 
  44.                     mActionDoneSync.wait(delay); 
  45.                 } catch (InterruptedException e) { 
  46.                 } 
  47.             } 
  48.         } 
  49.   
  50.         Log.i(TAG, "Shutting down activity manager..."); 
  51.   
  52.         final IActivityManager am = 
  53.             ActivityManagerNative.asInterface(ServiceManager.checkService("activity")); 
  54.         if (am != null) { 
  55.             try { 
  56.                 am.shutdown(MAX_BROADCAST_TIME); 
  57.             } catch (RemoteException e) { 
  58.             } 
  59.         } 
  60.   
  61.         // 關(guān)閉移動(dòng)通信 
  62.         shutdownRadios(MAX_RADIO_WAIT_TIME); 
  63.   
  64.         // 安全移除外部存儲(chǔ)卡 
  65.         IMountShutdownObserver observer = new IMountShutdownObserver.Stub() { 
  66.             public void onShutDownComplete(int statusCode) throws RemoteException { 
  67.                 Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown"); 
  68.                 actionDone(); 
  69.             } 
  70.         }; 
  71.   
  72.         Log.i(TAG, "Shutting down MountService"); 
  73.   
  74.         // 初始化變量,并設(shè)置關(guān)機(jī)超時(shí)時(shí)限 
  75.         mActionDone = false
  76.         final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME; 
  77.         synchronized (mActionDoneSync) { 
  78.             try { 
  79.                 final IMountService mount = IMountService.Stub.asInterface( 
  80.                         ServiceManager.checkService("mount")); 
  81.                 if (mount != null) { 
  82.                     mount.shutdown(observer); 
  83.                 } else { 
  84.                     Log.w(TAG, "MountService unavailable for shutdown"); 
  85.                 } 
  86.             } catch (Exception e) { 
  87.                 Log.e(TAG, "Exception during MountService shutdown", e); 
  88.             } 
  89.             while (!mActionDone) { 
  90.                 long delay = endShutTime - SystemClock.elapsedRealtime(); 
  91.                 if (delay <= 0) { 
  92.                     Log.w(TAG, "Shutdown wait timed out"); 
  93.                     break
  94.                 } 
  95.                 try { 
  96.                     mActionDoneSync.wait(delay); 
  97.                 } catch (InterruptedException e) { 
  98.                 } 
  99.             } 
  100.         } 
  101.   
  102.         rebootOrShutdown(mReboot, mRebootReason); 
  103.     } 

第七步: 當(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ī)順序

  1. static void nativeShutdown(JNIEnv *env, jclass clazz) { 
  2.     android_reboot(ANDROID_RB_POWEROFF, 00); 

原文鏈接: javacodegeeks 翻譯: ImportNew.com - 靳禹
譯文鏈接: http://www.importnew.com/6356.html

責(zé)任編輯:閆佳明 來源: importnew
相關(guān)推薦

2014-06-23 10:31:09

Android啟動(dòng)過程

2013-03-26 13:55:45

Android Bro

2014-12-10 10:37:45

Android自定義布局

2016-05-18 17:15:17

互動(dòng)出版網(wǎng)

2010-10-09 11:20:13

2016-10-31 19:41:29

Java垃圾回收

2010-09-17 15:44:21

網(wǎng)絡(luò)協(xié)議

2009-09-02 14:00:34

C#文件處理

2023-12-12 07:16:34

HTML標(biāo)簽開發(fā)

2011-12-01 14:56:30

Java字節(jié)碼

2013-04-01 10:12:39

2009-03-16 15:47:16

Java線程多線程

2011-08-03 09:18:39

RIP路由協(xié)議RIP

2011-04-07 10:35:11

路由

2011-04-07 10:51:57

路由

2012-11-16 10:14:54

Windows 8

2011-04-07 10:35:37

路由

2020-10-07 14:20:41

Tomcat深入解析

2022-02-16 14:29:21

Callable接口IDE

2011-07-14 13:09:13

終端服務(wù)入侵檢測(cè)陷阱技術(shù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)