天天看點

android crash沒有日志_Android三方應用crash崩潰問題分析——開篇必讀am_crasham_finish_activityam_proc_died觸發列印 am_crash log 的代碼

在三方應用崩潰問題時,一定要注意下面事項。

注意:在 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);}
           
android crash沒有日志_Android三方應用crash崩潰問題分析——開篇必讀am_crasham_finish_activityam_proc_died觸發列印 am_crash log 的代碼