当前位置:   article > 正文

Android关机重启流程_android init关机流程

android init关机流程

一,概述

重启动作从按键触发中断,linux kernel层给Android framework层返回按键事件进入 framework层,再从 framework层到kernel层执行kernel层关机任务。当然还有非按键触发,比如shell 命令reboot,或者系统异常导致重启,或者直接调用PM的reboot()方法重启。

这里就先从PowerManager说起。


二,重启流程

  1. frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

  2. frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java

  3. frameworks/base/core/java/android/os/PowerManager.java


2.1 PM.reboot

[->PowerManager.java]

  1. public void reboot(String reason) {
  2. try {
  3. mService.reboot(false, reason, true); // 调用PowerManagerService->reboot
  4. } catch (RemoteException e) {
  5. throw e.rethrowFromSystemServer();
  6. }
  7. }


2.2 BinderService.reboot

[-> PowerManagerService.java]

  1. private final class BinderService extends IPowerManager.Stub {
  2. /**
  3. * Reboots the device.
  4. *
  5. * @param confirm If true, shows a reboot confirmation dialog.
  6. * @param reason The reason for the reboot, or null if none.
  7. * @param wait If true, this call waits for the reboot to complete and does not return.
  8. */
  9. @Override // Binder call
  10. public void reboot(boolean confirm, String reason, boolean wait) {
  11. //检查权限,reboot权限和reason是recovery时检查recovery权限
  12. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
  13. if (PowerManager.REBOOT_RECOVERY.equals(reason)
  14. || PowerManager.REBOOT_RECOVERY_UPDATE.equals(reason)) {
  15. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
  16. }
  17. final long ident = Binder.clearCallingIdentity();
  18. try {
  19. shutdownOrRebootInternal(HALT_MODE_REBOOT, confirm, reason, wait);
  20. } finally {
  21. Binder.restoreCallingIdentity(ident);
  22. }
  23. }
  24. }

此时参数为shutdownOrRebootInternal(false, false, reason, true);

  • shutdown=false:代表重启;
  • confirm=false:代表直接重启,无需弹出询问提示框;
  • reason 可能为recovery、bootloader、shutdown等
  • wait=true:代表阻塞等待重启操作完成。


2.3 PMS.shutdownOrRebootInternal

[-> PowerManagerService.java]

  1. private void shutdownOrRebootInternal(final @HaltMode int haltMode, final boolean confirm,
  2. final String reason, boolean wait) {
  3. ...
  4. Runnable runnable = new Runnable() {
  5. @Override
  6. public void run() {
  7. synchronized (this) {
  8. //根据haltMode 区分,reboot,shutdown,rebootsafemode
  9. if (haltMode == HALT_MODE_REBOOT_SAFE_MODE) {
  10. ShutdownThread.rebootSafeMode(getUiContext(), confirm);
  11. } else if (haltMode == HALT_MODE_REBOOT) {
  12. ShutdownThread.reboot(getUiContext(), reason, confirm);
  13. } else {
  14. ShutdownThread.shutdown(getUiContext(), reason, confirm);
  15. }
  16. }
  17. }
  18. };
  19. // ShutdownThread must run on a looper capable of displaying the UI.
  20. ShutdownThread必须运行在一个展现UI的looper
  21. Message msg = Message.obtain(UiThread.getHandler(), runnable);
  22. msg.setAsynchronous(true);
  23. UiThread.getHandler().sendMessage(msg);
  24. // PowerManager.reboot() is documented not to return so just wait for the inevitable.
  25. if (wait) {
  26. //等待ShutdownThread执行完毕
  27. synchronized (runnable) {
  28. while (true) {
  29. try {
  30. runnable.wait();
  31. } catch (InterruptedException e) {
  32. }
  33. }
  34. }
  35. }
  36. }
 


2.4 SDT.reboot

[->ShutdownThread.java]

  1. public static void reboot(final Context context, String reason, boolean confirm) {
  2. mReboot = true;
  3. mRebootSafeMode = false;
  4. mRebootHasProgressBar = false;
  5. mReason = reason;
  6. shutdownInner(context, confirm);
  7. }
mReboot为true则代表重启操作,值为false则代表关机操作。 


2.5 SDT.shutdownInner

[->ShutdownThread.java]

  1. private static void shutdownInner(final Context context, boolean confirm) {
  2. // ShutdownThread is called from many places, so best to verify here that the context passed
  3. // in is themed.
  4. context.assertRuntimeOverlayThemable();
  5. // ensure that only one thread is trying to power down.
  6. // any additional calls are just returned
  7. 确保只有唯一的线程执行shutdown/reboot操作
  8. synchronized (sIsStartedGuard) {
  9. if (sIsStarted) {
  10. Log.d(TAG, "Request to shutdown already running, returning.");
  11. return;
  12. }
  13. }
  14. final int longPressBehavior = context.getResources().getInteger(
  15. com.android.internal.R.integer.config_longPressOnPowerBehavior);
  16. final int resourceId = mRebootSafeMode
  17. ? com.android.internal.R.string.reboot_safemode_confirm
  18. : (longPressBehavior == 2
  19. ? com.android.internal.R.string.shutdown_confirm_question
  20. : com.android.internal.R.string.shutdown_confirm);
  21. /* longPressBehavior 并没有什么意义,只配置长按power键时弹窗power off选项还是语音助手。
  22. -- Control the behavior when the user long presses the power button.
  23. 0 - Nothing
  24. 1 - Global actions menu
  25. 2 - Power off (with confirmation)
  26. 3 - Power off (without confirmation)
  27. 4 - Go to voice assist
  28. */
  29. Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);
  30. if (confirm) {
  31. //这里是走弹出关机/重启提示框
  32. final CloseDialogReceiver closer = new CloseDialogReceiver(context);
  33. if (sConfirmDialog != null) {
  34. sConfirmDialog.dismiss();
  35. }
  36. sConfirmDialog = new AlertDialog.Builder(context)
  37. .setTitle(mRebootSafeMode
  38. ? com.android.internal.R.string.reboot_safemode_title
  39. : com.android.internal.R.string.power_off)
  40. .setMessage(resourceId)
  41. .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
  42. public void onClick(DialogInterface dialog, int which) {
  43. beginShutdownSequence(context);
  44. }
  45. })
  46. .setNegativeButton(com.android.internal.R.string.no, null)
  47. .create();
  48. closer.dialog = sConfirmDialog;
  49. sConfirmDialog.setOnDismissListener(closer);
  50. sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
  51. sConfirmDialog.show();
  52. } else {
  53. //本次confirm=false ,直接走这里
  54. beginShutdownSequence(context);
  55. }
  56. }
2.6 SDT.beginShutdownSequence
[->ShutdownThread.java]
  1. private static void beginShutdownSequence(Context context) {
  2. synchronized (sIsStartedGuard) {
  3. if (sIsStarted) {
  4. Log.d(TAG, "Shutdown sequence already running, returning.");
  5. return; //shutdown操作正在执行,则直接返回
  6. }
  7. sIsStarted = true;
  8. }
  9. sInstance.mProgressDialog = showShutdownDialog(context);
  10. sInstance.mContext = context;
  11. sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
  12. // make sure we never fall asleep again
  13. //确保系统不会进入休眠状态
  14. sInstance.mCpuWakeLock = null;
  15. try {
  16. sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
  17. PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");
  18. sInstance.mCpuWakeLock.setReferenceCounted(false);
  19. sInstance.mCpuWakeLock.acquire();
  20. } catch (SecurityException e) {
  21. Log.w(TAG, "No permission to acquire wake lock", e);
  22. sInstance.mCpuWakeLock = null;
  23. }
  24. // also make sure the screen stays on for better user experience
  25. //当处理亮屏状态,则获取亮屏锁,提供用户体验
  26. sInstance.mScreenWakeLock = null;
  27. if (sInstance.mPowerManager.isScreenOn()) {
  28. try {
  29. sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
  30. PowerManager.FULL_WAKE_LOCK, TAG + "-screen");
  31. sInstance.mScreenWakeLock.setReferenceCounted(false);
  32. sInstance.mScreenWakeLock.acquire();
  33. } catch (SecurityException e) {
  34. Log.w(TAG, "No permission to acquire wake lock", e);
  35. sInstance.mScreenWakeLock = null;
  36. }
  37. }
  38. if (SecurityLog.isLoggingEnabled()) {
  39. SecurityLog.writeEvent(SecurityLog.TAG_OS_SHUTDOWN);
  40. }
  41. // start the thread that initiates shutdown
  42. sInstance.mHandler = new Handler() {
  43. };
  44. //启动线程来执行shutdown初始化
  45. sInstance.start(); //接下来会启动shutdownThread.run
  46. }
