Android ICS 4.0 NDK NewStringUTF正在崩溃App

ran*_*ana 14 java-native-interface android android-ndk android-4.0-ice-cream-sandwich android-ndk-r7

我在JNI C/C++中有一个方法,它接受jstring并返回jstring,如下所示,

  NATIVE_CALL(jstring, method)(JNIEnv * env, jobject obj, jstring filename)
  {

// Get jstring into C string format.
  const char* cs = env->GetStringUTFChars (filename, NULL);
  char *file_path = new char [strlen (cs) + 1]; // +1 for null terminator
  sprintf (file_path, "%s", cs);
  env->ReleaseStringUTFChars (filename, cs);


  reason_code = INTERNAL_FAILURE;
  char* info = start_module(file_path);  


  jstring jinfo ;


  if(info==NULL)
  {
      jinfo = env->NewStringUTF(NULL);
  }
  else
  {
      jinfo = env->NewStringUTF(info);

  }


  delete info;

  info = NULL;
  return jinfo;
  }
Run Code Online (Sandbox Code Playgroud)

该代码与之前的Android 4.0版本(如2.2,2.3等)完美配合.使用ICS 4.0检查JNI默认打开,因此应用程序崩溃抛出以下错误

 08-25 22:16:35.480: W/dalvikvm(24027): **JNI WARNING: input is not valid Modified UTF-8: illegal  continuation byte 0x40**
08-25 22:16:35.480: W/dalvikvm(24027):              
08-25 22:16:35.480: W/dalvikvm(24027): ==========
08-25 22:16:35.480: W/dalvikvm(24027): /tmp/create
08-25 22:16:35.480: W/dalvikvm(24027): ==========
08-25 22:16:35.480: W/dalvikvm(24027): databytes,indoorgames,drop
08-25 22:16:35.480: W/dalvikvm(24027): ==========???c_ag?????@??@?????@'
 08-25 22:16:35.480: W/dalvikvm(24027):              in Lincom/inter       /ndk/comNDK;.rootNDK:(Ljava/lang/String;)Ljava/lang/String; **(NewStringUTF)**
08-25 22:16:35.480: I/dalvikvm(24027): "main" prio=5 tid=1 NATIVE
08-25 22:16:35.480: I/dalvikvm(24027):   | group="main" sCount=0 dsCount=0 obj=0x40a4b460   self=0x1be1850
08-25 22:16:35.480: I/dalvikvm(24027):   | sysTid=24027 nice=0 sched=0/0 cgrp=default handle=1074255080
08-25 22:16:35.490: I/dalvikvm(24027):   | schedstat=( 49658000 26700000 48 ) utm=1 stm=3 core=1
08-25 22:16:35.490: I/dalvikvm(24027):   at comrootNDK(Native Method)
Run Code Online (Sandbox Code Playgroud)

我对自己错在哪里一无所知.如果你看到上面的NewStringUTF正在向c char*字节添加一些垃圾值.

  1. 任何关于为什么会这样的想法
  2. 任何替代解决方案都可以实现上述目标

如果你们中的一个能帮助我,我真的很感激.提前致谢

让我退缩

Mos*_*bin 21

此问题的原因与NDK/JNI GetStringUTFChars()函数中已知UTF-8错误(以及可能与NewStringUTF相关的函数)直接相关.这些NDK函数不能正确转换补充Unicode字符(即,值为U + 10000及以上的Unicode字符).这导致错误的UTF-8和随后的崩溃.

处理包含表情符号字符的用户输入文本时遇到崩溃(请参阅相应的Unicode图表).表情字符位于补充Unicode字符范围内.

问题分析

  1. Java客户端将包含补充Unicode字符的字符串传递给JNI/NDK.
  2. JNI使用NDK函数GetStringUTFChars()来提取Java字符串的内容.
  3. GetStringUTFChars()将字符串数据作为错误且无效的UTF-8返回.

