温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Android AIDL通信DeadObjectException解决方法是什么

发布时间:2023-03-09 17:22:52 来源:亿速云 阅读:141 作者:iii 栏目:开发技术

这篇文章主要介绍了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 /*canThrowRemoteException*/, data->dataSize());
        return JNI_FALSE;
    }

    可以看到,这个方法主要做的事情是:

    • Java层传入的data,转换成C++层的指针

    • 获取C++层的Binder代理对象

    • 调用BpBinder对象的transact方法

    • 处理transact的结果,抛出异常

    接下来我们看看,BpBindertransact方法。

    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_BindersignalExceptionForError中处理。

    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解决方法是什么”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注亿速云行业资讯频道。

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    AI