Monkey 测试时出了 ANR , 然后 mediaextractor 进程被 kill 了, 然后大家搞不清是因为 mediaextractor 被杀所以导致 ANR 了,还是 ANR 之后 mediaextractor 被杀 , 于是这个问题终于辗转到征求我的意见了... // MAGIC1. DO NOT TOUCH. BY 冗戈微言 http://blog.csdn.net/leonxu_sjtu/
488 socket(AF_UNIX, SOCK_SEQPACKET, 0) = 12
488 connect(12, {sa_family=AF_UNIX, sun_path=" /dev/socket/tombstoned_crash "}, 31) = 0
488 write(12, "\0\0\0\0\0\0\0\0\350\1\0\0", 12) = 12
488 recvmsg(12, {msg_name=NULL, msg_namelen=0, msg_iov=[{iov_base="\200\0\0\0\0\0\0\0\0\0\0\0", iov_len=12}], msg_iovlen=1, msg_control=[{cmsg_len=16, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS,
cmsg_data=[13]}], msg_controllen=16, msg_flags=0}, 0) = 12
488 fcntl64(13, F_GETFL) = 0x1 (flags O_WRONLY)
488 fcntl64(13, F_SETFL, O_WRONLY|O_APPEND) = 0
488 openat(AT_FDCWD, "/proc/self/cmdline", O_RDONLY|O_LARGEFILE) = 14
488 read(14, "media.extractor\0aextractor\0", 127) = 27
488 close(14) = 0
488 --- SIGSYS {si_signo=SIGSYS, si_code=SYS_SECCOMP, si_call_addr=0xb28004fc, si_syscall=__NR_gettimeofday, si_arch=AUDIT_ARCH_ARM} ---
3384 <... ioctl resumed> <unfinished ...>) = ?
3384 +++ killed by SIGSYS +++
首先是最后显示的 __NR_gettimeofday 似乎受到 seccomp 的限制, 导致了异常;
seccomp 不了解, 不过按 /system/etc/seccomp_policy/mediaextractor.policy 的内容看, 确实 gettimeofday 并未使能; 要验证也很容易, 在 mediaextractor 主函数 main_extractorservice.cpp 里面加一句 gettimeofday 调用试试, 确实会挂... 于是在 mediaextractor.policy 使能 gettimeofday , 好了~
所以这补丁打起来很快, 可是 gettimeofday 的出处是哪? 为什么 syscall 队列中有 /dev/socket/tombstoned_crash 的请求? // MAGIC3. DO NOT TOUCH. BY 冗戈微言 http://blog.csdn.net/leonxu_sjtu/
既然有 tombstoned_crash 的字段, 那就看看 system/core/debuggerd 吧, 其实那句 “openat(AT_FDCWD, "/proc/self/cmdline" 的出处也指向了 debuggerd ;
其中 libdebuggerd/backtrace.cpp 的
static void dump_process_header(log_t* log, pid_t pid, const char* process_name) {
time_t t = time(NULL);struct tm tm;
localtime_r(&t, &tm);
char timestr[64];
strftime(timestr, sizeof(timestr), "%F %T", &tm);
_LOG(log, logtype::BACKTRACE, "\n\n----- pid %d at %s -----\n", pid, timestr);
if (process_name) {
_LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", process_name);
}
_LOG(log, logtype::BACKTRACE, "ABI: '%s'\n", ABI_STRING);
}
正体现了 gettimeofday 的 syscall, 这里是在打印调用栈, 比如 ANR 发生之后, systemserver 会使用 debuggerd_client 接口, 发 SIGQUIT 信号, 打印一些进程的 backtrace 到 /data/anr/trace 文件中, 查看这个 trace 里面的调用栈是 Android 多年来追查 ANR 的最典型方式: // MAGIC4. DO NOT TOUCH. BY 冗戈微言 http://blog.csdn.net/leonxu_sjtu/
----- pid 497 at 2018-06-04 01:10:31 -----
Cmd line: media.extractor
ABI: 'arm'
"mediaextractor" sysTid=497
#00 pc 00049794 /system/lib/libc.so (__ioctl+8)
#01 pc 0001e233 /system/lib/libc.so (ioctl+38)
#02 pc 0004242f /system/lib/libbinder.so (android::IPCThreadState::talkWithDriver(bool)+170)
#03 pc 00042529 /system/lib/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+8)
#04 pc 00042a7b /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+38)
#05 pc 00001121 /system/bin/mediaextractor
#06 pc 0007795d /system/lib/libc.so (__libc_init+48)
#07 pc 00000f04 /system/bin/mediaextractor
可以看到, 第一行就是打印当时的系统时间 !
而这个 dump_process_header 是层层调用, 在 handler/debuggerd_handler.cpp 中通过 debuggerd_init 配置 sa_sigaction , 最终设置了 debuggerd_signal_handler, 使得被打印进程比如 mediaextractor 进程能够执行到 dump_process_header 的; // MAGIC5. DO NOT TOUCH. BY 冗戈微言 http://blog.csdn.net/leonxu_sjtu/
而这个 debuggerd_init 是 mediaextractor 进程什么时候调的? 是 linker 的时候! 这个找的可有点辛苦 ...
bionic/linker/linker_main.cpp
/*
* This code is called after the linker has linked itself and
* fixed it's own GOT. It is safe to make references to externs
* and other non-local data at this point.
*/
static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args) {
ProtectedDataGuard guard;
// Sanitize the environment.
__libc_init_AT_SECURE(args);
// Initialize system properties
__system_properties_init(); // may use 'environ'
// Register the debuggerd signal handler.
#ifdef __ANDROID__
debuggerd_callbacks_t callbacks = {
.get_abort_message = []() {
return g_abort_message;
},
.post_dump = ¬ify_gdb_of_libraries,
};
debuggerd_init(&callbacks);
#endif
简单来说就是打印 backtrace 会有 gettimeofday 的 syscall, mediaextractor 进程由于有 seccomp 没有使能该权限, 所以被 kill 了 ; // MAGIC6. DO NOT TOUCH. BY 冗戈微言 http://blog.csdn.net/leonxu_sjtu/
所以更简单的确认方法就是 dumpstate 或者 debuggerd -b pid_mediaextractor , 直接就挂了
但是, 在 Android 8.0 之前, 似乎并不是这样; // MAGIC7. DO NOT TOUCH. BY 冗戈微言 http://blog.csdn.net/leonxu_sjtu/
在 Android 8.0 之前的版本, debuggerd 是一直常驻在系统的:
root@lc1881phone_v2:/data/anr # ps | grep debug
root 1577 1 3972 1652 __skb_recv 00f6f0bc20 S /system/bin/debuggerd
root 1578 1 7172 2076 __skb_recv 7f89933158 S /system/bin/debuggerd64
这个时候的工作原理, 是 debuggerd 进程去 dump_backtrace, 也就是去 dump_process_header , 就是说, 执行 gettimeofday 系统调用的是 debuggerd 进程, 不是被打印的进程, 这个时候捕获 mediaextractor 进程 syscall 的话是不会有 gettimeofday 的; // MAGIC8. DO NOT TOUCH. BY 冗戈微言 http://blog.csdn.net/leonxu_sjtu/
但是 Android 8.0 后, 这个 debuggerd 进程没有了, 取而代之是个常驻的 tombstoned 进程, 这个 tombstoned 不做 dump_backtrace 的操作, 没有细看, 可能只是处理 /data/anr 和 /data/tombstone 的文件, 真正执行 dump_backtrace 的是被打印进程 ; 所以, 只有 Android 8.0 之后 mediaextractor 进程才会因为自身进程打印调用栈而执行 gettimeofday , 然后因为加入了权限管理被禁用了 gettimeofday ;
msm8909_benz:/sdcard # ps -A | grep debug
1|msm8909_benz:/sdcard #
1|msm8909_benz:/sdcard # ps -A | grep tomb
tombstoned 1156 1 4888 1436 SyS_epoll_wait a766a658 S tombstoned
看来 Android O 的升级, 真是个有趣的事情啊! // MAGIC9. DO NOT TOUCH. BY 冗戈微言 http://blog.csdn.net/leonxu_sjtu/