JNI(1)

JNI是Android系统中Java与Native交互的桥梁


MediaRecorder举例

  • java:MediaRecorder.java
  • JNI:动态库libmedia_jni.so
  • Native:动态库libmedia.so (实际功能)

java层MediaRecorder

1
2
3
4
5
6
7
8
9
10
11
//frameworks/base/media/java/android/media/MediaRecorder.java
public class MediaRecorder{
static {
//加载mediajni动态库
System.loadLibrary("media_jni");
native_init();
}
//两个native方法,交给jni处理
private static native final void native_init();
public native void start() throws IllegalStateException;
}

JNI层的MediaRecorder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//frameworks/base/media/jni/android_media_MediaRecorder.cpp
static void android_media_MediaRecorder_native_init(JNIEnv *env){
jclass clazz;
clazz = env->FindClass("android/media/MediaRecorder");
if (clazz == NULL) {return;}
......
fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative","(Ljava/lang/Object;IIILjava/lang/Object;)V");
if (fields.post_event == NULL) {
return;
}
}

static void android_media_MediaRecorder_start(JNIEnv *env, jobject thiz){
ALOGV("start");
sp<MediaRecorder> mr = getMediaRecorder(env, thiz);
process_media_recorder_call(env, mr->start(), "java/lang/RuntimeException", "start failed.");
}

native_init如何找到对应的android_media_MediaRecorder_native_init ?

JNI注册

静态注册

静态注册就是根据方法名,将Java方法和JNI方法建立关联,但是它有一些缺点:

  • JNI层的方法名称过长。
  • 声明Native方法的类需要用javah生成头文件。
  • 初次调用JIN方法时需要建立关联,影响效率。
动态注册

JNI中的JNINativeMethod,用来关联Java中的Native方法和JNI中的方法,它在jni.h中被定义:

1
2
3
4
5
typedef struct {
const char* name;//Java方法的名字
const char* signature;//Java方法的签名信息
void* fnPtr;//JNI中对应的方法指针
} JNINativeMethod;

系统的MediaRecorder采用的就是动态注册,定义数组,然后注册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//frameworks/base/media/jni/android_media_MediaRecorder.cpp
static const JNINativeMethod gMethods[] = {
......
{"start", "()V", (void *)android_media_MediaRecorder_start},
{"stop", "()V", (void *)android_media_MediaRecorder_stop},
{"pause", "()V", (void *)android_media_MediaRecorder_pause},
{"resume", "()V", (void *)android_media_MediaRecorder_resume},
{"native_reset", "()V", (void *)android_media_MediaRecorder_native_reset},
{"release", "()V", (void *)android_media_MediaRecorder_release},
{"native_init", "()V", (void *)android_media_MediaRecorder_native_init},
......
};

//JNI_OnLoad in android_media_MediaPlayer.cpp
int register_android_media_MediaRecorder(JNIEnv *env){
return AndroidRuntime::registerNativeMethods(env,
"android/media/MediaRecorder", gMethods, NELEM(gMethods));
}

//frameworks/base/core/jni/AndroidRuntime.cpp
/*static*/ int AndroidRuntime::registerNativeMethods(JNIEnv* env,
const char* className, const JNINativeMethod* gMethods, int numMethods){
return jniRegisterNativeMethods(env, className, gMethods, numMethods);
}

//libnativehelper/JNIHelp.cpp
extern "C" int jniRegisterNativeMethods(JNIEnv* env, const char* className,
const JNINativeMethod* gMethods, int numMethods){
......
if (env->RegisterNatives(c.get(), gMethods, numMethods) < 0) {
char* msg;
(void)asprintf(&msg, "RegisterNatives failed for '%s'; aborting...", className);
env->FatalError(msg);
}
return 0;
}

最终调用JNIEnv的RegisterNatives
从注释//JNI_OnLoad in android_media_MediaPlayer.cpp可以看到register_android_media_MediaRecorder的调用点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//frameworks/base/media/jni/android_media_MediaPlayer.cpp
jint JNI_OnLoad(JavaVM* vm, void* /* reserved */){
JNIEnv* env = NULL;
jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
ALOGE("ERROR: GetEnv failed\n");
goto *bail;
}
assert(env != NULL);
......
if (register_android_media_MediaPlayer(env) < 0) {
ALOGE("ERROR: MediaPlayer native registration failed\n");
goto *bail;
}
if (register_android_media_MediaRecorder(env) < 0) {//1
ALOGE("ERROR: MediaRecorder native registration failed\n");
goto *bail;
}
......
result = JNI_VERSION_1_4;
bail:
return result;
}


参考:

http://liuwangshu.cn/tags/Android%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3JNI/