Android android.os.DeadObjectException aidl通信异常分析及解决

问题描述

做一款音乐播放应用,播放服务是通过AIDL形式对外暴露,允许跨进程调用且多个App同时操作音乐播放,偶现android.os.DeadObjectException问题

复制代码
12-15 09:28:12.371: W/System.err(5412): android.os.DeadObjectException
12-15 09:28:12.372: W/System.err(5412): 	at android.os.BinderProxy.transactNative(Native Method)
12-15 09:28:12.372: W/System.err(5412): 	at android.os.BinderProxy.transact(Binder.java:496)

问题分析

在使用aidl进行进程间通信时,有时候在客户端调用服务端的接口会抛出DeadObjectException异常,原因一般是由于某种原因服务端程序崩溃重启或者服务对象由于内存紧张被回收导致的

问题解决

方案1

针对应用开发,可以在服务端进程启动的时候发个消息给客户端,客户端收到消息的时候重新进行绑定操作,目的是为了同步客户端和服务端的连接,客户端进程启动的时候也要绑定一次(注:在已经连接的情况下,服务端由于某种原因进程重启了,如果客户端没有收到回调,客户端保存的连接不为空,这时调用服务端接口就会抛出DeadObjectException异常)

方案2

调用的对象不存在,因为它所在App进程不存在或进程崩溃,此时在底层回调时报错。

那么在调用对象之前,建议检查是否存在此进程。DeadObjectException异常出现是因为App进程不存在或进程崩溃因此在底层回调时报错。进程不存在或者进程崩溃需要查看其他日志来定位。对于进程崩溃的情况,也有可能部分原因是由于操作系统考虑到内存、CPU、优先级等指标,选择杀死一个进程得到资源。

java 复制代码
  ActivityManager activityManager = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> pidsTask = activityManager.getRunningAppProcesses();
    for(int i = 0; i < pidsTask.size(); i++) {
        nameList.add(pidsTask.get(i).processName);
    idList.add(pidsTask.get(i).uid);
    }
    If(nameList.contains("processName")){
       // 进程存在
    }
    else{
       // 进程不存在
    }

方案2

进行死亡监听

1)在调用服务端接口的时候先进行判断bind是否还活着

java 复制代码
if (mIMyAidlInterface != null && mIMyAidlInterface.asBinder().isBinderAlive()) {
    try {
        mIMyAidlInterface.startRecord();
    } catch (Exception e) {
        Log.e(TAG, "Exception");
        e.printStackTrace();
    }
}

2)注册死亡代理

java 复制代码
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {

    @Override
    public void binderDied() {                           
    // 当绑定的service异常断开连接后,自动执行此方法
        Log.e(TAG,"binderDied " );
        if (mIMyAidlInterface != null){
    // 当前绑定由于异常断开时,将当前死亡代理进行解绑        mIMyAidlInterface.asBinder().unlinkToDeath(mDeathRecipient, 0);
            //  重新绑定服务端的service
            bindService(new Intent("com.service.bind"),mMyServiceConnection,BIND_AUTO_CREATE);      
        }
    }
};

3)在service绑定成功后,调用linkToDeath()注册进service,当service发生异常断开连接后会自动调用binderDied()

java 复制代码
public void onServiceConnected(ComponentName name, IBinder service) {          
    //绑定成功回调
    Log.d(TAG, "onServiceConnected");
    mIMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);     
    //获取服务端提供的接口
    try {
    // 注册死亡代理
    if(mIMyAidlInterface != null){
    Log.d(TAG, mIMyAidlInterface.getName());
    service.linkToDeath(mDeathRecipient, 0); 
    }       
    } catch (RemoteException e) {
        e.printStackTrace();
    }
}
相关推荐
每次的天空1 小时前
Android-自定义View的实战学习总结
android·学习·kotlin·音视频
恋猫de小郭1 小时前
Flutter Widget Preview 功能已合并到 master,提前在体验毛坯的预览支持
android·flutter·ios
断剑重铸之日2 小时前
Android自定义相机开发(类似OCR扫描相机)
android
随心最为安2 小时前
Android Library Maven 发布完整流程指南
android
岁月玲珑2 小时前
【使用Android Studio调试手机app时候手机老掉线问题】
android·ide·android studio
还鮟7 小时前
CTF Web的数组巧用
android
小蜜蜂嗡嗡8 小时前
Android Studio flutter项目运行、打包时间太长
android·flutter·android studio
aqi008 小时前
FFmpeg开发笔记(七十一)使用国产的QPlayer2实现双播放器观看视频
android·ffmpeg·音视频·流媒体
zhangphil10 小时前
Android理解onTrimMemory中ComponentCallbacks2的内存警戒水位线值
android
你过来啊你10 小时前
Android View的绘制原理详解
android