[tests] Root StartupHook test assembly directly#11280
Merged
jonathanpeppers merged 1 commit intomainfrom May 4, 2026
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR tightens and simplifies trimming roots for the on-device runtime test app (notably rooting the StartupHook test assembly directly), while also extending the trimmable typemap/runtime/test coverage and improving typemap build/packaging plumbing for CoreCLR.
Changes:
- Simplify CoreCLRTrimmable test rooting: use
TrimmerRootAssemblyforStartupHookand switch test assembly roots toRootMode="Visible"under the trimmable typemap path. - Improve trimmable typemap runtime behavior and tests (e.g., cached simple-reference lookup; additional disposal/finalization scenarios; scanner edge cases).
- Adjust typemap generation/emission and MSBuild targets to better support incremental builds and CoreCLR per-ABI packaging, plus fix typemap debug duplicate handling.
Reviewed changes
Copilot reviewed 26 out of 26 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.RuntimeTests/NUnitInstrumentation.cs | Tweaks excluded test list for CoreCLRTrimmable runtime runs. |
| tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj | Updates category exclusions and replaces/adjusts trimmer roots (including StartupHook). |
| tests/Mono.Android-Tests/Mono.Android-Tests/Java.Interop/TrimmableTypeMapTypeManagerTests.cs | Refactors/extends trimmable typemap runtime tests (incl. disposal/finalization coverage). |
| tests/Mono.Android-Tests/Java.Interop-Tests/Java.Interop-Tests.NET.csproj | Compiles a Java.Interop GenericMarshaler helper source directly instead of referencing the external project. |
| tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/TestFixtures/TestTypes.cs | Adds fixture types for nested invoker edge-case coverage. |
| tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Scanner/JavaPeerScannerTests.EdgeCases.cs | Adds regression test for connector nested invoker naming. |
| tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Scanner/JavaPeerScannerTests.cs | Adds content-provider authorities test and minor comment cleanup. |
| tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TypeMapModelBuilderTests.cs | Updates expectations around invoker associations in the model. |
| tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TypeMapAssemblyGeneratorTests.cs | Expands metadata-shape tests for UCO wrappers/ctors and activation ctor referencing. |
| tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/TrimmableTypeMapGeneratorTests.cs | Updates cross-assembly alias merge tests to match current ownership rules. |
| tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/RootTypeMapAssemblyGeneratorTests.cs | Adds validation for merged vs aggregate anchoring behavior in target attributes. |
| tests/Microsoft.Android.Sdk.TrimmableTypeMap.Tests/Generator/FixtureTestBase.cs | Removes IL-token scanning helper no longer needed by generator tests. |
| src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs | Fixes Java→managed debug mapping emission to use the correct duplicate template entry. |
| src/Xamarin.Android.Build.Tasks/Utilities/TypeMapCecilAdapter.cs | Prefers Mono.Android as the template for debug duplicates when present. |
| src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.targets | Moves typemap assembly item population into a dedicated pre-target for incremental correctness. |
| src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.CoreCLR.targets | Refactors CoreCLR typemap-to-store addition to batch across ABIs and depend on the new prepare target. |
| src/Mono.Android/Microsoft.Android.Runtime/TrimmableTypeMapTypeManager.cs | Adds cached/simple-reference resolution that falls back to base-type chain when needed. |
| src/Mono.Android/Microsoft.Android.Runtime/TrimmableTypeMap.cs | Splits native registration into an explicit post-runtime-init step; adds single-run guard. |
| src/Mono.Android/Microsoft.Android.Runtime/ITypeMapWithAliasing.cs | Clarifies interface doc comment around returned types. |
| src/Mono.Android/Android.Runtime/JNIEnvInit.cs | Initializes typemap data earlier and registers typemap natives after JniRuntime.SetCurrent. |
| src/Microsoft.Android.Sdk.TrimmableTypeMap/Scanner/JavaPeerScanner.cs | Normalizes connector-managed type names consistently (nested type separator handling). |
| src/Microsoft.Android.Sdk.TrimmableTypeMap/Scanner/AssemblyIndex.cs | Captures ContentProvider authorities (including ctor array form) into component metadata. |
| src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/TypeMapAssemblyEmitter.cs | Updates emitted UCO wrapper bodies and references internal runtime helpers for exception bridging behavior. |
| src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/RootTypeMapAssemblyGenerator.cs | Emits target attributes differently for merged vs per-assembly universes (anchor selection). |
| src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/PEAssemblyBuilder.cs | Increases default maxstack for emitted bodies with locals to avoid verifier issues. |
| src/Microsoft.Android.Sdk.TrimmableTypeMap/Generator/ModelBuilder.cs | Ensures invoker types get managed→proxy associations where needed; minor string helper update. |
Comment on lines
+85
to
+103
| internal static unsafe void RegisterNativeMethods () | ||
| { | ||
| // Use the `string` overload of `JniType` deliberately. Its underlying | ||
| // `JniEnvironment.Types.TryFindClass(string, bool)` tries raw JNI `FindClass` | ||
| // first and, if that fails, falls back to `Class.forName(name, true, info.Runtime.ClassLoader)`, | ||
| // which resolves via the runtime's app ClassLoader — the same one that loads | ||
| // `mono.android.Runtime` from the APK. | ||
| // The `ReadOnlySpan<byte>` overload (see external/Java.Interop/src/Java.Interop/Java.Interop/JniEnvironment.Types.cs) | ||
| // only calls raw JNI `FindClass`, which resolves via the system ClassLoader on | ||
| // Android and returns a different `Class` instance from the one JCWs reference. | ||
| // Registering natives on that other instance is silently wrong. | ||
| using var runtimeClass = new JniType ("mono/android/Runtime"); | ||
| fixed (byte* name = "registerNatives"u8, sig = "(Ljava/lang/Class;)V"u8) { | ||
| var onRegisterNatives = (IntPtr)(delegate* unmanaged<IntPtr, IntPtr, IntPtr, void>)&OnRegisterNatives; | ||
| var method = new JniNativeMethod (name, sig, onRegisterNatives); | ||
| JniEnvironment.Types.RegisterNatives (runtimeClass.PeerReference, [method]); | ||
| lock (s_initLock) { | ||
| if (s_nativeMethodsRegistered) { | ||
| throw new InvalidOperationException ("TrimmableTypeMap native methods have already been registered."); | ||
| } | ||
|
|
||
| if (s_instance is null) { | ||
| throw new InvalidOperationException ( | ||
| "TrimmableTypeMap has not been initialized. Ensure RuntimeFeature.TrimmableTypeMap is enabled and the JNI runtime is initialized."); | ||
| } | ||
|
|
||
| using var runtimeClass = new JniType ("mono/android/Runtime"u8); | ||
| fixed (byte* name = "registerNatives"u8, sig = "(Ljava/lang/Class;)V"u8) { | ||
| var onRegisterNatives = (IntPtr)(delegate* unmanaged<IntPtr, IntPtr, IntPtr, void>)&OnRegisterNatives; | ||
| var method = new JniNativeMethod (name, sig, onRegisterNatives); | ||
| JniEnvironment.Types.RegisterNatives (runtimeClass.PeerReference, [method]); | ||
| } | ||
| s_nativeMethodsRegistered = true; |
e8a15d3 to
04969c5
Compare
Replace the dedicated StartupHookRoots.xml descriptor with a conditional TrimmerRootAssembly item, matching the rest of the test project roots and avoiding a single-purpose descriptor file. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
5dc9e05 to
f8749ea
Compare
jonathanpeppers
approved these changes
May 4, 2026
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.
Stacked on #11252 via temporary base branch
pr-11252-startup-fixes-base.Follow-up to #11252 (comment).
Replaces the dedicated
StartupHookRoots.xmldescriptor with a conditionalTrimmerRootAssemblyitem forStartupHook. Once #11252 lands, this PR should be retargeted tomainand should still contain only the StartupHook root simplification.Validation: