赞
踩
应用崩溃过程:常驻应用不断崩溃,救援等级增加,最终达到LEVEL_FACTORY_RESET等级。进入recovery(Android 9.0源码):
frameworks\base\services\core\java\com\android\server\am\AppErrors.java
/** * Bring up the "unexpected error" dialog box for a crashing app. * Deal with edge cases (intercepts from instrumented applications, * ActivityController, error intent receivers, that sort of thing). * @param r the application crashing * @param crashInfo describing the failure */ void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) { final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); try { crashApplicationInner(r, crashInfo, callingPid, callingUid); } finally { Binder.restoreCallingIdentity(origId); } }
void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo, int callingPid, int callingUid) { long timeMillis = System.currentTimeMillis(); String shortMsg = crashInfo.exceptionClassName; String longMsg = crashInfo.exceptionMessage; String stackTrace = crashInfo.stackTrace; if (shortMsg != null && longMsg != null) { longMsg = shortMsg + ": " + longMsg; } else if (shortMsg != null) { longMsg = shortMsg; } // If a persistent app is stuck in a crash loop, the device isn't very // usable, so we want to consider sending out a rescue party. if (r != null && r.persistent) { //常驻应用调用,该地方可以添加自己的代码保存Log日志,shortMsg longMsg stackTrace RescueParty.notePersistentAppCrash(mContext, r.uid); } ......................
/** * Take note of a persistent app crash. If we notice too many of these * events happening in rapid succession, we'll send out a rescue party. */ public static void notePersistentAppCrash(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); } }
/** * Escalate to the next rescue level. After incrementing the level you'll * probably want to call {@link #executeRescueLevel(Context)}. * 增加救援等级,执行executeRescueLevel */ 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); }
private static void executeRescueLevel(Context context) { final int level = SystemProperties.getInt(PROP_RESCUE_LEVEL, LEVEL_NONE); if (level == LEVEL_NONE) return; Slog.w(TAG, "Attempting rescue level " + levelToString(level)); try { executeRescueLevelInternal(context, level); EventLogTags.writeRescueSuccess(level); logCriticalInfo(Log.DEBUG, "Finished rescue level " + levelToString(level)); } catch (Throwable t) { final String msg = ExceptionUtils.getCompleteMessage(t); EventLogTags.writeRescueFailure(level, msg); logCriticalInfo(Log.ERROR, "Failed rescue level " + levelToString(level) + ": " + msg); } } private static void executeRescueLevelInternal(Context context, int level) throws Exception { 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; } }
/** {@hide} */ public static void rebootPromptAndWipeUserData(Context context, String reason) throws IOException { String reasonArg = null; if (!TextUtils.isEmpty(reason)) { reasonArg = "--reason=" + sanitizeArg(reason); } final String localeArg = "--locale=" + Locale.getDefault().toString(); bootCommand(context, null, "--prompt_and_wipe_data", reasonArg, localeArg); } /** * Reboot into the recovery system with the supplied argument. * @param args to pass to the recovery utility. * @throws IOException if something goes wrong. */ private static void bootCommand(Context context, String... args) throws IOException { LOG_FILE.delete(); StringBuilder command = new StringBuilder(); for (String arg : args) { if (!TextUtils.isEmpty(arg)) { command.append(arg); command.append("\n"); } } // Write the command into BCB (bootloader control block) and boot from // there. Will not return unless failed. //进入 Recovery RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE); rs.rebootRecoveryWithCommand(command.toString()); throw new IOException("Reboot failed (no permissions?)"); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。