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

  • 相关阅读:
    (2.3)备份与还原--事务的运行模式与处理机制
    (2.2)备份与还原--备份类型与恢复模式、备份介质
    (2.1)备份与还原--sql server文件的概念及操作
    (1.3.3)权限控制
    (1.3.2)登录验证(加密连接与登录验证)
    (1.3.1)连接安全(连接实例与网络协议及TDS端点)
    static class
    cnblog
    microsoft
    C# socket android
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/6807222.html
Copyright © 2020-2023  润新知