JasonWang's Blog

Android进程Crash处理流程

字数统计: 3.7k阅读时长: 18 min
2017/07/09

之前的一篇文章,讲到了应用程序无响应(ANR)时Android的处理逻辑。这篇文章,就来分析下应用进程发生崩溃(Crash)时,Android是如何处理的?总的说来,Android主要有两大类Crash:

  • Java(JVM)层: 应用程序发生运行时错误(如空指针,浮点运算错误,数据索引超出界限)或者系统进程崩溃(长时间无响应);
  • Native层: native进程或者kernel发生运行时错误;

APP层Crash处理

对Java层,Android需要处理两种情况的Crash:

  • 对于APP中未捕获的异常,捕捉到后,进行处理;
  • 监控UI线程(主线程)、前台服务线程、IO线程、显示线程(IMS/WMS,DMS中使用)以及Binder进程通信线程是否挂起(10s内无响应则视为挂起);

主线程(main thread)是指应用启动时创建的进程中的第一个线程,而UI线程则是负责输入、绘制等前台交互,大部分情况下主线程就是UI线程,参考:

下面就从这两种情况来分析APP出现的Crash。

未捕获异常Crash

对于每个进程,在启动过程初始化运行时执行环境时,都会设置一个未捕获异常处理函数,用于捕获APP中未捕获到的异常情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

private static final void commonInit() {
if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!");

/* set default handler; this applies to all threads in the VM */
Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());

TimezoneGetter.setInstance(new TimezoneGetter() {
@Override
public String getId() {
return SystemProperties.get("persist.sys.timezone");
}
});
TimeZone.setDefault(null);
....
initialized = true;
}

捕获到应用Crash后,向AMS发送Crash信息,最后将进程杀死:

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

private static class UncaughtHandler implements Thread.UncaughtExceptionHandler {
public void uncaughtException(Thread t, Throwable e) {
try {
// Don't re-enter -- avoid infinite loops if crash-reporting crashes.
if (mCrashing) return;
mCrashing = true;

if (mApplicationObject == null) {
// 进程启动时设置了mApplicationObject = ApplicationThread
} else {
StringBuilder message = new StringBuilder();
message.append("FATAL EXCEPTION: ").append(t.getName()).append("\n");
final String processName = ActivityThread.currentProcessName();
if (processName != null) {
message.append("Process: ").append(processName).append(", ");
}
message.append("PID: ").append(Process.myPid());
Clog_e(TAG, message.toString(), e);
}
....
// Bring up crash dialog, wait for it to be dismissed
ActivityManagerNative.getDefault().handleApplicationCrash(
mApplicationObject, new ApplicationErrorReport.CrashInfo(e));
} catch (Throwable t2) {
....
} finally {
// Try everything to make sure this process goes away.
Process.killProcess(Process.myPid());
System.exit(10);
}
}
}

参考源码:/android/frameworks/base/core/java/com/android/internal/os/RuntimeInit.java

AMS接收到Crash后,找到应用的进程记录,做下一步处理:

1
2
3
4
5
6
7
8
9
10
11
12
13


public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
ProcessRecord r = findAppProcess(app, "Crash");
final String processName = app == null ? "system_server"
: (r == null ? "unknown" : r.processName);
final int userId = r == null ? UserHandle.USER_OWNER : r.userId;
....
// 处理应用Crash
handleApplicationCrashInner("crash", r, processName, crashInfo);
}


AMS处理APP的Crash主要做了两件事情:

  • 保存Crash的当时的现场到Dropbox;
  • 如果发现该APP频繁Crash,记录信息,强制其停止,不提示用户;否则需要弹出APP出错的对话框告知用户,由用户自己选择处理的方式(重启或者强制停止);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17


void handleApplicationCrashInner(String eventType, ProcessRecord r, String processName,
ApplicationErrorReport.CrashInfo crashInfo) {
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);

