恢复模式
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, 如果每次10ms
内system server
发生错误, 连续发生了大于等于5次
, 则执行executeBootLoopMitigation
如果APP发生了糟糕的崩溃, 则执行execute
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();
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
返回true
当onFailureLocked
返回true
, 对监听器执行onHealthCheckFailed
,如果结果不是USER_IMPACT_NONE
, 则最终执行到execute
.
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 }
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 }
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
被调用了, 但是currentObserverToNotify
为null
, 所以跟踪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
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
, 不进入救援模式; 否则热重启后就会执行重置操作.
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
时, RescueParty
按sys.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 : 恢复出厂设置并清除用户数据
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),
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 }
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 }
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.start
为setup-bcb
, 然后把命令发给UncryptSocket
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,
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>
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 }