救援模式:
目前市场上的手机消费者包括资深用户,当他们的手机出现无限循环启动的异常时,用户没有办法修复异常只能通过设备商售后处理。Google在Android 8.0加入该新功能,称之为rescue party救援程序。主要监控系统核心程序出现循环崩溃的时候,会启动该程序,根据不同的救援级别做出一系列操作,看是否可恢复设备,最严重的时候则是通过进入recovery然后提供用户清空用户数据恢复出厂设置解决。
遇到开机进到recovery模式的情况,其实我们全局搜索下关键字“RescueParty”
就可以看到在init进程收到reboot,recovery指令之前,就可以看到因为救援模式,而发生了wipe-data
以下代码基于Android13:
首先救援分不同的级别,不同的级别执行不同的代码逻辑
//QSSI.13\frameworks\base\services\core\java\com\android\server\RescueParty.java
@VisibleForTesting
static final int LEVEL_NONE = 0;
@VisibleForTesting
static final int LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS = 1;
@VisibleForTesting
static final int LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES = 2;
@VisibleForTesting
static final int LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS = 3;
@VisibleForTesting
static final int LEVEL_WARM_REBOOT = 4;
@VisibleForTesting
static final int LEVEL_FACTORY_RESET = 5;
@VisibleForTesting
static final String PROP_RESCUE_BOOT_COUNT = "sys.rescue_boot_count";
@VisibleForTesting
static final String TAG = "RescueParty";
....
private static void executeRescueLevelInternal(Context context, int level, @Nullable
String failedPackage) throws Exception {
FrameworkStatsLog.write(FrameworkStatsLog.RESCUE_PARTY_RESET_REPORTED, level);
// Try our best to reset all settings possible, and once finished
// rethrow any exception that we encountered
Exception res = null;
Runnable runnable;
Thread thread;
switch (level) {
case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
try {
resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS,
level);
} catch (Exception e) {
res = e;
}
try {
resetDeviceConfig(context, /*isScoped=*/true, failedPackage);
} catch (Exception e) {
res = e;
}
break;
case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
try {
resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_CHANGES,
level);
} catch (Exception e) {
res = e;
}
try {
resetDeviceConfig(context, /*isScoped=*/true, failedPackage);
} catch (Exception e) {
res = e;
}
break;
case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
try {
resetAllSettingsIfNecessary(context, Settings.RESET_MODE_TRUSTED_DEFAULTS,
level);
} catch (Exception e) {
res = e;
}
try {
resetDeviceConfig(context, /*isScoped=*/false, failedPackage);
} catch (Exception e) {
res = e;
}
break;
case LEVEL_WARM_REBOOT:
// Request the reboot from a separate thread to avoid deadlock on PackageWatchdog
// when device shutting down.
SystemProperties.set(PROP_ATTEMPTING_REBOOT, "true");
runnable = () -> {
try {
PowerManager pm = context.getSystemService(PowerManager.class);
if (pm != null) {
pm.reboot(TAG);
}
} catch (Throwable t) {
logRescueException(level, failedPackage, t);
}
};
thread = new Thread(runnable);
thread.start();
break;
case LEVEL_FACTORY_RESET:
SystemProperties.set(PROP_ATTEMPTING_FACTORY_RESET, "true");
runnable = new Runnable() {
@Override
public void run() {
try {
RecoverySystem.rebootPromptAndWipeUserData(context, TAG);
} catch (Throwable t) {
logRescueException(level, failedPackage, t);
}
}
};
thread = new Thread(runnable);
thread.start();
break;
}
if (res != null) {
throw res;
}
}
触发场景:
(1)system_server 在 10 分钟内重启 5 次以上调整一次级别。(Android 12以前 为5分钟内5次)
(2)永久性系统应用在 50 秒内崩溃 5 次以上调整一次级别。(Android 12 以前 默认为30秒内5次)
当检测到上述某种情况时,救援程序会将其上报给下一救援级别、处理与该级别相关联的任务,并让设备继续运行,看看能否恢复。清除或重置内容的程度随级别而增加。最高级别会提示用户将设备恢复出厂设置。
别的逻辑都比较简单,我们看一下恢复出厂的逻辑:
//QSSI.13/frameworks/base/core/java/android/os/RecoverySystem.java
public static void rebootPromptAndWipeUserData(Context context, String reason)
throws IOException {
boolean checkpointing = false;
boolean needReboot = false;
IVold vold = null;
try {
vold = IVold.Stub.asInterface(ServiceManager.checkService("vold"));
if (vold != null) {
checkpointing = vold.needsCheckpoint();
} else {
Log.w(TAG, "Failed to get vold");
}
} catch (Exception e) {
Log.w(TAG, "Failed to check for checkpointing");
}
// If we are running in checkpointing mode, we should not prompt a wipe.
// Checkpointing may save us. If it doesn't, we will wind up here again.
// 检测是否可以通过回滚消除问题,
if (checkpointing) {
try {
vold.abortChanges("rescueparty", false);
Log.i(TAG, "Rescue Party requested wipe. Aborting update");
} catch (Exception