addErrorToDropBox(eventType, r, processName, null, null, null, null, null, crashInfo);

mAppErrors.crashApplication(r, crashInfo);
}

系统挂起

在应用层, Android有一个专门的监控者Watchdog线程来负责监控应用层是否出现系统挂起(在给定时间10s无响应则视为挂起),比如系统服务IMS(AMS,WMS)无响应,UI线程、IO线程无响应,Binder IPC线程无响应等各种异常情况:

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

private Watchdog() {
super("watchdog");

// The shared foreground thread is the main checker. It is where we
// will also dispatch monitor checks and do other work.
mMonitorChecker = new HandlerChecker(FgThread.getHandler(),
"foreground thread", DEFAULT_TIMEOUT);
mHandlerCheckers.add(mMonitorChecker);
// Add checker for main thread. We only do a quick check since there
// can be UI running on the thread.
mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()),
"main thread", DEFAULT_TIMEOUT));
// Add checker for shared UI thread.
mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(),
"ui thread", DEFAULT_TIMEOUT));
// And also check IO thread.
mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(),
"i/o thread", DEFAULT_TIMEOUT));
// And the display thread.
mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(),
"display thread", DEFAULT_TIMEOUT));

// Initialize monitor for Binder threads.
addMonitor(new BinderThreadMonitor());
}


Watchdog线程是在system_server进程启动时启动起来的:

1
2
3
4
5
6
7
8
9
10

private void startOtherServices() {
....
final Watchdog watchdog = Watchdog.getInstance();
watchdog.init(context, mActivityManagerService);
....
Watchdog.getInstance().start();
}


Watchdog线程启动后,开始监测各个线程有无响应(通过在线程消息队列的头部添加一个可执行对象,对于Binder线程则通过BlockUtilThreadAvailable来检测是否有Binder线程可用),一旦发现系统某个线程无响应,则抓取相应APP的堆栈LOG,同时保存kernel的堆栈信息:

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

public void run() {
boolean waitedHalf = false;
File traceFile = new File("/data/anr/traces.txt");
try {
if (!traceFile.exists()) {
traceFile.createNewFile();
}
traceFile.setReadable(true, false);
traceFile.setWritable(true, false);
} catch(IOException e) {
Slog.e(TAG, "Failed to create /data/anr/traces.txt");
}

while (true) {
final ArrayList<HandlerChecker> blockedCheckers;
final String subject;
final boolean allowRestart;
synchronized (this) {
long timeout = CHECK_INTERVAL;
for (int i=0; i<mHandlerCheckers.size(); i++) {
HandlerChecker hc = mHandlerCheckers.get(i);
hc.scheduleCheckLocked();
}
....
final int waitState = evaluateCheckerCompletionLocked();
if (waitState == COMPLETED) {
// The monitors have returned; reset
waitedHalf = false;
continue;
} else if (waitState == WAITING) {
// still waiting but within their configured intervals; back off and recheck
continue;
} else if (waitState == WAITED_HALF) {
....
continue;
}

// something is overdue!
blockedCheckers = getBlockedCheckersLocked();
subject = describeCheckersLocked(blockedCheckers);
allowRestart = mAllowRestart;
}
}

// 系统处于挂起状态,保存APP堆栈信息
final File stack = ActivityManagerService.dumpStackTraces(
!waitedHalf, pids, null, null, NATIVE_STACKS_OF_INTEREST);
....
// 保存kernel堆栈信息
if (RECORD_KERNEL_THREADS) {
dumpKernelStackTraces();
}
....
}

参考源码:/android/frameworks/base/services/core/java/com/android/server/Watchdog.java

接下来,就来看一看Android是如何处理native进程crash的。

Native层Crash处理

