Skip to content

[TrimmableTypeMap] Root manifest-referenced types as unconditional#11016

Draft
simonrozsival wants to merge 2 commits intodev/simonrozsival/trimmable-typemap-build-pipelinefrom
dev/simonrozsival/trimmable-typemap-post-manifest-rooting
Draft

[TrimmableTypeMap] Root manifest-referenced types as unconditional#11016
simonrozsival wants to merge 2 commits intodev/simonrozsival/trimmable-typemap-build-pipelinefrom
dev/simonrozsival/trimmable-typemap-post-manifest-rooting

Conversation

@simonrozsival
Copy link
Member

Part of #10807
Depends on #10980

Summary

Ensures types declared only in hand-edited AndroidManifest.xml (no C# component attribute) are marked as unconditional and survive trimming.

Problem

A user can hand-edit their manifest with <activity android:name="com.example.MyLegacyActivity" /> where the type has [Register] but no [Activity] attribute. Without this fix, the scanner treats it as a conditional peer (3-arg TypeMapAttribute) and the linker may trim it → runtime crash.

Changes

  • JavaPeerInfo.cs: Changed IsUnconditional from init to set so it can be mutated after scanning
  • GenerateTrimmableTypeMap.cs: Added RootManifestReferencedTypes() that parses ManifestTemplate XML, extracts android:name values, and marks matching peers as unconditional
  • Tests: Verifies rooting works for known types and warns for missing types

// Multiple managed types can map to the same Java name (aliases).
var peersByDotName = new Dictionary<string, List<JavaPeerInfo>> (StringComparer.Ordinal);
foreach (var peer in allPeers) {
var dotName = peer.JavaName.Replace ('/', '.');
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is not enough - nested types would have $ that also needs to be replaced with . to form valid Java name. Is this the same problem we had elsewhere? Should this be a helper method? Or is there an existing helper method we could use?

Comment on lines +281 to +289
var manifestPath = Path.Combine (manifestDir, "AndroidManifest.xml");
File.WriteAllText (manifestPath, """
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.test">
<application>
<activity android:name="android.app.Activity" />
</application>
</manifest>
""");
Copy link
Member Author

@simonrozsival simonrozsival Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we do this without writing to a file? Can we somehow change this to use memory stream instead? I believe we could just change GenerateTrimmableTypeMap so it expects the ManifestTemplate to be the memory stream (+ of course use memory stream pooling!)

@simonrozsival simonrozsival force-pushed the dev/simonrozsival/trimmable-typemap-build-pipeline branch from 6f42b4d to 384a5a8 Compare March 25, 2026 16:16
simonrozsival and others added 2 commits March 25, 2026 17:17
When users hand-edit AndroidManifest.xml with component entries that have
no corresponding C# attribute (e.g. [Activity]), the referenced types
may be trimmed by the linker, causing runtime crashes when Android tries
to launch them.

This change adds RootManifestReferencedTypes() which parses the manifest
template before typemap assembly generation, finds matching peers by
their Java name, and marks them as unconditional so the linker preserves
them. A warning is logged for manifest-referenced types not found in any
scanned assembly (likely framework types).

Changes:
- JavaPeerInfo.IsUnconditional: changed from init to set
- GenerateTrimmableTypeMap: added RootManifestReferencedTypes method
- Added two tests for rooting and warning behavior

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Parse the user's AndroidManifest.xml template to find hand-edited
component entries (activity, service, receiver, provider) and mark
matching Java peers as unconditional so they survive trimming.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@simonrozsival simonrozsival force-pushed the dev/simonrozsival/trimmable-typemap-post-manifest-rooting branch from 1a0330a to 6831cef Compare March 25, 2026 16:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant