zoukankan      html  css  js  c++  java
  • Android JNI 学习(四):接口方法表 & Base Api & Exception Api

    本文我们来总结一下JNI 提供的功能列表及相关的函数表。

    注意:请注意使用术语“必须”来描述对JNI程序员的限制。例如,当您看到某个JNI函数必须接收非NULL对象时,您有责任确保不将NULL传递给该JNI函数。因此,JNI实现不需要在该JNI函数中执行NULL指针检查。

    一、接口方法表

    可以通过JNIEnv参数以固定偏移量访问每个函数JNIEnv类型是一个指向存储所有JNI函数指针的结构。它的定义如下:

    typedef const struct JNINativeInterface * JNIEnv;

    VM初始化功能表,如下面的代码所示 请注意,前三个条目是保留用于将来与COM的兼容性的。此外,我们NULL在函数表的开头附近保留了许多附加条目,因此,例如,可以在FindClass之后而不是在表的末尾添加与类相关的未来JNI操作。

    const struct JNINativeInterface ... = {
    
        NULL,
        NULL,
        NULL,
        NULL,
        GetVersion,
    
        DefineClass,
        FindClass,
    
        FromReflectedMethod,
        FromReflectedField,
        ToReflectedMethod,
    
        GetSuperclass,
        IsAssignableFrom,
    
        ToReflectedField,
    
        Throw,
        ThrowNew,
        ExceptionOccurred,
        ExceptionDescribe,
        ExceptionClear,
        FatalError,
    
        PushLocalFrame,
        PopLocalFrame,
    
        NewGlobalRef,
        DeleteGlobalRef,
        DeleteLocalRef,
        IsSameObject,
        NewLocalRef,
        EnsureLocalCapacity,
    
        AllocObject,
        NewObject,
        NewObjectV,
        NewObjectA,
    
        GetObjectClass,
        IsInstanceOf,
    
        GetMethodID,
    
        CallObjectMethod,
        CallObjectMethodV,
        CallObjectMethodA,
        CallBooleanMethod,
        CallBooleanMethodV,
        CallBooleanMethodA,
        CallByteMethod,
        CallByteMethodV,
        CallByteMethodA,
        CallCharMethod,
        CallCharMethodV,
        CallCharMethodA,
        CallShortMethod,
        CallShortMethodV,
        CallShortMethodA,
        CallIntMethod,
        CallIntMethodV,
        CallIntMethodA,
        CallLongMethod,
        CallLongMethodV,
        CallLongMethodA,
        CallFloatMethod,
        CallFloatMethodV,
        CallFloatMethodA,
        CallDoubleMethod,
        CallDoubleMethodV,
        CallDoubleMethodA,
        CallVoidMethod,
        CallVoidMethodV,
        CallVoidMethodA,
    
        CallNonvirtualObjectMethod,
        CallNonvirtualObjectMethodV,
        CallNonvirtualObjectMethodA,
        CallNonvirtualBooleanMethod,
        CallNonvirtualBooleanMethodV,
        CallNonvirtualBooleanMethodA,
        CallNonvirtualByteMethod,
        CallNonvirtualByteMethodV,
        CallNonvirtualByteMethodA,
        CallNonvirtualCharMethod,
        CallNonvirtualCharMethodV,
        CallNonvirtualCharMethodA,
        CallNonvirtualShortMethod,
        CallNonvirtualShortMethodV,
        CallNonvirtualShortMethodA,
        CallNonvirtualIntMethod,
        CallNonvirtualIntMethodV,
        CallNonvirtualIntMethodA,
        CallNonvirtualLongMethod,
        CallNonvirtualLongMethodV,
        CallNonvirtualLongMethodA,
        CallNonvirtualFloatMethod,
        CallNonvirtualFloatMethodV,
        CallNonvirtualFloatMethodA,
        CallNonvirtualDoubleMethod,
        CallNonvirtualDoubleMethodV,
        CallNonvirtualDoubleMethodA,
        CallNonvirtualVoidMethod,
        CallNonvirtualVoidMethodV,
        CallNonvirtualVoidMethodA,
    
        GetFieldID,
    
        GetObjectField,
        GetBooleanField,
        GetByteField,
        GetCharField,
        GetShortField,
        GetIntField,
        GetLongField,
        GetFloatField,
        GetDoubleField,
        SetObjectField,
        SetBooleanField,
        SetByteField,
        SetCharField,
        SetShortField,
        SetIntField,
        SetLongField,
        SetFloatField,
        SetDoubleField,
    
        GetStaticMethodID,
    
        CallStaticObjectMethod,
        CallStaticObjectMethodV,
        CallStaticObjectMethodA,
        CallStaticBooleanMethod,
        CallStaticBooleanMethodV,
        CallStaticBooleanMethodA,
        CallStaticByteMethod,
        CallStaticByteMethodV,
        CallStaticByteMethodA,
        CallStaticCharMethod,
        CallStaticCharMethodV,
        CallStaticCharMethodA,
        CallStaticShortMethod,
        CallStaticShortMethodV,
        CallStaticShortMethodA,
        CallStaticIntMethod,
        CallStaticIntMethodV,
        CallStaticIntMethodA,
        CallStaticLongMethod,
        CallStaticLongMethodV,
        CallStaticLongMethodA,
        CallStaticFloatMethod,
        CallStaticFloatMethodV,
        CallStaticFloatMethodA,
        CallStaticDoubleMethod,
        CallStaticDoubleMethodV,
        CallStaticDoubleMethodA,
        CallStaticVoidMethod,
        CallStaticVoidMethodV,
        CallStaticVoidMethodA,
    
        GetStaticFieldID,
    
        GetStaticObjectField,
        GetStaticBooleanField,
        GetStaticByteField,
        GetStaticCharField,
        GetStaticShortField,
        GetStaticIntField,
        GetStaticLongField,
        GetStaticFloatField,
        GetStaticDoubleField,
    
        SetStaticObjectField,
        SetStaticBooleanField,
        SetStaticByteField,
        SetStaticCharField,
        SetStaticShortField,
        SetStaticIntField,
        SetStaticLongField,
        SetStaticFloatField,
        SetStaticDoubleField,
    
        NewString,
    
        GetStringLength,
        GetStringChars,
        ReleaseStringChars,
    
        NewStringUTF,
        GetStringUTFLength,
        GetStringUTFChars,
        ReleaseStringUTFChars,
    
        GetArrayLength,
    
        NewObjectArray,
        GetObjectArrayElement,
        SetObjectArrayElement,
    
        NewBooleanArray,
        NewByteArray,
        NewCharArray,
        NewShortArray,
        NewIntArray,
        NewLongArray,
        NewFloatArray,
        NewDoubleArray,
    
        GetBooleanArrayElements,
        GetByteArrayElements,
        GetCharArrayElements,
        GetShortArrayElements,
        GetIntArrayElements,
        GetLongArrayElements,
        GetFloatArrayElements,
        GetDoubleArrayElements,
    
        ReleaseBooleanArrayElements,
        ReleaseByteArrayElements,
        ReleaseCharArrayElements,
        ReleaseShortArrayElements,
        ReleaseIntArrayElements,
        ReleaseLongArrayElements,
        ReleaseFloatArrayElements,
        ReleaseDoubleArrayElements,
    
        GetBooleanArrayRegion,
        GetByteArrayRegion,
        GetCharArrayRegion,
        GetShortArrayRegion,
        GetIntArrayRegion,
        GetLongArrayRegion,
        GetFloatArrayRegion,
        GetDoubleArrayRegion,
        SetBooleanArrayRegion,
        SetByteArrayRegion,
        SetCharArrayRegion,
        SetShortArrayRegion,
        SetIntArrayRegion,
        SetLongArrayRegion,
        SetFloatArrayRegion,
        SetDoubleArrayRegion,
    
        RegisterNatives,
        UnregisterNatives,
    
        MonitorEnter,
        MonitorExit,
    
        GetJavaVM,
    
        GetStringRegion,
        GetStringUTFRegion,
    
        GetPrimitiveArrayCritical,
        ReleasePrimitiveArrayCritical,
    
        GetStringCritical,
        ReleaseStringCritical,
    
        NewWeakGlobalRef,
        DeleteWeakGlobalRef,
    
        ExceptionCheck,
    
        NewDirectByteBuffer,
        GetDirectBufferAddress,
        GetDirectBufferCapacity,
    
        GetObjectRefType
      };
    View Code

    请注意,函数表可以在所有JNI接口指针之间共享。

     二、JNI 接口基本方法(JNI Base Api)

    1. GetVersion (获取版本信息)

    jint GetVersion(JNIEnv *env);

    返回JNI的版本号。

    参数:

    env: jni接口指针  

    返回值:

    返回一个值,其中高位为major版本号返回,低位为minor版本号。

    在 JDK/JRE 1.1中返回 0x00010001

    在 JDK/JRE 1.2中返回 0x00010002

    在 JDK/JRE 1.4中返回 0x00010004

    在 JDK/JRE 1.6中返回 0x00010006

    常量:

    SINCE JDK/JRE 1.2:

    #define JNI_VERSION_1_1 0x00010001 
    #define JNI_VERSION_1_2 0x00010002 
    /* Error codes */ 
    #define JNI_EDETACHED (-2) /* thread detached from the VM */ 
    #define JNI_EVERSION (-3) /* JNI version error 

    SINCE JDK/JRE 1.4:

    #define JNI_VERSION_1_4 0x00010004

    SINCE JDK/JRE 1.6:

    #define JNI_VERSION_1_6 0x00010006 

    使用实例:

    jint version = env->GetVersion();  

    2. FindClass(发现Java类)

    jclass FindClass(JNIEnv *env, const char *name); 

    在JDK 1.1发行版中,这个函数加载本地定义的类(locally-defined class), 它搜索在由环境变量 CLASSPATH 目录下的子目录和zip文件中搜索指定的类名。

    从JDK 1.2发行版之后,Java安全模型允许非本地系统类也可以加载和调用本地方法。FindClass 函数会使用与当前本地方法关联的ClassLoader, 并用它来加载本地方法指定的class。如果本地方法属于系统类(system class),则没有ClassLoader会被调用。否则,将使用正确的ClassLoader来加载(load)和链接(link)指定名称的类。

    从JDK 1.2发行版之后,当通过 Invocation 接口来调用 FindClass 函数,将没有当前的本地方法或与之关联的ClassLoader。这种情况下,会使用 ClassLoader.getSystemClassLoader 来替代。这个ClassLoader 是虚拟机用来创建应用(applications)的,它有能力定位到 java.class.path 参数下的所有类。

    第二个 name 参数,使用全称类名或数组类型签名(array type signature)。例如,String类的全称类名为:

    "java/lang/String" 

    而Object数组类型的使用:

    "[Ljava/lang/Object;" 

    注意:一定要注意分隔符不是 . 而是 / ,不要写错了。

    参数:

    env:JNI接口指针 
    name:全称的类名(包名以 / 作为分隔符, 然后紧跟着类名),如果名字以 [开头(数组签名标识符),则返回一个数组的类,这个字符串也是MUTF-8。 

    返回值:

    指定名称的类的对象(a class object),或者在没有找到对应类时返回 NULL

    抛出异常:

    ClassFormatError :如果class内容不是一个有效的class文件。 

    ClassCircularityError:如果class或interface是它自己的父类或父接口,造成循环层级关系。 

    OutOfMemoryError:如果系统在载入的过程中内存不足。

    NoClassDefFoundError:如果指定的类或接口没有被找到。(当name传null或超长时也会抛出这个异常) 

    使用实例:

    // Start thread which receives commands from the SA. 
    jclass threadClass = env->FindClass("java/lang/Thread"); 
    if (threadClass == NULL) stop("Unable to find class java/lang/Thread"); 
    jstring threadName = env->NewStringUTF("Serviceability Agent Command Thread"); 
    if (threadName == NULL) stop("Unable to allocate debug thread name"); 
    jmethodID ctor = env->GetMethodID(threadClass, "<init>", "(Ljava/lang/String;)V"); 
    if (ctor == NULL) stop("Unable to find appropriate constructor for java/lang/Thread"); 
    // Allocate thread object 
    jthread thr = (jthread) env->NewObject(threadClass, ctor, threadName);  

    以上代码来之 openJDK 源码 中的 /hotspot/agent/src/share/native/jvmdi/sa.cpp

     3. GetSuperclass (获取父类)

    jclass GetSuperclass(JNIEnv *env, jclass clazz); 

    只要传入的 clazz 参数不是 java/lang/Object 则返回该类的父类。 

    如果传入的 clazz 参数是 java/lang/Object 则返回NULL,因为它没有父类。当传入的是一个接口,而不是类时,也返回 NULL 。

    参数:

    env:JNI接口指针 
    clazz: Java类对象(java class object) 

    返回值:

    返回传入的 clazz 的父类,或 NULL .

    使用实例:

    jclass clazz = env->GetObjectClass(thiz); 
    clazz = env->GetSuperclass(clazz); 
    jfieldID __state = env->GetFieldID(clazz, "__state", "J");  

    以上代码来至:https://github.com/liucheng98/mesos-0.22.0/blob/5cfd2c36c0e8361fa2e2d9b6f191a738d22a9cfd/src/java/jni/org_apache_mesos_state_LogState.cpp

    4. IsAssignableFrom (检查类是否能转型)

    jboolean IsAssignableFrom(JNIEnv *env, jclass class1, jclass clazz2); 

    检查 clazz1 的对象是否能被安全的转型(cast)为 clazz2

    参数:

    env:JNI接口指针 
    clazz1:第一个class参数(需要转型的类) 
    clazz2:第二个class参数(转型的目标类) 

    返回值:

    如果是以下情况则返回 JNI_TRUE :

    clazz1 和 clazz2 指向同一个java类 
    clazz1 是 clazz2 的子类。(向上转型是安全的) 
    clazz1 是 clazz2(接口)的实现类。(也属于向上转型) 

    使用实例:

    jclass listInterface = env->FindClass("java/util/List") 
    jclass arrayListClass = env->FindClass("java/util/ArrayList") 
    jboolean isSafe = env->IsAssignableFrom(arrayListClass, listInterface); 
    // isSafe: true; 
    isSafe = env->IsAssignableFrom(listInterface, arrayListClass); 
    // isSafe: false; 

    三、 JNI 异常方法 (JNI Exception) 

    1. Throw (抛出异常)

    jint Throw(JNIEnv *env, jthrowable obj);  

    触发一个 java.lang.Throwable 对象的异常被抛出。

    参数:

    env:JNI接口指针 
    obj: java.lang.Throwable 对象 

    返回值:

    成功则返回0, 失败时返回赋值 

    抛出异常:

    抛出 java.lang.Throwable 对象 

    使用实例:

    jthrowable exception = env->ExceptionOccurred(); 
    if (exception) { 
    env->ExceptionClear(); 
    detach_internal(env, this_obj); 
    env->Throw(exception); 
    return; 
    }  

    以上代码来至 OpenJDK 源码 /hotspot/agent/src/os/solaris/proc/saproc.cpp

    2. ThrowNew (构造一个异常对象并抛出)

    jint ThrowNew(JNIEnv *env, jclass clazz, const char *message); 

    Exception对象的构造器函数,message为异常的错误消息,clazz为异常的类。

    参数:

    env:JNI接口指针 
    clazz: java.lang.Throwable 的子类 
    message: 用于创建 java.lang.Throwable 对象时传入的错误消息。这个是字符串是MUTF-8编码。 

    返回值: 

    成功则返回0, 失败时返回赋值 

    抛出异常: 

    抛出刚构造出来的 java.lang.Throwable 对象 

    使用实例:

    env->ThrowNew(env->FindClass("sun/jvm/hotspot/debugger/DebuggerException"), errMsg); 

    3. ExceptionOccurred (检查是否有异常被抛出)

    jthrowable ExceptionOccurred(JNIEnv *env); 

    检查是否有异常被抛出。这个异常在本地方法调用 ExceptionClear() 方法或被Java代码处理这个异常之前都会保持在被抛出状态。

    参数:

    env:JNI接口指针 

    返回值:

    返回过程中抛出的异常,或没有异常被抛出时返回 NULL 。

    使用实例:

    jthrowable exception = env->ExceptionOccurred(); 
    if (exception) { 
    env->ExceptionClear(); 
    detach_internal(env, this_obj); 
    env->Throw(exception); 
    return; 
    } 

    以上代码来至 OpenJDK 源码 /hotspot/agent/src/os/solaris/proc/saproc.cpp

    4. ​ExceptionDescribe (打印异常的stack trace)

    void ExceptionDescribe(JNIEnv *env);  

    打印一个异常的stack trace到系统的错误输出,例如 stderr 这是为了调试提供便利。

    参数:

    env:JNI接口指针 

    使用实例:

    jthrowable exc = safe_ExceptionOccurred(env); 
    if (exc) { 
    env->DeleteLocalRef(exc); 
    env->ExceptionDescribe(); 
    env->ExceptionClear(); 
    }  

    以上代码来至:OpenJDK 源码中的 /jdk/src/windows/native/sun/windows/awt_Object.cpp

    5. ExceptionClear (清理所有即将抛出的异常)

    void ExceptionClear(JNIEnv *env); 

    清理任何即将抛出的异常。如果没有异常被抛出,则不起任何作用。

    参数:

    env:JNI接口指针 

    使用实例:

    jthrowable exc = safe_ExceptionOccurred(env); 
    if (exc) { 
    env->DeleteLocalRef(exc); 
    env->ExceptionDescribe(); 
    env->ExceptionClear(); 
    }  

    以上代码来至:OpenJDK 源码中的 /jdk/src/windows/native/sun/windows/awt_Object.cpp

    6. FatalError (抛出一个严重的错误)

    void FatalError(JNIEnv *env, const char *msg); 

    抛出一个严重错误,并不希望虚拟机恢复。 

    参数:

    env:JNI接口指针 
    msg : 错误消息,这个字符串为MUTF-8编码 

    使用实例:

    env->CallVoidMethod(currentThread, setThreadName, threadName) ; 
    if( env->ExceptionCheck() ) { 
    env->ExceptionDescribe() ; 
    env->FatalError("setting thread name failed: could not start reading thread"); 
    return 0L ; 
    }  

    以上代码来至:https://github.com/tnarnold/netsnmpj/blob/3153c3e9297dd7de7db9d1a65c97f77937ae147b/netsnmpj-preliminary/native/nativeThread.cc

    7. ExceptionCheck (快速检查是否有异常被抛出)

    jboolean ExceptionCheck(JNIEnv *env); 

    这是一个快速函数用于检查是否有被抛出的异常,而不创建一个这个异常的局部引用。

    参数:

    env:JNI接口指针 

    返回值: 

    有一个即将被抛出的异常时返回 JNI_TURE ,没有则返回 JNI_FALSE 

    使用实例:

    env->CallVoidMethod(thread, runId); 
    if (env->ExceptionCheck()) { 
    env->ExceptionDescribe(); 
    env->ExceptionClear(); 
    // handle exception 
    }  

    以上代码来至:OpenJDK 源码中的 /jdk/src/windows/native/sun/windows/awt_Toolkit.cpp

     

  • 相关阅读:
    VS2012开发调试PHP扩展
    Android webapi
    拖动上传文件
    IE11被识别为mozilla
    jquery validate.js 不能验证
    如何安装或卸载 Internet Explorer 9?
    C# 操作IIS -App & AppPools
    Filewatcher
    Notepad++使用技巧
    u-boot-2012.04.01移植笔记——支持NAND启动
  • 原文地址:https://www.cnblogs.com/renhui/p/9944922.html
Copyright © 2011-2022 走看看