您好,登錄后才能下訂單哦!
這篇文章主要介紹了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
的結果,拋出異常
接下來我們看看,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
接口。
這個方案比較簡單粗暴,就是在多有調用跨進程接口的地方,都加一個Binder是否存活的判斷。
if (mService != null && mService.asBinder().isBinderAlive()) { mService.test(); }
我們來看下isBinderAlive
的源碼,就是判斷mAlive
標志位是否為0。
bool BpBinder::isBinderAlive() const { return mAlive != 0; }
先初始化一個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解決方法是什么”知識都有一定的了解,大家如果還想學習更多知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。