Android稳定性系列8 Nativecrash处理流程

Android稳定性系列8 Nativecrash处理流程
⼀ 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 = auxval(AT_BASE);
微型吸尘器
...
//【见⼩节1.3】
ElfW(Addr) start_address =__linker_init_post_relocation(args, linker_addr);
return start_address;
}
hxi1.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);
#endif
sigaction(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:
#endif
case SIGTRAP:
tgkill(getpid(),gettid(), signal_number);
break;
default:// SIGILL, SIGBUS, SIGSEGV
break;
}
}
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);
//将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);
}
return0;
}
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,gid
int 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;
/
/读取tid
status =TEMP_FAILURE_RETRY(poll(pollfds,1,3000));
debugger_msg_t msg;
memset(&msg,0,sizeof(msg));
//从fd读取数据并保存到结构体msg
status =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 = iginal_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;
}
return0;
}
read_request执⾏完成后,则从socket通道中读取到out_request。
2.4 worker_process
处于client发送过来的请求,server端通过⼦进程来处理
/debuggerd/debuggerd.cpp

本文发布于:2024-09-23 00:34:12,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/3/277474.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:处理   服务端   进程   系统   等待   发送
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议