2.7 SDT.run

[->ShutdownThread.java]

  1. /**
  2. * Makes sure we handle the shutdown gracefully.
  3. * Shuts off power regardless of radio state if the allotted time has passed.
  4. */
  5. public void run() {
  6. TimingsTraceLog shutdownTimingLog = newTimingsLog();
  7. shutdownTimingLog.traceBegin("SystemServerShutdown");
  8. metricShutdownStart();//用来统计关机时间
  9. metricStarted(METRIC_SYSTEM_SERVER);
  10. BroadcastReceiver br = new BroadcastReceiver() {
  11. @Override public void onReceive(Context context, Intent intent) {
  12. // We don't allow apps to cancel this, so ignore the result.
  13. actionDone();
  14. }
  15. };
  16. /*
  17. * Write a system property in case the system_server reboots before we
  18. * get to the actual hardware restart. If that happens, we'll retry at
  19. * the beginning of the SystemServer startup.
  20. */
  21. {
  22. String reason = (mReboot ? "1" : "0") + (mReason != null ? mReason : "");
  23. SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
  24. //设置属性"sys.shutdown.requested"的值为reason
  25. }
  26. /*
  27. * If we are rebooting into safe mode, write a system property
  28. * indicating so.
  29. */
  30. if (mRebootSafeMode) {
  31. //如果需要重启进入安全模式,则设置"persist.sys.safemode"=1
  32. SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
  33. }
  34. metricStarted(METRIC_SEND_BROADCAST);
  35. shutdownTimingLog.traceBegin("SendShutdownBroadcast");
  36. Log.i(TAG, "Sending shutdown broadcast...");
  37. // First send the high-level shut down broadcast.
  38. //1. 发送关机广播
  39. mActionDone = false;
  40. Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
  41. intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY);
  42. mContext.sendOrderedBroadcastAsUser(intent,
  43. UserHandle.ALL, null, br, mHandler, 0, null, null);
  44. final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
  45. synchronized (mActionDoneSync) {
  46. //循环等待,超时或者mActionDone都会结束该循环
  47. while (!mActionDone) {
  48. long delay = endTime - SystemClock.elapsedRealtime();
  49. if (delay <= 0) {
  50. Log.w(TAG, "Shutdown broadcast timed out");
  51. break;
  52. } else if (mRebootHasProgressBar) {
  53. int status = (int)((MAX_BROADCAST_TIME - delay) * 1.0 *
  54. BROADCAST_STOP_PERCENT / MAX_BROADCAST_TIME);
  55. sInstance.setRebootProgress(status, null);
  56. }
  57. try {
  58. mActionDoneSync.wait(Math.min(delay, ACTION_DONE_POLL_WAIT_MS));
  59. } catch (InterruptedException e) {
  60. }
  61. }
  62. }
  63. if (mRebootHasProgressBar) {//设置reboot进程条
  64. sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null);
  65. }
  66. shutdownTimingLog.traceEnd(); // SendShutdownBroadcast
  67. metricEnded(METRIC_SEND_BROADCAST);
  68. Log.i(TAG, "Shutting down activity manager...");
  69. shutdownTimingLog.traceBegin("ShutdownActivityManager");
  70. metricStarted(METRIC_AM);
  71. //2. 关闭AMS
  72. final IActivityManager am =
  73. IActivityManager.Stub.asInterface(ServiceManager.checkService("activity"));
  74. if (am != null) {
  75. try {
  76. am.shutdown(MAX_BROADCAST_TIME);
  77. } catch (RemoteException e) {
  78. }
  79. }
  80. if (mRebootHasProgressBar) {
  81. sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null);
  82. }
  83. shutdownTimingLog.traceEnd();// ShutdownActivityManager
  84. metricEnded(METRIC_AM);
  85. Log.i(TAG, "Shutting down package manager...");
  86. shutdownTimingLog.traceBegin("ShutdownPackageManager");
  87. metricStarted(METRIC_PM);
  88. //3. 关闭PMS
  89. final PackageManagerService pm = (PackageManagerService)
  90. ServiceManager.getService("package");
  91. if (pm != null) {
  92. pm.shutdown();
  93. }
  94. if (mRebootHasProgressBar) {
  95. sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
  96. }
  97. shutdownTimingLog.traceEnd(); // ShutdownPackageManager
  98. metricEnded(METRIC_PM);
  99. // Shutdown radios.
  100. //4. 关闭radios
  101. shutdownTimingLog.traceBegin("ShutdownRadios");
  102. metricStarted(METRIC_RADIOS);
  103. shutdownRadios(MAX_RADIO_WAIT_TIME);
  104. if (mRebootHasProgressBar) {
  105. sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);
  106. }
  107. shutdownTimingLog.traceEnd(); // ShutdownRadios
  108. metricEnded(METRIC_RADIOS);
  109. if (mRebootHasProgressBar) {
  110. sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);
  111. // If it's to reboot to install an update and uncrypt hasn't been
  112. // done yet, trigger it now.
  113. uncrypt();
  114. }
  115. shutdownTimingLog.traceEnd(); // SystemServerShutdown
  116. metricEnded(METRIC_SYSTEM_SERVER);
  117. saveMetrics(mReboot, mReason);
  118. // Remaining work will be done by init, including vold shutdown
  119. //关机剩下得动作由init完成,包括void,下一节分析
  120. rebootOrShutdown(mContext, mReboot, mReason);
  121. }
设置”sys.shutdown.requested”,记录下mRebootmReason。如果是进入安全模式,则”persist.sys.safemode=1”。

接下来主要关闭一些系统服务:

  1. 发送关机广播
  2. 关闭AMS
  3. 关闭PMS
  4. 关闭radios

之后就需要进入重启/关机流程,由init 进程处理。


2.7.1 AMS.shutdown

通过AMP.shutdown,通过binder调用到AMS.shutdown.

[->ActivityManagerService.java]

  1. @Override
  2. public boolean shutdown(int timeout) {
  3. 权限检测
  4. if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
  5. != PackageManager.PERMISSION_GRANTED) {
  6. throw new SecurityException("Requires permission "
  7. + android.Manifest.permission.SHUTDOWN);
  8. }
  9. boolean timedout = false;
  10. synchronized(this) {
  11. mShuttingDown = true;
  12. mStackSupervisor.prepareForShutdownLocked();
  13. //禁止WMS继续处理Event
  14. updateEventDispatchingLocked();
  15. //调用ASS处理shutdown操作
  16. timedout = mStackSupervisor.shutdownLocked(timeout);
  17. }
  18. mAppOpsService.shutdown();
  19. if (mUsageStatsService != null) {
  20. mUsageStatsService.prepareShutdown();
  21. }
  22. mBatteryStatsService.shutdown();
  23. synchronized (this) {
  24. mProcessStats.shutdownLocked();
  25. notifyTaskPersisterLocked(null, true);
  26. }
  27. return timedout;
  28. }

此处timeout为MAX_BROADCAST_TIME=10s


2.7.2 PMS.shutdown

  1. public void shutdown() {
  2. mPackageUsage.write(true);
  3. }

此处mPackageUsage数据类型是PMS的内部类PackageUsage。

  1. private class PackageUsage {
  2. void write(boolean force) {
  3. if (force) {
  4. writeInternal();
  5. return;
  6. }
  7. ...
  8. }
  9. }

对于force=true,接下来调用writeInternal方法。

  1. private class PackageUsage {
  2. private void writeInternal() {
  3. synchronized (mPackages) {
  4. synchronized (mFileLock) {
  5. //file是指/data/system/package-usage.list
  6. AtomicFile file = getFile();
  7. FileOutputStream f = null;
  8. try {
  9. //将原来的文件记录到package-usage.list.bak
  10. f = file.startWrite();
  11. BufferedOutputStream out = new BufferedOutputStream(f);
  12. FileUtils.setPermissions(file.getBaseFile().getPath(), 0640, SYSTEM_UID, PACKAGE_INFO_GID);
  13. StringBuilder sb = new StringBuilder();
  14. for (PackageParser.Package pkg : mPackages.values()) {
  15. if (pkg.mLastPackageUsageTimeInMills == 0) {
  16. continue;
  17. }
  18. sb.setLength(0);
  19. sb.append(pkg.packageName);
  20. sb.append(' ');
  21. sb.append((long)pkg.mLastPackageUsageTimeInMills);
  22. sb.append('\n');
  23. out.write(sb.toString().getBytes(StandardCharsets.US_ASCII));
  24. }
  25. out.flush();
  26. //将文件内容同步到磁盘,并删除.bak文件
  27. file.finishWrite(f);
  28. } catch (IOException e) {
  29. if (f != null) {
  30. file.failWrite(f);
  31. }
  32. Log.e(TAG, "Failed to write package usage times", e);
  33. }
  34. }
  35. }
  36. mLastWritten.set(SystemClock.elapsedRealtime());
  37. }
  38. }

