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 |
JNIEnv 提供了一些JNI系统函数,是一个与线程相关的变量。在JNI中,用jfieldID和jmethodID来表示Java类的成员变量和成员函数,通过以下方法来获取成员变量和成员函数:
//查找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层抛出异常