Android关机流程(framework layer)

来源:互联网 发布:linux socket网络编程 编辑:程序博客网 时间:2024/06/06 02:12

一. 长按power key对应的handler代码:

frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java

[cpp] view plain copy
  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. };  

run()函数中通过从mLongPressOnPowerBehavior向resolvedBehavior传入值,从而基于resolvedBehavior决定关机动作。下面是对代码的分析:

1. mLongPressOnPowerBehavior初始值为-1,所以会通过getInteger()从config_longPressOnPowerBehavior配置选项中得到mLongPressOnPowerBehavior。

[cpp] view plain copy
  1. int mLongPressOnPowerBehavior = -1;  

2. 检查是否是FactoryTest模式enable了长按powerkey进行关机的选项,是则LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM。

3. switch(resolvedBehavior)来决定关机动作:

  • LONG_PRESS_POWER_NOTHING = 0,Do nothing;
  • LONG_PRESS_POWER_GLOBAL_ACTIONS = 1,这是正常关机所走的流程。首先mPowerKeyHandled = ture,然后sendCloseSystemWindows()发送显示关闭系统的对话框的请求,reason是SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS,
    [cpp] view plain copy
    1. void sendCloseSystemWindows(String reason) {  
    2.     sendCloseSystemWindows(mContext, reason);  
    3. }  
    4.   
    5. static void sendCloseSystemWindows(Context context, String reason) {  
    6.     if (ActivityManagerNative.isSystemReady()) {  
    7.         try {  
    8.             ActivityManagerNative.getDefault().closeSystemDialogs(reason);  
    9.         } catch (RemoteException e) {  
    10.         }  
    11.     }  
    12. }  
    最后,showGlobalActionsDialog()会显示请求的对话框;
  • LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM = 3,直接调用mWindowManagerFuncs.shutdown()进行关机,shutdown()原型:
    [cpp] view plain copy
    1. public void shutdown(boolean confirm);  

二、显示power off对话框:showGlobalActionsDialog()

showGlobalActionsDialog()的定义:

[cpp] view plain copy
  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.         // since it took two seconds of long press to bring this up,  
  9.         // poke the wake lock so they have some time to see the dialog.  
  10.         mKeyguardMediator.userActivity();  
  11.     }  
  12. }  

下面是对代码的分析:

1. 这里首先new GlobalActions,注意一下GlobalActions()的后一个参数是mWindowManagerFuncs;

2. 然后会调用mGlobalActions.showDialog()来显示对话框;


3. 最后根据keyguardShowing的值,也就是是否在锁屏状态,决定是否需要userActivity。一般不会有这种情况。

显示对话框的具体调用是mGlobalActions.showDialog(),它在frameworks/base/policy/src/com/android/internal/policy/impl/GlobalActions.java中。

[cpp] view plain copy
  1. /** 
  2.  * Show the global actions dialog (creating if necessary) 
  3.  * @param keyguardShowing True if keyguard is showing 
  4.  */  
  5. public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {  
  6.     mKeyguardShowing = keyguardShowing;  
  7.     mDeviceProvisioned = isDeviceProvisioned;  
  8.     if (mDialog != null) {  
  9.         mDialog.dismiss();  
  10.         mDialog = null;  
  11.         // Show delayed, so that the dismiss of the previous dialog completes  
  12.         mHandler.sendEmptyMessage(MESSAGE_SHOW);  
  13.     } else {  
  14.         handleShow();  
  15.     }  
  16. }  
再进入mGlobalActions.handleShow()中,handleShow()中调用了createDialog(),showDialog()、handleShow()和createDialog()都是GlobalActions类的私有函数。
[cpp] view plain copy
  1. private void handleShow() {  
  2.     awakenIfNecessary();  
  3.     mDialog = createDialog();  
  4.     prepareDialog();  
  5.   
  6.     WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes();  
  7.     attrs.setTitle("GlobalActions");  
  8.     mDialog.getWindow().setAttributes(attrs);  
  9.     mDialog.show();  
  10.     mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);  
  11. }  
