Android 关机
Android Framework层Power键关机流程(二,关机流程)
Android 关机(reboot)流程 -- "sys.powerctl"
一.framework
一.framework
1.1.按钮关机 mWindowManagerFuncs实现接口
frameworks\base\services\core\java\com\android\server\policy\GlobalActions.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @Override public void onPress() { boolean isBox = "box" .equals(SystemProperties.get( "ro.target.product" )); boolean notUseLegeacyWakeupRestartPlatform = "rk3399" .equals(SystemProperties.get( "ro.board.platform" )); if (isBox && !notUseLegeacyWakeupRestartPlatform){ wakeup_restart_set(); Log.d(TAG, "don't shutdown here,only go to sleep for box!" ); mPowerManager.goToSleep(SystemClock.uptimeMillis()); } else { // shutdown by making sure radio and power are handled accordingly. mWindowManagerFuncs.shutdown( false /* confirm */ ); } } } |
1.2.回调接口
frameworks\base\core\java\android\view\WindowManagerPolicy.java
1 2 3 4 5 6 7 | /** * Interface for calling back in to the window manager that is private * between it and the policy. */ public interface WindowManagerFuncs { public void shutdown( boolean confirm); |
1.3.实现接口 shutdown方法
frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java
1 2 3 4 5 | // Called by window manager policy. Not exposed externally. @Override public void shutdown( boolean confirm) { ShutdownThread.shutdown(mContext, PowerManager.SHUTDOWN_USER_REQUESTED, confirm); } |
1.4.关机流程
frameworks\base\services\core\java\com\android\server\power\ShutdownThread.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | /** *请求清除关闭,等待子系统清除它们的 *状态等。必须从其UI中的环形线程中调用 *显示。 * @param context用于显示关机进度对话框的上下文。 * @param原因代码传递给android_reboot()(例如“userrequested”),或null。 * @param confirm true如果在关闭之前需要用户确认。 */ public static void shutdown( final Context context, String reason, boolean confirm) { mReboot = false ; mRebootSafeMode = false ; mReason = reason; shutdownInner(context, confirm); } |
//shutdownInner 主要还是看 beginShutdownSequence这个方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | 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); } } |
//beginShutdownSequence 对话框 关机动画
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | // Used for shutdownanimation private static final String SYSTEM_SHUTDOWNANIMATION_FILE = "/system/media/shutdownanimation.zip" ; 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 = new ProgressDialog(context); // Path 1: Reboot to recovery for update // Condition: mReason == REBOOT_RECOVERY_UPDATE // // Path 1a: uncrypt needed // Condition: if /cache/recovery/uncrypt_file exists but // /cache/recovery/block.map doesn't. // UI: determinate progress bar (mRebootHasProgressBar == True) // // * Path 1a is expected to be removed once the GmsCore shipped on // device always calls uncrypt prior to reboot. // // Path 1b: uncrypt already done // UI: spinning circle only (no progress bar) // // Path 2: Reboot to recovery for factory reset // Condition: mReason == REBOOT_RECOVERY // UI: spinning circle only (no progress bar) // // Path 3: Regular reboot / shutdown // Condition: Otherwise // UI: spinning circle only (no progress bar) if (PowerManager.REBOOT_RECOVERY_UPDATE.equals(mReason)) { // We need the progress bar if uncrypt will be invoked during the // reboot, which might be time-consuming. mRebootHasProgressBar = RecoverySystem.UNCRYPT_PACKAGE_FILE.exists() && !(RecoverySystem.BLOCK_MAP_FILE.exists()); pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_update_title)); if (mRebootHasProgressBar) { pd.setMax( 100 ); pd.setProgress( 0 ); pd.setIndeterminate( false ); pd.setProgressNumberFormat( null ); pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); pd.setMessage(context.getText( com.android.internal.R.string.reboot_to_update_prepare)); } else { pd.setIndeterminate( true ); pd.setMessage(context.getText( com.android.internal.R.string.reboot_to_update_reboot)); } } else if (PowerManager.REBOOT_RECOVERY.equals(mReason)) { // Factory reset path. Set the dialog message accordingly. 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 { 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.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 sInstance.mHandler = new Handler() { }; sInstance.start(); } |
run
1 2 3 4 5 6 7 8 | public void run() { //一大堆代码 if (checkAnimationFileExist()) { //跑开机动画 start_shutdownanim(); thaw_orien_shutdownanim(); } rebootOrShutdown(mContext, mReboot, mReason); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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); } |
1.5.PowerManagerService 设置关机属性
frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java
1 2 3 4 5 6 | public static void lowLevelShutdown(String reason) { if (reason == null ) { reason = "" ; } SystemProperties.set( "sys.powerctl" , "shutdown," + reason); } |
二.kernel
2.1.system/core/rootdir/init.rc
1 2 | on property:sys.powerctl=* powerctl ${sys.powerctl} |
2.2.system\core\init\builtins.cpp 解析属性 showdown ANDROID_RB_POWEROFF
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | static int do_powerctl( const std::vector<std::string>& args) { const char * command = args[1].c_str(); int len = 0; unsigned int cmd = 0; const char *reboot_target = "" ; void (*callback_on_ro_remount)( const struct mntent*) = NULL; if ( strncmp (command, "shutdown" , 8) == 0) { cmd = ANDROID_RB_POWEROFF; len = 8; } else if ( strncmp (command, "reboot" , 6) == 0) { cmd = ANDROID_RB_RESTART2; len = 6; } else { ERROR( "powerctl: unrecognized command '%s'\n" , command); return -EINVAL; } if (command[len] == ',' ) { if (cmd == ANDROID_RB_POWEROFF && ! strcmp (&command[len + 1], "userrequested" )) { // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED. // Run fsck once the file system is remounted in read-only mode. callback_on_ro_remount = unmount_and_fsck; } else if (cmd == ANDROID_RB_RESTART2) { reboot_target = &command[len + 1]; } } else if (command[len] != '\0' ) { ERROR( "powerctl: unrecognized reboot target '%s'\n" , &command[len]); return -EINVAL; } std::string timeout = property_get( "ro.build.shutdown_timeout" ); unsigned int delay = 0; if (android::base::ParseUint(timeout.c_str(), &delay) && delay > 0) { Timer t; // Ask all services to terminate. ServiceManager::GetInstance().ForEachService( [] (Service* s) { s->Terminate(); }); while (t.duration() < delay) { ServiceManager::GetInstance().ReapAnyOutstandingChildren(); int service_count = 0; ServiceManager::GetInstance().ForEachService( [&service_count] (Service* s) { // Count the number of services running. // Exclude the console as it will ignore the SIGTERM signal // and not exit. // Note: SVC_CONSOLE actually means "requires console" but // it is only used by the shell. if (s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) { service_count++; } }); if (service_count == 0) { // All terminable services terminated. We can exit early. break ; } // Wait a bit before recounting the number or running services. usleep(kTerminateServiceDelayMicroSeconds); } NOTICE( "Terminating running services took %.02f seconds" , t.duration()); } return android_reboot_with_callback(cmd, 0, reboot_target, callback_on_ro_remount); } |
2.3.看android_reboot_with_callback 这个回调
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | int android_reboot_with_callback( int cmd, int flags __unused, const char *arg, void (*cb_on_remount)( const struct mntent*)) { int ret; remount_ro(cb_on_remount); switch (cmd) { case ANDROID_RB_RESTART: ret = reboot(RB_AUTOBOOT); break ; case ANDROID_RB_POWEROFF: ret = reboot(RB_POWER_OFF); break ; case ANDROID_RB_RESTART2: ret = syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, arg); break ; default : ret = -1; } return ret; } int android_reboot( int cmd, int flags, const char *arg) { return android_reboot_with_callback(cmd, flags, arg, NULL); } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】