title: JNI DETECTED ERROR IN APPLICATION: bad arguments & JNI ERROR (app bug): accessed stale global reference
body: <p>Recently I'm learning Android JNI. I wrote a demo and tried to call some Android SDK methods using JNI, then some stranges crash occurred.
  1. Call IActivityManager.getLaunchedFromUid(IBinder token) using JNI, fail on some devices!
  2. Call IPackageManager.getLaunchedFromUid(String packageName, int flags) using JNI, almost fail on all devices!</p>
  
  <p>Here is my Java code.</p>
  
  <pre><code>public class HelloJni extends Activity {
  
      private static final String TAG = "HelloJni";
  
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.activity_hello_jni);
          TextView tv = (TextView) findViewById(R.id.hello_textview);
  
          try {
              Class&lt;?&gt; activityManagerNativeClass = Class.forName("android.app.ActivityManagerNative");
              Field gDefaultField = activityManagerNativeClass.getDeclaredField("gDefault");
              gDefaultField.setAccessible(true);
              Object gDefault = gDefaultField.get(null);
              // gDefault is an android.util.Singleton Object
              Class&lt;?&gt; singleton = Class.forName("android.util.Singleton");
              // get the mInstance from ActivityManagerNative.gDefault. The mInstance implements IActivityManager
              Field mInstanceField = singleton.getDeclaredField("mInstance");
              mInstanceField.setAccessible(true);
              Object rawIActivityManager = mInstanceField.get(gDefault);
  
              // get ActivityToken
              Class&lt;?&gt; activityClazz = Class.forName("android.app.Activity");
              Method getActivityTokenMethod = activityClazz.getDeclaredMethod("getActivityToken");
              getActivityTokenMethod.setAccessible(true);
              Object activityToken = getActivityTokenMethod.invoke(this);
  
              Class&lt;?&gt; iActivityManagerClazz = Class.forName("android.app.IActivityManager");
              Method getLaunchedFromUidMethod = iActivityManagerClazz.getDeclaredMethod("getLaunchedFromUid", IBinder.class);
              getLaunchedFromUidMethod.setAccessible(true);
              // Call IActivityManager.getLaunchedFromUid(IBinder token) using reflection, success!
              int uid = (int) getLaunchedFromUidMethod.invoke(rawIActivityManager, activityToken);
              Log.d(TAG, "uid=" + uid);
  
              Class&lt;?&gt; iPackageManagerClazz = Class.forName("android.content.pm.IPackageManager");
              Method getPackageUidMethod = iPackageManagerClazz.getDeclaredMethod("getPackageUid", String.class, int.class);
              getPackageUidMethod.setAccessible(true);
              Class&lt;?&gt; activityThreadClazz = Class.forName("android.app.ActivityThread");
              Field sPackageManagerFiled = activityThreadClazz.getDeclaredField("sPackageManager");
              sPackageManagerFiled.setAccessible(true);
              Method method = activityThreadClazz.getDeclaredMethod("currentActivityThread");
              method.setAccessible(true);
              Object activityThread = method.invoke(null);
              Object sPackageManager = sPackageManagerFiled.get(activityThread);
              // Call IPackageManager.getLaunchedFromUid(IBinder token) using reflection, success!
              int packageUid = (int) getPackageUidMethod.invoke(sPackageManager, "com.example.hellojni", 0);
              Log.d(TAG, "packageUid=" + packageUid);
  
              // Call IActivityManager.getLaunchedFromUid(IBinder token) using JNI, fail on some devices!
              // Call IPackageManager.getLaunchedFromUid(String packageName, int flags) using JNI, almost fail on all devices!
              packageUid = getPackageUid(sPackageManager);
              tv.setText("uid=" + getLaunchedFromUid(rawIActivityManager, activityToken) + " packageUid=" + packageUid);
          } catch (Exception e) {
              e.printStackTrace();
          }
      }
  
      public native int getPackageUid(Object iPackageManager);
  
      public native int getLaunchedFromUid(Object iActivityManager, Object activityToken);
  
      static {
          System.loadLibrary("hello-jni");
      }
  }
  </code></pre>
  
  <p>Here is my C++ code.</p>
  
  <pre class="lang-cpp prettyprint-override"><code>extern "C" {
      JNIEXPORT jint JNICALL Java_com_example_hellojni_HelloJni_getPackageUid(JNIEnv * env, jobject thisObject, jobject iPackageManager);
      JNIEXPORT jint JNICALL Java_com_example_hellojni_HelloJni_getLaunchedFromUid(JNIEnv * env, jobject thisObject, jobject iActivityManager, jobject activityToken);
  };
  
  JNIEXPORT jint JNICALL Java_com_example_hellojni_HelloJni_getPackageUid(JNIEnv * env, jobject thisObject, jobject iPackageManager) {
      jclass IPackageManagerClazz = env-&gt;FindClass("android/content/pm/IPackageManager");
      jmethodID mid = env-&gt;GetMethodID(IPackageManagerClazz, "getPackageUid", "(Ljava/lang/String;I)I");
      jint uid = env-&gt;CallIntMethod(iPackageManager, mid, "com.example.hellojn", 0);
      return uid;
  }
  
  JNIEXPORT jint JNICALL Java_com_example_hellojni_HelloJni_getLaunchedFromUid(JNIEnv * env, jobject thisObject, jobject iActivityManager, jobject activityToken) {
      jclass IActivityManagerClazz = env-&gt;FindClass("android/app/IActivityManager");
      jmethodID midGetLaunchedFromUid = env-&gt;GetMethodID(IActivityManagerClazz, "getLaunchedFromUid", "(Landroid/os/IBinder;)I");
      int uid = env-&gt;CallIntMethod(iActivityManager, midGetLaunchedFromUid, activityToken);
      return uid;
  }
  </code></pre>
  
  <p>Crash log when calling IActivityManager.getLaunchedFromUid(IBinder token) using JNI</p>
  
  <pre><code>E/art: JNI ERROR (app bug): attempt to pass an instance of android.app.IActivityManager as argument 1 to int android.app.IActivityManager.getLaunchedFromUid(android.os.IBinder)
  E/art: JNI DETECTED ERROR IN APPLICATION: bad arguments passed to int android.app.IActivityManager.getLaunchedFromUid(android.os.IBinder) (see above for details)
  E/art:     from int com.example.hellojni.HelloJni.getLaunchedFromUid(java.lang.Object, java.lang.Object)
  E/art: "main" prio=5 tid=1 Runnable
  E/art:   | group="main" sCount=0 dsCount=0 obj=0x755b12a0 self=0xf4bf6a00
  E/art:   | sysTid=23997 nice=-1 cgrp=default sched=0/0 handle=0xf75f7de4
  E/art:   | state=R schedstat=( 172765773 2780770 100 ) utm=12 stm=5 core=9 HZ=100
  E/art:   | stack=0xff370000-0xff372000 stackSize=8MB
  E/art:   | held mutexes= "mutator lock"(shared held)
  E/art:     at com.example.hellojni.HelloJni.getLaunchedFromUid(Native method)
  E/art:     at com.example.hellojni.HelloJni.onCreate(HelloJni.java:64)
  E/art:     at android.app.Activity.performCreate(Activity.java:6288)
  E/art:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1113)
  </code></pre>
  
  <p>Crash log when calling IPackageManager.getLaunchedFromUid(String packageName, int flags) using JNI</p>
  
  <pre><code>E/art: JNI ERROR (app bug): accessed stale global reference 0xf392b302 (index 44224 in a table of size 300)
  E/art: JNI DETECTED ERROR IN APPLICATION: use of deleted global reference 0xf392b302
  E/art:     from int com.example.hellojni.HelloJni.getPackageUid(java.lang.Object)
  E/art: "main" prio=5 tid=1 Runnable
  E/art:   | group="main" sCount=0 dsCount=0 obj=0x755b12a0 self=0xf4bf6a00
  E/art:   | sysTid=24310 nice=-1 cgrp=default sched=0/0 handle=0xf75f7de4
  E/art:   | state=R schedstat=( 48943077 1340463 65 ) utm=1 stm=3 core=9 HZ=100
  E/art:   | stack=0xff370000-0xff372000 stackSize=8MB
  E/art:   | held mutexes= "mutator lock"(shared held)
  E/art:     at com.example.hellojni.HelloJni.getPackageUid(Native method)
  E/art:     at com.example.hellojni.HelloJni.onCreate(HelloJni.java:63)
  E/art:     at android.app.Activity.performCreate(Activity.java:6288)
  E/art:     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1113)
  E/art:     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2500)
  E/art:     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2613)
  E/art:     at android.app.ActivityThread.access$900(ActivityThread.java:180)
  E/art:     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1473)
  E/art:     at android.os.Handler.dispatchMessage(Handler.java:111)
  E/art:     at android.os.Looper.loop(Looper.java:207)
  E/art:     at android.app.ActivityThread.main(ActivityThread.java:5710)
  E/art:     at java.lang.reflect.Method.invoke!(Native method)
  E/art:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:900)
  </code></pre>
  
  <p>Although we may not do such things in real application, I'm so curious about why these crashes occurred.</p>
  
  <p>Thanks for your help!</p>