简单介绍下 coredump抓取方法,该方法适用于Android 5.0之后的 Root版本。
adb shell setprop persist.debug.trace 1
设置这个属性的作用:
1.创建存放 core文件的目录 /data/core,配置 core_pattern
# corefile limit on property:persist.debug.trace=1 mkdir /data/core 0777 root root write /proc/sys/kernel/core_pattern "/data/core/%E.%p.%e"
2.在 zygote 新 fork出一个进程后,给这个进程设置 rlimit 为 RLIM_INFINITY
【注意】如果这个属性是在当前进程 fork 出来之后设置的,则不能起到设置当前进程的 rlimit的作用,因为:
--------------------------------------------------------------------------------------------
ForkAndSpecializeCommon()
if(pid == 0) {
→ env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags, is_system_server, instructionSet);
→ callPostForkChildHooks
→ VM_HOOKS.postForkChild(debugFlags, isSystemServer, instructionSet);
→ nativePostForkChild(token, debugFlags, isSystemServer, instructionSet);
→ EnableDebugFeatures(debug_flags);
→ EnableDebugger();
if ( persist.debug.trace == 1) {
→ setrlimit(RLIMIT_CORE, &rl)
}
}
--------------------------------------------------------------------------------------------
从这个调用过程可以看到,一个 APP进程的 Rlimit 是在进程刚刚 fork 出来时设置的,根据 persist.debug.trace==1 来设置 rlimit 的;
如果错过了这个时机,是没有其他机会设置 rlimit的;【问题1】如果错过了这个时机怎么办,比如定屏的手机,想让 system_server coredump,而在定屏之前没有设置这个属性 ?这个在第 5部分说明。
【注】这个属性是 persist 的,设置一次后,即便重启也不需要重设了。
adb shell setenforce 0
关闭 selinux功能,从而不会因为 SE权限问题导致的 dump core 失败;
【注】每次重启手机,都需要重新关闭一次。
coredump类型,是由进程的 /proc/pid/coredump_filter 标志位决定的。
full dump: /*0x27 MMF_DUMP_ANON_PRIVATE|MMF_DUMP_ANON_SHARED|MMF_DUMP_MAPPED_PRIVATE|MMF_DUMP_HUGETLB_PRIVATE*/
normal dump: /*0x23 MMF_DUMP_ANON_PRIVATE|MMF_DUMP_ANON_SHARED|MMF_DUMP_HUGETLB_PRIVATE*/
进程默认的 filter是 0x23,所以如果是一般的 dump core就能满足需求,则不需要这一步;
而如果需要 full dump,则需要设置:
adb shell echo 0x27 > /proc/pid/coredump_filter
它们的区别是:MMF_DUMP_MAPPED_PRIVATE
【注】如果需要 full dump,进程重启后需要重新设置,因为默认启动后是 0x23
对于一个 APP进程,如果不能很好的把握其启动时机,以及 FC的时机 { 比如app一启动就 Crash,比如 CTS测试过程中 FC },而又要抓其 fulldump,
那么可以给对应的 zygote/ zygote64 进程设置 coredump_filter,因为APP进程从 zygote fork出来会继承其 coredump_filter,也能达到目的;
如果你的进程在特定步骤下就会 Native Crash,则触发这个路径即可。
一般情况下,我们使用发送信号的方式触发 coredump:
adb shell kill -6 pid
即,给 pid发送一个 ABORT信号,使之 abort;
这样 core file 就会生成在 /data/core/ 目录下了,同样 /data/tombstones/ 目录下有对应的 tombstone文件
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
【注】一般情况下,我们遇到的问题都是偶现的,有一个现场不容易,所以在有一定把握前,不要轻易的发送使进程挂掉的信号,先做如下检查,输出符合时再发送信号:
@1:~$ adb shell cat /proc/1310/coredump_filter
00000023
@1:~$ adb shell cat /proc/1310/limits | grep "core file"
Max core file size unlimited unlimited bytes
@1:~$ adb shell cat /proc/sys/kernel/core_pattern
/data/core/%E.%p.%e
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
第2部分的问题,在这里回答,
【问题1】如果错过了这个时机怎么办,比如定屏的手机,想让 system_server coredump,而在定屏之前没有设置这个属性 ?
对于这种情况,我们可以使用 GDB attach 上 system_server进程,调用 setrlimit 函数来给当前进程设置 rlimit。
其实,在能够 attach的情况下,已经不需要 core dump了,不过,在调试完成后,做个 coredump可以把现场长久的保留下来。
设置方式:
gdb attach方法,网上都有,这里就不展开了。主要介绍下 GDB中 调用函数的方法:
调用函数的关键在于参数的构造:
1.我们可以使用当前线程栈上还未使用的空间上构造参数, $sp - 0x1000 可以用来构造参数,使用之前先查看原来的值(如果你想还原栈的话)
2.参数的赋值使用 set 命令
3.函数的调用使用 call 命令
【注】一般Art线程的 stack size >= 1MB + 8k + 8k,实际查看的size是: 1036 K,最后 8K 不可用。所以上边使用当前栈帧 $sp - 0x1000 (4k),一般情况下,都应该还在线程的栈上;
(gdb) p /x $sp
$1 = 0x7fc2519240
(gdb) x /6x 0x7fc2518240
0x7fc2518240: 0xc25192d0 0x0000007f 0xacb70a8c 0x00000071
0x7fc2518250: 0xa1ce18c7 0xb398b292
(gdb) p * ((rlimit*)0x7fc2518240)
$3 = {
rlim_cur = 548720972496,
rlim_max = 488228981388
}
(gdb) set ((rlimit*)0x7fc2518240)->rlim_cur=10
(gdb) set ((rlimit*)0x7fc2518240)->rlim_max=20
(gdb) p * ((rlimit*)0x7fc2518240)
$4 = {
rlim_cur = 10,
rlim_max = 20
}
(gdb) call setrlimit(4, 0x7fc2518240)
$5 = 0
可以看到调用 setrlimit 函数的返回值是 0;
# cat /proc/24656/limits | grep core
Limit Soft Limit Hard Limit Units
Max core file size 10 20 bytes
在函数调用完成后当前进程的 rlimit 已经成功设置为 10 和 20;我们的真实情况应该是设置这两个值都是 -1;
要开启 coredump,像上面那样要设置的项还是过多,不够方便。所以我们集成了这些设置到一个工具: setcoredump使用该工具,执行一条命令即可达到开启 coredump功能的能力:
具体使用方式,在 help msg 中已有说明,工具是在 Android5.0 环境下编译的;test:/ # setcoredump setcoredump: should have an option value as bellow: Usage: setcoredump -h: show this help message. setcoredump -f: enable full dump on this device. setcoredump -n: enable normal dump on this device. setcoredump -p [pid] : enable normal dump for one process [pid]. setcoredump -f -p [pid]: enable full dump for one process [pid]. core file directory: /data/core/