存在已知的NDK错误,其中GetStringUTFChars()错误地转换补充的Unicode字符,从而产生不正确且无效的UTF-8序列.

在我的例子中,结果字符串是一个JSON缓冲区.当缓冲区传递给JSON解析器时,解析器立即失败,因为解压缩的UTF-8中的一个UTF-8字符具有无效的UTF-8前缀字节.

可能的解决方法

我用过的解决方案可归纳如下:

  1. 目标是防止GetStringUTFChars()执行补充Unicode字符的错误UTF-8编码.
  2. 这是由将客户端编码为Base64的Java客户端完成的.
  3. Base64编码的请求被传递给JNI.
  4. JNI调用GetStringUTFChars(),它提取Base64编码的字符串而不执行任何UTF-8编码.
  5. 然后,JNI代码对Base-64数据进行解码,生成原始的UTF-16(宽字符)请求字符串,包括补充的Unicode字符.

通过这种方式,我们避免了从Java字符串中提取补充Unicode字符的问题.相反,我们在调用GetStringUTFChars()之前将数据转换为Base-64 ASCII,使用GetStringUTFChars()提取Base-64 ASCII字符,并将Base-64数据转换回宽字符.

  • 非常有帮助,谢谢!查看[Lollipop源代码](http://androidxref.com/5.0.0_r2/xref/art/runtime/check_jni.cc#549),看起来像NewStringUTF()进行检查(entry == true),而GetStringUTFChars ()没有,所以它的行为不同. (2认同)

Ber*_*ncı 12

这就是我这样做的方式.

1- Char Array到JByteArray.

2- JByteArray到JString.

3-将jstring返回到java端.

JNI准则; (.c)格式

jstring Java_com_x_y_z_methodName(JNIEnv *env, jobject thiz) {
    int size = 16;
    char r[] = {'P', 'K', 'd', 'h', 't', 'X', 'M', 'm', 'r', '1', '8', 'n', '2', 'L', '9', 'K'};
    jbyteArray array = (*env)->NewByteArray(env, size);
    (*env)->SetByteArrayRegion(env, array, 0, size, r);
    jstring strEncode = (*env)->NewStringUTF(env, "UTF-8");
    jclass cls = (*env)->FindClass(env, "java/lang/String");
    jmethodID ctor = (*env)->GetMethodID(env, cls, "<init>", "([BLjava/lang/String;)V");
    jstring object = (jstring) (*env)->NewObject(env, cls, ctor, array, strEncode);

    return object;
}
Run Code Online (Sandbox Code Playgroud)

Java代码;

native String methodName();
Run Code Online (Sandbox Code Playgroud)

其他方法对我不起作用;

我也试过return (*env)->NewStringUTF(env, r)但返回一些不在char数组中的字符,在字符串的末尾带有JNI警告警告:输入无效修改UTF-8:非法连续字节0x40.

例; PKdhtXMmr18n2L9Kؾ-DL

编辑:

C++版

jstring clientStringFromStdString(JNIEnv *env,const std::string &str){
//    return env->NewStringUTF(str.c_str());
    jbyteArray array = env->NewByteArray(str.size());
    env->SetByteArrayRegion(array, 0, str.size(), (const jbyte*)str.c_str());
    jstring strEncode = env->NewStringUTF("UTF-8");
    jclass cls = env->FindClass("java/lang/String");
    jmethodID ctor = env->GetMethodID(cls, "<init>", "([BLjava/lang/String;)V");
    jstring object = (jstring) env->NewObject(cls, ctor, array, strEncode);
    return object;
}
Run Code Online (Sandbox Code Playgroud)


ran*_*ana 11

我通过返回字节数组而不是String来解决了这个问题.在Java方面,我现在将Byte数组转换为字符串.Works很好!因为已经在Google Android NDK上报告了一个错误,因此请远离使用适用于Android 4.0及更高版本的NewStringUTF().

  • 链接到错误报告? (6认同)