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_methods string is built but registration is deferred
- Skips
TypeManager.Activate(...) in constructors — normal activation is suppressed
- Defers registration to
ApplicationRegistration.registerApplications() — generated by GenerateAdditionalProviderSources.cs, called at step 7 after the runtime is initialized
Relevant legacy code:
CallableWrapperType.cs:36: CannotRegisterInStaticConstructor => IsApplication || IsInstrumentation
CallableWrapperType.cs:272-273: skips registration in static block
CallableWrapperConstructor.cs:40: skips activation in ctor body
GenerateAdditionalProviderSources.cs:116-139: generates ApplicationRegistration.java with deferred registration calls
What needs to change in the new generator
JavaPeerInfo (or the scanner) needs to expose whether a type is Application/Instrumentation
JcwJavaSourceGenerator.WriteStaticInitializer() must skip registerNatives for these types
JcwJavaSourceGenerator.WriteConstructors() must skip or adjust the nctor_N() call for these types
- The existing
ApplicationRegistration infrastructure 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.
Problem
The new
JcwJavaSourceGeneratorunconditionally emitsmono.android.Runtime.registerNatives(Class)in the static initializer block for every JCW type. For Application and Instrumentation types, this will crash withUnsatisfiedLinkErrorbecause 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
How legacy solved it
The legacy
CallableWrapperTypehas aCannotRegisterInStaticConstructorflag (IsApplication || IsInstrumentation) that:Runtime.register(...)in the static block — the__md_methodsstring is built but registration is deferredTypeManager.Activate(...)in constructors — normal activation is suppressedApplicationRegistration.registerApplications()— generated byGenerateAdditionalProviderSources.cs, called at step 7 after the runtime is initializedRelevant 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 callsWhat 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 typesApplicationRegistrationinfrastructure handles deferred registration — no changes needed thereNote 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; vestigialin the method body. Context registration moved toApplicationRegistration.Context = contextduring provider startup. No need to replicate this in the new generator.