Android O中增加了一个新的功能,当核心系统组件发生循环崩溃的时候,就会触发“救援程序”,也就是本篇要介绍的RescueParty 。然后RescueParty 会通过自身判断逻辑来进行崩溃级别的提升,直到最后触发ResetFactory,进而进入Recovery,然后提示用户恢复出厂设置。
 
接下来根据源码(基于Android Q)来分析下是如何触发救援程序以及进入Recovery。
涉及到的源码路径:

frameworks/base/services/core/java/com/android/server/RescueParty.java
frameworks/base/services/java/com/android/server/SystemServer.java
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
frameworks/base/services/core/java/com/android/server/am/AppErrors.java

通过RescueParty类的概述可以了解到,程序崩溃的足够频繁,并且逐步上升级别,最终通过提示用户擦除数据解决。救援级别分为5级,只有达到LEVEL_FACTORY_RESET这个级别,才会触发设备进入Recovery。而通过"sys.rescue_level"这个属性可以查询当前处于什么级别?

/*** Utilities to help rescue the system from crash loops. Callers are expected to* report boot events and persistent app crashes, and if they happen frequently* enough this class will slowly escalate through several rescue operations* before finally rebooting and prompting the user if they want to wipe data as* a last resort.*///救援级别
static final int LEVEL_NONE = 0;
static final int LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS = 1;
static final int LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES = 2;
static final int LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS = 3;
static final int LEVEL_FACTORY_RESET = 4;

接着来看下如何触发级别上升,并最终达到LEVEL_FACTORY_RESET。RescueParty 类中有一个用来提升级别的方法incrementRescueLevel,从方法名就可以看出作用。存储方式就是从属性中读出,然后+1再写进属性,默认的值就是0。

/*** Escalate to the next rescue level. After incrementing the level you'll* probably want to call {@link #executeRescueLevel(Context)}.*/
private static void incrementRescueLevel(int triggerUid) {final int level = MathUtils.constrain(SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE) + 1,LEVEL_NONE, LEVEL_FACTORY_RESET);SystemProperties.set(PROP_RESCUE_LEVEL, Integer.toString(level));EventLogTags.writeRescueLevel(level, triggerUid);logCriticalInfo(Log.WARN, "Incremented rescue level to "+ levelToString(level) + " triggered by UID " + triggerUid);
}

该方法是私有方法,本类中的调用方有两处,分别对应了两种不同的场景——
永久性系统应用在 30 秒内崩溃 5 次以上和system_server 在 10 分钟内重启 5 次以上。
 
1、noteAppCrash; //记录App奔溃
2、noteBoot; //记录Boot阶段奔溃,也就是system_server奔溃

//场景1:
/*** Take note of a persistent app or apex module crash. If we notice too many of these* events happening in rapid succession, we'll send out a rescue party.*/
public static void noteAppCrash(Context context, int uid) {if (isDisabled()) return;        //该功能是否已经关闭Threshold t = sApps.get(uid);   //查看该uid对应的app是否已经出现过crashif (t == null) {t = new AppThreshold(uid);sApps.put(uid, t);          //未出现就新增一个记录}if (t.incrementAndTest()) {     //判断是否需要提升救援级别t.reset();incrementRescueLevel(t.uid);executeRescueLevel(context);}
}//场景2
/*** Take note of a boot event. If we notice too many of these events* happening in rapid succession, we'll send out a rescue party.*/
public static void noteBoot(Context context) {if (isDisabled()) return;if (sBoot.incrementAndTest()) {sBoot.reset();incrementRescueLevel(sBoot.uid);executeRescueLevel(context);}
}

场景1就是AMS记录到app crash后调到AppErrors中的crashApplication方法来处理该crash,之后会判断是常驻进程或者是Apex组件化模块就调用noteAppCrash触发救援程序。

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则判断是否存在boot阶段持续崩溃,也就是会不会有连续重启的事件发生。该场景触发是在system_server进程启动的过程中。所以判断的机制相当于是对system_server的监控,实际上该进程也可以理解为一个特殊的app。

private void startBootstrapServices() {...RescueParty.noteBoot(mSystemContext);...
}

该场景的触发是针对Q以及之前的源码逻辑,R上已经将该逻辑调整到PackagesWatchDog这个类中来实现,此类也是在system_server启动过程拉起来的,因此殊途同归。
 
最后来看下RescueParty的逻辑,如何实现crash的监控。前面提到,每次触发救援级别提升前,都会先通过incrementAndTest来判断是否需要提升,所以该方法是实际上对救援级别提升的判断标准。

public boolean incrementAndTest() {final long now = getElapsedRealtime();   //获取系统现在的时间final long window = now - getStart();    //系统时间与救援开始时间的差值//triggerWindow对应BOOT_TRIGGER_WINDOW_MILLIS或者PERSISTENT_APP_CRASH_TRIGGER_WINDOW_MILLIS分别对应600s和30sif (window > triggerWindow) {   //超过预定的时间后则重新开始,计数为1,时间从现在开始计算;setCount(1);setStart(now);return false;} else {    //反之,如果在预定的时间内再次触发,则计数+1,int count = getCount() + 1;setCount(count);EventLogTags.writeRescueNote(uid, count, window);Slog.w(TAG, "Noticed " + count + " events for UID " + uid + " in last "+ (window / 1000) + " sec");return (count >= triggerCount);  //返回计数是否达到预期,也就是5次}
}

