当前位置:   article > 正文

Android 7.0 ActivityManagerService(10) App的crash处理_activitymanager: hmcp: deny showing crash dialog f

activitymanager: hmcp: deny showing crash dialog for

在这篇博客中,我们来看一下AMS处理App crash时涉及到的主要流程。

一、设置异常处理器
Android平台中,应用进程fork出来后会为虚拟机设置一个未截获异常处理器,
即在程序运行时,如果有任何一个线程抛出了未被截获的异常,
那么该异常最终会抛给未截获异常处理器处理。

我们首先看看Android N中设置异常处理器的这部分代码。
在ZygoteInit.Java的runSelectLoop中:

  1. private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
  2. ...........
  3. while (true) {
  4. ..........
  5. for (int i = pollFds.length - 1; i >= 0; --i) {
  6. ..........
  7. if (i == 0) {
  8. //zygote中的server socket收到消息后,建立起ZygoteConnection
  9. ZygoteConnection newPeer = acceptCommandPeer(abiList);
  10. peers.add(newPeer);
  11. fds.add(newPeer.getFileDesciptor());
  12. } else {
  13. //ZygoteConnection建立后,收到消息调用自己的runOnce函数
  14. boolean done = peers.get(i).runOnce();
  15. .............
  16. }
  17. }
  18. }
  19. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

我们知道zygote启动后,会在自己的进程中定义一个server socket,专门接收创建进程的消息。
如上面的代码所示,收到创建进程的消息后,zygote会创建出ZygoteConnection,并调用其runOnce函数:

  1. boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
  2. ...............
  3. try {
  4. ...........
  5. //fork出子进程
  6. pid = Zygote.forkAndSpecialize(.......);
  7. } catch (ErrnoException ex) {
  8. ............
  9. } catch (IllegalArgumentException ex) {
  10. ...........
  11. } catch (ZygoteSecurityException ex) {
  12. ..........
  13. }
  14. try {
  15. if (pid == 0) {
  16. ........
  17. //进程fork成功后,进行处理
  18. handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
  19. ........
  20. } else {
  21. ...........
  22. }
  23. } finally {
  24. ..........
  25. }
  26. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

我们跟进一下handleChildProc函数:

  1. private void handleChildProc(......) {
  2. ............
  3. if (parsedArgs.invokeWith != null) {
  4. ..........
  5. } else {
  6. //进入到RuntimeInit中的zygoteInit函数
  7. RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
  8. parsedArgs.remainingArgs, null /* classLoader */);
  9. }
  10. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

