gpt4 book ai didi

android - 来自 Android JNI 中任何线程的 FindClass

转载 作者:IT老高 更新时间:2023-10-28 14:02:02 35 4
gpt4 key购买 nike

Android 的 JNI 提示页面提到了 FAQ: Why didn't FindClass find my class?他们提到了多种解决方案,最后一个选项是这个:

Cache a reference to the ClassLoader object somewhere handy, and issue loadClass calls directly. This requires some effort.

所以,我试图让它工作,但似乎无论如何,这种方法对我来说根本不起作用。最终,我想出了如何使用 ClassLoader 但如果我从 native 线程尝试加载尚未触摸/加载的类,它将无法工作。本质上,它在从 native 线程调用时的行为与 env->FindClass 相同,但它不会为已在应用程序中使用的类返回 0。任何想法,如果我没有做对,或者不可能从尚未使用/加载的 native 线程访问类。






编辑:我将提供更多信息来解释我的意思。有常规的 JNI env->FindClass(className),还有一个我写的 myFindClass(env, className) 使用缓存的 ClassLoader->loadClass.

我试图从 native c/c++ 访问的类是“com/noname/TestClient”。在 myFindClass 中,我还使用 env->FindClass 并记录它返回的值:

jclass myFindClass(JNIEnv * env, const char* name)
{
...
jclass c0 = env->FindClass(name);
jclass c1 = (jclass)env->CallObjectMethod(ClassLoader,
MID_loadClass, envNewStringUTF(name));
dlog("myFindClass(\"%s\") => c0:%p, c1:%p, c0 and c1 are same: %d",
name, c0, c1, env->IsSameObject(c0, c1));
...
}

那么,我有这 3 个组合来解释这个问题。

1)

//inside JNI_OnLoad thread
myFindClass(env, "com/noname/TestClient");
...

//inside native thread created by pthread_create
myFindClass(env, "com/noname/TestClient");

我得到了这个 logcat:

myFindClass("com/noname/TestClent") => c0:0x41b64558, c1:0x41b64558, c0 and c1 are same: 1
...
myFindClass("com/noname/TestClent") => c0:0, c1:0x41b64558, c0 and c1 are same: 0

2)

//inside JNI_OnLoad thread
env->FindClass("com/noname/TestClient");
...

//inside native thread created by pthread_create
myFindClass("com/noname/TestClient");

我得到了这个 logcat:

myFindClass("com/noname/TestClent") => c0:0, c1:0x41b64558, c0 and c1 are same: 0

3)

//inside JNI_OnLoad thread
//"com/noname/TestClient" isn't touched from JNI_OnLoad.
...

//inside native thread created by pthread_create
myFindClass(env, "com/noname/TestClient");

我得到了这个 logcat:

myFindClass("com/noname/TestClent") => c0:0, c1:0, c0 and c1 are same: 1

基本上,我的问题是 ClassLoader 在第三种情况下找不到我的类(class)。它是一个错误吗?有什么办法可以解决这个问题?

EDIT2:最重要的是,似乎 ClassLoader::loadClass 显然是错误的。如果我问 myFindClass("noname/TestClent") 那么它会返回一些垃圾,当我以任何方式使用返回的 jclass 时,应用程序就会崩溃。

最佳答案

在我的应用程序经过多次尝试和崩溃之后,我和一位同事设法缓存并成功地在另一个 native 线程中使用了类加载器。我们使用的代码如下所示(C++11,但很容易转换为 C++2003),发布在这里,因为我们找不到上述“在方便的地方缓存对 ClassLoader 对象的引用,并发出 loadClass直接调用。这需要一些努力。”。当从与 JNI_OnLoad 线程不同的线程调用时,调用 findClass 可以完美运行。我希望这会有所帮助。

JavaVM* gJvm = nullptr;
static jobject gClassLoader;
static jmethodID gFindClassMethod;

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *pjvm, void *reserved) {
gJvm = pjvm; // cache the JavaVM pointer
auto env = getEnv();
//replace with one of your classes in the line below
auto randomClass = env->FindClass("com/example/RandomClass");
jclass classClass = env->GetObjectClass(randomClass);
auto classLoaderClass = env->FindClass("java/lang/ClassLoader");
auto getClassLoaderMethod = env->GetMethodID(classClass, "getClassLoader",
"()Ljava/lang/ClassLoader;");
gClassLoader = env->CallObjectMethod(randomClass, getClassLoaderMethod);
gFindClassMethod = env->GetMethodID(classLoaderClass, "findClass",
"(Ljava/lang/String;)Ljava/lang/Class;");

return JNI_VERSION_1_6;
}

jclass findClass(const char* name) {
return static_cast<jclass>(getEnv()->CallObjectMethod(gClassLoader, gFindClassMethod, getEnv()->NewStringUTF(name)));
}

JNIEnv* getEnv() {
JNIEnv *env;
int status = gJvm->GetEnv((void**)&env, JNI_VERSION_1_6);
if(status < 0) {
status = gJvm->AttachCurrentThread(&env, NULL);
if(status < 0) {
return nullptr;
}
}
return env;
}

关于android - 来自 Android JNI 中任何线程的 FindClass,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13263340/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com