diff --git a/src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/JreRuntime.cs b/src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/JreRuntime.cs
index 5891149578f..ff7ec8395f3 100644
--- a/src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/JreRuntime.cs
+++ b/src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/JreRuntime.cs
@@ -56,6 +56,9 @@ static NativeAotRuntimeOptions CreateJreVM (NativeAotRuntimeOptions builder)
builder.EnvironmentPointer == IntPtr.Zero &&
string.IsNullOrEmpty (builder.JvmLibraryPath))
throw new InvalidOperationException ($"Member `{nameof (NativeAotRuntimeOptions)}.{nameof (NativeAotRuntimeOptions.JvmLibraryPath)}` must be set.");
+ if (!RuntimeFeature.TrimmableTypeMap) {
+ throw new NotSupportedException ("NativeAOT requires the trimmable typemap.");
+ }
#if NET
builder.TypeManager ??= CreateDefaultTypeManager ();
@@ -77,11 +80,11 @@ internal protected JreRuntime (NativeAotRuntimeOptions builder)
static JniRuntime.JniTypeManager CreateDefaultTypeManager ()
{
- if (RuntimeFeature.TrimmableTypeMap) {
- return new TrimmableTypeMapTypeManager ();
+ if (!RuntimeFeature.TrimmableTypeMap) {
+ throw new NotSupportedException ("NativeAOT requires the trimmable typemap.");
}
- return new ManagedTypeManager ();
+ return new TrimmableTypeMapTypeManager ();
}
public override string? GetCurrentManagedThreadName ()
diff --git a/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj b/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj
index 6d3aa528fa1..d1ec626bab5 100644
--- a/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj
+++ b/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj
@@ -22,13 +22,8 @@
-
-
-
-
-
diff --git a/src/Microsoft.Android.Sdk.ILLink/TypeMappingStep.cs b/src/Microsoft.Android.Sdk.ILLink/TypeMappingStep.cs
deleted file mode 100644
index 0f775f4d87c..00000000000
--- a/src/Microsoft.Android.Sdk.ILLink/TypeMappingStep.cs
+++ /dev/null
@@ -1,422 +0,0 @@
-using System;
-using System.Buffers.Binary;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.InteropServices;
-using Java.Interop.Tools.Cecil;
-using Java.Interop.Tools.TypeNameMappings;
-using Mono.Cecil;
-using Mono.Cecil.Cil;
-using Mono.Linker;
-using Mono.Linker.Steps;
-
-namespace Microsoft.Android.Sdk.ILLink;
-
-///
-/// MVP "typemap" implementation for NativeAOT
-///
-public class TypeMappingStep : BaseStep
-{
- const string AssemblyName = "Mono.Android";
- const string TypeName = "Microsoft.Android.Runtime.ManagedTypeMapping";
- const string SystemIOHashingAssemblyPathCustomData = "SystemIOHashingAssemblyPath";
- readonly IDictionary> TypeMappings = new Dictionary> (StringComparer.Ordinal);
- AssemblyDefinition? MonoAndroidAssembly;
-
- delegate ulong HashMethod (ReadOnlySpan data, long seed = 0);
- HashMethod? _hashMethod;
-
- protected override void Process ()
- {
- _hashMethod = LoadHashMethod ();
- }
-
- protected override void ProcessAssembly (AssemblyDefinition assembly)
- {
- if (assembly.Name.Name == AssemblyName) {
- MonoAndroidAssembly = assembly;
- }
- if (Annotations?.GetAction (assembly) == AssemblyAction.Delete)
- return;
-
- foreach (var type in assembly.MainModule.Types) {
- ProcessType (assembly, type);
- }
- }
-
- protected override void EndProcess ()
- {
- Context.LogMessage ($"Writing {TypeMappings.Count} typemap entries");
-
- if (MonoAndroidAssembly is null) {
- throw new InvalidOperationException ($"Unable to find {AssemblyName} assembly");
- }
-
- var module = MonoAndroidAssembly.MainModule;
- var type = module.GetType (TypeName);
- if (type is null) {
- throw new InvalidOperationException ($"Unable to find {TypeName} type");
- }
-
- var typeMappingRecords = TypeMappings
- .Select (kvp =>
- new TypeMapRecord {
- JniName = kvp.Key,
- Types = kvp.Value.ToArray (),
- Context = Context,
- })
- .ToArray ();
-
- // Java -> .NET mapping
- {
- var orderedJavaToDotnetMapping = typeMappingRecords.OrderBy (record => Hash (record.JniName))
- .ToArray ();
- var jniNames = orderedJavaToDotnetMapping.Select (record => record.JniName)
- .ToArray ();
- var jniNameHashes = jniNames.Select (Hash)
- .ToArray ();
- var types = orderedJavaToDotnetMapping.Select (record => record.SelectTypeDefinition ())
- .ToArray ();
-
- Context.LogMessage ("JNI -> .NET mappings");
- Context.LogMessage ($"Generated field {type.FullName}.s_get_JniNameHashes_data contains {jniNameHashes.Length} hashes:");
- for (int i = 0; i < jniNameHashes.Length; ++i ) {
- var java = jniNames [i];
- var hash = jniNameHashes [i];
- Context.LogMessage ($"\t0x{hash.ToString ("x", System.Globalization.CultureInfo.InvariantCulture), -16} // {i,4}: {java}");
- }
- Context.LogMessage ($"Generated method {type.FullName}.GetTypeByJniNameHashIndex contains {types.Length} mappings:");
- var maxAqtnLength = types.Max (t => TypeDefinitionRocks.GetAssemblyQualifiedName (t, Context).Length)+2;
- for (int i = 0; i < types.Length; ++i ) {
- var aqtn = TypeDefinitionRocks.GetAssemblyQualifiedName (types [i], Context);
- var java = jniNames [i];
- var hash = jniNameHashes [i];
- Context.LogMessage (
- string.Format (System.Globalization.CultureInfo.InvariantCulture,
- "\tindex {0,4} => Type.GetType({1,-" + maxAqtnLength + "}), // `{2}` hash=0x{3:x16}", i, $"\"{aqtn}\"", java, hash));
- }
- Context.LogMessage ($"Generated method {type.FullName}.GetJniNameByJniNameHashIndex contains {jniNames.Length} mappings:");
- var maxJavaLength = jniNames.Max (s => s.Length)+2;
- for (int i = 0; i < jniNames.Length; ++i ) {
- var java = jniNames [i];
- var aqtn = TypeDefinitionRocks.GetAssemblyQualifiedName (types [i], Context);
- var hash = jniNameHashes [i];
- Context.LogMessage (
- string.Format (System.Globalization.CultureInfo.InvariantCulture,
- "\tindex {0,4} => {1,-" + maxJavaLength + "}, // `{2}` hash=0x{3:x16}", i, $"\"{java}\"", aqtn, hash));
- }
-
- GenerateHashes (jniNameHashes, methodName: "get_JniNameHashes");
- GenerateGetTypeByJniNameHashIndex (types);
- GenerateStringSwitchMethod (type, "GetJniNameByJniNameHashIndex", jniNames);
- }
-
- // .NET -> Java mapping
- {
- var orderedManagedToJavaMapping = typeMappingRecords
- .SelectMany (record => record.Flatten ())
- .OrderBy (record => Hash (record.TypeName))
- .ToArray ();
-
- var typeNames = orderedManagedToJavaMapping
- .Select (record => record.TypeName)
- .ToArray ();
- var typeNameHashes = typeNames.Select (Hash)
- .ToArray ();
- var jniNames = orderedManagedToJavaMapping.Select (record => record.JniName)
- .ToArray ();
-
- Context.LogMessage (".NET -> JNI mappings");
- Context.LogMessage ($"Generated field {type.FullName}.s_get_TypeNameHashes_data contains {typeNameHashes.Length} hashes:");
- for (int i = 0; i < typeNameHashes.Length; ++i ) {
- var aqtn = typeNames [i];
- var hash = typeNameHashes [i];
- Context.LogMessage ($"\t0x{hash.ToString ("x", System.Globalization.CultureInfo.InvariantCulture), -16} // {i,4}: {aqtn}");
- }
- var maxJavaLength = jniNames.Max (s => s.Length) + 2;
- Context.LogMessage ($"Generated method {type.FullName}.GetJniNameByTypeNameHashIndex contains {jniNames.Length} mappings:");
- for (int i = 0; i < jniNames.Length; ++i ) {
- var java = jniNames [i];
- var aqtn = typeNames [i];
- var hash = typeNameHashes [i];
- Context.LogMessage (
- string.Format (System.Globalization.CultureInfo.InvariantCulture,
- "\tindex {0,4} => {1,-" + maxJavaLength + "}, // `{2}` hash=0x{3:x16}", i, $"\"{java}\"", aqtn, hash));
- }
- Context.LogMessage ($"Generated method {type.FullName}.GetTypeNameByTypeNameHashIndex contains {typeNames.Length} mappings:");
- var maxAqtnLength = typeNames.Max (s => s.Length) + 2;
- for (int i = 0; i < typeNames.Length; ++i ) {
- var java = jniNames [i];
- var aqtn = typeNames [i];
- var hash = typeNameHashes [i];
- Context.LogMessage (
- string.Format (System.Globalization.CultureInfo.InvariantCulture,
- "\tindex {0,4} => {1,-" + maxAqtnLength + "}, // `{2}` hash=0x{3:x16}", i, $"\"{aqtn}\"", java, hash));
- }
-
- GenerateHashes (typeNameHashes, methodName: "get_TypeNameHashes");
- GenerateStringSwitchMethod (type, "GetJniNameByTypeNameHashIndex", jniNames);
- GenerateStringSwitchMethod (type, "GetTypeNameByTypeNameHashIndex", typeNames);
- }
-
- void GenerateGetTypeByJniNameHashIndex (IEnumerable types)
- {
- var method = type.Methods.FirstOrDefault (m => m.Name == "GetTypeByJniNameHashIndex");
- if (method is null) {
- throw new InvalidOperationException ($"Unable to find {TypeName}.GetTypeByJniNameHashIndex() method");
- }
-
- var getTypeFromHandle = module.ImportReference (typeof (Type).GetMethod ("GetTypeFromHandle"));
- if (getTypeFromHandle is null) {
- throw new InvalidOperationException ($"Unable to find Type.GetTypeFromHandle() method");
- }
-
- // Clear IL in method body
- method.Body.Instructions.Clear ();
-
- var il = method.Body.GetILProcessor ();
-
- var targets = new List ();
- foreach (var target in types) {
- targets.Add (il.Create (OpCodes.Ldtoken, module.ImportReference (target)));
- }
-
- il.Emit (OpCodes.Ldarg_0);
- il.Emit (OpCodes.Switch, targets.ToArray ());
-
- var defaultTarget = il.Create (OpCodes.Ldnull);
- il.Emit (OpCodes.Br, defaultTarget);
-
- foreach (var target in targets) {
- il.Append (target);
- il.Emit (OpCodes.Call, getTypeFromHandle);
- il.Emit (OpCodes.Ret);
- }
-
- il.Append (defaultTarget);
- il.Emit (OpCodes.Ret);
- }
-
- void GenerateStringSwitchMethod (TypeDefinition type, string methodName, string[] values)
- {
- var method = type.Methods.FirstOrDefault (m => m.Name == methodName);
- if (method is null) {
- throw new InvalidOperationException ($"Unable to find {type.FullName}.{methodName} method");
- }
-
- // Clear IL in method body
- method.Body.Instructions.Clear ();
-
- var il = method.Body.GetILProcessor ();
-
- var targets = new List ();
- foreach (var value in values) {
- targets.Add (il.Create (OpCodes.Ldstr, value));
- }
-
- il.Emit (OpCodes.Ldarg_0);
- il.Emit (OpCodes.Switch, targets.ToArray ());
-
- var defaultTarget = il.Create (OpCodes.Ldnull);
- il.Emit (OpCodes.Br, defaultTarget);
-
- foreach (var target in targets) {
- il.Append (target);
- il.Emit (OpCodes.Ret);
- }
-
- il.Append (defaultTarget);
- il.Emit (OpCodes.Ret);
- }
-
- void GenerateHashes (ulong[] hashes, string methodName)
- {
- // Sanity check: hashes must be unique and sorted
- if (hashes.Length > 0) {
- ulong previous = hashes[0];
- for (int i = 1; i < hashes.Length; ++i) {
- if (hashes[i] == previous) {
- throw new InvalidOperationException ($"Duplicate hashes");
- } else if (hashes[i] < previous) {
- throw new InvalidOperationException ($"Hashes are not in ascending order");
- }
-
- previous = hashes[i];
- }
- }
-
- GenerateReadOnlySpanGetter (type, methodName, hashes, sizeof (ulong), BitConverter.GetBytes);
- }
-
- void GenerateReadOnlySpanGetter (TypeDefinition type, string name, T[] data, int sizeOfT, Func getBytes)
- where T : struct
- {
- // Create static array struct for `byte[#data * sizeof(T)]`
- var arrayType = GetArrayType (type, data.Length * sizeOfT);
-
- // Create static field to store the raw bytes
- var bytesField = new FieldDefinition ($"s_{name}_data", FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.InitOnly, arrayType);
- bytesField.InitialValue = data.SelectMany (getBytes).ToArray ();
- if (!bytesField.Attributes.HasFlag (FieldAttributes.HasFieldRVA)) {
- throw new InvalidOperationException ($"Field {bytesField.Name} does not have RVA");
- }
-
- type.Fields.Add (bytesField);
-
- // Generate the Hashes getter
- var getHashes = type.Methods.FirstOrDefault (f => f.Name == name) ?? throw new InvalidOperationException ($"Unable to find {TypeName}.{name} field");
-
- getHashes.Body.Instructions.Clear ();
- var il = getHashes.Body.GetILProcessor ();
-
- il.Emit (OpCodes.Ldsflda, bytesField);
- il.Emit (OpCodes.Ldc_I4, data.Length);
- il.Emit (OpCodes.Newobj, module.ImportReference (typeof (ReadOnlySpan).GetConstructor (new[] { typeof(void*), typeof(int) })));
-
- il.Emit (OpCodes.Ret);
- }
-
- TypeDefinition GetArrayType (TypeDefinition type, int size)
- {
- var hashesArrayName = $"HashesArray_{size}";
- var arrayType = type.NestedTypes.FirstOrDefault (td => td.Name == hashesArrayName);
- if (arrayType is null) {
- arrayType = new TypeDefinition (
- "",
- hashesArrayName,
- TypeAttributes.NestedPrivate | TypeAttributes.ExplicitLayout,
- module.ImportReference (typeof (ValueType)))
- {
- PackingSize = 1,
- ClassSize = size,
- };
-
- type.NestedTypes.Add (arrayType);
- }
-
- return arrayType;
- }
- }
-
- class TypeMapRecord
- {
- public required string JniName { get; init; }
- public required TypeDefinition[] Types { get; init; }
- public required LinkContext Context { get; init; }
-
- public string TypeName
- {
- get
- {
- // We need to drop the version, culture, and public key information from the AQN.
- var type = SelectTypeDefinition ();
- var assemblyQualifiedName = TypeDefinitionRocks.GetAssemblyQualifiedName (type, Context);
- var commaIndex = assemblyQualifiedName.IndexOf(',');
- var secondCommaIndex = assemblyQualifiedName.IndexOf(',', startIndex: commaIndex + 1);
- return secondCommaIndex < 0
- ? assemblyQualifiedName
- : assemblyQualifiedName.Substring (0, secondCommaIndex);
- }
- }
-
- public TypeDefinition SelectTypeDefinition ()
- {
- if (Types.Length == 1)
- return Types[0];
-
- var best = Types[0];
- foreach (var type in Types) {
- if (type == best)
- continue;
- // Types in Mono.Android assembly should be first in the list
- if (best.Module.Assembly.Name.Name != "Mono.Android" &&
- type.Module.Assembly.Name.Name == "Mono.Android") {
- best = type;
- continue;
- }
- // We found the `Invoker` type *before* the declared type
- // Fix things up so the abstract type is first, and the `Invoker` is considered a duplicate.
- if ((type.IsAbstract || type.IsInterface) &&
- !best.IsAbstract &&
- !best.IsInterface &&
- type.IsAssignableFrom (best, Context)) {
- best = type;
- continue;
- }
-
- // we found a generic subclass of a non-generic type
- if (type.IsGenericInstance &&
- !best.IsGenericInstance &&
- type.IsAssignableFrom (best, Context)) {
- best = type;
- continue;
- }
- }
- foreach (var type in Types) {
- if (type == best)
- continue;
- Context.LogMessage ($"Duplicate typemap entry for {JniName} => {type.FullName}");
- }
- return best;
- }
-
- public IEnumerable Flatten () =>
- Types.Select (type =>
- new TypeMapRecord {
- JniName = JniName,
- Types = new[] { type },
- Context = Context,
- });
- }
-
- void ProcessType (AssemblyDefinition assembly, TypeDefinition type)
- {
- if (type.HasJavaPeer (Context)) {
- var javaName = JavaNativeTypeManager.ToJniName (type, Context);
- if (!TypeMappings.TryGetValue (javaName, out var list)) {
- TypeMappings.Add (javaName, list = new List ());
- }
- list.Add (type);
- }
-
- if (!type.HasNestedTypes)
- return;
-
- foreach (TypeDefinition nested in type.NestedTypes)
- ProcessType (assembly, nested);
- }
-
- ulong Hash (string value)
- {
- ReadOnlySpan bytes = MemoryMarshal.AsBytes(value.AsSpan ());
- ulong hash = _hashMethod!(bytes);
-
- if (!BitConverter.IsLittleEndian) {
- hash = BinaryPrimitives.ReverseEndianness (hash);
- }
-
- return hash;
- }
-
- HashMethod LoadHashMethod ()
- {
- if (!Context.TryGetCustomData (SystemIOHashingAssemblyPathCustomData, out var assemblyPath)) {
- throw new InvalidOperationException ($"The {nameof (TypeMappingStep)} step requires setting the '{SystemIOHashingAssemblyPathCustomData}' custom data");
- } else if (!System.IO.File.Exists (assemblyPath)) {
- throw new InvalidOperationException ($"The '{SystemIOHashingAssemblyPathCustomData}' custom data must point to a valid assembly path ('{assemblyPath}' does not exist)");
- }
-
- System.Reflection.MethodInfo? hashToUInt64MethodInfo;
- try {
- hashToUInt64MethodInfo = System.Reflection.Assembly.LoadFile (assemblyPath).GetType ("System.IO.Hashing.XxHash3")?.GetMethod ("HashToUInt64");
- } catch (Exception ex) {
- throw new InvalidOperationException ($"The '{SystemIOHashingAssemblyPathCustomData}' custom data must point to a valid assembly path ('{assemblyPath}' could not be loaded)", ex);
- }
-
- if (hashToUInt64MethodInfo is null) {
- throw new InvalidOperationException ($"Unable to find System.IO.Hashing.XxHash3.HashToUInt64 method, {nameof(TypeMappingStep)} cannot proceed");
- }
-
- return (HashMethod)Delegate.CreateDelegate (typeof (HashMethod), hashToUInt64MethodInfo, throwOnBindFailure: true);
- }
-}
diff --git a/src/Mono.Android/Android.Runtime/JNIEnvInit.cs b/src/Mono.Android/Android.Runtime/JNIEnvInit.cs
index c2e7ea913ca..9c116bebb7d 100644
--- a/src/Mono.Android/Android.Runtime/JNIEnvInit.cs
+++ b/src/Mono.Android/Android.Runtime/JNIEnvInit.cs
@@ -174,8 +174,8 @@ internal static JniRuntime.JniTypeManager CreateTypeManager (JnienvInitializeArg
return new TrimmableTypeMapTypeManager ();
}
- if (RuntimeFeature.IsNativeAotRuntime || RuntimeFeature.ManagedTypeMap) {
- return new ManagedTypeManager ();
+ if (RuntimeFeature.IsNativeAotRuntime) {
+ return new TrimmableTypeMapTypeManager ();
}
return new AndroidTypeManager (args.jniAddNativeMethodRegistrationAttributePresent != 0);
@@ -225,7 +225,7 @@ static void InitializeTrimmableTypeMapDataIfNeeded ()
static void RegisterTrimmableTypeMapNativeMethodsIfNeeded ()
{
if (RuntimeFeature.TrimmableTypeMap) {
- // TypeMapLoader.Initialize() only loads managed typemap data. Registering
+ // TypeMapLoader.Initialize() only loads typemap data. Registering
// mono.android.Runtime natives requires JniRuntime.Current and its ClassLoader.
TrimmableTypeMap.RegisterNativeMethods ();
}
diff --git a/src/Mono.Android/Microsoft.Android.Runtime/ManagedTypeManager.cs b/src/Mono.Android/Microsoft.Android.Runtime/ManagedTypeManager.cs
deleted file mode 100644
index 454bab0e1bb..00000000000
--- a/src/Mono.Android/Microsoft.Android.Runtime/ManagedTypeManager.cs
+++ /dev/null
@@ -1,194 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using System.Reflection;
-using Java.Interop;
-using Java.Interop.Tools.TypeNameMappings;
-
-namespace Microsoft.Android.Runtime;
-
-class ManagedTypeManager : JniRuntime.JniTypeManager {
-
- const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors;
- internal const DynamicallyAccessedMemberTypes Methods = DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods;
- internal const DynamicallyAccessedMemberTypes MethodsAndPrivateNested = Methods | DynamicallyAccessedMemberTypes.NonPublicNestedTypes;
-
- public ManagedTypeManager ()
- {
- }
-
- [return: DynamicallyAccessedMembers (Constructors)]
- protected override Type? GetInvokerTypeCore (
- [DynamicallyAccessedMembers (Constructors)]
- Type type)
- {
- const string suffix = "Invoker";
-
- // https://github.com/xamarin/xamarin-android/blob/5472eec991cc075e4b0c09cd98a2331fb93aa0f3/src/Microsoft.Android.Sdk.ILLink/MarkJavaObjects.cs#L176-L186
- const string assemblyGetTypeMessage = "'Invoker' types are preserved by the MarkJavaObjects trimmer step.";
- const string makeGenericTypeMessage = "Generic 'Invoker' types are preserved by the MarkJavaObjects trimmer step.";
-
- [UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = assemblyGetTypeMessage)]
- [UnconditionalSuppressMessage ("Trimming", "IL2073", Justification = assemblyGetTypeMessage)]
- [return: DynamicallyAccessedMembers (Constructors)]
- static Type? AssemblyGetType (Assembly assembly, string typeName) =>
- assembly.GetType (typeName);
-
- [UnconditionalSuppressMessage ("Trimming", "IL2055", Justification = makeGenericTypeMessage)]
- [return: DynamicallyAccessedMembers (Constructors)]
- static Type MakeGenericType (
- [DynamicallyAccessedMembers (Constructors)]
- Type type,
- Type [] arguments) =>
- // FIXME: https://github.com/dotnet/java-interop/issues/1192
- #pragma warning disable IL3050
- type.MakeGenericType (arguments);
- #pragma warning restore IL3050
-
- Type[] arguments = type.GetGenericArguments ();
- if (arguments.Length == 0)
- return AssemblyGetType (type.Assembly, type + suffix) ?? base.GetInvokerTypeCore (type);
- Type definition = type.GetGenericTypeDefinition ();
- int bt = definition.FullName!.IndexOf ("`", StringComparison.Ordinal);
- if (bt == -1)
- throw new NotSupportedException ("Generic type doesn't follow generic type naming convention! " + type.FullName);
- Type? suffixDefinition = AssemblyGetType (definition.Assembly,
- definition.FullName.Substring (0, bt) + suffix + definition.FullName.Substring (bt));
- if (suffixDefinition == null)
- return base.GetInvokerTypeCore (type);
- return MakeGenericType (suffixDefinition, arguments);
- }
-
- // NOTE: suppressions below also in `src/Mono.Android/Android.Runtime/AndroidRuntime.cs`
- [UnconditionalSuppressMessage ("Trimming", "IL2057", Justification = "Type.GetType() can never statically know the string value parsed from parameter 'methods'.")]
- [UnconditionalSuppressMessage ("Trimming", "IL2067", Justification = "Delegate.CreateDelegate() can never statically know the string value parsed from parameter 'methods'.")]
- [UnconditionalSuppressMessage ("Trimming", "IL2072", Justification = "Delegate.CreateDelegate() can never statically know the string value parsed from parameter 'methods'.")]
- public override void RegisterNativeMembers (
- JniType nativeClass,
- [DynamicallyAccessedMembers (MethodsAndPrivateNested)]
- Type type,
- ReadOnlySpan methods)
- {
- if (methods.IsEmpty) {
- base.RegisterNativeMembers (nativeClass, type, methods);
- return;
- }
-
- int methodCount = CountMethods (methods);
- if (methodCount < 1) {
- base.RegisterNativeMembers (nativeClass, type, methods);
- return;
- }
-
- JniNativeMethodRegistration [] natives = new JniNativeMethodRegistration [methodCount];
- int nativesIndex = 0;
-
- ReadOnlySpan methodsSpan = methods;
- bool needToRegisterNatives = false;
-
- while (!methodsSpan.IsEmpty) {
- int newLineIndex = methodsSpan.IndexOf ('\n');
-
- ReadOnlySpan methodLine = methodsSpan.Slice (0, newLineIndex != -1 ? newLineIndex : methodsSpan.Length);
- if (!methodLine.IsEmpty) {
- SplitMethodLine (methodLine,
- out ReadOnlySpan name,
- out ReadOnlySpan signature,
- out ReadOnlySpan callbackString,
- out ReadOnlySpan callbackDeclaringTypeString);
-
- Delegate? callback = null;
- if (callbackString.SequenceEqual ("__export__")) {
- throw new InvalidOperationException (FormattableString.Invariant ($"Methods such as {callbackString.ToString ()} are not implemented!"));
- } else {
- Type callbackDeclaringType = type;
- if (!callbackDeclaringTypeString.IsEmpty) {
- callbackDeclaringType = Type.GetType (callbackDeclaringTypeString.ToString (), throwOnError: true)!;
- }
- while (callbackDeclaringType.ContainsGenericParameters) {
- callbackDeclaringType = callbackDeclaringType.BaseType!;
- }
-
- GetCallbackHandler connector = (GetCallbackHandler) Delegate.CreateDelegate (typeof (GetCallbackHandler),
- callbackDeclaringType, callbackString.ToString ());
- callback = connector ();
- }
-
- if (callback != null) {
- needToRegisterNatives = true;
- natives [nativesIndex++] = new JniNativeMethodRegistration (name.ToString (), signature.ToString (), callback);
- }
- }
-
- methodsSpan = newLineIndex != -1 ? methodsSpan.Slice (newLineIndex + 1) : default;
- }
-
- if (needToRegisterNatives) {
- JniEnvironment.Types.RegisterNatives (nativeClass.PeerReference, natives, nativesIndex);
- }
- }
-
-
- protected override IEnumerable GetTypesForSimpleReference (string jniSimpleReference)
- {
- // Base class contains built-in mappings (e.g. java/lang/String → System.String)
- // which must take priority over ManagedTypeMapping (which would return Java.Lang.String).
- foreach (var t in base.GetTypesForSimpleReference (jniSimpleReference)) {
- yield return t;
- }
- if (ManagedTypeMapping.TryGetType (jniSimpleReference, out var target)) {
- yield return target;
- }
- }
-
- protected override IEnumerable GetSimpleReferences (Type type)
- {
- foreach (var r in base.GetSimpleReferences (type)) {
- yield return r;
- }
-
- if (ManagedTypeMapping.TryGetJniName (type, out var jniName)) {
- yield return jniName;
- }
- }
-
- protected override IReadOnlyList? GetStaticMethodFallbackTypesCore (string jniSimpleReference)
- {
- return JniRemappingLookup.GetStaticMethodFallbackTypes (jniSimpleReference, useReplacementTypes: false);
- }
-
- static int CountMethods (ReadOnlySpan methodsSpan)
- {
- int count = 0;
- while (!methodsSpan.IsEmpty) {
- count++;
-
- int newLineIndex = methodsSpan.IndexOf ('\n');
- methodsSpan = newLineIndex != -1 ? methodsSpan.Slice (newLineIndex + 1) : default;
- }
- return count;
- }
-
- static void SplitMethodLine (
- ReadOnlySpan methodLine,
- out ReadOnlySpan name,
- out ReadOnlySpan signature,
- out ReadOnlySpan callback,
- out ReadOnlySpan callbackDeclaringType)
- {
- int colonIndex = methodLine.IndexOf (':');
- name = methodLine.Slice (0, colonIndex);
- methodLine = methodLine.Slice (colonIndex + 1);
-
- colonIndex = methodLine.IndexOf (':');
- signature = methodLine.Slice (0, colonIndex);
- methodLine = methodLine.Slice (colonIndex + 1);
-
- colonIndex = methodLine.IndexOf (':');
- callback = methodLine.Slice (0, colonIndex != -1 ? colonIndex : methodLine.Length);
-
- callbackDeclaringType = colonIndex != -1 ? methodLine.Slice (colonIndex + 1) : default;
- }
-
- delegate Delegate GetCallbackHandler ();
-}
diff --git a/src/Mono.Android/Microsoft.Android.Runtime/ManagedTypeMapping.cs b/src/Mono.Android/Microsoft.Android.Runtime/ManagedTypeMapping.cs
deleted file mode 100644
index 3cc7d790342..00000000000
--- a/src/Mono.Android/Microsoft.Android.Runtime/ManagedTypeMapping.cs
+++ /dev/null
@@ -1,106 +0,0 @@
-using System;
-using System.Buffers.Binary;
-using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
-using System.IO.Hashing;
-using System.Runtime.InteropServices;
-using System.Text;
-using Android.Runtime;
-
-namespace Microsoft.Android.Runtime;
-
-internal static class ManagedTypeMapping
-{
- internal static bool TryGetType (string jniName, [NotNullWhen (true)] out Type? type)
- {
- type = null;
-
- // the hashes array is sorted and all the hashes are unique
- ulong jniNameHash = Hash (jniName);
- int jniNameHashIndex = MemoryExtensions.BinarySearch (JniNameHashes, jniNameHash);
- if (jniNameHashIndex < 0) {
- return false;
- }
-
- // we need to make sure if this is the right match or if it is a hash collision
- if (jniName != GetJniNameByJniNameHashIndex (jniNameHashIndex)) {
- return false;
- }
-
- type = GetTypeByJniNameHashIndex (jniNameHashIndex);
- if (type is null) {
- throw new InvalidOperationException ($"Type for {jniName} (hash: {jniNameHash}, index: {jniNameHashIndex}) not found.");
- }
-
- return true;
- }
-
- internal static bool TryGetJniName (Type type, [NotNullWhen (true)] out string? jniName)
- {
- jniName = null;
-
- string? assemblyQualifiedName = type.AssemblyQualifiedName;
- if (assemblyQualifiedName is null) {
- jniName = null;
- return false;
- }
-
- ReadOnlySpan typeName = GetSimplifiedAssemblyQualifiedTypeName (assemblyQualifiedName);
-
- // the hashes array is sorted and all the hashes are unique
- ulong typeNameHash = Hash (typeName);
- int typeNameHashIndex = MemoryExtensions.BinarySearch (TypeNameHashes, typeNameHash);
- if (typeNameHashIndex < 0) {
- return false;
- }
-
- // we need to make sure if this is the match or if it is a hash collision
- if (!typeName.SequenceEqual (GetTypeNameByTypeNameHashIndex (typeNameHashIndex))) {
- return false;
- }
-
- jniName = GetJniNameByTypeNameHashIndex (typeNameHashIndex);
- if (jniName is null) {
- throw new InvalidOperationException ($"JNI name for {typeName} (hash: {typeNameHash}, index: {typeNameHashIndex}) not found.");
- }
-
- return true;
- }
-
- private static ulong Hash (ReadOnlySpan value)
- {
- ReadOnlySpan bytes = MemoryMarshal.AsBytes (value);
- ulong hash = XxHash3.HashToUInt64 (bytes);
-
- // The bytes in the hashes array are stored as little endian. If the target platform is big endian,
- // we need to reverse the endianness of the hash.
- if (!BitConverter.IsLittleEndian) {
- hash = BinaryPrimitives.ReverseEndianness (hash);
- }
-
- return hash;
- }
-
- // This method keeps only the full type name and the simple assembly name.
- // It drops the version, culture, and public key information.
- //
- // For example: "System.Int32, System.Private.CoreLib, Version=9.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e"
- // becomes: "System.Int32, System.Private.CoreLib"
- private static ReadOnlySpan GetSimplifiedAssemblyQualifiedTypeName(string assemblyQualifiedName)
- {
- var commaIndex = assemblyQualifiedName.IndexOf(',');
- var secondCommaIndex = assemblyQualifiedName.IndexOf(',', startIndex: commaIndex + 1);
- return secondCommaIndex < 0
- ? assemblyQualifiedName
- : assemblyQualifiedName.AsSpan(0, secondCommaIndex);
- }
-
- // Replaced by src/Microsoft.Android.Sdk.ILLink/TypeMappingStep.cs
- private static ReadOnlySpan TypeNameHashes => throw new NotImplementedException ();
- private static Type? GetTypeByJniNameHashIndex (int jniNameHashIndex) => throw new NotImplementedException ();
- private static string? GetJniNameByJniNameHashIndex (int jniNameHashIndex) => throw new NotImplementedException ();
-
- private static ReadOnlySpan JniNameHashes => throw new NotImplementedException ();
- private static string? GetJniNameByTypeNameHashIndex (int typeNameHashIndex) => throw new NotImplementedException ();
- private static string? GetTypeNameByTypeNameHashIndex (int typeNameHashIndex) => throw new NotImplementedException ();
-}
diff --git a/src/Mono.Android/Microsoft.Android.Runtime/RuntimeFeature.cs b/src/Mono.Android/Microsoft.Android.Runtime/RuntimeFeature.cs
index 5d20f9e5ac4..f15a79ff6f4 100644
--- a/src/Mono.Android/Microsoft.Android.Runtime/RuntimeFeature.cs
+++ b/src/Mono.Android/Microsoft.Android.Runtime/RuntimeFeature.cs
@@ -5,7 +5,6 @@ namespace Microsoft.Android.Runtime;
static class RuntimeFeature
{
- const bool ManagedTypeMapEnabledByDefault = false;
const bool IsMonoRuntimeEnabledByDefault = true;
const bool IsCoreClrRuntimeEnabledByDefault = false;
const bool IsNativeAotRuntimeEnabledByDefault = false;
@@ -17,10 +16,6 @@ static class RuntimeFeature
const string FeatureSwitchPrefix = "Microsoft.Android.Runtime.RuntimeFeature.";
const string StartupHookProviderSwitch = "System.StartupHookProvider.IsSupported";
- [FeatureSwitchDefinition ($"{FeatureSwitchPrefix}{nameof (ManagedTypeMap)}")]
- internal static bool ManagedTypeMap { get; } =
- AppContext.TryGetSwitch ($"{FeatureSwitchPrefix}{nameof (ManagedTypeMap)}", out bool isEnabled) ? isEnabled : ManagedTypeMapEnabledByDefault;
-
[FeatureSwitchDefinition ($"{FeatureSwitchPrefix}{nameof (IsMonoRuntime)}")]
internal static bool IsMonoRuntime { get; } =
AppContext.TryGetSwitch ($"{FeatureSwitchPrefix}{nameof (IsMonoRuntime)}", out bool isEnabled) ? isEnabled : IsMonoRuntimeEnabledByDefault;
diff --git a/src/Mono.Android/Mono.Android.csproj b/src/Mono.Android/Mono.Android.csproj
index 611ef7edf07..0b21238d63d 100644
--- a/src/Mono.Android/Mono.Android.csproj
+++ b/src/Mono.Android/Mono.Android.csproj
@@ -363,8 +363,6 @@
-
-
diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets
index e145c311485..53f153a8720 100644
--- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets
+++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets
@@ -17,7 +17,7 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android.
<_AndroidRuntimePackRuntime>NativeAOT
<_AndroidUseWorkloadNativeLinker Condition=" '$(_AndroidUseWorkloadNativeLinker)' == '' ">true
<_AndroidJcwCodegenTarget Condition=" '$(_AndroidJcwCodegenTarget)' == '' ">JavaInterop1
- <_AndroidTypeMapImplementation Condition=" '$(_AndroidTypeMapImplementation)' == '' ">managed
+ <_AndroidTypeMapImplementation Condition=" '$(_AndroidTypeMapImplementation)' == '' ">trimmable
true
diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.RuntimeConfig.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.RuntimeConfig.targets
index 276cc236459..fe4db586982 100644
--- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.RuntimeConfig.targets
+++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.RuntimeConfig.targets
@@ -12,7 +12,6 @@ See: https://github.com/dotnet/runtime/blob/b13715b6984889a709ba29ea8a1961db469f
<_BinaryRuntimeConfigPath>$(IntermediateOutputPath)$(ProjectRuntimeConfigFileName).bin
- <_AndroidUseManagedTypeMap Condition=" '$(_AndroidTypeMapImplementation)' == 'managed' ">true
<_AndroidEnableObjectReferenceLogging Condition=" '$(_AndroidEnableObjectReferenceLogging)' == '' And '$(PublishTrimmed)' == 'true' ">false
@@ -54,10 +53,6 @@ See: https://github.com/dotnet/runtime/blob/b13715b6984889a709ba29ea8a1961db469f
Value="$(AndroidAvoidEmitForPerformance)"
Trim="true"
/>
-
@@ -165,7 +164,6 @@
-->
<_TrimmerDumpDependencies Condition=" '$(LinkerDumpDependencies)' == 'true' ">true
<_AndroidLinkerCustomStepAssembly>$(MSBuildThisFileDirectory)..\tools\Microsoft.Android.Sdk.ILLink.dll
- <_SystemIOHashingAssemblyPath>$(MSBuildThisFileDirectory)..\tools\System.IO.Hashing.dll
<_ProguardProjectConfiguration Condition=" '$(AndroidLinkTool)' != '' ">$(IntermediateOutputPath)proguard\proguard_project_references.cfg
@@ -174,7 +172,6 @@
https://github.com/dotnet/sdk/blob/a5393731b5b7b225692fff121f747fbbc9e8b140/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.ILLink.targets#L147
-->
<_TrimmerCustomData Include="AndroidCustomViewMapFile" Value="$(_OuterCustomViewMapFile)" />
- <_TrimmerCustomData Include="SystemIOHashingAssemblyPath" Value="$(_SystemIOHashingAssemblyPath)" />
- <_TrimmerCustomSteps
- Condition=" '$(_AndroidTypeMapImplementation)' == 'managed' "
- Include="$(_AndroidLinkerCustomStepAssembly)"
- AfterStep="CleanStep"
- Type="Microsoft.Android.Sdk.ILLink.TypeMappingStep"
- />
+
diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateTypeMappings.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateTypeMappings.cs
index 1d6dfb5a434..b703e39d30d 100644
--- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateTypeMappings.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateTypeMappings.cs
@@ -4,7 +4,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
-using Java.Interop.Tools.Cecil;
using Microsoft.Android.Build.Tasks;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
@@ -39,8 +38,6 @@ public class GenerateTypeMappings : AndroidTask
[Required]
public string [] SupportedAbis { get; set; } = [];
- public string TypemapImplementation { get; set; } = "llvm-ir";
-
[Required]
public string TypemapOutputDirectory { get; set; } = "";
@@ -53,7 +50,7 @@ public override bool RunTask ()
androidRuntime = MonoAndroidHelper.ParseAndroidRuntime (AndroidRuntime);
if (androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.NativeAOT) {
- // NativeAOT typemaps are generated in `Microsoft.Android.Sdk.ILLink.TypeMappingStep`
+ // NativeAOT uses the trimmable typemap.
Log.LogDebugMessage ("Skipping type maps for NativeAOT.");
return !Log.HasLoggedErrors;
}
@@ -89,11 +86,6 @@ void GenerateTypeMap (AndroidTargetArch arch, List assemblies)
if (state is null)
return;
- if (TypemapImplementation != "llvm-ir") {
- Log.LogDebugMessage ($"TypemapImplementation='{TypemapImplementation}' will write an empty native typemap.");
- state.XmlFiles.Clear ();
- }
-
var tmg = new TypeMapGenerator (Log, state, androidRuntime);
tmg.Generate (Debug, SkipJniAddNativeMethodRegistrationAttributeScan, TypemapOutputDirectory);
@@ -119,7 +111,7 @@ void GenerateAllTypeMappingsFromNativeState (bool useMarshalMethods)
foreach (var kvp in nativeCodeGenStates) {
NativeCodeGenState state = kvp.Value;
templateCodeGenState = state;
- GenerateTypeMapFromNativeState (state, useMarshalMethods);
+ GenerateTypeMapFromNativeState (state);
}
if (templateCodeGenState is null)
@@ -130,20 +122,15 @@ void GenerateAllTypeMappingsFromNativeState (bool useMarshalMethods)
NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent = templateCodeGenState.JniAddNativeMethodRegistrationAttributePresent;
}
- void GenerateTypeMapFromNativeState (NativeCodeGenState state, bool useMarshalMethods)
+ void GenerateTypeMapFromNativeState (NativeCodeGenState state)
{
if (androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.NativeAOT) {
- // NativeAOT typemaps are generated in `Microsoft.Android.Sdk.ILLink.TypeMappingStep`
+ // NativeAOT uses the trimmable typemap.
Log.LogDebugMessage ("Skipping type maps for NativeAOT.");
return;
}
Log.LogDebugMessage ($"Generating type maps from native state for architecture '{state.TargetArch}'");
- if (TypemapImplementation != "llvm-ir") {
- Log.LogDebugMessage ($"TypemapImplementation='{TypemapImplementation}' will write an empty native typemap.");
- state = new NativeCodeGenState (state.TargetArch, new TypeDefinitionCache (), state.Resolver, [], [], state.Classifier);
- }
-
var tmg = new TypeMapGenerator (Log, new NativeCodeGenStateAdapter (state), androidRuntime);
tmg.Generate (Debug, SkipJniAddNativeMethodRegistrationAttributeScan, TypemapOutputDirectory);
diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs
index 05a317d6669..76f3c3110e4 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs
@@ -166,15 +166,13 @@ public void NativeAOT ()
ProjectName = "Hello",
};
proj.SetRuntime (AndroidRuntime.NativeAOT);
- proj.SetProperty ("_ExtraTrimmerArgs", "--verbose");
- // Required for java/util/ArrayList assertion below
+ // Exercise typemap generation for framework generic mappings.
proj.MainActivity = proj.DefaultMainActivity
.Replace ("//${AFTER_ONCREATE}", "new Android.Runtime.JavaList (); new Android.Runtime.JavaList ();");
using var b = CreateApkBuilder ();
Assert.IsTrue (b.Build (proj), "Build should have succeeded.");
- b.Output.AssertTargetIsNotSkipped ("_PrepareLinking");
string [] mono_classes = [
"Lmono/MonoRuntimeProvider;",
@@ -191,66 +189,9 @@ public void NativeAOT ()
var intermediate = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath);
var output = Path.Combine (Root, b.ProjectDirectory, proj.OutputPath);
- var linkedMonoAndroidAssembly = Path.Combine (intermediate, "android-arm64", "linked", "Mono.Android.dll");
- FileAssert.Exists (linkedMonoAndroidAssembly);
- var javaClassNames = new List ();
- var types = new List ();
-
- using (var assembly = AssemblyDefinition.ReadAssembly (linkedMonoAndroidAssembly)) {
- var typeName = "Android.App.Activity";
- var methodName = "GetOnCreate_Landroid_os_Bundle_Handler";
- var type = assembly.MainModule.GetType (typeName);
- Assert.IsNotNull (type, $"{linkedMonoAndroidAssembly} should contain {typeName}");
- var method = type.Methods.FirstOrDefault (m => m.Name == methodName);
- Assert.IsNotNull (method, $"{linkedMonoAndroidAssembly} should contain {typeName}.{methodName}");
-
- type = assembly.MainModule.Types.FirstOrDefault (t => t.Name == "ManagedTypeMapping");
- Assert.IsNotNull (type, $"{linkedMonoAndroidAssembly} should contain ManagedTypeMapping");
- method = type.Methods.FirstOrDefault (m => m.Name == "GetJniNameByTypeNameHashIndex");
- Assert.IsNotNull (method, $"{type.Name} should contain GetJniNameByTypeNameHashIndex");
-
- foreach (var i in method.Body.Instructions) {
- if (i.OpCode != Mono.Cecil.Cil.OpCodes.Ldstr)
- continue;
- if (i.Operand is not string javaName)
- continue;
- if (i.Next.OpCode != Mono.Cecil.Cil.OpCodes.Ret)
- continue;
- javaClassNames.Add (javaName);
- }
-
- method = type.Methods.FirstOrDefault (m => m.Name == "GetTypeByJniNameHashIndex");
- Assert.IsNotNull (method, $"{type.Name} should contain GetTypeByJniNameHashIndex");
-
- foreach (var i in method.Body.Instructions) {
- if (i.OpCode != Mono.Cecil.Cil.OpCodes.Ldtoken)
- continue;
- if (i.Operand is not TypeReference typeReference)
- continue;
- if (i.Next?.OpCode != Mono.Cecil.Cil.OpCodes.Call)
- continue;
- if (i.Next.Next?.OpCode != Mono.Cecil.Cil.OpCodes.Ret)
- continue;
- types.Add (typeReference);
- }
-
- // Basic types
- AssertTypeMap ("java/lang/Object", "Java.Lang.Object");
- AssertTypeMap ("java/lang/String", "Java.Lang.String");
- AssertTypeMap ("[Ljava/lang/Object;", "Java.Interop.JavaArray`1");
- AssertTypeMap ("java/util/ArrayList", "Android.Runtime.JavaList");
- AssertTypeMap ("android/app/Activity", "Android.App.Activity");
- AssertTypeMap ("android/widget/Button", "Android.Widget.Button");
- Assert.IsFalse (StringAssertEx.ContainsText (b.LastBuildOutput,
- "Duplicate typemap entry for java/util/ArrayList => Android.Runtime.JavaList`1"),
- "Should get log message about duplicate Android.Runtime.JavaList`1!");
-
- // Special *Invoker case
- AssertTypeMap ("android/view/View$OnClickListener", "Android.Views.View/IOnClickListener");
- Assert.IsFalse (StringAssertEx.ContainsText (b.LastBuildOutput,
- "Duplicate typemap entry for android/view/View$OnClickListener => Android.Views.View/IOnClickListenerInvoker"),
- "Should get log message about duplicate IOnClickListenerInvoker!");
- }
+ var typemapDir = Path.Combine (intermediate, "typemap");
+ FileAssert.Exists (Path.Combine (typemapDir, "_Microsoft.Android.TypeMaps.dll"));
+ FileAssert.Exists (Path.Combine (typemapDir, "_Mono.Android.TypeMap.dll"));
// Verify that Java stubs for Mono.Android.dll were generated, instead of using mono.android.jar/dex
var onLayoutChangeListenerImplementor = Path.Combine (intermediate, "android", "src", "mono", "android", "view", "View_OnClickListenerImplementor.java");
@@ -271,18 +212,6 @@ public void NativeAOT ()
foreach (var nativeaot_file in nativeaot_files) {
Assert.IsTrue (zip.ContainsEntry (nativeaot_file, caseSensitive: true), $"APK must contain `{nativeaot_file}`.");
}
-
- void AssertTypeMap(string javaName, string managedName)
- {
- var javaNameIndex = javaClassNames.FindIndex (name => name == javaName);
- var typeIndex = types.FindIndex (td => td.ToString() == managedName);
-
- if (javaNameIndex < 0) {
- Assert.Fail ($"TypeMapping should contain \"{javaName}\"!");
- } else if (typeIndex < 0) {
- Assert.Fail ($"TypeMapping should contain \"{managedName}\"!");
- }
- }
}
[Test]
diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
index ea3cf49c141..41d5bacc865 100644
--- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
+++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
@@ -2930,8 +2930,10 @@ because xbuild doesn't support framework reference assemblies.
Condition=" '$(DesignTimeBuild)' != 'true' "/>
-
+
+
+ Condition=" '$(_AndroidTypeMapImplementation)' == 'llvm-ir' " />
diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs
index 5eae82b12ce..103f0856749 100644
--- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs
+++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs
@@ -51,9 +51,6 @@ static IEnumerable
-
-
+
+
diff --git a/tests/Mono.Android-Tests/Mono.Android-Tests/Java.Lang/ObjectTest.cs b/tests/Mono.Android-Tests/Mono.Android-Tests/Java.Lang/ObjectTest.cs
index 764fc416379..b1e2e2fabe3 100644
--- a/tests/Mono.Android-Tests/Mono.Android-Tests/Java.Lang/ObjectTest.cs
+++ b/tests/Mono.Android-Tests/Mono.Android-Tests/Java.Lang/ObjectTest.cs
@@ -86,7 +86,7 @@ public void NestedDisposeInvocations ()
value.Dispose ();
}
- // TODO: fix on CoreCLR once new managed type maps are implemented. Currently fails with
+ // TODO: fix on CoreCLR once the typemap behavior is fixed. Currently fails with
// java/lang/Object is typemap'd to Java.InteropTests.JavaLangRemappingTestObject, not Java.Lang.Object, Mono.Android!
[Test]
public void java_lang_Object_Is_Java_Lang_Object ()