在native层,Android的Crash处理主要由三个部分组成:

  • kernel捕捉到进程的异常信号(SIGABRT,SIGBUS,SIGFPE)时,调用信号处理函数;信号处理函数负责收集Crash进程的错误信息,并将错误信息通过socket发送给debugger守护进程;
  • debugger守护进程接收到crash信息后,一方面告知AMS有进程发生Crash,一方面通过tomestone保存完整的现场信息;
  • AMS收到Crash信息后,弹出对话框告知用户Crash信息,同时保存该crash进程的相关LOG;

接下来,我们分步骤来看下native层Crash的处理流程。

Crash信号处理函数

Native进程发生崩溃(Crash)时,kernel会向其发送一个信号(signal),此时当前进程被中断,kernel接着调用事先注册在系统中的信号处理函数(Signal Handler)。Android在启动时专门注册了一个signal handler用于处理Native进程由于运行错误而出现的信号。

那么,Android的signal handler是在哪里注册到系统中的了?在Android库bionic中有一个动态链接库linker(文件目录/android/bionic/ ),linker启动时会初始化通过系统调用signal向系统注册信号处理函数; Android主要处理SIGABRTSIGBUS等几种Crash信号(linux signal):

  • SIGABRT(6): abort, 异常终止;
  • SIGBUS(10): bus error, 总线错误;
  • SIGFPE(8): Floating Point Exception, 浮点运算异常;
  • SIGILL(4): Illegal Instruction, 非法指令;
  • SIGSEGV(11): Invalid memory Segmentation Fault, 无效内存访问;
  • SIGSTKFLT(16): stack fault, 堆栈错误;
  • SIGTRAP(5): Trace Trap, 跟踪陷阱;

debugger.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

__LIBC_HIDDEN__ void debuggerd_init() {
struct sigaction action;
memset(&action, 0, sizeof(action));
sigemptyset(&action.sa_mask);
// 信号处理函数
action.sa_sigaction = debuggerd_signal_handler;
action.sa_flags = SA_RESTART | SA_SIGINFO;

// Use the alternate signal stack if available so we can catch stack overflows.
action.sa_flags |= SA_ONSTACK;
// 需要捕捉的信号
sigaction(SIGABRT, &action, nullptr);
sigaction(SIGBUS, &action, nullptr);
sigaction(SIGFPE, &action, nullptr);
sigaction(SIGILL, &action, nullptr);
sigaction(SIGSEGV, &action, nullptr);
#if defined(SIGSTKFLT)
sigaction(SIGSTKFLT, &action, nullptr);
#endif
sigaction(SIGTRAP, &action, nullptr);
}

注册完信号处理函数后,一旦kernel检测到有进程出现上述信号,则会调用debuggerd_signal_handler函数进行处理:此时会通过socket接口android:debuggerd32(对于64位系统,socket名为android:debuggerd)发送错误信息,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19


/*
* Catches fatal signals so we can ask debuggerd to ptrace us before
* we crash.
*/
static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*) {
// It's possible somebody cleared the SA_SIGINFO flag, which would mean
// our "info" arg holds an undefined value.
if (!have_siginfo(signal_number)) {
info = nullptr;
}

log_signal_summary(signal_number, info);
// 向debuggered发送错误信息
send_debuggerd_packet(info);
....
}

调用send_debuggerd_packet,首先连接debuggerd的服务端socket;接着不断尝试向该socket写入数据,直至成功:

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

