这里详细说明下binder的调用堆栈,方便下次更快的定位到具体的代码
一堆栈信息跟踪
得出下以下观点,就是一个普通的堆栈信息打印
见BinderProxy.java的set方法:
throw new AssertionError("Binder ProxyMap has too many entries:......
1 中间没有对端的堆栈信息输出
2 也不会有native的调用堆栈信息
3 此堆栈信息是服务端打印的
具体看下每行的注释吧
E AndroidRuntime: FATAL EXCEPTION: Binder:1080_2
E AndroidRuntime: Process: com.xxx.xxx, PID: 1080
E AndroidRuntime: java.lang.AssertionError: Binder ProxyMap has too many entries: 20691 (total), 20691 (uncleared), 20691 (uncleared after GC). BinderProxy leak?//binderProxy:说明是客户端发送过来的binder泄漏了
E AndroidRuntime: at android.os.BinderProxy$ProxyMap.set(BinderProxy.java:230)//对BinderProxy对象的缓存进行检查,发现太多了,报错
E AndroidRuntime: at android.os.BinderProxy.getInstance(BinderProxy.java:432)//根据传来的参数new一个BinderProxy来
E AndroidRuntime: at android.os.Parcel.nativeReadStrongBinder(Native Method)//困惑,居然能打印一行native(难道是javaObjectForIBinder用了啥牛叉的机制)
E AndroidRuntime: at android.os.Parcel.readStrongBinder(Parcel.java:2483)//读取parcel中关于客户端的binde参数
E AndroidRuntime: at com.xxx.xxx.object$Stub.onTransact(Iobject.java:121)//服务端重写的onTransact接口
E AndroidRuntime: at android.os.Binder.execTransactInternal(Binder.java:1154)//
E AndroidRuntime: at android.os.Binder.execTransact(Binder.java:1123)//1:服务端唤醒后的执行接口
所以这里的binder对象太多了,也就是客户端的那个binder太多了,没有释放,一般情况下,这个binder都是ams或servicemanager传过来的,唯一的,怎么会
太多了呢,这个一般不会泄漏,往往泄漏的是匿名的binder,比如通过callback传输一个binder给服务端以达到监听服务端的目的的时候
这个时候如果没有对这个客户端binder进行死亡监听,服务端又强引用了这个binder,客户端不停的启动的话,那就会泄漏
这个堆栈信息可以结合抓hprof文件来进行内存泄漏分析,hprof分析问题会解决的更全面,防止其他binder泄漏没有达到这个阈值,但仍泄漏的情况。
二:提供一套简化版的客户端和服务端,可以清晰的看到调用流程,而不是通过aidl来生成
简化版服务端
public class IPCService extends Service {
private MyBinder mBinder = new MyBinder();
private class MyBinder extends Binder {
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
switch (code) {
case 0x001: {
data.enforceInterface(DESCRIPTOR);
int num = data.readInt();
reply.writeNoException();
reply.writeString("");
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
简化版客户端:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
mIBinder = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mIBinder = service;
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
String _result = null;
try {
_data.writeInterfaceToken("IPCService");
_data.writeInt(num);
mIBinder.transact(0x01, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
} catch (RemoteException e) {
e.printStackTrace();
} finally {
_reply.recycle();
_data.recycle();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 绑定远程Service
Intent service = new Intent("xxx.xxx.ipcserver");
bindService(service, mConnection, BIND_AUTO_CREATE);
}
}
三 带有callback的简化版服务端代码
对于我们刚才的打印堆栈信息中的情况
是需要一个callback接口由客户端传输过来一个binder的情况。
,也贴一个对应的简化版的服务端代码
即客户端定义了一个binder接口 IMyBinder通过一个callback接口传入到服务端,这时候服务端是要实例化这个binder的
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
case TRANSACTION_callback:
{
data.enforceInterface(descriptor);
xxx.xxx.IMyBinder _arg0;
_arg0 = xxx.xxx.IMyBinder.Stub.asInterface(data.readStrongBinder());
this.callback(_arg0);
reply.writeNoException();
return true;
}
}