/data/system/package-usage.list文件中每一行记录一条package及其上次使用时间(单位ms)。

由于IO操作的过程中,写入文件并非立刻就会真正意义上写入物理磁盘,以及在写入文件的过程中还可能中断或者出错等原因的考虑,采用的策略是先将老的文件package-usage.list,重命为增加后缀package-usage.list.bak;然后再往package-usage.list文件写入新的数据,数据写完之后再执行sync操作,将内存数据彻底写入物理磁盘,此时便可以安全地删除原来的package-usage.list.bak文件。


2.7.3 ST.shutdownRadios

[-> ShutdownThread.java]   

  1. private void shutdownRadios(final int timeout) {
  2. // If a radio is wedged, disabling it may hang so we do this work in another thread,
  3. // just in case.
  4. final long endTime = SystemClock.elapsedRealtime() + timeout;
  5. final boolean[] done = new boolean[1];
  6. Thread t = new Thread() {
  7. public void run() {
  8. TimingsTraceLog shutdownTimingsTraceLog = newTimingsLog();
  9. boolean radioOff;
  10. final ITelephony phone =
  11. ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
  12. try {
  13. radioOff = phone == null || !phone.needMobileRadioShutdown();
  14. if (!radioOff) {
  15. Log.w(TAG, "Turning off cellular radios...");
  16. metricStarted(METRIC_RADIO);
  17. phone.shutdownMobileRadios();
  18. }
  19. } catch (RemoteException ex) {
  20. Log.e(TAG, "RemoteException during radio shutdown", ex);
  21. radioOff = true;
  22. }
  23. Log.i(TAG, "Waiting for Radio...");
  24. long delay = endTime - SystemClock.elapsedRealtime();
  25. while (delay > 0) {
  26. if (mRebootHasProgressBar) {
  27. int status = (int)((timeout - delay) * 1.0 *
  28. (RADIO_STOP_PERCENT - PACKAGE_MANAGER_STOP_PERCENT) / timeout);
  29. status += PACKAGE_MANAGER_STOP_PERCENT;
  30. sInstance.setRebootProgress(status, null);
  31. }
  32. if (!radioOff) {
  33. try {
  34. radioOff = !phone.needMobileRadioShutdown();
  35. } catch (RemoteException ex) {
  36. Log.e(TAG, "RemoteException during radio shutdown", ex);
  37. radioOff = true;
  38. }
  39. if (radioOff) {
  40. Log.i(TAG, "Radio turned off.");
  41. metricEnded(METRIC_RADIO);
  42. shutdownTimingsTraceLog
  43. .logDuration("ShutdownRadio", TRON_METRICS.get(METRIC_RADIO));
  44. }
  45. }
  46. if (radioOff) {
  47. Log.i(TAG, "Radio shutdown complete.");
  48. done[0] = true;
  49. break;
  50. }
  51. SystemClock.sleep(RADIOS_STATE_POLL_SLEEP_MS);
  52. delay = endTime - SystemClock.elapsedRealtime();
  53. }
  54. }
  55. };
  56. t.start();
  57. try {
  58. t.join(timeout);
  59. } catch (InterruptedException ex) {
  60. }
  61. if (!done[0]) {
  62. Log.w(TAG, "Timed out waiting for Radio shutdown.");
  63. }
  64. }

创建新的线程来处理NFC, Radio and Bluetooth这些射频相关的模块的shutdown过程。每间隔500ms,check一次,直到nfc、bluetooth、radio全部关闭或者超时(MAX_RADIO_WAIT_TIME=12s)才会退出循环。


2.8 SDT.rebootOrShutdown

[-> ShutdownThread.java]

  1. /**
  2. * Do not call this directly. Use {@link #reboot(Context, String, boolean)}
  3. * or {@link #shutdown(Context, String, boolean)} instead.
  4. *
  5. * @param context Context used to vibrate or null without vibration
  6. * @param reboot true to reboot or false to shutdown
  7. * @param reason reason for reboot/shutdown
  8. */
  9. public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
  10. if (reboot) {
  11. Log.i(TAG, "Rebooting, reason: " + reason);
  12. PowerManagerService.lowLevelReboot(reason);
  13. Log.e(TAG, "Reboot failed, will attempt shutdown instead");
  14. reason = null;
  15. } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {
  16. // vibrate before shutting down
  17. Vibrator vibrator = new SystemVibrator(context);
  18. try {
  19. vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);
  20. } catch (Exception e) {
  21. // Failure to vibrate shouldn't interrupt shutdown. Just log it.
  22. Log.w(TAG, "Failed to vibrate during shutdown.", e);
  23. }
  24. // vibrator is asynchronous so we need to wait to avoid shutting down too soon.
  25. try {
  26. Thread.sleep(SHUTDOWN_VIBRATE_MS);
  27. } catch (InterruptedException unused) {
  28. }
  29. }
  30. // Shutdown power
  31. //关闭电源 [见流程2.10]
  32. Log.i(TAG, "Performing low-level shutdown...");
  33. PowerManagerService.lowLevelShutdown(reason);
  34. }

对于重启原因:

logcat会直接输出Rebooting, reason: ;

如果重启失败,则会输出Reboot failed; ,- 果无法重启,则会尝试直接关机。


2.9 PMS.lowLevelReboot

  1. public static void lowLevelShutdown(String reason) {
  2. if (reason == null) {
  3. reason = "";
  4. }
  5. SystemProperties.set("sys.powerctl", "shutdown," + reason);
  6. }
  7. /**
  8. * Low-level function to reboot the device. On success, this
  9. * function doesn't return. If more than 20 seconds passes from
  10. * the time a reboot is requested, this method returns.
  11. *
  12. * @param reason code to pass to the kernel (e.g. "recovery"), or null.
  13. */
  14. public static void lowLevelReboot(String reason) {
  15. if (reason == null) {
  16. reason = "";
  17. }
  18. // If the reason is "quiescent", it means that the boot process should proceed
  19. // without turning on the screen/lights.
  20. // The "quiescent" property is sticky, meaning that any number
  21. // of subsequent reboots should honor the property until it is reset.
  22. if (reason.equals(PowerManager.REBOOT_QUIESCENT)) {
  23. sQuiescent = true;
  24. reason = "";
  25. } else if (reason.endsWith("," + PowerManager.REBOOT_QUIESCENT)) {
  26. sQuiescent = true;
  27. reason = reason.substring(0,
  28. reason.length() - PowerManager.REBOOT_QUIESCENT.length() - 1);
  29. }
  30. if (reason.equals(PowerManager.REBOOT_RECOVERY)
  31. || reason.equals(PowerManager.REBOOT_RECOVERY_UPDATE)) {
  32. reason = "recovery";
  33. }
  34. if (sQuiescent) {
  35. // Pass the optional "quiescent" argument to the bootloader to let it know
  36. // that it should not turn the screen/lights on.
  37. reason = reason + ",quiescent";
  38. }
  39. SystemProperties.set("sys.powerctl", "reboot," + reason);
  40. try {
  41. Thread.sleep(20 * 1000L);
  42. } catch (InterruptedException e) {
  43. Thread.currentThread().interrupt();
  44. }
  45. Slog.wtf(TAG, "Unexpected return from lowLevelReboot!");
  46. }
  • 当reboot原因是“recovery”,则设置属性sys.powerctl=reboot,recovery
  • 当其他情况,则设置属性”sys.powerctl=reboot,[reason]”。
  • 当关机时,则设置属性”sys.powerctl=shutdown,[reason]”。

到此,framework层面的重启就流程基本介绍完了,那么接下来就要进入属性服务,即设置sys.powerctl=reboot,


三,总结

先用一句话总结,从最开始的PM.reboot(),经过层层调用,最终重启的核心方法等价于调用SystemProperties.set(“sys.powerctl”, “reboot,” + reason); 也就意味着调用下面命令,也能重启手机:

adb shell setprop sys.powerctl reboot

后续,还会进一步上面命令的执行流程,如何进入native,如何进入kernel来完成重启的,以及PM.reboot如何触发的。

