Java Char*在JNI调用中损坏

Java Char*在JNI调用中损坏,java,android,c,swig,google-glass,Java,Android,C,Swig,Google Glass,我正在使用android(特别是Google glass)上的C库(librtmp),使用SWIG创建的绑定 当我使用包含char*的结构调用一个本机方法,从该方法返回,然后调用另一个本机方法时,char*中不会包含相同的数据,很多时候数据会显示为null,但有时它会包含部分java或项目路径或随机文本(例如:glassvideostreamer/libr,Zunk+,sun/*)它有时也会包含无效的unicode代码点。 指针本身在JNI调用之间始终指向相同的内存位置,当第一个本机方法退出时指

我正在使用android(特别是Google glass)上的C库(librtmp),使用SWIG创建的绑定

当我使用包含char*的结构调用一个本机方法,从该方法返回,然后调用另一个本机方法时,char*中不会包含相同的数据,很多时候数据会显示为null,但有时它会包含部分java或项目路径或随机文本(例如:
glassvideostreamer/libr
Zunk+
sun/*
)它有时也会包含无效的unicode代码点。 指针本身在JNI调用之间始终指向相同的内存位置,当第一个本机方法退出时指针是正确的,当它进入另一个本机方法时指针已损坏

将这两个方法包装在一个本机函数中,然后调用该函数可以正常工作,但是当调用另一个本机方法时,数据将不再位于内存位置

这是我的密码:

test.i

%module test_wrapper
#define NO_CRYPTO
/* Anything in the following section is added verbatim to the .cxx wrapper file*/
%{
#include "rtmp.h"
%}
test* Alloc_Test();
void Init_Test(test* t, char* data, int len);
void Test_String(test* t);
void Init_And_Test_String(test* t, char* data, int len);
rtmp.h

  typedef struct test {
    char* data;
    int len;
  } test;
  test* Alloc_Test();
  void Init_Test(test* t, char* data, int len);
  void Test_String(test* t);
  void Init_And_Test_String(test* t, char* data, int len);
rtmp.c

test* Alloc_Test(){
  return calloc(sizeof(test));
}
void Init_Test(test* t, char* data, int len){
  t->data = data;
  t->len = len;
  __android_log_print(ANDROID_LOG_DEBUG,"TEST", "String: %.*s  (pointer: %p)", t->len, t->data, t);
}
void Test_String(test* t){
 __android_log_print(ANDROID_LOG_DEBUG,"TEST","%String: %.*s  (pointer: %p)", t->len, t->data, t);
}
void Init_And_Test_String(test* t, char* data, int len){
  Init_Test(t, data, len);
  Test_String(t);
}
SWIGEXPORT jlong JNICALL Java_atellis_glassvideostreamer_librtmp_test_1wrapperJNI_Alloc_1Test(JNIEnv *jenv, jclass jcls) {
  jlong jresult = 0 ;
  test *result = 0 ;

  (void)jenv;
  (void)jcls;
  result = (test *)Alloc_Test();
  *(test **)&jresult = result; 
  return jresult;
}


SWIGEXPORT void JNICALL Java_atellis_glassvideostreamer_librtmp_test_1wrapperJNI_Init_1Test(JNIEnv *jenv, jclass jcls, jlong jarg1, jstring jarg2, jint jarg3) {
  test *arg1 = (test *) 0 ;
  char *arg2 = (char *) 0 ;
  int arg3 ;

  (void)jenv;
  (void)jcls;
  arg1 = *(test **)&jarg1; 
  arg2 = 0;
  if (jarg2) {
    arg2 = (char *)(*jenv)->GetStringUTFChars(jenv, jarg2, 0);
    if (!arg2) return ;
  }
  arg3 = (int)jarg3; 
  Init_Test(arg1,arg2,arg3);
  if (arg2) (*jenv)->ReleaseStringUTFChars(jenv, jarg2, (const char *)arg2);
}


SWIGEXPORT void JNICALL Java_atellis_glassvideostreamer_librtmp_test_1wrapperJNI_Test_1String(JNIEnv *jenv, jclass jcls, jlong jarg1) {
  test *arg1 = (test *) 0 ;

  (void)jenv;
  (void)jcls;
  arg1 = *(test **)&jarg1; 
  Test_String(arg1);
}


SWIGEXPORT void JNICALL Java_atellis_glassvideostreamer_librtmp_test_1wrapperJNI_Init_1And_1Test_1String(JNIEnv *jenv, jclass jcls, jlong jarg1, jstring jarg2, jint jarg3) {
  test *arg1 = (test *) 0 ;
  char *arg2 = (char *) 0 ;
  int arg3 ;

  (void)jenv;
  (void)jcls;
  arg1 = *(test **)&jarg1; 
  arg2 = 0;
  if (jarg2) {
    arg2 = (char *)(*jenv)->GetStringUTFChars(jenv, jarg2, 0);
    if (!arg2) return ;
  }
  arg3 = (int)jarg3; 
  Init_And_Test_String(arg1,arg2,arg3);
  if (arg2) (*jenv)->ReleaseStringUTFChars(jenv, jarg2, (const char *)arg2);
}
最后(对于c),这里是生成的swig绑定
librtmp\u wrap.c

test* Alloc_Test(){
  return calloc(sizeof(test));
}
void Init_Test(test* t, char* data, int len){
  t->data = data;
  t->len = len;
  __android_log_print(ANDROID_LOG_DEBUG,"TEST", "String: %.*s  (pointer: %p)", t->len, t->data, t);
}
void Test_String(test* t){
 __android_log_print(ANDROID_LOG_DEBUG,"TEST","%String: %.*s  (pointer: %p)", t->len, t->data, t);
}
void Init_And_Test_String(test* t, char* data, int len){
  Init_Test(t, data, len);
  Test_String(t);
}
SWIGEXPORT jlong JNICALL Java_atellis_glassvideostreamer_librtmp_test_1wrapperJNI_Alloc_1Test(JNIEnv *jenv, jclass jcls) {
  jlong jresult = 0 ;
  test *result = 0 ;

  (void)jenv;
  (void)jcls;
  result = (test *)Alloc_Test();
  *(test **)&jresult = result; 
  return jresult;
}


SWIGEXPORT void JNICALL Java_atellis_glassvideostreamer_librtmp_test_1wrapperJNI_Init_1Test(JNIEnv *jenv, jclass jcls, jlong jarg1, jstring jarg2, jint jarg3) {
  test *arg1 = (test *) 0 ;
  char *arg2 = (char *) 0 ;
  int arg3 ;

  (void)jenv;
  (void)jcls;
  arg1 = *(test **)&jarg1; 
  arg2 = 0;
  if (jarg2) {
    arg2 = (char *)(*jenv)->GetStringUTFChars(jenv, jarg2, 0);
    if (!arg2) return ;
  }
  arg3 = (int)jarg3; 
  Init_Test(arg1,arg2,arg3);
  if (arg2) (*jenv)->ReleaseStringUTFChars(jenv, jarg2, (const char *)arg2);
}


SWIGEXPORT void JNICALL Java_atellis_glassvideostreamer_librtmp_test_1wrapperJNI_Test_1String(JNIEnv *jenv, jclass jcls, jlong jarg1) {
  test *arg1 = (test *) 0 ;

  (void)jenv;
  (void)jcls;
  arg1 = *(test **)&jarg1; 
  Test_String(arg1);
}


SWIGEXPORT void JNICALL Java_atellis_glassvideostreamer_librtmp_test_1wrapperJNI_Init_1And_1Test_1String(JNIEnv *jenv, jclass jcls, jlong jarg1, jstring jarg2, jint jarg3) {
  test *arg1 = (test *) 0 ;
  char *arg2 = (char *) 0 ;
  int arg3 ;

  (void)jenv;
  (void)jcls;
  arg1 = *(test **)&jarg1; 
  arg2 = 0;
  if (jarg2) {
    arg2 = (char *)(*jenv)->GetStringUTFChars(jenv, jarg2, 0);
    if (!arg2) return ;
  }
  arg3 = (int)jarg3; 
  Init_And_Test_String(arg1,arg2,arg3);
  if (arg2) (*jenv)->ReleaseStringUTFChars(jenv, jarg2, (const char *)arg2);
}
在java方面:我们只需要生成SWIGTYPE_p测试,它封装了结构指针和调用JNI函数的代码:
test\u wrapperJNI.java

public class test_wrapperJNI {
  public final static native long Alloc_Test();
  public final static native void Init_Test(long jarg1, String jarg2, int jarg3);
  public final static native void Test_String(long jarg1);
  public final static native void Init_And_Test_String(long jarg1, String jarg2, int jarg3);
}
public class test_wrapper {
  public static SWIGTYPE_p_test Alloc_Test() {
    long cPtr = test_wrapperJNI.Alloc_Test();
    return (cPtr == 0) ? null : new SWIGTYPE_p_test(cPtr, false);
  }

  public static void Init_Test(SWIGTYPE_p_test t, String data, int len) {
    test_wrapperJNI.Init_Test(SWIGTYPE_p_test.getCPtr(t), data, len);
  }

  public static void Test_String(SWIGTYPE_p_test t) {
    test_wrapperJNI.Test_String(SWIGTYPE_p_test.getCPtr(t));
  }

  public static void Init_And_Test_String(SWIGTYPE_p_test t, String data, int len) {
    test_wrapperJNI.Init_And_Test_String(SWIGTYPE_p_test.getCPtr(t), data, len);
  }

}
test_wrapper.java

public class test_wrapperJNI {
  public final static native long Alloc_Test();
  public final static native void Init_Test(long jarg1, String jarg2, int jarg3);
  public final static native void Test_String(long jarg1);
  public final static native void Init_And_Test_String(long jarg1, String jarg2, int jarg3);
}
public class test_wrapper {
  public static SWIGTYPE_p_test Alloc_Test() {
    long cPtr = test_wrapperJNI.Alloc_Test();
    return (cPtr == 0) ? null : new SWIGTYPE_p_test(cPtr, false);
  }

  public static void Init_Test(SWIGTYPE_p_test t, String data, int len) {
    test_wrapperJNI.Init_Test(SWIGTYPE_p_test.getCPtr(t), data, len);
  }

  public static void Test_String(SWIGTYPE_p_test t) {
    test_wrapperJNI.Test_String(SWIGTYPE_p_test.getCPtr(t));
  }

  public static void Init_And_Test_String(SWIGTYPE_p_test t, String data, int len) {
    test_wrapperJNI.Init_And_Test_String(SWIGTYPE_p_test.getCPtr(t), data, len);
  }

}
把所有这些放在一起,你会得到:

System.loadLibrary("TEST");
SWIGTYPE_p_test test = test_wrapper.Alloc_Test();
test_wrapper.Init_Test(test, "Will this string stay the same?", 31);
test_wrapper.Test_String(test);

test = test_wrapper.Alloc_Test();
test_wrapper.Init_And_Test_String(test, "This string will stay the same", 30);
获取此结果(在logcat中):

在这种情况下,字符串变为空白!正如我上面提到的,它有时会包含文件路径或随机文本

typedef struct test {
    char* data;
    int len;
} test;
这不指定任何空间来实际存储字符串
数据
,而只指定一个指针来保存其地址

实际上,您似乎将它指向可能是临时保留的各种函数参数的内存,而这将不起作用,因为该内存稍后可以重新使用

void Init_Test(test* t, char* data, int len){
    t->data = data;
事实上,您明确地释放了对该内存的声明:

Init_And_Test_String(arg1,arg2,arg3); 
if (arg2) (*jenv)->ReleaseStringUTFChars(jenv, jarg2, (const char *)arg2);
您必须显式保留内存来保存字符串,并从任何临时存储复制到该字符串