Android之RescueParty机制
2022-02-04 本文已影响0人
锄禾豆
参考学习
https://source.android.com/devices/tech/debug/rescue-party?hl=zh-cn
简介
Android 8.0 中纳入了一个功能,当该功能注意到核心系统组件陷入崩溃循环僵局时,就会派出“救援程序”。然后救援程序会通过一系列操作来上报相关情况,以期恢复设备。最后的解决方法是,Rescue Party 使设备重新启动并进入恢复模式,然后提示用户恢复出厂设置。
源码分析 -- Android 10.0
1-1.system_server 进程
1)启动监听。SystemServer.startBootstrapServices
private void startBootstrapServices() {
···
RescueParty.noteBoot(mSystemContext);
···
}
2)RescueParty.noteBoot
public static void noteBoot(Context context) {
//业务是否打开
if (isDisabled()) return;
//数据记录。mBoot是BootThreshold对象
if (sBoot.incrementAndTest()) {
sBoot.reset();
//紧急业务级别记录
incrementRescueLevel(sBoot.uid);
//执行紧急救援
executeRescueLevel(context);
}
}
3)mBoot初始化介绍
//触发次数triggerCount
static final int TRIGGER_COUNT = 5;
//触发次数的时长triggerWindow
static final long BOOT_TRIGGER_WINDOW_MILLIS = 600 * DateUtils.SECOND_IN_MILLIS;
private static class BootThreshold extends Threshold {
public BootThreshold() {
super(android.os.Process.ROOT_UID, TRIGGER_COUNT, BOOT_TRIGGER_WINDOW_MILLIS);
}
···
}
1-2.persistent 进程
1)启动。Ams.handleApplicationCrashInner
AppErrors.crashApplicationInner
void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo,
int callingPid, int callingUid) {
···
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);
}
···
}
2)RescueParty.noteAppCrash
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);
}
}
3)AppThreshold初始化
//触发次数triggerCount,5次
static final int TRIGGER_COUNT = 5;
//触发次数的时长triggerWindow,30秒
static final long PERSISTENT_APP_CRASH_TRIGGER_WINDOW_MILLIS = 30 * DateUtils.SECOND_IN_MILLIS;
private static class AppThreshold extends Threshold {
···
public AppThreshold(int uid) {
super(uid, TRIGGER_COUNT, PERSISTENT_APP_CRASH_TRIGGER_WINDOW_MILLIS);
}
···
}
2.核心记录业务incrementAndTest
public boolean incrementAndTest() {
final long now = getElapsedRealtime();
final long window = now - getStart();
if (window > triggerWindow) {//时长大于10分钟,重置次数和时间
setCount(1);
setStart(now);
return false;
} else {//时长小于等于10分钟,记录次数
int count = getCount() + 1;
setCount(count);
return (count >= triggerCount);
}
}
数据保存采用属性服务
次数:SystemProperties.set("sys.rescue_boot_count"
启动时间:SystemProperties.set("sys.rescue_boot_start"
3.执行紧急救援。根据级别越来越高级
executeRescueLevel --> executeRescueLevelInternal
private static void executeRescueLevelInternal(Context context, int level) throws Exception {
StatsLog.write(StatsLog.RESCUE_PARTY_RESET_REPORTED, level);
switch (level) {
case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS);
break;
case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_CHANGES);
break;
case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
resetAllSettings(context, Settings.RESET_MODE_TRUSTED_DEFAULTS);
break;
case LEVEL_FACTORY_RESET:
//进入recovery模式
RecoverySystem.rebootPromptAndWipeUserData(context, TAG);
break;
}
FlagNamespaceUtils.addToKnownResetNamespaces(
FlagNamespaceUtils.NAMESPACE_NO_PACKAGE);
}
总结
1.system_server进程,在10分钟内,异常发送次数>=5,则发生紧急救援
2.persistent进程,在30秒分,异常发送次数>=5,则发生紧急救援
3.紧急救援范围1-4,可默认自定义到最高级别4(sys.rescue_level)