Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
163 commits
Select commit Hold shift + click to select a range
6bae3ac
[TrimmableTypeMap] Remove post-trim generation pass
simonrozsival Jun 8, 2026
579ea8a
Bump external/Java.Interop from `b881d21` to `d7dbad5`
dependabot[bot] Jun 10, 2026
f79c0cc
Implement Android JavaMarshal value manager split
simonrozsival Jun 9, 2026
676dca4
Use pure trimmable typemap value manager
simonrozsival Jun 9, 2026
01dfd04
Use pure trimmable typemap type manager
simonrozsival Jun 9, 2026
b77c841
Propagate trimmable typemap DAM annotations
simonrozsival Jun 9, 2026
0554d57
Prefer Requires annotations for reflection managers
simonrozsival Jun 9, 2026
7d81397
Remove manager suppression attributes
simonrozsival Jun 9, 2026
1fe2ef5
Remove invoker lookup suppression attributes
simonrozsival Jun 9, 2026
7228982
Use feature guards for runtime manager selection
simonrozsival Jun 9, 2026
326f0fd
Inline CoreCLR JavaMarshal peer delegation
simonrozsival Jun 9, 2026
6a8ec68
Throw unreachable from trimmable native registration
simonrozsival Jun 9, 2026
7d3d1e3
Remove SimpleValueManager
simonrozsival Jun 10, 2026
725d433
Simplify changes to the ManagedTypeManager
simonrozsival Jun 10, 2026
caaea85
Remove the option to use ManagedTypeManager
simonrozsival Jun 10, 2026
b489d1f
Cleanup value managers
simonrozsival Jun 10, 2026
f1ce2a2
Refine trimmable typemap runtime paths
simonrozsival Jun 10, 2026
0a1072a
Reuse Java.Interop value marshalers in trimmable runtime
simonrozsival Jun 11, 2026
78cb7d6
Support JavaObjectArray in trimmable value marshaling
simonrozsival Jun 11, 2026
169bc8f
Generalize trimmable primitive value marshaling
simonrozsival Jun 11, 2026
869f183
Apply trimmable test exclusions to new runner
simonrozsival Jun 11, 2026
93ddc73
Remove LayoutInflater test contamination
simonrozsival Jun 11, 2026
933a38d
Address trimmable review cleanup
simonrozsival Jun 11, 2026
65a2cf5
Flow excluded NUnit categories from MSBuild
simonrozsival Jun 11, 2026
6b4aedb
Extract trimmable primitive marshaler helpers
simonrozsival Jun 11, 2026
80997b8
Address trimmable review feedback
simonrozsival Jun 11, 2026
6071fd0
Support trimmable custom value marshalers
simonrozsival Jun 11, 2026
d45a519
Unwrap trimmable proxy throwables
simonrozsival Jun 11, 2026
4282882
Support trimmable type manager lookups
simonrozsival Jun 11, 2026
152845b
Use trimmable CrossReferenceBridge fixture
simonrozsival Jun 11, 2026
8105789
Use trimmable method binding fixtures
simonrozsival Jun 11, 2026
7a7ca23
Support trimmable marshaler expressions
simonrozsival Jun 11, 2026
fece7d7
Remove generated value marshaler registry
simonrozsival Jun 11, 2026
b134621
Address trimmable test review feedback
simonrozsival Jun 11, 2026
6e1a69a
Fix trimmable typemap CI failures
simonrozsival Jun 12, 2026
8447f63
Simplify generated proxy trim suppression
simonrozsival Jun 12, 2026
18f39bc
Address trimmable runtime review feedback
simonrozsival Jun 12, 2026
4e40404
Clean stale trimmable typemap Java sources
simonrozsival Jun 12, 2026
7496a32
Simplify trimmable marshaler integration
simonrozsival Jun 12, 2026
f2c59bd
Re-enable trimmable GC bridge coverage
simonrozsival Jun 12, 2026
298f262
Re-enable trimmable replacement method lookup test
simonrozsival Jun 12, 2026
7ab9659
Re-enable trimmable method binding coverage
simonrozsival Jun 12, 2026
12946a7
Remove JavaProxyThrowable Exception wrapper
simonrozsival Jun 12, 2026
1cae90b
Remove ManagedPeer workarounds from trimmable PR
simonrozsival Jun 12, 2026
a53fb70
Document built-in type signature mapping choice
simonrozsival Jun 12, 2026
25a0526
Split Java marshal value manager types
simonrozsival Jun 12, 2026
a5b39d1
Simplify trimmable object array marshaling
simonrozsival Jun 12, 2026
5dff3a8
Return object references from trimmable marshaling
simonrozsival Jun 12, 2026
f928f99
Clarify trimmable local reference ownership
simonrozsival Jun 12, 2026
66c29f3
Merge origin/main into dev/simonrozsival/java-interop-1441-android
simonrozsival Jun 17, 2026
f7b0fec
Fix AndroidRuntime merge follow-ups
simonrozsival Jun 17, 2026
39583fa
Update tests + cleanup
simonrozsival Jun 17, 2026
db14c80
Remove unnecessary code
simonrozsival Jun 17, 2026
4bbc8fa
Merge remote-tracking branch 'origin/main' into android-remove-second…
Copilot Jun 17, 2026
a23c1f2
Merge latest main, resolve conflicts (keep post-trim pass removal)
Copilot Jun 17, 2026
7412129
Fix more stuff
simonrozsival Jun 17, 2026
6a0b25f
Merge remote-tracking branch 'origin/main' into dev/simonrozsival/jav…
simonrozsival Jun 17, 2026
dcdfbae
Use Java.Interop from main
simonrozsival Jun 17, 2026
89e133e
Merge PR #11604 post-trim typemap cleanup
simonrozsival Jun 18, 2026
d95a356
Remove unnecessary MakeArrayType
simonrozsival Jun 18, 2026
2ba985f
Annotate JNINativeWrapper.CreateDelegate method
simonrozsival Jun 18, 2026
8ec4aee
Drop assertions which expect AOT and trimming warnings
simonrozsival Jun 18, 2026
200b6a4
Update apkdesc files
simonrozsival Jun 18, 2026
0aa8bad
Avoid more MakeArrayType
simonrozsival Jun 18, 2026
ebc9b9e
Suppress expected runtime manager trim warnings
simonrozsival Jun 18, 2026
46bb3ff
We removed AOT warning, do not assert that there will be a warning
simonrozsival Jun 18, 2026
1392c44
Address trimmable typemap review feedback
simonrozsival Jun 18, 2026
d4dd398
[TrimmableTypeMap] Support built-in reference arrays
simonrozsival Jun 18, 2026
b76c959
[TrimmableTypeMap] Prefer dynamic array creation on CoreCLR
simonrozsival Jun 19, 2026
94eeb39
Merge branch 'main' of github.com:dotnet/android into dev/simonrozsiv…
simonrozsival Jun 22, 2026
9b41a8f
[typemap] Fix trimmable typemap CI failures
simonrozsival Jun 22, 2026
2a12f82
[typemap] Include runtime version in root fingerprint
simonrozsival Jun 22, 2026
48a1e77
[typemap] Extract deterministic hash builder
simonrozsival Jun 22, 2026
46bf686
[typemap] Restore span-based MVID hashing
simonrozsival Jun 22, 2026
a9336e4
[typemap] Keep NativeAOT managed typemap default
simonrozsival Jun 22, 2026
c2522ea
[typemap] Restore managed NativeAOT runtime managers
simonrozsival Jun 22, 2026
1d45090
Revert "[typemap] Restore managed NativeAOT runtime managers"
simonrozsival Jun 22, 2026
a0d0fb7
Revert "[typemap] Keep NativeAOT managed typemap default"
simonrozsival Jun 22, 2026
f54ef34
[deps] Update android-tools for task hashing compatibility
simonrozsival Jun 22, 2026
b50a4c8
[runtime] Proxy opaque objects in trimmable value manager
simonrozsival Jun 22, 2026
0152cc1
Merge remote-tracking branch 'origin/main' into dev/simonrozsival/jav…
simonrozsival Jun 22, 2026
ef8cbb3
[deps] Update android-tools task hashing fix
simonrozsival Jun 22, 2026
78efb4f
[runtime] Override Java proxy object methods
simonrozsival Jun 23, 2026
705fc27
[runtime] Override Java proxy object methods
simonrozsival Jun 23, 2026
9d5110b
Remove DAM where they're causing more harm than good
simonrozsival Jun 23, 2026
c6bafae
Merge remote-tracking branch 'origin/main' into dev/simonrozsival/jav…
simonrozsival Jun 23, 2026
97eb32e
[runtime] Disable ManagedPeer for trimmable apps
simonrozsival Jun 23, 2026
158fa0c
Merge remote-tracking branch 'origin/dev/simonrozsival/java-interop-1…
simonrozsival Jun 23, 2026
828dbe9
Improve array handling
simonrozsival Jun 23, 2026
8a8cbde
Clean-up trimmable value manager
simonrozsival Jun 23, 2026
33de611
Add support for nullable primitive types without unwrapping Nullable
simonrozsival Jun 23, 2026
2d5fef1
Fix incrementality
simonrozsival Jun 24, 2026
6645710
Temporary bump to external/Java.Interop
simonrozsival Jun 24, 2026
840d342
Revert "Temporary bump to external/Java.Interop"
simonrozsival Jun 24, 2026
18f3b9d
Merge branch 'main' of github.com:dotnet/android into dev/simonrozsiv…
simonrozsival Jun 24, 2026
8fe902d
Temporary bump to external/Java.Interop
simonrozsival Jun 24, 2026
f8964c7
Temporary bump to external/Java.Interop
simonrozsival Jun 24, 2026
9d3217b
Reuse array handling code between the type and value managers
simonrozsival Jun 24, 2026
4f23922
Redo array type mapping for Native AOT
simonrozsival Jun 24, 2026
dcf1c96
Bump Java.Interop to 8d54473
simonrozsival Jun 24, 2026
9bd6825
Preserve trimmable array proxies for wrapper types
simonrozsival Jun 24, 2026
8d5969d
Fix array proxy association duplication
simonrozsival Jun 24, 2026
a05be93
Scope array proxy associations to rank maps
simonrozsival Jun 24, 2026
dd3155c
Use reverse typemap entries for peer proxy lookup
simonrozsival Jun 24, 2026
fc65df3
Use array types as array proxy trim targets
simonrozsival Jun 24, 2026
5c20adc
Revert "Use array types as array proxy trim targets"
simonrozsival Jun 24, 2026
ea922d4
Fix collections of generic types
simonrozsival Jun 24, 2026
87cea50
Fix trimmable collection wrapper reuse
simonrozsival Jun 25, 2026
e966fd5
Skip unresolvable trimmable typemap peers
simonrozsival Jun 25, 2026
54a0df4
Update package versions to avoid test failures
simonrozsival Jun 25, 2026
f1a1491
Simplify SmokeTestBuildWithSpecialCharacters test
simonrozsival Jun 25, 2026
62652db
Refactor ModelBuilder and SingleUniverseTypeMap to remove ManagedType…
simonrozsival Jun 25, 2026
7c75e61
Fix inherited generic base typemap refs
simonrozsival Jun 25, 2026
6d5ca25
Fix package version
simonrozsival Jun 25, 2026
4c0d418
Restore typemap proxy associations
simonrozsival Jun 25, 2026
003e118
Fix msbuild
simonrozsival Jun 25, 2026
48288f0
Update msbuild targets
simonrozsival Jun 25, 2026
45a7e62
Fix typo
simonrozsival Jun 25, 2026
68c438b
Avoid null dereference
simonrozsival Jun 25, 2026
807df5f
Fix trimmable value manager create semantics
simonrozsival Jun 25, 2026
c82b464
Fix trimmable manifest generation parity
simonrozsival Jun 25, 2026
ef8085f
Fix NativeAOT trimmable build integration
simonrozsival Jun 25, 2026
d13fde4
Revert accidental android tools submodule bump
simonrozsival Jun 25, 2026
a7ea92e
Preserve NativeAOT proguard keep rules
simonrozsival Jun 25, 2026
21e297b
Write NativeAOT keep rules to primary proguard config
simonrozsival Jun 25, 2026
d86671f
Stop R8 from generating NativeAOT app keep config
simonrozsival Jun 25, 2026
5c8463c
Disable NativeAOT DGML proguard filtering
simonrozsival Jun 25, 2026
24186b8
Accept NativeAOT R8 mapping output in DotNetBuild test
simonrozsival Jun 25, 2026
7ef0463
[typemap] Restore NativeAOT managed typemap default
simonrozsival Jun 25, 2026
71adeb2
Switch back to ManagedTypeManager as the default for NativeAOT
simonrozsival Jun 26, 2026
425542a
Default NativeAOT to trimmable typemaps
simonrozsival Jun 26, 2026
05d1451
[Tests] Skip NativeAOT tests that inspect illink's `linked/` output
simonrozsival Jun 26, 2026
fbcd702
[Tests] Fully skip BuildReleaseArm64 on NativeAOT
simonrozsival Jun 26, 2026
fe41750
[TrimmableTypeMap] Fix manifest content gaps on NativeAOT (B2)
simonrozsival Jun 26, 2026
4a1f51e
[TrimmableTypeMap] Complete activity manifest attribute mappings (B2)
simonrozsival Jun 26, 2026
7d44fd4
[TrimmableTypeMap] Produce android/AndroidManifest.xml for the legacy…
simonrozsival Jun 26, 2026
9bf113b
[TrimmableTypeMap] Resolve parentActivityName and fix persistableMode…
simonrozsival Jun 26, 2026
107ece2
Fix uses-sdk without specifying min version
simonrozsival Jun 26, 2026
5dd97b0
[build] Guard staging-dir globs when extraction is skipped
simonrozsival Jun 27, 2026
6a1555a
[Tests] Adjust NativeAOT cases for unsupported/different-trimmer beha…
simonrozsival Jun 27, 2026
49f3378
[TrimmableTypeMap] Honor AndroidApplicationJavaClass for the JCW base…
simonrozsival Jun 27, 2026
44c9a98
[Tests] Expect trimmable scrc64 JCW package names on NativeAOT (J2)
simonrozsival Jun 27, 2026
b7977de
[TrimmableTypeMap] Sort component manifest attributes alphabetically
simonrozsival Jun 27, 2026
494d0e6
[TrimmableTypeMap] Warn XA1010 for invalid manifest placeholders
simonrozsival Jun 27, 2026
c892216
[TrimmableTypeMap] Resolve placeholder package names in the manifest
simonrozsival Jun 27, 2026
ae860a4
[TrimmableTypeMap] Normalize manifest placeholder values like the leg…
simonrozsival Jun 27, 2026
570afc8
[TrimmableTypeMap] Don't touch typemap assemblies so incremental buil…
simonrozsival Jun 27, 2026
79a144c
[TrimmableTypeMap] Direct-dispatch interface-implementation proxy met…
simonrozsival Jun 27, 2026
552e290
[TrimmableTypeMap] Use non-generic JavaPeerProxy base for interface p…
simonrozsival Jun 27, 2026
3ea9d59
[TrimmableTypeMap] Run FixLegacyResourceDesigner before ILC on NativeAOT
simonrozsival Jun 27, 2026
40cf921
[Tests] Fix GenerateTrimmableTypeMapTests for string[] ManifestPlaceh…
simonrozsival Jun 27, 2026
97ba631
Remove more suppressions
simonrozsival Jun 27, 2026
99511eb
Fix null ref warning
simonrozsival Jun 27, 2026
cb09b6e
[TrimmableTypeMap] Merge library manifests for the legacy manifest me…
simonrozsival Jun 27, 2026
7611484
[Tests] ExportedErrorMessage: assert AMM0000 code, not exact line, on…
simonrozsival Jun 27, 2026
9a0d987
[TrimmableTypeMap] Don't direct-dispatch interface-implementation met…
simonrozsival Jun 27, 2026
b5d106f
Merge branch 'main' into dev/simonrozsival/java-interop-1441-android
simonrozsival Jun 27, 2026
5293815
[Tests] Ignore flaky BuildReleaseArm64
simonrozsival Jun 27, 2026
efae987
[TrimmableTypeMap] Fix DesignTimeBuildSignAndroidPackage on NativeAOT
simonrozsival Jun 27, 2026
9e74ff7
[TrimmableTypeMap] Keep user AndroidJavaSource Java under R8 shrinking
simonrozsival Jun 27, 2026
31bfd46
[Mono.Android] Fix IL2077 build break in JavaConvert.ArrayElementConv…
simonrozsival Jun 27, 2026
a6cd268
[TrimmableTypeMap] Don't stage shrunk assemblies into the shared runt…
simonrozsival Jun 28, 2026
140d9a8
[TrimmableTypeMap] Gate IDE-sign typemap target on _OuterIntermediate…
simonrozsival Jun 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Documentation/docs-mobile/messages/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,7 @@ Either change the value in the AndroidManifest.xml to match the $(SupportedOSPla
+ [XA4250](xa4250.md): Manifest-referenced type '{type}' was not found in any scanned assembly. It may be a framework type.
+ [XA4252](xa4252.md): Insecure HTTP Maven repository URL '{url}' is not allowed. Use an HTTPS URL, or set AllowInsecureHttp="true" metadata on the item to override this check.
+ [XA4253](xa4253.md): Generated Java callable wrapper code changed: '{path}'
+ [XA4254](xa4254.md): Trimmable type map Java source input directory '{input}' and output directory '{output}' must be different.
+ [XA4255](xa4255.md): Generated trimmable type map Java source '{path}' was not found.
+ [XA4256](xa4256.md): Skipping Java peer type '{type}' from assembly '{assembly}' because referenced type '{referencedType}' from assembly '{referencedAssembly}' could not be resolved in '{path}'. This type will not be included in the trimmable type map.
+ XA4300: Native library '{library}' will not be bundled because it has an unsupported ABI.
+ [XA4301](xa4301.md): Apk already contains the item `xxx`.
+ [XA4302](xa4302.md): Unhandled exception merging \`AndroidManifest.xml\`: {ex}
Expand Down
25 changes: 0 additions & 25 deletions Documentation/docs-mobile/messages/xa4254.md

This file was deleted.

27 changes: 0 additions & 27 deletions Documentation/docs-mobile/messages/xa4255.md

This file was deleted.

27 changes: 27 additions & 0 deletions Documentation/docs-mobile/messages/xa4256.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
title: .NET for Android warning XA4256
description: XA4256 warning code
ms.date: 06/25/2026
f1_keywords:
- "XA4256"
---

# .NET for Android warning XA4256

## Example message

```
warning XA4256: Skipping Java peer type 'Google.Android.Material.Shadow.ShadowDrawableWrapper' from assembly 'Xamarin.Google.Android.Material' because referenced type 'AndroidX.AppCompat.Graphics.Drawable.DrawableWrapper' from assembly 'Xamarin.AndroidX.AppCompat.AppCompatResources' could not be resolved in '/home/user/.nuget/packages/xamarin.androidx.appcompat.appcompatresources/1.6.0/lib/net6.0-android31.0/Xamarin.AndroidX.AppCompat.AppCompatResources.dll'. This type will not be included in the trimmable type map.
```

## Issue

The trimmable type map found a Java peer type whose managed base type or implemented interface references a type that is not present in the resolved assembly set.

This can happen when NuGet packages in the Android binding graph were built against different versions of another binding package. The type may be unused by the app, but NativeAOT compiles a closed world and must resolve rooted managed types eagerly.

## Solution

If your app uses the skipped type, update the affected NuGet packages so the referenced type exists, or update to versions of the binding packages that are compatible with each other.

If your app does not use the skipped type, no action is required. The type is omitted from the trimmable type map so NativeAOT does not fail while resolving unused stale metadata.
2 changes: 1 addition & 1 deletion external/xamarin-android-tools
1 change: 1 addition & 0 deletions samples/HelloWorld/HelloWorld/HelloWorld.DotNet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<TargetFramework>$(DotNetAndroidTargetFramework)</TargetFramework>
<OutputType>Exe</OutputType>
<RootNamespace>HelloWorld</RootNamespace>
<PublishAot>true</PublishAot>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\HelloLibrary\HelloLibrary.DotNet.csproj" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ static NativeAotRuntimeOptions CreateJreVM (NativeAotRuntimeOptions builder)
builder.TypeManager ??= CreateDefaultTypeManager ();
#endif // NET

builder.ValueManager ??= new JavaMarshalValueManager ();
builder.ValueManager ??= Android.Runtime.JNIEnvInit.CreateValueManager ();
builder.ObjectReferenceManager ??= new Android.Runtime.AndroidObjectReferenceManager ();

if (builder.InvocationPointer != IntPtr.Zero || builder.EnvironmentPointer != IntPtr.Zero)
Expand All @@ -81,7 +81,7 @@ static JniRuntime.JniTypeManager CreateDefaultTypeManager ()
return new TrimmableTypeMapTypeManager ();
}

return new ManagedTypeManager ();
throw new NotImplementedException ();
}

public override string? GetCurrentManagedThreadName ()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
<type fullname="Android.Runtime.RaiseThrowableEventArgs" />
<type fullname="Android.Runtime.RegisterAttribute" />
<type fullname="Android.Runtime.TypeManager" />
<type fullname="Microsoft.Android.Runtime.ManagedTypeMapping" preserve="all" />
<!--
<type fullname="Android.Runtime.XmlResourceParserReader" />
<type fullname="Android.Runtime.XmlPullParserReader" />
Expand Down
5 changes: 5 additions & 0 deletions src/Microsoft.Android.Sdk.TrimmableTypeMap/AssemblyInput.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using System.Reflection.PortableExecutable;

namespace Microsoft.Android.Sdk.TrimmableTypeMap;

public readonly record struct AssemblyInput (string Name, string Path, PEReader Reader);
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ static class AndroidEnumConverter
_ => null,
};

public static string? RotationAnimationToString (int value) => value switch {
0 => "rotate",
1 => "crossfade",
2 => "jumpcut",
3 => "seamless",
_ => null,
};

public static string? ScreenOrientationToString (int value, int targetSdkVersion = 0) => value switch {
-1 => "unspecified",
0 => "landscape",
Expand Down Expand Up @@ -126,8 +134,8 @@ static class AndroidEnumConverter

public static string? ActivityPersistableModeToString (int value) => value switch {
0 => "persistRootOnly",
1 => "persistAcrossReboots",
2 => "persistNever",
1 => "persistNever",
2 => "persistAcrossReboots",
_ => null,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ static class ComponentElementBuilder
static readonly XNamespace AndroidNs = ManifestConstants.AndroidNs;
static readonly XName AttName = ManifestConstants.AttName;

internal static XElement? CreateComponentElement (JavaPeerInfo peer, string jniName, int targetSdkVersion = 0)
internal static XElement? CreateComponentElement (JavaPeerInfo peer, string jniName, int targetSdkVersion = 0, IReadOnlyDictionary<string, string>? managedToManifestNames = null)
{
var component = peer.ComponentAttribute;
if (component is null) {
Expand All @@ -34,11 +34,24 @@ static class ComponentElementBuilder
// Map known properties to android: attributes
PropertyMapper.MapComponentProperties (element, component, targetSdkVersion);

// android:parentActivityName comes from a [Activity (ParentActivity = typeof (...))] and is
// captured as the managed type name. Resolve it to the parent's Java/manifest name, matching
// the legacy ManifestDocument behavior (JavaNativeTypeManager.ToJniName).
ResolveParentActivityName (element, managedToManifestNames);

// Add intent filters
foreach (var intentFilter in component.IntentFilters) {
element.Add (CreateIntentFilterElement (intentFilter));
}

// Add <layout> element from a [Layout] attribute, if present
if (component.LayoutProperties is not null) {
var layout = CreateLayoutElement (component.LayoutProperties);
if (layout is not null) {
element.Add (layout);
}
}

// Handle MainLauncher for activities
if (component.Kind == ComponentKind.Activity && component.Properties.TryGetValue ("MainLauncher", out var ml) && ml is bool b && b) {
AddLauncherIntentFilter (element);
Expand All @@ -49,9 +62,54 @@ static class ComponentElementBuilder
element.Add (CreateMetaDataElement (meta));
}

// The legacy ManifestDocumentElement.ToElement sorts attributes alphabetically
// (specified.OrderBy (e => e)). Match that ordering so the generated manifest is
// byte-compatible with the legacy path when AndroidManifestMerger='legacy' (the
// manifestmerger.jar path re-sorts attributes itself, so this is also safe there).
SortAttributesAlphabetically (element);

return element;
}

// Reorders an element's attributes alphabetically by local name (case-insensitive),
// matching the legacy manifest generator's attribute ordering.
static void SortAttributesAlphabetically (XElement element)
{
var sorted = element.Attributes ()
.OrderBy (a => a.Name.LocalName, StringComparer.OrdinalIgnoreCase)
.ToList ();
if (sorted.Count < 2) {
return;
}
foreach (var attr in element.Attributes ().ToList ()) {
attr.Remove ();
}
foreach (var attr in sorted) {
element.Add (attr);
}
}

static void ResolveParentActivityName (XElement element, IReadOnlyDictionary<string, string>? managedToManifestNames)
{
if (managedToManifestNames is null) {
return;
}

var attr = element.Attribute (AndroidNs + "parentActivityName");
if (attr is null) {
return;
}

// The value may be assembly-qualified ("Foo.Bar, Asm [Version=...]"); use the type name part.
var value = attr.Value;
int comma = value.IndexOf (',');
var typeName = (comma < 0 ? value : value.Substring (0, comma)).Trim ();

if (managedToManifestNames.TryGetValue (typeName, out var manifestName)) {
attr.Value = manifestName;
}
}

internal static void AddLauncherIntentFilter (XElement activity)
{
// Check if there's already a launcher intent filter
Expand Down Expand Up @@ -154,6 +212,30 @@ internal static XElement CreateMetaDataElement (MetaDataInfo meta)
return element;
}

// Maps [Layout] attribute properties to the <layout> element's android: attributes.
static readonly (string Property, string Attribute) [] LayoutMappings = [
("DefaultHeight", "defaultHeight"),
("DefaultWidth", "defaultWidth"),
("Gravity", "gravity"),
("MinHeight", "minHeight"),
("MinWidth", "minWidth"),
];

internal static XElement? CreateLayoutElement (IReadOnlyDictionary<string, object?> layoutProperties)
{
var element = new XElement ("layout");
bool hasAttribute = false;

foreach (var (property, attribute) in LayoutMappings) {
if (layoutProperties.TryGetValue (property, out var value) && value is string s && !string.IsNullOrEmpty (s)) {
element.SetAttributeValue (AndroidNs + attribute, s);
hasAttribute = true;
}
}

return hasAttribute ? element : null;
}

internal static void UpdateApplicationElement (XElement app, JavaPeerInfo peer, int targetSdkVersion = 0)
{
string jniName = JniSignatureHelper.JniNameToJavaName (peer.JavaName);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using System;
using System.Buffers;
using System.Security.Cryptography;
using System.Text;

namespace Microsoft.Android.Sdk.TrimmableTypeMap;

sealed class DeterministicHashBuilder : IDisposable
{
readonly HashAlgorithm hash = SHA256.Create ();
readonly byte [] intBuffer = new byte [4];
readonly byte [] byteBuffer = new byte [1];
bool finished;

public void AddString (string value)
{
var bytes = Encoding.UTF8.GetBytes (value);
AddInt32 (bytes.Length);
AddBytes (bytes);
}

public void AddVersion (Version version)
{
AddInt32 (version.Major);
AddInt32 (version.Minor);
AddInt32 (version.Build);
AddInt32 (version.Revision);
}

public void AddInt32 (int value)
{
intBuffer [0] = (byte) value;
intBuffer [1] = (byte) (value >> 8);
intBuffer [2] = (byte) (value >> 16);
intBuffer [3] = (byte) (value >> 24);
AddBytes (intBuffer);
}

public void AddByte (byte value)
{
byteBuffer [0] = value;
AddBytes (byteBuffer);
}

public void AddBytes (byte [] bytes)
{
EnsureNotFinished ();
if (bytes.Length != 0) {
hash.TransformBlock (bytes, 0, bytes.Length, null, 0);
}
}

public void AddBytes (ReadOnlySpan<byte> bytes)
{
EnsureNotFinished ();
if (bytes.IsEmpty) {
return;
}

var buffer = ArrayPool<byte>.Shared.Rent (Math.Min (bytes.Length, 4096));
try {
while (!bytes.IsEmpty) {
var count = Math.Min (bytes.Length, buffer.Length);
bytes.Slice (0, count).CopyTo (buffer);
hash.TransformBlock (buffer, 0, count, null, 0);
bytes = bytes.Slice (count);
}
} finally {
ArrayPool<byte>.Shared.Return (buffer);
}
}

public byte [] ToHash ()
{
if (!finished) {
hash.TransformFinalBlock ([], 0, 0);
finished = true;
}
if (hash.Hash is not null) {
return hash.Hash;
}
throw new InvalidOperationException ("SHA256 did not produce a hash.");
}

void EnsureNotFinished ()
{
if (finished) {
throw new InvalidOperationException ("Cannot add data after finalizing the hash.");
}
}

public void Dispose ()
{
hash.Dispose ();
}
}
Loading