Skip to content

Commit ffef891

Browse files
[Xamarin.Android.Build.Tasks] make "managed typemap" runtime agnostic
For NativeAOT, we implemented a "managed" typemap that is trimmer-safe. In order to test its performance characteristics, we can make this typemap useable for Mono and CoreCLR as well: * Move `NativeAotTypeManager`, `NativeAotValueManager`, and `TypeMapping` types to `Mono.Android.dll` * Rename `NativeAot*` to `Managed*` * Add a new private `$(_AndroidTypeMapImplementation)` MSBuild property that can be set to `llvm-ir` or `managed`. * Add a new trimmer feature flag `Android.Runtime.RuntimeFeature.ManagedTypeMap` that when `true` uses the managed typemap on any runtime. I added a test that verifies `dotnet run` succeeds for all typemap implementations. Note that NativeAOT will *only* support the managed typemap.
1 parent e347cd3 commit ffef891

File tree

20 files changed

+93
-35
lines changed

20 files changed

+93
-35
lines changed

build-tools/create-packs/Microsoft.Android.Runtime.proj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ projects that use the Microsoft.Android framework in .NET 6+.
4646
/>
4747
<_AndroidRuntimePackAssemblies
4848
Include="$(_MonoAndroidNETOutputRoot)$(AndroidLatestStableApiLevel)\System.IO.Hashing.dll"
49-
Condition=" '$(AndroidRuntime)' == 'NativeAOT' "
5049
NoSymbols="true"
5150
/>
5251
<_AndroidRuntimePackAssemblies Include="$(_MonoAndroidNETOutputRoot)$(AndroidLatestStableApiLevel)\Mono.Android.Export.dll" />

src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/JavaInteropRuntime.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ static void init (IntPtr jnienv, IntPtr klass)
3737
var settings = new DiagnosticSettings ();
3838
settings.AddDebugDotnetLog ();
3939