四、回顾

先回顾下上部分得分析,从最开始的PM.reboot(),经过层层调用,最终调用

SystemProperties.set(“sys.powerctl”, “reboot,” + reason);


五、重启流程

 
  1. aosp/system/core/init/property_service.cpp

  2. aosp/system/core/init/reboot.cpp

  3. aosp/system/core/init/reboot_utils.cpp

  4. aosp/system/core/init/init.cpp

PM.reboot最终也就是setprop sys.powerctl,那么谁来监听sys.powerctl 值呢,肯定是init了,接下来就也就引入本节得重点,

init监听 sys.powerctl 处理关机后半部流程

5.1 HandlePropertySet

[->property_service.cpp]

  1. // This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
  2. uint32_t HandlePropertySet(const std::string& name, const std::string& value,
  3. const std::string& source_context, const ucred& cr, std::string* error) {
  4. ...
  5. // sys.powerctl is a special property that is used to make the device reboot. We want to log
  6. // any process that sets this property to be able to accurately blame the cause of a shutdown.
  7. //此时会记录到logcat中,那个进程设置sys.powerctl得以及原因
  8. if (name == "sys.powerctl") {
  9. std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
  10. std::string process_cmdline;
  11. std::string process_log_string;
  12. if (ReadFileToString(cmdline_path, &process_cmdline)) {
  13. // Since cmdline is null deliminated, .c_str() conveniently gives us just the process
  14. // path.
  15. process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
  16. }
  17. LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
  18. << process_log_string;
  19. }
  20. ...
  21. return PropertySet(name, value, error); //设置属性值
  22. }

5.2 HandlePropertySet

[->property_service.cpp]

  1. static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
  2. ...
  3. property_changed(name, value);// 会通知init property值改变
  4. return PROP_SUCCESS;
  5. }

5.3  property_changed

[->init.cpp]

  1. void property_changed(const std::string& name, const std::string& value) {
  2. // If the property is sys.powerctl, we bypass the event queue and immediately handle it.
  3. // This is to ensure that init will always and immediately shutdown/reboot, regardless of
  4. // if there are other pending events to process or if init is waiting on an exec service or
  5. // waiting on a property.
  6. // In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific
  7. // commands to be executed.
  8. if (name == "sys.powerctl") { //当init检测到某个进程设置 sys.powerctl时,会把do_shutdown 置true,init主循环会执行关机动作 见2.3节
  9. // Despite the above comment, we can't call HandlePowerctlMessage() in this function,
  10. // because it modifies the contents of the action queue, which can cause the action queue
  11. // to get into a bad state if this function is called from a command being executed by the
  12. // action queue. Instead we set this flag and ensure that shutdown happens before the next
  13. // command is run in the main init loop.
  14. // TODO: once property service is removed from init, this will never happen from a builtin,
  15. // but rather from a callback from the property service socket, in which case this hack can
  16. // go away.
  17. shutdown_command = value;
  18. do_shutdown = true;
  19. }
  20. if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value);
  21. if (waiting_for_prop) {
  22. if (wait_prop_name == name && wait_prop_value == value) {
  23. LOG(INFO) << "Wait for property took " << *waiting_for_prop;
  24. ResetWaitForProp();
  25. }
  26. }
  27. }

5.4 SecondStageMain

[->init.cpp]

  1. int SecondStageMain(int argc, char** argv) {
  2. ...
  3. while (true) {
  4. // By default, sleep until something happens.
  5. auto epoll_timeout = std::optional<std::chrono::milliseconds>{};
  6. if (do_shutdown && !shutting_down) {
  7. do_shutdown = false;
  8. if (HandlePowerctlMessage(shutdown_command)) { //执行关机重启流程
  9. shutting_down = true;
  10. }
  11. }
  12. if (!(waiting_for_prop || Service::is_exec_service_running())) {
  13. am.ExecuteOneCommand();
  14. }
  15. if (!(waiting_for_prop || Service::is_exec_service_running())) {
  16. if (!shutting_down) {
  17. auto next_process_action_time = HandleProcessActions();
  18. // If there's a process that needs restarting, wake up in time for that.
  19. if (next_process_action_time) {
  20. epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(
  21. *next_process_action_time - boot_clock::now());
  22. if (*epoll_timeout < 0ms) epoll_timeout = 0ms;
  23. }
  24. }
  25. // If there's more work to do, wake up again immediately.
  26. if (am.HasMoreCommands()) epoll_timeout = 0ms;
  27. }
  28. if (auto result = epoll.Wait(epoll_timeout); !result) {
  29. LOG(ERROR) << result.error();
  30. }
  31. }
  32. return 0;
  33. }


5.5 HandlePowerctlMessage

[->reboot.cpp]

  1. bool HandlePowerctlMessage(const std::string& command) {
  2. unsigned int cmd = 0;
  3. std::vector<std::string> cmd_params = Split(command, ",");
  4. std::string reboot_target = "";
  5. bool run_fsck = false;
  6. bool command_invalid = false;
  7. if (cmd_params.size() > 3) {
  8. command_invalid = true;
  9. } else if (cmd_params[0] == "shutdown") {
  10. cmd = ANDROID_RB_POWEROFF;
  11. if (cmd_params.size() == 2) {
  12. if (cmd_params[1] == "userrequested") {
  13. // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
  14. // Run fsck once the file system is remounted in read-only mode.
  15. run_fsck = true;
  16. } else if (cmd_params[1] == "thermal") {
  17. // Turn off sources of heat immediately.
  18. TurnOffBacklight();
  19. // run_fsck is false to avoid delay
  20. cmd = ANDROID_RB_THERMOFF;
  21. }
  22. }
  23. } else if (cmd_params[0] == "reboot") {
  24. cmd = ANDROID_RB_RESTART2;
  25. if (cmd_params.size() >= 2) {
  26. reboot_target = cmd_params[1];
  27. // adb reboot fastboot should boot into bootloader for devices not
  28. // supporting logical partitions.
  29. if (reboot_target == "fastboot" &&
  30. !android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
  31. reboot_target = "bootloader";
  32. }
  33. // When rebooting to the bootloader notify the bootloader writing
  34. // also the BCB.
  35. if (reboot_target == "bootloader") {
  36. std::string err;
  37. if (!write_reboot_bootloader(&err)) {//会把bootloader写到kernel,重启使用
  38. LOG(ERROR) << "reboot-bootloader: Error writing "
  39. "bootloader_message: "
  40. << err;
  41. }
  42. } else if (reboot_target == "sideload" || reboot_target == "sideload-auto-reboot" ||
  43. reboot_target == "fastboot") {
  44. std::string arg = reboot_target == "sideload-auto-reboot" ? "sideload_auto_reboot"
  45. : reboot_target;
  46. const std::vector<std::string> options = {
  47. "--" + arg,
  48. };
  49. std::string err;
  50. if (!write_bootloader_message(options, &err)) {//会把recovery写到kernel,重启使用
  51. LOG(ERROR) << "Failed to set bootloader message: " << err;
  52. return false;
  53. }
  54. reboot_target = "recovery";
  55. }
  56. // If there is an additional parameter, pass it along
  57. if ((cmd_params.size() == 3) && cmd_params[2].size()) {
  58. reboot_target += "," + cmd_params[2];
  59. }
  60. }
  61. } else {
  62. command_invalid = true;
  63. }
  64. if (command_invalid) {
  65. LOG(ERROR) << "powerctl: unrecognized command '" << command << "'";
  66. return false;
  67. }
  68. LOG(INFO) << "Clear action queue and start shutdown trigger";
  69. ActionManager::GetInstance().ClearQueue();
  70. // Queue shutdown trigger first
  71. ActionManager::GetInstance().QueueEventTrigger("shutdown");//处理init.rc中shutdown部分,依次关闭各个模块
  72. // Queue built-in shutdown_done
  73. auto shutdown_handler = [cmd, command, reboot_target, run_fsck](const BuiltinArguments&) {
  74. DoReboot(cmd, command, reboot_target, run_fsck); //reboot 流程核心,见下节
  75. return Success();
  76. };
  77. ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done");//设置中shutdown_done部分,shutdown执行完会执行DoReboot
  78. // Skip wait for prop if it is in progress
  79. ResetWaitForProp();
  80. // Clear EXEC flag if there is one pending
  81. for (const auto& s : ServiceList::GetInstance()) {
  82. s->UnSetExec();
  83. }
  84. return true;
  85. }


5.6 DoReboot

