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)

上一篇下一篇

猜你喜欢

热点阅读