前言
不知道你有没有遇过,就是有时系统开机异常,会直接进入到一个机器人的error界面。我这边就遇到,在OTA升级后,开机后会自动重启,且进入到机器人error界面。经查找,是由于有一个进程在系统开机的时候,不断重启,触发了RescueParty机制,今天在这带大家稍微了解下这个机制。
RescueParty
目前市场上的消费者包括小白用户,当他们的手机出现无限循环启动的异常时,用户没有办法修复异常只能通过设备商售后处理。
Google在Android 8.0加入该新功能,称之为rescue party救援程序。
主要监控系统核心程序出现循环崩溃的时候,会启动该程序,根据不同的救援级别做出一系列操作,看是否可恢复设备,最严重的时候则是通过进入recovery然后提供用户清空用户数据恢复出厂设置解决。
代码路径
frameworks\base\services\core\java\com\android\server\RescueParty.java
救援级别
private static final int LEVEL_NONE = 0;
private static final intLEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS = 1; //主要针对非系统进程的属性设置进行重置
private static final intLEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES = 2;//针对非系统进程属性,来自系统默认的属性重置,其他删除
private static final intLEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS = 3;//所有进程系统默认的属性重置,其他删除
private static final intLEVEL_FACTORY_RESET = 4; //尝试恢复出厂设置
触发场景
(1)system_server 在 5 分钟内重启 5 次以上调整一次级别。
(2)永久性系统应用在 30 秒内崩溃 5 次以上调整一次级别。
救援程序的禁用场景
(1)PROP_ENABLE_RESCUE属性值为false,并且PROP_DISABLE_RESCUE为true
(2)eng版本下
(3)手机连接usb模式
对外接口
在AppErrors.java的crashApplicationInner方法中加上了RescueParty监控,具体代码如下:
void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo,
int callingPid, int callingUid) {
...
// If a persistent app is stuck in a crash loop, the device isn't very
// usable, so we want to consider sending out a rescue party.
if (r != null && r.persistent) {
RescueParty.notePersistentAppCrash(mContext, r.uid);
}
AppErrorResult result = new AppErrorResult();
TaskRecord task;
...
}
这里调用了 RescueParty的notePersistentAppCrash方法,并传入了Context和进程uid.现在我们进入方法内部看看:
/**
* Take note of a persistent app crash. If we notice too many of these
* events happening in rapid succession, we'll send out a rescue party.
*/
public static void notePersistentAppCrash(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);
}
}
番外
当设备具有有效的 USB 数据连接时,系统会停止所有救援事件,因为这是一个较强的信号,表示有人正在调试设备。
要停止此类抑制行为,请运行:
adb shell setprop persist.sys.enable_rescue 1
查看源码,可发现,在判断该机制是否生效的方法中,该属性被放在最前面,即优先判断该属性。
在此处,您可以触发系统或界面崩溃循环。
要触发低级 system_server 崩溃循环,请运行:
adb shell setprop debug.crash_system 1
要触发中级 SystemUI 崩溃循环,请运行:
adb shell setprop debug.crash_sysui 1
这两个崩溃循环都会启动救援逻辑。所有的救援操作也都会记录到存储在 /data/system/uiderrors.txt 中的永久性的 PackageManager 日志中,以供日后进行检查和调试。 此外,“软件包警告消息”部分下的每个错误报告中也会包含这些永久性的日志。