fd泄漏检测

一.摘要

我们在分析fd泄漏问题的时候一般的通用方法是在/proc/pid/fd下不断的ls -al | wc -l统计fd数量,并且查看哪个fd不断的增多,然后再去代码中排查对应的代码,有时候光看fd并不容易找到泄漏的地方。本文章将介绍高通的leakdetect方法。

 

二.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

四.hprof辅助分析

    我们有了调用栈后还可以看下是哪个对象持有了这个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

fd泄漏检测_第1张图片

继续搜索:TaskSnapshot

fd泄漏检测_第2张图片

我们发现这里创建了很多TaskSnapshot,因为TaskSnapshot中又包含了一个GraphicBuffer,所以这个时候我们就去排查TaskSnapshot为什么被一直被创建并且没有被回收

五.总结

    有了调用栈之后我们再去分析那就简单了很多了,不需要翻遍源码到处找在哪里泄漏了,直接从调用栈出发查问题就好了

你可能感兴趣的:(安卓应用,安卓系统,c/c++)