Home » Android » android – NullPointerException (etc) from Parcel.readException

android – NullPointerException (etc) from Parcel.readException

Posted by: admin June 15, 2020 Leave a comment

Questions:

Exceptions that look like this are confusing:

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)

I found a bunch of related questions for this, but none with the answer to “how do you debug this”. So I’m making this Question/Answer.

By looking at the android source here and here you’ll see that it can be throwing any of these (the NullPointerException is just what I had):

SecurityException(msg);
BadParcelableException(msg);
IllegalArgumentException(msg);
NullPointerException(msg);
IllegalStateException(msg);
RuntimeException("Unknown exception code: " + code + " msg " + msg);

But what’s causing these?

How to&Answers:

What’s going on here is that readException() is checking the IPC byte stream for a header that says that an exception occurred; if it finds one, then it throws a new exception of that type, with the same message, but missing the original stack trace. (It only actually knows a few exception types; anything else gets translated into a base RuntimeException.)

So where’s the original exception coming from? Well, somewhere down in the guts of the real implementation of YourClass.yourMethod() — not in any of the parcelable or IPC code. So go there, wrap the whole method in a try/catch, and log whatever you caught.

(Or set a breakpoint there if you’ve got remote process breakpoints working.)

Answer:

I think android SHOULD provide more binder remote exception information

so i modify Parcel.java to wrap more binder remote exception information

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()));
}

SerializeExceptionSecondService defination:

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 fragment:

    <service
        android:name=".SerializeExceptionSecondService"
        android:enabled="true"
        android:exported="true"
        android:process=":second_remote" >
    </service>

in this way, the binder exception logcat will look like the below:

enter image description here