美文网首页
binder通信过程中,服务端和客户端异常处理

binder通信过程中,服务端和客户端异常处理

作者: Ed_Lannister | 来源:发表于2018-05-22 10:51 被阅读94次

    起因是在使用第三方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)

相关文章

网友评论

      本文标题:binder通信过程中,服务端和客户端异常处理

      本文链接:https://www.haomeiwen.com/subject/tiacjftx.html