[->reboot.cpp]

  1. //* Reboot / shutdown the system.
  2. // cmd ANDROID_RB_* as defined in android_reboot.h
  3. // reason Reason string like "reboot", "shutdown,userrequested"
  4. // rebootTarget Reboot target string like "bootloader". Otherwise, it should be an
  5. // empty string.
  6. // runFsck Whether to run fsck after umount is done.
  7. //
  8. static void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
  9. bool runFsck) {
  10. Timer t;
  11. LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;
  12. // Ensure last reboot reason is reduced to canonical
  13. // alias reported in bootloader or system boot reason.
  14. size_t skip = 0;
  15. std::vector<std::string> reasons = Split(reason, ",");
  16. if (reasons.size() >= 2 && reasons[0] == "reboot" &&
  17. (reasons[1] == "recovery" || reasons[1] == "bootloader" || reasons[1] == "cold" ||
  18. reasons[1] == "hard" || reasons[1] == "warm")) {
  19. skip = strlen("reboot,");
  20. }
  21. property_set(LAST_REBOOT_REASON_PROPERTY, reason.c_str() + skip);//设置reboot 重启原因到persist.sys.boot.reason,重启后可以查看
  22. sync();
  23. bool is_thermal_shutdown = cmd == ANDROID_RB_THERMOFF;
  24. auto shutdown_timeout = 0ms;
  25. if (!SHUTDOWN_ZERO_TIMEOUT) {
  26. constexpr unsigned int shutdown_timeout_default = 6;
  27. constexpr unsigned int max_thermal_shutdown_timeout = 3;
  28. auto shutdown_timeout_final = android::base::GetUintProperty("ro.build.shutdown_timeout",
  29. shutdown_timeout_default);
  30. if (is_thermal_shutdown && shutdown_timeout_final > max_thermal_shutdown_timeout) {
  31. shutdown_timeout_final = max_thermal_shutdown_timeout;
  32. }
  33. shutdown_timeout = std::chrono::seconds(shutdown_timeout_final);
  34. }
  35. LOG(INFO) << "Shutdown timeout: " << shutdown_timeout.count() << " ms";
  36. // keep debugging tools until non critical ones are all gone.
  37. const std::set<std::string> kill_after_apps{"tombstoned", "logd", "adbd"};
  38. // watchdogd is a vendor specific component but should be alive to complete shutdown safely.
  39. const std::set<std::string> to_starts{"watchdogd"};
  40. for (const auto& s : ServiceList::GetInstance()) {
  41. if (kill_after_apps.count(s->name())) {
  42. s->SetShutdownCritical();
  43. } else if (to_starts.count(s->name())) {
  44. if (auto result = s->Start(); !result) {
  45. LOG(ERROR) << "Could not start shutdown 'to_start' service '" << s->name()
  46. << "': " << result.error();
  47. }
  48. s->SetShutdownCritical();
  49. } else if (s->IsShutdownCritical()) {
  50. // Start shutdown critical service if not started.
  51. if (auto result = s->Start(); !result) {
  52. LOG(ERROR) << "Could not start shutdown critical service '" << s->name()
  53. << "': " << result.error();
  54. }
  55. }
  56. }
  57. // remaining operations (specifically fsck) may take a substantial duration
  58. if (cmd == ANDROID_RB_POWEROFF || is_thermal_shutdown) {
  59. TurnOffBacklight();
  60. }
  61. Service* bootAnim = ServiceList::GetInstance().FindService("bootanim");
  62. Service* surfaceFlinger = ServiceList::GetInstance().FindService("surfaceflinger");
  63. if (bootAnim != nullptr && surfaceFlinger != nullptr && surfaceFlinger->IsRunning()) {
  64. // will not check animation class separately
  65. for (const auto& service : ServiceList::GetInstance()) {
  66. if (service->classnames().count("animation")) service->SetShutdownCritical();
  67. }
  68. }
  69. // optional shutdown step
  70. // 1. terminate all services except shutdown critical ones. wait for delay to finish
  71. //终止除shutdown关键之外的所有服务。 等待完成
  72. if (shutdown_timeout > 0ms) {
  73. LOG(INFO) << "terminating init services";
  74. // Ask all services to terminate except shutdown critical ones.
  75. for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
  76. if (!s->IsShutdownCritical()) s->Terminate();
  77. }
  78. int service_count = 0;
  79. // Only wait up to half of timeout here
  80. auto termination_wait_timeout = shutdown_timeout / 2;
  81. while (t.duration() < termination_wait_timeout) {
  82. ReapAnyOutstandingChildren();
  83. service_count = 0;
  84. for (const auto& s : ServiceList::GetInstance()) {
  85. // Count the number of services running except shutdown critical.
  86. // Exclude the console as it will ignore the SIGTERM signal
  87. // and not exit.
  88. // Note: SVC_CONSOLE actually means "requires console" but
  89. // it is only used by the shell.
  90. if (!s->IsShutdownCritical() && s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) {
  91. service_count++;
  92. }
  93. }
  94. if (service_count == 0) {
  95. // All terminable services terminated. We can exit early.
  96. break;
  97. }
  98. // Wait a bit before recounting the number or running services.
  99. std::this_thread::sleep_for(50ms);
  100. }
  101. LOG(INFO) << "Terminating running services took " << t
  102. << " with remaining services:" << service_count;
  103. }
  104. // minimum safety steps before restarting
  105. // 2. kill all services except ones that are necessary for the shutdown sequence.
  106. //2. 关闭所有得服务
  107. for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
  108. if (!s->IsShutdownCritical()) s->Stop();
  109. }
  110. SubcontextTerminate();
  111. ReapAnyOutstandingChildren();
  112. // 3. send volume shutdown to vold
  113. // 3. 关闭vold
  114. Service* voldService = ServiceList::GetInstance().FindService("vold");
  115. if (voldService != nullptr && voldService->IsRunning()) {
  116. ShutdownVold();
  117. voldService->Stop();
  118. } else {
  119. LOG(INFO) << "vold not running, skipping vold shutdown";
  120. }
  121. // logcat stopped here
  122. for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
  123. if (kill_after_apps.count(s->name())) s->Stop();
  124. }
  125. // 4. sync, try umount, and optionally run fsck for user shutdown
  126. //4. 同步,卸载分区,
  127. {
  128. Timer sync_timer;
  129. LOG(INFO) << "sync() before umount...";
  130. sync();
  131. LOG(INFO) << "sync() before umount took" << sync_timer;
  132. }
  133. UmountStat stat = TryUmountAndFsck(runFsck, shutdown_timeout - t.duration());
  134. // Follow what linux shutdown is doing: one more sync with little bit delay
  135. {
  136. Timer sync_timer;
  137. LOG(INFO) << "sync() after umount...";
  138. sync();
  139. LOG(INFO) << "sync() after umount took" << sync_timer;
  140. }
  141. if (!is_thermal_shutdown) std::this_thread::sleep_for(100ms);
  142. LogShutdownTime(stat, &t);
  143. // Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.
  144. RebootSystem(cmd, rebootTarget); //重启系统
  145. abort();
  146. }

5.7 RebootSystem

[->reboot_utils.cpp]

  1. void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
  2. LOG(INFO) << "Reboot ending, jumping to kernel";
  3. if (!IsRebootCapable()) {
  4. // On systems where init does not have the capability of rebooting the
  5. // device, just exit cleanly.
  6. exit(0);
  7. }
  8. //下面就是reboot的system call进入内核空间了:
  9. switch (cmd) {
  10. case ANDROID_RB_POWEROFF:
  11. reboot(RB_POWER_OFF); //调用reboot函数执行关机
  12. break;
  13. case ANDROID_RB_RESTART2:
  14. syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
  15. LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());//调用syscall函数执行重启
  16. break;
  17. case ANDROID_RB_THERMOFF:
  18. reboot(RB_POWER_OFF);//调用reboot函数执行重启
  19. break;
  20. }
  21. // In normal case, reboot should not return.
  22. PLOG(ERROR) << "reboot call returned";
  23. abort();
  24. }

六、总结

一句话总结,从 设置属性sys.powerctrl,最终重启调用libc库得  reboot或syscall, 也就意味这reboot下一步流程到达内核空间,

七、回顾

前面我们从最开始的PM.reboot(),经过层层调用,最终调用libc库得reboot和syscall,也正式开始从用户空间切到到内核空间。

八、内核重启流程

 
  1. kernel/reboot.c

  2. arch/arm64/kernel/process.c