static void send_debuggerd_packet(siginfo_t* info) {
// Mutex to prevent multiple crashing threads from trying to talk
// to debuggerd at the same time.
static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER;
int ret = pthread_mutex_trylock(&crash_mutex);
...
// 连接debuggerd
int s = socket_abstract_client(DEBUGGER_SOCKET_NAME, SOCK_STREAM | SOCK_CLOEXEC);
if (s == -1) {
__libc_format_log(ANDROID_LOG_FATAL, "libc", "Unable to open connection to debuggerd: %s", strerror(errno));
return;
}

// debuggerd knows our pid from the credentials on the
// local socket but we need to tell it the tid of the crashing thread.
// debuggerd will be paranoid and verify that we sent a tid
// that's actually in our process.
debugger_msg_t msg;
// crash
msg.action = DEBUGGER_ACTION_CRASH;
msg.tid = gettid();
msg.abort_msg_address = reinterpret_cast<uintptr_t>(g_abort_message);
msg.original_si_code = (info != nullptr) ? info->si_code : 0;
// 向socket写入数据
ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg)));
if (ret == sizeof(msg)) {
char debuggerd_ack;
ret = TEMP_FAILURE_RETRY(read(s, &debuggerd_ack, 1));
int saved_errno = errno;
notify_gdb_of_libraries();
errno = saved_errno;
} else {
// read or write failed -- broken connection?
__libc_format_log(ANDROID_LOG_FATAL, "libc", "Failed while talking to debuggerd: %s", strerror(errno));
}
// 关闭socket
close(s);
}

参考源码: /android/bionic/linker/debugger.cpp

debuggerd.cpp

在服务端进程debuggerd启动时,会不断监听客户端的连接请求,一旦发现有连接,就会读取其中的数据进行处理:

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

static int do_server() {
// debuggerd crashes can't be reported to debuggerd.
// Reset all of the crash handlers.
signal(SIGABRT, SIG_DFL);
signal(SIGBUS, SIG_DFL);
signal(SIGFPE, SIG_DFL);
signal(SIGILL, SIG_DFL);
signal(SIGSEGV, SIG_DFL);
#ifdef SIGSTKFLT
signal(SIGSTKFLT, SIG_DFL);
#endif
signal(SIGTRAP, SIG_DFL);

// Ignore failed writes to closed sockets
signal(SIGPIPE, SIG_IGN);
....
// 创建服务端socket
int s = socket_local_server(SOCKET_NAME, ANDROID_SOCKET_NAMESPACE_ABSTRACT,
SOCK_STREAM | SOCK_CLOEXEC);

// Fork a process that stays root, and listens on a pipe to pause and resume the target.(具体什么作用,没看明白)
if (!start_signal_sender()) {
ALOGE("debuggerd: failed to fork signal sender");
return 1;
}
// 监听并处理客户端进程请求
for (;;) {
sockaddr_storage ss;
sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);
socklen_t alen = sizeof(ss);

ALOGV("waiting for connection\n");
int fd = accept4(s, addrp, &alen, SOCK_CLOEXEC);
if (fd == -1) {
continue;
}

handle_request(fd);
}
return 0;
}


现在debuggerd与客户端进程已经建立好连接了,读取其中的数据并fork一个新的进程处理之:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

static void handle_request(int fd) {
ScopedFd closer(fd);
debugger_request_t request;
memset(&request, 0, sizeof(request));
// 读取数据
int status = read_request(fd, &request);
if (status != 0) {
return;
}
....
// Fork a child to handle the rest of the request.
pid_t fork_pid = fork();
if (fork_pid == -1) {
ALOGE("debuggerd: failed to fork: %s\n", strerror(errno));
// 在子进程中处理请求
} else if (fork_pid == 0) {
worker_process(fd, request);
} else {
monitor_worker_process(fork_pid, request);
}
}

在子进程中处理Crash:首先尝试连接AMS,接着会保存Crash进程的DUMP LOG,最后通过socket发送消息告知AMS有Crash发生,

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

