Skip to content

Commit aba2726

Browse files
[Mono.Android] JNIEnv.FindClass() uses JniEnvironment.Types.FindClass() (#9769)
Context: xamarin/monodroid@ed984a3 Context: dotnet/java-interop#23 Update `JNIEnv.FindClass()` to use `JniEnvironment.Types.FindClass()`. This avoids the problem of `JNIEnvInit.mid_Class_forName` being `null` in a NativeAOT context: E AndroidRuntime: Process: net.dot.hellonativeaot, PID: 30744 E AndroidRuntime: net.dot.jni.internal.JavaProxyThrowable: System.TypeInitializationException: TypeInitialization_Type_NoTypeAvailable E AndroidRuntime: ---> System.ArgumentNullException: ArgumentNull_Generic Arg_ParamName_Name, method E AndroidRuntime: at Java.Interop.JniEnvironment.StaticMethods.CallStaticObjectMethod(JniObjectReference, JniMethodInfo, JniArgumentValue*) + 0x1c8 E AndroidRuntime: at Android.Runtime.JNIEnv.FindClass(String) + 0xb4 E AndroidRuntime: at Java.Lang.Class..cctor() + 0x7c E AndroidRuntime: at System.Runtime.CompilerServices.ClassConstructorRunner.EnsureClassConstructorRun(StaticClassConstructionContext*) + 0xb4 E AndroidRuntime: Exception_EndOfInnerExceptionStack E AndroidRuntime: at System.Runtime.CompilerServices.ClassConstructorRunner.EnsureClassConstructorRun(StaticClassConstructionContext*) + 0x160 E AndroidRuntime: at System.Runtime.CompilerServices.ClassConstructorRunner.CheckStaticClassConstructionReturnNonGCStaticBase(StaticClassConstructionContext*, IntPtr) + 0x14 E AndroidRuntime: at Android.Runtime.JNIEnv.FindClass(String) + 0xc0 E AndroidRuntime: at Android.App.Application.get_Context() + 0x50 E AndroidRuntime: at Microsoft.Maui.Hosting.EssentialsExtensions.<>c.<UseEssentials>b__0_0(ILifecycleBuilder life) + 0x18 E AndroidRuntime: at Microsoft.Maui.LifecycleEvents.LifecycleEventService..ctor(IEnumerable`1) + 0x94 E AndroidRuntime: at Microsoft.Maui.LifecycleEvents.MauiAppHostBuilderExtensions.<>c.<ConfigureLifecycleEvents>b__0_0(IServiceProvider sp) + 0x3c E AndroidRuntime: at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite, RuntimeResolverContext) + 0x68 E AndroidRuntime: at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(ServiceIdentifier serviceIdentifier) + 0x180 E AndroidRuntime: at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey, Func`2) + 0x11c E AndroidRuntime: at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier, ServiceProviderEngineScope) + 0x44 E AndroidRuntime: at Microsoft.Maui.MauiContext.WrappedServiceProvider.GetService(Type) + 0x48 E AndroidRuntime: at Microsoft.Maui.MauiContext.WrappedServiceProvider.GetService(Type) + 0x48 E AndroidRuntime: at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetService[T](IServiceProvider) + 0x3c E AndroidRuntime: at Microsoft.Maui.LifecycleEvents.LifecycleEventServiceExtensions.<GetLifecycleEventDelegates>d__3`1.MoveNext() + 0x38 E AndroidRuntime: at Microsoft.Maui.LifecycleEvents.LifecycleEventServiceExtensions.InvokeLifecycleEvents[TDelegate](IServiceProvider, Action`1) + 0x68 E AndroidRuntime: at Microsoft.Maui.MauiApplication.OnCreate() + 0xb0 E AndroidRuntime: at Android.App.Application.n_OnCreate(IntPtr jnienv, IntPtr native__this) + 0xb0 E AndroidRuntime: at my.MainApplication.n_onCreate(Native Method) E AndroidRuntime: at my.MainApplication.onCreate(MainApplication.java:24) E AndroidRuntime: at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1386) E AndroidRuntime: at android.app.ActivityThread.handleBindApplication(ActivityThread.java:7398) E AndroidRuntime: at android.app.ActivityThread.-$$Nest$mhandleBindApplication(Unknown Source:0) E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2379) E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:107) E AndroidRuntime: at android.os.Looper.loopOnce(Looper.java:232) E AndroidRuntime: at android.os.Looper.loop(Looper.java:317) E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:8592) E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method) E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:580) E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:878) This also allows us to remove these fields that are now unused: * `JnienvInitializeArgs.Class_forName` * `JNIEnv.BinaryName()` TODO? While `JNIEnv.FindClass()` was using [`Class.forName()`][0], `JniEnvironment.Types.FindClass()` uses [`ClassLoader.loadClass()`][1]. `JNIEnv.FindClass()` originally used `ClassLoader.loadClass()`, but was changed to use `Class.forName()` in xamarin/monodroid@ed984a3a as part of supporting the Xamarin.Android Designer. Updating `JNIEnv.FindClass()` to use `JniEnvironment.Types.FindClass()` effectively reverts that original change. This is "fine" for now -- the Xamarin.Android Designer is no longer supported -- but in the future we may want to update `JniEnvironment.Types.FindClass()` to use `Class.forName()`; see dotnet/java-interop#23. [0]: https://developer.android.com/reference/java/lang/Class#forName(java.lang.String) [1]: https://developer.android.com/reference/java/lang/ClassLoader#loadClass(java.lang.String)
1 parent a9299a2 commit aba2726

File tree

4 files changed

+2
-51
lines changed

4 files changed

+2
-51
lines changed

Diff for: src/Mono.Android/Android.Runtime/JNIEnv.cs

+2-45
Original file line numberDiff line numberDiff line change
@@ -280,52 +280,9 @@ public static IntPtr FindClass (System.Type type)
280280
}
281281
}
282282

