Android 来自Parcel.readException的NullPointerException(etc)
看起来像这样的异常令人困惑:Android 来自Parcel.readException的NullPointerException(etc),android,parcel,Android,Parcel,看起来像这样的异常令人困惑: FATAL EXCEPTION: main java.lang.NullPointerException at android.os.Parcel.readException(Parcel.java:1437) at android.os.Parcel.readException(Parcel.java:1385) at com.yourpackage.ipc.IYourClass$Stub$Proxy.yourMethod(IYourCla
FATAL EXCEPTION: main
java.lang.NullPointerException
at android.os.Parcel.readException(Parcel.java:1437)
at android.os.Parcel.readException(Parcel.java:1385)
at com.yourpackage.ipc.IYourClass$Stub$Proxy.yourMethod(IYourClass.java:488)
at com.yourpackage.ipc.YourClassShim.yourMethod(YourClassShim.java:269)
我找到了一大堆相关的问题,但没有一个是关于“如何调试这个”的。所以我要提出这个问题/答案
通过查看android源代码,您将看到它可以抛出其中任何一个(NullPointerException正是我所拥有的):
但是是什么导致了这些呢?这里发生的是
readException()
正在检查IPC字节流中是否有一个报头表明发生了异常;如果找到一个异常,则抛出该类型的新异常,该异常包含相同的消息,但缺少原始堆栈跟踪。(它实际上只知道一些异常类型;其他任何类型都会转换为基本的运行时异常
)
那么最初的例外来自哪里?好吧,在YourClass.yourMethod()
的真正实现中的某个地方——不在任何parcelable或IPC代码中。因此,去那里,将整个方法包装在一个try/catch中,并记录您捕获的任何内容
(如果远程进程断点正常工作,也可以在那里设置断点。)我认为android应该提供更多的binder远程异常信息
public final void writeException(Exception e) {
int code = 0;
if (e instanceof SecurityException) {
code = EX_SECURITY;
} else if (e instanceof BadParcelableException) {
code = EX_BAD_PARCELABLE;
} else if (e instanceof IllegalArgumentException) {
code = EX_ILLEGAL_ARGUMENT;
} else if (e instanceof NullPointerException) {
code = EX_NULL_POINTER;
} else if (e instanceof IllegalStateException) {
code = EX_ILLEGAL_STATE;
}
writeInt(code);
StrictMode.clearGatheredViolations();
if (code == 0) {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
}
throw new RuntimeException(e);
}
// I replace writeString(e.getMessage()) with writeString(remoteExceptionToString(e))
writeString(remoteExceptionToString(e));
}
static String remoteExceptionToString(Exception e) {
final StringWriter sw = new StringWriter(1024);
final PrintWriter pw = new PrintWriter(sw, true);
pw.println();
e.printStackTrace(pw);
return sw.toString().replace("\n", String.format("\n(%5d %5d): ", Process.myPid(), Process.myTid()));
}
所以我修改了Parcel.java来包装更多的绑定器远程异常信息
public final void writeException(Exception e) {
int code = 0;
if (e instanceof SecurityException) {
code = EX_SECURITY;
} else if (e instanceof BadParcelableException) {
code = EX_BAD_PARCELABLE;
} else if (e instanceof IllegalArgumentException) {
code = EX_ILLEGAL_ARGUMENT;
} else if (e instanceof NullPointerException) {
code = EX_NULL_POINTER;
} else if (e instanceof IllegalStateException) {
code = EX_ILLEGAL_STATE;
}
writeInt(code);
StrictMode.clearGatheredViolations();
if (code == 0) {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
}
throw new RuntimeException(e);
}
// I replace writeString(e.getMessage()) with writeString(remoteExceptionToString(e))
writeString(remoteExceptionToString(e));
}
static String remoteExceptionToString(Exception e) {
final StringWriter sw = new StringWriter(1024);
final PrintWriter pw = new PrintWriter(sw, true);
pw.println();
e.printStackTrace(pw);
return sw.toString().replace("\n", String.format("\n(%5d %5d): ", Process.myPid(), Process.myTid()));
}
序列化异常SecondService定义:
public class SerializeExceptionSecondService extends Service {
private static final String TAG = "SerializeExceptionSecondService";
public SerializeExceptionSecondService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
return mServiceBinder;
}
private final ISerializeExceptionSecondService.Stub mServiceBinder = new ISerializeExceptionSecondService.Stub() {
@Override
public void throwException() throws RemoteException {
// TODO Auto-generated method stub
Log.e(TAG, "throwException");
throw new IllegalStateException("Cause1", new IllegalStateException("Cause2", new IllegalStateException("Cause3")));
}
@Override
public void noThrowException() throws RemoteException {
// TODO Auto-generated method stub
}
};
}
AndroidManifest.xml片段:
<service
android:name=".SerializeExceptionSecondService"
android:enabled="true"
android:exported="true"
android:process=":second_remote" >
</service>
这样,活页夹异常日志将如下所示: