本文是基于Android 7.0源码,来分析Native Crash流程。

转自 http://gityuan.com/2016/06/25/android-native-crash/

一、Native Crash

从系统全局来说,Crash分为Framework/App Crash, Native Crash,以及Kernel Crash。

  • 对于framework层或者app层的Crash(即Java层面Crash),那么往往是通过抛出未捕获异常而导致的Crash,这个内容在本文的姊妹篇理解Android Crash处理流程已详细介绍过。
  • 至于Kernel Crash,很多情况是发生Kernel panic,对于内核崩溃往往是驱动或者硬件出现故障。
  • Native Crash,即C/C++层面的Crash,这是介于系统framework层与Linux层之间的一层,这是本文接下来要讲解的内容。

如果你是从事Android系统开发或者架构相关工作,或者遇到需要解系统性的疑难杂症,再或者需要写JNI代码,则就有可能遇到Native Crash,了解系统Native Crash处理流程就很有必要。

接下来介绍介绍Android N的Native Crash处理流程,你没有看错,本文就是针对最新Android Nouget来分析的。Native crash的工作核心是由debuggerd守护进程来完成,在文章调试系列4:debuggerd源码篇),已经介绍过Debuggerdd的工作原理。

要了解Native Crash,首先从应用程序入口位于begin.S中的__linker_init入手。

1.1 begin.S

[-> arch/arm/begin.S]

ENTRY(_start)mov r0, sp//入口地址 【见小节1.2】bl __linker_init/* linker init returns the _entry address in the main image */mov pc, r0
END(_start)

1.2 __linker_init

[-> linker.cpp]

extern "C" ElfW(Addr) __linker_init(void* raw_args) {KernelArgumentBlock args(raw_args);ElfW(Addr) linker_addr = args.getauxval(AT_BASE);...//【见小节1.3】ElfW(Addr) start_address = __linker_init_post_relocation(args, linker_addr);return start_address;
}

1.3 __linker_init_post_relocation

[-> linker.cpp]

static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW(Addr) linker_base) {...// Sanitize the environment.__libc_init_AT_SECURE(args);// Initialize system properties__system_properties_init();//【见小节1.4】debuggerd_init();...
}

1.4 debuggerd_init

[-> linker/debugger.cpp]

__LIBC_HIDDEN__ void debuggerd_init() {struct sigaction action;memset(&action, 0, sizeof(action));sigemptyset(&action.sa_mask);//【见小节1.5】action.sa_sigaction = debuggerd_signal_handler;//SA_RESTART代表中断某个syscall,则会自动重新调用该syscall//SA_SIGINFO代表信号附带参数siginfo_t结构体可传送到signal_handler函数action.sa_flags = SA_RESTART | SA_SIGINFO;//使用备用signal栈(如果可用),以便我们能捕获栈溢出action.sa_flags |= SA_ONSTACK;sigaction(SIGABRT, &action, nullptr);sigaction(SIGBUS, &action, nullptr);sigaction(SIGFPE, &action, nullptr);sigaction(SIGILL, &action, nullptr);sigaction(SIGPIPE, &action, nullptr);sigaction(SIGSEGV, &action, nullptr);
#if defined(SIGSTKFLT)sigaction(SIGSTKFLT, &action, nullptr);
#endifsigaction(SIGTRAP, &action, nullptr);
}

1.5 debuggerd_signal_handler

连接到bionic上的native程序(C/C++)出现异常时,kernel会发送相应的signal; 当进程捕获致命的signal,通知debuggerd调用ptrace来获取有价值的信息(发生crash之前)。

[-> linker/debugger.cpp]

