关于使用AIDL出现空指针的解决办法

  • Post author:
  • Post category:其他


使用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实现中抛出来的,然后直接返回,将异常结果抛给了调用远端程序的客户端,原来如此。然后借助上面的调试代码打出的堆栈信息,直接定位,解决问题。