android-jni与java参数传递

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 代码编写如下

	/**
	 * 按长度进行缓冲区分配空间
	 * @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);


下面是测试代码:

	// 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;
	}

下面贴下jni实现代码:

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 ;
}

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

你可能感兴趣的:(java,String,struct,jni,null,byte)