顺着流程看一看RuntimeInit中的zygoteInit函数:

  1. public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
  2. throws ZygoteInit.MethodAndArgsCaller {
  3. ............
  4. //跟进commonInit
  5. commonInit();
  6. ............
  7. }
  8. private static final void commonInit() {
  9. ...........
  10. /* set default handler; this applies to all threads in the VM */
  11. //到达目的地!
  12. Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
  13. ...........
  14. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

从上面的代码可以看出,fork出进程后,将在进程commonInit的阶段设置异常处理器UncaughtHandler。

二、异常处理的流程
1、UncaughtHandler的异常处理
接下来我们看看UncaughtHandler如何处理未被捕获的异常。

  1. private static class UncaughtHandler implements Thread.UncaughtExceptionHandler {
  2. public void uncaughtException(Thread t, Throwable e) {
  3. try {
  4. // Don't re-enter -- avoid infinite loops if crash-reporting crashes.
  5. if (mCrashing) return;
  6. mCrashing = true;
  7. if (mApplicationObject == null) {
  8. Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
  9. } else {
  10. //打印进程的crash信息
  11. .............
  12. }
  13. .............
  14. // Bring up crash dialog, wait for it to be dismissed
  15. //调用AMS的接口,进行处理
  16. ActivityManagerNative.getDefault().handleApplicationCrash(
  17. mApplicationObject, new ApplicationErrorReport.CrashInfo(e));
  18. } catch (Throwable t2) {
  19. if (t2 instanceof DeadObjectException) {
  20. // System process is dead; ignore
  21. } else {
  22. try {
  23. Clog_e(TAG, "Error reporting crash", t2);
  24. } catch (Throwable t3) {
  25. // Even Clog_e() fails! Oh well.
  26. }
  27. }
  28. } finally {
  29. // Try everything to make sure this process goes away.
  30. //crash的最后,会杀死进程
  31. Process.killProcess(Process.myPid());
  32. //并exit
  33. System.exit(10);
  34. }
  35. }
  36. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

从代码来看,UncaughtHandler对异常的处理流程比较清晰,基本上就是:
1、记录log信息;
2、调用AMS的接口进行一些处理;
3、杀死出现crash的进程。

其中比较重要的应该是AMS处理crash的流程,接下来我们跟进一下这部分流程的代码。

2、AMS的异常处理

  1. public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
  2. //得到crash app对应的信息
  3. ProcessRecord r = findAppProcess(app, "Crash");
  4. final String processName = app == null ? "system_server"
  5. : (r == null ? "unknown" : r.processName);
  6. //调用handleApplicationCrashInner进一步处理
  7. handleApplicationCrashInner("crash", r, processName, crashInfo);
  8. }
  9. void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
  10. ApplicationErrorReport.CrashInfo crashInfo) {
  11. ...............
  12. //Write a description of an error (crash, WTF, ANR) to the drop box.
  13. //记录信息到drop box
  14. addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);
  15. //调用内部类AppErrors的crashApplication函数
  16. mAppErrors.crashApplication(r, crashInfo);
  17. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

