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 代码编写如下
- <span style="font-size:16px;"> /**
- * 按长度进行缓冲区分配空间
- * @param length: buffer length
- * @return start address
- */
- public int AllocStructMem(int length){
- if (length % 4 != 0) {
- length -= (length % 4);
- length += 4;
- }
- if ((address = native_alloc(length)) == 0)
- throw new RuntimeException();
- return address;
- }
- /**
- * 释放缓冲区空间
- * @param ptr:start address
- */
- public void FreeStructMem(int ptr){
- if(ptr == 0x00){
- throw new NullPointerException("NULL pointer");
- }
- native_free(ptr);
- }
- public int DSSetInt(int ptr,int offset,int value) {
- if(ptr == 0x00){
- throw new NullPointerException("NULL pointer");
- }
- return native_setInt(ptr,offset,4,value);
- }
- public int DSSetBytes(int addr,int off,int len,byte[] b){
- return native_setBytes(addr,off, len, b);
- }
- public void DSSetUTFString(int addr,int off, int len, String s) {
- DSSetBytes(addr,off, len, s.getBytes());
- }
- public int DSGetInt(int addr,int off, int len) {
- if(off < 0 || len <= 0 || addr == 0x00 )
- throw new IllegalArgumentException();
- return native_getInt(addr, off, len);
- }
- public int DSGetBytes(int addr,int off, int len, byte[] b) {
- if (off < 0 || len <= 0 || addr == 0x00 ||b == null || b.length < len)
- throw new IllegalArgumentException();
- return native_getBytes(addr, off, len, b);
- }
- public String DSGetUTFString(int addr,int off, int len) {
- if (off < 0 || len <= 0 )
- throw new IllegalArgumentException();
- byte[] b = new byte[len];
- native_getBytes(addr, off, len, b);
- return new String(b);
- }
- private static native int native_alloc(int length);
- private static native void native_free(int ptr);
- private static native int native_setInt(int addr, int offset, int len,
- int value);
- private static native int native_setBytes(int addr, int offset, int len,
- byte[] b);
- private static native int native_getInt(int addr, int offset, int len);
- private static native int native_getBytes(int addr, int offset, int len,
- byte[] b);</span>
下面是测试代码:
- <span style="font-size:16px;"> // C++ 定义结构
- // struct mmm_t {
- // int a;
- // int b[4];
- // struct {
- // int c1, c2;
- // } c;
- // struct {
- // int d1;
- // char*d2;
- // } d[2];
- // float e;
- // };
- static class cc{
- int c1;
- int c2;
- }
- static class dd{
- int d1;
- byte[] d2 = new byte[64];
- };
- static class mmm_t{
- int a;
- int[] b = new int[4];
- cc c[] = new cc[1];
- dd d[] = new dd[2];
- int e;
- dd darr[] = new dd[10];
- public void mmm_malloc(){
- c[0] = new cc();
- for(int i=0;i<2;i++){
- d[i] = new dd();
- }
- for(int i=0; i < 10; i++){
- darr[i] = new dd();
- }
- }
- }
- public int complexStructTest(){
- mmm_t m = new mmm_t();
- m.mmm_malloc();
- Log.i(TAG,"complexStructTest is test.....");
- /* 赋值 */
- m.a = 10;
- Log.i(TAG,"complexStructTest 000");
- m.b[0] = 0x22352352;
- m.b[1] = 0x31212362;
- m.b[2] = 0x31343521;
- m.b[3] = 0x33299552;
- Log.i(TAG,"complexStructTest 111");
- m.c[0].c1 = 0x2352539;
- Log.i(TAG,"complexStructTest 222");
- m.c[0].c2 = 0x9235265;
- Log.i(TAG,"complexStructTest 333");
- m.d[0].d1 = 0x983652;
- String s = "ksdf2035k8";
- Log.i(TAG,"length111:" + s.length());
- m.d[0].d2 = s.getBytes();
- m.d[1].d1 = 0x983652;
- String s1 = "ksdf2035k8";
- Log.i(TAG,"length222:" + s1.length());
- m.d[1].d2 = s1.getBytes();
- Log.i(TAG,"complexStructTest 444");
- m.e = 0x8923572;
- Log.i(TAG,"complexStructTest 555");
- /* 设定值到jni层 */
- int size = 0;
- size += 4 + 4*4;
- size += 4*2;
- size += 2 * (4+64);
- size += 4 ;
- Log.i("size","size=" + size);
- int ptr = AllocStructMem(size);
- Log.i(TAG,"alloc memory address=" + ptr);
- if(ptr !=0){
- DSSetInt(ptr,0,m.a);
- DSSetInt(ptr,1,m.b[0]);
- DSSetInt(ptr,2,m.b[1]);
- DSSetInt(ptr,3,m.b[2]);
- DSSetInt(ptr,4,m.b[3]);
- DSSetInt(ptr,5,m.c[0].c1);
- DSSetInt(ptr,6,m.c[0].c1);
- DSSetInt(ptr,7,m.d[0].d1);
- DSSetBytes(ptr,8,s.length(),s.getBytes());
- Log.e(TAG,"complexStructTest aaaa");
- DSSetInt(ptr,12,m.d[1].d1);
- Log.e(TAG,"complexStructTest bbbb");
- DSSetBytes(ptr,13,s1.length(),s1.getBytes());
- Log.e(TAG,"complexStructTest cccc");
- DSSetInt(ptr,17,m.e);
- }
- if(ptr != 0){
- FreeStructMem(ptr);
- ptr = 0;
- }
- return 0;
- }</span>
下面贴下jni实现代码:
- <span style="font-size:16px;">static jint native_setInt(JNIEnv *e, jclass cls, jint addr,jint off,jint len,jint value) {
- int *ptr = (int*)addr;
- if(ptr == NULL){
- LOGE("setInt illegal memory address");
- return -1;
- }
- assert( len == 4);
- LOGI("ptr=0x%x,offset=%d native_setInt value = %d",ptr,off,value);
- (*(int*)(ptr + off)) = value;
- return 0;
- }
- static jint native_setBytes(JNIEnv *e, jclass cls, jint addr, jint off, jint len, jbyteArray byteValues) {
- jbyte *ptr = (jbyte*)addr;
- e->GetByteArrayRegion(byteValues,0,len,ptr+off*4);
- if(buf == NULL){
- LOGE("setBytes illegal memory address");
- return -1;
- }
- return 0;
- }
- static jint native_getInt(JNIEnv *e, jclass cls, jint addr, jint off, jint len) {
- int value = 0x00;
- int *ptr = (int*)addr;
- if(ptr == NULL){
- LOGE("getInt illegal memory address");
- return -1;
- }
- assert(len == 4);
- value = *((int*)(ptr + off));
- LOGI("ptr=0x%x,offset=%d native_getInt value = %d",ptr,off,value);
- return value;
- }
- static jint native_getBytes(JNIEnv *e, jclass cls, jint addr, jint off, jint len, jbyteArray byteValues) {
- jbyte *ptr = (jbyte*)addr;
- if(ptr == NULL){
- LOGE("getBytes illegal memory address");
- return -1;
- }
- e->SetByteArrayRegion(byteValues,0,len,ptr+off*4);
- return 0;
- }
- static jint native_alloc(JNIEnv *e, jobject thiz, jint len) {
- void *ptr = (void*)calloc(1,len);
- if(ptr == NULL){
- LOGE("alloc buffer out of memory(size=0x%x)",len);
- return -1;
- }
- return (jint)ptr;
- }
- static void native_free(JNIEnv *e, jobject thiz, jint ptr) {
- if(ptr != NULL){
- free((void*)ptr);
- ptr = NULL;
- }
- return ;
- }</span>
嘿嘿,还是够复杂噻,不过比第一个方案前进了一大步。还有没有更好的办法呢?
请听下会分解。。。哈哈哈!!!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通