static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void*) {if (!have_siginfo(signal_number)) {info = nullptr; //SA_SIGINFO标识被意外清空,则info未定义}//防止debuggerd无法链接时,仍可以输出一些简要signal信息log_signal_summary(signal_number, info);//建立于debuggerd的socket通信连接 【见小节1.6】send_debuggerd_packet(info);//重置信号处理函数为SIG_DFL(默认操作)signal(signal_number, SIG_DFL);switch (signal_number) {case SIGABRT:case SIGFPE:case SIGPIPE:
#if defined(SIGSTKFLT)case SIGSTKFLT:
#endifcase SIGTRAP:tgkill(getpid(), gettid(), signal_number);break;default:    // SIGILL, SIGBUS, SIGSEGVbreak;}
}

1.6 send_debuggerd_packet

[-> linker/debugger.cpp]

static void send_debuggerd_packet(siginfo_t* info) {// Mutex防止多个crashing线程同一时间来来尝试跟debuggerd进行通信static pthread_mutex_t crash_mutex = PTHREAD_MUTEX_INITIALIZER;int ret = pthread_mutex_trylock(&crash_mutex);if (ret != 0) {if (ret == EBUSY) {__libc_format_log(ANDROID_LOG_INFO, "libc","Another thread contacted debuggerd first; not contacting debuggerd.");//等待其他线程释放该锁,从而获取该锁pthread_mutex_lock(&crash_mutex);}return;}//建立与debuggerd的socket通道int s = socket_abstract_client(DEBUGGER_SOCKET_NAME, SOCK_STREAM | SOCK_CLOEXEC);...debugger_msg_t msg;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;//将DEBUGGER_ACTION_CRASH消息发送给debuggerd服务端ret = TEMP_FAILURE_RETRY(write(s, &msg, sizeof(msg)));if (ret == sizeof(msg)) {char debuggerd_ack;//阻塞等待debuggerd服务端的回应数据ret = TEMP_FAILURE_RETRY(read(s, &debuggerd_ack, 1));int saved_errno = errno;notify_gdb_of_libraries();errno = saved_errno;}close(s);
}

该方法的主要功能:

  • 调用socket_abstract_client,建立于debuggerd的socket通道;
  • action = DEBUGGER_ACTION_CRASH的消息发送给debuggerd服务端;
  • 阻塞等待debuggerd服务端的回应数据。

接下来,看看debuggerd服务端接收到DEBUGGER_ACTION_CRASH的处理流程

二、debuggerd服务端

debuggerd 守护进程启动后,一直在等待socket client的连接。当native crash发送后便会向debuggerd发送action = DEBUGGER_ACTION_CRASH的消息。

2.1 do_server

[-> /debuggerd/debuggerd.cpp]

static int do_server() {...for (;;) {sockaddr_storage ss;sockaddr* addrp = reinterpret_cast<sockaddr*>(&ss);socklen_t alen = sizeof(ss);//等待客户端连接int fd = accept4(s, addrp, &alen, SOCK_CLOEXEC);if (fd == -1) {continue; //accept失败}//处理native crash发送过来的请求【见小节2.2】handle_request(fd);}return 0;
}

2.2 handle_request

[-> /debuggerd/debuggerd.cpp]

static void handle_request(int fd) {android::base::unique_fd closer(fd);debugger_request_t request;memset(&request, 0, sizeof(request));//读取client发送过来的请求【见小节2.3】int status = read_request(fd, &request);...//fork子进程来处理其余请求命令pid_t fork_pid = fork();if (fork_pid == -1) {ALOGE("debuggerd: failed to fork: %s\n", strerror(errno));} else if (fork_pid == 0) {//子进程执行【见小节2.4】worker_process(fd, request);} else {//父进程执行【见小节2.5】monitor_worker_process(fork_pid, request);}
}

2.3 read_request

[-> /debuggerd/debuggerd.cpp]

static int read_request(int fd, debugger_request_t* out_request) {ucred cr;socklen_t len = sizeof(cr);//从fd获取client进程的pid,uid,gidint status = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len);...fcntl(fd, F_SETFL, O_NONBLOCK);pollfd pollfds[1];pollfds[0].fd = fd;pollfds[0].events = POLLIN;pollfds[0].revents = 0;//读取tidstatus = TEMP_FAILURE_RETRY(poll(pollfds, 1, 3000));debugger_msg_t msg;memset(&msg, 0, sizeof(msg));//从fd读取数据并保存到结构体msgstatus = TEMP_FAILURE_RETRY(read(fd, &msg, sizeof(msg)));...out_request->action = static_cast<debugger_action_t>(msg.action);out_request->tid = msg.tid;out_request->pid = cr.pid;out_request->uid = cr.uid;out_request->gid = cr.gid;out_request->abort_msg_address = msg.abort_msg_address;out_request->original_si_code = msg.original_si_code;if (msg.action == DEBUGGER_ACTION_CRASH) {// native crash时发送过来的请求char buf[64];struct stat s;snprintf(buf, sizeof buf, "/proc/%d/task/%d", out_request->pid, out_request->tid);if (stat(buf, &s)) {return -1;  //tid不存在,忽略该显式dump请求}} else if (cr.uid == 0|| (cr.uid == AID_SYSTEM && msg.action == DEBUGGER_ACTION_DUMP_BACKTRACE)) {...} else {return -1;}return 0;
}

read_request执行完成后,则从socket通道中读取到out_request。

2.4 worker_process

处于client发送过来的请求,server端通过子进程来处理

[-> /debuggerd/debuggerd.cpp]

static void worker_process(int fd, debugger_request_t& request) {std::string tombstone_path;int tombstone_fd = -1;switch (request.action) {case DEBUGGER_ACTION_CRASH://打开tombstone文件tombstone_fd = open_tombstone(&tombstone_path);if (tombstone_fd == -1) {exit(1); //无法打开tombstone文件,则退出该进程}break;...}// Attach到目标进程if (ptrace(PTRACE_ATTACH, request.tid, 0, 0) != 0) {exit(1); //attach失败则退出该进程}...//生成backtracestd::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(request.pid));int amfd = -1;std::unique_ptr<std::string> amfd_data;if (request.action == DEBUGGER_ACTION_CRASH) {//当发生native crash,则连接到AMS【见小节2.4.1】amfd = activity_manager_connect();amfd_data.reset(new std::string);}bool succeeded = false;//取消特权模式if (!drop_privileges()) {_exit(1); //操作失败则退出}int crash_signal = SIGKILL;//执行dump操作,【见小节2.4.2】succeeded = perform_dump(request, fd, tombstone_fd, backtrace_map.get(), siblings,&crash_signal, amfd_data.get());if (!attach_gdb) {//将进程crash情况告知AMS【见小节2.4.3】activity_manager_write(request.pid, crash_signal, amfd, *amfd_data.get());}//detach目标进程ptrace(PTRACE_DETACH, request.tid, 0, 0);for (pid_t sibling : siblings) {ptrace(PTRACE_DETACH, sibling, 0, 0);}if (!attach_gdb && request.action == DEBUGGER_ACTION_CRASH) {//发送信号SIGKILL给目标进程[【见小节2.4.4】if (!send_signal(request.pid, request.tid, crash_signal)) {ALOGE("debuggerd: failed to kill process %d: %s", request.pid, strerror(errno));}}...
}

整个过程比较复杂,下面只介绍attach_gdb=false的执行流程:

  1. 当DEBUGGER_ACTION_CRASH ,则调用open_tombstone并继续执行;
  2. 调用ptrace方法attach到目标进程;
  3. 调用BacktraceMap::Create来生成backtrace;
  4. 当DEBUGGER_ACTION_CRASH,则执行activity_manager_connect;
  5. 调用drop_privileges来取消特权模式;
  6. 通过perform_dump执行dump操作;
    • SIGBUS等致命信号,则调用engrave_tombstone(),这是核心方法
  7. 调用activity_manager_write,将进程crash情况告知AMS;
  8. 调用ptrace方法detach到目标进程;
  9. 当DEBUGGER_ACTION_CRASH,发送信号SIGKILL给目标进程tid

2.4.1 activity_manager_connect

[-> debuggerd.cpp]

static int activity_manager_connect() {android::base::unique_fd amfd(socket(PF_UNIX, SOCK_STREAM, 0));if (amfd.get() < -1) {return -1; ///无法连接到ActivityManager(socket失败)}struct sockaddr_un address;memset(&address, 0, sizeof(address));address.sun_family = AF_UNIX;//该路径必须匹配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;  //无法连接到ActivityManager(connect失败)}struct timeval tv;memset(&tv, 0, sizeof(tv));tv.tv_sec = 1;if (setsockopt(amfd.get(), SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) {return -1; //无法连接到ActivityManager(setsockopt SO_SNDTIMEO失败)}tv.tv_sec = 3;if (setsockopt(amfd.get(), SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {return -1; //无法连接到ActivityManager(setsockopt SO_RCVTIMEO失败)}return amfd.release();
}

该方法的功能是建立跟上层ActivityManager的socket连接。对于”/data/system/ndebugsocket”的服务端是在,NativeCrashListener.java方法中创建并启动的。

2.4.2 perform_dump

根据接收到不同的signal采取相应的操作

[-> debuggerd.cpp]

static bool perform_dump(const debugger_request_t& request, int fd, int tombstone_fd,BacktraceMap* backtrace_map, const std::set<pid_t>& siblings,int* crash_signal, std::string* amfd_data) {if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) {return false; //无法响应client端请求}int total_sleep_time_usec = 0;while (true) {//等待信号到来int signal = wait_for_signal(request.tid, &total_sleep_time_usec);switch (signal) {...case SIGABRT:case SIGBUS:case SIGFPE:case SIGILL:case SIGSEGV:
#ifdef SIGSTKFLTcase SIGSTKFLT:
#endifcase SIGTRAP:ALOGV("stopped -- fatal signal\n");*crash_signal = signal;//这是输出tombstone信息最为核心的方法engrave_tombstone(tombstone_fd, backtrace_map, request.pid, request.tid, siblings, signal,request.original_si_code, request.abort_msg_address, amfd_data);break;default:ALOGE("debuggerd: process stopped due to unexpected signal %d\n", signal);break;}break;}return true;
}

对于以下信号都是致命的信号:

  • SIGABRT:abort退出异常
  • SIGBUS:硬件访问异常
  • SIGFPE:浮点运算异常
  • SIGILL:非法指令异常
  • SIGSEGV:内存访问异常
  • SIGSTKFLT:协处理器栈异常
  • SIGTRAP:陷阱异常

另外,上篇文章已介绍过engrave_tombstone的功能内容,这里就不再累赘了。

2.4.3 activity_manager_write

[-> debuggerd.cpp]

static void activity_manager_write(int pid, int signal, int amfd, const std::string& amfd_data) {if (amfd == -1) {return;}//写入pid和signal,以及原始dump信息,最后添加0以标记结束uint32_t datum = htonl(pid);if (!android::base::WriteFully(amfd, &datum, 4)) {return; //AM pid写入失败}datum = htonl(signal);if (!android::base::WriteFully(amfd, &datum, 4)) {return;//AM signal写入失败}if (!android::base::WriteFully(amfd, amfd_data.c_str(), amfd_data.size())) {return;//AM data写入失败}uint8_t eodMarker = 0;if (!android::base::WriteFully(amfd, &eodMarker, 1)) {return; //AM eod 写入失败}//读取应答消息,如果3s超时未收到则读取失败android::base::ReadFully(amfd, &eodMarker, 1);
}

debuggerd与AMS的NativeCrashListener建立socket连接后,再通过该方法发送数据,数据项包括pid、signal、dump信息。

2.4.4 send_signal

此处只是向目标进程发送SIGKILL信号,用于杀掉目标进程,文章理解杀进程的实现原理已详细讲述过发送SIGKILL信号的处理流程。

2.5 monitor_worker_process

static void monitor_worker_process(int child_pid, const debugger_request_t& request) {struct timespec timeout = {.tv_sec = 10, .tv_nsec = 0 };if (should_attach_gdb(request)) {//如果使能wait_for_gdb,则将timeout设置为非常大timeout.tv_sec = INT_MAX;}sigset_t signal_set;sigemptyset(&signal_set);sigaddset(&signal_set, SIGCHLD);bool kill_worker = false;bool kill_target = false;bool kill_self = false;int status;siginfo_t siginfo;int signal = TEMP_FAILURE_RETRY(sigtimedwait(&signal_set, &siginfo, &timeout));if (signal == SIGCHLD) {pid_t rc = waitpid(-1, &status, WNOHANG | WUNTRACED);if (rc != child_pid) {ALOGE("debuggerd: waitpid returned unexpected pid (%d), committing murder-suicide", rc);if (WIFEXITED(status)) {ALOGW("debuggerd: pid %d exited with status %d", rc, WEXITSTATUS(status));} else if (WIFSIGNALED(status)) {ALOGW("debuggerd: pid %d received signal %d", rc, WTERMSIG(status));} else if (WIFSTOPPED(status)) {ALOGW("debuggerd: pid %d stopped by signal %d", rc, WSTOPSIG(status));} else if (WIFCONTINUED(status)) {ALOGW("debuggerd: pid %d continued", rc);}kill_worker = true;kill_target = true;kill_self = true;} else if (WIFSIGNALED(status)) {ALOGE("debuggerd: worker process %d terminated due to signal %d", child_pid, WTERMSIG(status));kill_worker = false;kill_target = true;} else if (WIFSTOPPED(status)) {ALOGE("debuggerd: worker process %d stopped due to signal %d", child_pid, WSTOPSIG(status));kill_worker = true;kill_target = true;}} else {ALOGE("debuggerd: worker process %d timed out", child_pid);kill_worker = true;kill_target = true;}

该方法是运行在debuggerd父进程,用于监控子进程的执行情况。

2.6 小结

debuggerd服务端调用链:

do_serverhandle_requestread_requestworker_process(子进程执行)open_tombstoneptrace(PTRACE_ATTACH, request.tid, 0, 0)backtrace_mapactivity_manager_connectperform_dumpactivity_manager_writeptrace(PTRACE_DETACH, request.tid, 0, 0);send_signalmonitor_worker_process(父进程执行)

handle_request方法中通过fork机制,创建子进程来执行worker_process,由于fork返回两次,返回到父进程则执行monitor_worker_process。

三、NativeCrashListener

3.1 startOtherServices

[-> SystemServer.java]

private void startOtherServices() {...mActivityManagerService.systemReady(new Runnable() {@Overridepublic void run() {mSystemServiceManager.startBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY);try {//【见小节3.2】mActivityManagerService.startObservingNativeCrashes();} catch (Throwable e) {reportWtf("observing native crashes", e);}}}
}

当开机过程中启动服务启动到阶段PHASE_ACTIVITY_MANAGER_READY(550),即服务可以广播自己的Intents,然后启动native crash的监听进程。

3.2 startObservingNativeCrashes

[-> ActivityManagerService.java]

public void startObservingNativeCrashes() {//【见小节3.3】final NativeCrashListener ncl = new NativeCrashListener(this);ncl.start();
}

NativeCrashListener继承于Thread,可见这是线程,通过调用start方法来启动线程开始工作。

3.3 NativeCrashListener

[-> NativeCrashListener.java]

public void run() {final byte[] ackSignal = new byte[1];{//此处DEBUGGERD_SOCKET_PATH= "/data/system/ndebugsocket"File socketFile = new File(DEBUGGERD_SOCKET_PATH);if (socketFile.exists()) {socketFile.delete();}}try {FileDescriptor serverFd = Os.socket(AF_UNIX, SOCK_STREAM, 0);//创建socket服务端final UnixSocketAddress sockAddr = UnixSocketAddress.createFileSystem(DEBUGGERD_SOCKET_PATH);Os.bind(serverFd, sockAddr);Os.listen(serverFd, 1);while (true) {FileDescriptor peerFd = null;try {//等待debuggerd建立连接peerFd = Os.accept(serverFd, null /* peerAddress */);//获取debuggerd的socket文件描述符if (peerFd != null) {//只有超级用户才被允许通过该socket进行通信StructUcred credentials =Os.getsockoptUcred(peerFd, SOL_SOCKET, SO_PEERCRED);if (credentials.uid == 0) {//【见小节3.4】处理native crash信息consumeNativeCrashData(peerFd);}}} catch (Exception e) {Slog.w(TAG, "Error handling connection", e);} finally {//应答debuggerd已经建立连接if (peerFd != null) {Os.write(peerFd, ackSignal, 0, 1);//写入应答消息Os.close(peerFd);//关闭socket...}}}} catch (Exception e) {Slog.e(TAG, "Unable to init native debug socket!", e);}
}

该方法主要功能:

  1. 创建socket服务端:”/data/system/ndebugsocket”文件权限700,owned为system:system,debuggerd是以root权限运行,因此可以与该socket建立连接,但对于第三方App则没有权限;
  2. 等待socket客户端(即debuggerd)来建立连接;
  3. 调用consumeNativeCrashData来处理native crash信息;
  4. 应答debuggerd已经建立连接,并写入应答消息告知debuggerd进程。

3.4 consumeNativeCrashData

[-> NativeCrashListener.java]

void consumeNativeCrashData(FileDescriptor fd) {//进入该方法,标识着debuggerd已经与AMS建立连接final byte[] buf = new byte[4096];final ByteArrayOutputStream os = new ByteArrayOutputStream(4096);try {//此处SOCKET_TIMEOUT_MILLIS=2sStructTimeval timeout = StructTimeval.fromMillis(SOCKET_TIMEOUT_MILLIS);Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, timeout);Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, timeout);//1.读取pid和signal numberint headerBytes = readExactly(fd, buf, 0, 8);if (headerBytes != 8) {return; //读取失败}int pid = unpackInt(buf, 0);int signal = unpackInt(buf, 4);//2.读取dump内容if (pid > 0) {final ProcessRecord pr;synchronized (mAm.mPidsSelfLocked) {pr = mAm.mPidsSelfLocked.get(pid);}if (pr != null) {//persistent应用,直接忽略if (pr.persistent) {return;}int bytes;do {//获取数据bytes = Os.read(fd, buf, 0, buf.length);if (bytes > 0) {if (buf[bytes-1] == 0) {//到达文件EOD, 忽略该字节os.write(buf, 0, bytes-1);break;}os.write(buf, 0, bytes);}} while (bytes > 0);synchronized (mAm) {pr.crashing = true;pr.forceCrashReport = true;}final String reportString = new String(os.toByteArray(), "UTF-8");//异常处理native crash报告【见小节3.5】(new NativeCrashReporter(pr, signal, reportString)).start();}}} catch (Exception e) {Slog.e(TAG, "Exception dealing with report", e);}
}

读取debuggerd那端发送过来的数据,再通过NativeCrashReporter来把native crash事件报告给framework层。

3.5 NativeCrashReporter

[-> NativeCrashListener.java]

class NativeCrashReporter extends Thread {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;//AMS真正处理crash的过程mAm.handleApplicationCrashInner("native_crash", mApp, mApp.processName, ci);} catch (Exception e) {Slog.e(TAG, "Unable to report native crash", e);}}
}

不论是Native crash还是framework crash最终都会调用到handleApplicationCrashInner(),该方法见文章理解Android Crash处理流程。

3.6 小结

system_server进程启动过程中,调用startOtherServices来启动各种其他系统Service时,也正是这个时机会创建一个用于监听native crash事件的NativeCrashListener对象(继承于线程),通过socket机制来监听,等待即debuggerd与该线程创建连接,并处理相应事件。紧接着调用handleApplicationCrashInner来处理crash流程。

NativeCrashListener的主要工作:

  1. 创建socket服务端”/data/system/ndebugsocket”
  2. 等待socket客户端(即debuggerd)来建立连接;
  3. 调用consumeNativeCrashData来处理native crash信息;
  4. 应答debuggerd已经建立连接,并写入应答消息告知debuggerd进程。

四、总结

点击查看大图

Native程序通过link连接后,当发生Native Crash时,则kernel会发送相应的signal,当进程捕获致命的signal,通知debuggerd调用ptrace来获取有价值的信息(这是发生在crash前)。

  1. kernel 发送signal给target进程(包含native代码);
  2. target进程通过debuggerd_signal_handler,捕获signal;
    • 建立于debuggerd进程的socket通道;
    • 将action = DEBUGGER_ACTION_CRASH的消息发送给debuggerd服务端;
    • 阻塞等待debuggerd服务端的回应数据。
  3. debuggerd作为守护进程,一直在等待socket client的连接,此时收到action = DEBUGGER_ACTION_CRASH的消息;
  4. 执行到handle_request时,通过fork创建子进程来执行各种dump相关操作;
  5. 新创建的进程,通过socket与system_server进程中的NativeCrashListener线程建立socket通道,并向其发送native crash信息;
  6. NativeCrashListener线程通过创建新的名为“NativeCrashReport”的子线程来执行AMS的handleApplicationCrashInner方法。

这个流程图只是从整体来概要介绍native crash流程,其中有两个部分是核心方法:

  • 其一是图中红色块perform_dump是整个debuggerd的核心工作,该方法内部调用engrave_tombstone,该方法的具体工作见文章ebuggerd守护进程的功能内容,这个过程还需要与target进程通信来获取target进程更多信息。
  • 其二是AMS的handleApplicationCrashInner,该方法的工作见姊妹篇理解Android Crash处理流程。

理解Native Crash处理流程相关推荐

  1. 结合源码深入理解Android Crash处理流程

    应用程序crash在开发过程中还是很常见的,本文主要是从源码的角度去跟踪下Android对于crash的处理流程.App crash的全称:Application crash.而Crash又分为:na ...

  2. Android稳定性系列8 Native crash处理流程

    一 Native Crash 从系统全局来说,Crash分为Framework/App Crash, Native Crash,以及Kernel Crash. 对于framework层或者app层的C ...

  3. android 中断处理流程,Android P的native crash处理流程

    一.概述 Android系统有监控程序异常退出的机制,这便是本文要讲述得debuggerd守护进程.当发生native crash或者主动调用debuggerd时,会输出进程相关的状态信息到文件或者控 ...

  4. 深入理解Android Crash 流程

    和你一起终身学习,这里是程序员Android 经典好文推荐,通过阅读本文,您将收获以下知识点: 一.Crash 概述 二.Crash处理流程 三.handleApplicationCrash处理分析 ...

  5. 当Android发生Native Crash时,Coredump能为我们带来什么信息?

    ​更多内核安全.eBPF分析和实践文章,请关注博客和公众号: CSDN博客:内核功守道 公众号: 内核功守道 1.概述 1.1 Coredump形成原因 1.2 Coredump的作用 2.使能Cor ...

  6. React Native 源码分析(三)——Native View创建流程

    1.React Native 源码分析(一)-- 启动流程 2.React Native 源码分析(二)-- 通信机制 3.React Native 源码分析(三)-- Native View创建流程 ...

  7. android p 权限流程,Android native 权限控制流程

    关联文章: 前言: 在 Android Runtime Permission 详解 中详细的说明了permission 在Android 6.0 前后的区别,对于M 以后应用可以通过checkPerm ...

  8. Android Native crash 处理案例分享

    简介:Android Native crash 处理案例分享 1. 背景 目前 mPaas[1] Android使用Crash SDK对闪退进行的处理,CrashSDK 是 Android 平台上一款 ...

  9. (1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序

    (1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序 原文:(1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序 版权声明:本作品采用知识共享署名-非商 ...

最新文章

  1. 中国矿业大学计算机英语复试,中国矿业大学2020计算机科学与技术学院考研复试科目参考书目...
  2. Java中一个令人惊讶的bug
  3. mysql导入指定数据库_从mysql全备 导入指定数据库的数据:三种考虑方法
  4. HashMap实现原理
  5. 网络营销专员浅析在网络营销推广中有不少渠道可适当“利用”一下
  6. 《天涯明月刀》窦德斌:美术需要突破自我的局限
  7. 剑与远征种族刻印让玩家期待,绿裔刻印真有那么好看
  8. classpath环境变量
  9. 【转载】浅谈 看图软件 的设计与实现
  10. 【华为云分享】MongoDB-系统时钟跳变引发的风波
  11. SQL Sever — 查询前10%的数据、查询并参与计算显示出数据、查询前10行数据、多重升序降序查询、去掉重复值、替换列名显示
  12. [bzoj3668][Noi2014]起床困难综合症/[洛谷3613]睡觉困难综合症
  13. 企业上云计划:上云前应该考虑哪些因素
  14. ansys怎么批量输入点坐标_AUTO CAD批量输入坐标的技巧
  15. PAT乙级——1010.月饼
  16. 面试时Dubbo原理记不住?来看看《Dubbo原理浅析——从RPC本质看Dubbo》
  17. 行李箱出口沙特saber认证
  18. 帝国CMS整站|手机号/QQ靓号商城源码|适配移动端
  19. google学术,高级搜索怎么使用
  20. [转]提问的智慧(富格式图文版)

热门文章

  1. Sublime text 2和3 修改字体 | 修改主题
  2. 微软发布 Win11 累积更新(KB5014019),版本号升至 22000.708
  3. Maven仓库的分类及优先级
  4. 单身情人节,看看这位Python小哥如何完成人生的逆袭!
  5. 查看DB2数据库版本的方法
  6. 开机登录失败 提示user profile service服务未能登录,无法加载用户配置文件
  7. XDOJ 字符串压缩 C
  8. 上海大学计算机考研试题,08-09上海大学计算机考研试卷.doc
  9. 有了 IP 地址,为什么还要用 MAC 地址?(原作写的真好,转载记录了)
  10. Win10获得system(即超级管理员)权限