createDialog()是最后要显示的对话框的内容,这个函数虽然很长,但是耐心分析很快就能知道它都做了什么。
[cpp] view plain copy
  1. /** 
  2.  * Create the global actions dialog. 
  3.  * @return A new dialog. 
  4.  */  
  5. private GlobalActionsDialog createDialog() {  
  6.     // Simple toggle style if there's no vibrator, otherwise use a tri-state  
  7.     if (!mHasVibrator) {  
  8.         mSilentModeAction = new SilentModeToggleAction();  
  9.     } else {  
  10.         mSilentModeAction = new SilentModeTriStateAction(mContext, mAudioManager, mHandler);  
  11.     }  
  12.     mAirplaneModeOn = new ToggleAction(  
  13.             R.drawable.ic_lock_airplane_mode,  
  14.             R.drawable.ic_lock_airplane_mode_off,  
  15.             R.string.global_actions_toggle_airplane_mode,  
  16.             R.string.global_actions_airplane_mode_on_status,  
  17.             R.string.global_actions_airplane_mode_off_status) {  
  18.   
  19.         void onToggle(boolean on) {  
  20.             if (mHasTelephony && Boolean.parseBoolean(  
  21.                     SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {  
  22.                 mIsWaitingForEcmExit = true;  
  23.                 // Launch ECM exit dialog  
  24.                 Intent ecmDialogIntent =  
  25.                         new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);  
  26.                 ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
  27.                 mContext.startActivity(ecmDialogIntent);  
  28.             } else {  
  29.                 changeAirplaneModeSystemSetting(on);  
  30.             }  
  31.         }  
  32.   
  33.         @Override  
  34.         protected void changeStateFromPress(boolean buttonOn) {  
  35.             if (!mHasTelephony) return;  
  36.   
  37.             // In ECM mode airplane state cannot be changed  
  38.             if (!(Boolean.parseBoolean(  
  39.                     SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) {  
  40.                 mState = buttonOn ? State.TurningOn : State.TurningOff;  
  41.                 mAirplaneState = mState;  
  42.             }  
  43.         }  
  44.   
  45.         public boolean showDuringKeyguard() {  
  46.             return true;  
  47.         }  
  48.   
  49.         public boolean showBeforeProvisioning() {  
  50.             return false;  
  51.         }  
  52.     };  
  53.     onAirplaneModeChanged();  
  54.   
  55.     mItems = new ArrayList<Action>();  
  56.   
  57.     // first: power off  
  58.     mItems.add(  
  59.         new SinglePressAction(  
  60.                 com.android.internal.R.drawable.ic_lock_power_off,  
  61.                 R.string.global_action_power_off) {  
  62.   
  63.             public void onPress() {  
  64.                 // shutdown by making sure radio and power are handled accordingly.  
  65.                 mWindowManagerFuncs.shutdown(true);  
  66.             }  
  67.   
  68.             public boolean onLongPress() {  
  69.                 mWindowManagerFuncs.rebootSafeMode(true);  
  70.                 return true;  
  71.             }  
  72.   
  73.             public boolean showDuringKeyguard() {  
  74.                 return true;  
  75.             }  
  76.   
  77.             public boolean showBeforeProvisioning() {  
  78.                 return true;  
  79.             }  
  80.         });  
  81.   
  82.     // next: airplane mode  
  83.     mItems.add(mAirplaneModeOn);  
  84.   
  85.     // next: bug report, if enabled  
  86.     if (Settings.Global.getInt(mContext.getContentResolver(),  
  87.             Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0) {  
  88.         mItems.add(  
  89.             new SinglePressAction(com.android.internal.R.drawable.stat_sys_adb,  
  90.                     R.string.global_action_bug_report) {  
  91.   
  92.                 public void onPress() {  
  93.                     AlertDialog.Builder builder = new AlertDialog.Builder(mContext);  
  94.                     builder.setTitle(com.android.internal.R.string.bugreport_title);  
  95.                     builder.setMessage(com.android.internal.R.string.bugreport_message);  
  96.                     builder.setNegativeButton(com.android.internal.R.string.cancel, null);  
  97.                     builder.setPositiveButton(com.android.internal.R.string.report,  
  98.                             new DialogInterface.OnClickListener() {  
  99.                                 @Override  
  100.                                 public void onClick(DialogInterface dialog, int which) {  
  101.                                     // Add a little delay before executing, to give the  
  102.                                     // dialog a chance to go away before it takes a  
  103.                                     // screenshot.  
  104.                                     mHandler.postDelayed(new Runnable() {  
  105.                                         @Override public void run() {  
  106.                                             try {  
  107.                                                 ActivityManagerNative.getDefault()  
  108.                                                         .requestBugReport();  
  109.                                             } catch (RemoteException e) {  
  110.                                             }  
  111.                                         }  
  112.                                     }, 500);  
  113.                                 }  
  114.                             });  
  115.                     AlertDialog dialog = builder.create();  
  116.                     dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);  
  117.                     dialog.show();  
  118.                 }  
  119.   
  120.                 public boolean onLongPress() {  
  121.                     return false;  
  122.                 }  
  123.   
  124.                 public boolean showDuringKeyguard() {  
  125.                     return true;  
  126.                 }  
  127.   
  128.                 public boolean showBeforeProvisioning() {  
  129.                     return false;  
  130.                 }  
  131.             });  
  132.     }  
  133.   
  134.     // last: silent mode  
  135.     if (mShowSilentToggle) {  
  136.         mItems.add(mSilentModeAction);  
  137.     }  
  138.   
  139.     // one more thing: optionally add a list of users to switch to  
  140.     if (SystemProperties.getBoolean("fw.power_user_switcher"false)) {  
  141.         addUsersToMenu(mItems);  
  142.     }  
  143.   
  144.     mAdapter = new MyAdapter();  
  145.   
  146.     AlertParams params = new AlertParams(mContext);  
  147.     params.mAdapter = mAdapter;  
  148.     params.mOnClickListener = this;  
  149.     params.mForceInverseBackground = true;  
  150.   
  151.     GlobalActionsDialog dialog = new GlobalActionsDialog(mContext, params);  
  152.     dialog.setCanceledOnTouchOutside(false); // Handled by the custom class.  
  153.   
  154.     dialog.getListView().setItemsCanFocus(true);  
  155.     dialog.getListView().setLongClickable(true);  
  156.     dialog.getListView().setOnItemLongClickListener(  
  157.             new AdapterView.OnItemLongClickListener() {  
  158.                 @Override  
  159.                 public boolean onItemLongClick(AdapterView<?> parent, View view, int position,  
  160.                         long id) {  
  161.                     return mAdapter.getItem(position).onLongPress();  
  162.                 }  
  163.     });  
  164.     dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);  
  165.   
  166.     dialog.setOnDismissListener(this);  
  167.   
  168.     return dialog;  
  169. }  

  • 前面函数中为稍后的各类选项做了准备工作;
  • first: power off,这里主要定义了两种动作,短按(onPress)和长按(onLongPress),对应的两种结果就是shutdown()和rebootSafeMode();                                                                                                                                      
  • next: airplane mode
  • next: bug report, if enabled 
  • last: silent mode 

因为本文主要分析关机流程,所以对后面几个选项就不分析了。回到handleShow()中,然后调用mDialog类中的函数做显示窗口的动作。

三、执行ShutdownThread.shutdown(),启动关机线程执行关机动作。

前面在GlobalActions.createDialog()中,当进入power off,然后onPress()的时候,mWindowManagerFuncs.shutdown(ture)将被调用。

[cpp] view plain copy
  1. public void onPress() {  
  2.     // shutdown by making sure radio and power are handled accordingly.  
  3.     mWindowManagerFuncs.shutdown(true);  
  4. }  
看一下mWindowManagerFuncs的定义,可以看到它是一个WindowManagerFuncs接口类。

[cpp] view plain copy
  1. private final WindowManagerFuncs mWindowManagerFuncs;  
WindowManagerFuncs类是在/frameworks/base/core/java/android/view/WindowManagerPolicy.java中定义,它被包含在WindowManagerPolicy接口类中。

在WindowManagerFuncs类中,shutdown(boolean confirm)只给出了原型,并没有具体实现。搜索一下很容易发现真正被调用执行的是在/frameworks/base/services/java/com/android/server/wm/WindowManagerService.java中定义的shutdown(),即WindowManagerService.shutdown()。

[cpp] view plain copy
  1. // Called by window manager policy.  Not exposed externally.  
  2. @Override  
  3. public void shutdown(boolean confirm) {  
  4.     ShutdownThread.shutdown(mContext, confirm);  
  5. }  
  6.   
  7. // Called by window manager policy.  Not exposed externally.  
  8. @Override  
  9. public void rebootSafeMode(boolean confirm) {  
  10.     ShutdownThread.rebootSafeMode(mContext, confirm);  
  11. }  
shutdown()和rebootSafeMode()都在这里定义并会被window manager policy调用。这里已经指明真正执行关机线程的是ShutdownThread.shutdown(mContext, confirm)。

下面来看一下具体的关机流程:

ShutdownThread类在frameworks/base/services/java/com/android/server/power/ShutdownThread.java中定义,下面是shutdown()的代码。

[cpp] view plain copy
  1. /** 
  2.  * Request a clean shutdown, waiting for subsystems to clean up their 
  3.  * state etc.  Must be called from a Looper thread in which its UI 
  4.  * is shown. 
  5.  * 
  6.  * @param context Context used to display the shutdown progress dialog. 
  7.  * @param confirm true if user confirmation is needed before shutting down. 
  8.  */  
  9. public static void shutdown(final Context context, boolean confirm) {  
  10.     mReboot = false;  
  11.     mRebootSafeMode = false;  
  12.     shutdownInner(context, confirm);  
  13. }  
  14.   
  15. static void shutdownInner(final Context context, boolean confirm) {  
  16.     // ensure that only one thread is trying to power down.  
  17.     // any additional calls are just returned  
  18.     synchronized (sIsStartedGuard) {  
  19.         if (sIsStarted) {  
  20.             Log.d(TAG, "Request to shutdown already running, returning.");  
  21.             return;  
  22.         }  
  23.     }  
  24.   
  25.     final int longPressBehavior = context.getResources().getInteger(  
  26.                     com.android.internal.R.integer.config_longPressOnPowerBehavior);  
  27.     final int resourceId = mRebootSafeMode  
  28.             ? com.android.internal.R.string.reboot_safemode_confirm  
  29.             : (longPressBehavior == 2  
  30.                     ? com.android.internal.R.string.shutdown_confirm_question  
  31.                     : com.android.internal.R.string.shutdown_confirm);  
  32.   
  33.     Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);  
  34.   
  35.     if (confirm) {  
  36.         final CloseDialogReceiver closer = new CloseDialogReceiver(context);  
  37.         if (sConfirmDialog != null) {  
  38.             sConfirmDialog.dismiss();  
  39.         }  
  40.         sConfirmDialog = new AlertDialog.Builder(context)  
  41.                 .setTitle(mRebootSafeMode  
  42.                         ? com.android.internal.R.string.reboot_safemode_title  
  43.                         : com.android.internal.R.string.power_off)  
  44.                 .setMessage(resourceId)  
  45.                 .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {  
  46.                     public void onClick(DialogInterface dialog, int which) {  
  47.                         beginShutdownSequence(context);  
  48.                     }  
  49.                 })  
  50.                 .setNegativeButton(com.android.internal.R.string.no, null)  
  51.                 .create();  
  52.         closer.dialog = sConfirmDialog;  
  53.         sConfirmDialog.setOnDismissListener(closer);  
  54.         sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);  
  55.         sConfirmDialog.show();  
  56.     } else {  
  57.         beginShutdownSequence(context);  
  58.     }  
  59. }  
