进入recovery模式分析

tech2026-02-14  1

frameworks/base/services/java/com/android/server/SystemServer.java 305 /** 306 * The main entry point from zygote. 307 */ 308 public static void main(String[] args) { 309 new SystemServer().run(); //SystemServer启动开始 310 } run方法中执行了 java 446 try { 447 traceBeginAndSlog("StartServices"); 448 startBootstrapServices(); //启动startBootstrapServices 449 startCoreServices(); 450 startOtherServices(); 451 SystemServerInitThreadPool.shutdown(); 452 } catch (Throwable ex) { 453 Slog.e("System", "******************************************"); 454 Slog.e("System", "************ Failure starting system services", ex); 455 throw ex; 456 } finally { 457 traceEnd(); 458 } private void startBootstrapServices() { ... 603 // Now that we have the bare essentials of the OS up and running, take 604 // note that we just booted, which might send out a rescue party if 605 // we're stuck in a runtime restart loop. 606 RescueParty.noteBoot(mSystemContext);//注释解释:操作系统刚刚启动,现在救援机制已经随时待命,如果遇到接下来发生的特殊情况的话。 ... } 最终会到 这是第一个会造成触救援发机制的原因, frameworks/base/services/core/java/com/android/server/RescueParty.java 102 /** 103 * Take note of a boot event. If we notice too many of these events 104 * happening in rapid succession, we'll send out a rescue party. 105 */ 106 public static void noteBoot(Context context) { 107 if (isDisabled()) return; 108 if (sBoot.incrementAndTest()) { 109 sBoot.reset(); 110 incrementRescueLevel(sBoot.uid); 111 executeRescueLevel(context); 112 } 113 } 另外一个是本次触发救援机制的原因即APPCrash导致。 115 /** 116 * Take note of a persistent app crash. If we notice too many of these 117 * events happening in rapid succession, we'll send out a rescue party. 118 */ 119 public static void notePersistentAppCrash(Context context, int uid) { 120 if (isDisabled()) return; 121 Threshold t = sApps.get(uid); 122 if (t == null) { 123 t = new AppThreshold(uid); 124 sApps.put(uid, t); 125 } 126 if (t.incrementAndTest()) { 127 t.reset(); 128 incrementRescueLevel(t.uid); 129 executeRescueLevel(context); 130 } 131 } 这两个即https://blog.csdn.net/weixin_33841722/article/details/94650416 这篇博客提到的 1.system_server 在 5 分钟内重启 5 次以上。 2.永久性系统应用在 30 秒内崩溃 5 次以上。 下面重点分析第2种 永久性系统应用在 30 秒内崩溃 5 次以上。 首先 找到进入该方法的入口 frameworks/base/services/core/java/com/android/server/am/AppErrors.java +:445: 442 // If a persistent app is stuck in a crash loop, the device isn't very 443 // usable, so we want to consider sending out a rescue party. 444 if (r != null && r.persistent) { 445 RescueParty.notePersistentAppCrash(mContext, r.uid);//解释为如果一个持久性的应用程序陷入了崩溃循环,那么这个设备就不能很好地使用了,所以我们想考虑派出一个救援队。 446 } 447 那么何为persistent?源码解释为200 boolean persistent; // always keep this application running? 在这里我们可以解释为系统常驻应用,比如systemui,当然还有一些人为增加的保持常驻的应用。 到现在可以进入到RescueParty.java本身开始看问题。 if (isDisabled()) return; isDisabled()的几种条件。 (1) persist.sys.enable_rescue 本身系统没有设值,默认false ,所以得看下面的判断。 (2) eng版本默认return true,不会触发救援机制。 (3) userdebug 版本并且插入usb状态 return true,不会触发救援机制。 (4) persist.sys.disable_rescue 这个值默认也为false ,所以最后return false ,更改这个值为true ,即可关闭触发救援机制。 121 Threshold t = sApps.get(uid); 122 if (t == null) { 123 t = new AppThreshold(uid); 124 sApps.put(uid, t); 125 } ```java 126 if (t.incrementAndTest()) { 127 t.reset(); 128 incrementRescueLevel(t.uid); 129 executeRescueLevel(context); 130 } 接下来分别介绍4个方法 1. t.incrementAndTest() 250 /** 251 * @return if this threshold has been triggered 252 */ 253 public boolean incrementAndTest() { 254 final long now = SystemClock.elapsedRealtime(); 255 final long window = now - getStart(); 256 if (window > triggerWindow) { 257 setCount(1); 258 setStart(now); 259 return false;//持续的时间大于触发窗口的时间即被认定为正常情况 260 } else { 261 int count = getCount() + 1; //出现异常情况在上一次事件+1 262 setCount(count); //将事件数量保存在sys.rescue_boot_count ,读也读这个值 263 EventLogTags.writeRescueNote(uid, count, window); 264 Slog.w(TAG, "Noticed " + count + " events for UID " + uid + " in last " 265 + (window / 1000) + " sec"); 266 return (count >= triggerCount);//上面我们有提到triggerCount这个值为5 ,在构造函数中固定了这个值,所以当事件累积到5次时会return true 267 } 268 } 269 } Log: Line 97942: S02FC4B 08-31 11:33:37.445 3934 11449 W RescueParty: Noticed 2 events for UID 10016 in last 1 sec Line 99210: S0300DB 08-31 11:33:39.086 3934 4382 W RescueParty: Noticed 3 events for UID 10016 in last 3 sec Line 100288: S0304D2 08-31 11:33:40.942 3934 6769 W RescueParty: Noticed 4 events for UID 10016 in last 5 sec Line 102030: S030AAD 08-31 11:33:43.772 3934 11186 W RescueParty: Noticed 5 events for UID 10016 in last 8 sec Line 104296: S0312F7 08-31 11:33:47.373 3934 4382 W RescueParty: Noticed 2 events for UID 10016 in last 1 sec Line 106359: S031AE5 08-31 11:33:49.264 3934 12091 W RescueParty: Noticed 3 events for UID 10016 in last 3 sec Line 107860: S032093 08-31 11:33:51.229 3934 9042 W RescueParty: Noticed 4 events for UID 10016 in last 5 sec Line 109329: S0325B6 08-31 11:33:53.377 3934 7285 W RescueParty: Noticed 5 events for UID 10016 in last 7 sec Line 111998: S032F58 08-31 11:33:57.584 3934 11501 W RescueParty: Noticed 2 events for UID 10016 in last 2 sec Line 113602: S0334E6 08-31 11:33:59.478 3934 7285 W RescueParty: Noticed 3 events for UID 10016 in last 4 sec Line 115201: S033A87 08-31 11:34:02.461 3934 11501 W RescueParty: Noticed 4 events for UID 10016 in last 7 sec Line 116883: S034098 08-31 11:34:05.734 3934 4106 W RescueParty: Noticed 5 events for UID 10016 in last 10 sec Line 119206: S03491B 08-31 11:34:09.965 3934 4906 W RescueParty: Noticed 2 events for UID 10016 in last 1 sec Line 120468: S034DA1 08-31 11:34:11.946 3934 3945 W RescueParty: Noticed 3 events for UID 10016 in last 3 sec Line 121787: S03527D 08-31 11:34:13.810 3934 6769 W RescueParty: Noticed 4 events for UID 10016 in last 5 sec Line 123441: S03584C 08-31 11:34:16.216 3934 4106 W RescueParty: Noticed 5 events for UID 10016 in last 8 sec 2. t.reset(); 245 public void reset() { 246 setCount(0);//之前累积的释放掉,重置为0 247 setStart(0); 248 } 3. incrementRescueLevel(t.uid); 140 /** 141 * Escalate to the next rescue level. After incrementing the level you'll 142 * probably want to call {@link #executeRescueLevel(Context)}. 143 */ 144 private static void incrementRescueLevel(int triggerUid) { 145 final int level = MathUtils.constrain( 146 SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE) + 1, 147 LEVEL_NONE, LEVEL_FACTORY_RESET);//第一次走进来的时候为1,level 也为1 最多为4 为LEVEL_FACTORY_RESET这个值 148 SystemProperties.set(PROP_RESCUE_LEVEL, Integer.toString(level));//保存level 149 150 EventLogTags.writeRescueLevel(level, triggerUid); 151 logCriticalInfo(Log.WARN, "Incremented rescue level to " 152 + levelToString(level) + " triggered by UID " + triggerUid); 153 } 154 35 public static int constrain(int amount, int low, int high) { 36 return amount < low ? low : (amount > high ? high : amount); 37 } 38 Log: Line 102032: S030AAF 08-31 11:33:43.772 3934 11186 W PackageManager: Incremented rescue level to RESET_SETTINGS_UNTRUSTED_DEFAULTS triggered by UID 10016 Line 102033: E030AB0 08-31 11:33:43.772 3934 11186 I pm_critical_info: Incremented rescue level to RESET_SETTINGS_UNTRUSTED_DEFAULTS triggered by UID 10016 Line 109332: S0325B9 08-31 11:33:53.379 3934 7285 W PackageManager: Incremented rescue level to RESET_SETTINGS_UNTRUSTED_CHANGES triggered by UID 10016 Line 109333: E0325BA 08-31 11:33:53.379 3934 7285 I pm_critical_info: Incremented rescue level to RESET_SETTINGS_UNTRUSTED_CHANGES triggered by UID 10016 Line 116885: S03409A 08-31 11:34:05.735 3934 4106 W PackageManager: Incremented rescue level to RESET_SETTINGS_TRUSTED_DEFAULTS triggered by UID 10016 Line 116886: E03409B 08-31 11:34:05.735 3934 4106 I pm_critical_info: Incremented rescue level to RESET_SETTINGS_TRUSTED_DEFAULTS triggered by UID 10016 Line 123443: S03584E 08-31 11:34:16.217 3934 4106 W PackageManager: Incremented rescue level to FACTORY_RESET triggered by UID 10016 Line 123444: E03584F 08-31 11:34:16.217 3934 4106 I pm_critical_info: Incremented rescue level to FACTORY_RESET triggered by UID 10016 4. executeRescueLevel(context); 163 private static void executeRescueLevel(Context context) { 164 final int level = SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE); 165 if (level == LEVEL_NONE) return; 166 167 Slog.w(TAG, "Attempting rescue level " + levelToString(level)); 168 try { 169 executeRescueLevelInternal(context, level);//接下来走这个方法 170 EventLogTags.writeRescueSuccess(level); 171 logCriticalInfo(Log.DEBUG, 172 "Finished rescue level " + levelToString(level)); 173 } catch (Throwable t) { 174 final String msg = ExceptionUtils.getCompleteMessage(t); 175 EventLogTags.writeRescueFailure(level, msg); 176 logCriticalInfo(Log.ERROR, 177 "Failed rescue level " + levelToString(level) + ": " + msg); 178 } 179 } Log: Line 102038: S030AB5 08-31 11:33:43.774 3934 11186 W RescueParty: Attempting rescue level RESET_SETTINGS_UNTRUSTED_DEFAULTS Line 109334: S0325BB 08-31 11:33:53.380 3934 7285 W RescueParty: Attempting rescue level RESET_SETTINGS_UNTRUSTED_CHANGES Line 116887: S03409C 08-31 11:34:05.736 3934 4106 W RescueParty: Attempting rescue level RESET_SETTINGS_TRUSTED_DEFAULTS Line 123445: S035850 08-31 11:34:16.217 3934 4106 W RescueParty: Attempting rescue level FACTORY_RESET Line 102049: S030AC0 08-31 11:33:43.775 3934 11186 D PackageManager: Finished rescue level RESET_SETTINGS_UNTRUSTED_DEFAULTS Line 102050: E030AC1 08-31 11:33:43.775 3934 11186 I pm_critical_info: Finished rescue level RESET_SETTINGS_UNTRUSTED_DEFAULTS Line 109337: S0325BE 08-31 11:33:53.381 3934 7285 D PackageManager: Finished rescue level RESET_SETTINGS_UNTRUSTED_CHANGES Line 109338: E0325BF 08-31 11:33:53.381 3934 7285 I pm_critical_info: Finished rescue level RESET_SETTINGS_UNTRUSTED_CHANGES Line 116894: S0340A3 08-31 11:34:05.747 3934 4106 D PackageManager: Finished rescue level RESET_SETTINGS_TRUSTED_DEFAULTS Line 116895: E0340A4 08-31 11:34:05.747 3934 4106 I pm_critical_info: Finished rescue level RESET_SETTINGS_TRUSTED_DEFAULTS 180 181 private static void executeRescueLevelInternal(Context context, int level) throws Exception { 182 switch (level) { 183 case LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS: 184 resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_DEFAULTS);//重置数据 185 break; 186 case LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES: 187 resetAllSettings(context, Settings.RESET_MODE_UNTRUSTED_CHANGES); 188 break; 189 case LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS: 190 resetAllSettings(context, Settings.RESET_MODE_TRUSTED_DEFAULTS); 191 break; 192 case LEVEL_FACTORY_RESET: 193 //bug917816 debug system_server/zygote manay times restart question. 194 if (Build.IS_USERDEBUG){ 195 Slog.w(TAG, "[SPRD_DBG]RescueParty ERROR system again and again reboot!!!"); 196 }else{ 197 RecoverySystem.rebootPromptAndWipeUserData(context, TAG); 198 } 199 break; 200 } 201 } 202 总结: 第一次常驻应用发生crash,累积5次会从原来的LEVEL_NONE到LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS (0->1) 并且系统做了resetAllSettings,重置了部分数据。 第二次常驻应用发生crash,累积5次会从原来的LEVEL_RESET_SETTINGS_UNTRUSTED_DEFAULTS到LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES(1->2) 并且系统仍然尝试重置部分数据。 第三次常驻应用发生crash,累积5次会从原来的LEVEL_RESET_SETTINGS_UNTRUSTED_CHANGES到LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS(2->3) 并且系统仍然尝试重置部分数据。 第四次常驻应用发生crash,累积5次会从原来的LEVEL_RESET_SETTINGS_TRUSTED_DEFAULTS到LEVEL_FACTORY_RESET(3->4) 会再次判断是否为userdebug软件,然后进入recovery模式。
最新回复(0)