zoukankan      html  css  js  c++  java
  • android-jni与java参数传递


    http://blog.csdn.net/andyhuabing/article/details/7551230


    android-jni与java参数传递

    ===================================================================================================
    问题的来源:
    jni与java层之间互传参数,有几个问题需要解决:
    1、需要传递的参数的函数非常多,达到100个左右
    2、传递的参数有些比较复杂,涉及到结构的嵌套
    3、参数有输入参数与输出参数两种

    举函数例子如下:
    /*-- 授权信息 --*/
    typedef struct {
        int  m_dwProductID;   /* 普通授权的节目ID */    
        int  m_tBeginDate;    /* 授权的起始时间 */
        int  m_tExpireDate;   /* 授权的过期时间 */
        char m_bCanTape;      /* 用户是否购买录像:1-可以录像;0-不可以录像 */
        char m_byReserved[3]; /* 保留 */
    }CAEntitle;


    结构嵌套结构,比较复杂
    /*-- 授权信息集合 --*/
    typedef struct {
        int        m_wProductCount;
        char       m_m_byReserved[2];    /* 保留 */
        CAEntitle  m_Entitles[300];      /* 授权列表 */
    }SCDCAEntitles;


    前面两个是输入参数,后面两个是输出参数
    extern boolean STBCA_SCPBRun( const char* pbyCommand, 
     int       wCommandLen,  
     char*     pbyReply,  
     int*      pwReplyLen  );


    问题解决方案1:
    常用方案,
    A、C++调用传递参数给java层
       调用成员函数利用CallxxxMethodYYY(其中xxx表示返回数据类型,YYY表代码V/A)
       其参数可以直接利用函数传,也可采用GetFieldID&SetObjectField配对使用
       即如下方案:
    struct CATestOffsets
    {
       jfieldID    name;
       jfieldID    vendor;
       jfieldID    version;
       jfieldID    handle;
       jfieldID    m_tBeginDate;
       jfieldID    m_tExpireDate;
       ....
       
       jmethodID  STBCA_SCPBRunCallXX;
       jmethodID  ....
    } gSensorOffsets;   
      利用jfieldID和jmethodID表示java类的成员变量及成员函数。。。。工作量相当大,调试也很麻烦
      
    B、JAVA调用C++代码
    通过做法就是定义一堆的native函数,然后将参数传递一一定义传递下来
    对于结构在java层定义类,在jni层进行转换,首先可能传递的参数很多,而且每个函数都要小心写,
    对于需要既需要输入参数又需要输出参数的,很麻烦哟。。非常痛苦。

    这种方案做了两天,实在受不了,太多native函数,大多jmethodID与jfieldID,而且同时输入及输出。

    确认让人很头痛噻!


    问题解决方案2:
    重点就是利用C++层分配共享内存空间,函数参数非常简单,只需要返回值,所有参数传递利用共享内存搞定


    这利方式对于参数的传递非常方便,只是需要注意地址及偏移值(addr:offset),代码比较清晰。
    但对于native函数及jmethodID与jfieldID的处理还是很麻烦呀!不对对于参数处理简化了很多了。


    基本代码如下,我这里搞了个最复杂的传递结构参数举例:



    Java 代码编写如下

    1. <span style="font-size:16px;">  /** 
    2.      * 按长度进行缓冲区分配空间 
    3.      * @param length: buffer length  
    4.      * @return start address 
    5.      */  
    6.     public int AllocStructMem(int length){  
    7.         if (length % 4 != 0) {  
    8.             length -= (length % 4);  
    9.             length += 4;  
    10.         }  
    11.         if ((address = native_alloc(length)) == 0)  
    12.             throw new RuntimeException();  
    13.           
    14.         return address;  
    15.     }     
    16.       
    17.     /** 
    18.      * 释放缓冲区空间 
    19.      * @param ptr:start address 
    20.      */  
    21.     public void FreeStructMem(int ptr){  
    22.         if(ptr == 0x00){  
    23.             throw new NullPointerException("NULL pointer");  
    24.         }  
    25.           
    26.         native_free(ptr);  
    27.     }  
    28.       
    29.     public int DSSetInt(int ptr,int offset,int value) {  
    30.         if(ptr == 0x00){  
    31.             throw new NullPointerException("NULL pointer");  
    32.         }  
    33.           
    34.         return native_setInt(ptr,offset,4,value);  
    35.     }  
    36.       
    37.     public int DSSetBytes(int addr,int off,int len,byte[] b){  
    38.         return native_setBytes(addr,off, len, b);  
    39.     }  
    40.   
    41.     public void DSSetUTFString(int addr,int off, int len, String s) {  
    42.         DSSetBytes(addr,off, len, s.getBytes());  
    43.     }  
    44.       
    45.     public int DSGetInt(int addr,int off, int len) {  
    46.         if(off < 0 || len <= 0 || addr == 0x00 )  
    47.             throw new IllegalArgumentException();  
    48.           
    49.         return native_getInt(addr, off, len);  
    50.     }  
    51.   
    52.     public int DSGetBytes(int addr,int off, int len, byte[] b) {  
    53.         if (off < 0 || len <= 0 || addr == 0x00 ||b == null || b.length < len)  
    54.             throw new IllegalArgumentException();  
    55.           
    56.         return native_getBytes(addr, off, len, b);  
    57.     }  
    58.   
    59.     public String DSGetUTFString(int addr,int off, int len) {  
    60.         if (off < 0 || len <= 0 )  
    61.             throw new IllegalArgumentException();  
    62.           
    63.         byte[] b = new byte[len];  
    64.         native_getBytes(addr, off, len, b);  
    65.         return new String(b);  
    66.     }     
    67.       
    68.     private static native int native_alloc(int length);  
    69.     private static native void native_free(int ptr);  
    70.     private static native int native_setInt(int addr, int offset, int len,  
    71.             int value);  
    72.     private static native int native_setBytes(int addr, int offset, int len,  
    73.             byte[] b);  
    74.     private static native int native_getInt(int addr, int offset, int len);  
    75.     private static native int native_getBytes(int addr, int offset, int len,  
    76.             byte[] b);</span>  


    下面是测试代码:

    1. <span style="font-size:16px;">  // C++ 定义结构  
    2.     //  struct mmm_t {  
    3.     //      int a;  
    4.     //      int b[4];  
    5.     //      struct {  
    6.     //          int c1, c2;  
    7.     //      } c;  
    8.     //      struct {  
    9.     //          int d1;  
    10.     //          char*d2;  
    11.     //      } d[2];  
    12.     //      float e;  
    13.     //  };  
    14.       
    15.     static class cc{  
    16.         int c1;  
    17.         int c2;  
    18.     }  
    19.       
    20.     static class dd{  
    21.         int d1;  
    22.         byte[] d2 = new byte[64];  
    23.     };  
    24.       
    25.     static class mmm_t{  
    26.         int a;  
    27.         int[] b = new int[4];  
    28.         cc c[] = new cc[1];  
    29.         dd d[] = new dd[2];  
    30.         int e;  
    31.         dd darr[] = new dd[10];  
    32.   
    33.         public void mmm_malloc(){  
    34.             c[0] = new cc();  
    35.             for(int i=0;i<2;i++){  
    36.                 d[i] = new dd();  
    37.             }  
    38.             for(int i=0; i < 10; i++){  
    39.                 darr[i] = new dd();  
    40.             }  
    41.         }  
    42.     }  
    43.       
    44.     public int complexStructTest(){  
    45.         mmm_t m = new mmm_t();   
    46.           
    47.         m.mmm_malloc();  
    48.           
    49.         Log.i(TAG,"complexStructTest is test.....");  
    50.           
    51.         /* 赋值 */  
    52.         m.a = 10;  
    53.           
    54.         Log.i(TAG,"complexStructTest 000");  
    55.           
    56.         m.b[0] = 0x22352352;  
    57.         m.b[1] = 0x31212362;  
    58.         m.b[2] = 0x31343521;  
    59.         m.b[3] = 0x33299552;  
    60.           
    61.         Log.i(TAG,"complexStructTest 111");  
    62.         m.c[0].c1 = 0x2352539;  
    63.         Log.i(TAG,"complexStructTest 222");  
    64.         m.c[0].c2 = 0x9235265;  
    65.           
    66.         Log.i(TAG,"complexStructTest 333");  
    67.           
    68.         m.d[0].d1 = 0x983652;  
    69.         String s = "ksdf2035k8";  
    70.         Log.i(TAG,"length111:" + s.length());  
    71.         m.d[0].d2 = s.getBytes();  
    72.           
    73.         m.d[1].d1 = 0x983652;  
    74.         String s1 = "ksdf2035k8";  
    75.         Log.i(TAG,"length222:" + s1.length());  
    76.         m.d[1].d2 = s1.getBytes();  
    77.   
    78.         Log.i(TAG,"complexStructTest 444");  
    79.           
    80.         m.e = 0x8923572;  
    81.           
    82.         Log.i(TAG,"complexStructTest 555");  
    83.           
    84.         /* 设定值到jni层 */  
    85.         int size = 0;  
    86.         size += 4 + 4*4;  
    87.         size += 4*2;  
    88.         size += 2 * (4+64);  
    89.         size += 4 ;  
    90.         Log.i("size","size=" + size);  
    91.           
    92.         int ptr = AllocStructMem(size);  
    93.         Log.i(TAG,"alloc memory address=" + ptr);  
    94.         if(ptr !=0){              
    95.             DSSetInt(ptr,0,m.a);  
    96.               
    97.             DSSetInt(ptr,1,m.b[0]);  
    98.             DSSetInt(ptr,2,m.b[1]);  
    99.             DSSetInt(ptr,3,m.b[2]);  
    100.             DSSetInt(ptr,4,m.b[3]);  
    101.               
    102.             DSSetInt(ptr,5,m.c[0].c1);  
    103.             DSSetInt(ptr,6,m.c[0].c1);  
    104.               
    105.             DSSetInt(ptr,7,m.d[0].d1);  
    106.             DSSetBytes(ptr,8,s.length(),s.getBytes());  
    107.               
    108.             Log.e(TAG,"complexStructTest aaaa");  
    109.             DSSetInt(ptr,12,m.d[1].d1);  
    110.             Log.e(TAG,"complexStructTest bbbb");  
    111.             DSSetBytes(ptr,13,s1.length(),s1.getBytes());  
    112.             Log.e(TAG,"complexStructTest cccc");  
    113.               
    114.             DSSetInt(ptr,17,m.e);  
    115.         }  
    116.           
    117.         if(ptr != 0){  
    118.             FreeStructMem(ptr);  
    119.             ptr = 0;  
    120.         }  
    121.           
    122.         return 0;  
    123.     }</span>  

    下面贴下jni实现代码:
    1. <span style="font-size:16px;">static jint native_setInt(JNIEnv *e, jclass cls, jint addr,jint off,jint len,jint value) {  
    2.     int *ptr = (int*)addr;  
    3.     if(ptr == NULL){  
    4.         LOGE("setInt illegal memory address");  
    5.         return -1;  
    6.     }  
    7.   
    8.     assert( len == 4);  
    9.   
    10.     LOGI("ptr=0x%x,offset=%d native_setInt value = %d",ptr,off,value);  
    11.       
    12.     (*(int*)(ptr + off)) = value;  
    13.     return 0;  
    14. }  
    15.   
    16. static jint native_setBytes(JNIEnv *e, jclass cls, jint addr, jint off, jint len, jbyteArray byteValues) {  
    17.     jbyte *ptr = (jbyte*)addr;  
    18.       
    19.     e->GetByteArrayRegion(byteValues,0,len,ptr+off*4);  
    20.     if(buf == NULL){  
    21.         LOGE("setBytes illegal memory address");  
    22.         return -1;  
    23.     }  
    24.   
    25.     return 0;  
    26. }  
    27.   
    28. static jint native_getInt(JNIEnv *e, jclass cls, jint addr, jint off, jint len) {  
    29.     int value = 0x00;  
    30.     int *ptr = (int*)addr;  
    31.   
    32.     if(ptr == NULL){  
    33.         LOGE("getInt illegal memory address");  
    34.         return -1;  
    35.     }  
    36.   
    37.     assert(len == 4);  
    38.   
    39.     value = *((int*)(ptr + off));  
    40.   
    41.     LOGI("ptr=0x%x,offset=%d native_getInt value = %d",ptr,off,value);  
    42.   
    43.     return value;  
    44. }  
    45.   
    46. static jint native_getBytes(JNIEnv *e, jclass cls, jint addr, jint off, jint len, jbyteArray byteValues) {  
    47.     jbyte *ptr = (jbyte*)addr;  
    48.   
    49.     if(ptr == NULL){  
    50.         LOGE("getBytes illegal memory address");  
    51.         return -1;  
    52.     }  
    53.   
    54.     e->SetByteArrayRegion(byteValues,0,len,ptr+off*4);  
    55.     return 0;  
    56. }  
    57.   
    58. static jint native_alloc(JNIEnv *e, jobject thiz, jint len) {  
    59.     void *ptr = (void*)calloc(1,len);  
    60.     if(ptr == NULL){  
    61.         LOGE("alloc buffer out of memory(size=0x%x)",len);  
    62.         return -1;  
    63.     }  
    64.     return (jint)ptr;  
    65. }  
    66.   
    67. static void native_free(JNIEnv *e, jobject thiz, jint ptr) {  
    68.     if(ptr != NULL){  
    69.         free((void*)ptr);  
    70.         ptr = NULL;  
    71.     }  
    72.     return ;  
    73. }</span>  

    嘿嘿,还是够复杂噻,不过比第一个方案前进了一大步。还有没有更好的办法呢?
    请听下会分解。。。哈哈哈!!!

  • 相关阅读:
    科大奥瑞大物实验-A类不确定度计算器 代码
    在手机和电脑间双向加密传输文件 —— Windows 安装 Kde Connect
    Leetcode 寻找两个有序数组的中位数
    树莓派3B安装 Arch Linux ARM
    从零开始编译安装 Extcalc
    Oracle, PostgreSQl, MySQL针对INSERT时可能唯一键重复的SQL
    如何从Oracle, MySql, PostgreSQL的PreparedStatement获得所执行的sql语句?
    PostgreSQL报错:当前事务被终止,命令被忽略,直到事务块结束
    PostgreSQL对GROUP BY子句使用常量的特殊限制
    一种用JDBC实现批量查询的巧妙方法
  • 原文地址:https://www.cnblogs.com/ztguang/p/12645403.html
Copyright © 2011-2022 走看看