什么是Rescue Party?
官方解释救援程序[https://source.android.com/devices/tech/debug/rescue-party]
“当该功能注意到核心系统组件陷入崩溃循环僵局时,就会派出“救援程序”。然后救援程序会通过一系列操作来上报相关情况,以期恢复设备。最后的解决方法是,救援程序使设备重新启动并进入恢复模式,然后提示用户恢复出厂设置。”
实现
在 Android 8.0 中,救援程序默认处于启用状态,其实现位于 /services/core/java/com/android/server/RescueParty.java 中。 在出现以下情况时,救援程序会收到有关启动和崩溃事件的信息,然后即会启动:
system_server 在 5 分钟内重启 5 次以上。
永久性系统应用在 30 秒内崩溃 5 次以上。
当检测到上述某种情况时,救援程序会将其上报给下一救援级别、处理与该级别相关联的任务,并让设备继续运行,看看能否恢复。清除或重置内容的程度随级别而增加。最高级别会提示用户将设备恢复出厂设置。
所有的救援操作都会记录到“/data/system/uiderrors.txt”中的永久性的PackageManager日志中。
界面
会显示下面的字串:
“Can`t load Android system. Your data may be corrupt. If you continue to get this message, you may need to perfrom a factory data reset and erase all user data stored on this device.”
相关代码
frameworks/base/services/core/java/com/android/server/RescueParty.java
启动相关的代码:
system/core/bootstat/
大体套路就是,先检查对应的标志位是否足够触发重启了(incrementAndTest),如果足够,先重置标志位,然后升级Rescue Level(不是每个level都会触发factory reset)。执行对应等级对应的操作(executeRescueLevel)
/**
* Take note of a boot event. If we notice too many of these events
* happening in rapid succession, we'll send out a rescue party.
*/
public static void noteBoot(Context context) {
if (isDisabled()) return;
if (sBoot.incrementAndTest()) {
sBoot.reset();
incrementRescueLevel(sBoot.uid);
executeRescueLevel(context);
}
}
/**
* Take note of a persistent app or apex module crash. If we notice too many of these
* events happening in rapid succession, we'll send out a rescue party.
*/
public static void noteAppCrash(Context context, int uid) {
if (isDisabled()) return;
Threshold t = sApps.get(uid);
if (t == null) {
t = new AppThreshold(uid);
sApps.put(uid, t);
}
if (t.incrementAndTest()) {
t.reset();
incrementRescueLevel(t.uid);
executeRescueLevel(context);
}
}
注意里面的incrementAndTest()/incrementRescueLevel/executeRescueLevel三个接口。
Rescue Level
看看,从LEVEL_NONE升级到最后,一定会触发LEVEL_FACTORY_RESET的。
static final int LEVEL_NONE = 0;
static final int LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS = 1;
static final int LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES = 2;
static final int LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS = 3;
static final int LEVEL_FACTORY_RESET = 4;
对于persistent应用来说,应用的crash会触发noteAppCrash:
frameworks/base/services/core/java/com/android/server/am/AppErrors.java
if (r.isPersistent() || isApexModule) {
// If a persistent app or apex module is stuck in a crash loop, the device isn't
// very usable, so we want to consider sending out a rescue party.
RescueParty.noteAppCrash(mContext, r.uid);
}
什么是永久性系统应用,其实就是persist应用(always keep this application running?)。
参考:
官方解释救援程序[https://source.android.com/devices/tech/debug/rescue-party]