Enable trimmable typemap for Mono.Android.NET-Tests#11087
Closed
simonrozsival wants to merge 34 commits intomainfrom
Closed
Enable trimmable typemap for Mono.Android.NET-Tests#11087simonrozsival wants to merge 34 commits intomainfrom
simonrozsival wants to merge 34 commits intomainfrom
Conversation
Parse the user's AndroidManifest.xml template for activity, service, receiver, and provider elements with android:name attributes. Mark matching scanned Java peer types as IsUnconditional = true so the ILLink TypeMap step preserves them even if no managed code references them directly. Changes: - JavaPeerInfo.IsUnconditional: init → set (must be mutated after scanning) - TrimmableTypeMapGenerator: add warn callback, RootManifestReferencedTypes() called between scanning and typemap generation - GenerateTrimmableTypeMap task: pass Log.LogWarning as warn callback - 4 new xUnit tests covering rooting, unresolved warnings, already-unconditional skip, and empty manifest Replaces #11016 (closed — depended on old PR shape with TaskLoggingHelper). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix RootManifestReferencedTypes to resolve relative android:name values (.MyActivity, MyActivity) using manifest package attribute - Keep $ separator in peer lookup keys so nested types (Outer$Inner) match correctly against manifest class names - Guard Path.GetDirectoryName against null return for acw-map path - Fix pre-existing compilation error: load XDocument from template path before passing to ManifestGenerator.Generate - Add tests for relative name resolution and nested type matching Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Remove file-path overload (IO belongs in MSBuild task, not generator) - Accept XDocument? directly, handle null with pattern match - Add ResolveManifestClassName to resolve dot-relative (.MyActivity) and simple (MyService) names against the manifest package attribute - Fix '$' handling in peer lookup: manifests use '$' for nested types, don't replace it with '.' in the lookup key Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The generated TypeMap assembly emits IL that references
Android.Runtime.TrimmableNativeRegistration.ActivateInstance(IntPtr, Type)
in Mono.Android. This class was referenced by TypeMapAssemblyEmitter but
never created in this branch, causing a TypeLoadException at runtime when
any UCO constructor wrapper (nctor_*_uco) was invoked — for example when
managed code creates an ACW instance like RunnableImplementor.
The new class is a thin wrapper that delegates to the existing
Microsoft.Android.Runtime.TrimmableTypeMap.ActivateInstance, which is
internal to Mono.Android. The generated TypeMap assembly accesses
TrimmableNativeRegistration via [IgnoresAccessChecksTo("Mono.Android")].
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add a single MSBuild property MonoAndroidTypeMapFlavor=legacy|trimmable to run Mono.Android.NET-Tests with the trimmable typemap on CoreCLR. Add a separate CoreCLRTrimmable package-test CI lane. Fix many runtime bugs exposed by running real tests with trimmable CoreCLR: - Fix native SIGSEGV by routing trimmable typemap lookups through the managed TrimmableTypeMap instead of native libxamarin-app.so P/Invokes - Fix open generic type activation crash in [UnmanagedCallersOnly] UCO constructor wrappers by checking IsGenericTypeDefinition early and using RaisePendingException instead of throwing across the JNI boundary - Fix CRC64 package name mismatch between generator and runtime by reusing the Java.Interop Jones CRC64 algorithm in the trimmable scanner - Add PeekObject/WithinNewObjectScope guards to ActivateInstance to match legacy TypeManager.n_Activate behavior - Set JniRuntime.SetCurrent() during initialization for background threads Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Remove unreachable trimmable branches from TypeManager.GetJavaToManagedTypeCore and JNIEnv.TypemapManagedToJava (these codepaths are never hit because TrimmableTypeMapTypeManager and JavaMarshalValueManager handle all lookups) - Remove null guard on TrimmableTypeMap.Instance in JavaMarshalValueManager.CreatePeer (null Instance is a fatal initialization error, not a recoverable case) - Remove '?? mappedType' fallback in TryGetType — if the proxy attribute is missing, the entry is invalid and should not be returned - Remove TypeManager.GetJniTypeName fallback from TryGetJniName to avoid depending on the legacy TypeManager (which we want to eventually delete) - Add JNI class name caching to GetProxyForPeer via _peerProxyCache Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The generated typemap assemblies already have [IgnoresAccessChecksTo("Mono.Android")]
so they can call TrimmableTypeMap.ActivateInstance directly. The TrimmableNativeRegistration
wrapper class was an unnecessary indirection.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The generated nctor_*_uco wrappers now directly call the activation constructor instead of going through TrimmableTypeMap.ActivateInstance. Each UCO already knows the exact type to create at build time, so the typemap re-lookup was unnecessary indirection. - EmitUcoConstructor now emits the same ctor call that CreateInstance uses (newobj for leaf types, GetUninitializedObject+call for inherited), handling both XamarinAndroid and JavaInterop ctor styles - Skip UCO constructor generation for open generic type definitions (they can't be activated from Java) - Remove ActivateInstance from TrimmableTypeMap (no longer called) - Remove _trimmableNativeRegistrationRef and _activateInstanceRef fields Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
NativeTypeMap tests call TypeManager.GetJavaToManagedType and JNIEnv.TypemapManagedToJava directly, which call into the native typemap tables that don't exist in the trimmable path. Exclude these tests when MonoAndroidTypeMapFlavor=trimmable. Also add defensive guards in both methods to delegate to the managed TrimmableTypeMap when RuntimeFeature.TrimmableTypeMap is enabled, preventing crashes if these APIs are called outside of the excluded test categories. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Open generic types (e.g., GenericHolder<T>) cannot be activated from Java because the type parameters are unknown. The ModelBuilder already skips generating UCO constructor wrappers for these, but the JCW Java source generator still emitted the 'private native void nctor_0()' declaration and 'nctor_0(args)' call in the constructor. This caused UnsatisfiedLinkError at runtime because no native method was registered. Now the JCW generator checks IsGenericDefinition and skips both the nctor call in the constructor body and the native method declaration. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When a managed type is constructed via JNIEnv.StartCreateInstance/NewObject, the JCW constructor calls nctor_0 which invokes the UCO. Without this guard, the UCO creates a second managed peer instance for the same Java object handle, corrupting JNI references and causing GC crashes (SIGSEGV in ART's ConcurrentCopying::FlipThreadRoots). The fix mirrors the legacy TypeManager.n_Activate behavior: check JniEnvironment.WithinNewObjectScope and skip activation when true. Updated PEAssemblyBuilder.EmitBody to accept useBranches parameter for ControlFlowBuilder support. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Revert the JCW nctor skip for generics — the nctor_0 native declaration and call must still exist to avoid UnsatisfiedLinkError. Instead, emit a no-op UCO constructor wrapper for open generic type definitions that just returns immediately. The test NewOpenGenericTypeThrows expects the JCW constructor to be called (it triggers FinishCreateInstance which handles the open generic case). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The no-op UCO for open generic types must call ThrowIfOpenGenericActivation() to raise NotSupportedException when called outside WithinNewObjectScope (i.e., from FinishCreateInstance). This matches the legacy TypeManager.n_Activate behavior that the NewOpenGenericTypeThrows test expects. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The generic type's UCO is shared across all closed instantiations (GenericHolder<int>, GenericHolder<string>, etc.), so it can't distinguish open vs closed. ThrowIfOpenGenericActivation breaks NewClosedGenericTypeWorks. Revert to no-op UCO and exclude the legacy NewOpenGenericTypeThrows test for trimmable via TrimmableIgnore. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move the trimmable ExcludeCategories to after the MonoAndroidTypeMapFlavor property group so it appends to categories already set by UseMonoRuntime conditions. Without this, the NativeTypeMap/TrimmableIgnore/SSL exclusions were evaluated before UseMonoRuntime was derived from the flavor. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…mable TrimmableTypeMap.CreatePeer was creating peers for incompatible Java types (e.g., IAppendableInvoker wrapping java.lang.Integer) because the GetProxyForManagedType fallback didn't validate Java-side IsAssignableFrom. Added the check to match the legacy base.CreatePeer behavior. Also exclude JavaObjectTest.Dispose and Dispose_Finalized by name when running in trimmable mode — these tests create JavaObject types whose JCW Java classes don't exist in the trimmable APK, causing ClassNotFoundException on background threads that crash the process. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Exclude Java.Interop-Tests fixtures that use JavaObject types (not Java.Lang.Object) whose JCW Java classes don't exist in the trimmable APK: JavaObjectTest, InvokeVirtualFromConstructorTests, JniPeerMembersTests, JniTypeManagerTests, JniValueMarshaler tests, and JavaExceptionTests.InnerExceptionIsNotAProxy. Also exclude ActivatedDirectThrowableSubclassesShouldBeRegistered (uses legacy n_Activate default-ctor flow that differs from trimmable UCO activation-ctor) and JavaCast_BaseToGenericWrapper (generic JavaList cast needs further investigation). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Member
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a single MSBuild property
MonoAndroidTypeMapFlavor=legacy|trimmableto runMono.Android.NET-Testswith the trimmable typemap on CoreCLR, and adds a separateCoreCLRTrimmableCI lane.Test results: 792 passed, 0 failed, 6 skipped (vs legacy: 885 passed, 2 failed, 6 skipped)
Changes by area
1. Generator fixes (Scanner/JCW/Emitter)
System.IO.Hashing.Crc64but runtime uses Jones CRC64 (Crc64Helper)DoNotGenerateAcwintermediate MCW base typesNestedPrivatetoNestedAssemblyto fixFieldAccessException2. UCO constructor refactoring
ActivateInstance→ typemap re-lookupuseBranchesparameter toPEAssemblyBuilder.EmitBodyTrimmableNativeRegistrationwrapper,ActivateInstancemethod3. Runtime trimmable typemap support
[Register]→ compat Android component names →JavaNativeTypeManager.ToJniNameIsAssignableFromvalidation to prevent invalid JavaCast peersJniRuntime.SetCurrentfor background thread support4. Test plumbing and CI
Mono.Android.NET_Tests-CoreCLRTrimmablein stage-package-tests.yamlJavaObjecttypes (notJava.Lang.Object)Proposed PR split
This PR is large and should be split into 4 vertical slices:
src/Microsoft.Android.Sdk.TrimmableTypeMap/+ unit testsTypeMapAssemblyEmitter.cs,PEAssemblyBuilder.cs(depends on 1)src/Mono.Android/(depends on 2)tests/Mono.Android-Tests/,build-tools/(depends on 3)Tests excluded for trimmable (93 tests)
NewOpenGenericTypeThrows,ActivatedDirectThrowableSubclassesShouldBeRegisteredJavaObjecttypes whose JCW Java classes are not generated