使用AIDL进行远程调用的时候出现的空指针异常,解决过程稍微有点小曲折。具体安下
1.先贴异常信息
1 ERROR/AndroidRuntime(9435): FATAL EXCEPTION: main2 ERROR/AndroidRuntime(9435): java.lang.NullPointerException3 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: " + code15 + " 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实现中抛出来的,然后直接返回,将异常结果抛给了调用远端程序的客户端,原来如此。然后借助上面的调试代码打出的堆栈信息,直接定位,解决问题。