Question

I'm seeing exceptions when ActivityManager.isUserAMonkey() is run on older Android devices:

java.lang.RuntimeException: Unable to start activity ComponentInfo{com.myapp.AndroidApp}: java.lang.RuntimeException: Unknown exception code: 1 msg null
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2781)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2797)
    at android.app.ActivityThread.access$2300(ActivityThread.java:135)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2132)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:143)
    at android.app.ActivityThread.main(ActivityThread.java:4914)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:521)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:858)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
    at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.RuntimeException: Unknown exception code: 1 msg null
    at android.os.Parcel.readException(Parcel.java:1257)
    at android.os.Parcel.readException(Parcel.java:1235)
    at android.app.ActivityManagerProxy.isUserAMonkey(ActivityManagerNative.java:2762)
    at android.app.ActivityManager.isUserAMonkey(ActivityManager.java:990)
    at <com.myapp....> ...

There is a bit of discussion of the bug here (including a classic thats-not-possible response from one of the developers: "In the standard platform implementation this is pretty much not possible.")

https://groups.google.com/forum/?fromgroups=#!topic/android-developers/tQJcM4O4WxM

Its not clear to me if this always happens, or only happens when running under a test monkey, or only on some devices or what. (I'm running into this problem using Apkudo's device testing service, where the user is always a monkey.) Its not clear when this was fixed, either (it doesn't happen on most (all?) newer devices).

Was it helpful?

Solution

The exception seems to be restricted to Android 2.2 (SDK version 8) releases. And seems to have been a bug in android.app.ActivityManagerNative.

Here's the 2.2.1 code (found in ActivityManagerNative.java on grepcode.com):

1248        case IS_USER_A_MONKEY_TRANSACTION: {
1249            data.enforceInterface(IActivityManager.descriptor);
1250            reply.writeInt(isUserAMonkey() ? 1 : 0);
1251            reply.writeNoException();
1252            return true;
1253        }

Here's the 2.3.1 code (which seems to be the same as much more recent 4.x code which I know works correctly). (Also found on grepcode.com):

1248      case IS_USER_A_MONKEY_TRANSACTION: {
1239            data.enforceInterface(IActivityManager.descriptor);
1240            boolean areThey = isUserAMonkey();
1241            reply.writeNoException();
1242            reply.writeInt(areThey ? 1 : 0);
1243            return true;
1244        }

Notice the order of writeNoException and writeInt are reversed in the newer code. The corresponding code to read the parcel seems to be unchanged since 2.2.1 as far as I can tell:

2749    public boolean isUserAMonkey() throws RemoteException {
2750        Parcel data = Parcel.obtain();
2751        Parcel reply = Parcel.obtain();
2752        data.writeInterfaceToken(IActivityManager.descriptor);
2753        mRemote.transact(IS_USER_A_MONKEY_TRANSACTION, data, reply, 0);
2754        reply.readException();
2755        boolean res = reply.readInt() != 0;
2756        data.recycle();
2757        reply.recycle();
2758        return res;
2759    }

This side reads the exception first, then expects the data.

The javadoc for Parcel readException and writeException imply that they record the exception in the parcel's header (and thus shouldn't impact the actual data in the parcel), but it seems the order does matter.

This means on SDK version 8 the ActivietyManager.isUserAMonkey() API will always throw an exception, monkey or not. Android builds after SDK 8 should not throw this exception.

I suspect the SDK 8 exception message might be slightly different without a monkey ("1 msg null" vs. maybe "0 msg null"?), but don't have an example of the exception without a monkey running.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top