Android ndk android art运行时检查包名上的jni.cc错误

Android ndk android art运行时检查包名上的jni.cc错误,android-ndk,java-native-interface,android-5.0-lollipop,Android Ndk,Java Native Interface,Android 5.0 Lollipop,--编辑-- 由于构建不明确,共享库的版本太多了。gradle ./src/main/jniLibs/armeabi-v7a/libaudioboo-native.so rob@ app$ rm ./src/main/libs/armeabi-v7a/libaudioboo-native.so rob@ app$ rm ./src/main/obj/local/armeabi-v7a/libaudioboo-native.so rob@ app$ rm ./src/main/jniLibs/ar

--编辑-- 由于构建不明确,共享库的版本太多了。gradle

./src/main/jniLibs/armeabi-v7a/libaudioboo-native.so
rob@ app$ rm ./src/main/libs/armeabi-v7a/libaudioboo-native.so
rob@ app$ rm ./src/main/obj/local/armeabi-v7a/libaudioboo-native.so
rob@ app$ rm ./src/main/jniLibs/armeabi-v7a/libaudioboo-native.so 
已解决问题-将生成更改为以下内容,以便仅使用./src/main/libs中的共享库

sourceSets {
    main {
        jni.srcDirs = [] /*disable automatic ndk-build call */
        jniLibs.srcDir 'src/main/libs'
    }
}
在android5上崩溃了,所以我在AndroidStudio(1.0)ndk构建中使用它。我扫描了所有“findClass”的代码,答案是@holo。注意-将第34行的字符串常量从

 "fm.audioboo.jni.FLACStreamEncoder"; to "fm/audioboo/jni/FLACStreamEncoder";
这没有解决任何问题

java代码调用一个函数,在该本机函数执行之前,它看起来好像art框架自己正在使用第二个参数中的坏字符分隔符调用FindClass(_JNIEnv*,char const*)。如果您查看pastebin链接的第46-48行,它看起来似乎从未调用过本机函数。框架只是抛出错误的包名Findclass错误。注意,本机函数的第一行是运行时未到达的日志语句

Java层

  public FLACStreamEncoder(String outfile, int sample_rate, int channels,
      int bits_per_sample)
  {
    init(outfile, sample_rate, channels, bits_per_sample);
  }

...
  native private void init(String outfile, int sample_rate, int channels,
      int bits_per_sample);

...
  static {
    System.loadLibrary("audioboo-native");
  }
CPP层。。。函数永远不会到达第一行日志stmt