283-
const int nameBufferLength = 1024;
284-
[ThreadStatic] static char[]? nameBuffer;
285-
286-
static unsafe IntPtr BinaryName (string classname)
283+
public static IntPtr FindClass (string classname)
287284
{
288-
int index = classname.IndexOf ('/');
289-
290-
if (index == -1)
291-
return NewString (classname);
292-
293-
int length = classname.Length;
294-
if (length > nameBufferLength)
295-
return NewString (classname.Replace ('/', '.'));
296-
297-
if (nameBuffer == null)
298-
nameBuffer = new char[nameBufferLength];
299-
300-
fixed (char* src = classname, dst = nameBuffer) {
301-
char* src_ptr = src;
302-
char* dst_ptr = dst;
303-
char* end_ptr = src + length;
304-
while (src_ptr < end_ptr) {
305-
*dst_ptr = (*src_ptr == '/') ? '.' : *src_ptr;
306-
src_ptr++;
307-
dst_ptr++;
308-
}
309-
}
310-
return NewString (nameBuffer, length);
311-
}
312-
313-
public unsafe static IntPtr FindClass (string classname)
314-
{
315-
JniObjectReference local_ref;
316-
317-
IntPtr native_str = BinaryName (classname);
318-
try {
319-
JniArgumentValue* parameters = stackalloc JniArgumentValue [3] {
320-
new JniArgumentValue (native_str),
321-
new JniArgumentValue (true),
322-
new JniArgumentValue (JNIEnvInit.java_class_loader),
323-
};
324-
local_ref = JniEnvironment.StaticMethods.CallStaticObjectMethod (Java.Lang.Class.Members.JniPeerType.PeerReference, JNIEnvInit.mid_Class_forName!, parameters);
325-
} finally {
326-
DeleteLocalRef (native_str);
327-
}
328-
285+
JniObjectReference local_ref = JniEnvironment.Types.FindClass (classname);
329286
IntPtr global_ref = NewGlobalRef (local_ref.Handle);
330287
JniObjectReference.Dispose (ref local_ref);
331288
return global_ref;

Diff for: src/Mono.Android/Android.Runtime/JNIEnvInit.cs

-4
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ internal struct JnienvInitializeArgs {
2020
public IntPtr grefLoader;
2121
public IntPtr Loader_loadClass;
2222
public IntPtr grefClass; // TODO: remove, not needed anymore
23-
public IntPtr Class_forName;
2423
public uint logCategories;
2524
public int version; // TODO: remove, not needed anymore
2625
public int grefGcThreshold;
@@ -46,7 +45,6 @@ internal struct JnienvInitializeArgs {
4645
internal static IntPtr grefIGCUserPeer_class;
4746
internal static IntPtr grefGCUserPeerable_class;
4847
internal static IntPtr java_class_loader;
49-
internal static JniMethodInfo? mid_Class_forName;
5048

5149
internal static JniRuntime? androidRuntime;
5250

@@ -100,8 +98,6 @@ internal static unsafe void Initialize (JnienvInitializeArgs* args)
10098
MarshalMethodsEnabled = args->marshalMethodsEnabled;
10199
java_class_loader = args->grefLoader;
102100

103-
mid_Class_forName = new JniMethodInfo (args->Class_forName, isStatic: true);
104-
105101
BoundExceptionType = (BoundExceptionType)args->ioExceptionType;
106102
androidRuntime = new AndroidRuntime (args->env, args->javaVm, args->grefLoader, args->Loader_loadClass, args->jniAddNativeMethodRegistrationAttributePresent != 0);
107103
ValueManager = androidRuntime.ValueManager;

Diff for: src/native/mono/monodroid/monodroid-glue-internal.hh

-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,6 @@ namespace xamarin::android::internal
8989
jobject grefLoader;
9090
jmethodID Loader_loadClass;
9191
jclass grefClass;
92-
jmethodID Class_forName;
9392
unsigned int logCategories;
9493
int version;
9594
int grefGcThreshold;

Diff for: src/native/mono/monodroid/monodroid-glue.cc

-1
Original file line numberDiff line numberDiff line change
@@ -860,7 +860,6 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec
860860

861861
init.grefClass = RuntimeUtil::get_class_from_runtime_field (env, runtimeClass, "java_lang_Class", true);
862862
Class_getName = env->GetMethodID (init.grefClass, "getName", "()Ljava/lang/String;");
863-
init.Class_forName = env->GetStaticMethodID (init.grefClass, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
864863

865864
MonoAssembly *mono_android_assembly;
866865

0 commit comments

Comments
 (0)