在三方应用崩溃问题时,一定要注意下面事项。

注意:在 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,具体说明如下。

查看 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]

应用发生 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() 函数中打印。

当应用进程异常退出时,会打印下面的 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 进程来运行 activity

04-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 那边来 kill

04-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

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);

}