1. 注意两个参数:context 和 confirm,context用来用来显示关机进程的对话,confirm确保是true如果关机之前需要确认。这一点很容易理解。

2. 在shutdown()将会调用shutdownInner(),longPressBehavior和resourceId是用来记录一些标志。

一般情况下confirm为true,即表示确认shutdown,然后系统会显示确认shutdown的对话框,同时执行beginShutdownSequence(),启动shutdown线程。如果不需要confirm就可以shutdown,则直接执行beginShutdownSequence(),启动shutdown线程。

3. 下面看一下beginShutdownSequence()的具体流程。

[cpp] view plain copy
  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.     // throw up an indeterminate system dialog to indicate radio is  
  11.     // shutting down.  
  12.     ProgressDialog pd = new ProgressDialog(context);  
  13.     pd.setTitle(context.getText(com.android.internal.R.string.power_off));  
  14.     pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));  
  15.     pd.setIndeterminate(true);  
  16.     pd.setCancelable(false);  
  17.     pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);  
  18.   
  19.     pd.show();  
  20.   
  21.     sInstance.mContext = context;  
  22.     sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);  
  23.   
  24.     // make sure we never fall asleep again  
  25.     sInstance.mCpuWakeLock = null;  
  26.     try {  
  27.         sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(  
  28.                 PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");  
  29.         sInstance.mCpuWakeLock.setReferenceCounted(false);  
  30.         sInstance.mCpuWakeLock.acquire();  
  31.     } catch (SecurityException e) {  
  32.         Log.w(TAG, "No permission to acquire wake lock", e);  
  33.         sInstance.mCpuWakeLock = null;  
  34.     }  
  35.   
  36.     // also make sure the screen stays on for better user experience  
  37.     sInstance.mScreenWakeLock = null;  
  38.     if (sInstance.mPowerManager.isScreenOn()) {  
  39.         try {  
  40.             sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(  
  41.                     PowerManager.FULL_WAKE_LOCK, TAG + "-screen");  
  42.             sInstance.mScreenWakeLock.setReferenceCounted(false);  
  43.             sInstance.mScreenWakeLock.acquire();  
  44.         } catch (SecurityException e) {  
  45.             Log.w(TAG, "No permission to acquire wake lock", e);  
  46.             sInstance.mScreenWakeLock = null;  
  47.         }  
  48.     }  
  49.   
  50.     // start the thread that initiates shutdown  
  51.     sInstance.mHandler = new Handler() {  
  52.     };  
  53.     sInstance.start();  
  54. }  

  • 参数context非常重要,它继续用来显示关机进程的对话框;还要注意一点,sInstance是ShutdownThread静态类实例,也是this thread的实例,接下来还会用到很多它的函数。
    [cpp] view plain copy
    1. // static instance of this thread  
    2. private static final ShutdownThread sInstance = new ShutdownThread();  

  • ProgressDialog pd用来启动一个不明确的系统对话框来表明radio正在关闭,在Google原生系统中可以看到这样的对话框。pd的成员函数setTitle()、setMessage()、setIndeterminate()、setCancelable()会根据context内容对对话框属性进行设置,show()会显示对话框。
  • 确保系统不会再进入睡眠。通过sInstance.mCpuWakeLock来获得wakelock,使系统不会睡眠。
  • 保证screen不会马上黑下去,这样可以保证更好的用户体验。通过sInstance.mScreenWakeLock获得screen wakelock使屏幕长亮。
  • 最后启动shutdown线程sInstance.start()。

