Android6.0关机流程源码分析一
2017-03-27 15:10
369 查看
_前段时间盆友问我怎么实现关机功能,于是我就开始捣鼓,第一个想法就是发送关机广播,然而遇到了些问题,一是获取不到关机权限,二是Intent.ACTION_REQUEST_SHUT_DOWN和Intent.SHUTDOWN这两个属性不对上层开放。一条路行不通就换条走吧,既然没对上层提供shutdown()函数,那就用反射的方法来取,结果还是因为没有关机权限而无法调用shutdown()函数。无奈只好决定来看下源码,分析关机流程。这里主要是分析正常的关机流程。画了个简单的调用流程图。
接下来一步步分析。我们正常关机一般就是长按关机键,然后系统弹出个关机对话框
选择Power Off则开启关机。
长按关机键(KEYCODE_POWER),PhoneWindowManager.java拦截该事件,做出处理
down事件:
主线程接收到长按的消息并做出下一步处理
那接着来看powerLongPress()函数是如何处理长按事件的
这里根据长按的行为behavior来分情况处理的。
情况一:LONG_PRESS_POWER_NOTHING:不处理
情况二:LONG_PRESS_POWER_GLOBAL_ACTIONS:正常关机流程
(1)sendCloseSystemWindows();//发送请求关闭系统的对话框
调用的是PhoneWindow.java的方法,如下:
继续调用ActivityManagerNative.java的方法,如下:
mRemote.transact(CLOSE_SYSTEM_DIALOGS_TRANSACTION, data, reply, 0)
(2)mGlobalActions.showDialog();//显示关机对话框
调用HandleShow()方法创建GlobalActionsDialog对话框
关机Action:PowerAction
onPress()和onLongpress()是分别处理单击和长按的方法,那么WindownManagerService.java实现了WindowManagerPolicy.WindowManagerFuncs接口,所以实际上调用的是WindownManagerService.java类的shutdown()、rebootSafeMode()方法。
路径:framework/base/services/core/java/com/android/server/wm/WindowManagerService.java
最终都是调用ShutdownThread.java的方法。
该类路径:framework/base/services/core/java/com/android/server/power/ShutdownThread.java
最后调用shutdownInner()
开始进入关机流程
run()
重启或关机
run()方法主要完成以下一些工作:
(1)发送关机广播ACTION_SHUTDOWN;
(2)关闭服务;
(3)关闭Radio
(4)设置关机震动
(5)调用PowerManagerService的方法关闭电源。
路径:/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
开始进入到jni层,暂时不深入分析。
情况三、四:LONG_PRESS_POWER_SHUT_OFF:
直接调用mWindowManagerFuncs.shutdown()进行关机。
把关机源码粗略的分析一遍,大概了解了关机的流程。对于篇头说的两个Intent的属性是定义在Intent.java
把自己写的apk放在源码里编译,调用关机的函数shutdown()就可以实现关机功能了,当然也可以参考源码中的定时关机功能通过启动ShutdownActivity关机。
接下来一步步分析。我们正常关机一般就是长按关机键,然后系统弹出个关机对话框
选择Power Off则开启关机。
长按关机键(KEYCODE_POWER),PhoneWindowManager.java拦截该事件,做出处理
/** {@inheritDoc} */ @Override public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { if (!mSystemBooted) { // If we have not yet booted, don't let key events do anything. return 0; } final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0; final boolean down = event.getAction() == KeyEvent.ACTION_DOWN; final boolean canceled = event.isCanceled(); final int keyCode = event.getKeyCode(); switch(keycode){ case KeyEvent.KEYCODE_POWER: { result &= ~ACTION_PASS_TO_USER; isWakeKey = false; // wake-up will be handled separately if (down) { interceptPowerKeyDown(event, interactive); } else { interceptPowerKeyUp(event, interactive, canceled); } break; } case KeyEvent.KEYCODE_SLEEP: { result &= ~ACTION_PASS_TO_USER; isWakeKey = false; if (!mPowerManager.isInteractive()) { useHapticFeedback = false; // suppress feedback if already non-interactive } if (down) { sleepPress(event.getEventTime()); } else { sleepRelease(event.getEventTime()); } break; } case KeyEvent.KEYCODE_WAKEUP: { 4000 result &= ~ACTION_PASS_TO_USER; isWakeKey = true; break; } } }
down事件:
private void interceptPowerKeyDown(KeyEvent event, boolean interactive) { //如果电源键尚未处理,则检测是短按,长按,或多按操作中的哪一种,再决定做下一步处理。 mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered || mScreenshotChordVolumeUpKeyTriggered; if (!mPowerKeyHandled) { //手机处于激活(亮屏)状态 if (interactive) { // When interactive, we're already awake. // Wait for a long press or for the button to be released to decide what to do. //检查是否是长按操作 //hasLongPressOnPowerBehavior=getResolvedLongPressOnPowerBehavior() != LONG_PRESS_POWER_NOTHING; if (hasLongPressOnPowerBehavior()) {//true Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS); msg.setAsynchronous(true); //发送消息通知主线程处理长按操作 mHandler.sendMessageDelayed(msg, ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout()); } } //手机待机状态 else { //唤醒手机 wakeUpFromPowerKey(event.getDownTime()); if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior()) { Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS); msg.setAsynchronous(true); mHandler.sendMessageDelayed(msg, ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout()); mBeganFromNonInteractive = true; } else { final int maxCount = getMaxMultiPressPowerCount(); if (maxCount <= 1) { mPowerKeyHandled = true; } else { mBeganFromNonInteractive = true; } } } } }
主线程接收到长按的消息并做出下一步处理
private class PolicyHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_POWER_LONG_PRESS: //调用powerPress()函数 powerLongPress(); break; } } }
那接着来看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); break; } }
这里根据长按的行为behavior来分情况处理的。
情况一:LONG_PRESS_POWER_NOTHING:不处理
情况二:LONG_PRESS_POWER_GLOBAL_ACTIONS:正常关机流程
void showGlobalActionsInternal() { //请求ActivityManagerNative关闭系统所有窗口 sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); if (mGlobalActions == null) { //初始化GlobalActions mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs); } final boolean keyguardShowing = isKeyguardShowingAndNotOccluded(); //显示关机对话框 mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned()); if (keyguardShowing) { // since it took two seconds of long press to bring this up, // poke the wake lock so they have some time to see the dialog. mPowerManager.userActivity(SystemClock.uptimeMillis(), false); } }
(1)sendCloseSystemWindows();//发送请求关闭系统的对话框
void sendCloseSystemWindows(String reason) { PhoneWindow.sendCloseSystemWindows(mContext, reason); }
调用的是PhoneWindow.java的方法,如下:
public static void sendCloseSystemWindows(Context context, String reason) { if (ActivityManagerNative.isSystemReady()) { try { ActivityManagerNative.getDefault().closeSystemDialogs(reason); } catch (RemoteException e) { } } }
继续调用ActivityManagerNative.java的方法,如下:
public void closeSystemDialogs(String reason) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeString(reason); mRemote.transact(CLOSE_SYSTEM_DIALOGS_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); reply.recycle(); }
mRemote.transact(CLOSE_SYSTEM_DIALOGS_TRANSACTION, data, reply, 0)
@Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { switch (code) { case CLOSE_SYSTEM_DIALOGS_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); String reason = data.readString(); closeSystemDialogs(reason); reply.writeNoException(); return true; } } }
(2)mGlobalActions.showDialog();//显示关机对话框
/** * Show the global actions dialog (creating if necessary) * @param keyguardShowing True if keyguard is showing */ public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) { mKeyguardShowing = keyguardShowing; mDeviceProvisioned = isDeviceProvisioned; if (mDialog != null) { mDialog.dismiss(); mDialog = null; // Show delayed, so that the dismiss of the previous dialog completes mHandler.sendEmptyMessage(MESSAGE_SHOW); } else { handleShow(); } }
调用HandleShow()方法创建GlobalActionsDialog对话框
private void handleShow() { awakenIfNecessary(); //创建关机对话框 mDialog = createDialog(); prepareDialog(); // 对话框视图只有一个item,当手单按时回调onPress()函数 if (mAdapter.getCount() == 1 && mAdapter.getItem(0) instanceof SinglePressAction && !(mAdapter.getItem(0) instanceof LongPressAction)) { ((SinglePressAction) mAdapter.getItem(0)).onPress(); } //否则显示关机对话框,设置对话框参数属性 else { WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes(); attrs.setTitle("GlobalActions"); mDialog.getWindow().setAttributes(attrs); mDialog.show(); mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND); } } /** * Create the global actions dialog. * @return A new dialog. */ private GlobalActionsDialog createDialog() { // Simple toggle style if there's no vibrator, otherwise use a tri-state if (!mHasVibrator) { mSilentModeAction = new SilentModeToggleAction(); } else { mSilentModeAction = new SilentModeTriStateAction(mContext, mAudioManager, mHandler); } //飞行模式 mAirplaneModeOn = new ToggleAction( R.drawable.ic_lock_airplane_mode, R.drawable.ic_lock_airplane_mode_off, R.string.global_actions_toggle_airplane_mode, R.string.global_actions_airplane_mode_on_status, R.string.global_actions_airplane_mode_off_status) { void onToggle(boolean on) { if (mHasTelephony && Boolean.parseBoolean( SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) { mIsWaitingForEcmExit = true; // Launch ECM exit dialog Intent ecmDialogIntent = new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null); ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); mContext.startActivity(ecmDialogIntent); } else { changeAirplaneModeSystemSetting(on); } } @Override protected void changeStateFromPress(boolean buttonOn) { if (!mHasTelephony) return; // In ECM mode airplane state cannot be changed if (!(Boolean.parseBoolean( SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) { mState = buttonOn ? State.TurningOn : State.TurningOff; mAirplaneState = mState; } } public boolean showDuringKeyguard() { return true; } public boolean showBeforeProvisioning() { return false; } 13e26 }; //飞行模式改变 onAirplaneModeChanged(); mItems = new ArrayList<Action>(); //framework/base/core/res/res/values/config.xml(Global Actions:power、bugreport、users、reboot、airplane) String[] defaultActions = mContext.getResources().getStringArray( com.android.internal.R.array.config_globalActionsList); ArraySet<String> addedKeys = new ArraySet<String>(); //循环给对话框的的列表添加item for (int i = 0; i < defaultActions.length; i++) { String actionKey = defaultActions[i]; if (addedKeys.contains(actionKey)) { // If we already have added this, don't add it again. continue; } if (GLOBAL_ACTION_KEY_POWER.equals(actionKey)) { //关机 mItems.add(new PowerAction()); } else if (GLOBAL_ACTION_KEY_AIRPLANE.equals(actionKey)) { //飞行模式 mItems.add(mAirplaneModeOn); } else if (GLOBAL_ACTION_KEY_BUGREPORT.equals(actionKey)) { if (Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.BUGREPORT_IN_POWER_MENU, 0) != 0 && isCurrentUserOwner()) { mItems.add(getBugReportAction()); } } else if (GLOBAL_ACTION_KEY_SILENT.equals(actionKey)) { //静音 if (mShowSilentToggle) { mItems.add(mSilentModeAction); } } else { Log.e(TAG, "Invalid global action key " + actionKey); } // Add here so we don't add more than one. addedKeys.add(actionKey); } //创建适配器 mAdapter = new MyAdapter(); AlertParams params = new AlertParams(mContext); params.mAdapter = mAdapter; params.mOnClickListener = this; params.mForceInverseBackground = true; //创建GlobalActionsDialog对象 GlobalActionsDialog dialog = new GlobalActionsDialog(mContext, params); //触摸对话框外部,对话框消失 dialog.setCanceledOnTouchOutside(false); // Handled by the custom class. //给对话框列表注册监听事件 dialog.getListView().setItemsCanFocus(true); dialog.getListView().setLongClickable(true); dialog.getListView().setOnItemLongClickListener( new AdapterView.OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { final Action action = mAdapter.getItem(position); if (action instanceof LongPressAction) { return ((LongPressAction) action).onLongPress(); } return false; } }); dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); dialog.setOnDismissListener(this); return dialog; }
关机Action:PowerAction
private final class PowerAction extends SinglePressAction implements LongPressAction { private PowerAction() { super(com.android.internal.R.drawable.ic_lock_power_off, R.string.global_action_power_off); } @Override 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; } @Override public boolean showDuringKeyguard() { return true; } @Override public boolean showBeforeProvisioning() { return true; } @Override public void onPress() { // shutdown by making sure radio and power are handled accordingly. mWindowManagerFuncs.shutdown(false /* confirm */); } }
onPress()和onLongpress()是分别处理单击和长按的方法,那么WindownManagerService.java实现了WindowManagerPolicy.WindowManagerFuncs接口,所以实际上调用的是WindownManagerService.java类的shutdown()、rebootSafeMode()方法。
路径:framework/base/services/core/java/com/android/server/wm/WindowManagerService.java
最终都是调用ShutdownThread.java的方法。
该类路径:framework/base/services/core/java/com/android/server/power/ShutdownThread.java
/** * Request a clean shutdown, waiting for subsystems to clean up their * state etc. Must be called from a Looper thread in which its UI * is shown. * * @param context Context used to display the shutdown progress dialog. * @param confirm true if user confirmation is needed before shutting down. */ public static void shutdown(final Context context, boolean confirm) { mReboot = false; mRebootSafeMode = false; shutdownInner(context, confirm); } /** * Request a reboot into safe mode. Must be called from a Looper thread in which its UI * is shown. * * @param context Context used to display the shutdown progress dialog. * @param confirm true if user confirmation is needed before shutting down. */ public static void rebootSafeMode(final Context context, boolean confirm) { UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); if (um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) { return; } mReboot = true; mRebootSafeMode = true; mRebootUpdate = false; mRebootReason = null; shutdownInner(context, confirm); }
最后调用shutdownInner()
static void shutdownInner(final Context context, boolean confirm) { // ensure that only one thread is trying to power down. // any additional calls are just returned synchronized (sIsStartedGuard) { if (sIsStarted) { Log.d(TAG, "Request to shutdown already running, returning."); return; } } final int longPressBehavior = context.getResources().getInteger( com.android.internal.R.integer.config_longPressOnPowerBehavior); final int resourceId = mRebootSafeMode ? com.android.internal.R.string.reboot_safemode_confirm : (longPressBehavior == 2 ? com.android.internal.R.string.shutdown_confirm_question : com.android.internal.R.string.shutdown_confirm); Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior); if (confirm) { final CloseDialogReceiver closer = new CloseDialogReceiver(context); if (sConfirmDialog != null) { sConfirmDialog.dismiss(); } //创建关机确认对话框 sConfirmDialog = new AlertDialog.Builder(context) .setTitle(mRebootSafeMode ? com.android.internal.R.string.reboot_safemode_title : com.android.internal.R.string.power_off) .setMessage(resourceId) .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { //进入关机流程 beginShutdownSequence(context); } }) .setNegativeButton(com.android.internal.R.string.no, null) .create(); closer.dialog = sConfirmDialog; sConfirmDialog.setOnDismissListener(closer); sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); sConfirmDialog.show(); } else { //不需要关机确认对话框,直接进入关机流程 beginShutdownSequence(context); } }
开始进入关机流程
private static void beginShutdownSequence(Context context) { synchronized (sIsStartedGuard) { if (sIsStarted) { Log.d(TAG, "Shutdown sequence already running, returning."); return; } sIsStarted = true; } // Throw up a system dialog to indicate the device is rebooting / shutting down. ProgressDialog pd = null; // Path 1: Reboot to recovery and install the update // Condition: mRebootReason == REBOOT_RECOVERY and mRebootUpdate == True // (mRebootUpdate is set by checking if /cache/recovery/uncrypt_file exists.) // UI: progress bar // // Path 2: Reboot to recovery for factory reset // Condition: mRebootReason == REBOOT_RECOVERY // UI: spinning circle only (no progress bar) // // Path 3: Regular reboot / shutdown // Condition: Otherwise // UI: spinning circle only (no progress bar) //检查是否是定时关机 if(!sIsPowerOffAlarm){ //非定时关机 pd = new ProgressDialog(context); if (PowerManager.REBOOT_RECOVERY.equals(mRebootReason)) { mRebootUpdate = new File(UNCRYPT_PACKAGE_FILE).exists(); if (mRebootUpdate) { //Reboot to Recovery Progress Dialog. This is shown before it reboots to recovery pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_update_title)); pd.setMessage(context.getText( com.android.internal.R.string.reboot_to_update_prepare)); pd.setMax(100); pd.setProgressNumberFormat(null); pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); pd.setProgress(0); pd.setIndeterminate(false); } else { // Factory reset path. Set the dialog message accordingly. //恢复出厂设置对话框属性设置Reboot to Recovery for factory reset pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_reset_title)); pd.setMessage(context.getText( com.android.internal.R.string.reboot_to_reset_message)); pd.setIndeterminate(true); } } else { //关机Shutdown Progress Dialog. This is shown if the user chooses to power off the phone 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); } String[] bootcmd = {"bootanimation", "shutdown"} ; try { ////执行关机动画 Log.i(TAG, "exec the bootanimation "); SystemProperties.set("service.bootanim.exit", "0"); Runtime.getRuntime().exec(bootcmd); } catch (Exception e){ Log.e(TAG,"bootanimation command exe err!"); } } //初始化关机线程 sInstance.mProgressDialog = pd; sInstance.mContext = context; sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); // make sure we never fall asleep again 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; } // also make sure the screen stays on for better user experience 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; } } // start the thread that initiates shutdown //启动关机线程 if(sIsPowerOffAlarm){ Looper.prepare(); sInstance.mHandler = new Handler(); Log.d(TAG,">>> before start <<<"); sInstance.start(); Looper.loop(); }else{ sInstance.mHandler = new Handler() { }; sInstance.start(); } }
run()
/** * Makes sure we handle the shutdown gracefully. * Shuts off power regardless of radio and bluetooth state if the alloted time has passed. */ 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. //用于接收关机广播,bu,不允许appcancel this,忽略 actionDone(); } }; /* * 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") + (mRebootReason != null ? mRebootReason : ""); 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"); } Log.i(TAG, "Sending shutdown broadcast..."); // First send the high-level shut down broadcast.发送关机广播 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); //等待10s,前面定义的广播接收器收到关机广播时mActionDone设置为true,同时取消等待 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; } else if (mRebootUpdate) { int status = (int)((MAX_BROADCAST_TIME - delay) * 1.0 * BROADCAST_STOP_PERCENT / MAX_BROADCAST_TIME); sInstance.setRebootProgress(status, null); } try { mActionDoneSync.wait(Math.min(delay, PHONE_STATE_POLL_SLEEP_MSEC)); } catch (InterruptedException e) { } } } if (mRebootUpdate) { sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null); } Log.i(TAG, "Shutting down activity manager..."); //10s内关闭ActivityManager服务 final IActivityManager am = ActivityManagerNative.asInterface(ServiceManager.checkService("activity")); if (am != null) { try { am.shutdown(MAX_BROADCAST_TIME); } catch (RemoteException e) { } } if (mRebootUpdate) { sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null); } Log.i(TAG, "Shutting down package manager..."); //关掉PackageManager服务 final PackageManagerService pm = (PackageManagerService) ServiceManager.getService("package"); if (pm != null) { pm.shutdown(); } if (mRebootUpdate) { sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null); } // Shutdown radios.12秒内关闭收音机 shutdownRadios(MAX_RADIO_WAIT_TIME); if (mRebootUpdate) { sInstance.setRebootProgress(RADIO_STOP_PERCENT, null); } // Shutdown MountService to ensure media is in a safe state 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"); // Set initial variables and time out time. //20s内关闭MountService服务 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; } else if (mRebootUpdate) { int status = (int)((MAX_SHUTDOWN_WAIT_TIME - delay) * 1.0 * (MOUNT_SERVICE_STOP_PERCENT - RADIO_STOP_PERCENT) / MAX_SHUTDOWN_WAIT_TIME); status += RADIO_STOP_PERCENT; sInstance.setRebootProgress(status, null); } try { mActionDoneSync.wait(Math.min(delay, PHONE_STATE_POLL_SLEEP_MSEC)); } catch (InterruptedException e) { } } } if (mRebootUpdate) { sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null); // If it's to reboot to install update, invoke uncrypt via init service. uncrypt(); } //重启或关机 rebootOrShutdown(mContext, mReboot, mRebootReason); }
重启或关机
/** * Do not call this directly. Use {@link #reboot(Context, String, boolean)} * or {@link #shutdown(Context, boolean)} instead. * * @param context Context used to vibrate or null without vibration * @param reboot true to reboot or false to shutdown * @param reason reason for reboot */ public static void rebootOrShutdown(final Context context, boolean reboot, String reason) { if (reboot) { Log.i(TAG, "Rebooting, reason: " + reason); PowerManagerService.lowLevelReboot(reason); Log.e(TAG, "Reboot failed, will attempt shutdown instead"); } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) { // vibrate before shutting down //关机前震动 Vibrator vibrator = new SystemVibrator(context); try { //震动时间、属性设置 vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES); } catch (Exception e) { // Failure to vibrate shouldn't interrupt shutdown. Just log it. Log.w(TAG, "Failed to vibrate during shutdown.", e); } // vibrator is asynchronous so we need to wait to avoid shutting down too soon. //先休眠一会,震动结束再关机。 try { Thread.sleep(SHUTDOWN_VIBRATE_MS); } catch (InterruptedException unused) { } } // Shutdown power Log.i(TAG, "Performing low-level shutdown..."); //调用PowerManagerService的方法关闭电源。 PowerManagerService.lowLevelShutdown(); }
run()方法主要完成以下一些工作:
(1)发送关机广播ACTION_SHUTDOWN;
(2)关闭服务;
(3)关闭Radio
(4)设置关机震动
(5)调用PowerManagerService的方法关闭电源。
路径:/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
/** * Low-level function turn the device off immediately, without trying * to be clean. Most people should use {@link ShutdownThread} for a clean shutdown. */ public static void lowLevelShutdown() { SystemProperties.set("sys.powerctl", "shutdown"); }
开始进入到jni层,暂时不深入分析。
情况三、四:LONG_PRESS_POWER_SHUT_OFF:
直接调用mWindowManagerFuncs.shutdown()进行关机。
把关机源码粗略的分析一遍,大概了解了关机的流程。对于篇头说的两个Intent的属性是定义在Intent.java
public static final String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN"; public static final String ACTION_REQUEST_SHUTDOWN = "android.intent.action.ACTION_REQUEST_SHUTDOWN";
把自己写的apk放在源码里编译,调用关机的函数shutdown()就可以实现关机功能了,当然也可以参考源码中的定时关机功能通过启动ShutdownActivity关机。
Intent sdIntent = new Intent(android.intent.action.ACTION_REQUEST_SHUTDOWN); /*是否显示关机确认对话框 */ sdIntent.putExtra(Intent.EXTRA_KEY_CONFIRM, false); sdIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 启动ShutdownActivity this.startActivity(shutdown);
相关文章推荐
- Android关机流程源码分析
- Android关机流程源码分析
- Android关机流程源码分析
- android6.0源码分析之Camera API2.0下的初始化流程分析
- Android6.0源码分析之menu键弹出popupwindow菜单流程分析
- android6.0源码分析之Camera API2.0下的Preview(预览)流程分析
- Android关机流程源码分析
- Android6.0的phone应用源码分析(4)——phone拨号流程分析
- Android关机流程源码分析
- Android关机流程源码分析
- android6.0源码分析之Camera API2.0下的Capture流程分析
- Android6.0的phone应用源码分析(4)——phone拨号流程分析
- Android关机流程源码分析
- Android关机流程源码分析
- Android关机流程源码分析
- android6.0源码分析之Camera API2.0下的初始化流程分析
- android6.0源码分析之Camera API2.0下的Preview(预览)流程分析
- Android关机流程源码分析
- Android关机流程源码分析
- Android6.0 关机shutdown & 重启reboot流程分析