关于 OpenCoreSDK
详情可参考上一篇文章 Android 应用程序如何抓取 Coredump
配置 Coredump
1 | java复制代码public class App extends Application { |
测试 Java OOM 场景
1 | java复制代码public class LeakMemory { |
1 | java复制代码void doOOM(View view) { |
当我们点击 “doOOM” 的按钮时,程序会不停的创建一个 LeakMemory 对象,直到程序发生 OOM Crash,当发生 Java Crash 时,会被 Opencore 拦截触发抓取 Coredump。
1 | java复制代码AndroidRuntime: java.lang.OutOfMemoryError: Failed to allocate a 65552 byte allocation with 63712 free bytes and 62KB until OOM, target footprint 268435456, growth limit 268435456 |
我们即可拿个到该 OOM 问题的内存现场,那么我们可以进行离线内存分析,对于 ART 虚拟机的应用程序,我们有专门的分析工具可以辅助。类似的也可用 GDB、LLDB 来完成。
解析 Java 堆栈定位 Execption 类型。
1 | java复制代码art-parser> bt 19987 |
展开寄存器查看 Java 函数调用参数。
1 | java复制代码... |
字节码反编译确定 Throwable 对象所在寄存器。
1 | java复制代码art-parser> disassemble 0x707001e0 -i 0x7caeeb287e |
解析 Throwable 错误信息。
1 | java复制代码art-parser> dumpjava 0x12cc0000 |
统计 Java 堆内存对象占用的 ShallowSize 大小以及分配数量,可见 byte[] 数组占用了 200+M 内存。并与 LeakMemory 对象分配的数量高度吻合。
1 | java复制代码art-parser> top 10 -a -d |
解析每一个 LeakMemory 内存分布, 可确定 LeakMemory 对象均持有一个 byte[] 数组,并且每一个 byte[] 大小为 65552 字节, 因此 LeakMemory 对象存在泄露。
1 | java复制代码art-parser> p 0x12f69ec8 -r |
由于 LeakMemory 被线程的局部变量 java.util.ArrayList 所持有,无法 GC 回收,因此造成 OOM。
1 | java复制代码art-parser> p 0x12f57108 |
测试 Native Crash 场景
该测试用例在 Android12~Android13 之间使用,要看到这个 Native Crash 问题编译 apk 注意 debuggable 的条件,当 debuggable 为 false,此问题必现。
1 | java复制代码public class NterpTester { |
1 | java复制代码void doTest(View view) { |
当 debuggable 为 true 时,需做一些小小的 HOOK 处理才能复现,我们需要将 setList 这个 Java 函数运行方式修改为 Nterp 解析运行。
1 | java复制代码void doHook(View view) { |
强行修改 entry_point_from_quick_compiled_code_ 让其跳转函数到 ExecuteNterpImpl。
1 | c++复制代码extern "C" |
1 | java复制代码Opencore-SDK: Init opencore environment.. |
可看到堆栈在 java 函数 java.lang.String.valueOf 处发生 Native Crash。
1 | java复制代码art-parser> bt 20397 -adj |
解析机器码可看到在指令 ldr x0,[x0, #192] 上发生段错误。此时 x0 实际上是 x1 对象的 klass_ 成员变量的值。
1 | asm复制代码(gdb) x /32i 0x9cb60fb0 |
而 x1 对象为 java.util.ArrayList, 并且最终内存转储后,klass_ = 0x705bf568,并非空指针。
1 | java复制代码art-parser> p 0x000000001409fec0 |
该问题这里不进行详细解答,感兴趣的可以私信我,该问主要原因在于 mList = new ArrayList<>(); 该代码为 Nterp 解释运行下的 new-instance 这条字节码身上。
1 | java复制代码art-parser> disassemble 0x7c9c56ded0 --full |
具体修复可对 mList 成员对象添加 volatile 修饰来避免,只有 Android14 之后才修复。
1 | asm复制代码// https://android-review.googlesource.com/c/platform/art/+/2583193 |
本文转载自: 掘金