经常遇到binder泄露的问题,要怎么分析呢
一 加log
1: binder 驱动log :要先其他log锁定时间点,因为他的进程号一直是0 所以不建议这里加log。
可以直接打印对应的文件信息:/dev/binderfs/binder_logs/state
里面列出了各个进程对应的binder node信息,可以大致看下有没有binder句柄泄露的情况
2: writeStrongBinder 客户端只要有binder请求,都会调用这个接口
对应的服务端也会调用这个readStrongBinder接口(native层对应的接口也有)
3:给binder 传入自己的 ProxyTransactListener 可以实现客户端调用开始结束等的监听
参考 MediaProvider里面的Binder.setProxyTransactListener(mTransactListener);
4: BinderProxy内部的map缓存也会在set的时候打印关键信息
加log信息:看对应进程的binder连接数,kenel看node数,必要时候打印堆栈信息以获取具体泄露调用链,或hprop文件查看对应的泄露对象和调用链。
打印hprop文件
Debug.dumpHprofData("/data/system/dropbox/" + file);
打印堆棧信息:
Log.i("ygn",new Exception("Custom Exception")
二 案例总结
1 surfaceflinger 中layer大于最大值会提示报错:
这种问题就是binder句柄泄露导致的,这种情况往往会有两种情况导致,一是wms端 的binder(surface,windowstate) 泄露,或者 app端 mWindow 对应的binder泄露
2 system_server崩溃重启:
这种往往会搜到对应的各个进程的bpbinder句柄数,进而能大概知道哪个进程binder泄露,而如果要进一步查找对应的泄漏对象及其引用堆栈,需要打印 hprof 文件协助分析
3 app端 提示binder对端可能已死:
这种原因往往是binder缓存空间用尽导致,两种情况导致
一是 该端频繁调用未释放,一是 该端使用了oneway,频繁调用且服务端又比较耗时,导致堵死在异步todo队列里占满了缓存空间
4 app端比较常见的一种 window was originally added here 这种泄漏,这个问题原因
就是子窗口需要依附父窗口,但父窗口却先结束了,导致这个子窗口泄漏,子窗口往往是dialog等,父窗口一般是activiy。