JNI是Java Native Interface 的缩写,通过JNI,Java函数可以调用C/C++编写的函数,同时C/C++程序可以调用Java函数。调用顺序如下:
java -----> libxxx_jni.so ----->libxxx.so
Java 在调用C/C++函数之前,需要加载JNI库,例如在SystemServer中
[java] view plain copy
1. System.loadLibrary("android_servers");
2. init1(args);
[cpp] view plain copy
1. native public static void init1(String[] args);
init1 是应该本地函数调用,其JNI层代码位于idh.code\frameworks\base\services\jni\com_android_server_SystemServer.cpp
[cpp] view plain copy
1. extern "C" int system_init();
2.
3. static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz)
4. {
5. system_init();
6. }
7.
8. /*
9. * JNI registration.
10. */
11. static JNINativeMethod gMethods[] = {
12. /* name, signature, funcPtr */
13. "init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 },
14. };
15.
16. int register_android_server_SystemServer(JNIEnv* env)
17. {
18. return jniRegisterNativeMethods(env, "com/android/server/SystemServer",
19. gMethods, NELEM(gMethods));
20. }
21.
22. };
JNI层函数android_server_SystemServer_init1调用了本地函数system_init():
[cpp] view plain copy
1. extern "C" status_t system_init()
2. {
3. "Entered system_init()");
4.
5. sp<ProcessState> proc(ProcessState::self());
6.
7. sp<IServiceManager> sm = defaultServiceManager();
8. "ServiceManager: %p\n", sm.get());
9.
10. new GrimReaper();
11. sm->asBinder()->linkToDeath(grim, grim.get(), 0);
12.
13. char propBuf[PROPERTY_VALUE_MAX];
14. "system_init.startsurfaceflinger", propBuf, "1");
15. if (strcmp(propBuf, "1") == 0) {
16. // Start the SurfaceFlinger
17. SurfaceFlinger::instantiate();
18. }
19.
20. // Start the sensor service
21. SensorService::instantiate();
22.
23. // On the simulator, audioflinger et al don't get started the
24. // same way as on the device, and we need to start them here
25. if (!proc->supportsProcesses()) {
26.
27. // Start the AudioFlinger
28. AudioFlinger::instantiate();
29.
30. // Start the media playback service
31. MediaPlayerService::instantiate();
32.
33. // Start the camera service
34. CameraService::instantiate();
35.
36. // Start the audio policy service
37. AudioPolicyService::instantiate();
38. }
39.
40. // And now start the Android runtime. We have to do this bit
41. // of nastiness because the Android runtime initialization requires
42. // some of the core system services to already be started.
43. // All other servers should just start the Android runtime at
44. // the beginning of their processes's main(), before calling
45. // the init function.
46. "System server: starting Android runtime.\n");
47.
48. AndroidRuntime* runtime = AndroidRuntime::getRuntime();
49.
50. "System server: starting Android services.\n");
51. "com/android/server/SystemServer", "init2");
52.
53. // If running in our own process, just go into the thread
54. // pool. Otherwise, call the initialization finished
55. // func to let this process continue its initilization.
56. if (proc->supportsProcesses()) {
57. "System server: entering thread pool.\n");
58. ProcessState::self()->startThreadPool();
59. IPCThreadState::self()->joinThreadPool();
60. "System server: exiting thread pool.\n");
61. }
62. return NO_ERROR;
63. }
以上是整个Java 调用C/C++函数的过程。那么Java 中声明的本地函数如何匹配JNI中的函数呢?这就需要注册JNI函数,JNI函数注册方法包含静态注册和动态注册,下面分别进行介绍。
1.静态注册JNI函数的方法
<1>在java中通过native关键字声明本地方法
<2>通过javah工具生成JNI层头文件
<3>根据生成的头文件,编写相应的C++文件,实现头文件中的方法
当java层调用native函数时,虚拟机会根据JNI函数名在对应的JNI库中寻找相应的JNI函数。
2.动态注册JNI函数的方法
通过JNINativeMethod结构体来关联native函数和JNI函数
[cpp] view plain copy
1. typedef struct {
2. const char* name; //java 中native函数的名字
3. const char* signature; //函数签名,是参数类型和返回值类型组合的字符串
4. void* fnPtr; //JNI层的函数指针
5. } JNINativeMethod;
如上:
[cpp] view plain copy
1. static JNINativeMethod gMethods[] = {
2. /* name, signature, funcPtr */
3. "init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 },
4. };
当Java层通过System.loadLibrary加载完JNI动态库后,会查找该库中的一个叫JNI_OnLoad的函数,如果有,就调用它,JNI函数的动态注册就在这里完成:
[cpp] view plain copy
1. extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
2. {
3. JNIEnv* env = NULL;
4. jint result = -1;
5.
6. if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
7. "GetEnv failed!");
8. return result;
9. }
10. "Could not retrieve the env!");
11.
12. register_android_server_PowerManagerService(env);
13. register_android_server_InputManager(env);
14. register_android_server_LightsService(env);
15. register_android_server_AlarmManagerService(env);
16. register_android_server_BatteryService(env);
17. register_android_server_UsbService(env);
18. register_android_server_VibratorService(env);
19. register_android_server_SystemServer(env);
20. register_android_server_location_GpsLocationProvider(env);
21.
22. return JNI_VERSION_1_4;
23. }
[cpp] view plain copy
1. int register_android_server_SystemServer(JNIEnv* env)
2. {
3. return jniRegisterNativeMethods(env, "com/android/server/SystemServer",gMethods, NELEM(gMethods));//调用jniRegisterNativeMethods完成注册
4. }
[cpp] view plain copy
1. int jniRegisterNativeMethods(JNIEnv* env, const char* className,const JNINativeMethod* gMethods, int numMethods)
2. {
3. jclass clazz;
4.
5. "Registering %s natives\n", className);
6. clazz = (*env)->FindClass(env, className);
7. if (clazz == NULL) {
8. "Native registration unable to find class '%s'\n", className);
9. return -1;
10. }
11.
12. int result = 0;
13. if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
14. "RegisterNatives failed for '%s'\n", className);
15. result = -1;
16. }
17.
18. (*env)->DeleteLocalRef(env, clazz);
19. return result;
20. }
[cpp] view plain copy
1. static jint RegisterNatives(JNIEnv* env, jclass jclazz,const JNINativeMethod* methods, jint nMethods)
2. {
3. JNI_ENTER();
4.
5. ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
6. jint retval = JNI_OK;
7. int i;
8.
9. if (gDvm.verboseJni) {
10. "[Registering JNI native methods for class %s]\n",
11. clazz->descriptor);
12. }
13.
14. for (i = 0; i < nMethods; i++) {
15. if (!dvmRegisterJNIMethod(clazz, methods[i].name,
16. methods[i].signature, methods[i].fnPtr))
17. {
18. retval = JNI_ERR;
19. }
20. }
21.
22. JNI_EXIT();
23. return retval;
24. }
Java 和JNI基本数据类型对应关系
Java 类型 | Native类型 | 符号属性 | 字长 |
Boolean | Jboolean | 无符号 | 8位 |
Byte | Jbyte | 无符号 | 8位 |
Char | Jchar | 无符号 | 16位 |
Short | Jshort | 有符号 | 16位 |
Int | Jint | 有符号 | 32位 |
Long | Jlong | 有符号 | 64位 |
Float | Jfloat | 有符号 | 32位 |
Double | Jdouble | 有符号 | 64位 |
Java 和JNI引用类型对应关系
Java 类型 | Native类型 |
All objects | jobject |
Java.lang.Class | jclass |
Java.lang.String | Jstring |
Object[] | jobjectArray |
Boolean[] | jbooleanArray |
Byte[] | jbyteArray |
Java.lang.Throwable | Jthrowable |
Char[] | jcharArray |
Short[] | jshortArray |
Int[] | jintArray |
Long[] | jlongArray |
Float[] | jfloatArray |
Double[] | jdoubleArray |
JNIEnv 提供了一些JNI系统函数,是一个与线程相关的变量。在JNI中,用jfieldID和jmethodID来表示Java类的成员变量和成员函数,通过以下方法来获取成员变量和成员函数:
[cpp] view plain copy
1. //查找java类
2. static jclass FindClass(JNIEnv* env, const char* name)
3. //获取成员变量
4. static jfieldID GetFieldID(JNIEnv* env, jclass jclazz,const char* name, const char* sig)
5. //获取静态类变量
6. static jfieldID GetStaticFieldID(JNIEnv* env, jclass jclazz,const char* name, const char* sig)
7. //获取成员方法
8. static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name,const char* sig)
9. //获取静态类方法
10. static jmethodID GetStaticMethodID(JNIEnv* env, jclass jclazz,const char* name, const char* sig)
JNI方法签名:
[cpp] view plain copy
1. { "init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 },
()表示参数类型,最右边表示返回值类型,格式为:(参数1类型;参数2类型;参数n类型)返回值类型
V表示void,L表示参数为引用类型
JNI函数签名标示表
Java 类型 | 类型标示 |
Z | Boolean |
B | Byte |
C | Char |
S | Short |
I | Int |
J | long |
F | Float |
D | double |
L/java/lang/string | String |
[I | Int[] |
[L/java/lang/object | Object[] |
JNI中的异常处理:
JNIEnv提供以下三个函数来处理异常:
ExceptionOccured函数,用来判断是否发生异常
ExceptionClear函数,用来清理当前JNI层中发生的异常
ThrowNew函数,用来向Java层抛出异常