我们跟进一下AppErrors类中的crashApplication函数:

  1. /**
  2. * Bring up the "unexpected error" dialog box for a crashing app.
  3. * Deal with edge cases (intercepts from instrumented applications,
  4. * ActivityController, error intent receivers, that sort of thing).
  5. * /
  6. void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
  7. final long origId = Binder.clearCallingIdentity();
  8. try {
  9. //实际的处理函数为crashApplicationInner
  10. crashApplicationInner(r, crashInfo);
  11. } finally {
  12. Binder.restoreCallingIdentity(origId);
  13. }
  14. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

此处实际的处理函数为crashApplicationInner。

  1. void crashApplicationInner(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
  2. long timeMillis = System.currentTimeMillis();
  3. //从应用进程传递过来的crashInfo中获取相关的信息
  4. String shortMsg = crashInfo.exceptionClassName;
  5. String longMsg = crashInfo.exceptionMessage;
  6. String stackTrace = crashInfo.stackTrace;
  7. ................
  8. AppErrorResult result = new AppErrorResult();
  9. TaskRecord task;
  10. synchronized (mService) {
  11. /**
  12. * If crash is handled by instance of {@link android.app.IActivityController},
  13. * finish now and don't show the app error dialog.
  14. */
  15. //通知观察者处理crash
  16. //如果存在观察者且能够处理crash,那么不显示error dialog
  17. //例如在进行Monkey Test,那么可设置检测到crash后,就停止测试等
  18. if (handleAppCrashInActivityController(r, crashInfo, shortMsg, longMsg, stackTrace,
  19. timeMillis)) {
  20. return;
  21. }
  22. /**
  23. * If this process was running instrumentation, finish now - it will be handled in
  24. * {@link ActivityManagerService#handleAppDiedLocked}.
  25. */
  26. if (r != null && r.instrumentationClass != null) {
  27. return;
  28. }
  29. // Log crash in battery stats.
  30. if (r != null) {
  31. mService.mBatteryStatsService.noteProcessCrash(r.processName, r.uid);
  32. }
  33. AppErrorDialog.Data data = new AppErrorDialog.Data();
  34. data.result = result;
  35. data.proc = r;
  36. // If we can't identify the process or it's already exceeded its crash quota,
  37. // quit right away without showing a crash dialog.
  38. // 调用makeAppCrashingLocked进行处理,如果返回false,则无需进行后续处理
  39. if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace, data)) {
  40. return;
  41. }
  42. //发送SHOW_ERROR_UI_MSG给mUiHandler,将弹出一个对话框,提示用户某进程crash
  43. //用户可以选择"退出"或"退出并报告"等
  44. //一般的厂商应该都定制了这个界面
  45. Message msg = Message.obtain();
  46. msg.what = ActivityManagerService.SHOW_ERROR_UI_MSG;
  47. task = data.task;
  48. msg.obj = data;
  49. mService.mUiHandler.sendMessage(msg);
  50. }
  51. //调用AppErrorResult的get函数,该函数是阻塞的,直到用户处理了对话框为止
  52. //注意此处涉及了两个线程的工作
  53. //crashApplicationInner函数工作在Binder调用所在的线程
  54. //对话框工作于AMS的Ui线程
  55. int res = result.get();
  56. Intent appErrorIntent = null;
  57. //以下开始根据对话框中用户的选择,进行对应的处理
  58. ...................
  59. //长时间未点击对话框或者点击取消,那么相当于选择强行停止crash进程
  60. if (res == AppErrorDialog.TIMEOUT || res == AppErrorDialog.CANCEL) {
  61. res = AppErrorDialog.FORCE_QUIT;
  62. }
  63. //根据res的值进行相应的处理
  64. synchronized (mService) {
  65. //选择不再提示错误
  66. if (res == AppErrorDialog.MUTE) {
  67. //将进程名加入到AMS的mAppsNotReportingCrashes表中
  68. stopReportingCrashesLocked(r);
  69. }
  70. //选择了重新启动
  71. if (res == AppErrorDialog.RESTART) {
  72. mService.removeProcessLocked(r, false, true, "crash");
  73. if (task != null) {
  74. try {
  75. //尝试重启进程
  76. mService.startActivityFromRecents(task.taskId,
  77. ActivityOptions.makeBasic().toBundle());
  78. } catch (IllegalArgumentException e) {
  79. // Hmm, that didn't work, app might have crashed before creating a
  80. // recents entry. Let's see if we have a safe-to-restart intent.
  81. if (task.intent.getCategories().contains(
  82. Intent.CATEGORY_LAUNCHER)) {
  83. //换一种方式重启
  84. mService.startActivityInPackage(............);
  85. }
  86. }
  87. }
  88. }
  89. //选择强行停止
  90. if (res == AppErrorDialog.FORCE_QUIT) {
  91. long orig = Binder.clearCallingIdentity();
  92. try {
  93. // Kill it with fire!
  94. //handleAppCrashLocked主要是结束activity,并更新oom_adj
  95. mService.mStackSupervisor.handleAppCrashLocked(r);
  96. if (!r.persistent) {
  97. //如果不是常驻应用,则在此处kill掉
  98. mService.removeProcessLocked(r, false, false, "crash");
  99. mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
  100. }
  101. } finally {
  102. Binder.restoreCallingIdentity(orig);
  103. }
  104. }
  105. //选择强制停止并报告
  106. if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
  107. //该函数中将生成错误信息,并构造一个Intent用于拉起报告界面
  108. appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
  109. }
  110. if (r != null && !r.isolated && res != AppErrorDialog.RESTART) {
  111. // XXX Can't keep track of crash time for isolated processes,
  112. // since they don't have a persistent identity.
  113. //记录crash时间
  114. mProcessCrashTimes.put(r.info.processName, r.uid,
  115. SystemClock.uptimeMillis());
  116. }
  117. }
  118. if (appErrorIntent != null) {
  119. try {
  120. //如果选择了强制停止并报告,那么此时就会拉起报告界面
  121. mContext.startActivityAsUser(appErrorIntent, new UserHandle(r.userId));
  122. } catch (ActivityNotFoundException e) {
  123. ..............
  124. }
  125. }
  126. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144

