Android AIDL通信DeadObjectException解决方法是什么
这篇文章主要介绍了Android AIDL通信DeadObjectException解决方法是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Android AIDL通信DeadObjectException解决方法是什么文章都会有所收获,下面我们一起来看看吧。
崩溃来源
首先,这个崩溃的意思是,多进程在进行跨进程Binder
通信的时候,发现通信的Binder
对端已经死亡了。
抛出异常的Java
堆栈最后一行是BinderProxy.transactNative
,所以我们从这个方法入手,看看崩溃是在哪里产生的。
很显现,transactNative
对应的是一个native
方法,我们找到对应的native
方法,在android_util_Binder.cpp
中。
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj, jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException{ // 如果data数据为空,直接抛出空指针异常 if (dataObj == NULL) { jniThrowNullPointerException(env, NULL); return JNI_FALSE; } // 将Java层传入的对象转换为C++层的指针,如果转换出错,中断执行,返回JNI_FALSE Parcel* data = parcelForJavaObject(env, dataObj); if (data == NULL) { return JNI_FALSE; } Parcel* reply = parcelForJavaObject(env, replyObj); if (reply == NULL && replyObj != NULL) { return JNI_FALSE; } // 获取C++层的Binder代理对象指针 // 如果获取失败,会抛出IllegalStateException IBinder* target = getBPNativeData(env, obj)->mObject.get(); if (target == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!"); return JNI_FALSE; } // 调用BpBinder对象的transact方法 status_t err = target->transact(code, *data, reply, flags); // 如果成功,返回JNI_TRUE,如果失败,返回JNI_FALSE if (err == NO_ERROR) { return JNI_TRUE; } else if (err == UNKNOWN_TRANSACTION) { return JNI_FALSE; } // 处理异常情况的抛出 signalExceptionForError(env, obj, err, true , data->dataSize()); return JNI_FALSE;}
可以看到,这个方法主要做的事情是:
将
Java
层传入的data
,转换成C++
层的指针获取
C++
层的Binder
代理对象调用
BpBinder
对象的transact
方法处理
transact
的结果,抛出异常
接下来我们看看,BpBinder
的transact
方法。
status_t BpBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){ // 首先判断Binder对象是否还存活,如果不存活,直接返回DEAD_OBJECT if (mAlive) { ... status = IPCThreadState::self()->transact(binderHandle(), code, data, reply, flags); return status; } return DEAD_OBJECT;}
transact
的具体方法,我们这里先不讨论。我们可以看到,在这里会判断当前的Binder
对象是否alive
,如果不alive
,会直接返回DEAD_OBJECT
的状态。
返回的结果,在android_util_Binder
的signalExceptionForError
中处理。
void signalExceptionForError(JNIEnv* env, jobject obj, status_t err, bool canThrowRemoteException, int parcelSize){ // 省略其他异常处理的代码 .... case DEAD_OBJECT: // DeadObjectException is a checked exception, only throw from certain methods. jniThrowException(env, canThrowRemoteException ? "android/os/DeadObjectException" : "java/lang/RuntimeException", NULL); break;}
这个方法,其实包含非常多异常情况的处理。为了看起来更清晰,这里我们省略了其他异常的处理逻辑,只保留了DEAD_OBJECT
的处理。可以很明显的看到,在这里我们抛出了DeadObjectException
异常。
解决方法
通过前面的源码分析,我们知道DeadObjectException
是发生在,当我们调用transact
接口发现Binder
对象不再存活的情况。
解决方案也很简单,就是当这个Binder
对象死亡之后,不再调用transact
接口。
方法1 调用跨进程接口之前,先判断Binder是否存活
这个方案比较简单粗暴,就是在多有调用跨进程接口的地方,都加一个Binder是否存活的判断。
if (mService != null && mService.asBinder().isBinderAlive()) { mService.test(); }
我们来看下isBinderAlive
的源码,就是判断mAlive
标志位是否为0。
bool BpBinder::isBinderAlive() const{ return mAlive != 0;}
方法2 监听Binder死亡通知
先初始化一个DeathRecipient
,用来监听死亡通知。
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { @Override public void binderDied() { // 解绑当前监听,重新启动服务 mService.asBinder().unlinkToDeath(mDeathRecipient, 0); if (mService != null) bindService(new Intent("com.service.bind"), mService, BIND_AUTO_CREATE); } };
在这个死亡监听里,我们可以选择几种处理方式:
什么都不做,直接将
mService
设置为空再次尝试启动和绑定服务
在onServiceConnected
方法中,注册死亡监听:
public void onServiceConnected(ComponentName name, IBinder service) { mService = IServiceInterface.Stub.asInterface(service); //获取服务端提供的接口 try { // 注册死亡代理 if(mService != null){ service.linkToDeath(mDeathRecipient, 0); } } catch (RemoteException e) { e.printStackTrace(); }}
关于“Android AIDL通信DeadObjectException解决方法是什么”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“Android AIDL通信DeadObjectException解决方法是什么”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注编程网行业资讯频道。
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341