Android JNI技术介绍【转】

本文转载自:http://blog.csdn.net/yangwen123/article/details/8085833

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.codeframeworksaseservicesjnicom_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.     LOGI("Entered system_init()");  
  4.       
  5.     sp<ProcessState> proc(ProcessState::self());  
  6.       
  7.     sp<IServiceManager> sm = defaultServiceManager();  
  8.     LOGI("ServiceManager: %p ", sm.get());  
  9.       
  10.     sp<GrimReaper> grim = new GrimReaper();  
  11.     sm->asBinder()->linkToDeath(grim, grim.get(), 0);  
  12.       
  13.     char propBuf[PROPERTY_VALUE_MAX];  
  14.     property_get("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.     LOGI("System server: starting Android runtime. ");  
  47.       
  48.     AndroidRuntime* runtime = AndroidRuntime::getRuntime();  
  49.   
  50.     LOGI("System server: starting Android services. ");  
  51.     runtime->callStatic("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.         LOGI("System server: entering thread pool. ");  
  58.         ProcessState::self()->startThreadPool();  
  59.         IPCThreadState::self()->joinThreadPool();  
  60.         LOGI("System server: exiting thread pool. ");  
  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.         LOGE("GetEnv failed!");  
  8.         return result;  
  9.     }  
  10.     LOG_ASSERT(env, "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.     LOGV("Registering %s natives ", className);  
  6.     clazz = (*env)->FindClass(env, className);  
  7.     if (clazz == NULL) {  
  8.         LOGE("Native registration unable to find class '%s' ", className);  
  9.         return -1;  
  10.     }  
  11.   
  12.     int result = 0;  
  13.     if ((*env)->RegisterNatives(env, clazz, gMethods, numMethods) < 0) {  
  14.         LOGE("RegisterNatives failed for '%s' ", 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.         LOGI("[Registering JNI native methods for class %s] ",  
  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层抛出异常

原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/6807222.html