Android13 救援模式

救援模式:

目前市场上的手机消费者包括资深用户,当他们的手机出现无限循环启动的异常时,用户没有办法修复异常只能通过设备商售后处理。Google在Android 8.0加入该新功能,称之为rescue party救援程序。主要监控系统核心程序出现循环崩溃的时候,会启动该程序,根据不同的救援级别做出一系列操作,看是否可恢复设备,最严重的时候则是通过进入recovery然后提供用户清空用户数据恢复出厂设置解决。

遇到开机进到recovery模式的情况,其实我们全局搜索下关键字“RescueParty”

就可以看到在init进程收到reboot,recovery指令之前,就可以看到因为救援模式,而发生了wipe-data

以下代码基于Android13:

首先救援分不同的级别,不同的级别执行不同的代码逻辑

//QSSI.13\frameworks\base\services\core\java\com\android\server\RescueParty.java
@VisibleForTesting
static final int LEVEL_NONE = 0;
@VisibleForTesting
static final int LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS = 1;
@VisibleForTesting
static final int LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES = 2;
@VisibleForTesting
static final int LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS = 3;
@VisibleForTesting
static final int LEVEL_WARM_REBOOT = 4;
@VisibleForTesting
static final int LEVEL_FACTORY_RESET = 5;
@VisibleForTesting
static final String PROP_RESCUE_BOOT_COUNT = "sys.rescue_boot_count";
@VisibleForTesting
static final String TAG = "RescueParty";
....
private static void executeRescueLevelInternal(Context context, int level, @Nullable
        String failedPackage) throws Exception {
    FrameworkStatsLog.write(FrameworkStatsLog.RESCUE_PARTY_RESET_REPORTED, level);
    // Try our best to reset all settings possible, and once finished
    // rethrow any exception that we encountered
    Exception res = null;
    Runnable runnable;
    Thread thread;
    switch (level) {
        case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS:
            try {
                resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS,
                        level);
            } catch (Exception e) {
                res = e;
            }
            try {
                resetDeviceConfig(context, /*isScoped=*/true, failedPackage);
            } catch (Exception e) {
                res = e;
            }
            break;
        case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES:
            try {
                resetAllSettingsIfNecessary(context, Settings.RESET_MODE_UNTRUSTED_CHANGES,
                        level);
            } catch (Exception e) {
                res = e;
            }
            try {
                resetDeviceConfig(context, /*isScoped=*/true, failedPackage);
            } catch (Exception e) {
                res = e;
            }
            break;
        case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS:
            try {
                resetAllSettingsIfNecessary(context, Settings.RESET_MODE_TRUSTED_DEFAULTS,
                        level);
            } catch (Exception e) {
                res = e;
            }
            try {
                resetDeviceConfig(context, /*isScoped=*/false, failedPackage);
            } catch (Exception e) {
                res = e;
            }
            break;
        case LEVEL_WARM_REBOOT:
            // Request the reboot from a separate thread to avoid deadlock on PackageWatchdog
            // when device shutting down.
            SystemProperties.set(PROP_ATTEMPTING_REBOOT, "true");
            runnable = () -> {
                try {
                    PowerManager pm = context.getSystemService(PowerManager.class);
                    if (pm != null) {
                        pm.reboot(TAG);
                    }
                } catch (Throwable t) {
                    logRescueException(level, failedPackage, t);
                }
            };
            thread = new Thread(runnable);
            thread.start();
            break;
        case LEVEL_FACTORY_RESET:
            SystemProperties.set(PROP_ATTEMPTING_FACTORY_RESET, "true");
            runnable = new Runnable() {
                @Override
                public void run() {
                    try {
                        RecoverySystem.rebootPromptAndWipeUserData(context, TAG);
                    } catch (Throwable t) {
                        logRescueException(level, failedPackage, t);
                    }
                }
            };
            thread = new Thread(runnable);
            thread.start();
            break;
    }

    if (res != null) {
        throw res;
    }
}

触发场景:

