我们在分析fd泄漏问题的时候一般的通用方法是在/proc/pid/fd下不断的ls -al | wc -l统计fd数量,并且查看哪个fd不断的增多,然后再去代码中排查对应的代码,有时候光看fd并不容易找到泄漏的地方。本文章将介绍高通的leakdetect方法。
默认情况下手机已经包含了fd泄漏的检测代码,具体路径在:bionic/libc/malloc_debug/,它可以监控:file(1),socket(2),mmap(3)
具体原理就不多说了,有兴趣的自己看源码吧,下边介绍使用方法:
1.adb root
2.adb shell setprop libc.debug.leakdetect 1(1代表监控file,2代表监控socket,3代表监控mmap)
3.adb shell setprop libc.debug.leakdetect.program app_process(安卓进程填app_process,native进程填对应的进程名字)
4.adb shell stop
5.adb shell start
6.adb shell kill -28 pid(你要监控的进程)
7.当你的fd不断增加的时候再次输入:adb shell kill -28 pid
你会在logcat中看到对应的结果:O机器关键字:fd_leak_debug Q机器关键字:malloc_debug
file泄漏检测结果:
06-02 11:59:34.040 5534 17218 E fd_leak_debug: Leak Type: file, count = 1, fd = 173, path = anon_inode:dmabuf
06-02 11:59:34.040 5534 17218 E fd_leak_debug: #00 pc 0000000000004bd8 /system/lib64/libc_leak_detector.so (dup+124)
06-02 11:59:34.040 5534 17218 E fd_leak_debug: #01 pc 00000000000070f0 /system/lib64/libcutils.so (native_handle_clone+144)
06-02 11:59:34.040 5534 17218 E fd_leak_debug: #02 pc 0000000000005e84 /vendor/lib64/hw/[email protected] (android::hardware::graphics::mapper::V2_0::implementation::GrallocMapper::importBuffer(android::hardware::hidl_handle const&, std::__1::function)+80)
06-02 11:59:34.040 5534 17218 E fd_leak_debug: #03 pc 000000000001896c /system/lib64/[email protected]
06-02 11:59:34.040 5534 17218 E fd_leak_debug: #04 pc 0000000000014600 /system/lib64/libui.so (android::Gralloc2::Mapper::importBuffer(android::hardware::hidl_handle const&, native_handle const**) const+88)
06-02 11:59:34.040 5534 17218 E fd_leak_debug: #05 pc 0000000000017dc4 /system/lib64/libui.so (android::GraphicBufferMapper::importBuffer(native_handle const*, native_handle const**)+108)
06-02 11:59:34.040 5534 17218 E fd_leak_debug: #06 pc 0000000000016a04 /system/lib64/libui.so (android::GraphicBuffer::unflatten(void const*&, unsigned long&, int const*&, unsigned long&)+604)
06-02 11:59:34.040 5534 17218 E fd_leak_debug: #07 pc 00000000001373c8 /system/lib64/libandroid_runtime.so
06-02 11:59:34.040 5534 17218 E fd_leak_debug: #08 pc 000000000006b9a4 /system/lib64/libbinder.so (android::Parcel::read(android::Parcel::FlattenableHelperInterface&) const+464)
06-02 11:59:34.040 5534 17218 E fd_leak_debug: #09 pc 0000000000136e1c /system/lib64/libandroid_runtime.so
mmap泄漏检测结果:
06-01 20:47:01.342 17087 19660 E malloc_debug: Leak Type: mmap, count = 1, addr = 0x794fee8000
06-01 20:47:01.342 17087 19660 E malloc_debug: #00 pc 000000000000084c /system/lib64/libc_leak_detector.so (mmap+180)
06-01 20:47:01.342 17087 19660 E malloc_debug: #01 pc 0000000000007bcc /apex/com.android.runtime/lib64/libartbase.so (art::MemMap::MapInternal(void*, unsigned long, int, int, int, long, bool)+88)
06-01 20:47:01.342 17087 19660 E malloc_debug: #02 pc 0000000000007844 /apex/com.android.runtime/lib64/libartbase.so (art::MemMap::MapAnonymous(char const*, unsigned char*, unsigned long, int, bool, bool, art::MemMap*, std::__1::basic_string, std::__1::allocator>*, bool)+280)
06-01 20:47:01.342 17087 19660 E malloc_debug: #03 pc 000000000017aa84 /apex/com.android.runtime/lib64/libart.so (art::IndirectReferenceTable::IndirectReferenceTable(unsigned long, art::IndirectRefKind, art::IndirectReferenceTable::ResizableCapacity, std::__1::basic_string, std::__1::allocator>*)+176)
06-01 20:47:01.342 17087 19660 E malloc_debug: #04 pc 0000000000258890 /apex/com.android.runtime/lib64/libart.so (art::JNIEnvExt::JNIEnvExt(art::Thread*, art::JavaVMExt*, std::__1::basic_string, std::__1::allocator>*)+52)
06-01 20:47:01.342 17087 19660 E malloc_debug: #05 pc 00000000002587fc /apex/com.android.runtime/lib64/libart.so (art::JNIEnvExt::Create(art::Thread*, art::JavaVMExt*, std::__1::basic_string, std::__1::allocator>*)+52)
06-01 20:47:01.342 17087 19660 E malloc_debug: #06 pc 00000000003ce91c /apex/com.android.runtime/lib64/libart.so (art::Thread::CreateNativeThread(_JNIEnv*, _jobject*, unsigned long, bool)+400)
06-01 20:47:01.342 17087 19660 E malloc_debug: #07 pc 0000000000308f28 /apex/com.android.runtime/lib64/libart.so
06-01 20:47:01.342 17087 19660 E malloc_debug: #08 pc 0000000000007fec /system/framework/arm64/boot.oat
06-01 20:47:01.342 17087 19660 E malloc_debug: #09 pc 00000000003dcbf5 /apex/com.android.runtime/javalib/core-oj.jar
我们有了调用栈后还可以看下是哪个对象持有了这个fd,那么我们就需要抓一个hprof辅助分析,抓取方法:adb shell am dumpheap com.android.settings /data/local/tmp/settings.hprof,然后将settings.hprof pull到电脑上并打开,我们这里以“file泄漏检测结果”中的“file泄漏检测结果“来举例,之前我们已经看到了是和GraphicBuffer相关,那么我们在hprof中找到GraphicBuffer,我们发现它的引用关系是:ActivityManager->TaskSnapshot->mSnapshot
继续搜索:TaskSnapshot
我们发现这里创建了很多TaskSnapshot,因为TaskSnapshot中又包含了一个GraphicBuffer,所以这个时候我们就去排查TaskSnapshot为什么被一直被创建并且没有被回收
有了调用栈之后我们再去分析那就简单了很多了,不需要翻遍源码到处找在哪里泄漏了,直接从调用栈出发查问题就好了