關於使用AIDL出現空指針的解決辦法


使用AIDL進行遠程調用的時候出現的空指針異常,解決過程稍微有點小曲折。具體安下

1.先貼異常信息

1 ERROR/AndroidRuntime(9435): FATAL EXCEPTION: main
2 ERROR/AndroidRuntime(9435): java.lang.NullPointerException
3 ERROR/AndroidRuntime(9435): at android.os.Parcel.readException(Parcel.java:1328)
4 ERROR/AndroidRuntime(9435): at android.os.Parcel.readException(Parcel.java:1276)

2.解析原因:看調用棧顯示的是android.os.Parcel.readException位置出現了空指針異常,但是這是源代碼啊,這里怎么會出空指針異常呢。好吧,要本看源碼了:

 1 public final void readException(int code, String msg) {
 2         switch (code) {
 3             case EX_SECURITY:
 4                 throw new SecurityException(msg);
 5             case EX_BAD_PARCELABLE:
 6                 throw new BadParcelableException(msg);
 7             case EX_ILLEGAL_ARGUMENT:
 8                 throw new IllegalArgumentException(msg);
 9             case EX_NULL_POINTER:
10                 throw new NullPointerException(msg);
11             case EX_ILLEGAL_STATE:
12                 throw new IllegalStateException(msg);
13         }
14         throw new RuntimeException("Unknown exception code: " + code
15                 + " msg " + msg);
16     }

上面是出錯的位置的代碼。傻眼了,原來不是哪里有引用了空對象,而是它拋出了一個空指針異常。這是什么情況呢?

3.接着分析原因:追查readException方法調用的地方

 1 @Override public java.lang.String doOperation() throws android.os.RemoteException
 2 {
 3 android.os.Parcel _data = android.os.Parcel.obtain();
 4 android.os.Parcel _reply = android.os.Parcel.obtain();
 5 java.lang.String _result;
 6 try {
 7 _data.writeInterfaceToken(DESCRIPTOR);
 8 mRemote.transact(Stub.TRANSACTION_getMaxCpuFreq, _data, _reply, 0);
 9 _reply.readException();
10 _result = _reply.readString();
11 }
12 finally {
13 _reply.recycle();
14 _data.recycle();
15 }
16 return _result;
17 }

關鍵代碼是_reply.readException(); _reply為mRemote.transact()方法執行后的返回數據對象,即_reply為遠程接口返回的數據封裝對象。但是通過log查看,遠程接口方法並沒有執行完成啊,並沒有返回數據啊,那怎么會有返回數據呢,而且返回通過返回數據對象拋出了空指針異常?

4.繼續分析原因:由上可知遠程方法並沒有執行完成,但是transact方法卻執行完成了,並且通過返回數據對象拋出了空指針,說明遠程接口的api里面的實現是有問題的,它的問題導致了遠程方法沒有執行完成,直接返回。但是現在問題又來了,由於沒有錯誤日志,沒有調用棧信息,如果快速知道遠程接口哪里代碼出問題了呢。正在困惑的時候看到了國外的網站上給出了解決辦法:

在遠程實現接口的時候,實現onTransact方法,然后在里面捕獲異常,並打印出調用棧的信息:

1 protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
2     try {
3         super.onTransact(code, data, reply, flags);
4     } catch (RuntimeException e) {
5         Log.w("MyClass", "Unexpected remote exception", e);
6         throw e;
7     }
8 }

原來是出現的exception是遠端api實現中拋出來的,然后直接返回,將異常結果拋給了調用遠端程序的客戶端,原來如此。然后借助上面的調試代碼打出的堆棧信息,直接定位,解決問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM