美文网首页
Android之RescueParty机制

Android之RescueParty机制

作者: 锄禾豆 | 来源:发表于2022-02-04 09:27 被阅读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)

    相关文章

      网友评论

          本文标题:Android之RescueParty机制

          本文链接:https://www.haomeiwen.com/subject/ziwqkrtx.html