【问题标题】:NewGlobalRef called with pending exception java.lang.ClassNotFoundException on different .soNewGlobalRef 在不同的.so 上调用了挂起的异常 java.lang.ClassNotFoundException
【发布时间】:2021-06-29 17:56:52
【问题描述】:

我有一个使用 my_app_helper.so 的库 my_app.so

线

jclass jc = env->FindClass("com.my_app.flutter_app.MainActivity");

my_app.so 的任何地方都可以完美运行,但会给出:

A/zygote64: java_vm_ext.cc:523] JNI DETECTED ERROR IN APPLICATION: JNI 
NewGlobalRef called with pending exception java.lang.ClassNotFoundException: 
Didn't find class "com.my_app.flutter_app.MainActivity" on path: 
DexPathList[[dex file "InMemoryDexFile[cookie=[0, 
547409613216]]"],nativeLibraryDirectories=[/system/lib64, /system/vendor/lib64]]

my_app_helper.so

我的JNI_Onloadmy_app.so 上,它会将JavaVM *vm 传递给my_app_helper.so

为什么在my_app_helper.so内部调用时找不到类?

更新:

这是回溯:

A/zygote64: java_vm_ext.cc:523] JNI DETECTED ERROR IN APPLICATION: JNI NewGlobalRef called with pending exception java.lang.ClassNotFoundException: Didn't find class "com.my_app.flutter_app.MainActivity" on path: DexPathList[[dex file "InMemoryDexFile[cookie=[0, 547694828128]]"],nativeLibraryDirectories=[/system/lib64, /system/vendor/lib64]]
    java_vm_ext.cc:523]   at java.lang.Class dalvik.system.BaseDexClassLoader.findClass(java.lang.String) (BaseDexClassLoader.java:93)
    java_vm_ext.cc:523]   at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String, boolean) (ClassLoader.java:379)
    java_vm_ext.cc:523]   at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String) (ClassLoader.java:312)
    java_vm_ext.cc:523]   at java.lang.Object com.rmsl.juce.JuceInvocationHandler.dispatchInvoke(long, java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) (JuceInvocationHandler.java:-2)
    java_vm_ext.cc:523]   at java.lang.Object com.rmsl.juce.JuceInvocationHandler.invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) (JuceInvocationHandler.java:28)
    java_vm_ext.cc:523]   at java.lang.Object java.lang.reflect.Proxy.invoke(java.lang.reflect.Proxy, java.lang.reflect.Method, java.lang.Object[]) (Proxy.java:913)
    java_vm_ext.cc:523]   at void android.app.Application$ActivityLifecycleCallbacks.onActivityStarted(android.app.Activity) ((null):-1)
    java_vm_ext.cc:523]   at void android.app.Application.dispatchActivityStarted(android.app.Activity) (Application.java:207)
    java_vm_ext.cc:523]   at void android.app.Activity.onStart() (Activity.java:1249)
    java_vm_ext.cc:523]   at void io.flutter.embedding.android.FlutterActivity.onStart() (FlutterActivity.java:533)
    java_vm_ext.cc:523]   at void com.my_app.flutter_app.MainActivity.onStart() (MainActivity.kt:256)
    java_vm_ext.cc:523]   at void android.app.Instrumentation.callActivityOnStart(android.app.Activity) (Instrumentation.java:1355)
    java_vm_ext.cc:523]   at void android.app.Activity.performStart() (Activity.java:7001)
    java_vm_ext.cc:523]   at android.app.Activity android.app.ActivityThread.performLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.content.Intent) (ActivityThread.java:2807)
    java_vm_ext.cc:523]   at void android.app.ActivityThread.handleLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.content.Intent, java.lang.String) (ActivityThread.java:2923)
    java_vm_ext.cc:523]   at void android.app.ActivityThread.-wrap11(android.app.ActivityThread, android.app.ActivityThread$ActivityClientRecord, android.content.Intent, java.lang.String) (ActivityThread.java:-1)
    java_vm_ext.cc:523]   at void android.app.ActivityThread$H.handleMessage(android.os.Message) (ActivityThread.java:1616)
    java_vm_ext.cc:523]   at void android.os.Handler.dispatchMessage(android.os.Message) (Handler.java:105)
    java_vm_ext.cc:523]   at void android.os.Looper.loop() (Looper.java:164)
    java_vm_ext.cc:523]   at void android.app.ActivityThread.main(java.lang.String[]) (ActivityThread.java:6617)
    java_vm_ext.cc:523]   at java.lang.Object java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object[]) (Method.java:-2)
    java_vm_ext.cc:523]   at void com.android.internal.os.Zygote$MethodAndArgsCaller.run() (Zygote.java:240)
    java_vm_ext.cc:523]   at void com.android.internal.os.ZygoteInit.main(java.lang.String[]) (ZygoteInit.java:769)
    java_vm_ext.cc:523] 
    java_vm_ext.cc:523]     in call to NewGlobalRef
    java_vm_ext.cc:523]     from java.lang.Object com.rmsl.juce.JuceInvocationHandler.dispatchInvoke(long, java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
    java_vm_ext.cc:523] "main" prio=5 tid=1 Runnable
    java_vm_ext.cc:523]   | group="main" sCount=0 dsCount=0 flags=0 obj=0x72a3f710 self=0x7f93ec3a00
    java_vm_ext.cc:523]   | sysTid=21008 nice=-10 cgrp=default sched=0/0 handle=0x7f986549b0
    java_vm_ext.cc:523]   | state=R schedstat=( 583813855 313733548 562 ) utm=46 stm=11 core=1 HZ=100
    java_vm_ext.cc:523]   | stack=0x7ff863b000-0x7ff863d000 stackSize=8MB
    java_vm_ext.cc:523]   | held mutexes= "mutator lock"(shared held)
