本文转载自:
JNI是Native Interface 的缩写,通过JNI,函数可以调用C/C++编写的函数,同时C/C++程序可以调用Java函数。调用顺序如下:
java -----> libxxx_jni.so ----->libxxx.so
Java 在调用C/C++函数之前,需要加载JNI库,例如在SystemServer中
- System.loadLibrary("android_servers");
- init1(args);
- native public static void init1(String[] args);
init1 是应该本地函数调用,其JNI层代码位于idh.code\frameworks\base\services\jni\com_android_server_SystemServer.cpp
- extern "C" int system_init();
- static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz)
- {
- system_init();
- }
- /*
- * JNI registration.
- */
- static JNINativeMethod gMethods[] = {
- /* name, signature, funcPtr */
- { "init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 },
- };
- int register_android_server_SystemServer(JNIEnv* env)
- {
- return jniRegisterNativeMethods(env, "com/android/server/SystemServer",
- gMethods, NELEM(gMethods));
- }
- };
JNI层函数android_server_SystemServer_init1调用了本地函数system_init():
- extern "C" status_t system_init()
- {
- LOGI("Entered system_init()");
- sp<ProcessState> proc(ProcessState::self());
- sp<IServiceManager> sm = defaultServiceManager();
- LOGI("ServiceManager: %p\n", sm.get());
- sp<GrimReaper> grim = new GrimReaper();
- sm->asBinder()->linkToDeath(grim, grim.get(), 0);
- char propBuf[PROPERTY_VALUE_MAX];
- property_get("system_init.startsurfaceflinger", propBuf, "1");
- if (strcmp(propBuf, "1") == 0) {
- // Start the SurfaceFlinger
- SurfaceFlinger::instantiate();
- }
- // Start the sensor service
- SensorService::instantiate();
- // On the simulator, audioflinger et al don't get started the
- // same way as on the device, and we need to start them here
- if (!proc->supportsProcesses()) {
- // Start the AudioFlinger
- AudioFlinger::instantiate();
- // Start the media playback service
- MediaPlayerService::instantiate();
- // Start the camera service
- CameraService::instantiate();
- // Start the audio policy service
- AudioPolicyService::instantiate();
- }
- // And now start the Android runtime. We have to do this bit
- // of nastiness because the Android runtime initialization requires
- // some of the core system services to already be started.
- // All other servers should just start the Android runtime at
- // the beginning of their processes's main(), before calling
- // the init function.
- LOGI("System server: starting Android runtime.\n");
- AndroidRuntime* runtime = AndroidRuntime::getRuntime();
- LOGI("System server: starting Android services.\n");
- runtime->callStatic("com/android/server/SystemServer", "init2");
- // If running in our own process, just go into the thread
- // pool. Otherwise, call the initialization finished
- // func to let this process continue its initilization.
- if (proc->supportsProcesses()) {
- LOGI("System server: entering thread pool.\n");
- ProcessState::self()->startThreadPool();
- IPCThreadState::self()->joinThreadPool();
- LOGI("System server: exiting thread pool.\n");
- }
- return NO_ERROR;
- }
以上是整个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函数
- typedef struct {
- const char* name; //java 中native函数的名字
- const char* signature; //函数签名,是参数类型和返回值类型组合的字符串
- void* fnPtr; //JNI层的函数指针
- } JNINativeMethod;
如上:
- static JNINativeMethod gMethods[] = {
- /* name, signature, funcPtr */
- { "init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1 },
- };
当Java层通过System.loadLibrary加载完JNI动态库后,会查找该库中的一个叫JNI_OnLoad的函数,如果有,就调用它,JNI函数的动态注册就在这里完成:
- extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
- {
- JNIEnv* env = NULL;
- jint result = -1;
- if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
- LOGE("GetEnv failed!");
- return result;
- }
- LOG_ASSERT(env, "Could not retrieve the env!");
- register_android_server_PowerManagerService(env);
- register_android_server_InputManager(env);
- register_android_server_LightsService(env);
- register_android_server_AlarmManagerService(env);
- register_android_server_BatteryService(env);
- register_android_server_UsbService(env);
- register_android_server_VibratorService(env);
- register_android_server_SystemServer(env);
- register_android_server_location_GpsLocationProvider(env);
- return JNI_VERSION_1_4;
- }
- int register_android_server_SystemServer(JNIEnv* env)
- {
- return jniRegisterNativeMethods(env, "com/android/server/SystemServer",gMethods, NELEM(gMethods));//调用jniRegisterNativeMethods完成注册
- }
- int jniRegisterNativeMethods(JNIEnv* env, const char* className,const JNINativeMethod* gMethods, int numMethods)
- {
- jclass clazz;
- LOGV("Registering %s natives\n", className);
- clazz = (*env)->FindClass(env, className);
- if (clazz == NULL) {
- LOGE("Native registration unable to find class '%s'\n", className);
- return -1;
- }
- int result = 0;
- if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {
- LOGE("RegisterNatives failed for '%s'\n", className);
- result = -1;
- }
- (*env)->DeleteLocalRef(env, clazz);
- return result;
- }
- static jint RegisterNatives(JNIEnv* env, jclass jclazz,const JNINativeMethod* methods, jint nMethods)
- {
- JNI_ENTER();
- ClassObject* clazz = (ClassObject*) dvmDecodeIndirectRef(env, jclazz);
- jint retval = JNI_OK;
- int i;
- if (gDvm.verboseJni) {
- LOGI("[Registering JNI native methods for class %s]\n",
- clazz->descriptor);
- }
- for (i = 0; i < nMethods; i++) {
- if (!dvmRegisterJNIMethod(clazz, methods[i].name,
- methods[i].signature, methods[i].fnPtr))
- {
- retval = JNI_ERR;
- }
- }
- JNI_EXIT();
- return retval;
- }
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 |
- //查找java类
- static jclass FindClass(JNIEnv* env, const char* name)
- //获取成员变量
- static jfieldID GetFieldID(JNIEnv* env, jclass jclazz,const char* name, const char* sig)
- //获取静态类变量
- static jfieldID GetStaticFieldID(JNIEnv* env, jclass jclazz,const char* name, const char* sig)
- //获取成员方法
- static jmethodID GetMethodID(JNIEnv* env, jclass jclazz, const char* name,const char* sig)
- //获取静态类方法
- static jmethodID GetStaticMethodID(JNIEnv* env, jclass jclazz,const char* name, const char* sig)
JNI方法签名:
- { "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层抛出异常