在三方應用崩潰問題時,一定要注意下面事項。
注意:在 log 裡面看到三方應用列印了 Java 層的程序異常堆棧,并不一定表示應用就發生 crash 了。
應用自身可能 catch 了這些 exception ,隻是把堆棧列印出來,并沒有 crash。
應用突然閃退,有可能是發生 crash,也有可能是自身正常調用 finish() 函數退出。
要确認是否發生 crash,可以檢視 event log 是否列印應用 crash 的資訊。
如果列印了很多程序堆棧,但是 event log 沒有列印應用對應的 crash 資訊,那麼應用可能就沒有發生異常退出。
在Android應用代碼中,可以替換系統預設的KillApplicationHandler,自己來處理 uncaught exception。
那麼應用在遇到沒有顯式 catch 的異常時,并不會導緻異常退出,AMS 也不會得到通知來 kill 應用,該應用仍正常運作。
Android應用崩潰、結束、程序終止時,會在 events log 裡面列印一些關鍵log,具體說明如下。
am_crash
檢視 Android 源碼裡面的 frameworks/base/services/core/java/com/android/server/am/EventLogTags.logtags 檔案,對 event log 的 am_crash 資訊說明如下:
# Unhandled exception:
am_crash (User|1|5),(PID|1|5),(Process Name|3),(Flags|1|5),(Exception|3),(Message|3),(File|3),(Line|1|5)
在這個說明中,am_crash 表示發生 crash。
在這句 log 中也會列印具體的 exception 類型。例如,列印 “Native crash,Segmentation fault” 這個資訊表示 native 代碼發生空指針異常(後面貼出的 log 列印了這個資訊,可以參考)。
關于 (User|1|5) 這種寫法的含義可以檢視 system/core/logcat/event.logtags 檔案的說明,具體如下:
Optionally, after the tag names can be put a description for the value(s) of the tag. Description are in the format (|data type[|data unit])
是以,(User|1|5) 表示 name 是 User。後面的 1 是 data type,對應 int 類型。最後面的 5 是 data unit,對應 Id。
這些 tag 的格式資訊可以檢視手機的 /system/etc/event-log-tags 檔案。
Android 源碼裡面的 EventLogTags.logtags 檔案可以作為源代碼進行編譯,build/tools/java-event-log-tags.py 腳本負責将 EventLogTags.logtags 轉化為EventLogTags.jav a檔案。
在 event log 中列印 am_crash 的 log 舉例如下:
I am_crash: [1159,0,com.jiuyan.infashion,953728580,Native crash,Segmentation fault,unknown,0]
am_finish_activity
應用發生 crash,在 event log 中還會列印下面的資訊:
I am_finish_activity: [0,96662550,113,com.jiuyan.infashion/.LaunchActivity,force-crash]
關于 am_finish_activity 這個 tag 的資訊說明如下:
An activity is being finished: am_finish_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3),(Reason|3)
這個 log 最後面的資訊表示 finish reason。
這裡列印的是 “force-crash”,說明發生 crash 導緻應用 finish。
這句 log 在 frameworks/base/services/core/java/com/android/server/am/AppErrors.java 檔案的 makeAppCrashingLocked() 函數中列印。
am_proc_died
當應用程序異常退出時,會列印下面的 log:
I am_proc_died: [0,30306,com.jiuyan.infashion,199,2]
關于 am_proc_died 這個 tag 的資訊說明如下:
Application process died: am_proc_died (User|1|5),(PID|1|5),(Process Name|3),(OomAdj|1|5),(ProcState|1|5)
ProcState 的含義可以參考 frameworks/base/core/java/android/app/ActivityManager.java 裡面以 “PROCESS_STATE_” 開通的常量定義。
例如上面 log 列印的 2 對應 PROCESS_STATE_TOP 這個常量:
/** @hide Process is hosting the current top activities. Note that this covers * all activities that are visible to the user. */public static final int PROCESS_STATE_TOP = 2;
可參考的一些 log 如下:
# 啟動一個 29504 程序來運作 activity04-09 15:05:42.393 1159 1321 I ActivityManager: Start proc 29504:com.jiuyan.infashion/u0a122 for activity com.jiuyan.infashion/.LaunchActivity# 從 libc 來 kill 這個程序,而不是在 Java 那邊來 kill04-09 15:05:42.482 29504 29504 F libc : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 29504 (iuyan.infashion), pid 29504 (iuyan.infashion)04-09 15:05:42.930 660 660 I Zygote : Process 29504 exited due to signal (11)04-09 15:05:43.068 1159 8056 I ActivityManager: Process com.jiuyan.infashion (pid 29504) has died: vis +99TOP
觸發列印 am_crash log 的代碼
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
// 後面代碼貼出的 KillApplicationHandler 會調用 handleApplicationCrash()。// handleApplicationCrash() 調用 handleApplicationCrashInner() 列印 am_crash log。// 即,由系統主動 kill 應用時,就會列印 am_crash log// Used by {@link com.android.internal.os.RuntimeInit} to report when an application crashes.// The application process will exit immediately after this call returns.public 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);}void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName, ApplicationErrorReport.CrashInfo crashInfo) {// am_crash 的 log 在這裡列印 EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(), UserHandle.getUserId(Binder.getCallingUid()), processName, r == null ? -1 : r.info.flags, crashInfo.exceptionClassName, crashInfo.exceptionMessage, crashInfo.throwFileName, crashInfo.throwLineNumber);}
frameworks/base/services/core/java/com/android/server/am/AppErrors.java
// 由系統處理 uncaught exception 時,就會執行到這裡來,// 進而列印 am_crash、am_finish_activity force-crash 這些 log。private boolean makeAppCrashingLocked(ProcessRecord app, String shortMsg, String longMsg, String stackTrace, AppErrorDialog.Data data) { return handleAppCrashLocked(app, "force-crash" /*reason*/, shortMsg, longMsg, stackTrace, data);}