static void worker_process(int fd, debugger_request_t& request) {
// Open the tombstone file if we need it.
std::string tombstone_path;
int tombstone_fd = -1;
switch (request.action) {
case DEBUGGER_ACTION_DUMP_TOMBSTONE:
case DEBUGGER_ACTION_CRASH:
tombstone_fd = open_tombstone(&tombstone_path);
if (tombstone_fd == -1) {
ALOGE("debuggerd: failed to open tombstone file: %s\n", strerror(errno));
exit(1);
}
break;
....
}

// Don't attach to the sibling threads if we want to attach gdb.
// Supposedly, it makes the process less reliable.
bool attach_gdb = should_attach_gdb(request);
....
std::set<pid_t> siblings;
if (!attach_gdb) {
ptrace_siblings(request.pid, request.tid, siblings);
}

int amfd = -1;
std::unique_ptr<std::string> amfd_data;
if (request.action == DEBUGGER_ACTION_CRASH) {
// 连接AMS
amfd = activity_manager_connect();
amfd_data.reset(new std::string);
}

bool succeeded = false;
....
int crash_signal = SIGKILL;
// 保存DUMP LOG
succeeded = perform_dump(request, fd, tombstone_fd, backtrace_map.get(), siblings,
&crash_signal, amfd_data.get());
if (succeeded) {
if (request.action == DEBUGGER_ACTION_DUMP_TOMBSTONE) {
if (!tombstone_path.empty()) {
android::base::WriteFully(fd, tombstone_path.c_str(), tombstone_path.length());
}
}
}
....
if (!attach_gdb) {
// Tell the Activity Manager about the crashing process. If we are
// waiting for gdb to attach, do not send this or Activity Manager
// might kill the process before anyone can attach.
activity_manager_write(request.pid, crash_signal, amfd, *amfd_data.get());
}
....

close(amfd);

exit(!succeeded);
}

连接AMS用来监听native crash的socket, 从这里我们也可以看到,debuggerd进程实际连接的是在NativeCrashListener.java中创建的socket:

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