四、framework层最后的一步:ShutdownThread.run()

当进程执行到sInstance.start()后,就进入了framework层最后的一步:ShutdownThread.run()。

[cpp] view plain copy
  1. /** 
  2.  * Makes sure we handle the shutdown gracefully. 
  3.  * Shuts off power regardless of radio and bluetooth state if the alloted time has passed. 
  4.  */  
  5. public void run() {  
  6.     BroadcastReceiver br = new BroadcastReceiver() {  
  7.         @Override public void onReceive(Context context, Intent intent) {  
  8.             // We don't allow apps to cancel this, so ignore the result.  
  9.             actionDone();  
  10.         }  
  11.     };  
  12.   
  13.     /* 
  14.      * Write a system property in case the system_server reboots before we 
  15.      * get to the actual hardware restart. If that happens, we'll retry at 
  16.      * the beginning of the SystemServer startup. 
  17.      */  
  18.     {  
  19.         String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");  
  20.         SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);  
  21.     }  
  22.   
  23.     /* 
  24.      * If we are rebooting into safe mode, write a system property 
  25.      * indicating so. 
  26.      */  
  27.     if (mRebootSafeMode) {  
  28.         SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");  
  29.     }  
  30.   
  31.     Log.i(TAG, "Sending shutdown broadcast...");  
  32.       
  33.     // First send the high-level shut down broadcast.  
  34.     mActionDone = false;  
  35.     mContext.sendOrderedBroadcastAsUser(new Intent(Intent.ACTION_SHUTDOWN),  
  36.             UserHandle.ALL, null, br, mHandler, 0, null, null);  
  37.       
  38.     final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;  
  39.     synchronized (mActionDoneSync) {  
  40.         while (!mActionDone) {  
  41.             long delay = endTime - SystemClock.elapsedRealtime();  
  42.             if (delay <= 0) {  
  43.                 Log.w(TAG, "Shutdown broadcast timed out");  
  44.                 break;  
  45.             }  
  46.             try {  
  47.                 mActionDoneSync.wait(delay);  
  48.             } catch (InterruptedException e) {  
  49.             }  
  50.         }  
  51.     }  
  52.       
  53.     Log.i(TAG, "Shutting down activity manager...");  
  54.       
  55.     final IActivityManager am =  
  56.         ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));  
  57.     if (am != null) {  
  58.         try {  
  59.             am.shutdown(MAX_BROADCAST_TIME);  
  60.         } catch (RemoteException e) {  
  61.         }  
  62.     }  
  63.   
  64.     // Shutdown radios.  
  65.     shutdownRadios(MAX_RADIO_WAIT_TIME);  
  66.   
  67.     // Shutdown MountService to ensure media is in a safe state  
  68.     IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {  
  69.         public void onShutDownComplete(int statusCode) throws RemoteException {  
  70.             Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");  
  71.             actionDone();  
  72.         }  
  73.     };  
  74.   
  75.     Log.i(TAG, "Shutting down MountService");  
  76.   
  77.     // Set initial variables and time out time.  
  78.     mActionDone = false;  
  79.     final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;  
  80.     synchronized (mActionDoneSync) {  
  81.         try {  
  82.             final IMountService mount = IMountService.Stub.asInterface(  
  83.                     ServiceManager.checkService("mount"));  
  84.             if (mount != null) {  
  85.                 mount.shutdown(observer);  
  86.             } else {  
  87.                 Log.w(TAG, "MountService unavailable for shutdown");  
  88.             }  
  89.         } catch (Exception e) {  
  90.             Log.e(TAG, "Exception during MountService shutdown", e);  
  91.         }  
  92.         while (!mActionDone) {  
  93.             long delay = endShutTime - SystemClock.elapsedRealtime();  
  94.             if (delay <= 0) {  
  95.                 Log.w(TAG, "Shutdown wait timed out");  
  96.                 break;  
  97.             }  
  98.             try {  
  99.                 mActionDoneSync.wait(delay);  
  100.             } catch (InterruptedException e) {  
  101.             }  
  102.         }  
  103.     }  
  104.   
  105.     rebootOrShutdown(mReboot, mRebootReason);  
  106. }  
