起因是在使用第三方app的时候,鼠标进入第三方app后,退出进入其他app卡顿的问题。通过分析log发现有大量的System.err: android.os.DeadObjectException产生。
这个异常的产生是因为app和鼠标服务组成的cs模型中,app client突然挂掉导致,服务端产生DeadObjectException。
这里涉及到binder的死亡监听机制对服务端和客户端的处理,客户端需要调用linkToDeath去获取服务端binder的生存状态,如果binder突然挂掉,客户端就要讲binder连接remove掉。同样,如果客户端突然挂掉,服务端也需要去及时的进行处理,否则就会出现DeadObjectException。网上大多介绍了如何去对服务端的binder进行死亡监听,但是没有简洁的服务端对客户端的死亡监听(这里相当于对服务端的listener进行处理)。
首先新建一个继承 implements IBinder.DeathRecipient的listener类,然后在服务端的registerAIDLListener函数内新建一个类,然后添加linkToDeath。
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return mAIDLController;
}
private Binder mAIDLController = new AIDLController.Stub(){
@Override
public void registerAIDLListener(AIDLListener listener,String client){
Log.d(TAG,"registerAIDLListener"+" client = "+client+" pid = "+Binder.getCallingPid());
if ("airmouse".equals(client)){
mAirMouseListener = listener;
}else if("XXX".equals(client)){
mXXXListenerPid = Binder.getCallingPid();
mListenerHashMap.put(mXXXListenerPid,listener);
//Add client listener
XXXListenerRecord mXXXListenerRecord = new XXXListenerRecord();//add新建一个死亡监听对象
try {//add
listener.asBinder().linkToDeath(mXXXListenerRecord, 0);//add 通过对刚才新建的一个listener添加linkToDeath,一但检测到client端异常死亡,就会出发该类重写的binderdied事件
} catch (RemoteException e) {//add 获取远端异常
Log.d(TAG, "XXXListener already died.", e);//add
}//add
}else{
Log.d(TAG,"registerAIDLListener client is not support: client = "+client);
}
}
@Override
public void unRegisterAIDLListener(AIDLListener listener,String client){
Log.d(TAG,"unRegisterAIDLListener"+" client = "+client+" pid = "+Binder.getCallingPid());
if ("airmouse".equals(client)){
mAirMouseListener = null;
}else if("XXX".equals(client)){
mListenerHashMap.remove(Binder.getCallingPid());
}else{
Log.d(TAG,"unRegisterAIDLListener client is not support: client = "+client);
}
}
@Override
public void updateAirMouseControllerState(boolean enable){
Log.d(TAG,"UpdateAirMouseControllerState"+" enable = "+enable);
mAirMouseControllerState = enable;
Intent intent = new Intent();
intent.putExtra("enable", enable);
intent.setAction("ENABLE_HAND_DEVICES");
localBroadcastManager.sendBroadcast(intent);
}
};
private class XXXListenerRecord implements IBinder.DeathRecipient {//add该类继承于IBinder的DeathRecipient
@Override//add
public void binderDied() {//add
Log.d(TAG, "BinderDied.");//add
mListenerHashMap.remove(mXXXListenerPid);//add当linkToDeath受到client异常死亡之后,从hash表里移除该listener
}//
}
实际上,测试的时候,先进入app,然后开始kill掉app进程,采用
adb shell ps | grep "XXX"
adb shell kill -9 pid
的方法,并没有成功kill掉进程,采用
adb shell pm disable packagename;
的方法会让app不在自动起,因为项目中launch会自动起该app,disable后,就无法被唤起,需要再度唤起需要
adb shell pm enable packagename;
同时,如果关联进程比较多,binder可能并不会挂掉,可以尝试多杀几个关联进程,来确保binder连接挂掉
第二部分
关于对服务器binder进行的监听,网上版本比较多,同时上诉方法中,没有考虑client列表的情况,如果有多个client的情况下,需要进行listener的添加和移除,可以考虑参看如下blog
# [Android AIDL SERVICE 双向通信 详解](http://www.cnblogs.com/punkisnotdead/p/5158016.html)
网友评论