40-
var typeManager = new NativeAotTypeManager ();
40+
var typeManager = new ManagedTypeManager ();
4141
var options = new NativeAotRuntimeOptions {
4242
EnvironmentPointer = jnienv,
4343
TypeManager = typeManager,

src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/JreRuntime.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ static NativeAotRuntimeOptions CreateJreVM (NativeAotRuntimeOptions builder)
5858
throw new InvalidOperationException ($"Member `{nameof (NativeAotRuntimeOptions)}.{nameof (NativeAotRuntimeOptions.JvmLibraryPath)}` must be set.");
5959

6060
#if NET
61-
builder.TypeManager ??= new NativeAotTypeManager ();
61+
builder.TypeManager ??= new ManagedTypeManager ();
6262
#endif // NET
6363

6464
builder.ValueManager ??= new ManagedValueManager ();

src/Microsoft.Android.Runtime.NativeAOT/Microsoft.Android.Runtime.NativeAOT.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
<Target Name="_CopyToPackDirs">
3939
<ItemGroup>
4040
<_RuntimePackFiles Include="$(OutputPath)Microsoft.Android.Runtime.NativeAOT.dll" AndroidRID="%(AndroidAbiAndRuntimeFlavor.AndroidRID)" AndroidRuntime="%(AndroidAbiAndRuntimeFlavor.AndroidRuntime)" />
41-
<_RuntimePackFiles Include="$(OutputPath)System.IO.Hashing.dll" AndroidRID="%(AndroidAbiAndRuntimeFlavor.AndroidRID)" AndroidRuntime="%(AndroidAbiAndRuntimeFlavor.AndroidRuntime)" />
4241
</ItemGroup>
4342
<Message Importance="high" Text="$(TargetPath) %(AndroidAbiAndRuntimeFlavor.AndroidRID)" />
4443
<Copy

src/Microsoft.Android.Sdk.ILLink/TypeMappingStep.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ namespace Microsoft.Android.Sdk.ILLink;
1919
/// </summary>
2020
public class TypeMappingStep : BaseStep
2121
{
22-
const string AssemblyName = "Microsoft.Android.Runtime.NativeAOT";
23-
const string TypeName = "Microsoft.Android.Runtime.TypeMapping";
22+
const string AssemblyName = "Mono.Android";
23+
const string TypeName = "Microsoft.Android.Runtime.ManagedTypeMapping";
2424
const string SystemIOHashingAssemblyPathCustomData = "SystemIOHashingAssemblyPath";
2525
readonly IDictionary<string, List<TypeDefinition>> TypeMappings = new Dictionary<string, List<TypeDefinition>> (StringComparer.Ordinal);
26-
AssemblyDefinition? MicrosoftAndroidRuntimeNativeAot;
26+
AssemblyDefinition? MonoAndroidAssembly;
2727

2828
delegate ulong HashMethod (ReadOnlySpan<byte> data, long seed = 0);
2929
HashMethod? _hashMethod;
@@ -36,8 +36,7 @@ protected override void Process ()
3636
protected override void ProcessAssembly (AssemblyDefinition assembly)
3737
{
3838
if (assembly.Name.Name == AssemblyName) {
39-
MicrosoftAndroidRuntimeNativeAot = assembly;
40-
return;
39+
MonoAndroidAssembly = assembly;
4140
}
4241
if (Annotations?.GetAction (assembly) == AssemblyAction.Delete)
4342
return;
@@ -51,11 +50,11 @@ protected override void EndProcess ()
5150
{
5251
Context.LogMessage ($"Writing {TypeMappings.Count} typemap entries");
5352

54-
if (MicrosoftAndroidRuntimeNativeAot is null) {
53+
if (MonoAndroidAssembly is null) {
5554
throw new InvalidOperationException ($"Unable to find {AssemblyName} assembly");
5655
}
5756

58-
var module = MicrosoftAndroidRuntimeNativeAot.MainModule;
57+
var module = MonoAndroidAssembly.MainModule;
5958
var type = module.GetType (TypeName);
6059
if (type is null) {
6160
throw new InvalidOperationException ($"Unable to find {TypeName} type");

src/Mono.Android/Android.Runtime/AndroidRuntime.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Diagnostics;
4+
using System.Diagnostics.CodeAnalysis;
45
using System.Globalization;
56
using System.Runtime.CompilerServices;
67
using System.Runtime.InteropServices;
@@ -11,7 +12,8 @@
1112

1213
using Java.Interop;
1314
using Java.Interop.Tools.TypeNameMappings;
14-
using System.Diagnostics.CodeAnalysis;
15+
using Microsoft.Android.Runtime;
16+
using RuntimeFeature = Microsoft.Android.Runtime.RuntimeFeature;
1517

1618
#if JAVA_INTEROP
1719
namespace Android.Runtime {
@@ -103,8 +105,13 @@ public AndroidRuntimeOptions (IntPtr jnienv,
103105
ClassLoader = new JniObjectReference (classLoader, JniObjectReferenceType.Global);
104106
InvocationPointer = vm;
105107
ObjectReferenceManager = new AndroidObjectReferenceManager ();
106-
TypeManager = typeManager ?? new AndroidTypeManager (jniAddNativeMethodRegistrationAttributePresent);
107-
ValueManager = valueManager ?? new AndroidValueManager ();
108+
if (RuntimeFeature.ManagedTypeMap) {
109+
TypeManager = new ManagedTypeManager ();
110+
ValueManager = new ManagedValueManager ();
111+
} else {
112+
TypeManager = new AndroidTypeManager (jniAddNativeMethodRegistrationAttributePresent);
113+
ValueManager = new AndroidValueManager ();
114+
}
108115
UseMarshalMemberBuilder = false;
109116
JniAddNativeMethodRegistrationAttributePresent = jniAddNativeMethodRegistrationAttributePresent;
110117
}

src/Mono.Android/Android.Runtime/JNIEnvInit.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,13 @@ static Type TypeGetType (string typeName) =>
7979
JniType.GetCachedJniType (ref jniType, className);
8080

8181
ReadOnlySpan<char> methods = new ReadOnlySpan<char> ((void*) methods_ptr, methods_len);
82-
((AndroidTypeManager)androidRuntime!.TypeManager).RegisterNativeMembers (jniType, type, methods);
82+
if (androidRuntime!.TypeManager is AndroidTypeManager typeManager) {
83+
// Span-based overload
84+
typeManager.RegisterNativeMembers (jniType, type, methods);
85+
} else {
86+
// String-based overload
87+
androidRuntime!.TypeManager.RegisterNativeMembers (jniType, type, methods);
88+
}
8389
}
8490

8591
// NOTE: should have different name than `Initialize` to avoid:

src/Mono.Android/ILLink/ILLink.Substitutions.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,9 @@
44
<method signature="System.Boolean get_NegotiateAuthenticationIsEnabled()" body="stub" feature="Xamarin.Android.Net.UseNegotiateAuthentication" featurevalue="false" value="false" />
55
<method signature="System.Boolean get_NegotiateAuthenticationIsEnabled()" body="stub" feature="Xamarin.Android.Net.UseNegotiateAuthentication" featurevalue="true" value="true" />
66
</type>
7+
<type fullname="Microsoft.Android.Runtime.RuntimeFeature">
8+
<method signature="System.Boolean get_ManagedTypeMap()" body="stub" feature="Microsoft.Android.Runtime.RuntimeFeature.ManagedTypeMap" featurevalue="false" value="false" />
9+
<method signature="System.Boolean get_ManagedTypeMap()" body="stub" feature="Microsoft.Android.Runtime.RuntimeFeature.ManagedTypeMap" featurevalue="true" value="true" />
10+
</type>
711
</assembly>
812
</linker>
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
1+
using System;
2+
using System.Collections.Generic;
13
using System.Diagnostics.CodeAnalysis;
24
using System.Reflection;
35
using Java.Interop;
46
using Java.Interop.Tools.TypeNameMappings;
57

68
namespace Microsoft.Android.Runtime;
79

8-
partial class NativeAotTypeManager : JniRuntime.JniTypeManager {
10+
class ManagedTypeManager : JniRuntime.JniTypeManager {
911

1012
const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors;
1113
internal const DynamicallyAccessedMemberTypes Methods = DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods;
1214
internal const DynamicallyAccessedMemberTypes MethodsAndPrivateNested = Methods | DynamicallyAccessedMemberTypes.NonPublicNestedTypes;
1315

14-
public NativeAotTypeManager ()
16+
public ManagedTypeManager ()
1517
{
1618
}
1719

@@ -127,7 +129,7 @@ public override void RegisterNativeMembers (
127129

128130
protected override IEnumerable<Type> GetTypesForSimpleReference (string jniSimpleReference)
129131
{
130-
if (TypeMapping.TryGetType (jniSimpleReference, out var target)) {
132+
if (ManagedTypeMapping.TryGetType (jniSimpleReference, out var target)) {
131133
yield return target;
132134
}
133135
foreach (var t in base.GetTypesForSimpleReference (jniSimpleReference)) {
@@ -141,7 +143,7 @@ protected override IEnumerable<string> GetSimpleReferences (Type type)
141143
yield return r;
142144
}
143145

144-
if (TypeMapping.TryGetJniName (type, out var jniName)) {
146+
if (ManagedTypeMapping.TryGetJniName (type, out var jniName)) {
145147
yield return jniName;
146148
}
147149
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Buffers.Binary;
23
using System.Diagnostics;
34
using System.Diagnostics.CodeAnalysis;
@@ -8,7 +9,7 @@
89

910
namespace Microsoft.Android.Runtime;
1011

11-
internal static class TypeMapping
12+
internal static class ManagedTypeMapping
1213
{
1314
internal static bool TryGetType (string jniName, [NotNullWhen (true)] out Type? type)
1415
{

0 commit comments

Comments
 (0)