run()函数虽然长,但是还是比较好理解的。

1. 如果分配的时间已经过去,不管radio和bluetooth状态如何都关闭。

2. 如果是rebootSafeMode,会设置一些系统属性。

3. 接下来是shutdown的流程,首先向APP层发送shutdown的广播。注意synchronized。

4. shutdown radios,调用shutdownRadios(),它也是ShutdownThread的成员函数。

5. shutdown mountservice,这样可以保证media的安全。

6. 设置初始化参数和时间。

7. rebootOrShutdown(),最后执行的shutdown流程的函数。

[cpp] view plain copy
  1.     /** 
  2.      * Do not call this directly. Use {@link #reboot(Context, String, boolean)} 
  3.      * or {@link #shutdown(Context, boolean)} instead. 
  4.      * 
  5.      * @param reboot true to reboot or false to shutdown 
  6.      * @param reason reason for reboot 
  7.      */  
  8.     public static void rebootOrShutdown(boolean reboot, String reason) {  
  9.         if (reboot) {  
  10.             Log.i(TAG, "Rebooting, reason: " + reason);  
  11.             try {  
  12.                 PowerManagerService.lowLevelReboot(reason);  
  13.             } catch (Exception e) {  
  14.                 Log.e(TAG, "Reboot failed, will attempt shutdown instead", e);  
  15.             }  
  16.         } else if (SHUTDOWN_VIBRATE_MS > 0) {  
  17.             // vibrate before shutting down  
  18.             Vibrator vibrator = new SystemVibrator();  
  19.             try {  
  20.                 vibrator.vibrate(SHUTDOWN_VIBRATE_MS);  
  21.             } catch (Exception e) {  
  22.                 // Failure to vibrate shouldn't interrupt shutdown.  Just log it.  
  23.                 Log.w(TAG, "Failed to vibrate during shutdown.", e);  
  24.             }  
  25.   
  26.             // vibrator is asynchronous so we need to wait to avoid shutting down too soon.  
  27.             try {  
  28.                 Thread.sleep(SHUTDOWN_VIBRATE_MS);  
  29.             } catch (InterruptedException unused) {  
  30.             }  
  31.         }  
  32.   
  33.         // Shutdown power  
  34.         Log.i(TAG, "Performing low-level shutdown...");  
  35.         PowerManagerService.lowLevelShutdown();  
  36.     }  
  37. }  
1. 注释表明:这是由shutdown(final Context context, boolean confirm)调用的。参数reboot如果是true,则reboot,false则shutdown;参数reason就是reboot reason。

2. 如果reboot是true,则会执行PowerManagerService.lowLevelReboot(reason)的过程;否则继续shutdown的过程。文章中分析shutdown的流程,所以reboot暂时不看。

3. 接下来系统会确保shutdown之前的机器震动,从注释很容易看明白。

4. Shutdown power开始进入底层的shutdown,即进入JNI层和kernel层。

PowerManagerService.lowLevelShutdown()是在frameworks/base/services/java/com/android/server/power/PowerManagerService.java中定义的。它是一个通往下层JNI的函数。

[cpp] view plain copy
  1. /** 
  2.  * Low-level function turn the device off immediately, without trying 
  3.  * to be clean.  Most people should use {@link ShutdownThread} for a clean shutdown. 
  4.  */  
  5. public static void lowLevelShutdown() {  
  6.     nativeShutdown();  
  7. }  
nativeShutdown()就是通往下层的接口了。

上层framework层的分析就到此为止了,后续的文章将继续分析JNI层以及kernel的关机流程。
原创粉丝点击