A/zygote64: java_vm_ext.cc:523]   native: #00 pc 00000000003982fc  /system/lib64/libart.so (_ZN3art15DumpNativeStackERNSt3__113basic_ostreamIcNS0_11char_traitsIcEEEEiP12BacktraceMapPKcPNS_9ArtMethodEPv+212)

【问题讨论】:

  • 你从哪个线程调用env->FindClass?调用堆栈是什么样子的?
  • @esentsov 我用回溯更新了
  • 不应该是env->FindClass("com/my_app/flutter_app/MainActivity")吗?另外,你是从你自己用pthread_new 或类似的线程创建的吗?
  • @Botje 是的,事情正在新线程中发生。不是我控制的线程,但它们是。我应该附上线程吗?我不确切知道,但我想有一些关于将线程附加到某物的东西。如果我没记错,我试过了,但它没有用。是的,应该是com/my_app/flutter_app/MainActivity,我打错了,但我写对了代码。

标签: android c++ java-native-interface


【解决方案1】:

你没有给我们太多的工作,但我认为你的问题源于this Android JNI FAQ

如果您自己创建一个线程(可能通过调用 pthread_create 然后使用 AttachCurrentThread 附加它),您可能会遇到麻烦。现在您的应用程序中没有堆栈帧。如果您从该线程调用 FindClass,JavaVM 将在“系统”类加载器而不是与您的应用程序关联的类加载器中启动,因此尝试查找特定于应用程序的类将失败。

因此,在my_app_helper.so 的代码中,您应该:

  1. 确保使用特定于线程的env(如果需要,通过在虚拟机上调用AttachCurrentThread 获得);
  2. 确保您需要的所有类引用均已提前获得。这就像从 my_app.so 调用 FindClass 并将 GlobalReference 存储在静态/全局变量中一样简单。 (g_my_class = env->NewGlobalRef(env->FindClass("..."))) 这是最简单的解决方法,但请参阅链接帖子了解其他选项。

一般来说,您应该养成良好的 JNI 卫生习惯,并始终在 JNI 调用后检查错误,特别是对于 Android,请考虑在开发时打开 extended checking

编辑:在第二种情况下FindClass 将始终有效:

作为执行 JNI_OnLoad 的一部分进行的任何 FindClass 调用都将使用与调用 System.loadLibrary 的函数相关联的类加载器(这是一个特殊规则,提供用于使库初始化更方便)。"

你可以在Android Runtime源代码here看到这个:

    // **: class_loader is the class loader of the code that called `loadLibrary`
    ScopedLocalRef<jobject> old_class_loader(env, env->NewLocalRef(self->GetClassLoaderOverride()));
    self->SetClassLoaderOverride(class_loader); // **

    VLOG(jni) << "[Calling JNI_OnLoad in \"" << path << "\"]";
    using JNI_OnLoadFn = int(*)(JavaVM*, void*);
    JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);
    int version = (*jni_on_load)(this, nullptr);

    self->SetClassLoaderOverride(old_class_loader.get()); // **

【讨论】:

  • 很遗憾,AttachCurrentThread 不起作用。是否真的需要从主线程缓存所有类,或者更好的是,从JNI_Onload 缓存?
  • 你需要同时做:禁止跨线程共享 JNIEnv,并且 android JVM 不支持在它不是自己创建的线程中的 FindClass。请参阅常见问题解答链接了解原因。
  • 我怀疑我不能在不同的线程上使用FindClass,所以我做了这个最小的例子并且它有效:pastebin.com/WjfnFaDX。你知道为什么吗? FindCLass 正在从不同的线程调用
  • 有趣。这可能是由于常见问题解答中的以下措辞:“作为执行 JNI_OnLoad 的一部分进行的任何 FindClass 调用都将使用与调用 System.loadLibrary 的函数关联的类加载器(这是一个特殊规则,提供了使库初始化更方便)。”对我来说,这就像“我们在 JNI_Onload 运行时覆盖系统类加载器”。但是,我没有时间深入研究 ART 源代码:/
  • Found it!:当 JNI_Onload 运行时,VM 的根类加载器被覆盖。如果 lambda 在 JNI_Onload 返回后运行,我预计您的实验将无法进行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-10
  • 2011-10-05
  • 1970-01-01
  • 2018-08-14
相关资源
最近更新 更多