做电子商务网站需要什么手续,php做网站和小程序很好,建设包包网站的目的,公司用wordpress建站用花钱1. RuntimeInit.commonInit()
上层应用都是由Zygote fork孵化出来的#xff0c;分为system_server进程和普通应用进程进程创建之初会设置未捕获异常的处理器#xff0c;当系统抛出未捕获的异常时候都会交给异常处理器RuntimeInit.java的commonInit方法设置UncaughtHandler
…1. RuntimeInit.commonInit()
上层应用都是由Zygote fork孵化出来的分为system_server进程和普通应用进程进程创建之初会设置未捕获异常的处理器当系统抛出未捕获的异常时候都会交给异常处理器RuntimeInit.java的commonInit方法设置UncaughtHandler
//frameworks/base/core/java/com/android/internal/os/RuntimeInit.javaprotected static final void commonInit() {...LoggingHandler loggingHandler new LoggingHandler();RuntimeHooks.setUncaughtExceptionPreHandler(loggingHandler);Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));...}········//libcore/dalvik/src/main/java/dalvik/system/RuntimeHooks.javaSystemApi(client MODULE_LIBRARIES)public static void setUncaughtExceptionPreHandler(Nullable Thread.UncaughtExceptionHandler uncaughtExceptionHandler) {Thread.setUncaughtExceptionPreHandler(uncaughtExceptionHandler);}
···········//libcore/ojluni/annotations/hiddenapi/java/lang/Thread.javapublic static void setUncaughtExceptionPreHandler(UncaughtExceptionHandler eh) {uncaughtExceptionPreHandler eh;}
// 注意 一个setUncaughtExceptionPreHandler 一个setDefaultUncaughtExceptionHandlerpublic static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {// Android-removed: SecurityManager stubbed out on Android./*SecurityManager sm System.getSecurityManager();if (sm ! null) {sm.checkPermission(new RuntimePermission(setDefaultUncaughtExceptionHandler));}*/defaultUncaughtExceptionHandler eh;}1.1LoggingHandler
UncaughtExceptionHandler只定义了一个接口方法 public void uncaughtException(java.lang.Thread t, java.lang.Throwable e) private static class LoggingHandler implements Thread.UncaughtExceptionHandler {public volatile boolean mTriggered false;Overridepublic void uncaughtException(Thread t, Throwable e) {mTriggered true;// Dont re-enter if KillApplicationHandler has already run//已经在crash 流程中则已经在处理KillApplicationHandler则不再重复进入if (mCrashing) return;// mApplicationObject is null for non-zygote java programs (e.g. am)// There are also apps running with the system UID. We dont want the// first clause in either of these two cases, only for system_server.if (mApplicationObject null (Process.SYSTEM_UID Process.myUid())) {// sysyem_server进程Clog_e(TAG, *** FATAL EXCEPTION IN SYSTEM PROCESS: t.getName(), e);} else {logUncaught(t.getName(), ActivityThread.currentProcessName(), Process.myPid(), e);}}}........................public static void logUncaught(String threadName, String processName, int pid, Throwable e) {StringBuilder message new StringBuilder();// The FATAL EXCEPTION string is still used on Android even though// apps can set a custom UncaughtExceptionHandler that renders uncaught// exceptions non-fatal.//这个就是日志经常看到的 TAG是AndroidRuntime打印message.append(FATAL EXCEPTION: ).append(threadName).append(\n);if (processName ! null) {message.append(Process: ).append(processName).append(, );}message.append(PID: ).append(pid);Clog_e(TAG, message.toString(), e);}当线程因为未捕获的异常停止时Java 虚拟机会调用 uncaughtException() 函数。
可以看出uncaughtException() 是在crash 最开始调用的用以输出crash 开头信息
当 system 进程crash提示 *** FATAL EXCEPTION IN SYSTEM PROCESS: [线程名]当 app 进程crash 提示三个内容 FATAL EXCEPTION: [线程名]Process: [进程名], PID: [pid]对于processName 为null只会提示PID。
1.2 setUncaughtExceptionPreHandler SystemApi(client MODULE_LIBRARIES)public static void setUncaughtExceptionPreHandler(Nullable Thread.UncaughtExceptionHandler uncaughtExceptionHandler) {Thread.setUncaughtExceptionPreHandler(uncaughtExceptionHandler);}1.3 KillApplicationHandler
//frameworks/base/core/java/com/android/internal/os/RuntimeInit.javaprivate static class KillApplicationHandler implements Thread.UncaughtExceptionHandler {private final LoggingHandler mLoggingHandler;public KillApplicationHandler(LoggingHandler loggingHandler) {this.mLoggingHandler Objects.requireNonNull(loggingHandler);}Overridepublic void uncaughtException(Thread t, Throwable e) {...}...}KillApplicationHandler 类以及构造中传入的LoggingHandler都是实现UncaughtExceptionHandler 接口
2 KillApplicationHandler.uncaughtException()
当线程因为未捕获的异常停止时java虚拟机会调用uncaughtException()函数即调用KillApplicationHandler 中的 uncaughtException() 函数下面好好看下uncaughtException() 函数
//frameworks/base/core/java/com/android/internal/os/RuntimeInit.javapublic void uncaughtException(Thread t, Throwable e) {try {//调用LoggingHandler.uncaughtException()不会反复调用ensureLogging(t, e);//全局变量用以控制重复进入crash流程第一次进入后会将该变量置trueif (mCrashing) return;mCrashing true;//尝试去停止profiling因为后面需要kill 进程内存buffer会丢失//所以尝试停止来 flush 内存bufferif (ActivityThread.currentActivityThread() ! null) {ActivityThread.currentActivityThread().stopProfiling();}//弹出crash对话框等待处理完成ActivityManager.getService().handleApplicationCrash(mApplicationObject, new ApplicationErrorReport.ParcelableCrashInfo(e));} catch (Throwable t2) {if (t2 instanceof DeadObjectException) {// System process is dead; ignore} else {try {Clog_e(TAG, Error reporting crash, t2);} catch (Throwable t3) {// Even Clog_e() fails! Oh well.}}} finally {//确保当前进程彻底杀掉Process.killProcess(Process.myPid());System.exit(10);}}通过 AMS 调用 handleApplicationCrash() 函数进行 crash report共两个参数
第一个参数为进程对象第二个参数为ParcelableCrashInfo(父类为 CrashInfo 实现 Parcelable接口)CrashInfo 类主要是保存 crash 信息文件名、类名、方法名、对应行号、异常信息等
3 AMS.handleApplicationCrash()
//frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.javapublic void handleApplicationCrash(IBinder app,ApplicationErrorReport.ParcelableCrashInfo crashInfo) {ProcessRecord r findAppProcess(app, Crash);final String processName app null ? system_server: (r null ? unknown : r.processName);handleApplicationCrashInner(crash, r, processName, crashInfo);}该函数主要两个操作
确定进程名handleApplicationCrashInner() 函数调用
对于进程名
当参数 app 为null表示 system_server 进程当参数 app不为null通过findAppProcess() 确认ProcessRecord进而确认进程名
3.1 AMS.handleApplicationCrashInner()
//frameworks/base/services/core/java/com/android/server/am/AMS.javavoid handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,ApplicationErrorReport.CrashInfo crashInfo) {EventLogTags.writeAmCrash(Binder.getCallingPid(),UserHandle.getUserId(Binder.getCallingUid()), processName,r null ? -1 : r.info.flags,crashInfo.exceptionClassName,crashInfo.exceptionMessage,crashInfo.throwFileName,crashInfo.throwLineNumber);FrameworkStatsLog.write(FrameworkStatsLog.APP_CRASH_OCCURRED,Binder.getCallingUid(),eventType,processName,Binder.getCallingPid(),(r ! null r.info ! null) ? r.info.packageName : ,(r ! null r.info ! null) ? (r.info.isInstantApp()? FrameworkStatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__TRUE: FrameworkStatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__FALSE): FrameworkStatsLog.APP_CRASH_OCCURRED__IS_INSTANT_APP__UNAVAILABLE,r ! null ? (r.isInterestingToUserLocked()? FrameworkStatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__FOREGROUND: FrameworkStatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__BACKGROUND): FrameworkStatsLog.APP_CRASH_OCCURRED__FOREGROUND_STATE__UNKNOWN,processName.equals(system_server) ? ServerProtoEnums.SYSTEM_SERVER: (r ! null) ? r.getProcessClassEnum(): ServerProtoEnums.ERROR_SOURCE_UNKNOWN);final int relaunchReason r null ? RELAUNCH_REASON_NONE: r.getWindowProcessController().computeRelaunchReason();final String relaunchReasonString relaunchReasonToString(relaunchReason);if (crashInfo.crashTag null) {crashInfo.crashTag relaunchReasonString;} else {crashInfo.crashTag crashInfo.crashTag relaunchReasonString;}addErrorToDropBox(eventType, r, processName, null, null, null, null, null, null, crashInfo);mAppErrors.crashApplication(r, crashInfo);}函数比较长主要做了下面几件事情 写event log 类似 12-01 16:45:29.663198 1260 3220 I am_crash: [21597,0,com.qualcomm.qti.PresenceApp,550026821,java.lang.NoSuchMethodException,com.qualcomm.qti.PresenceApp.SubsriptionTab.init [],Class.java,2363] addErrorToDropBox() 将crash 的信息输出到 /data/system/dropbox/ 下例如system_server 的dropbox 文件名为 system_server_crashxxx.txt (xxx 代表时间戳) crashApplication() 继续处理 crash 流程发出 SHOW_ERROR_UI_MSG弹出 crash 对话框
4. AppErrors.crashApplication()
//frameworks/base/services/core/java/com/android/server/am/AppErrors.javavoid 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);}}
//-------------------------------------------------------------------------------------------private void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo,int callingPid, int callingUid) {
.........................................................AppErrorResult result new AppErrorResult();int taskId;synchronized (mService) {/*** If crash is handled by instance of {link android.app.IActivityController},* finish now and dont show the app error dialog.*/if (handleAppCrashInActivityController(r, crashInfo, shortMsg, longMsg, stackTrace,timeMillis, callingPid, callingUid)) {return;}// If we cant identify the process or its already exceeded its crash quota,// quit right away without showing a crash dialog.if (r null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, data)) {return;}final Message msg Message.obtain();msg.what ActivityManagerService.SHOW_ERROR_UI_MSG;taskId data.taskId;msg.obj data;mService.mUiHandler.sendMessage(msg);}int res result.get();Intent appErrorIntent null;MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_CRASH, res);if (res AppErrorDialog.TIMEOUT || res AppErrorDialog.CANCEL) {res AppErrorDialog.FORCE_QUIT;}switch (res) {case AppErrorDialog.MUTE:synchronized (mBadProcessLock) {stopReportingCrashesLBp(r);}break;case AppErrorDialog.RESTART:synchronized (mService) {mService.mProcessList.removeProcessLocked(r, false, true,ApplicationExitInfo.REASON_CRASH, crash);}if (taskId ! INVALID_TASK_ID) {try {mService.startActivityFromRecents(taskId,ActivityOptions.makeBasic().toBundle());} catch (IllegalArgumentException e) {// Hmm...that didnt work. Task should either be in recents or associated// with a stack.Slog.e(TAG, Could not restart taskId taskId, e);}}break;case AppErrorDialog.FORCE_QUIT:final long orig Binder.clearCallingIdentity();try {// Kill it with fire!mService.mAtmInternal.onHandleAppCrash(r.getWindowProcessController());if (!r.isPersistent()) {synchronized (mService) {mService.mProcessList.removeProcessLocked(r, false, false,ApplicationExitInfo.REASON_CRASH, crash);}mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);}} finally {Binder.restoreCallingIdentity(orig);}break;case AppErrorDialog.APP_INFO:appErrorIntent new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);appErrorIntent.setData(Uri.parse(package: r.info.packageName));appErrorIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);break;case AppErrorDialog.FORCE_QUIT_AND_REPORT:synchronized (mProcLock) {appErrorIntent createAppErrorIntentLOSP(r, timeMillis, crashInfo);}break;}if (appErrorIntent ! null) {try {mContext.startActivityAsUser(appErrorIntent, new UserHandle(r.userId));} catch (ActivityNotFoundException e) {Slog.w(TAG, bug report receiver dissappeared, e);}}}handleAppCrashInActivityController() 如果是 IActivityController 类型该处理的 crash是不会弹出对话框通过该函数进入 makeAppCrashingLocked() 流程。makeAppCrashingLocked() 如果无法识别进程或者进程已经超过crash 额度将不再弹出对话框而是直接return到上一级发出 SHOW_ERROR_UI_MSG 消息弹出crash 对话框详细看下面第 6 节等待用户选择根据不同选择做进一步处理
5 makeAppCrashingLocked
//frameworks/base/services/core/java/com/android/server/am/AppErrors.javaGuardedBy(mService)private boolean makeAppCrashingLocked(ProcessRecord app,String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {synchronized (mProcLock) {final ProcessErrorStateRecord errState app.mErrorState;errState.setCrashing(true);//封装crash信息到crashingReport对象 generateProcessError 5.1errState.setCrashingReport(generateProcessError(app,ActivityManager.ProcessErrorStateInfo.CRASHED,null, shortMsg, longMsg, stackTrace));//5.2errState.startAppProblemLSP();app.getWindowProcessController().stopFreezingActivities();synchronized (mBadProcessLock) {//5.3return handleAppCrashLSPB(app, force-crash /*reason*/, shortMsg, longMsg,stackTrace, data);}}}5.1 generateProcessError()
//frameworks/base/services/core/java/com/android/server/am/AppErrors.java
//通过该函数创建 ActivityManager.ProcessErrorStateInfo 对象并保存在 app.crashingReport 对象中ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,int condition, String activity, String shortMsg, String longMsg, String stackTrace) {ActivityManager.ProcessErrorStateInfo report new ActivityManager.ProcessErrorStateInfo();report.condition condition;report.processName app.processName;report.pid app.pid;report.uid app.info.uid;report.tag activity;report.shortMsg shortMsg;report.longMsg longMsg;report.stackTrace stackTrace;return report;}5.2 startAppProblemLSP()
//frameworks/base/services/core/java/com/android/server/am/ProcessRecord.javaGuardedBy({mService, mProcLock})void startAppProblemLSP() {// If this app is not running under the current user, then we cant give it a report button// because that would require launching the report UI under a different user.mErrorReportReceiver null;for (int userId : mService.mUserController.getCurrentProfileIds()) {if (mApp.userId userId) {mErrorReportReceiver ApplicationErrorReport.getErrorReportReceiver(mService.mContext, mApp.info.packageName, mApp.info.flags);}}mService.skipCurrentReceiverLocked(mApp);}当crash 的app 是当前user 下会通过 getErrorReportReceiver() 获取应用的report receiver该receiver 指定的Intent 的action 为android.intent.action.APP_ERROR。如果没有找到则使用prop ro.error.receiver.default 指定的否则返回null。
5.2.1 getErrorReportReceiver()
//frameworks/base/core/java/android/app/ApplicationErrorReport.javapublic static ComponentName getErrorReportReceiver(Context context,String packageName, int appFlags) {//首先global表中需要enable send_action_app_error属性否则return nullint enabled Settings.Global.getInt(context.getContentResolver(),Settings.Global.SEND_ACTION_APP_ERROR, 0);if (enabled 0) {return null;}PackageManager pm context.getPackageManager();// look for receiver in the installer packageString candidate null;ComponentName result null;try {//获取该crash应用的包名candidate pm.getInstallerPackageName(packageName);} catch (IllegalArgumentException e) {// the package could already removed}//第一次获取使用的是crash应用的包名if (candidate ! null) {result getErrorReportReceiver(pm, packageName, candidate);if (result ! null) {return result;}}//第二次获取使用prop ro.error.receiver.system.apps指定的包名if ((appFlagsApplicationInfo.FLAG_SYSTEM) ! 0) {candidate SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);result getErrorReportReceiver(pm, packageName, candidate);if (result ! null) {return result;}}//第三次获取使用prop ro.error.receiver.default指定的包名candidate SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);return getErrorReportReceiver(pm, packageName, candidate);}上面最终会调用 getErrorReportReceiver() 的另一个函数最后的参数为最终的候选包名
//frameworks/base/core/java/android/app/ApplicationErrorReport.javastatic ComponentName getErrorReportReceiver(PackageManager pm, String errorPackage,String receiverPackage) {//候选的包名为null 或为空返回nullif (receiverPackage null || receiverPackage.length() 0) {return null;}// 如果与crash的应用包名相同if (receiverPackage.equals(errorPackage)) {return null;}//action 为android.intent.action.APP_ERRORIntent intent new Intent(Intent.ACTION_APP_ERROR);intent.setPackage(receiverPackage);ResolveInfo info pm.resolveActivity(intent, 0);if (info null || info.activityInfo null) {return null;}return new ComponentName(receiverPackage, info.activityInfo.name);}需要注意的是寻找这个report receiver 是为了在此处makeAppCrashingLocked() 函数返回crash 对话框弹出之后根据用户的选择做进一步的处理包括了通过该 receiver 发从 report 信息
5.2.2 AMS.skipCurrentReceiverLocked() void skipCurrentReceiverLocked(ProcessRecord app) {for (BroadcastQueue queue : mBroadcastQueues) {queue.skipCurrentReceiverLocked(app);}}
//frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.javapublic void skipCurrentReceiverLocked(ProcessRecord app) {BroadcastRecord r null;final BroadcastRecord curActive mDispatcher.getActiveBroadcastLocked();if (curActive ! null curActive.curApp app) {// confirmed: the current active broadcast is to the given appr curActive;}// If the current active broadcast isnt this BUT were waiting for// mPendingBroadcast to spin up the target app, thats what we use.if (r null mPendingBroadcast ! null mPendingBroadcast.curApp app) {if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,[ mQueueName ] skip discard pending app r);r mPendingBroadcast;}if (r ! null) {skipReceiverLocked(r);}}private void skipReceiverLocked(BroadcastRecord r) {logBroadcastReceiverDiscardLocked(r);finishReceiverLocked(r, r.resultCode, r.resultData,r.resultExtras, r.resultAbort, false);scheduleBroadcastsLocked();}主要是结束 app进程的广播
5.3 stopFreezingActivities()
//frameworks/base/services/core/java/com/android/server/am/WindowProcessController.javapublic void stopFreezingActivities() {synchronized (mAtm.mGlobalLock) {int i mActivities.size();while (i 0) {i--;mActivities.get(i).stopFreezingScreenLocked(true);}}}//其中的 mActivities 为 ArrayListActivityRecord停止进程里所有activity。
//frameworks/base/services/core/java/com/android/server/wm/ActivityRecord.javavoid stopFreezingScreenLocked(boolean force) {if (force || frozenBeforeDestroy) {frozenBeforeDestroy false;if (getParent() null) {return;}ProtoLog.v(WM_DEBUG_ORIENTATION,Clear freezing of %s: visible%b freezing%b, appToken,isVisible(), isFreezingScreen());stopFreezingScreen(true, force);}}最终调用的是 WSM.stopFreezingDisplayLocked() 函数详细可以查看源码大致流程
将冻屏相关的信息remove 掉屏幕旋转动画的相关操作display 冻结时执行GC 操作更新当前的屏幕方向
5.4 handleAppCrashLocked()
这个crash 后续操作流程的核心处理函数
//frameworks/base/services/core/java/com/android/server/am/AppErrors.javaGuardedBy({mService, mProcLock, mBadProcessLock})private boolean handleAppCrashLSPB(ProcessRecord app, String reason,String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {final long now SystemClock.uptimeMillis();final boolean showBackground Settings.Secure.getIntForUser(mContext.getContentResolver(),Settings.Secure.ANR_SHOW_BACKGROUND, 0,mService.mUserController.getCurrentUserId()) ! 0;Long crashTime;Long crashTimePersistent;final String processName app.processName;final int uid app.uid;final int userId app.userId;final boolean isolated app.isolated;final boolean persistent app.isPersistent();final WindowProcessController proc app.getWindowProcessController();final ProcessErrorStateRecord errState app.mErrorState;if (!app.isolated) {crashTime mProcessCrashTimes.get(processName, uid);crashTimePersistent mProcessCrashTimesPersistent.get(processName, uid);} else {crashTime crashTimePersistent null;}// Bump up the crash count of any services currently running in the proc.boolean tryAgain app.mServices.incServiceCrashCountLocked(now);final boolean quickCrash crashTime ! null now crashTime ActivityManagerConstants.MIN_CRASH_INTERVAL;if (quickCrash || isProcOverCrashLimitLBp(app, now)) {// The process either crashed again very quickly or has been crashing periodically in// the last few hours. If it was a bound foreground service, lets try to restart again// in a while, otherwise the process loses!Slog.w(TAG, Process processName has crashed too many times, killing! Reason: (quickCrash ? crashed quickly : over process crash limit));EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,userId, processName, uid);mService.mAtmInternal.onHandleAppCrash(proc);if (!persistent) {// We dont want to start this process again until the user// explicitly does so... but for persistent process, we really// need to keep it running. If a persistent process is actually// repeatedly crashing, then badness for everyone.EventLog.writeEvent(EventLogTags.AM_PROC_BAD, userId, uid,processName);if (!isolated) {// XXX We dont have a way to mark isolated processes// as bad, since they dont have a persistent identity.markBadProcess(processName, app.uid,new BadProcessInfo(now, shortMsg, longMsg, stackTrace));mProcessCrashTimes.remove(processName, app.uid);mProcessCrashCounts.remove(processName, app.uid);}errState.setBad(true);app.setRemoved(true);final AppStandbyInternal appStandbyInternal LocalServices.getService(AppStandbyInternal.class);if (appStandbyInternal ! null) {appStandbyInternal.restrictApp(// Sometimes the processName is the same as the package name, so use// that if we dont have the ApplicationInfo object.// AppStandbyController will just return if it cant find the app.app.info ! null ? app.info.packageName : processName,userId, UsageStatsManager.REASON_SUB_FORCED_SYSTEM_FLAG_BUGGY);}// Dont let services in this process be restarted and potentially// annoy the user repeatedly. Unless it is persistent, since those// processes run critical code.mService.mProcessList.removeProcessLocked(app, false, tryAgain,ApplicationExitInfo.REASON_CRASH, crash);mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);if (!showBackground) {return false;}}mService.mAtmInternal.resumeTopActivities(false /* scheduleIdle */);} else {final int affectedTaskId mService.mAtmInternal.finishTopCrashedActivities(proc, reason);if (data ! null) {data.taskId affectedTaskId;}if (data ! null crashTimePersistent ! null now crashTimePersistent ActivityManagerConstants.MIN_CRASH_INTERVAL) {data.repeating true;}}if (data ! null tryAgain) {data.isRestartableForService true;}// If the crashing process is what we consider to be the home process and it has been// replaced by a third-party app, clear the package preferred activities from packages// with a home activity running in the process to prevent a repeatedly crashing app// from blocking the user to manually clear the list.if (proc.isHomeProcess() proc.hasActivities() (app.info.flags FLAG_SYSTEM) 0) {proc.clearPackagePreferredForHomeActivities();}if (!isolated) {// XXX Cant keep track of crash times for isolated processes,// because they dont have a persistent identity.mProcessCrashTimes.put(processName, uid, now);mProcessCrashTimesPersistent.put(processName, uid, now);updateProcessCrashCountLBp(processName, uid, now);}if (errState.getCrashHandler() ! null) {mService.mHandler.post(errState.getCrashHandler());}return true;}
6. SHOW_ERROR_UI_MSG 消息
当makeAppCrashingLocked() 返回true 时会通过 AMS.mUiHandler发送 SHOW_ERROR_UI_MSG 消息
//frameworks/base/services/core/java/com/android/server/am/AMS.javapublic void handleMessage(Message msg) {switch (msg.what) {case SHOW_ERROR_UI_MSG: {mAppErrors.handleShowAppErrorUi(msg);ensureBootCompleted();} break;最终是调用 mAppErrors.handleShowAppErrorUi()代码逻辑不是很复杂这里暂时不做剖析。
正常情况在发生 crash 时默认系统会弹出提示 crash 的对话框并阻塞等待用户的选择。
7. killProcess()
crash 的处理流程大致剖析完成回到第 2 节 KillApplicationHandler.uncaughtException() 最后的finally
frameworks/base/core/java/com/android/internal/os/RuntimeInit.javapublic void uncaughtException(Thread t, Throwable e) {try {...} catch (Throwable t2) {...} finally {//确保当前进程彻底杀掉Process.killProcess(Process.myPid());System.exit(10);}}8. 避开uncaught exception
java 端提供了一个接口
//libcore/ojluni/src/main/java/java/lang/Thread.javaprivate volatile UncaughtExceptionHandler uncaughtExceptionHandler;public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {checkAccess();uncaughtExceptionHandler eh;}在app 出现 crash 的时候需要确定当线程中是否设置了 uncaughtExceptionHandler那么原来的 defaultUncaughtExceptionHandler 将不会被调用即如果设置了 uncaughtExceptionHandler最终调用的是 uncaughtExceptionHandler.uncaughtException()。
利用这种方式可以避开 uncaught exception 而引起的 app 被kill。例如 if (true) {//create threadThread thread new Thread(new Runnable() {Overridepublic void run() {String str null;System.out.println(str.length());}});thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {Overridepublic void uncaughtException(NonNull Thread t, NonNull Throwable e) {}});thread.start();return;}上面是个简单的示例只要通过 setUncaughtExceptionHandler() 设置一个新的UncaughtExceptionHandler 就可以避开上述问题。
9 总结
9.1 调用栈
KillApplicationHandler.uncaughtException() stopProfilingAMS.handleApplicationCrash() handleApplicationCrashInner AppErrors.crashApplication()makeAppCrashingLocked generateProcessError()startAppProblemLSP() getErrorReportReceiverAMS.skipCurrentReceiverLocked() stopFreezingActivities()handleAppCrashLocked
9.2 handleAppCrashLocked
当同一进程 1 分钟之内连续两次 crash则执行
mService.mAtmInternal.onHandleAppCrash()对于非 persistent 进程 ·mService.mProcessList.removeProcessLocked()mService.mAtmInternal.resumeTopActivities() 对于 persistent 进程 mService.mAtmInternal.resumeTopActivities() 没有在1分钟频繁 crash则执行 mService.mAtmInternal.finishTopCrashedActivities()