中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

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

    珠海市| 嘉善县| 平塘县| 保定市| 大宁县| 星子县| 凌源市| 乌拉特中旗| 台山市| 枣庄市| 保定市| 泉州市| 库尔勒市| 昆明市| 三明市| 内江市| 屯门区| 临武县| 观塘区| 朝阳市| 仪征市| 台中县| 龙井市| 周宁县| 于都县| 栖霞市| 杭锦旗| 阿瓦提县| 和政县| 富源县| 原阳县| 巴彦县| 招远市| 木里| 方城县| 临潭县| 衡东县| 正定县| 莫力| 万安县| 彭州市|