8.1  SYSCALL_DEFINE4(reboot

内核空间reboot入口

  1. /*
  2. * Reboot system call: for obvious reasons only root may call it,
  3. * and even root needs to set up some magic numbers in the registers
  4. * so that some mistake won't make this reboot the whole machine.
  5. * You can also set the meaning of the ctrl-alt-del-key here.
  6. *
  7. * reboot doesn't sync: do that yourself before calling this.
  8. */
  9. SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
  10. void __user *, arg)
  11. {
  12. ...
  13. switch (cmd) {
  14. case LINUX_REBOOT_CMD_RESTART:
  15. kernel_restart(NULL);
  16. break;
  17. case LINUX_REBOOT_CMD_CAD_ON:
  18. C_A_D = 1;
  19. break;
  20. case LINUX_REBOOT_CMD_CAD_OFF:
  21. C_A_D = 0;
  22. break;
  23. case LINUX_REBOOT_CMD_HALT:
  24. kernel_halt();
  25. do_exit(0);
  26. panic("cannot halt");
  27. case LINUX_REBOOT_CMD_POWER_OFF: //power off
  28. kernel_power_off();
  29. do_exit(0);
  30. break;
  31. case LINUX_REBOOT_CMD_RESTART2: // reboot
  32. ret = strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1);
  33. if (ret < 0) {
  34. ret = -EFAULT;
  35. break;
  36. }
  37. buffer[sizeof(buffer) - 1] = '\0';
  38. kernel_restart(buffer);
  39. break;
  40. #ifdef CONFIG_KEXEC_CORE
  41. case LINUX_REBOOT_CMD_KEXEC:
  42. ret = kernel_kexec();
  43. break;
  44. #endif
  45. #ifdef CONFIG_HIBERNATION
  46. case LINUX_REBOOT_CMD_SW_SUSPEND:
  47. ret = hibernate();
  48. break;
  49. #endif
  50. default:
  51. ret = -EINVAL;
  52. break;
  53. }
  54. mutex_unlock(&reboot_mutex);
  55. return ret;
  56. }

8.2 kernel_restart

  1. /**
  2. * kernel_restart - reboot the system
  3. * @cmd: pointer to buffer containing command to execute for restart
  4. * or %NULL
  5. *
  6. * Shutdown everything and perform a clean reboot.
  7. * This is not safe to call in interrupt context.
  8. */
  9. void kernel_restart(char *cmd)
  10. {
  11. kernel_restart_prepare(cmd);
  12. void kernel_restart_prepare(char *cmd)
  13. /* 内核通知链,
  14. void kernel_restart_prepare(char *cmd)
  15. {
  16. blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); 锁定内核reboot通知链,我们可以监听reboot_notifier_list获取重启原因
  17. system_state = SYSTEM_RESTART;
  18. usermodehelper_disable();
  19. device_shutdown();
  20. }
  21. */
  22. migrate_to_reboot_cpu();
  23. syscore_shutdown();
  24. if (!cmd)// lastkmsg 可以搜索一下关键词获取重启原因
  25. pr_emerg("Restarting system\n");
  26. else
  27. pr_emerg("Restarting system with command '%s'\n", cmd);
  28. kmsg_dump(KMSG_DUMP_RESTART); // 打印堆栈
  29. machine_restart(cmd);
  30. }

8.3 machine_restart

  1. /*
  2. * Restart requires that the secondary CPUs stop performing any activity
  3. * while the primary CPU resets the system. Systems with multiple CPUs must
  4. * provide a HW restart implementation, to ensure that all CPUs reset at once.
  5. * This is required so that any code running after reset on the primary CPU
  6. * doesn't have to co-ordinate with other CPUs to ensure they aren't still
  7. * executing pre-reset code, and using RAM that the primary CPU's code wishes
  8. * to use. Implementing such co-ordination would be essentially impossible.
  9. */
  10. void machine_restart(char *cmd)
  11. {
  12. /* Disable interrupts first */
  13. //关闭中断
  14. local_irq_disable();
  15. smp_send_stop();
  16. /*
  17. * UpdateCapsule() depends on the system being reset via
  18. * ResetSystem().
  19. */
  20. if (efi_enabled(EFI_RUNTIME_SERVICES))
  21. efi_reboot(reboot_mode, NULL);
  22. /* Now call the architecture specific reboot code. */
  23. //现在调用体系结构特定的重启代码。由于我是在aosp上下载得代码,不包含具体芯片部分得操作,因此重启流程到此结束,
  24. if (arm_pm_restart)
  25. arm_pm_restart(reboot_mode, cmd);
  26. else
  27. do_kernel_restart(cmd);
  28. /*
  29. void do_kernel_restart(char *cmd)
  30. {
  31. atomic_notifier_call_chain(&restart_handler_list, reboot_mode, cmd);//通知所有注册restart_handler_list得模块
  32. }
  33. */
  34. /*
  35. * Whoops - the architecture was unable to reboot.
  36. */
  37. printk("Reboot failed -- System halted\n");
  38. while (1);
  39. }
  40. arm_pm_restart = mdesc->restart; //arm_pm_restart

针对插单卡,开数据业务情况下radio关机流程分析。

先贴一下ShutdownThread的log:

  1. 05-24 03:48:17.226 1354 1354 D ShutdownThread: Notifying thread to start shutdown longPressBehavior=1
  2. 05-24 03:48:17.298 1354 4205 I ShutdownThread: Sending shutdown broadcast...
  3. 05-24 03:48:17.422 1354 4205 I ShutdownThread: Shutting down activity manager...
  4. 05-24 03:48:17.500 1354 4205 I ShutdownThread: Shutting down package manager...
  5. 05-24 03:48:17.511 1354 4213 W ShutdownThread: Turning off cellular radios...
  6. 05-24 03:48:17.516 1354 4213 I ShutdownThread: Waiting for Radio...
  7. 05-24 03:48:18.422 1354 4213 I ShutdownThread: Radio turned off.
  8. 05-24 03:48:18.422 1354 4213 I ShutdownThread: Radio shutdown complete.
  9. 05-24 03:48:19.226 1354 4205 I ShutdownThread: Shutdown critical subsyslist is :modem :
  10. 05-24 03:48:19.226 1354 4205 I ShutdownThread: Waiting for a maximum of 10000ms
  11. 05-24 03:48:19.227 1354 4205 I ShutdownThread: Vendor subsystem(s) shutdown successful
  12. 05-24 03:48:19.734 1354 4205 I ShutdownThread: Performing low-level shutdown...

每一步的耗时时间:

  1. 05-24 03:48:17.422 1354 4205 D ShutdownTiming: SendShutdownBroadcast took to complete: 124ms
  2. 05-24 03:48:17.500 1354 4205 D ShutdownTiming: ShutdownActivityManager took to complete: 77ms
  3. 05-24 03:48:17.509 1354 4205 D ShutdownTiming: ShutdownPackageManager took to complete: 9ms
  4. 05-24 03:48:18.422 1354 4213 D ShutdownTiming: ShutdownRadio took to complete: 911ms
  5. 05-24 03:48:18.422 1354 4205 D ShutdownTiming: ShutdownRadios took to complete: 914ms
  6. //在rebootorShutdown函数前的每一步耗时
  7. 05-24 03:48:18.422 1354 4205 D ShutdownTiming: SystemServerShutdown took to complete: 1133ms

ShutdownThread.shutdown()
Notifying thread to start shutdown longPressBehavior=1 打印出现在shutdownInner函数中。当重启或关机时会分别触发shutdown或reboot函数。最终都会走到shutdownInner函数。shutdownInner函数会触发ShutdownThread 中static实例的start函数。因为其继承自thread,所以会触发run函数。

关机画面
shutdownInner中调用beginShutdownSequence
确保此函数只进入一次。
在这里插入图片描述
接着调用showShutdwonDialog()判断是否去显示关机动画。

 在这里插入图片描述
然后触发ShutdownThread.run()

 

在这里插入图片描述

ShutdownThread.run()

发送广播

 在这里插入图片描述
注意其在调用sendOrderedBraodcastAsUser的参数br,即在发送广播的同时,br会成为此广播的最后一个接受者。br的作用是为了确保所有上层应用都收到关机广播再走下面的流程。

 

等待广播发送完毕

br最后收到广播,将mActionDone设置为true。 run函数中轮询mActionDone,为true时退出,走下面的流程。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

关闭ActivityManager和PackageManager

在这里插入图片描述

关闭radio

 调用shutdownRadio函数

在这里插入图片描述
shutdownRadio函数启动一个thread执行关闭radio的操作。

shutdownRadio