static int activity_manager_connect() {
android::base::unique_fd amfd(socket(PF_UNIX, SOCK_STREAM, 0));

struct sockaddr_un address;
memset(&address, 0, sizeof(address));
address.sun_family = AF_UNIX;
// The path used here must match the value defined in NativeCrashListener.java.
strncpy(address.sun_path, "/data/system/ndebugsocket", sizeof(address.sun_path));
if (TEMP_FAILURE_RETRY(connect(amfd.get(), reinterpret_cast<struct sockaddr*>(&address), sizeof(address))) == -1) {
return -1;
}

struct timeval tv;
memset(&tv, 0, sizeof(tv));
tv.tv_sec = 1; // tight leash
if (setsockopt(amfd.get(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) {
ALOGE("debuggerd: Unable to connect to activity manager (setsockopt SO_SNDTIMEO failed: %s)",
strerror(errno));
return -1;
}

tv.tv_sec = 3; // 3 seconds on handshake read
if (setsockopt(amfd.get(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
ALOGE("debuggerd: Unable to connect to activity manager (setsockopt SO_RCVTIMEO failed: %s)",
strerror(errno));
return -1;
}

return amfd.release();
}

参考源码: /android/system/core/debuggerd/debuggerd.cpp

ActivityManagerService.java

进程debuggerd跟AMS是通过一个叫/data/system/ndebugsocket的socket进行通信的,该socket在NativeCrashListener.java中创建的; NativeCrashListener实际是一个线程,它是在AMS初始化时创建的,其作用是一直在监听来自debuggerd进程的请求,如果有则处理:

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

NativeCrashListener(ActivityManagerService am) {
mAm = am;
}

@Override
public void run() {
final byte[] ackSignal = new byte[1];

// The file system entity for this socket is created with 0700 perms, owned
// by system:system. debuggerd runs as root, so is capable of connecting to
// it, but 3rd party apps cannot.
....
try {
FileDescriptor serverFd = Os.socket(AF_UNIX, SOCK_STREAM, 0);
final UnixSocketAddress sockAddr = UnixSocketAddress.createFileSystem(
DEBUGGERD_SOCKET_PATH);
Os.bind(serverFd, sockAddr);
Os.listen(serverFd, 1);

while (true) {
FileDescriptor peerFd = null;
try {
// 等待客户端连接
peerFd = Os.accept(serverFd, null /* peerAddress */);
if (MORE_DEBUG) Slog.v(TAG, "Got debuggerd socket " + peerFd);
if (peerFd != null) {
// Only the superuser is allowed to talk to us over this socket
StructUcred credentials =
Os.getsockoptUcred(peerFd, SOL_SOCKET, SO_PEERCRED);
if (credentials.uid == 0) {
// 处理Crash数据
consumeNativeCrashData(peerFd);
}
}
} catch (Exception e) {
Slog.w(TAG, "Error handling connection", e);
} finally {
....
}
}
} catch (Exception e) {
Slog.e(TAG, "Unable to init native debug socket!", e);
}
}

读取socket中的Crash数据,并将其报告给AMS:

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

void consumeNativeCrashData(FileDescriptor fd) {
final byte[] buf = new byte[4096];
final ByteArrayOutputStream os = new ByteArrayOutputStream(4096);

try {
StructTimeval timeout = StructTimeval.fromMillis(SOCKET_TIMEOUT_MILLIS);
Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, timeout);
Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, timeout);

// first, the pid and signal number
int headerBytes = readExactly(fd, buf, 0, 8);
if (headerBytes != 8) {
// protocol failure; give up
Slog.e(TAG, "Unable to read from debuggerd");
return;
}

int pid = unpackInt(buf, 0);
int signal = unpackInt(buf, 4);

// now the text of the dump
if (pid > 0) {
final ProcessRecord pr;
synchronized (mAm.mPidsSelfLocked) {
pr = mAm.mPidsSelfLocked.get(pid);
}
if (pr != null) {
// Don't attempt crash reporting for persistent apps
if (pr.persistent) {
return;
}

int bytes;
do {
// get some data
bytes = Os.read(fd, buf, 0, buf.length);
if (bytes > 0) {
// did we just get the EOD null byte?
if (buf[bytes-1] == 0) {
os.write(buf, 0, bytes-1); // exclude the EOD token
break;
}
// no EOD, so collect it and read more
os.write(buf, 0, bytes);
}
} while (bytes > 0);
....
// 启动另一个线程NativeCrashReporter通知AMS
final String reportString = new String(os.toByteArray(), "UTF-8");
(new NativeCrashReporter(pr, signal, reportString)).start();
} else {
Slog.w(TAG, "Couldn't find ProcessRecord for pid " + pid);
}
} else {
Slog.e(TAG, "Bogus pid!");
}
} catch (Exception e) {
Slog.e(TAG, "Exception dealing with report", e);
// ugh, fail.
}
}

通过NativeCrashReporter线程告知AMS有native crash发生:

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

class NativeCrashReporter extends Thread {
ProcessRecord mApp;
int mSignal;
String mCrashReport;

NativeCrashReporter(ProcessRecord app, int signal, String report) {
super("NativeCrashReport");
mApp = app;
mSignal = signal;
mCrashReport = report;
}

@Override
public void run() {
try {
CrashInfo ci = new CrashInfo();
ci.exceptionClassName = "Native crash";
ci.exceptionMessage = Os.strsignal(mSignal);
ci.throwFileName = "unknown";
ci.throwClassName = "unknown";
ci.throwMethodName = "unknown";
ci.stackTrace = mCrashReport;

mAm.handleApplicationCrashInner("native_crash", mApp, mApp.processName, ci);
} catch (Exception e) {
Slog.e(TAG, "Unable to report native crash", e);
}
}
}


之后的处理流程,跟在第一节关于未捕获异常的时候,就基本一样了。详细可以参考上节内容。

原文作者:Jason Wang

更新日期:2017-07-09, 14:28:30

版权声明:本文采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可

CATALOG
  1. 1. APP层Crash处理
    1. 1.1. 未捕获异常Crash
    2. 1.2. 系统挂起
  2. 2. Native层Crash处理
    1. 2.1. Crash信号处理函数
      1. 2.1.1. debugger.cpp
      2. 2.1.2. debuggerd.cpp
      3. 2.1.3. ActivityManagerService.java