跳转至

恢复模式

0 结论: Demo应该如何写

  • Demo应该在1分钟内至少挂掉5次
  • RescueParty应该合入修复代码, 否则不能进入recovery(否则mayObservePackage返回失败)
  • Demo应该是android:persistent="true"的, (否则mayObservePackage返回失败)
  • 不要存在adb连接, 否则判断是用户在调试.(isDisabled判断成功, 用户调试)

Demo代码:

    <application
        ...
        android:name=".CrashApp"
        android:persistent="true">
public class CrashApp extends Application {
    boolean flag = true;
    @Override
    public final void onCreate() {
        super.onCreate();

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.e("==>", "1/0 = " + (flag ? 1/0 : 1/1) );
            }
        }, 100);
    }
}

1 监听SystemServer崩溃

SystemServer中, RescueParty注册监听器, 并启动PackageWatchdog, 如果每次10mssystem server发生错误, 连续发生了大于等于5次, 则执行executeBootLoopMitigation 如果APP发生了糟糕的崩溃, 则执行execute

http://www.aospxref.com/android-11.0.0_r21/xref/frameworks/base/services/java/com/android/server/SystemServer.java


710      private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
711          t.traceBegin("startBootstrapServices");
...
802          // Bring up recovery system in case a rescue party needs a reboot
803          t.traceBegin("StartRecoverySystemService");
804          mSystemServiceManager.startService(RecoverySystemService.Lifecycle.class);
805          t.traceEnd();
806  
807          // Now that we have the bare essentials of the OS up and running, take
808          // note that we just booted, which might send out a rescue party if
809          // we're stuck in a runtime restart loop.
810          RescueParty.registerHealthObserver(mSystemContext);
811          PackageWatchdog.getInstance(mSystemContext).noteBoot();

1013      /**
1014       * Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.
1015       */
1016      private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
1017          t.traceBegin("startOtherServices");

1121              t.traceBegin("InstallSystemProviders");
1122              mActivityManagerService.installSystemProviders();
1123              // Now that SettingsProvider is ready, reactivate SQLiteCompatibilityWalFlags
1124              SQLiteCompatibilityWalFlags.reset();
1125              t.traceEnd();

http://www.aospxref.com/android-11.0.0_r21/xref/frameworks/base/services/core/java/com/android/server/PackageWatchdog.java

123      static final int DEFAULT_BOOT_LOOP_TRIGGER_COUNT = 5;
124      static final long DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS = TimeUnit.MINUTES.toMillis(10);

206      PackageWatchdog(Context context, AtomicFile policyFile, Handler shortTaskHandler,
207              Handler longTaskHandler, ExplicitHealthCheckController controller,
208              ConnectivityModuleConnector connectivityModuleConnector, SystemClock clock) {
209          mContext = context;
210          mPolicyFile = policyFile;
211          mShortTaskHandler = shortTaskHandler;
212          mLongTaskHandler = longTaskHandler;
213          mHealthCheckController = controller;
214          mConnectivityModuleConnector = connectivityModuleConnector;
215          mSystemClock = clock;
216          mNumberOfNativeCrashPollsRemaining = NUMBER_OF_NATIVE_CRASH_POLLS;
217          mBootThreshold = new BootThreshold(DEFAULT_BOOT_LOOP_TRIGGER_COUNT,
218                  DEFAULT_BOOT_LOOP_TRIGGER_WINDOW_MS);
219          loadFromFile();
220          sPackageWatchdog = this;
221      }
222  

