-
Notifications
You must be signed in to change notification settings - Fork 566
Description
Problem
The new JcwJavaSourceGenerator unconditionally emits mono.android.Runtime.registerNatives(Class) in the static initializer block for every JCW type. For Application and Instrumentation types, this will crash with UnsatisfiedLinkError because the native library (libmonodroid.so) is not loaded until the runtime ContentProvider runs — which happens after the Application class is loaded.
Android process startup order
1. Application class loaded (static {} runs) ← registerNatives would run HERE
2. Application object instantiated
3. ContentProviders installed
4. MonoRuntimeProvider.attachInfo()
5. → System.loadLibrary("monodroid")
6. → Runtime.initInternal(...) ← Native JNI bridge ready HERE
7. → ApplicationRegistration.registerApplications()
8. Application.onCreate()
How legacy solved it
The legacy CallableWrapperType has a CannotRegisterInStaticConstructor flag (IsApplication || IsInstrumentation) that:
- Skips
Runtime.register(...)in the static block — the__md_methodsstring is built but registration is deferred - Skips
TypeManager.Activate(...)in constructors — normal activation is suppressed - Defers registration to
ApplicationRegistration.registerApplications()— generated byGenerateAdditionalProviderSources.cs, called at step 7 after the runtime is initialized
Relevant legacy code:
CallableWrapperType.cs:36:CannotRegisterInStaticConstructor => IsApplication || IsInstrumentationCallableWrapperType.cs:272-273: skips registration in static blockCallableWrapperConstructor.cs:40: skips activation in ctor bodyGenerateAdditionalProviderSources.cs:116-139: generatesApplicationRegistration.javawith deferred registration calls
What needs to change in the new generator
JavaPeerInfo(or the scanner) needs to expose whether a type is Application/InstrumentationJcwJavaSourceGenerator.WriteStaticInitializer()must skipregisterNativesfor these typesJcwJavaSourceGenerator.WriteConstructors()must skip or adjust thenctor_N()call for these types- The existing
ApplicationRegistrationinfrastructure handles deferred registration — no changes needed there
Note on MonoPackageManager.setContext(this)
The legacy synthetic Application constructor called MonoPackageManager.setContext(this). This is now vestigial — both Mono and CLR runtime variants have // Ignore; vestigial in the method body. Context registration moved to ApplicationRegistration.Context = context during provider startup. No need to replicate this in the new generator.