zoukankan      html  css  js  c++  java
  • JNI,RegisterNative参数解析

    Register native method - 数据类型和method descriptor

    使用JNI时,为了使得虚拟机可以找到在C/C++ code中定义的native方法,有两种机制可以用,一种是通过为native 方法以特定格式命名来实现,另外的一种是所谓的JNI_OnLoad机制。更多信息,可参考《android app中使用JNI》。在JNI_OnLoad机制中,我们需要创建一个映射表,以描述java code中声明的native 方法,与C/C++ code中的实现函数之间的对应关系。如下面的这样:

    static JNINativeMethod gMethods[] = {
            NATIVE_METHOD(HelloJni, stringFromJNI, "()Ljava/lang/String;"),
            NATIVE_METHOD(HelloJni, stringToJNI, "(Ljava/lang/String;)Ljava/lang/String;"),
            NATIVE_METHOD(HelloJni, sumIntWithNative, "([III)I"),
            NATIVE_METHOD(HelloJni, sumDoubleWithNative, "([DII)D"),
    };

    可以看到,这个映射表是一个数组,它的数据元素类型为JNINativeMethod,这个结构的定义如下:

    typedef struct {
        const char* name;
        const char* signature;
        void*       fnPtr;
    } JNINativeMethod;

    这个结构有三个成员,name为java code中声明的方法名,fnPtr为函数指针,指向实现了java 的native方法的那个C/C++函数,signature则为方法的签名。name 和fnPtr的含义都清晰明确。而方法的签名究竟是干什么的呢?看上面的gMethods的定义,想必我们大概也可以猜个八九不离十。没错,方法的签名就是用来描述一个方法,它所接受的参数类型,及其返回值类型的。

    这个signature,又称为method descriptor。它的定义,究竟又有什么样的规则呢?JNI的Spec中对于这个问题,有如下的一段描述:

    • Method descriptors are formed by placing the field descriptors of all argument types in a pair of parentheses, and following that by the field descriptor of the return type. There are no spaces or other separator characters between the argument types. "V" is used to denote the void method return type. Constructors use "V" as their return type, and use "<init>" as their name.

    意思就是说,method descriptor由两个部分组成,一是由小括号包裹的,所有参数类型的field descriptors所组成的部分,其中的这些field descriptors对应于参数的顺序依次排列;二是紧紧跟着的返回值类型的field descriptors整个的method descriptor中都不包含空格。“V”用于表示void 方法的返回值类型。构造函数用“V”作为他们的返回值类型,并使用“<init>”作为他们的名字。而不接受任何参数的方法,其参数的field descriptors部分则为空,而只留小括号在那里。

    接下来我们可以看一下,各种数据类型,它的field descriptors都是些什么鬼东西。首先,可以先来看一下Java的原始数据类型的field descriptors


    而对于引用类型,其field descriptor则是以“L”字符开头,后面紧跟着class descriptor,并以“;”字符结尾。一个class descriptor用表示一个类或接口的名称。我们可以从一个类或接口的完全限定名中获取到这个class descriptor,方法为,将完全限定名字串中的“.”字符都用“/”字符来替换,比如java.lang.String 这个类的class descriptor就是"java/lang/String"数组当然也是引用类型。数组的field descriptor的构成则为“[”字符,后面紧跟着数组成员类型的field descriptor。比如,“int[]”的class descriptor为 "[I", “double[][][]” 的class descriptor为"[[[D"。回到field descriptor,原始数据类型的数组,它们的field descriptor不同于其他的引用类型的地方则在于,其是不需要开头的“L”及后面的“;”字符的。像下面这样:


    看一些实际code的例子。首先,是Java code中的native方法的声明:

    public native int sumIntWithNative(int[] dataElement, int start, int end);
    public native double sumDoubleWithNative (double[] dataElement, int start, int end);
    public native String  stringToJNI(String text);

    然后是native code中,我们所创建的映射表,值得我们重点关注的,是那些个方法的签名与Java code中native 方法的声明中参数及返回值类型之间的对应关系: 

    static JNINativeMethod gMethods[] = {
            NATIVE_METHOD(HelloJni, stringFromJNI, "()Ljava/lang/String;"),
            NATIVE_METHOD(HelloJni, stringToJNI, "(Ljava/lang/String;)Ljava/lang/String;"),
            NATIVE_METHOD(HelloJni, sumIntWithNative, "([III)I"),
            NATIVE_METHOD(HelloJni, sumDoubleWithNative, "([DII)D"),
    };

    在Java code中,对于那些native方法的调用:

    int[] dataElement = new int[]{2, 3, 4, 6};
    int sum = sumIntWithNative(dataElement, 0, dataElement.length);      
    double[] doubleElement = new double[]{3.4, 5.3, 7.6, 9.2};
    double doubleSum = sumDoubleWithNative(doubleElement, 0, doubleElement.length);
    stringToJNI("text");

    native code中,对于那些native方法的实现:

    static jstring HelloJni_stringToJNI( JNIEnv* env, jobject thiz, jstring text) 
    {
        JniDebug("from HelloJni_stringToJNI");
        return text;
    }
    
    
    static jint HelloJni_sumIntWithNative( JNIEnv* env, jobject thiz,
            jintArray dataElement, jint start, jint end) {
        JniDebug("from HelloJni_sumIntWithNative");
    }
    
    static jdouble HelloJni_sumDoubleWithNative( JNIEnv* env, jobject thiz,
            jdoubleArray dataElement, jint start, jint end) {
        JniDebug("from HelloJni_sumDoubleWithNative");
    }

    在native 方法的实现中,值得我们关注的是,那些参数的声明。可以看到,Java Language Type用于java code中,native方法声明时描述参数或返回值的类型;field descriptor 用于method descriptor,或称signature中,描述参数或返回值的类型;而Native Type则用于native method 声明中,描述参数或返回值的类型。上面的那段code执行的结果:


    此外,android frameworks中JNI code的一些例子,也值得我们参考,如JellyBean/frameworks/base/core/jni/android/graphics/Canvas.cpp这个文件里面的映射表:

    {"native_drawPaint","(II)V", (void*) SkCanvasGlue::drawPaint},
    {"drawPoint", "(FFLandroid/graphics/Paint;)V",(void*) SkCanvasGlue::drawPoint},
    {"drawPoints", "([FIILandroid/graphics/Paint;)V",(void*) SkCanvasGlue::drawPoints},
    {"drawLines", "([FIILandroid/graphics/Paint;)V",(void*) SkCanvasGlue::drawLines},
    {"native_drawLine","(IFFFFI)V", (void*) SkCanvasGlue::drawLine__FFFFPaint},
    {"native_drawRect","(ILandroid/graphics/RectF;I)V",(void*) SkCanvasGlue::drawRect__RectFPaint},
    {"native_drawRect","(IFFFFI)V", (void*) SkCanvasGlue::drawRect__FFFFPaint},
    {
    "native_drawOval","(ILandroid/graphics/RectF;I)V",(void*) SkCanvasGlue::drawOval}, {"native_drawCircle","(IFFFI)V", (void*) SkCanvasGlue::drawCircle},
    {
    "native_drawArc","(ILandroid/graphics/RectF;FFZI)V",(void*) SkCanvasGlue::drawArc}, {"native_drawRoundRect","(ILandroid/graphics/RectF;FFI)V",(void*) SkCanvasGlue::drawRoundRect}, {"native_drawPath","(III)V", (void*) SkCanvasGlue::drawPath}, {"native_drawBitmap","(IIFFIIII)V",(void*) SkCanvasGlue::drawBitmap__BitmapFFPaint}, {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/RectF;III)V",(void*) SkCanvasGlue::drawBitmapRF}, {"native_drawBitmap","(IILandroid/graphics/Rect;Landroid/graphics/Rect;III)V",

    这个表中,非java 语言内部类的field descriptor,如android.graphics.Paint, android.graphics.RectF等的field descriptor的写法,值得我们参考借鉴。

    【转】:https://my.oschina.net/wolfcs/blog/126474

  • 相关阅读:
    U盘启动盘的制作与U盘重装系统
    如何使用鲁大师进行驱动备份
    电子科大POJ "3*3矩阵的乘法"
    数字图像处理之sobel边缘检测
    (续)一个demo弄清楚位图在内存中的存储结构
    VC++6.0出现no compile tool is associated with the extension.解决方法
    显卡参数简单介绍
    数字图像处理之位图在计算机中的存储结构
    图像处理之边缘检测概述
    linux下mysql数据库的操作
  • 原文地址:https://www.cnblogs.com/yelao/p/9605172.html
Copyright © 2011-2022 走看看