最近,我正在学习Android JNI。我写了一个演示并尝试使用JNI调用一些Android SDK方法,然后发生了一些奇怪的崩溃。 1.使用JNI调用IActivityManager.getLaunchedFromUid(IBinder令牌),在某些设备上失败! 2.使用JNI调用IPackageManager.getLaunchedFromUid(String packageName,int flags),几乎在所有设备上都失败了!
这是我的Java代码。
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<?> 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<?> 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<?> activityClazz = Class.forName("android.app.Activity");
Method getActivityTokenMethod = activityClazz.getDeclaredMethod("getActivityToken");
getActivityTokenMethod.setAccessible(true);
Object activityToken = getActivityTokenMethod.invoke(this);
Class<?> 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<?> iPackageManagerClazz = Class.forName("android.content.pm.IPackageManager");
Method getPackageUidMethod = iPackageManagerClazz.getDeclaredMethod("getPackageUid", String.class, int.class);
getPackageUidMethod.setAccessible(true);
Class<?> 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");
}
}
这是我的C ++代码。
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->FindClass("android/content/pm/IPackageManager");
jmethodID mid = env->GetMethodID(IPackageManagerClazz, "getPackageUid", "(Ljava/lang/String;I)I");
jint uid = env->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->FindClass("android/app/IActivityManager");
jmethodID midGetLaunchedFromUid = env->GetMethodID(IActivityManagerClazz, "getLaunchedFromUid", "(Landroid/os/IBinder;)I");
int uid = env->CallIntMethod(iActivityManager, midGetLaunchedFromUid, activityToken);
return uid;
}
使用JNI调用IActivityManager.getLaunchedFromUid(IBinder令牌)时的崩溃日志
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)
使用JNI调用IPackageManager.getLaunchedFromUid(String packageName,int flags)时出现崩溃日志
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)
虽然我们可能不会在实际应用中做这些事情,但我很好奇为什么会发生这些崩溃。
感谢您的帮助!