如何用AndroidStudio动态调试ART虚拟机?
1.前言
之前有debug过jvm, 开发anroid 临时起意想能不能动态debug art虚拟机,代码是看不下去的,还是跑起来直观。其实调试其他native lib 的原理是一样的。网上也看到一些,受启发比较大的是这位大佬17年写的https://zhuanlan.zhihu.com/p/24867284, 在此先感谢一下他,自己也算是做一个较的,记录一下自己踩过的坑。以下全部基于Android 9 。
2. 编译Android 9 系统
这个有门槛,毕竟AOSP 超大。有个在64核服务器当然好,大概半个小时,全目录60GB左右,但是自己笔记本还是吃不消的,怎么拉下自己编译,还请google。如果只是想要原生这里有https://ci.android.com/,AOSP google编译的,可以在里面直接下载AOSP编译文件,也比较大,且需要联网。如果你还有个pixel, 还可以用来刷机。
- 自己有条件,可以编译
- 从AOSP下载
- 用别人给的,比如我android_framework_native_debug
- 不管怎么,当然要有目标库的源码最好,(哦,你不要的的话,😂 可以直接指令级debug,其实可以不用这么麻烦了,可以直接return )
3.准备一台手机
- 可以刷机,那就刷自己编译的系统
- 不能刷机 ,但可以root,看你是需要调试那个库,如果是其它库,你可能需要自己把编译好的so库push到手机
- 不能root,同用的基础库才可以,比如本次我尝试的art库,libart.so 在2台手机 root和非root,刷机和不刷机的情况下都是可以的。想想厂商还是很少改动art的
4. 新建一个AS工程
我们需要
编译出来好的 目标so文件
AOSP 工程里面源码
编译出来的symbol 目录,里面对应的就是相应库的 debug标记文件,调试中需要用到。找到对应的libart.so。对比大小你就会发现,一个是7mb,一个是150mb。拷贝出来,可以放到工程目录下
当然也可以用你现在的工程,只要是方便debug,查看源码,进行native debug。可以先导入 art 源码到工程里面,可以参考android_framework_native_debug样式。主要是通过AS里面的debug attach 到选择的进程,就可以进行相应的进程debug了。
5.将目标库PUSH到手机
当然也可以不用,比如我在另外一台其它品牌不能root的手机上测试,art库可以直接使用。如果你其它库,建议可以尝试。
6.Attach到目标进程Debug
本android_framework_native_debug工程先写了一个native code ,方便打上断掉,寻找入库,你也可以不用,直接pause也是可以的。
选择带native,可以是dual,等待lldb连接成功。
等待lldb连接成功,点击触发
但是现在看到,栈还没有行号信息,我们自己写的native代码,才有
1
2
3
4
5
6::Java_com_test_CustomizeThread_start(JNIEnv , jobject) native-lib.cpp:38 //这里有行号,
art_quick_generic_jni_trampoline 0x0000006f4bb9b9e4 //这里只有地址
art_quick_invoke_stub 0x0000006f4bb9298c
art::ArtMethod::Invoke(art::Thread, unsigned int, unsigned int, art::JValue, char const) 0x0000006f4b70c6cc
art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread, art::ArtMethod, art::ShadowFrame, unsigned short, art::JValue) 0x0000006f4b8bcab8
bool art::interpreter::DoCall<false, false>(art::ArtMethod, art::Thread, art::ShadowFrame&,我们继续进入,force step into
1
2
3
4
5
6art::(anonymous namespace)::CheckJNI::FindClass(_JNIEnv*, char const*) 0x0000006f4b71e728
_JNIEnv::FindClass(char const*) jni.h:504
::Java_com_test_CustomizeThread_start(JNIEnv *, jobject) native-lib.cpp:38
art_quick_generic_jni_trampoline 0x0000006f4bb9b9e4
art_quick_invoke_stub 0x0000006f4bb9298c
---可以看到,又没有源码信息了,接下来我们手动加入符号信息库
通过 d -p 反编译,可以知道我们当前pc所在的库和函数
1
2
3
4
5
6(lldb) d -p
libart.so`art::(anonymous namespace)::CheckJNI::FindClass:
-> 0x6f4b71e728 <+4>: stp x28, x27, [sp, #0x70]
0x6f4b71e72c <+8>: stp x26, x25, [sp, #0x80]
0x6f4b71e730 <+12>: stp x24, x23, [sp, #0x90]
0x6f4b71e734 <+16>: stp x22, x21, [sp, #0xa0]手动加入符号信息库, 有下面信息,说明ok
报错就是目标so不符合
1
2(lldb) add-dsym /Users/kenchan/GitHub/android_framework_native_debug/symbol/libart.so
symbol file '/Users/kenchan/GitHub/android_framework_native_debug/symbol/libart.so' has been added to '/Users/kenchan/.lldb/module_cache/remote-android/.cache/88B6A7B4-8B23-9260-2988-33B24671013C/libart.so'
通过souce info 查看一下 对应的源码信息
1
2
3(lldb) source info
Lines found in module `libart.so
[0x0000006f4b71e714-0x0000006f4b71e750): art/runtime/scoped_thread_state_change-inl.h:38:5可以看到目录信息,这里linux下是绝对路径。所以我们要做一下映射
1
(lldb) settings set target.source-map art/ /Users/kenchan/GitHub/android_framework_native_debug/art
你再点击一下 setp,就会发现调用栈里面有 源码文件信息了
我们点击某一个调用栈,就是发现 跳转了源码文件了
现在的调用栈是
1
2
3
4
5
6
7
8
9std::__1::basic_ostream<char, std::__1::char_traits<char> >& std::__1::operator<<<std::__1::char_traits<char> >(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, char const*) 0x0000006f4b71e750
art::ScopedThreadStateChange::ScopedThreadStateChange(art::Thread*, art::ThreadState) scoped_thread_state_change-inl.h:38
art::ScopedObjectAccessUnchecked::ScopedObjectAccessUnchecked(_JNIEnv*) scoped_thread_state_change-inl.h:108
art::ScopedObjectAccess::ScopedObjectAccess(_JNIEnv*) scoped_thread_state_change-inl.h:119
art::(anonymous namespace)::CheckJNI::DefineClass(_JNIEnv*, char const*, _jobject*, signed char const*, int) check_jni.cc:1824
_JNIEnv::FindClass(char const*) jni.h:504
::Java_com_test_CustomizeThread_start(JNIEnv *, jobject) native-lib.cpp:38
art_quick_alloc_array_resolved32_tlab 0x0000006f4bb9b9e4
art_quick_throw_string_bounds 0x0000006f4bb9298c
7. 你可以用本android_framework_native_debug工程做什么?
- 如果你的手机也是 anroid 9.0
- 如果你也是想debug art
- 你可以直接下载运行本工程,按步骤即可,不需要root,不需要push
- 我编译的是arm平台的,所以在模拟器里面不行
参考
https://zhuanlan.zhihu.com/p/24867284