442      /**
443       * Called when the system server boots. If the system server is detected to be in a boot loop,
444       * query each observer and perform the mitigation action with the lowest user impact.
445       */
446      public void noteBoot() {
447          synchronized (mLock) {
448              if (mBootThreshold.incrementAndTest()) {
449                  mBootThreshold.reset();
450                  PackageHealthObserver currentObserverToNotify = null;
451                  int currentObserverImpact = Integer.MAX_VALUE;
452                  for (int i = 0; i < mAllObservers.size(); i++) {
453                      final ObserverInternal observer = mAllObservers.valueAt(i);
454                      PackageHealthObserver registeredObserver = observer.registeredObserver;
455                      if (registeredObserver != null) {
456                          int impact = registeredObserver.onBootLoop();
457                          if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE
458                                  && impact < currentObserverImpact) {
459                              currentObserverToNotify = registeredObserver;
460                              currentObserverImpact = impact;
461                          }
462                      }
463                  }
464                  if (currentObserverToNotify != null) {
465                      currentObserverToNotify.executeBootLoopMitigation();
466                  }
467              }
468          }
469      }
     /**
1463       * Handles the thresholding logic for system server boots.
1464       */
1465      static class BootThreshold {
1466  
1467          private final int mBootTriggerCount;
1468          private final long mTriggerWindow;
1469  
1470          BootThreshold(int bootTriggerCount, long triggerWindow) {
1471              this.mBootTriggerCount = bootTriggerCount;
1472              this.mTriggerWindow = triggerWindow;
1473          }

1498          /** Increments the boot counter, and returns whether the device is bootlooping. */
1499          public boolean incrementAndTest() {
1500              final long now = android.os.SystemClock.elapsedRealtime();
1501              if (now - getStart() < 0) {
1502                  Slog.e(TAG, "Window was less than zero. Resetting start to current time.");
1503                  setStart(now);
1504              }
1505              final long window = now - getStart();
1506              if (window >= mTriggerWindow) {
1507                  setCount(1);
1508                  setStart(now);
1509                  return false;
1510              } else {
1511                  int count = getCount() + 1;
1512                  setCount(count);
1513                  EventLogTags.writeRescueNote(Process.ROOT_UID, count, window);
1514                  return count >= mBootTriggerCount;
1515              }
1516          }

2 监听APP发生了糟糕的崩溃

onPackagesReady完成加载配置(updateConfigs), 如果符合判断条件, 则通过函数execute执行回调的接口:

配置文件:

spm8675p1_64:/ # cat /data/system/package-watchdog.xml
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<package-watchdog version="1">
<observer name="rescue-party-observer" />
<observer name="rollback-observer" />
</package-watchdog>

758      /**
759       * Syncs the state of the observers.
760       *
761       * <p> Prunes all observers, saves new state to disk, syncs health check requests with the
762       * health check service and schedules the next state sync.
763       */
764      private void syncState(String reason) {
765          synchronized (mLock) {
766              Slog.i(TAG, "Syncing state, reason: " + reason);
767              pruneObserversLocked();
768  
769              saveToFileAsync();
770              syncRequestsAsync();
771  
772              // Done syncing state, schedule the next state sync
773              scheduleNextSyncStateLocked();
774          }
775      }

191      private PackageWatchdog(Context context) {
192          // Needs to be constructed inline
193          this(context, new AtomicFile(
194                          new File(new File(Environment.getDataDirectory(), "system"),
195                                  "package-watchdog.xml")),

968      /**
969       * Persists mAllObservers to file. Threshold information is ignored.
970       */
971      private boolean saveToFile() {
972          Slog.i(TAG, "Saving observer state to file");
973          synchronized (mLock) {
974              FileOutputStream stream;
975              try {
976                  stream = mPolicyFile.startWrite();
977              } catch (IOException e) {
978                  Slog.w(TAG, "Cannot update monitored packages", e);
979                  return false;
980              }
981  
982              try {
983                  XmlSerializer out = new FastXmlSerializer();
...

291      public void startObservingHealth(PackageHealthObserver observer, List<String> packageNames,
292              long durationMs) {
293          if (packageNames.isEmpty()) {
294              Slog.wtf(TAG, "No packages to observe, " + observer.getName());
295              return;
296          }
297          if (durationMs < 1) {
298              Slog.wtf(TAG, "Invalid duration " + durationMs + "ms for observer "
299                      + observer.getName() + ". Not observing packages " + packageNames);
300              durationMs = DEFAULT_OBSERVING_DURATION_MS;
301          }
302  
303          List<MonitoredPackage> packages = new ArrayList<>();
304          for (int i = 0; i < packageNames.size(); i++) {
305              // Health checks not available yet so health check state will start INACTIVE
306              MonitoredPackage pkg = newMonitoredPackage(packageNames.get(i), durationMs, false);
307              if (pkg != null) {
308                  packages.add(pkg);
309              }
310          }

1213      MonitoredPackage newMonitoredPackage(
1214              String name, long durationMs, boolean hasPassedHealthCheck) {
1215          return newMonitoredPackage(name, durationMs, Long.MAX_VALUE, hasPassedHealthCheck);
1216      }

1218      MonitoredPackage newMonitoredPackage(String name, long durationMs, long healthCheckDurationMs,
1219              boolean hasPassedHealthCheck) {
1220          VersionedPackage pkg = getVersionedPackage(name);
1221          if (pkg == null) {
1222              return null;
1223          }
1224          return new MonitoredPackage(pkg, durationMs, healthCheckDurationMs, hasPassedHealthCheck);
1225      }

1234      class MonitoredPackage {
1235          private final VersionedPackage mPackage;

1421          @HealthCheckState
1422          private int updateHealthCheckStateLocked() {
1423              int oldState = mHealthCheckState;
1424              if (mHasPassedHealthCheck) {
1425                  // Set final state first to avoid ambiguity
1426                  mHealthCheckState = HealthCheckState.PASSED;
1427              } else if (mHealthCheckDurationMs <= 0 || mDurationMs <= 0) {
1428                  // Set final state first to avoid ambiguity
1429                  mHealthCheckState = HealthCheckState.FAILED;
1430              } else if (mHealthCheckDurationMs == Long.MAX_VALUE) {
1431                  mHealthCheckState = HealthCheckState.INACTIVE;
1432              } else {
1433                  mHealthCheckState = HealthCheckState.ACTIVE;
1434              }
1435              Slog.i(TAG, "Updated health check state for package " + getName() + ": "
1436                      + toString(oldState) + " -> " + toString(mHealthCheckState));
1437              return mHealthCheckState;
1438          }

1011      /** Dump status of every observer in mAllObservers. */
1012      public void dump(IndentingPrintWriter pw) {
1013          pw.println("Package Watchdog status");
1014          pw.increaseIndent();
1015          synchronized (mLock) {
1016              for (String observerName : mAllObservers.keySet()) {
1017                  pw.println("Observer name: " + observerName);
1018                  pw.increaseIndent();
1019                  ObserverInternal observerInternal = mAllObservers.get(observerName);
1020                  observerInternal.dump(pw);
1021                  pw.decreaseIndent();
1022              }
1023          }
1024      }

当应用挂掉时间间隔不大于1min(mTriggerFailureDurationMs), 且挂掉的次数不小于5个, 则onFailureLocked返回trueonFailureLocked返回true, 对监听器执行onHealthCheckFailed,如果结果不是USER_IMPACT_NONE, 则最终执行到execute.

http://www.aospxref.com/android-11.0.0_r21/xref/frameworks/base/services/core/java/com/android/server/am/AppErrors.java

406      /**
407       * Bring up the "unexpected error" dialog box for a crashing app.
408       * Deal with edge cases (intercepts from instrumented applications,
409       * ActivityController, error intent receivers, that sort of thing).
410       * @param r the application crashing
411       * @param crashInfo describing the failure
412       */
413      void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
414          final int callingPid = Binder.getCallingPid();
415          final int callingUid = Binder.getCallingUid();
416  
417          final long origId = Binder.clearCallingIdentity();
418          try {
419              crashApplicationInner(r, crashInfo, callingPid, callingUid);
420          } finally {
421              Binder.restoreCallingIdentity(origId);
422          }
423      }

425      void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo,
426              int callingPid, int callingUid) {
427          long timeMillis = System.currentTimeMillis();
428          String shortMsg = crashInfo.exceptionClassName;
429          String longMsg = crashInfo.exceptionMessage;
430          String stackTrace = crashInfo.stackTrace;
431          if (shortMsg != null && longMsg != null) {
432              longMsg = shortMsg + ": " + longMsg;
433          } else if (shortMsg != null) {
434              longMsg = shortMsg;
435          }
436  
437          if (r != null) {
438              mPackageWatchdog.onPackageFailure(r.getPackageListWithVersionCode(),
439                      PackageWatchdog.FAILURE_REASON_APP_CRASH);
440  
441              mService.mProcessList.noteAppKill(r, (crashInfo != null
442                        && "Native crash".equals(crashInfo.exceptionClassName))
443                        ? ApplicationExitInfo.REASON_CRASH_NATIVE
444                        : ApplicationExitInfo.REASON_CRASH,
445                        ApplicationExitInfo.SUBREASON_UNKNOWN,
446                      "crash");
447          }

http://www.aospxref.com/android-11.0.0_r21/xref/frameworks/base/services/core/java/com/android/server/PackageWatchdog.java

359      /**
360       * Called when a process fails due to a crash, ANR or explicit health check.
361       *
362       * <p>For each package contained in the process, one registered observer with the least user
363       * impact will be notified for mitigation.
364       *
365       * <p>This method could be called frequently if there is a severe problem on the device.
366       */
367      public void onPackageFailure(List<VersionedPackage> packages,
368              @FailureReasons int failureReason) {
369          if (packages == null) {
370              Slog.w(TAG, "Could not resolve a list of failing packages");
371              return;
372          }
373          mLongTaskHandler.post(() -> {
374              synchronized (mLock) {
375                  if (mAllObservers.isEmpty()) {
376                      return;
377                  }
378                  boolean requiresImmediateAction = (failureReason == FAILURE_REASON_NATIVE_CRASH
379                          || failureReason == FAILURE_REASON_EXPLICIT_HEALTH_CHECK);
380                  if (requiresImmediateAction) {
381                      handleFailureImmediately(packages, failureReason);
382                  } else {
383                      for (int pIndex = 0; pIndex < packages.size(); pIndex++) {
384                          VersionedPackage versionedPackage = packages.get(pIndex);
385                          // Observer that will receive failure for versionedPackage
386                          PackageHealthObserver currentObserverToNotify = null;
387                          int currentObserverImpact = Integer.MAX_VALUE;
388  
389                          // Find observer with least user impact
390                          for (int oIndex = 0; oIndex < mAllObservers.size(); oIndex++) {
391                              ObserverInternal observer = mAllObservers.valueAt(oIndex);
392                              PackageHealthObserver registeredObserver = observer.registeredObserver;
393                              if (registeredObserver != null
394                                      && observer.onPackageFailureLocked(
395                                      versionedPackage.getPackageName())) {
396                                  int impact = registeredObserver.onHealthCheckFailed(
397                                          versionedPackage, failureReason);
398                                  if (impact != PackageHealthObserverImpact.USER_IMPACT_NONE
399                                          && impact < currentObserverImpact) {
400                                      currentObserverToNotify = registeredObserver;
401                                      currentObserverImpact = impact;
402                                  }
403                              }
404                          }
405  
406                          // Execute action with least user impact
407                          if (currentObserverToNotify != null) {
408                              currentObserverToNotify.execute(versionedPackage, failureReason);
409                          }
410                      }
411                  }
412              }
413          });
414      }

http://www.aospxref.com/android-11.0.0_r21/xref/frameworks/base/services/core/java/com/android/server/RescueParty.java

419          @Override
420          public int onHealthCheckFailed(@Nullable VersionedPackage failedPackage,
421                  @FailureReasons int failureReason) {
422              if (!isDisabled() && (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
423                      || failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING)) {
424                  return mapRescueLevelToUserImpact(getNextRescueLevel());
425              } else {
426                  return PackageHealthObserverImpact.USER_IMPACT_NONE;
427              }
428          }

通过加log, 发现onPackageFailure被调用了, 但是currentObserverToNotifynull, 所以跟踪observer.onPackageFailureLocked查看为啥为false: 通过增加log打印, 发现RescueParty存在Bug:

11-08 08:55:37.174  1153  1403 W RescueParty: ==>packageName = com.demo
11-08 08:55:37.174  1153  1826 W ActivityTaskManager:   Force finishing activity com.demo/.MainActivity
11-08 08:55:37.176  1153  1403 W RescueParty: NameNotFoundException
11-08 08:55:37.176  1153  1403 W RescueParty: android.content.pm.PackageManager$NameNotFoundException: No module info for package: com.demo
11-08 08:55:37.176  1153  1403 W RescueParty:   at android.app.ApplicationPackageManager.getModuleInfo(ApplicationPackageManager.java:1010)
11-08 08:55:37.176  1153  1403 W RescueParty:   at com.android.server.RescueParty$RescuePartyObserver.mayObservePackage(RescueParty.java:459)
11-08 08:55:37.176  1153  1403 W RescueParty:   at com.android.server.PackageWatchdog$ObserverInternal.onPackageFailureLocked(PackageWatchdog.java:1125)
11-08 08:55:37.176  1153  1403 W RescueParty:   at com.android.server.PackageWatchdog.lambda$onPackageFailure$4$PackageWatchdog(PackageWatchdog.java:398)
11-08 08:55:37.176  1153  1403 W RescueParty:   at com.android.server.-$$Lambda$PackageWatchdog$Ya4lYGbdDy3Dda20wvc2AHBqIMM.run(Unknown Source:6)
11-08 08:55:37.176  1153  1403 W RescueParty:   at android.os.Handler.handleCallback(Handler.java:938)
11-08 08:55:37.176  1153  1403 W RescueParty:   at android.os.Handler.dispatchMessage(Handler.java:99)
11-08 08:55:37.176  1153  1403 W RescueParty:   at android.os.Looper.loop(Looper.java:223)
11-08 08:55:37.176  1153  1403 W RescueParty:   at android.os.HandlerThread.run(HandlerThread.java:67)
11-08 08:55:37.177  1153  1403 E PackageWatchdog: ==> onPackageFailureLocked : registeredObserver.mayObservePackage(packageName) = false

http://www.aospxref.com/android-11.0.0_r21/xref/frameworks/base/services/core/java/com/android/server/PackageWatchdog.java


551      /** Register instances of this interface to receive notifications on package failure. */
552      public interface PackageHealthObserver {

1026      /**
1027       * Represents an observer monitoring a set of packages along with the failure thresholds for
1028       * each package.
1029       *
1030       * <p> Note, the PackageWatchdog#mLock must always be held when reading or writing
1031       * instances of this class.
1032       */
1033      private static class ObserverInternal {
1034          public final String name;
...
1110          /**
1111           * Increments failure counts of {@code packageName}.
1112           * @returns {@code true} if failure threshold is exceeded, {@code false} otherwise
1113           */
1114          @GuardedBy("mLock")
1115          public boolean onPackageFailureLocked(String packageName) {
1116              if (packages.get(packageName) == null && registeredObserver.isPersistent()
1117                      && registeredObserver.mayObservePackage(packageName)) {
1118                  packages.put(packageName, sPackageWatchdog.newMonitoredPackage(
1119                          packageName, DEFAULT_OBSERVING_DURATION_MS, false));
1120              }
1121              MonitoredPackage p = packages.get(packageName);
1122              if (p != null) {
1123                  return p.onFailureLocked();
1124              }
1125              return false;
1126          }

94      public static final int FAILURE_REASON_UNKNOWN = 0;
95      public static final int FAILURE_REASON_NATIVE_CRASH = 1;
96      public static final int FAILURE_REASON_EXPLICIT_HEALTH_CHECK = 2;
97      public static final int FAILURE_REASON_APP_CRASH = 3;
98      public static final int FAILURE_REASON_APP_NOT_RESPONDING = 4;
389      public static class RescuePartyObserver implements PackageHealthObserver {

419          @Override
420          public int onHealthCheckFailed(@Nullable VersionedPackage failedPackage,
421                  @FailureReasons int failureReason) {
422              if (!isDisabled() && (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
423                      || failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING)) {
424                  return mapRescueLevelToUserImpact(getNextRescueLevel());
425              } else {
426                  return PackageHealthObserverImpact.USER_IMPACT_NONE;
427              }
428          }

448          @Override
449          public boolean isPersistent() {
450              return true;
451          }
452  
453          @Override
454          public boolean mayObservePackage(String packageName) {
455              PackageManager pm = mContext.getPackageManager();
456              try {
457                  // A package is a module if this is non-null
458                  if (pm.getModuleInfo(packageName, 0) != null) {
459                      return true;
460                  }
461              } catch (PackageManager.NameNotFoundException ignore) {
462              }
463  
464              try {
465                  ApplicationInfo info = pm.getApplicationInfo(packageName, 0);
466                  return (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK;
467              } catch (PackageManager.NameNotFoundException e) {
468                  return false;
469              }
470          }

找到Android11上的diff : https://github.com/aosp-mirror/platform_frameworks_base/commit/f2abc4e6fa6ed79462e0ddfc6ede526edc646378, 注释内容:

Fix Rescue Party observability criteria
The previous behavior erroneously returned if the package
was not found by PackageManager#getModuleInfo, which means
the persistent process check would never be performed. This
caused packages like com.android.systemui to not be handled
by Rescue Party's mitigation logic. Instead, ensure that
both cases are checked.

Test: setprop persist.sys.enable_rescue true,
      adb shell setprop debug.crash_sysui 1,
      adb shell kill `pidof com.android.systemui`,
      ensure recovery mode is reached
Bug: 169284310
Change-Id: Ifec19b8daba1dacc7f5efcfa47ed3c3a046612e3

修复后, 拔掉USB调试线, 成功进入Recovery模式:

3 RescueParty执行重置的条件

测试情况手动设置属性persist.sys.enable_rescue进入救援模式; 系统回滚后, 通过设置属性persist.device_config.configuration.disable_rescue_party, 不进入救援模式; 工程版本, 不进入救援模式; userdebug版本且adb可用, 不进入救援模式; 当persist.sys.disable_rescue被设置为true, 不进入救援模式; 否则热重启后就会执行重置操作.

http://www.aospxref.com/android-11.0.0_r21/xref/frameworks/base/services/core/java/com/android/server/RescueParty.java

75      @VisibleForTesting
76      static final String PROP_ENABLE_RESCUE = "persist.sys.enable_rescue";

99      private static final String PROP_DISABLE_RESCUE = "persist.sys.disable_rescue";
101      private static final String PROP_DEVICE_CONFIG_DISABLE_FLAG =
102              "persist.device_config.configuration.disable_rescue_party";

113      private static boolean isDisabled() {
114          // Check if we're explicitly enabled for testing
115          if (SystemProperties.getBoolean(PROP_ENABLE_RESCUE, false)) {
116              return false;
117          }
118  
119          // We're disabled if the DeviceConfig disable flag is set to true.
120          // This is in case that an emergency rollback of the feature is needed.
121          if (SystemProperties.getBoolean(PROP_DEVICE_CONFIG_DISABLE_FLAG, false)) {
122              Slog.v(TAG, "Disabled because of DeviceConfig flag");
123              return true;
124          }
125  
126          // We're disabled on all engineering devices
127          if (Build.IS_ENG) {
128              Slog.v(TAG, "Disabled because of eng build");
129              return true;
130          }
131  
132          // We're disabled on userdebug devices connected over USB, since that's
133          // a decent signal that someone is actively trying to debug the device,
134          // or that it's in a lab environment.
135          if (Build.IS_USERDEBUG && isUsbActive()) {
136              Slog.v(TAG, "Disabled because of active USB connection");
137              return true;
138          }
139  
140          // One last-ditch check
141          if (SystemProperties.getBoolean(PROP_DISABLE_RESCUE, false)) {
142              Slog.v(TAG, "Disabled because of manual property");
143              return true;
144          }
145  
146          return false;
147      }

389      public static class RescuePartyObserver implements PackageHealthObserver {
...
430          @Override
431          public boolean execute(@Nullable VersionedPackage failedPackage,
432                  @FailureReasons int failureReason) {
433              if (isDisabled()) {
434                  return false;
435              }
436              if (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
437                      || failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING) {
438                  int triggerUid = getPackageUid(mContext, failedPackage.getPackageName());
439                  incrementRescueLevel(triggerUid);
440                  executeRescueLevel(mContext,
441                          failedPackage == null ? null : failedPackage.getPackageName());
442                  return true;
443              } else {
444                  return false;
445              }
446          }

472          @Override
473          public int onBootLoop() {
474              if (isDisabled()) {
475                  return PackageHealthObserverImpact.USER_IMPACT_NONE;
476              }
477              return mapRescueLevelToUserImpact(getNextRescueLevel());
478          }
479  
480          @Override
481          public boolean executeBootLoopMitigation() {
482              if (isDisabled()) {
483                  return false;
484              }
485              incrementRescueLevel(Process.ROOT_UID);
486              executeRescueLevel(mContext, /*failedPackage=*/ null);
487              return true;
488          }


540      /**
541       * Hacky test to check if the device has an active USB connection, which is
542       * a good proxy for someone doing local development work.
543       */
544      private static boolean isUsbActive() {
545          if (SystemProperties.getBoolean(PROP_VIRTUAL_DEVICE, false)) {
546              Slog.v(TAG, "Assuming virtual device is connected over USB");
547              return true;
548          }
549          try {
550              final String state = FileUtils
551                      .readTextFile(new File("/sys/class/android_usb/android0/state"), 128, "");
552              return "CONFIGURED".equals(state.trim());
553          } catch (Throwable t) {
554              Slog.w(TAG, "Failed to determine if device was on USB", t);
555              return false;
556          }
557      }

4 RescueParty执行重置

executeRescueLevel时, RescuePartysys.rescue_level设置的level顺序逐渐加强: - LEVEL_NONE : 未设置或设置为0, 直接返回 - LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS : 重置Setting配置, - LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES : 重置Setting配置, - LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS : 重置Setting配置, - LEVEL_FACTORY_RESET : 恢复出厂设置并清除用户数据

http://www.aospxref.com/android-11.0.0_r21/xref/frameworks/base/services/core/java/com/android/server/RescueParty.java

224      /**
225       * Get the next rescue level. This indicates the next level of mitigation that may be taken.
226       */
227      private static int getNextRescueLevel() {
228          return MathUtils.constrain(SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE) + 1,
229                  LEVEL_NONE, LEVEL_FACTORY_RESET);
230      }
231  
232      /**
233       * Escalate to the next rescue level. After incrementing the level you'll
234       * probably want to call {@link #executeRescueLevel(Context, String)}.
235       */
236      private static void incrementRescueLevel(int triggerUid) {
237          final int level = getNextRescueLevel();
238          SystemProperties.set(PROP_RESCUE_LEVEL, Integer.toString(level));
239  
240          EventLogTags.writeRescueLevel(level, triggerUid);
241          logCriticalInfo(Log.WARN, "Incremented rescue level to "
242                  + levelToString(level) + " triggered by UID " + triggerUid);
243      }
75      @VisibleForTesting
76      static final String PROP_ENABLE_RESCUE = "persist.sys.enable_rescue";
77      @VisibleForTesting
78      static final String PROP_RESCUE_LEVEL = "sys.rescue_level";
79      @VisibleForTesting
80      static final int LEVEL_NONE = 0;
81      @VisibleForTesting
82      static final int LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS = 1;
83      @VisibleForTesting
84      static final int LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES = 2;
85      @VisibleForTesting
86      static final int LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS = 3;
87      @VisibleForTesting
88      static final int LEVEL_FACTORY_RESET = 4;

245      private static void executeRescueLevel(Context context, @Nullable String failedPackage) {
246          final int level = SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE);
247          if (level == LEVEL_NONE) return;
248  
249          Slog.w(TAG, "Attempting rescue level " + levelToString(level));
250          try {
251              executeRescueLevelInternal(context, level, failedPackage);
252              EventLogTags.writeRescueSuccess(level);
253              logCriticalInfo(Log.DEBUG,
254                      "Finished rescue level " + levelToString(level));
255          } catch (Throwable t) {
256              logRescueException(level, t);
257          }
258      }

260      private static void executeRescueLevelInternal(Context context, int level, @Nullable
261              String failedPackage) throws Exception {
262          FrameworkStatsLog.write(FrameworkStatsLog.RESCUE_PARTY_RESET_REPORTED, level);
263          switch (level) {
264              case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
265                  resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS, failedPackage);
266                  break;
267              case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
268                  resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_CHANGES, failedPackage);
269                  break;
270              case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
271                  resetAllSettings(context, Settings.RESET_MODE_TRUSTED_DEFAULTS, failedPackage);
272                  break;
273              case LEVEL_FACTORY_RESET:
274                  // Request the reboot from a separate thread to avoid deadlock on PackageWatchdog
275                  // when device shutting down.
276                  Runnable runnable = new Runnable() {
277                      @Override
278                      public void run() {
279                          try {
280                              RecoverySystem.rebootPromptAndWipeUserData(context, TAG);
281                          } catch (Throwable t) {
282                              logRescueException(level, t);
283                          }
284                      }
285                  };
286                  Thread thread = new Thread(runnable);
287                  thread.start();
288                  break;
289          }
290      }

321      private static void resetAllSettings(Context context, int mode, @Nullable String failedPackage)
322              throws Exception {
323          // Try our best to reset all settings possible, and once finished
324          // rethrow any exception that we encountered
325          Exception res = null;
326          final ContentResolver resolver = context.getContentResolver();
327          try {
328              resetDeviceConfig(context, mode, failedPackage);
329          } catch (Exception e) {
330              res = new RuntimeException("Failed to reset config settings", e);
331          }
332          try {
333              Settings.Global.resetToDefaultsAsUser(resolver, null, mode, UserHandle.USER_SYSTEM);
334          } catch (Exception e) {
335              res = new RuntimeException("Failed to reset global settings", e);
336          }
337          for (int userId : getAllUserIds()) {
338              try {
339                  Settings.Secure.resetToDefaultsAsUser(resolver, null, mode, userId);
340              } catch (Exception e) {
341                  res = new RuntimeException("Failed to reset secure settings for " + userId, e);
342              }
343          }
344          if (res != null) {
345              throw res;
346          }
347      }
log/tar_logcat.02/logcat.log_1.42:11-03 05:05:34.228   879   909 W PackageManager: Incremented rescue level to RESET_SETTINGS_UNTRUSTED_DEFAULTS triggered by UID 1000
log/tar_logcat.02/logcat.log_1.42:11-03 05:05:35.859   879   909 W PackageManager: Incremented rescue level to RESET_SETTINGS_UNTRUSTED_CHANGES triggered by UID 1000
log/tar_logcat.02/logcat.log_1.42:11-03 05:05:37.289   879   909 W PackageManager: Incremented rescue level to RESET_SETTINGS_TRUSTED_DEFAULTS triggered by UID 1000
log/tar_logcat.02/logcat.log_1.42:11-03 05:05:40.503   879   909 W PackageManager: Incremented rescue level to FACTORY_RESET triggered by UID 1000

5 恢复出厂

恢厂传给参数reason的值是TAG (RescueParty),

http://www.aospxref.com/android-11.0.0_r21/xref/frameworks/base/core/java/android/os/RecoverySystem.java


107      /** Used to communicate with recovery.  See bootable/recovery/recovery.cpp. */
108      private static final File RECOVERY_DIR = new File("/cache/recovery");
109      private static final File LOG_FILE = new File(RECOVERY_DIR, "log");

1162      /**
1163       * Called after booting to process and remove recovery-related files.
1164       * @return the log file from recovery, or null if none was found.
1165       *
1166       * @hide
1167       */
1168      public static String handleAftermath(Context context) {
1169          // Record the tail of the LOG_FILE
1170          String log = null;
1171          try {
1172              log = FileUtils.readTextFile(LOG_FILE, -LOG_FILE_MAX_LENGTH, "...\n");
1173          } catch (FileNotFoundException e) {
1174              Log.i(TAG, "No recovery log file");
1175          } catch (IOException e) {
1176              Log.e(TAG, "Error reading recovery log", e);
1177          }

1050      /** {@hide} */
1051      public static void rebootPromptAndWipeUserData(Context context, String reason)
1052              throws IOException {
1053          boolean checkpointing = false;
1054          boolean needReboot = false;
1055          IVold vold = null;
1056          try {
1057              vold = IVold.Stub.asInterface(ServiceManager.checkService("vold"));
1058              if (vold != null) {
1059                  checkpointing = vold.needsCheckpoint();
1060              } else  {
1061                  Log.w(TAG, "Failed to get vold");
1062              }
1063          } catch (Exception e) {
1064              Log.w(TAG, "Failed to check for checkpointing");
1065          }
1066  
1067          // If we are running in checkpointing mode, we should not prompt a wipe.
1068          // Checkpointing may save us. If it doesn't, we will wind up here again.
1069          if (checkpointing) {
1070              try {
1071                  vold.abortChanges("rescueparty", false);
1072                  Log.i(TAG, "Rescue Party requested wipe. Aborting update");
1073              } catch (Exception e) {
1074                  Log.i(TAG, "Rescue Party requested wipe. Rebooting instead.");
1075                  PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
1076                  pm.reboot("rescueparty");
1077              }
1078              return;
1079          }
1080  
1081          String reasonArg = null;
1082          if (!TextUtils.isEmpty(reason)) {
1083              reasonArg = "--reason=" + sanitizeArg(reason);
1084          }
1085  
1086          final String localeArg = "--locale=" + Locale.getDefault().toString();
1087          bootCommand(context, null, "--prompt_and_wipe_data", reasonArg, localeArg);
1088      }


1138      /**
1139       * Reboot into the recovery system with the supplied argument.
1140       * @param args to pass to the recovery utility.
1141       * @throws IOException if something goes wrong.
1142       */
1143      private static void bootCommand(Context context, String... args) throws IOException {
1144          LOG_FILE.delete();
1145  
1146          StringBuilder command = new StringBuilder();
1147          for (String arg : args) {
1148              if (!TextUtils.isEmpty(arg)) {
1149                  command.append(arg);
1150                  command.append("\n");
1151              }
1152          }
1153  
1154          // Write the command into BCB (bootloader control block) and boot from
1155          // there. Will not return unless failed.
1156          RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
1157          rs.rebootRecoveryWithCommand(command.toString());
1158  
1159          throw new IOException("Reboot failed (no permissions?)");
1160      }

http://www.aospxref.com/android-11.0.0_r21/xref/frameworks/base/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java#276

275      @Override // Binder call
276      public void rebootRecoveryWithCommand(String command) {
277          if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");
278          synchronized (sRequestLock) {
279              if (!setupOrClearBcb(true, command)) {
280                  return;
281              }
282  
283              // Having set up the BCB, go ahead and reboot.
284              PowerManager pm = mInjector.getPowerManager();
285              pm.reboot(PowerManager.REBOOT_RECOVERY);
286          }
287      }

http://www.aospxref.com/android-11.0.0_r21/xref/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java#126

5128          /**
5129           * Reboots the device.
5130           *
5131           * @param confirm If true, shows a reboot confirmation dialog.
5132           * @param reason The reason for the reboot, or null if none.
5133           * @param wait If true, this call waits for the reboot to complete and does not return.
5134           */
5135          @Override // Binder call
5136          public void reboot(boolean confirm, @Nullable String reason, boolean wait) {
5137              mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
5138              if (PowerManager.REBOOT_RECOVERY.equals(reason)
5139                      || PowerManager.REBOOT_RECOVERY_UPDATE.equals(reason)) {
5140                  mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
5141              }
5142  
5143              final long ident = Binder.clearCallingIdentity();
5144              try {
5145                  shutdownOrRebootInternal(HALT_MODE_REBOOT, confirm, reason, wait);
5146              } finally {
5147                  Binder.restoreCallingIdentity(ident);
5148              }
5149          }

6 命令传递

函数setupOrClearBcb设置属性ctl.startsetup-bcb, 然后把命令发给UncryptSocket

http://www.aospxref.com/android-11.0.0_r21/xref/frameworks/base/services/core/java/com/android/server/recoverysystem/RecoverySystemService.java


415      private boolean setupOrClearBcb(boolean isSetup, String command) {
416          mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
417  
418          final boolean available = checkAndWaitForUncryptService();
419          if (!available) {
420              Slog.e(TAG, "uncrypt service is unavailable.");
421              return false;
422          }
423  
424          if (isSetup) {
425              mInjector.systemPropertiesSet("ctl.start", "setup-bcb");
426          } else {
427              mInjector.systemPropertiesSet("ctl.start", "clear-bcb");
428          }
429  
430          // Connect to the uncrypt service socket.
431          UncryptSocket socket = mInjector.connectService();
432          if (socket == null) {
433              Slog.e(TAG, "Failed to connect to uncrypt socket");
434              return false;
435          }
436  
437          try {
438              // Send the BCB commands if it's to setup BCB.
439              if (isSetup) {
440                  socket.sendCommand(command);
441              }
442  
443              // Read the status from the socket.
444              int status = socket.getPercentageUncrypted();
445  
446              // Ack receipt of the status code. uncrypt waits for the ack so
447              // the socket won't be destroyed before we receive the code.
448              socket.sendAck();
449  
450              if (status == 100) {
451                  Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear")
452                          + " bcb successfully finished.");
453              } else {
454                  // Error in /system/bin/uncrypt.
455                  Slog.e(TAG, "uncrypt failed with status: " + status);
456                  return false;
457              }
458          } catch (IOException e) {
459              Slog.e(TAG, "IOException when communicating with uncrypt:", e);
460              return false;
461          } finally {
462              socket.close();
463          }
464  
465          return true;
466      }

61      // The socket at /dev/socket/uncrypt to communicate with uncrypt.
62      private static final String UNCRYPT_SOCKET = "uncrypt";

468      /**
469       * Provides a wrapper for the low-level details of framing packets sent to the uncrypt
470       * socket.
471       */
472      public static class UncryptSocket {
473          private LocalSocket mLocalSocket;
474          private DataInputStream mInputStream;
475          private DataOutputStream mOutputStream;

485          public boolean connectService() {
486              mLocalSocket = new LocalSocket();
487              boolean done = false;
488              // The uncrypt socket will be created by init upon receiving the
489              // service request. It may not be ready by this point. So we will
490              // keep retrying until success or reaching timeout.
491              for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
492                  try {
493                      mLocalSocket.connect(new LocalSocketAddress(UNCRYPT_SOCKET,
494                              LocalSocketAddress.Namespace.RESERVED));
495                      done = true;
496                      break;

522          /**
523           * Sends a command to the uncrypt service.
524           *
525           * @param command command to send to the uncrypt service
526           * @throws IOException if there was an error writing to the socket
527           */
528          public void sendCommand(String command) throws IOException {
529              byte[] cmdUtf8 = command.getBytes(StandardCharsets.UTF_8);
530              mOutputStream.writeInt(cmdUtf8.length);
531              mOutputStream.write(cmdUtf8, 0, cmdUtf8.length);
532          }

main函数能够看到uncrypt应用创建了socket, 等待数据, 从log中看到数据格式如下:

log/log/log/tar_logcat.01/logcat.log.35:11-07 10:58:39.062  7027  7027 I uncrypt :   received command: [--prompt_and_wipe_data
log/log/log/tar_logcat.01/logcat.log.35-11-07 10:58:39.062  7027  7027 I uncrypt : --reason=RescueParty
log/log/log/tar_logcat.01/logcat.log.35-11-07 10:58:39.062  7027  7027 I uncrypt : --locale=zh_CN
log/log/log/tar_logcat.01/logcat.log.35-11-07 10:58:39.062  7027  7027 I uncrypt : ] (59)

http://www.aospxref.com/android-11.0.0_r21/xref/bootable/recovery/uncrypt/uncrypt.cpp

60   *                         b2. create socket at
61   *                           /dev/socket/uncrypt

135  // UNCRYPT service still needs files on /cache partition (UNCRYPT_PATH_FILE
136  // and CACHE_BLOCK_MAP). It will be working (and needed) only for non-A/B
137  // devices, on which /cache partitions always exist.
138  static const std::string CACHE_BLOCK_MAP = "/cache/recovery/block.map";
139  static const std::string UNCRYPT_PATH_FILE = "/cache/recovery/uncrypt_file";
140  static const std::string UNCRYPT_STATUS = "/cache/recovery/uncrypt_status";
141  static const std::string UNCRYPT_SOCKET = "uncrypt";

567  static bool setup_bcb(const int socket) {
568      // c5. receive message length
569      int length;
570      if (!android::base::ReadFully(socket, &length, 4)) {
571          PLOG(ERROR) << "failed to read the length";
572          return false;
573      }
574      length = ntohl(length);
575  
576      // c7. receive message
577      std::string content;
578      content.resize(length);
579      if (!android::base::ReadFully(socket, &content[0], length)) {
580          PLOG(ERROR) << "failed to read the message";
581          return false;
582      }
583      LOG(INFO) << "  received command: [" << content << "] (" << content.size() << ")";
584      std::vector<std::string> options = android::base::Split(content, "\n");
585      std::string wipe_package;
586      for (auto& option : options) {
587          if (android::base::StartsWith(option, "--wipe_package=")) {
588              std::string path = option.substr(strlen("--wipe_package="));
589              if (!android::base::ReadFileToString(path, &wipe_package)) {
590                  PLOG(ERROR) << "failed to read " << path;
591                  return false;
592              }
593              option = android::base::StringPrintf("--wipe_package_size=%zu", wipe_package.size());
594          }
595      }
596  
597      // c8. setup the bcb command
598      std::string err;
599      if (!write_bootloader_message(options, &err)) {
600          LOG(ERROR) << "failed to set bootloader message: " << err;
601          write_status_to_socket(-1, socket);
602          return false;
603      }
604      if (!wipe_package.empty() && !write_wipe_package(wipe_package, &err)) {
605          PLOG(ERROR) << "failed to set wipe package: " << err;
606          write_status_to_socket(-1, socket);
607          return false;
608      }
609      // c10. send "100" status
610      write_status_to_socket(100, socket);
611      return true;
612  }
613  

621  int main(int argc, char** argv) {
622      enum { UNCRYPT, SETUP_BCB, CLEAR_BCB, UNCRYPT_DEBUG } action;
623      const char* input_path = nullptr;
624      const char* map_file = CACHE_BLOCK_MAP.c_str();
625  
626      if (argc == 2 && strcmp(argv[1], "--clear-bcb") == 0) {
627          action = CLEAR_BCB;
628      } else if (argc == 2 && strcmp(argv[1], "--setup-bcb") == 0) {
629          action = SETUP_BCB;
630      } else if (argc == 1) {
631          action = UNCRYPT;
632      } else if (argc == 3) {
633          input_path = argv[1];
634          map_file = argv[2];
635          action = UNCRYPT_DEBUG;
636      } else {
637          usage(argv[0]);
638          return 2;
639      }
...
    // c3. The socket is created by init when starting the service. uncrypt
659      // will use the socket to communicate with its caller.
660      android::base::unique_fd service_socket(android_get_control_socket(UNCRYPT_SOCKET.c_str()));
661      if (service_socket == -1) {
662          PLOG(ERROR) << "failed to open socket \"" << UNCRYPT_SOCKET << "\"";
663          log_uncrypt_error_code(kUncryptSocketOpenError);
664          return 1;
665      }
666      fcntl(service_socket, F_SETFD, FD_CLOEXEC);
667  
668      if (listen(service_socket, 1) == -1) {
669          PLOG(ERROR) << "failed to listen on socket " << service_socket.get();
670          log_uncrypt_error_code(kUncryptSocketListenError);
671          return 1;
672      }
673  
674      android::base::unique_fd socket_fd(accept4(service_socket, nullptr, nullptr, SOCK_CLOEXEC));
675      if (socket_fd == -1) {
676          PLOG(ERROR) << "failed to accept on socket " << service_socket.get();
677          log_uncrypt_error_code(kUncryptSocketAcceptError);
678          return 1;
679      }
680  
681      bool success = false;
682      switch (action) {
683          case UNCRYPT:
684              success = uncrypt_wrapper(input_path, map_file, socket_fd);
685              break;
686          case SETUP_BCB:
687              success = setup_bcb(socket_fd);
688              break;
689          case CLEAR_BCB:
690              success = clear_bcb(socket_fd);
691              break;
692          default:  // Should never happen.
693              LOG(ERROR) << "Invalid uncrypt action code: " << action;
694              return 1;
695      }
696  

7 属性设置/参数传递

开发板上/system/etc/init/bootstat.rc对应如下文件,

Android通过三个属性来确定启动原因。 - ro.boot.bootreason:系统启动过程中,Init进程会将内核启动命令行中的androidboot.bootreason=<reason>转化为ro.boot.bootreason。启动命令行中的bootreason由一般芯片供应商提供,内核在断电前会将启动原因写入专用的硬件资源或约定的内存地址。下次启动时,Bootloader就可以读取相应的资源来确定启动原因,然后添加到内核启动命令行中。如果芯片供应商不支持启动原因写入,androidboot.bootreason就可能不存在。 - sys.boot.reason:系统启动时先将ro.boot.bootreason复制给sys.boot.reason。因为ro.boot.bootreason可能不存在,或者可能提供不准确、不可解析或不合规范的信息,在启动完成后会进一步更新sys.boot.reason。更新后的sys.boot.reason将提供准确可靠的、符合规范的启动原因。 - persist.sys.boot.reason:Android系统在重启前会将重启原因写入到persist.sys.boot.reason中。这个属性可以用来在ro.boot.bootreason不存在时,协助确定启动原因。

Bootstat对sys.boot.reason处理的简单流程如下, - 读取ro.boot.bootreason,将其转化为符合规范的reason。 - 如果reason是watchdog,检查是否需要增加security标签。 - 如果reason是kernel_panic,从last klog中查找详细信息。 - 如果reason属于弱集(包含空值),从last klog中查找信息,检查是否电池耗尽引起死机,根据persist.sys.boot.reason修正reason。 - 如果上述操作依然无法确定reason,将值设置为reboot,。 - 如果reason属于内核集,重写persist.sys.boot.reason。

http://www.aospxref.com/android-11.0.0_r21/xref/system/core/bootstat/bootstat.rc

3 # Mirror bootloader boot reason to system boot reason
4 # ro.boot.bootreason should be set by init already
5 # before post-fs trigger
6 on post-fs && property:ro.boot.bootreason=*
7     setprop sys.boot.reason ${ro.boot.bootreason}

70 # Set boot reason
71 on property:ro.persistent_properties.ready=true
72     # Converts bootloader boot reason and persist.sys.boot.reason to system boot reason
73     # Need go after persist peroperties are loaded which is right before zygote-start trigger
74     exec_background - system log -- /system/bin/bootstat --set_system_boot_reason

76 # Record boot complete metrics.
77 on property:sys.boot_completed=1 && property:sys.bootstat.first_boot_completed=0
78     # Record boot_complete and related stats (decryption, etc).
79     # Record the boot reason.
80     # Record time since factory reset.
81     # Log all boot events.
82     exec_background - system log -- /system/bin/bootstat --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l
83     setprop sys.bootstat.first_boot_completed 1

http://www.aospxref.com/android-11.0.0_r21/xref/system/core/bootstat/bootstat.cpp

1059      // Is there a controlled shutdown hint in last_reboot_reason_property?
1060      if (isBluntRebootReason(ret)) {
1061        // Content buffer no longer will have console data. Beware if more
1062        // checks added below, that depend on parsing console content.
1063        if (!android::base::ReadFileToString(last_reboot_reason_file, &content)) {
1064          content = android::base::GetProperty(last_reboot_reason_property, "");
1065        }
1066        transformReason(content);

1232  void SetSystemBootReason() {
1233    const auto bootloader_boot_reason =
1234        android::base::GetProperty(bootloader_reboot_reason_property, "");
1235    const std::string system_boot_reason(BootReasonStrToReason(bootloader_boot_reason));
1236    // Record the scrubbed system_boot_reason to the property
1237    BootReasonAddToHistory(system_boot_reason);
1238    // Shift last_reboot_reason_property to last_last_reboot_reason_property
1239    std::string last_boot_reason;
1240    if (!android::base::ReadFileToString(last_reboot_reason_file, &last_boot_reason)) {
1241      PLOG(ERROR) << "Failed to read " << last_reboot_reason_file;
1242      last_boot_reason = android::base::GetProperty(last_reboot_reason_property, "");
1243      LOG(INFO) << "Value of " << last_reboot_reason_property << " : " << last_boot_reason;
1244    } else {
1245      LOG(INFO) << "Last reboot reason read from " << last_reboot_reason_file << " : "
1246                << last_boot_reason << ". Last reboot reason read from "
1247                << last_reboot_reason_property << " : "
1248                << android::base::GetProperty(last_reboot_reason_property, "");
1249    }
1250    if (last_boot_reason.empty() || isKernelRebootReason(system_boot_reason)) {
1251      last_boot_reason = system_boot_reason;
1252    } else {
1253      transformReason(last_boot_reason);
1254    }
1255    LOG(INFO) << "Normalized last reboot reason : " << last_boot_reason;
1256    android::base::SetProperty(last_last_reboot_reason_property, last_boot_reason);
1257    android::base::SetProperty(last_reboot_reason_property, "");
1258    if (unlink(last_reboot_reason_file) != 0) {
1259      PLOG(ERROR) << "Failed to unlink " << last_reboot_reason_file;
1260    }
1261  }

8 完成启动

http://www.aospxref.com/android-11.0.0_r21/xref/frameworks/base/core/res/AndroidManifest.xml

5271 
5272         <receiver android:name="com.android.server.BootReceiver"
5273                 android:systemUserOnly="true">
5274             <intent-filter android:priority="1000">
5275                 <action android:name="android.intent.action.BOOT_COMPLETED" />
5276             </intent-filter>
5277         </receiver>

http://www.aospxref.com/android-11.0.0_r21/xref/frameworks/base/core/java/com/android/server/BootReceiver.java

65  public class BootReceiver extends BroadcastReceiver {

124      @Override
125      public void onReceive(final Context context, Intent intent) {
126          // Log boot events in the background to avoid blocking the main thread with I/O
127          new Thread() {
128              @Override
129              public void run() {
130                  try {
131                      logBootEvents(context);


198      private void logBootEvents(Context ctx) throws IOException {
199          final DropBoxManager db = (DropBoxManager) ctx.getSystemService(Context.DROPBOX_SERVICE);
200          final String headers = getBootHeadersToLogAndUpdate();
201          final String bootReason = SystemProperties.get("ro.boot.bootreason", null);
202  
203          String recovery = RecoverySystem.handleAftermath(ctx);
204          if (recovery != null && db != null) {
205              db.addText("SYSTEM_RECOVERY_LOG", headers + recovery);
206          }
207  
208          String lastKmsgFooter = "";
209          if (bootReason != null) {
210              lastKmsgFooter = new StringBuilder(512)
211                  .append("\n")
212                  .append("Boot info:\n")
213                  .append("Last boot reason: ").append(bootReason).append("\n")
214                  .toString();
215          }
216  
217          HashMap<String, Long> timestamps = readTimestamps();
218  
219          if (SystemProperties.getLong("ro.runtime.firstboot", 0) == 0) {
220              if (StorageManager.inCryptKeeperBounce()) {
221                  // Encrypted, first boot to get PIN/pattern/password so data is tmpfs
222                  // Don't set ro.runtime.firstboot so that we will do this again
223                  // when data is properly mounted
224              } else {
225                  String now = Long.toString(System.currentTimeMillis());
226                  SystemProperties.set("ro.runtime.firstboot", now);
227              }
228              if (db != null) db.addText("SYSTEM_BOOT", headers);
229  
230              // Negative sizes mean to take the *tail* of the file (see FileUtils.readTextFile())
231              addLastkToDropBox(db, timestamps, headers, lastKmsgFooter,
232                      "/proc/last_kmsg", -LASTK_LOG_SIZE, "SYSTEM_LAST_KMSG");
233              addLastkToDropBox(db, timestamps, headers, lastKmsgFooter,
234                      "/sys/fs/pstore/console-ramoops", -LASTK_LOG_SIZE, "SYSTEM_LAST_KMSG");
235              addLastkToDropBox(db, timestamps, headers, lastKmsgFooter,
236                      "/sys/fs/pstore/console-ramoops-0", -LASTK_LOG_SIZE, "SYSTEM_LAST_KMSG");
237              addFileToDropBox(db, timestamps, headers, "/cache/recovery/log", -LOG_SIZE,
238                      "SYSTEM_RECOVERY_LOG");
239              addFileToDropBox(db, timestamps, headers, "/cache/recovery/last_kmsg",
240                      -LOG_SIZE, "SYSTEM_RECOVERY_KMSG");
241              addAuditErrorsToDropBox(db, timestamps, headers, -LOG_SIZE, "SYSTEM_AUDIT");
242          } else {
243              if (db != null) db.addText("SYSTEM_RESTART", headers);
244          }
245          // log always available fs_stat last so that logcat collecting tools can wait until
246          // fs_stat to get all file system metrics.
247          logFsShutdownTime();
248          logFsMountTime();
249          addFsckErrorsToDropBoxAndLogFsStat(db, timestamps, headers, -LOG_SIZE, "SYSTEM_FSCK");
250          logSystemServerShutdownTimeMetrics();
251  
252          // Scan existing tombstones (in case any new ones appeared)
253          File[] tombstoneFiles = TOMBSTONE_DIR.listFiles();
254          for (int i = 0; tombstoneFiles != null && i < tombstoneFiles.length; i++) {
255              if (tombstoneFiles[i].isFile()) {
256                  addFileToDropBox(db, timestamps, headers, tombstoneFiles[i].getPath(),
257                          LOG_SIZE, "SYSTEM_TOMBSTONE");
258              }
259          }
260  
261          writeTimestamps(timestamps);
262  
263          // Start watching for new tombstone files; will record them as they occur.
264          // This gets registered with the singleton file observer thread.
265          sTombstoneObserver = new FileObserver(TOMBSTONE_DIR.getPath(), FileObserver.CREATE) {
266              @Override
267              public void onEvent(int event, String path) {
268                  HashMap<String, Long> timestamps = readTimestamps();
269                  try {
270                      File file = new File(TOMBSTONE_DIR, path);
271                      if (file.isFile() && file.getName().startsWith("tombstone_")) {
272                          addFileToDropBox(db, timestamps, headers, file.getPath(), LOG_SIZE,
273                                  TAG_TOMBSTONE);
274                      }
275                  } catch (IOException e) {
276                      Slog.e(TAG, "Can't log tombstone", e);
277                  }
278                  writeTimestamps(timestamps);
279              }
280          };
281  
282          sTombstoneObserver.startWatching();
283      }