manganis: load FFI classes from the activity classloader, not FindClass
JNIEnv::find_class resolves against the system classloader on a thread attached from native code, which cannot see APK classes (#5629). Route the generated #[manganis::ffi] type lookup through load_class_from_classloader, and reimplement that helper to ask the activity's own ClassLoader.loadClass instead of Class.forName.
This commit is contained in:
1 parent
07dddd569e
commit
aeb5568727
2 files changed
+25
-6
No files matched your search
@@ -398,7 +398,7 @@ impl FfiBridgeParser {
|
|||||||
// Use with_activity which returns Option<R>, wrapping our Result in the Option
|
// Use with_activity which returns Option<R>, wrapping our Result in the Option
|
||||||
let inner_result: Option<Result<Self, String>> = manganis::android::with_activity(|mut env, activity| {
|
let inner_result: Option<Result<Self, String>> = manganis::android::with_activity(|mut env, activity| {
|
||||||
// Find the class
|
// Find the class
|
||||||
let class_result = env.find_class(#class_name_lit);
|
let class_result = manganis::android::load_class_from_classloader(env, activity, #class_name_lit);
|
||||||
let class = match class_result {
|
let class = match class_result {
|
||||||
Ok(c) => c,
|
Ok(c) => c,
|
||||||
Err(e) => return Some(Err(format!("Failed to find class {}: {:?}", #class_name_lit, e))),
|
Err(e) => return Some(Err(format!("Failed to find class {}: {:?}", #class_name_lit, e))),
|
||||||
|
|||||||
@@ -111,15 +111,34 @@ pub fn request_permissions_via_helper(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load a Java class from the APK's classloader
|
/// Load a Java class from the APK's classloader.
|
||||||
|
///
|
||||||
|
/// `JNIEnv::find_class` resolves against the *system* classloader on a thread that
|
||||||
|
/// was attached from native code (`JavaVM::attach_current_thread`), which cannot see
|
||||||
|
/// classes packaged in the APK, so it raises `ClassNotFoundException`. The activity's
|
||||||
|
/// own classloader can, so we ask the activity for it and call `loadClass` on it.
|
||||||
|
///
|
||||||
|
/// `class_name` may be given in either JNI form (`com/example/Foo`) or binary form
|
||||||
|
/// (`com.example.Foo`); `loadClass` requires the binary form, so slashes are converted.
|
||||||
pub fn load_class_from_classloader<'env>(
|
pub fn load_class_from_classloader<'env>(
|
||||||
env: &mut JNIEnv<'env>,
|
env: &mut JNIEnv<'env>,
|
||||||
|
activity: &JObject<'_>,
|
||||||
class_name: &str,
|
class_name: &str,
|
||||||
) -> Result<JClass<'env>> {
|
) -> Result<JClass<'env>> {
|
||||||
let class_name_jstring = new_string(env, class_name)?;
|
let binary_name = class_name.replace('/', ".");
|
||||||
let class = env.call_static_method(
|
let activity_class = env.get_object_class(activity)?;
|
||||||
"java/lang/Class",
|
let loader = env
|
||||||
"forName",
|
.call_method(
|
||||||
|
&activity_class,
|
||||||
|
"getClassLoader",
|
||||||
|
"()Ljava/lang/ClassLoader;",
|
||||||
|
&[],
|
||||||
|
)?
|
||||||
|
.l()?;
|
||||||
|
let class_name_jstring = new_string(env, &binary_name)?;
|
||||||
|
let class = env.call_method(
|
||||||
|
&loader,
|
||||||
|
"loadClass",
|
||||||
"(Ljava/lang/String;)Ljava/lang/Class;",
|
"(Ljava/lang/String;)Ljava/lang/Class;",
|
||||||
&[JValue::Object(&class_name_jstring)],
|
&[JValue::Object(&class_name_jstring)],
|
||||||
)?;
|
)?;
|
||||||
|
|||||||
Reference in new issue
Block a user