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层抛出异常

更多相关文章

  1. 解读Android虚拟机工作原理
  2. Android(安卓)Jetpack 最佳开发姿势
  3. Android手动绘制ninepath(.9.png)图片
  4. Android(安卓)setContentView方法解析(二)
  5. camera的startpreview流程
  6. 【Android】理解Service和BroadcastReceiver
  7. Android应用程序的startActivity过程
  8. Android地图尝试之两行代码调用高德地图来完成位置展示
  9. 现在跨平台开发(手机平台,主要是Android、iOS以及WP)工具或者技术都

随机推荐

  1. Android(安卓)Bluetooth蓝牙开发\蓝牙协
  2. android上使用XML
  3. Android内核开发:图解Android系统的启动过
  4. Android防止内存溢出浅析
  5. Android(安卓)Provision (Setup Wizard)
  6. Android的Window类
  7. FFmpeg在Android上的移植优化步骤
  8. android与C++的选择
  9. 《Android取证实战:调查、分析与移动安全
  10. android 中Message、Handler、Message Qu