首先判断radio是否需要shutdown,若是则调用phone.shutdownMobileRadios来关闭radio。

 在这里插入图片描述
然后轮询needMobileRadioShutdown()状态。如果radiooff则走下一步。

 

在这里插入图片描述

关闭radio

 

接下来针对关闭radio 重点分析一下流程。

判断是否需要关闭radio

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

 

从上面截图可以知道,就是判断RIL.java的mState变量值。如果是RADIO_UNAVAILABLE则认为不需要关机,否则需要关机。

mState状态如何转变为UNAVAILABLE
有两个情况会变为UNAVAILBALBE:

radioIndication.java 被通知radioStateChanged时
在这里插入图片描述
对应log:

  1. 05-24 03:48:19.179 2128 2287 D RILJ : [UNSL]< UNSOL_RESPONSE_RADIO_STATE_CHANGED radioStateChanged: RADIO_UNAVAILABLE [SUB0]
  2. 05-24 03:48:19.184 2128 2287 D RILJ : [UNSL]< UNSOL_RESPONSE_RADIO_STATE_CHANGED radioStateChanged: RADIO_UNAVAILABLE [SUB1]

RIL_REQUEST_SHUTDOWN请求返回时

详细流程如下:
RILC 返回response时通过RadioResponse的对应接口返回。
对应RIL_REQUEST_SHUTDOWN是requestShutdownResponse().

在这里插入图片描述
在responseVoid函数中,先通过RIL.java的processResponse做一些处理。
然后通过sendMessageResponse通知AP上层的发送方,命令执行情况。
最后通过processResponseDone来打印收到的response信息

 在这里插入图片描述

 在这里插入图片描述
对应log:

 

  1. 05-24 03:48:18.120 2128 2128 D RILJ : [4151]> RIL_REQUEST_SHUTDOWN [SUB1]
  2. 05-24 03:48:18.124 2128 2128 D RILJ : [4152]> RIL_REQUEST_SHUTDOWN [SUB1]
  3. 05-24 03:48:18.134 2128 2287 D RILJ : [4151]< RIL_REQUEST_SHUTDOWN [SUB1]
  4. 05-24 03:48:18.149 2128 2287 D RILJ : [4152]< RIL_REQUEST_SHUTDOWN [SUB1]
  5. 05-24 03:48:18.212 2128 2128 D RILJ : [4153]> RIL_REQUEST_SHUTDOWN [SUB0]
  6. 05-24 03:48:18.214 2128 2128 D RILJ : [4154]> RIL_REQUEST_SHUTDOWN [SUB0]
  7. 05-24 03:48:18.374 2128 2287 D RILJ : [4153]< RIL_REQUEST_SHUTDOWN [SUB0]
  8. 05-24 03:48:19.108 2128 2287 D RILJ : [4154]< RIL_REQUEST_SHUTDOWN [SUB0]

关闭radio

在这里插入图片描述

 

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
对应log:

 

  1. 05-24 03:48:17.513 SST : [0] mDeviceShuttingDown=true, mDesiredPowerState=false, getRadioState=RADIO_ON, mPowerOffDelayNeed=true, mAlarmSwitch=false, mRadioDisabledByCarrier=false
  2. 05-24 03:48:17.515 SST : [1] mDeviceShuttingDown=true, mDesiredPowerState=false, getRadioState=RADIO_ON, mPowerOffDelayNeed=true, mAlarmSwitch=false, mRadioDisabledByCarrier=false

当插单卡,开数据业务,接着调用poweOffRadioSafely()

开数据业务情况下poweOffRadioSafely流程

在这里插入图片描述
调用流程如下:

 

ShutDownThread.shutdownRadios()-》phone.shutdownMobileRadios (ITelephone–>PhoneInterfaceManager)->PhoneInterfaceManager.shutdownRadiosUsingID()->Phone.shutdownRadio()->ServiceStateTracker.requestShutDown()->setPowerStateToDesired()->powerOffRadioSafely->DcTracker.clearUpAllConnections() 同事registerForAllDataDisconnected(EVENT_All_DATA_DISCONNECTED)

即使 插单卡,只要有数据业务,两个sub都会调用dcTracker.cleanUpAllConnections()。 无卡的那个sub还会关注EVENT_All_DATA_DISCONNECTED。
在cleanUpAllConnections()中,针对每一个APN调用一次cleanUpConnection。mDisconnectPendingCount 在cleanUpConnection ()中会自加1.

在这里插入图片描述

 cleanUpConnection 中tearDown apn。 mDisconnectPendingCount 自加1. 关闭成功后收到EVENT_DISCONNECT_DONE.
在这里插入图片描述

 

无卡sub 的cleanUpAllConnections中,直接调用notifyAllDataDisconnected().
数据业务sub data断开后触发onDisconnectDone,mDisconnectPendingCount 减1至0后,也调用notifyAllDataDisconnected。

数据业务卡是在onDisconnectDone中触发processPendingRadioPowerOffAfterDataOff().进而调用hangupAndPowerOff。
非数据业务卡,或无卡sub,在SST(serviceStateTracker) 处理EVENT_ALL_DATA_DISCONNTECD时调用hangupAndPowerOff


在这里插入图片描述

 无卡sub等待EVENT_All_DATA_DISCONNECTED
在这里插入图片描述

 log:

  1. //不插卡,或无数据业务的卡。等待另一张卡关数据业务
  2. 05-24 03:48:17.516 2128 2412 D SST : [1] Data is active on DDS. Wait for all data disconnect
  3. //两个sub 都等待30s,都会设置mPendingPowerOffAfterDataOff
  4. 05-24 03:48:17.514 2128 2412 D SST : [0] Wait upto 30s for data to disconnect, then turn off radio.
  5. 05-24 03:48:17.516 2128 2412 D SST : [1] Wait upto 30s for data to disconnect, then turn off radio.
  6. //两个sub,一个无卡mDisconnectPendingCount 为0,一个volte和data两个apn,所以mDisconnectPendingCount = 2
  7. 05-24 03:48:17.515 2128 2128 D QtiDCT : [0]cleanUpConnection: tearing down using gen#1apnContext={mApnType=default mState=CONNECTED mWaitingApns={[[ApnSettingV5] APN_NAME_CMNET, 2463, 46002, cmnet, , , , , , -1, default | net | supl, IPV4V6, IPV4V6, true, 0, 0, 0, false, 0, 0, 0, 0, , , false, 0, 0]} mApnSetting={[ApnSettingV5] APN_NAME_CMNET, 2463, 46002, cmnet, , , , , , -1, default | net | supl, IPV4V6, IPV4V6, true, 0, 0, 0, false, 0, 0, 0, 0, , , false, 0, 0} mReason=radioTurnedOff mDataEnabled=true mDependencyMet=true}
  8. 05-24 03:48:17.515 2128 2128 D QtiDCT : [0]cleanUpConnection: tearing down using gen#1apnContext={mApnType=ims mState=CONNECTED mWaitingApns={[[ApnSettingV5] China Mobile (IMS), 2466, 46002, ims, , , , , , -1, ims, IPV4V6, IPV4V6, true, 0, 0, 2, true, 1023, 0, 300, 0, , , false, 0, 0]} mApnSetting={[ApnSettingV5] China Mobile (IMS), 2466, 46002, ims, , , , , , -1, ims, IPV4V6, IPV4V6, true, 0, 0, 2, true, 1023, 0, 300, 0, , , false, 0, 0} mReason=radioTurnedOff mDataEnabled=true mDependencyMet=true}
  9. 05-24 03:48:17.523 2128 2128 D QtiDCT : [0]cleanUpConnection: mDisconnectPendingCount = 2
  10. 05-24 03:48:17.535 2128 2128 D QtiDCT : [1]cleanUpConnection: mDisconnectPendingCount = 0
  11. //使能数据业务的sub log,分别关闭数据和volte的apn
  12. //QtiDcTracker.java继承自DcTracker.java,由于多态,调用基本是DcTracker的函数
  13. 05-24 03:48:17.568 2128 2128 D QtiDCT : [0]getValidApnContext (onDisconnectDone) on {mApnType=ims mState=DISCONNECTING mWaitingApns={[[ApnSettingV5] China Mobile (IMS), 2466, 46002, ims, , , , , , -1, ims, IPV4V6, IPV4V6, true, 0, 0, 2, true, 1023, 0, 300, 0, , , false, 0, 0]} mApnSetting={[ApnSettingV5] China Mobile (IMS), 2466, 46002, ims, , , , , , -1, ims, IPV4V6, IPV4V6, true, 0, 0, 2, true, 1023, 0, 300, 0, , , false, 0, 0} mReason=radioTurnedOff mDataEnabled=true mDependencyMet=true} got 1 vs 1
  14. 05-24 03:48:17.568 2128 2128 D QtiDCT : [0]onDisconnectDone: EVENT_DISCONNECT_DONE apnContext={mApnType=ims mState=DISCONNECTING mWaitingApns={[[ApnSettingV5] China Mobile (IMS), 2466, 46002, ims, , , , , , -1, ims, IPV4V6, IPV4V6, true, 0, 0, 2, true, 1023, 0, 300, 0, , , false, 0, 0]} mApnSetting={[ApnSettingV5] China Mobile (IMS), 2466, 46002, ims, , , , , , -1, ims, IPV4V6, IPV4V6, true, 0, 0, 2, true, 1023, 0, 300, 0, , , false, 0, 0} mReason=radioTurnedOff mDataEnabled=true mDependencyMet=true}
  15. 05-24 03:48:17.583 2128 2128 D QtiDCT : [0]onDisconnectDone: not retrying
  16. 05-24 03:48:17.600 2128 2128 D QtiDCT : [0]getValidApnContext (onDisconnectDone) on {mApnType=default mState=DISCONNECTING mWaitingApns={[[ApnSettingV5] APN_NAME_CMNET, 2463, 46002, cmnet, , , , , , -1, default | net | supl, IPV4V6, IPV4V6, true, 0, 0, 0, false, 0, 0, 0, 0, , , false, 0, 0]} mApnSetting={[ApnSettingV5] APN_NAME_CMNET, 2463, 46002, cmnet, , , , , , -1, default | net | supl, IPV4V6, IPV4V6, true, 0, 0, 0, false, 0, 0, 0, 0, , , false, 0, 0} mReason=radioTurnedOff mDataEnabled=true mDependencyMet=true} got 1 vs 1
  17. 05-24 03:48:17.600 2128 2128 D QtiDCT : [0]onDisconnectDone: EVENT_DISCONNECT_DONE apnContext={mApnType=default mState=DISCONNECTING mWaitingApns={[[ApnSettingV5] APN_NAME_CMNET, 2463, 46002, cmnet, , , , , , -1, default | net | supl, IPV4V6, IPV4V6, true, 0, 0, 0, false, 0, 0, 0, 0, , , false, 0, 0]} mApnSetting={[ApnSettingV5] APN_NAME_CMNET, 2463, 46002, cmnet, , , , , , -1, default | net | supl, IPV4V6, IPV4V6, true, 0, 0, 0, false, 0, 0, 0, 0, , , false, 0, 0} mReason=radioTurnedOff mDataEnabled=true mDependencyMet=true}
  18. 05-24 03:48:17.606 2128 2128 D SST : [0] Process pending request to turn radio off.
  19. 05-24 03:48:17.608 2128 2128 D QtiDCT : [0]onDisconnectDone: radio will be turned off, no retries
  20. //数据业务sub调用hangupAndPowerOff
  21. 05-24 03:48:17.606 2128 2128 D SST : [0] Process pending request to turn radio off.
  22. //非数据业务sub调用hangupAndPowerOff
  23. 05-24 03:48:17.610 2128 2128 D SST : [1] EVENT_ALL_DATA_DISCONNECTED, turn radio off now.