extern "C" {

void
Java_fm_audioboo_jni_FLACStreamEncoder_init(JNIEnv * env, jobject obj,
    jstring outfile, jint sample_rate, jint channels, jint bits_per_sample)
{
    aj::log(ANDROID_LOG_DEBUG, LTAG, "Begin INIT extern call");
  assert(sizeof(jlong) >= sizeof(FLACStreamEncoder *));

  FLACStreamEncoder * encoder = new FLACStreamEncoder(
      aj::convert_jstring_path(env, outfile), sample_rate, channels,
      bits_per_sample);

  char const * const error = encoder->init();
  if (NULL != error) {
    delete encoder;

    aj::throwByName(env, IllegalArgumentException_classname, error);
    return;
  }

  set_encoder(env, obj, encoder);
}
在使用NDK10-C构建安卓5之前,一切都正常(jni构建/安卓构建/安卓java对cpp的调用)

android5/ART的新功能似乎是“check_jni.cc”和某种严格的模式给出错误:

D/FLACRecorder(26743): Setting up encoder /data/data/com.borneo.speech/files/20141123081747.flac rate: 22050 channels: 1 format 16
F/art     (26743): art/runtime/check_jni.cc:65] JNI DETECTED ERROR IN APPLICATION: illegal class name 'fm.audioboo.jni.FLACStreamEncoder'
F/art     (26743): art/runtime/check_jni.cc:65]     (should be of the form 'package/Class', [Lpackage/Class;' or '[[B')
F/art     (26743): art/runtime/check_jni.cc:65]     in call to FindClass
F/art     (26743): art/runtime/check_jni.cc:65]     from void fm.audioboo.jni.FLACStreamEncoder.init(java.lang.String, int, int, int)
F
注意第46-48行

查看日志,就好像框架正在使用CPP中的第二个“thisClazz”arg对“findClass”进行自己的调用:

Java_fm_audioboo_jni_FLACStreamEncoder_init(JNIEnv * env, jobject obj, ...  
这是一个错误的arg值,违反了art运行时检查

但是我没有运行“javah”来从java接口创建任何头文件,因为在我得到git项目之前,这一切都已经完成了

我被难住了。本机似乎访问了函数,从未访问函数的第一行(log statemt),在

 /system/lib/libart.so (art::CheckJNI::FindClass(_JNIEnv*, char const*)+66
ndk(R10C)将cpp类链接如下:

make: Entering directory `/home/rob/tmp/audioboo-android/app/src/main/jni'
[armeabi-v7a] Compile thumb  : audioboo-ogg <= bitwise.c
[armeabi-v7a] Compile thumb  : audioboo-ogg <= framing.c
[armeabi-v7a] StaticLibrary  : libaudioboo-ogg.a
[armeabi-v7a] Compile thumb  : audioboo-flac <= bitmath.c
[armeabi-v7a] Compile thumb  : audioboo-flac <= bitreader.c
[armeabi-v7a] Compile thumb  : audioboo-flac <= cpu.c
[armeabi-v7a] Compile thumb  : audioboo-flac <= crc.c
[armeabi-v7a] Compile thumb  : audioboo-flac <= fixed.c
[armeabi-v7a] Compile thumb  : audioboo-flac <= float.c
[armeabi-v7a] Compile thumb  : audioboo-flac <= format.c
[armeabi-v7a] Compile thumb  : audioboo-flac <= lpc.c
[armeabi-v7a] Compile thumb  : audioboo-flac <= md5.c
[armeabi-v7a] Compile thumb  : audioboo-flac <= memory.c
[armeabi-v7a] Compile thumb  : audioboo-flac <= metadata_iterators.c
[armeabi-v7a] Compile thumb  : audioboo-flac <= metadata_object.c
[armeabi-v7a] Compile thumb  : audioboo-flac <= ogg_decoder_aspect.c
[armeabi-v7a] Compile thumb  : audioboo-flac <= ogg_encoder_aspect.c
[armeabi-v7a] Compile thumb  : audioboo-flac <= ogg_helper.c
[armeabi-v7a] Compile thumb  : audioboo-flac <= ogg_mapping.c
[armeabi-v7a] Compile thumb  : audioboo-flac <= stream_decoder.c
[armeabi-v7a] Compile thumb  : audioboo-flac <= stream_encoder.c
[armeabi-v7a] Compile thumb  : audioboo-flac <= stream_encoder_framing.c
[armeabi-v7a] Compile thumb  : audioboo-flac <= window.c
[armeabi-v7a] Compile thumb  : audioboo-flac <= bitwriter.c
[armeabi-v7a] StaticLibrary  : libaudioboo-flac.a
[armeabi-v7a] Compile++ thumb: audioboo-native <= FLACStreamEncoder.cpp
[armeabi-v7a] Compile++ thumb: audioboo-native <= FLACStreamDecoder.cpp
[armeabi-v7a] Compile++ thumb: audioboo-native <= util.cpp
[armeabi-v7a] StaticLibrary  : libstdc++.a
[armeabi-v7a] SharedLibrary  : libaudioboo-native.so
[armeabi-v7a] Install        : libaudioboo-native.so => libs/armeabi-v7a/libaudioboo-native.so
make: Leaving directory `/home/rob/tmp/audioboo-android/app/src/main/jni'

在从Java调用本机函数时,我不知道为什么?

我在升级到Android 5时遇到了同样的问题,并且刚刚解决了这个问题

bug存在于本机代码中,而不是java代码中。在本机代码中的某个地方,有一个函数通过jni将FlacStreamEncoder对象作为jobject传递给您,您可以使用如下行检索它:

jclass streamEncoder = env->FindClass("fm.audioboo.jni.FLACStreamEncoder"); jclass streamncoder=env->FindClass(“fm.audioboo.jni.FLACStreamEncoder”); 但是JNI应该使用“/”作为分隔符,而不是“.”,因此此行应为:

jclass streamEncoder = env->FindClass("fm/audioboo/jni/FLACStreamEncoder"); jclass streamEncoder=env->FindClass(“fm/audioboo/jni/FLACStreamEncoder”); 相反。以前版本的android默默地忽略了这个问题,但现在它只是在你面前爆炸

//检查“class_name”是否为有效的“完全限定”JNI类名,如“java/lang/Thread” //或者“[Ljava/lang/Object;”。类加载器实际上可以规范化几个类名称 //所以使用“java.lang.Thread”而不是“java/lang/Thread”在某些情况下可能会起作用 //但这是不正确的 void CheckClassName(常量字符*类名称){ 如果(!IsValidJniClassName(类名称)){ JniAbortF(函数名), “非法类名“%s”\n” “(格式应为‘包/类’、[Lpackage/Class;'或'[[B')”, 类别名称); } } }
非常确定我修复了CPP层中的'env->FindClass'实例。谢谢。在我的例子中,它可能来自(JNIenv,object)的init在CPP上的静态函数调用中,该调用正在分派自己的“FindClass”,因为在更改CPP中的所有字符串值并重新生成(ndk build)后,我仍然看到“非法类名”fm.audioboo.jni.FLACStreamEncoder“”.ps.为什么代码样本来自kitkat AOSP而不是lollipop?似乎对JNI更严格的检查是从Dalvik切换到Art运行时的结果。Art代码出现在kitkat中,这就是我发现代码片段的地方,但只有Lolipop.FWIW才成为默认值,检查也出现在Dalvik中,但只有在C中heckJNI已启用。我猜检查已从可选更改为强制性,或者检查JNI现在已更频繁地启用。请参阅中的第231行--上面的注释说明了此特定问题。此检查至少早在Donut(中的第508行)时就已存在。 jclass streamEncoder = env->FindClass("fm/audioboo/jni/FLACStreamEncoder"); // Checks that 'class_name' is a valid "fully-qualified" JNI class name, like "java/lang/Thread" // or "[Ljava/lang/Object;". A ClassLoader can actually normalize class names a couple of // times, so using "java.lang.Thread" instead of "java/lang/Thread" might work in some // circumstances, but this is incorrect void CheckClassName(const char* class_name) { if (!IsValidJniClassName(class_name)) { JniAbortF(function_name_, "illegal class name '%s'\n" " (should be of the form 'package/Class', [Lpackage/Class;' or '[[B')", class_name); } } }