JNI是java Native Interface 的缩写,通过JNI,java函数可以调用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层抛出异常