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