(1)system_server 在 10 分钟内重启 5 次以上调整一次级别。(Android 12以前 为5分钟内5次)

(2)永久性系统应用在 50 秒内崩溃 5 次以上调整一次级别。(Android 12 以前 默认为30秒内5次)

当检测到上述某种情况时,救援程序会将其上报给下一救援级别、处理与该级别相关联的任务,并让设备继续运行,看看能否恢复。清除或重置内容的程度随级别而增加。最高级别会提示用户将设备恢复出厂设置。

别的逻辑都比较简单,我们看一下恢复出厂的逻辑:

//QSSI.13/frameworks/base/core/java/android/os/RecoverySystem.java
    public static void rebootPromptAndWipeUserData(Context context, String reason)
            throws IOException {
        boolean checkpointing = false;
        boolean needReboot = false;
        IVold vold = null;
        try {
            vold = IVold.Stub.asInterface(ServiceManager.checkService("vold"));
            if (vold != null) {
                checkpointing = vold.needsCheckpoint();
            } else  {
                Log.w(TAG, "Failed to get vold");
            }
        } catch (Exception e) {
            Log.w(TAG, "Failed to check for checkpointing");
        }

        // If we are running in checkpointing mode, we should not prompt a wipe.
        // Checkpointing may save us. If it doesn't, we will wind up here again.
        // 检测是否可以通过回滚消除问题,
        if (checkpointing) {
            try {
                vold.abortChanges("rescueparty", false);
                Log.i(TAG, "Rescue Party requested wipe. Aborting update");
            } catch (Exception
### 提升 Android 系统救援级别的方法 在 Android 系统中,`RescueParty` 是一种专门设计用来应对系统或关键组件频繁崩溃的机制。该机制的核心目标在于逐步提升救援级别并采取更激进的操作以恢复设备正常运行状态[^1]。 #### 1. **触发条件** 当 `SystemServer` 或持久化应用(Persistent Apps)发生多次连续崩溃时,系统会自动检测这些异常行为,并决定是否需要进入更高的救援级别。每次崩溃都会被记录下来,同时系统内部维护了一个计数器来跟踪失败次数。一旦超过预设阈值,则会升级至下一救援阶段[^2]。 #### 2. **救援等级划分及其操作** - **Level 0**: 初始状态下不执行任何特殊措施;仅简单尝试重新启动受影响的服务。 - **Level 1**: 如果再次遇到相同错误,在此层面上可能会延迟服务重启时间间隔以便观察是否有其他潜在问题浮现出来。 - **Higher Levels (e.g., Level 2, etc.)**: 随着救援级别的升高,后续行动可能涉及清除缓存数据、禁用某些第三方应用程序或者强制关闭特定进程等功能模块直至最终达到最高级即引导用户进入 Recovery Mode 下手动干预比如擦除 Data 分区等极端手段恢复正常工作环境为止. #### 3. **实现逻辑分析** 以下是关于如何编程层面控制 Rescue Party 的伪代码表示: ```java public class RescueManager { private int crashCount; public void handleCrash() { this.crashCount++; switch(getCurrentRescueLevel()) { case RESCUE_LEVEL_0: restartService(); // 尝试直接重啟服務 break; case RESCUE_LEVEL_1: delayRestartAndMonitor(); // 增加延遲並監控 break; default: escalateToNextLevel(); if(isMaxLevelReached()){ enterRecoveryMode(); // 进入恢復模式 } break; } } private int getCurrentRescueLevel(){ // 根據崩潰次數或其他條件計算當前級別 return calculateBasedOn(crashCount); } } ``` 上述代码展示了基于不同救援级别的响应策略以及何时应该推进到下一个更高层次的过程。 #### 4. **注意事项** 开发者需要注意的是,虽然提高救援级别可以帮助解决当前存在的严重问题,但它也可能带来副作用,例如删除用户的个人资料或暂时失去部分功能访问权限等问题。因此,在实际部署之前应当充分测试各种场景下的表现情况,确保不会对用户体验造成负面影响的同时有效解决问题。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值