hangupAndPoweroff

最终是向ril发送RIL_REQUEST_RADIO_POWER
在这里插入图片描述

 

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
qcril_qmi_nas_request_power
在这里插入图片描述

对应log:

  1. 05-24 03:48:17.608 2128 2128 D RILJ : [4127]> RADIO_POWER on = false [SUB0]
  2. 05-24 03:48:17.612 2128 2128 D RILJ : [4128]> RADIO_POWER on = false [SUB1]
  3. 05-24 03:48:17.997 2128 2287 D RILJ : [4128]< RADIO_POWER [SUB1]
  4. 05-24 03:48:18.003 2128 2287 D RILJ : [4127]< RADIO_POWER [SUB0]
  5. 05-24 03:48:18.117 2128 2128 D SST : [1] EVENT_RADIO_POWER_OFF_DONE
  6. 05-24 03:48:18.210 2128 2128 D SST : [0] EVENT_RADIO_POWER_OFF_DONE

成功power radio后的流程:

SST会收到EVENT_RADIO_POWER_OFF_DONE。
在这里插入图片描述

 调用requestShutDown。又会走到ril。
在这里插入图片描述

 
在这里插入图片描述
在这里插入图片描述

里面涉及到一个shutdown的状态机。
在这里插入图片描述
这个状态机如何触发ril内部模块shutdown呢?以内部的关卡状态为例。

在这里插入图片描述

在这里将UimCardPowerReqMsg命令发出。
在这里插入图片描述
最终UimModule模块处理。

 
在这里插入图片描述

 在这里插入图片描述
最终发送出去,由UimModemEndpointModule处理:

 
在这里插入图片描述
在这里插入图片描述

最终通过qmi发送QMI_UIM_POWER_DOWN_REQ命令给modem。真是一个弯弯曲曲的流程。
在这里插入图片描述

 

在这里插入图片描述

RIL_REQUEST_SHUTDOWN执行完毕

 不管ril内部的复杂流程。当执行完后,会通知上层么?
从代码看,调用是没有提供参数。所以不会通知上层。但是后续radio状态机会发生变化。
在这里插入图片描述

 并且RIL_REQUEST_SHUTDOWN 处理完毕后 ,RIl.java 会处理。也会将Radio状态设置为unavailable。所以发送shutdown后,终端在radio还没有到unavailabe时,ril层就提前转到unavialable了。
在这里插入图片描述

 

  1. 05-24 03:48:18.120 2128 2128 D RILJ : [4151]> RIL_REQUEST_SHUTDOWN [SUB1]
  2. 05-24 03:48:18.124 2128 2128 D RILJ : [4152]> RIL_REQUEST_SHUTDOWN [SUB1]
  3. 05-24 03:48:18.134 2128 2287 D RILJ : [4151]< RIL_REQUEST_SHUTDOWN [SUB1]
  4. 05-24 03:48:18.149 2128 2287 D RILJ : [4152]< RIL_REQUEST_SHUTDOWN [SUB1]
  5. 05-24 03:48:18.212 2128 2128 D RILJ : [4153]> RIL_REQUEST_SHUTDOWN [SUB0]
  6. 05-24 03:48:18.214 2128 2128 D RILJ : [4154]> RIL_REQUEST_SHUTDOWN [SUB0]
  7. 05-24 03:48:18.374 2128 2287 D RILJ : [4153]< RIL_REQUEST_SHUTDOWN [SUB0]
  8. // radio state 变为 unavialable是 03:48:19.175,但是由于RIL_REQUEST_SHUTDOWN 03:48:18.374时已经都执行完了。所以ShutdownThread的轮询认为radio turned off。在shutdownRadios中出现如下打印
  9. 05-24 03:48:18.422 1354 4213 I ShutdownThread: Radio turned off.
  10. 05-24 03:48:18.422 1354 4213 I ShutdownThread: Radio shutdown complete.
  11. 05-24 03:48:19.108 2128 2287 D RILJ : [4154]< RIL_REQUEST_SHUTDOWN [SUB0]
  12. 05-24 03:48:18.001 1208 1269 D RILC : radioStateChangedInd: radioState 0
  13. 05-24 03:48:18.006 1193 1255 D RILC : radioStateChangedInd: radioState 0
  14. 05-24 03:48:19.175 1193 1255 D RILC : radioStateChangedInd: radioState 1
  15. 05-24 03:48:19.182 1208 1269 D RILC : radioStateChangedInd: radioState 1

最后一步 rebootOrShutdown

在这里插入图片描述

 QCRIL执行RIL_REQUEST_SHUTDOWN 的内部状态机
这个内部状态机曾经发送过变化。之所以关注到这个代码的改动,是因为比较不同机器的ShutdownTiming: ShutdownRadio took to complete的时间打印在终端同样插卡开数据volte的情况下,稳定的存在差异。最后发现主要差异在RIL_REQUEST_SHUTDOWN 执行时间不同。新平台机器的时间要长。 最后对比了日志,发现在状态2至状态3时,新平台有500ms差异,而老平台没有。看了代码才发现,状态名变了,等待的事件变了(从ims service的ims-reg状态,到ims pdp connected状态)。 这个变化是为了确保ims从网络侧de-registered。

在这里插入图片描述
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/空白诗007/article/detail/945177
推荐阅读
相关标签
  

闽ICP备14008679号