以上便是RescueParty的整体逻辑,逻辑清晰明了。目的也很纯粹,就是通过监控崩溃的程序来确认系统是否遇到了严重的问题,通过提示用户清除数据来恢复。

RescueParty 简述相关推荐

  1. 简述计算机科学的核心内容,北京大学-计算机科学与技术(2018秋)作业及复习

    59.(第十章)外排序是指在排序前后,数据在外存上,排序时数据调入内存进行的排序方法. 60.(第十章)在选择排序.冒泡排序.归并排序中, 归并排序是空间复杂度最大的. 三.简答和程序题(共10题,每 ...

  2. 设计模式学习1:设计模式简述和设计模式原则

    设计模式简述 什么是设计模式? 软件工程中,设计模式(design pattern)是对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案. 设计模式的目的: 代码高可用(相同作用的代码能重复 ...

  3. Java中常见的锁简述

    在Java的应用中,或多或少的都会接触到一些锁,那么问题就来了,在Java中,常见的锁有哪些,都有什么样的作用?? 这里给大家简单的简述一下这些学常见的锁. 本文件所涉及到的锁: 1.公平锁 / 非公 ...

  4. 简述DataInputStream和DataOuputStream

    2019独角兽企业重金招聘Python工程师标准>>> Java开发中经常会用到IO流,那么就会碰到DataInputStream和DataOuputStream这两个包装类.下面就 ...

  5. 简要叙述matlab的含义,1,简述MATLAB组成部分? 2,说明使用M文件编辑/调试器的方法和优点? 3,存储在工作空间中的数组能编辑吗...

    匿名用户 1级 2012-05-17 回答 我也考这个....祝你好运 1,简述MATLAB组成部分? (1)开发环境(development Environment); (2)MATLAB数学函数库 ...

  6. 简述Linux和Windows下Python搭建步骤

    简述就Windows和Linux环境下安装Python的步骤. Python环境搭建首先到官网(www.python.org)下载相应的安装版本.主要分为Windows和Linux两种: 一.Linu ...

  7. 简述 OAuth 2.0 的运作流程

    本文将以用户使用 github 登录网站留言为例,简述 OAuth 2.0 的运作流程. 假如我有一个网站,你是我网站上的访客,看了文章想留言表示「朕已阅」,留言时发现有这个网站的帐号才能够留言,此时 ...

  8. 简述机器指令与微指令之间的关系_自考《计算机组成原理》模拟试题(一)

    一.单项选择题(本大题共 25小题,每小题1分,共25分)在每小题列出的四个选项中只有一个选项是符合题目要求的,请将正确选项前的字母填在题后的括号内. 1.-0的8位二进制补码是( ) A.10000 ...

  9. day1简述、输入输出、运算符、条件语句、文件读写、三元运算

    文章目录 1.Python 简述 2.变量 3.输入输出 4.数据运算 5. 条件语句 if..else.elif 循环语句 for.while 6.文件读写 7.三元运算 1.Python 简述   ...

最新文章

  1. 阿里副总裁肖利华:数智化转型的7个关键词
  2. 基于用例点来度量软件规模并管理进度 之二
  3. [Verilog] parameter
  4. c语言错误重定义,C语言的重定义错误求解
  5. 一建机电实务教材电子版_20年一建其实并不难,官方出版:复习题集(精修),速做速提90分...
  6. 学习笔记7-C语言-进制转换、原返补、位运算、函数
  7. 服务器数据库密码修改了,服务器密码修改后数据库
  8. 12月22日 冬至 隋文帝赏柳上上签
  9. 3D顶点转换和法线转换
  10. BZOJ 1857: [Scoi2010]传送带
  11. html中如何调整图片的对比色,风光照片如何调出冷暖对比色?后期案例分享
  12. 【Python基础】制作一个汇率换算程序
  13. 接收IWebBrowser2的自动化事件
  14. nexus5 博通芯片WIFI详解 (2)
  15. 饥荒为啥显示专用服务器,饥荒服务器和专用服务器有什么区别 | 手游网游页游攻略大全...
  16. C++基础概念(初步代码示例英石与磅单位互换)
  17. UE4材质—UV和贴图坐标系
  18. PHP:抓取网页指定内容
  19. 知明:技术 Leader 的思考法
  20. java画星星_用java画色彩斑斓的星星

热门文章

  1. 笔记本不能上网的原因和维修方法
  2. DApp投票合约简单开发步骤(完整)
  3. ROS 乌龟追逐实验
  4. pdf模板带图片二维码导出(多个)
  5. redis-09-哨兵模式
  6. 根据用户所在部门id,返回所在部门id及子部门id
  7. 英语见面礼仪:与各国友人见面必说的第一句话
  8. WID Process Server
  9. 2018-11-14 MIDI音乐格式笔记学习
  10. 树莓派python智能家居英文参考文献_Home Assistant + 树莓派:强大的智能家居系统 · 小米篇...