-
Notifications
You must be signed in to change notification settings - Fork 555
[NativeAOT] Provide the Android ClassLoader #10121
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Fixes: #10081 Fixes: #10118 Context: 18ca528 Context: dotnet/java-interop@5852e6e dotnet/java-interop@5852e6e3 updated `JniEnviroment.Types.FindClass()` to begin using [`Class.forName(String, bool, ClassLoader)`][0] to load Java types instead of `ClassLoader.loadClass()`. This broke type registration on non-Java threads under NativeAOT; attempting to load a non-Android Java type from a managed thread: var t = new System.Threading.Thread(() => { using var c = new ClassFromThisAssembly(); }); t.Start(); t.Join(); would fail with a `ClassNotFoundException`: E NUnit : Java.Lang.ClassNotFoundException: Didn't find class "from.NewManagedThreadOne" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib64, /system_ext/lib64, /system/lib64, /system_ext/lib64]] E NUnit : at Java.Interop.JniEnvironment.Types.TryFindClass(String, Boolean) + 0x3f4 E NUnit : at Java.Interop.JniPeerMembers.JniInstanceMethods..ctor(Type) + 0x130 E NUnit : at Java.Interop.JniPeerMembers.JniInstanceMethods.GetConstructorsForType(Type) + 0x94 E NUnit : at Java.Interop.JniPeerMembers.JniInstanceMethods.StartCreateInstance(String, Type, JniArgumentValue*) + 0x1c E NUnit : at Java.Lang.Object..ctor() + 0x108 E NUnit : at Java.InteropTests.JnienvTest.<>c__DisplayClass6_0.<RegisterTypeOnNewManagedThread>b__0() + 0x24 E NUnit : --- End of managed Java.Lang.ClassNotFoundException stack trace --- E NUnit : java.lang.ClassNotFoundException: Didn't find class "from.NewManagedThreadOne" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib64, /system_ext/lib64, /system/lib64, /system_ext/lib64]] E NUnit : at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:259) E NUnit : at java.lang.ClassLoader.loadClass(ClassLoader.java:637) E NUnit : at java.lang.ClassLoader.loadClass(ClassLoader.java:573) Fix this by setting `NativeAotRuntimeOptions.ClassLoader` to the `context.getClassLoader()` value within `NativeAotRuntimeProvider.attachInfo()`. This ensures that we use a `ClassLoader` that knows about the app's `classes.dex`. [0]: https://developer.android.com/reference/java/lang/Class#forName(java.lang.String,%20boolean,%20java.lang.ClassLoader)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR fixes issues with Java type registration on non-Java threads under NativeAOT by ensuring that a proper Android ClassLoader is passed during initialization. The changes include updating the tests to use new class registration names for native and managed threads, modifying the JavaInteropRuntime API to accept a ClassLoader parameter, and updating the native initialization method on the C# side.
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
File | Description |
---|---|
tests/Mono.Android-Tests/Mono.Android-Tests/Java.Interop/JnienvTest.cs | Updated tests to use new registration strings and added a new test for managed thread type registration. |
src/Xamarin.Android.Build.Tasks/Resources/NativeAotRuntimeProvider.java | Retrieves the app ClassLoader and passes it to the JavaInteropRuntime initializer. |
src/Xamarin.Android.Build.Tasks/Resources/JavaInteropRuntime.java | Updated native method signature to accept a ClassLoader argument. |
src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/JavaInteropRuntime.cs | Modified native initialization to accept and store the ClassLoader for proper type registration. |
} | ||
}); | ||
thread.Start (); | ||
thread.Join (5000); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Consider extracting the magic number 5000 into a named constant for improved clarity and maintainability in test code.
thread.Join (5000); | |
thread.Join (ThreadJoinTimeoutMs); |
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that I'm not sure if this actually fixes: I think their sample was running on Mono, but I asked to double-check. |
Fixes: #10081
Fixes: #10118
Context: 18ca528
Context: dotnet/java-interop@5852e6e
dotnet/java-interop@5852e6e3 updated
JniEnviroment.Types.FindClass()
to begin usingClass.forName(String, bool, ClassLoader)
to load Java types instead ofClassLoader.loadClass()
.This broke type registration on non-Java threads under NativeAOT; attempting to load a non-Android Java type from a managed thread:
would fail with a
ClassNotFoundException
:Fix this by setting
NativeAotRuntimeOptions.ClassLoader
to thecontext.getClassLoader()
value withinNativeAotRuntimeProvider.attachInfo()
. This ensures that we use aClassLoader
that knows about the app'sclasses.dex
.