欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android?AIDL通信DeadObjectException解決方法示例

 更新時(shí)間:2023年03月09日 16:16:40   作者:尹學(xué)姐  
這篇文章主要為大家介紹了Android?AIDL通信DeadObjectException解決的方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

崩潰來源

使用過AIDL進(jìn)行跨進(jìn)程通信的同學(xué),肯定遇到過DeadObjectException這個(gè)崩潰,那么這個(gè)崩潰是怎么來的,我們又該如何解決它呢?今天這篇文章就來聊一聊。

首先,這個(gè)崩潰的意思是,多進(jìn)程在進(jìn)行跨進(jìn)程Binder通信的時(shí)候,發(fā)現(xiàn)通信的Binder對(duì)端已經(jīng)死亡了。

拋出異常的Java堆棧最后一行是BinderProxy.transactNative,所以我們從這個(gè)方法入手,看看崩潰是在哪里產(chǎn)生的。

很顯現(xiàn),transactNative對(duì)應(yīng)的是一個(gè)native方法,我們找到對(duì)應(yīng)的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數(shù)據(jù)為空,直接拋出空指針異常
    if (dataObj == NULL) {
        jniThrowNullPointerException(env, NULL);
        return JNI_FALSE;
    }
    // 將Java層傳入的對(duì)象轉(zhuǎn)換為C++層的指針,如果轉(zhuǎn)換出錯(cuò),中斷執(zhí)行,返回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代理對(duì)象指針
    // 如果獲取失敗,會(huì)拋出IllegalStateException
    IBinder* target = getBPNativeData(env, obj)->mObject.get();
    if (target == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!");
        return JNI_FALSE;
    }
    // 調(diào)用BpBinder對(duì)象的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;
}

可以看到,這個(gè)方法主要做的事情是:

  • Java層傳入的data,轉(zhuǎn)換成C++層的指針
  • 獲取C++層的Binder代理對(duì)象
  • 調(diào)用BpBinder對(duì)象的transact方法
  • 處理transact的結(jié)果,拋出異常

接下來我們看看,BpBindertransact方法。

status_t BpBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    // 首先判斷Binder對(duì)象是否還存活,如果不存活,直接返回DEAD_OBJECT
    if (mAlive) {
            ...
            status = IPCThreadState::self()->transact(binderHandle(), code, data, reply, flags);
            return status;
    }
    return DEAD_OBJECT;
}

transact的具體方法,我們這里先不討論。我們可以看到,在這里會(huì)判斷當(dāng)前的Binder對(duì)象是否alive,如果不alive,會(huì)直接返回DEAD_OBJECT的狀態(tài)。

返回的結(jié)果,在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;
}

這個(gè)方法,其實(shí)包含非常多異常情況的處理。為了看起來更清晰,這里我們省略了其他異常的處理邏輯,只保留了DEAD_OBJECT的處理??梢院苊黠@的看到,在這里我們拋出了DeadObjectException異常。

解決方法

通過前面的源碼分析,我們知道DeadObjectException是發(fā)生在,當(dāng)我們調(diào)用transact接口發(fā)現(xiàn)Binder對(duì)象不再存活的情況。

解決方案也很簡(jiǎn)單,就是當(dāng)這個(gè)Binder對(duì)象死亡之后,不再調(diào)用transact接口。

方法1 調(diào)用跨進(jìn)程接口之前,先判斷Binder是否存活

這個(gè)方案比較簡(jiǎn)單粗暴,就是在多有調(diào)用跨進(jìn)程接口的地方,都加一個(gè)Binder是否存活的判斷。

        if (mService != null && mService.asBinder().isBinderAlive()) {
            mService.test();
        }

我們來看下isBinderAlive的源碼,就是判斷mAlive標(biāo)志位是否為0。

bool BpBinder::isBinderAlive() const
{
    return mAlive != 0;
}

方法2 監(jiān)聽Binder死亡通知

先初始化一個(gè)DeathRecipient,用來監(jiān)聽死亡通知。

    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            // 解綁當(dāng)前監(jiān)聽,重新啟動(dòng)服務(wù)
            mService.asBinder().unlinkToDeath(mDeathRecipient, 0);
            if (mService != null)
                bindService(new Intent("com.service.bind"), mService, BIND_AUTO_CREATE);
        }
    };

在這個(gè)死亡監(jiān)聽里,我們可以選擇幾種處理方式:

  • 什么都不做,直接將mService設(shè)置為空
  • 再次嘗試啟動(dòng)和綁定服務(wù)

onServiceConnected方法中,注冊(cè)死亡監(jiān)聽:

public void onServiceConnected(ComponentName name, IBinder service) {          
    mService = IServiceInterface.Stub.asInterface(service);     
    //獲取服務(wù)端提供的接口
    try {
        // 注冊(cè)死亡代理
        if(mService != null){
            service.linkToDeath(mDeathRecipient, 0); 
        }       
    } catch (RemoteException e) {
        e.printStackTrace();
    }
}

總結(jié)

跨進(jìn)程通信時(shí),無法避免出現(xiàn)Binder對(duì)端掛掉的情況,所以在調(diào)用相關(guān)通信接口時(shí),一定要判斷連接是否可用,否則就會(huì)出現(xiàn)DeadObjectException的崩潰。

以上就是Android AIDL通信DeadObjectException解決方法示例的詳細(xì)內(nèi)容,更多關(guān)于Android AIDL通信的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論