目录
崩溃来源解决方法方法1 调用跨进程接口之前,先判断Binder是否存活方法2 监听Binder死亡通知总结崩溃来源
使用过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 /*canThrowRemoteException*/, 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();
}
}
总结
跨进程通信时,无法避免出现Binder对端挂掉的情况,所以在调用相关通信接口时,一定要判断连接是否可用,否则就会出现DeadObjectException的崩溃。
以上就是Android AIDL通信DeadObjectException解决方法示例的详细内容,更多关于Android AIDL通信的资料请关注脚本之家其它相关文章!
关键词:
X 关闭
X 关闭
- 15G资费不大降!三大运营商谁提供的5G网速最快?中国信通院给出答案
- 2联想拯救者Y70发布最新预告:售价2970元起 迄今最便宜的骁龙8+旗舰
- 3亚马逊开始大规模推广掌纹支付技术 顾客可使用“挥手付”结账
- 4现代和起亚上半年出口20万辆新能源汽车同比增长30.6%
- 5如何让居民5分钟使用到各种设施?沙特“线性城市”来了
- 6AMD实现连续8个季度的增长 季度营收首次突破60亿美元利润更是翻倍
- 7转转集团发布2022年二季度手机行情报告:二手市场“飘香”
- 8充电宝100Wh等于多少毫安?铁路旅客禁止、限制携带和托运物品目录
- 9好消息!京东与腾讯续签三年战略合作协议 加强技术创新与供应链服务
- 10名创优品拟通过香港IPO全球发售4100万股 全球发售所得款项有什么用处?

