[vlc-devel] [PATCH 3/7] android: specific: store initial JNI classloader

Alexandre Janniaux ajanni at videolabs.io
Wed Feb 10 11:23:19 UTC 2021


Only the class loader associated to the JNI callstack can load the class
defined in the java application. This class loader can be stored and
used later in other threads so store it from the start of the native
libvlccore core. This is well explained from the JNI tips page[1]
documentation from the Android project:

> If the class name looks right, you could be running into a class
> loader issue. FindClass wants to start the class search in the class
> loader associated with your code. It examines the call stack, which
> will look something like:
>     Foo.myfunc(Native Method)
>     Foo.main(Foo.java:10)
>
> The topmost method is Foo.myfunc. FindClass finds the ClassLoader
> object associated with the Foo class and uses that.
>
> This usually does what you want. You can get into trouble if you create
> a thread yourself (perhaps by calling pthread_create and then attaching
> it with AttachCurrentThread). Now there are no stack frames from your
> application. If you call FindClass from this thread, the JavaVM will
> start in the "system" class loader instead of the one associated with
> your application, so attempts to find app-specific classes will fail.
>
> There are a few ways to work around this:
> ...
> - Cache a reference to the ClassLoader object somewhere handy, and
>   issue loadClass calls directly. This requires some effort.

[1]: https://developer.android.com/training/articles/perf-jni#faq:-why-didnt-findclass-find-my-class
---
 src/android/specific.c | 49 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/src/android/specific.c b/src/android/specific.c
index 1b74f522a3..d08f3a3a4f 100644
--- a/src/android/specific.c
+++ b/src/android/specific.c
@@ -49,6 +49,15 @@ static struct {
         jclass clazz;
         jmethodID getProperty;
     } System;
+    struct {
+        jobject instance;
+        jmethodID getClassLoader;
+    } ClassLoader;
+    struct {
+        jclass clazz;
+        jmethodID currentThread;
+        jmethodID getContextClassLoader;
+    } Thread;
 } fields = { .Environment.clazz = NULL };
 
 static char *
@@ -88,6 +97,12 @@ JNI_OnUnload(JavaVM* vm, void* reserved)
     if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_2) != JNI_OK)
         return;
 
+    if (fields.ClassLoader.instance)
+        (*env)->DeleteGlobalRef(env, fields.ClassLoader.instance);
+
+    if (fields.Thread.clazz)
+        (*env)->DeleteGlobalRef(env, fields.Thread.clazz);
+
     if (fields.Environment.clazz)
         (*env)->DeleteGlobalRef(env, fields.Environment.clazz);
 
@@ -154,6 +169,37 @@ JNI_OnLoad(JavaVM *vm, void *reserved)
                                   "(Ljava/lang/String;)Ljava/lang/String;");
     (*env)->DeleteLocalRef(env, clazz);
 
+    clazz = (*env)->FindClass(env, "java/lang/Thread");
+    if((*env)->ExceptionCheck(env))
+        goto error;
+
+    fields.Thread.clazz = (*env)->NewGlobalRef(env, clazz);
+    if((*env)->ExceptionCheck(env))
+        goto error;
+
+    fields.Thread.currentThread = (*env)->GetStaticMethodID(env,
+            fields.Thread.clazz, "currentThread", "()Ljava/lang/Thread;");
+    fields.Thread.getContextClassLoader = (*env)->GetMethodID(env,
+            fields.Thread.clazz, "getContextClassLoader", "()Ljava/lang/ClassLoader;");
+
+    jobject current_thread = (*env)->CallStaticObjectMethod(env,
+            fields.Thread.clazz,
+            fields.Thread.currentThread);
+    if((*env)->ExceptionCheck(env))
+        goto error;
+
+    jobject classloader_instance = (*env)->CallObjectMethod(env,
+            current_thread, fields.Thread.getContextClassLoader);
+    if((*env)->ExceptionCheck(env))
+        goto error;
+
+    (*env)->DeleteLocalRef(env, current_thread);
+
+    fields.ClassLoader.instance = (*env)->NewGlobalRef(env, classloader_instance);
+    (*env)->DeleteLocalRef(env, classloader_instance);
+    if (fields.ClassLoader.instance == NULL)
+        goto error;
+
     return JNI_VERSION_1_2;
 
 error:
@@ -175,6 +221,9 @@ system_Configure(libvlc_int_t *p_libvlc, int i_argc, const char *const pp_argv[]
     assert(s_jvm != NULL);
     var_Create(p_libvlc, "android-jvm", VLC_VAR_ADDRESS);
     var_SetAddress(p_libvlc, "android-jvm", s_jvm);
+
+    var_Create(p_libvlc, "android-classloader", VLC_VAR_ADDRESS);
+    var_SetAddress(p_libvlc, "android-classloader", fields.ClassLoader.instance);
 }
 
 static char *config_GetHomeDir(const char *psz_dir, const char *psz_default_dir)
-- 
2.30.1



More information about the vlc-devel mailing list