整体来看AMS处理crash的流程还是相当清晰的:
1、首先记录crash相关的信息到drop box;
2、如果存在可以处理App crash的ActivityController,那么将crash交给它处理;
否则,弹出crash对话框,然用户选择后续操作。
3、根据用户的选择,AMS可以进行重启应用、强行停止应用或拉起报告界面等操作。

不过上述流程中,在拉起对话框前,先调用了makeAppCrashingLocked函数。
若这个函数返回false,那么后续的流程就不会继续进行。
我们来看看这个函数的具体用途。

  1. private boolean makeAppCrashingLocked(ProcessRecord app,
  2. String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) {
  3. app.crashing = true;
  4. //就是创建一个对象,其中包含了所有的错误信息
  5. app.crashingReport = generateProcessError(app,
  6. ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
  7. //前面的代码已经提到过,系统可以通过Intent拉起一个crash报告界面
  8. //startAppProblemLocked函数,就是在系统中找到这个报告界面对应的ComponentName
  9. //此外,如果crash应用正好在处理有序广播,那么为了不影响后续广播接受器的处理,
  10. //startAppProblemLocked会停止crash应用对广播的处理流程,
  11. //即后续的广播接受器可以跳过crash应用,直接开始处理有序广播
  12. startAppProblemLocked(app);
  13. //停止“冻结”屏幕
  14. app.stopFreezingAllLocked();
  15. //进行一些后续的处理
  16. //从代码来看,如果应用不是在1min内连续crash,该函数都会返回true
  17. return handleAppCrashLocked(app, "force-crash" /*reason*/, shortMsg, longMsg, stackTrace,
  18. data);
  19. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

根据上面的代码,可以看出makeAppCrashingLocked函数最主要的工作主要有两个:
1、查找crash报告界面对应的componentName;
2、避免进程短时间内连续crash,导致频繁拉起对话框。

三、后续的清理工作
根据前面的流程,我们知道当进程crash后,最终将被kill掉,
此时AMS还需要完成后续的清理工作。

我们先来回忆一下进程启动后,注册到AMS的部分流程:

  1. //进程启动后,对应的ActivityThread会attach到AMS上
  2. private final boolean attachApplicationLocked(IApplicationThread thread,
  3. int pid) {
  4. ............
  5. ProcessRecord app;
  6. if (pid != MY_PID && pid >= 0) {
  7. synchronized (mPidsSelfLocked) {
  8. app = mPidsSelfLocked.get(pid);
  9. }
  10. } else {
  11. app = null;
  12. }
  13. ............
  14. final String processName = app.processName;
  15. try {
  16. //生成了一个“讣告”接收者
  17. AppDeathRecipient adr = new AppDeathRecipient(
  18. app, pid, thread);
  19. thread.asBinder().linkToDeath(adr, 0);
  20. app.deathRecipient = adr;
  21. } catch (RemoteException e) {
  22. app.resetPackageList(mProcessStats);
  23. startProcessLocked(app, "link fail", processName);
  24. return false;
  25. }
  26. ................
  27. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

从上面的代码可以看出,当进程注册到AMS时,AMS注册了一个“讣告”接收者注册到进程中。
因此,当crash进程被kill后,AppDeathRecipient中的binderDied函数将被回调:

  1. @Override
  2. public void binderDied() {
  3. ..........
  4. synchronized(ActivityManagerService.this) {
  5. appDiedLocked(mApp, mPid, mAppThread, true);
  6. }
  7. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

根据代码可知,接收到进程“死亡”的通知后,最后还是调用AMS的appDiedLocked函数进行处理:

  1. final void appDiedLocked(ProcessRecord app, int pid, IApplicationThread thread,
  2. boolean fromBinderDied) {
  3. // First check if this ProcessRecord is actually active for the pid.
  4. synchronized (mPidsSelfLocked) {
  5. ProcessRecord curProc = mPidsSelfLocked.get(pid);
  6. if (curProc != app) {
  7. ...........
  8. return;
  9. }
  10. }
  11. .............
  12. if (!app.killed) {
  13. if (!fromBinderDied) {
  14. Process.killProcessQuiet(pid);
  15. }
  16. killProcessGroup(app.uid, pid);
  17. app.killed = true;
  18. }
  19. //以上都是一些保证健壮性的代码
  20. if (app.pid == pid && app.thread != null &&
  21. app.thread.asBinder() == thread.asBinder()) {
  22. //进程是正常启动的,非测试启动,那么需要内存调整
  23. boolean doLowMem = app.instrumentationClass == null;
  24. boolean doOomAdj = doLowMem;
  25. if (!app.killedByAm) {
  26. ............
  27. mAllowLowerMemLevel = true;
  28. } else {
  29. mAllowLowerMemLevel = false;
  30. doLowMem = false;
  31. }
  32. ..............
  33. //handleAppDiedLocked进行实际的工作
  34. handleAppDiedLocked(app, false, true);
  35. if (doOomAdj) {
  36. //重新更新进程的oom_adj
  37. updateOomAdjLocked();
  38. }
  39. if (doLowMem) {
  40. //在必要时,触发系统中的进程做内存回收
  41. doLowMemReportIfNeededLocked(app);
  42. }
  43. }.........
  44. ..........
  45. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

appDiedLocked函数中比较重要的是handleAppDiedLocked函数:

  1. private final void handleAppDiedLocked(ProcessRecord app,
  2. boolean restarting, boolean allowRestart) {
  3. int pid = app.pid;
  4. //进行进程中service、ContentProvider、BroadcastReceiver等的收尾工作
  5. //这个函数虽然很长,但实际的功能还是很清晰的,这里不作进一步展开
  6. //比较重要的是:1、对于crash进程中的Bounded Service而言,会清理掉service与客户端之间的联系;
  7. //此外若service的客户端重要性过低,还会被直接kill掉
  8. //2、清理ContentProvider时,在removeDyingProviderLocked函数中,可能清理掉其客户端进程(对于stable contentProvider而言)
  9. boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1);
  10. if (!kept && !restarting) {
  11. //不再保留和重启时,从LRU表中移除
  12. removeLruProcessLocked(app);
  13. if (pid > 0) {
  14. ProcessList.remove(pid);
  15. }
  16. }
  17. ..................
  18. // Remove this application's activities from active lists.
  19. //进行Activity相关的收尾工作
  20. boolean hasVisibleActivities = mStackSupervisor.handleAppDiedLocked(app);
  21. app.activities.clear();
  22. if (app.instrumentationClass != null) {
  23. ..............
  24. }
  25. if (!restarting && hasVisibleActivities
  26. && !mStackSupervisor.resumeFocusedStackTopActivityLocked()) {
  27. // If there was nothing to resume, and we are not already restarting this process, but
  28. // there is a visible activity that is hosted by the process... then make sure all
  29. // visible activities are running, taking care of restarting this process.
  30. // 从注释来看,若当前只有crash进程中存在可视Activity,那么AMS还是会试图重启该进程
  31. mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
  32. }
  33. }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

上述代码中cleanUpApplicationRecordLocked函数,在此不做深入分析。
其中唯一比较麻烦的就是Bounded Service和ContentProvider的清理,
因为这两种组件全部要考虑其客户端进程。

四、总结

整体来讲,Android中进程crash后的处理流程基本上如上图所示。
这个流程相对来说是比较简单的,唯一麻烦点的地方可能是进程结束后,
AMS进行的清理工作。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/250849
推荐阅读
相关标签
  

闽ICP备14008679号