android系统关机源码(9.0)流程分析
16lz
2021-01-24
android系统关机流程分析
- 1.android 系统的关机是从用户按power 键开始的,而每个按键都会在PhoneWindowManager里面被处理
frameworks\base\services\core\java\com\android\server\policy/PhoneWindowManager.java @Override public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) { ... case KeyEvent.KEYCODE_POWER: //按下power键 { // Any activity on the power button stops the accessibility shortcut cancelPendingAccessibilityShortcutAction(); result &= ~ACTION_PASS_TO_USER; isWakeKey = false; // wake-up will be handled separately SystemProperties.set("persist.sys.power","1"); if (down) { interceptPowerKeyDown(event, interactive); //按下,down 为true,走此方法 } else { interceptPowerKeyUp(event, interactive, canceled); } break; } ...}
-
- interceptPowerKeyDown()方法
private void interceptPowerKeyDown(KeyEvent event, boolean interactive) { // Hold a wake lock until the power key is released. if (!mPowerKeyWakeLock.isHeld()) { mPowerKeyWakeLock.acquire(); } // Cancel multi-press detection timeout. if (mPowerKeyPressCounter != 0) { mHandler.removeMessages(MSG_POWER_DELAYED_PRESS); } // Detect user pressing the power button in panic when an application has // taken over the whole screen. boolean panic = mImmersiveModeConfirmation.onPowerKeyDown(interactive, SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags), isNavBarEmpty(mLastSystemUiFlags)); if (panic) { mHandler.post(mHiddenNavPanic); } // Abort possibly stuck animations. mHandler.post(mWindowManagerFuncs::triggerAnimationFailsafe); // Latch power key state to detect screenshot chord. //这段代码实现电源键和音量-键同时按截屏的功能 if (interactive && !mScreenshotChordPowerKeyTriggered && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { mScreenshotChordPowerKeyTriggered = true; mScreenshotChordPowerKeyTime = event.getDownTime(); interceptScreenshotChord(); interceptRingerToggleChord(); } // Stop ringing or end call if configured to do so when power is pressed. TelecomManager telecomManager = getTelecommService(); boolean hungUp = false; if (telecomManager != null) { if (telecomManager.isRinging()) { // Pressing Power while there's a ringing incoming // call should silence the ringer. telecomManager.silenceRinger(); // 如果来电时,则启动静音 } else if ((mIncallPowerBehavior & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0 && telecomManager.isInCall() && interactive) { // Otherwise, if "Power button ends call" is enabled, // the Power button will hang up any current active call. hungUp = telecomManager.endCall(); } } GestureLauncherService gestureService = LocalServices.getService( GestureLauncherService.class); boolean gesturedServiceIntercepted = false; if (gestureService != null) { gesturedServiceIntercepted = gestureService.interceptPowerKeyDown(event, interactive, mTmpBoolean); if (mTmpBoolean.value && mRequestedOrGoingToSleep) { mCameraGestureTriggeredDuringGoingToSleep = true; } } // Inform the StatusBar; but do not allow it to consume the event. sendSystemKeyToStatusBarAsync(event.getKeyCode()); // If the power key has still not yet been handled, then detect short // press, long press, or multi press and decide what to do. mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered || mA11yShortcutChordVolumeUpKeyTriggered || gesturedServiceIntercepted; 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. if (hasLongPressOnPowerBehavior() && fastBootMode) { if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) { powerLongPress(); //重点来了,长按power 会走这个方法,下面发消息其实最终也会走这个方法 } else { Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS); msg.setAsynchronous(true); mHandler.sendMessageDelayed(msg, ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout()); if (hasVeryLongPressOnPowerBehavior()) { Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS); longMsg.setAsynchronous(true); mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout); } } } } else { wakeUpFromPowerKey(event.getDownTime()); if (mSupportLongPressPowerWhenNonInteractive && hasLongPressOnPowerBehavior() && fastBootMode) { if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) { **powerLongPress();** //重点来了,长按power 会走这个方法,下面发消息其实最终也会走这个方法 } else { Message msg = mHandler.obtainMessage(MSG_POWER_LONG_PRESS); msg.setAsynchronous(true); mHandler.sendMessageDelayed(msg, ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout()); if (hasVeryLongPressOnPowerBehavior()) { Message longMsg = mHandler.obtainMessage(MSG_POWER_VERY_LONG_PRESS); longMsg.setAsynchronous(true); mHandler.sendMessageDelayed(longMsg, mVeryLongPressTimeout); } } mBeganFromNonInteractive = true; } else { final int maxCount = getMaxMultiPressPowerCount(); if (maxCount <= 1) { mPowerKeyHandled = true; } else { mBeganFromNonInteractive = true; } } } } }
-
- powerLongPress()方法
private void powerLongPress() { final int behavior = getResolvedLongPressOnPowerBehavior();//得到长按电源键的行为(例如是需要弹出确认对话框呢,还是不需要) switch (behavior) { case LONG_PRESS_POWER_NOTHING://0 break; case LONG_PRESS_POWER_GLOBAL_ACTIONS://1 原生的会走这个case mPowerKeyHandled = true; performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); 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; case LONG_PRESS_POWER_GO_TO_VOICE_ASSIST: mPowerKeyHandled = true; performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); final boolean keyguardActive = mKeyguardDelegate == null ? false : mKeyguardDelegate.isShowing(); if (!keyguardActive) { Intent intent = new Intent(Intent.ACTION_VOICE_ASSIST); if (mAllowStartActivityForLongPressOnPowerDuringSetup) { mContext.startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF); } else { startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF); } } break; } }
-
- 解析长按电源键行为的方法getResolvedLongPressOnPowerBehavior()
private int getResolvedLongPressOnPowerBehavior() { if (FactoryTest.isLongPressOnPowerOffEnabled()) { return LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM; } return mLongPressOnPowerBehavior; // 最后返回这个行为 }
mLongPressOnPowerBehavior 的初始化如下:
mLongPressOnPowerBehavior = mContext.getResources().getInteger( com.android.internal.R.integer.config_longPressOnPowerBehavior);
由此可见 mLongPressOnPowerBehavior 读取的是 config 中的值。如下:
\frameworks\base\core\res\res\values\config.xml <!-- Control the behavior when the user long presses the power button. 0 - Nothing // 表示直接关机 1 - Global actions menu //关机要显示Global actions 2 - Power off (with confirmation) // 关机要弹出对话框再次确认 3 - Power off (without confirmation) // 关机不需要弹出对话框 4 - Go to voice assist --> <integer name="config_longPressOnPowerBehavior">1</integer> //默认为1
-
- showGlobalActionsInternal() 方法
void showGlobalActionsInternal() { if (mGlobalActions == null) { mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs); } // 如果mGlobalActions 为空,则创建它 final boolean keyguardShowing = isKeyguardShowingAndNotOccluded(); mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned()); //然后通过这个showDialog 的方法弹出关机的对话框。 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); } }
- 6.showDialog() 方法
\frameworks\base\services\core\java\com\android\server\policy/GlobalActions.java public void showDialog(boolean keyguardShowing, boolean deviceProvisioned) { if (DEBUG) Slog.d(TAG, "showDialog " + keyguardShowing + " " + deviceProvisioned); if (mGlobalActionsProvider != null && mGlobalActionsProvider.isGlobalActionsDisabled()) { return; } mKeyguardShowing = keyguardShowing; mDeviceProvisioned = deviceProvisioned; mShowing = true; if (mGlobalActionsAvailable) { mHandler.postDelayed(mShowTimeout, 5000); mGlobalActionsProvider.showGlobalActions(); } else { // SysUI isn't alive, show legacy menu. ensureLegacyCreated(); mLegacyGlobalActions.showDialog(mKeyguardShowing, mDeviceProvisioned); }
\frameworks\base\services\core\java\com\android\server\policy/LegacyGlobalActions.java /** * 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(); // 如果Dialog 不为空,则创建它 } } private void handleShow() { awakenIfNecessary(); mDialog = createDialog(); prepareDialog(); // If we only have 1 item and it's a simple press action, just do this action. if (mAdapter.getCount() == 1 && mAdapter.getItem(0) instanceof SinglePressAction && !(mAdapter.getItem(0) instanceof LongPressAction)) { ((SinglePressAction) mAdapter.getItem(0)).onPress(); } else { if (mDialog != null) { WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes(); attrs.setTitle("LegacyGlobalActions"); mDialog.getWindow().setAttributes(attrs); mDialog.show(); mDialog.getWindow().getDecorView().setSystemUiVisibility( View.STATUS_BAR_DISABLE_EXPAND); } } }
- 当点击 dialog 的power off 时,会调用 PowerAction的onPress方法
@Override public void onPress() { // shutdown by making sure radio and power are handled accordingly. mWindowManagerFuncs.shutdown(false /* confirm */); }
- mWindowManagerFuncs实则为WindowManagerService的对象。故
frameworks\base\services\core\java\com\android\server\wm/WindowManagerService.java // Called by window manager policy. Not exposed externally. @Override public void shutdown(boolean confirm) { // Pass in the UI context, since ShutdownThread requires it (to show UI). ShutdownThread.shutdown(ActivityThread.currentActivityThread().getSystemUiContext(), PowerManager.SHUTDOWN_USER_REQUESTED, confirm); }
- ShutdownThread的shutdown方法
frameworks\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. This must be a context * suitable for displaying UI (aka Themable). * @param reason code to pass to android_reboot() (e.g. "userrequested"), or null. * @param confirm true if user confirmation is needed before shutting down. */ public static void shutdown(final Context context, String reason, boolean confirm) { mReboot = false; mRebootSafeMode = false; mReason = reason; shutdownInner(context, confirm);//confirm表示是否弹出确认对话框 }
private static void shutdownInner(final Context context, boolean confirm) { // ShutdownThread is called from many places, so best to verify here that the context passed // in is themed. context.assertRuntimeOverlayThemable(); // 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, R.style.Theme_Material_Dialog_Alert) .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) {SystemProperties.set("persist.sys.power","0"); beginShutdownSequence(context); } }) .setNegativeButton(com.android.internal.R.string.no, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { Log.d(TAG, "Notifying thread to cancle shutdown "); SystemProperties.set("persist.sys.power","0"); } }) .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; } sInstance.mProgressDialog = showShutdownDialog(context); 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; } } if (SecurityLog.isLoggingEnabled()) { SecurityLog.writeEvent(SecurityLog.TAG_OS_SHUTDOWN); } // start the thread that initiates shutdown sInstance.mHandler = new Handler() { }; sInstance.start(); //进入 ShutdownThread的run方法 }
/** * Makes sure we handle the shutdown gracefully. * Shuts off power regardless of radio state if the allotted time has passed. */ public void run() { TimingsTraceLog shutdownTimingLog = newTimingsLog(); shutdownTimingLog.traceBegin("SystemServerShutdown"); metricShutdownStart(); metricStarted(METRIC_SYSTEM_SERVER); 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(); } }; /* * 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") + (mReason != null ? mReason : ""); 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"); } metricStarted(METRIC_SEND_BROADCAST); shutdownTimingLog.traceBegin("SendShutdownBroadcast"); Log.i(TAG, "Sending shutdown broadcast..."); //Make ShutDownCamService to front Intent shutdownIntent = new Intent(); shutdownIntent.setAction("com.mediatek.ShutDownCamService"); shutdownIntent.setPackage("mtktvapi.agent"); mContext.startService(shutdownIntent); // First send the high-level shut down broadcast. mActionDone = false; Intent intent = new Intent(Intent.ACTION_SHUTDOWN); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY); 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; } else if (mRebootHasProgressBar) { 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, ACTION_DONE_POLL_WAIT_MS)); } catch (InterruptedException e) { } } } if (mRebootHasProgressBar) { sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null); } shutdownTimingLog.traceEnd(); // SendShutdownBroadcast metricEnded(METRIC_SEND_BROADCAST); Log.i(TAG, "Shutting down activity manager..."); shutdownTimingLog.traceBegin("ShutdownActivityManager"); metricStarted(METRIC_AM); final IActivityManager am = IActivityManager.Stub.asInterface(ServiceManager.checkService("activity")); if (am != null) { try { am.shutdown(MAX_BROADCAST_TIME); //关闭AMS服务 } catch (RemoteException e) { } } if (mRebootHasProgressBar) { sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null); } shutdownTimingLog.traceEnd();// ShutdownActivityManager metricEnded(METRIC_AM); Log.i(TAG, "Shutting down package manager..."); shutdownTimingLog.traceBegin("ShutdownPackageManager"); metricStarted(METRIC_PM); final PackageManagerService pm = (PackageManagerService) ServiceManager.getService("package"); if (pm != null) { pm.shutdown(); //关闭pms服务 } if (mRebootHasProgressBar) { sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null); } shutdownTimingLog.traceEnd(); // ShutdownPackageManager metricEnded(METRIC_PM); // Shutdown radios. shutdownTimingLog.traceBegin("ShutdownRadios"); metricStarted(METRIC_RADIOS); shutdownRadios(MAX_RADIO_WAIT_TIME); if (mRebootHasProgressBar) { sInstance.setRebootProgress(RADIO_STOP_PERCENT, null); } shutdownTimingLog.traceEnd(); // ShutdownRadios metricEnded(METRIC_RADIOS); if (mRebootHasProgressBar) { sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null); // If it's to reboot to install an update and uncrypt hasn't been // done yet, trigger it now. uncrypt(); } shutdownTimingLog.traceEnd(); // SystemServerShutdown metricEnded(METRIC_SYSTEM_SERVER); saveMetrics(mReboot, mReason); // Remaining work will be done by init, including vold shutdown rebootOrShutdown(mContext, mReboot, mReason); // 最后调用 这个方法进一步处理 }
/** * Do not call this directly. Use {@link #reboot(Context, String, boolean)} * or {@link #shutdown(Context, String, 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/shutdown */ 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"); reason = null; } 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.lowLevelShutdown(reason); // 关闭电源 }
/** * Low-level function turn the device off immediately, without trying * to be clean. Most people should use {@link ShutdownThread} for a clean shutdown. * * @param reason code to pass to android_reboot() (e.g. "userrequested"), or null. */ public static void lowLevelShutdown(String reason) { if (reason == null) { reason = ""; } SystemProperties.set("sys.powerctl", "shutdown," + reason); // 最后kernel 会检查此值来 实现真正的关闭。 }
到此 android 系统的framework 层关机流程就分析完毕。
更多相关文章
- android标题栏进度圈使用方法
- Android重写onOreate,onPause,onStop等方法时需要注意的问题!
- XML解析
- android 比较有用的方法总结
- 运行Android项目,报错java.lang.IllegalAccessException: access
- System.EntryPointNotFoundException: Unable to find an entry
- android中的alertdialog及LayoutInflater
- 【Android(安卓)开发教程】WebView
- android 设置LinearLayout,RelativeLayout等等layout的高和宽