From 70bd636b04ebf9dba36c632cdec586452e98cb8a Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 12 Feb 2025 09:23:13 -0600 Subject: [PATCH] [NativeAOT] introduce `Microsoft.Android.Runtime.NativeAOT.dll` (#9760) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This moves: * C# code from `samples/NativeAOT` to a new assembly, `Microsoft.Android.Runtime.NativeAOT.dll`. * Java code from `samples/NativeAOT` to `Xamarin.Android.Build.Tasks`, to be generated at build time. * C# code from `Java.Interop.Environment.csproj` has been trimmed down, copied into `Microsoft.Android.Runtime.NativeAOT.dll`. * Minimum Viable Product™ "typemap" implementation. * Change namespace to `Microsoft.Android.Runtime` ## Minimum Viable Product™ typemaps A quick-and-dirty -- and totally unoptimized -- typemap implementation has been added as a new `TypeMappingStep` into `Microsoft.Android.Sdk.ILLink`. Given this initial starting point within `NativeAotTypeManager`: partial class NativeAotTypeManager { IDictionary TypeMappings = new Dictionary(StringComparer.Ordinal); NativeAotTypeManager () { InitializeTypeMappings (); } void InitializeTypeMappings () { throw new InvalidOperationException ("Should be replaced at build time!"); } } then at build time `TypeMappingStep` will *replace* the body of `NativeAotTypeManager.InitializeTypeMappings()` with repeated `IDictionary.Add()` calls for each type which survived linking: // Cecil-generated code, C# equivalent void InitializeTypeMappings () { TypeMappings.Add ("java/lang/Object", typeof (Java.Lang.Object)); TypeMappings.Add ("android/app/Application", typeof (Android.App.Application)); // … } --- Xamarin.Android.sln | 7 + .../Microsoft.Android.Runtime.proj | 6 +- samples/NativeAOT/AndroidManifest.xml | 7 - samples/NativeAOT/NativeAOT.csproj | 8 - .../JavaInteropRuntime.cs | 4 +- .../Android.Runtime.NativeAOT}/Logging.cs | 2 +- .../NativeAotTypeManager.cs | 42 ++-- .../NativeAotValueManager.cs | 31 ++- .../AssemblyInfo.cs | 5 + .../Java.Interop/JreRuntime.cs | 98 ++++++++ .../ManagedObjectReferenceManager.cs | 229 ++++++++++++++++++ ...Microsoft.Android.Runtime.NativeAOT.csproj | 41 ++++ .../Microsoft.Android.Sdk.ILLink.csproj | 8 +- .../TypeMappingStep.cs | 104 ++++++++ .../Properties/AssemblyInfo.cs.in | 3 +- .../Microsoft.Android.Sdk.ILLink.targets | 7 + .../Microsoft.Android.Sdk.NativeAOT.targets | 2 + .../Resources}/JavaInteropRuntime.java | 4 +- .../Resources}/NativeAotRuntimeProvider.java | 0 .../Tasks/GenerateJavaStubs.cs | 30 ++- .../Utilities/ManifestDocument.cs | 13 +- .../Xamarin.Android.Build.Tasks.csproj | 19 +- .../Xamarin.Android.Common.targets | 6 + 23 files changed, 593 insertions(+), 83 deletions(-) rename {samples/NativeAOT => src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT}/JavaInteropRuntime.cs (95%) rename {samples/NativeAOT => src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT}/Logging.cs (98%) rename {samples/NativeAOT => src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT}/NativeAotTypeManager.cs (83%) rename {samples/NativeAOT => src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT}/NativeAotValueManager.cs (87%) create mode 100644 src/Microsoft.Android.Runtime.NativeAOT/AssemblyInfo.cs create mode 100644 src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/JreRuntime.cs create mode 100644 src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/ManagedObjectReferenceManager.cs create mode 100644 src/Microsoft.Android.Runtime.NativeAOT/Microsoft.Android.Runtime.NativeAOT.csproj create mode 100644 src/Microsoft.Android.Sdk.ILLink/TypeMappingStep.cs rename {samples/NativeAOT => src/Xamarin.Android.Build.Tasks/Resources}/JavaInteropRuntime.java (60%) rename {samples/NativeAOT => src/Xamarin.Android.Build.Tasks/Resources}/NativeAotRuntimeProvider.java (100%) diff --git a/Xamarin.Android.sln b/Xamarin.Android.sln index 5227e5fd898..782b20c69db 100644 --- a/Xamarin.Android.sln +++ b/Xamarin.Android.sln @@ -125,6 +125,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Android.Sdk.Analy EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "proguard-android", "src\proguard-android\proguard-android.csproj", "{5FD0133B-69E5-4474-9B67-9FD1D0150C70}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Android.Runtime.NativeAOT", "src\Microsoft.Android.Runtime.NativeAOT\Microsoft.Android.Runtime.NativeAOT.csproj", "{E8831F32-11D7-D42C-E43C-711998BC357A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|AnyCPU = Debug|AnyCPU @@ -347,6 +349,10 @@ Global {5FD0133B-69E5-4474-9B67-9FD1D0150C70}.Debug|AnyCPU.Build.0 = Debug|Any CPU {5FD0133B-69E5-4474-9B67-9FD1D0150C70}.Release|AnyCPU.ActiveCfg = Release|Any CPU {5FD0133B-69E5-4474-9B67-9FD1D0150C70}.Release|AnyCPU.Build.0 = Release|Any CPU + {E8831F32-11D7-D42C-E43C-711998BC357A}.Debug|AnyCPU.ActiveCfg = Debug|Any CPU + {E8831F32-11D7-D42C-E43C-711998BC357A}.Debug|AnyCPU.Build.0 = Debug|Any CPU + {E8831F32-11D7-D42C-E43C-711998BC357A}.Release|AnyCPU.ActiveCfg = Release|Any CPU + {E8831F32-11D7-D42C-E43C-711998BC357A}.Release|AnyCPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -406,6 +412,7 @@ Global {A39B6D7C-6616-40D6-8AE4-C6CEE93D2708} = {CAB438D8-B0F5-4AF0-BEBD-9E2ADBD7B483} {5E806C9F-1B67-4B6B-A6AB-258834250DBB} = {FFCF518F-2A4A-40A2-9174-2EE13B76C723} {5FD0133B-69E5-4474-9B67-9FD1D0150C70} = {FFCF518F-2A4A-40A2-9174-2EE13B76C723} + {E8831F32-11D7-D42C-E43C-711998BC357A} = {04E3E11E-B47D-4599-8AFC-50515A95E715} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {53A1F287-EFB2-4D97-A4BB-4A5E145613F6} diff --git a/build-tools/create-packs/Microsoft.Android.Runtime.proj b/build-tools/create-packs/Microsoft.Android.Runtime.proj index 9c3c22c1390..5f19f16ffdc 100644 --- a/build-tools/create-packs/Microsoft.Android.Runtime.proj +++ b/build-tools/create-packs/Microsoft.Android.Runtime.proj @@ -37,7 +37,11 @@ projects that use the Microsoft.Android framework in .NET 6+. <_AndroidRuntimePackAssemblies Include="$(_MonoAndroidNETDefaultOutDir)Java.Interop.dll" /> <_AndroidRuntimePackAssemblies Include="$(_MonoAndroidNETDefaultOutDir)Mono.Android.dll" /> <_AndroidRuntimePackAssemblies Include="$(_MonoAndroidNETDefaultOutDir)Mono.Android.Runtime.dll" /> - + + <_AndroidRuntimePackAssemblies + Include="$(_MonoAndroidNETOutputRoot)$(AndroidLatestStableApiLevel)\Microsoft.Android.Runtime.NativeAOT.dll" + Condition=" '$(AndroidRuntime)' == 'NativeAOT' " + /> <_AndroidRuntimePackAssemblies Include="$(_MonoAndroidNETOutputRoot)$(AndroidLatestStableApiLevel)\Mono.Android.Export.dll" /> diff --git a/samples/NativeAOT/AndroidManifest.xml b/samples/NativeAOT/AndroidManifest.xml index 70e89c99003..3fead98ca0f 100644 --- a/samples/NativeAOT/AndroidManifest.xml +++ b/samples/NativeAOT/AndroidManifest.xml @@ -1,13 +1,6 @@ - - \ No newline at end of file diff --git a/samples/NativeAOT/NativeAOT.csproj b/samples/NativeAOT/NativeAOT.csproj index e392eaa7646..18922a65b67 100644 --- a/samples/NativeAOT/NativeAOT.csproj +++ b/samples/NativeAOT/NativeAOT.csproj @@ -9,10 +9,6 @@ 1 1.0 apk - true - - true - ..\..\product.snk android-arm64 @@ -29,8 +25,4 @@ <_FastDeploymentDiagnosticLogging>true - - - - \ No newline at end of file diff --git a/samples/NativeAOT/JavaInteropRuntime.cs b/src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/JavaInteropRuntime.cs similarity index 95% rename from samples/NativeAOT/JavaInteropRuntime.cs rename to src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/JavaInteropRuntime.cs index 8c86e5d264b..869d82b1cd5 100644 --- a/samples/NativeAOT/JavaInteropRuntime.cs +++ b/src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/JavaInteropRuntime.cs @@ -2,7 +2,7 @@ using Java.Interop; using System.Runtime.InteropServices; -namespace NativeAOT; +namespace Microsoft.Android.Runtime; static class JavaInteropRuntime { @@ -35,7 +35,7 @@ static void init (IntPtr jnienv, IntPtr klass) { try { var typeManager = new NativeAotTypeManager (); - var options = new JreRuntimeOptions { + var options = new NativeAotRuntimeOptions { EnvironmentPointer = jnienv, TypeManager = typeManager, ValueManager = new NativeAotValueManager (typeManager), diff --git a/samples/NativeAOT/Logging.cs b/src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/Logging.cs similarity index 98% rename from samples/NativeAOT/Logging.cs rename to src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/Logging.cs index 5073ba9e5a3..880e107e72f 100644 --- a/samples/NativeAOT/Logging.cs +++ b/src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/Logging.cs @@ -6,7 +6,7 @@ using System.Runtime.InteropServices; using System.Text; -namespace NativeAOT; +namespace Microsoft.Android.Runtime; internal sealed class LogcatTextWriter : TextWriter { diff --git a/samples/NativeAOT/NativeAotTypeManager.cs b/src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/NativeAotTypeManager.cs similarity index 83% rename from samples/NativeAOT/NativeAotTypeManager.cs rename to src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/NativeAotTypeManager.cs index baffdef8859..b2f864587f3 100644 --- a/samples/NativeAOT/NativeAotTypeManager.cs +++ b/src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/NativeAotTypeManager.cs @@ -3,7 +3,7 @@ using Java.Interop; using Java.Interop.Tools.TypeNameMappings; -namespace NativeAOT; +namespace Microsoft.Android.Runtime; partial class NativeAotTypeManager : JniRuntime.JniTypeManager { @@ -11,25 +11,27 @@ partial class NativeAotTypeManager : JniRuntime.JniTypeManager { internal const DynamicallyAccessedMemberTypes Methods = DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods; internal const DynamicallyAccessedMemberTypes MethodsAndPrivateNested = Methods | DynamicallyAccessedMemberTypes.NonPublicNestedTypes; - // TODO: list of types specific to this application - Dictionary typeMappings = new () { - ["android/app/Activity"] = typeof (Android.App.Activity), - ["android/app/Application"] = typeof (Android.App.Application), - ["android/content/Context"] = typeof (Android.Content.Context), - ["android/content/ContextWrapper"] = typeof (Android.Content.ContextWrapper), - ["android/os/BaseBundle"] = typeof (Android.OS.BaseBundle), - ["android/os/Bundle"] = typeof (Android.OS.Bundle), - ["android/view/ContextThemeWrapper"] = typeof (Android.Views.ContextThemeWrapper), - ["my/MainActivity"] = typeof (MainActivity), - ["my/MainApplication"] = typeof (MainApplication), - }; + readonly IDictionary TypeMappings = new Dictionary (StringComparer.Ordinal); public NativeAotTypeManager () { - AndroidLog.Print (AndroidLogLevel.Info, "NativeAotTypeManager", $"# jonp: NativeAotTypeManager()"); + AndroidLog.Print (AndroidLogLevel.Info, "NativeAotTypeManager", $"NativeAotTypeManager()"); + var startTicks = global::System.Environment.TickCount; + InitializeTypeMappings (); + var endTicks = global::System.Environment.TickCount; + AndroidLog.Print (AndroidLogLevel.Info, "NativeAotTypeManager", $"InitializeTypeMappings() took {endTicks - startTicks}ms"); } - protected override Type? GetInvokerTypeCore (Type type) + void InitializeTypeMappings () + { + // Should be replaced by src/Microsoft.Android.Sdk.ILLink/TypeMappingStep.cs + throw new InvalidOperationException ("TypeMappings should be replaced during trimming!"); + } + + [return: DynamicallyAccessedMembers (Constructors)] + protected override Type? GetInvokerTypeCore ( + [DynamicallyAccessedMembers (Constructors)] + Type type) { const string suffix = "Invoker"; @@ -68,6 +70,10 @@ static Type MakeGenericType ( 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)] @@ -143,7 +149,7 @@ public override void RegisterNativeMembers ( protected override IEnumerable GetTypesForSimpleReference (string jniSimpleReference) { AndroidLog.Print (AndroidLogLevel.Info, "NativeAotTypeManager", $"# jonp: GetTypesForSimpleReference: jniSimpleReference=`{jniSimpleReference}`"); - if (typeMappings.TryGetValue (jniSimpleReference, out var target)) { + if (TypeMappings.TryGetValue (jniSimpleReference, out var target)) { Console.WriteLine ($"# jonp: GetTypesForSimpleReference: jniSimpleReference=`{jniSimpleReference}` -> `{target}`"); yield return target; } @@ -161,9 +167,7 @@ protected override IEnumerable GetSimpleReferences (Type type) IEnumerable CreateSimpleReferencesEnumerator (Type type) { - if (typeMappings == null) - yield break; - foreach (var e in typeMappings) { + foreach (var e in TypeMappings) { if (e.Value == type) yield return e.Key; } diff --git a/samples/NativeAOT/NativeAotValueManager.cs b/src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/NativeAotValueManager.cs similarity index 87% rename from samples/NativeAOT/NativeAotValueManager.cs rename to src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/NativeAotValueManager.cs index b1996b88b30..e54d49ca7e4 100644 --- a/samples/NativeAOT/NativeAotValueManager.cs +++ b/src/Microsoft.Android.Runtime.NativeAOT/Android.Runtime.NativeAOT/NativeAotValueManager.cs @@ -4,6 +4,7 @@ using System.Collections.ObjectModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.IO; using System.Linq; using System.Reflection; @@ -13,9 +14,9 @@ using Android.Runtime; using Java.Interop; -namespace NativeAOT; +namespace Microsoft.Android.Runtime; -internal class NativeAotValueManager : JniRuntime.JniValueManager +class NativeAotValueManager : JniRuntime.JniValueManager { const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; @@ -113,12 +114,12 @@ void WarnNotReplacing (int key, IJavaPeerable ignoreValue, IJavaPeerable keepVal "Warning: Not registering PeerReference={0} IdentityHashCode=0x{1} Instance={2} Instance.Type={3} Java.Type={4}; " + "keeping previously registered PeerReference={5} Instance={6} Instance.Type={7} Java.Type={8}.", ignoreValue.PeerReference.ToString (), - key.ToString ("x"), - RuntimeHelpers.GetHashCode (ignoreValue).ToString ("x"), + key.ToString ("x", CultureInfo.InvariantCulture), + RuntimeHelpers.GetHashCode (ignoreValue).ToString ("x", CultureInfo.InvariantCulture), ignoreValue.GetType ().FullName, JniEnvironment.Types.GetJniTypeNameFromInstance (ignoreValue.PeerReference), keepValue.PeerReference.ToString (), - RuntimeHelpers.GetHashCode (keepValue).ToString ("x"), + RuntimeHelpers.GetHashCode (keepValue).ToString ("x", CultureInfo.InvariantCulture), keepValue.GetType ().FullName, JniEnvironment.Types.GetJniTypeNameFromInstance (keepValue.PeerReference)); } @@ -186,8 +187,8 @@ public override void FinalizePeer (IJavaPeerable value) if (o.LogGlobalReferenceMessages) { o.WriteGlobalReferenceLine ("Finalizing PeerReference={0} IdentityHashCode=0x{1} Instance=0x{2} Instance.Type={3}", h.ToString (), - value.JniIdentityHashCode.ToString ("x"), - RuntimeHelpers.GetHashCode (value).ToString ("x"), + value.JniIdentityHashCode.ToString ("x", CultureInfo.InvariantCulture), + RuntimeHelpers.GetHashCode (value).ToString ("x", CultureInfo.InvariantCulture), value.GetType ().ToString ()); } RemovePeer (value); @@ -200,8 +201,8 @@ public override void FinalizePeer (IJavaPeerable value) if (o.LogGlobalReferenceMessages) { o.WriteGlobalReferenceLine ("Finalizing PeerReference={0} IdentityHashCode=0x{1} Instance=0x{2} Instance.Type={3}", h.ToString (), - value.JniIdentityHashCode.ToString ("x"), - RuntimeHelpers.GetHashCode (value).ToString ("x"), + value.JniIdentityHashCode.ToString ("x", CultureInfo.InvariantCulture), + RuntimeHelpers.GetHashCode (value).ToString ("x", CultureInfo.InvariantCulture), value.GetType ().ToString ()); } value.SetPeerReference (new JniObjectReference ()); @@ -214,9 +215,11 @@ public override void ActivatePeer (IJavaPeerable? self, JniObjectReference refer try { ActivateViaReflection (reference, cinfo, argumentValues); } catch (Exception e) { - var m = string.Format ("Could not activate {{ PeerReference={0} IdentityHashCode=0x{1} Java.Type={2} }} for managed type '{3}'.", + var m = string.Format ( + CultureInfo.InvariantCulture, + "Could not activate {{ PeerReference={0} IdentityHashCode=0x{1} Java.Type={2} }} for managed type '{3}'.", reference, - GetJniIdentityHashCode (reference).ToString ("x"), + GetJniIdentityHashCode (reference).ToString ("x", CultureInfo.InvariantCulture), JniEnvironment.Types.GetJniTypeNameFromInstance (reference), cinfo.DeclaringType?.FullName); Debug.WriteLine (m); @@ -257,7 +260,11 @@ public override List GetSurfacedPeers () static readonly Type[] XAConstructorSignature = new Type [] { typeof (IntPtr), typeof (JniHandleOwnership) }; - protected override IJavaPeerable? TryCreatePeer (ref JniObjectReference reference, JniObjectReferenceOptions options, Type type) + protected override IJavaPeerable? TryCreatePeer ( + ref JniObjectReference reference, + JniObjectReferenceOptions options, + [DynamicallyAccessedMembers (Constructors)] + Type type) { var c = type.GetConstructor (ActivationConstructorBindingFlags, null, XAConstructorSignature, null); if (c != null) { diff --git a/src/Microsoft.Android.Runtime.NativeAOT/AssemblyInfo.cs b/src/Microsoft.Android.Runtime.NativeAOT/AssemblyInfo.cs new file mode 100644 index 00000000000..00c8d7afa79 --- /dev/null +++ b/src/Microsoft.Android.Runtime.NativeAOT/AssemblyInfo.cs @@ -0,0 +1,5 @@ +using System.Runtime.Versioning; + +// NOTE: silences the CA1416 analyzer about supported Android APIs +[assembly: TargetPlatformAttribute("Android35.0")] +[assembly: SupportedOSPlatformAttribute("Android21.0")] diff --git a/src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/JreRuntime.cs b/src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/JreRuntime.cs new file mode 100644 index 00000000000..630707a17cc --- /dev/null +++ b/src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/JreRuntime.cs @@ -0,0 +1,98 @@ +// Originally from: https://github.com/dotnet/java-interop/blob/dd3c1d0514addfe379f050627b3e97493e985da6/src/Java.Runtime.Environment/Java.Interop/JreRuntime.cs +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Threading; +using Microsoft.Android.Runtime; + +namespace Java.Interop { + + struct JavaVMInitArgs { + #pragma warning disable CS0649 // Field is never assigned to; + public JniVersion version; /* use JNI_VERSION_1_2 or later */ + + public int nOptions; + public IntPtr /* JavaVMOption[] */ options; + public byte ignoreUnrecognized; + #pragma warning restore CS0649 + } + + class NativeAotRuntimeOptions : JniRuntime.CreationOptions { + + public bool IgnoreUnrecognizedOptions {get; set;} + + public TextWriter? JniGlobalReferenceLogWriter {get; set;} + public TextWriter? JniLocalReferenceLogWriter {get; set;} + + public NativeAotRuntimeOptions () + { + JniVersion = JniVersion.v1_2; + } + + public JreRuntime CreateJreVM () + { + return new JreRuntime (this); + } + } + + class JreRuntime : JniRuntime + { + static JreRuntime () + { + } + + static NativeAotRuntimeOptions CreateJreVM (NativeAotRuntimeOptions builder) + { + if (builder == null) + throw new ArgumentNullException ("builder"); + if (builder.InvocationPointer == IntPtr.Zero && + builder.EnvironmentPointer == IntPtr.Zero && + string.IsNullOrEmpty (builder.JvmLibraryPath)) + throw new InvalidOperationException ($"Member `{nameof (NativeAotRuntimeOptions)}.{nameof (NativeAotRuntimeOptions.JvmLibraryPath)}` must be set."); + +#if NET + builder.TypeManager ??= new NativeAotTypeManager (); +#endif // NET + + builder.ValueManager ??= new NativeAotValueManager (builder.TypeManager); + builder.ObjectReferenceManager ??= new ManagedObjectReferenceManager (builder.JniGlobalReferenceLogWriter, builder.JniLocalReferenceLogWriter); + + if (builder.InvocationPointer != IntPtr.Zero || builder.EnvironmentPointer != IntPtr.Zero) + return builder; + + throw new NotImplementedException (); + } + + [UnconditionalSuppressMessage ("Trimming", "IL3000", Justification = "We check for a null Assembly.Location value!")] + internal static string? GetAssemblyLocation (Assembly assembly) + { + var location = assembly.Location; + if (!string.IsNullOrEmpty (location)) + return location; + return null; + } + + internal protected JreRuntime (NativeAotRuntimeOptions builder) + : base (CreateJreVM (builder)) + { + } + + public override string? GetCurrentManagedThreadName () + { + return Thread.CurrentThread.Name; + } + + public override string GetCurrentManagedThreadStackTrace (int skipFrames, bool fNeedFileInfo) + { + return new StackTrace (skipFrames, fNeedFileInfo) + .ToString (); + } + } +} diff --git a/src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/ManagedObjectReferenceManager.cs b/src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/ManagedObjectReferenceManager.cs new file mode 100644 index 00000000000..b152ff5b797 --- /dev/null +++ b/src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/ManagedObjectReferenceManager.cs @@ -0,0 +1,229 @@ +// Originally from: https://github.com/dotnet/java-interop/blob/dd3c1d0514addfe379f050627b3e97493e985da6/src/Java.Runtime.Environment/Java.Interop/ManagedObjectReferenceManager.cs +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; + +namespace Java.Interop { + + class ManagedObjectReferenceManager : JniRuntime.JniObjectReferenceManager { + + TextWriter? grefLog; + TextWriter? lrefLog; + + int grefCount; + int wgrefCount; + + + public override int GlobalReferenceCount => grefCount; + public override int WeakGlobalReferenceCount => wgrefCount; + + public override bool LogLocalReferenceMessages => lrefLog != null; + public override bool LogGlobalReferenceMessages => grefLog != null; + + public ManagedObjectReferenceManager (TextWriter? grefLog, TextWriter? lrefLog) + { + if (grefLog != null && lrefLog != null && object.ReferenceEquals (grefLog, lrefLog)) { + this.grefLog = this.lrefLog = TextWriter.Synchronized (grefLog); + return; + } + + var grefPath = Environment.GetEnvironmentVariable ("JAVA_INTEROP_GREF_LOG"); + var lrefPath = Environment.GetEnvironmentVariable ("JAVA_INTEROP_LREF_LOG"); + + bool samePath = !string.IsNullOrEmpty (grefPath) && + !string.IsNullOrEmpty (lrefPath) && + grefPath == lrefPath; + + if (grefLog != null) { + this.grefLog = TextWriter.Synchronized (grefLog); + } + if (lrefLog != null) { + this.lrefLog = TextWriter.Synchronized (lrefLog); + } + + if (this.grefLog == null && !string.IsNullOrEmpty (grefPath)) { + this.grefLog = TextWriter.Synchronized (CreateTextWriter (grefPath)); + } + if (this.lrefLog == null && samePath) { + this.lrefLog = this.grefLog; + } + if (this.lrefLog == null && !string.IsNullOrEmpty (lrefPath)) { + this.lrefLog = TextWriter.Synchronized (CreateTextWriter (lrefPath)); + } + } + + public override void OnSetRuntime (JniRuntime runtime) + { + base.OnSetRuntime (runtime); + } + + static TextWriter CreateTextWriter (string path) + { + return new StreamWriter (path, append: false, encoding: new UTF8Encoding (encoderShouldEmitUTF8Identifier: false)); + } + + public override void WriteLocalReferenceLine (string format, params object[] args) + { + if (lrefLog == null) + return; + lrefLog.WriteLine (format, args); + lrefLog.Flush (); + } + + public override JniObjectReference CreateLocalReference (JniObjectReference reference, ref int localReferenceCount) + { + if (!reference.IsValid) + return reference; + + var r = base.CreateLocalReference (reference, ref localReferenceCount); + + CreatedReference (lrefLog, "+l+ lrefc", localReferenceCount, reference, r, Runtime); + + return r; + } + + public override void DeleteLocalReference (ref JniObjectReference reference, ref int localReferenceCount) + { + if (!reference.IsValid) + return; + + var r = reference; + + base.DeleteLocalReference (ref reference, ref localReferenceCount); + + DeletedReference (lrefLog, "-l- lrefc", localReferenceCount, r, Runtime); + } + + public override void CreatedLocalReference (JniObjectReference reference, ref int localReferenceCount) + { + if (!reference.IsValid) + return; + base.CreatedLocalReference (reference, ref localReferenceCount); + CreatedReference (lrefLog, "+l+ lrefc", localReferenceCount, reference, Runtime); + } + + public override IntPtr ReleaseLocalReference (ref JniObjectReference reference, ref int localReferenceCount) + { + if (!reference.IsValid) + return IntPtr.Zero; + var r = reference; + var p = base.ReleaseLocalReference (ref reference, ref localReferenceCount); + DeletedReference (lrefLog, "-l- lrefc", localReferenceCount, r, Runtime); + return p; + } + + public override void WriteGlobalReferenceLine (string format, params object?[]? args) + { + if (grefLog == null) + return; + grefLog.WriteLine (format, args!); + grefLog.Flush (); + } + + public override JniObjectReference CreateGlobalReference (JniObjectReference reference) + { + if (!reference.IsValid) + return reference; + var n = base.CreateGlobalReference (reference); + int c = Interlocked.Increment (ref grefCount); + CreatedReference (grefLog, "+g+ grefc", c, reference, n, Runtime); + return n; + } + + public override void DeleteGlobalReference (ref JniObjectReference reference) + { + if (!reference.IsValid) + return; + int c = Interlocked.Decrement (ref grefCount); + DeletedReference (grefLog, "-g- grefc", c, reference, Runtime); + base.DeleteGlobalReference (ref reference); + } + + public override JniObjectReference CreateWeakGlobalReference (JniObjectReference reference) + { + if (!reference.IsValid) + return reference; + var n = base.CreateWeakGlobalReference (reference); + + int wc = Interlocked.Increment (ref wgrefCount); + int gc = grefCount; + if (grefLog != null) { + string message = $"+w+ grefc {gc} gwrefc {wc} obj-handle {reference.ToString ()} -> new-handle {n.ToString ()} " + + $"from thread '{Runtime.GetCurrentManagedThreadName ()}'({Environment.CurrentManagedThreadId})" + + Environment.NewLine + + Runtime.GetCurrentManagedThreadStackTrace (skipFrames: 2, fNeedFileInfo: true); + grefLog.WriteLine (message); + grefLog.Flush (); + } + + return n; + } + + public override void DeleteWeakGlobalReference (ref JniObjectReference reference) + { + if (!reference.IsValid) + return; + + int wc = Interlocked.Decrement (ref wgrefCount); + int gc = grefCount; + + if (grefLog != null) { + string message = $"-w- grefc {gc} gwrefc {wc} handle {reference.ToString ()} " + + $"from thread '{Runtime.GetCurrentManagedThreadName ()}'({Environment.CurrentManagedThreadId})" + + Environment.NewLine + + Runtime.GetCurrentManagedThreadStackTrace (skipFrames: 2, fNeedFileInfo: true); + grefLog.WriteLine (message); + grefLog.Flush (); + } + + base.DeleteWeakGlobalReference (ref reference); + } + + protected override void Dispose (bool disposing) + { + } + + static void CreatedReference (TextWriter? writer, string kind, int count, JniObjectReference reference, JniRuntime runtime) + { + if (writer == null) + return; + string message = $"{kind} {count} handle {reference.ToString ()} " + + $"from thread '{runtime.GetCurrentManagedThreadName ()}'({Environment.CurrentManagedThreadId})" + + Environment.NewLine + + runtime.GetCurrentManagedThreadStackTrace (skipFrames: 2, fNeedFileInfo: true); + writer.WriteLine (message); + writer.Flush (); + } + + static void CreatedReference (TextWriter? writer, string kind, int count, JniObjectReference reference, JniObjectReference newReference, JniRuntime runtime) + { + if (writer == null) + return; + string message = $"{kind} {count} obj-handle {reference.ToString ()} -> new-handle {newReference.ToString ()} " + + $"from thread '{runtime.GetCurrentManagedThreadName ()}'({Environment.CurrentManagedThreadId})" + + Environment.NewLine + + runtime.GetCurrentManagedThreadStackTrace (skipFrames: 2, fNeedFileInfo: true); + writer.WriteLine (message); + writer.Flush (); + } + + static void DeletedReference (TextWriter? writer, string kind, int count, JniObjectReference reference, JniRuntime runtime) + { + if (writer == null) + return; + string message = $"{kind} {count} handle {reference.ToString ()} " + + $"from thread '{runtime.GetCurrentManagedThreadName ()}'({Environment.CurrentManagedThreadId})" + + Environment.NewLine + + runtime.GetCurrentManagedThreadStackTrace (skipFrames: 2, fNeedFileInfo: true); + writer.WriteLine (message); + writer.Flush (); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.Android.Runtime.NativeAOT/Microsoft.Android.Runtime.NativeAOT.csproj b/src/Microsoft.Android.Runtime.NativeAOT/Microsoft.Android.Runtime.NativeAOT.csproj new file mode 100644 index 00000000000..5ae08596c98 --- /dev/null +++ b/src/Microsoft.Android.Runtime.NativeAOT/Microsoft.Android.Runtime.NativeAOT.csproj @@ -0,0 +1,41 @@ + + + + + + $(DotNetTargetFramework) + enable + enable + false + ..\..\product.snk + true + $(_MonoAndroidNETDefaultOutDir) + Microsoft.Android.Runtime + + + + + + + + + + + $(BuildDependsOn); + _CopyToPackDirs; + + + + + + <_RuntimePackFiles Include="$(OutputPath)Microsoft.Android.Runtime.NativeAOT.dll" AndroidRID="%(AndroidAbiAndRuntimeFlavor.AndroidRID)" AndroidRuntime="%(AndroidAbiAndRuntimeFlavor.AndroidRuntime)" /> + + + + + + 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 0f7136c2746..393ef9077c1 100644 --- a/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj +++ b/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj @@ -2,10 +2,11 @@ $(DotNetTargetFramework) - ILLINK + ILLINK;HAVE_CECIL false $(MicrosoftAndroidSdkOutDir) annotations + true @@ -26,8 +27,13 @@ + + + + + diff --git a/src/Microsoft.Android.Sdk.ILLink/TypeMappingStep.cs b/src/Microsoft.Android.Sdk.ILLink/TypeMappingStep.cs new file mode 100644 index 00000000000..9b82e500fd8 --- /dev/null +++ b/src/Microsoft.Android.Sdk.ILLink/TypeMappingStep.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Java.Interop.Tools.Cecil; +using Java.Interop.Tools.TypeNameMappings; +using Mono.Cecil; +using Mono.Linker; +using Mono.Linker.Steps; + +namespace Microsoft.Android.Sdk.ILLink; + +/// +/// MVP "typemap" implementation for NativeAOT +/// +public class TypeMappingStep : BaseStep +{ + const string AssemblyName = "Microsoft.Android.Runtime.NativeAOT"; + const string TypeName = "Microsoft.Android.Runtime.NativeAotTypeManager"; + readonly IDictionary TypeMappings = new Dictionary (StringComparer.Ordinal); + AssemblyDefinition? MicrosoftAndroidRuntimeNativeAot; + + protected override void ProcessAssembly (AssemblyDefinition assembly) + { + if (assembly.Name.Name == AssemblyName) { + MicrosoftAndroidRuntimeNativeAot = assembly; + return; + } + if (Annotations?.GetAction (assembly) == AssemblyAction.Delete) + return; + + foreach (var type in assembly.MainModule.Types) { + ProcessType (assembly, type); + } + } + + protected override void EndProcess () + { + if (MicrosoftAndroidRuntimeNativeAot is null) { + Context.LogMessage ($"Unable to find {AssemblyName} assembly"); + return; + } + + var module = MicrosoftAndroidRuntimeNativeAot.MainModule; + var type = module.GetType (TypeName); + if (type is null) { + Context.LogMessage ($"Unable to find {TypeName} type"); + return; + } + + var method = type.Methods.FirstOrDefault (m => m.Name == "InitializeTypeMappings"); + if (method is null) { + Context.LogMessage ($"Unable to find {TypeName}.InitializeTypeMappings() method"); + return; + } + + var field = type.Fields.FirstOrDefault (f => f.Name == "TypeMappings"); + if (field is null) { + Context.LogMessage ($"Unable to find {TypeName}.TypeMappings field"); + return; + } + + // Clear IL in method body + method.Body.Instructions.Clear (); + + Context.LogMessage ($"Writing {TypeMappings.Count} typemap entries"); + var il = method.Body.GetILProcessor (); + var addMethod = module.ImportReference (typeof (IDictionary).GetMethod ("Add")); + var getTypeFromHandle = module.ImportReference (typeof (Type).GetMethod ("GetTypeFromHandle")); + foreach (var (javaKey, typeDefinition) in TypeMappings) { + /* + * IL_0000: ldarg.0 + * IL_0001: ldfld class [System.Runtime]System.Collections.Generic.IDictionary`2 Microsoft.Android.Runtime.NativeAotTypeManager::TypeMappings + * IL_0006: ldstr "java/lang/Object" + * IL_000b: ldtoken [Mono.Android]Java.Lang.Object + * IL_0010: call class [System.Runtime]System.Type [System.Runtime]System.Type::GetTypeFromHandle(valuetype [System.Runtime]System.RuntimeTypeHandle) + * IL_0015: callvirt instance void class [System.Runtime]System.Collections.Generic.IDictionary`2::Add(!0, !1) + */ + il.Emit (Mono.Cecil.Cil.OpCodes.Ldarg_0); + il.Emit (Mono.Cecil.Cil.OpCodes.Ldfld, field); + il.Emit (Mono.Cecil.Cil.OpCodes.Ldstr, javaKey); + il.Emit (Mono.Cecil.Cil.OpCodes.Ldtoken, module.ImportReference (typeDefinition)); + il.Emit (Mono.Cecil.Cil.OpCodes.Call, getTypeFromHandle); + il.Emit (Mono.Cecil.Cil.OpCodes.Callvirt, addMethod); + } + + il.Emit (Mono.Cecil.Cil.OpCodes.Ret); + } + + void ProcessType (AssemblyDefinition assembly, TypeDefinition type) + { + if (type.HasJavaPeer (Context)) { + var javaName = JavaNativeTypeManager.ToJniName (type, Context); + if (!TypeMappings.TryAdd (javaName, type)) { + Context.LogMessage ($"Duplicate typemap entry for {javaName}"); + } + } + + if (!type.HasNestedTypes) + return; + + foreach (TypeDefinition nested in type.NestedTypes) + ProcessType (assembly, nested); + } +} diff --git a/src/Mono.Android/Properties/AssemblyInfo.cs.in b/src/Mono.Android/Properties/AssemblyInfo.cs.in index 9d8b6f5694b..f083dafcd92 100644 --- a/src/Mono.Android/Properties/AssemblyInfo.cs.in +++ b/src/Mono.Android/Properties/AssemblyInfo.cs.in @@ -45,7 +45,6 @@ using System.Runtime.Versioning; [assembly: InternalsVisibleTo("Mono.Android-TestsMultiDex, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")] [assembly: InternalsVisibleTo("Mono.Android-TestsAppBundle, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")] [assembly: InternalsVisibleTo("Mono.Android.NET-Tests, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")] -// Temporary for samples/NativeAOT -[assembly: InternalsVisibleTo("NativeAOT, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")] +[assembly: InternalsVisibleTo("Microsoft.Android.Runtime.NativeAOT, PublicKey=0024000004800000940000000602000000240000525341310004000011000000438ac2a5acfbf16cbd2b2b47a62762f273df9cb2795ceccdf77d10bf508e69e7a362ea7a45455bbf3ac955e1f2e2814f144e5d817efc4c6502cc012df310783348304e3ae38573c6d658c234025821fda87a0be8a0d504df564e2c93b2b878925f42503e9d54dfef9f9586d9e6f38a305769587b1de01f6c0410328b2c9733db")] [assembly: SuppressMessage ("ApiDesign", "RS0016:Add public types and members to the declared API", Justification = "Analyzer fails due to extended characters.", Scope = "member", Target = "~F:Android.Util.Patterns.GoodIriChar")] diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.ILLink.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.ILLink.targets index 6e783fdf500..ecddf43795d 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.ILLink.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.ILLink.targets @@ -84,11 +84,18 @@ This file contains the .NET 5-specific targets to customize ILLink BeforeStep="MarkStep" Type="MonoDroid.Tuner.FixLegacyResourceDesignerStep" /> + <_TrimmerCustomSteps + Condition=" '$(_AndroidRuntime)' == 'NativeAOT' " + Include="$(_AndroidLinkerCustomStepAssembly)" + AfterStep="CleanStep" + Type="Microsoft.Android.Sdk.ILLink.TypeMappingStep" + /> <_PreserveLists Include="$(MSBuildThisFileDirectory)..\PreserveLists\*.xml" /> + 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 64dd729f9ed..292a86e28ad 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 @@ -81,6 +81,8 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android. + + diff --git a/samples/NativeAOT/JavaInteropRuntime.java b/src/Xamarin.Android.Build.Tasks/Resources/JavaInteropRuntime.java similarity index 60% rename from samples/NativeAOT/JavaInteropRuntime.java rename to src/Xamarin.Android.Build.Tasks/Resources/JavaInteropRuntime.java index 1eb07e9f2e5..cb0474682f9 100644 --- a/samples/NativeAOT/JavaInteropRuntime.java +++ b/src/Xamarin.Android.Build.Tasks/Resources/JavaInteropRuntime.java @@ -4,8 +4,8 @@ public class JavaInteropRuntime { static { - Log.d("JavaInteropRuntime", "Loading NativeAOT.so..."); - System.loadLibrary("NativeAOT"); + Log.d("JavaInteropRuntime", "Loading @MAIN_ASSEMBLY_NAME@.so..."); + System.loadLibrary("@MAIN_ASSEMBLY_NAME@"); } private JavaInteropRuntime() { diff --git a/samples/NativeAOT/NativeAotRuntimeProvider.java b/src/Xamarin.Android.Build.Tasks/Resources/NativeAotRuntimeProvider.java similarity index 100% rename from samples/NativeAOT/NativeAotRuntimeProvider.java rename to src/Xamarin.Android.Build.Tasks/Resources/NativeAotRuntimeProvider.java diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs index 2fa90dca06e..a908645c829 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs @@ -98,6 +98,9 @@ public class GenerateJavaStubs : AndroidTask public string CodeGenerationTarget { get; set; } = ""; + [Required] + public string TargetName { get; set; } = ""; + AndroidRuntime androidRuntime; JavaPeerStyle codeGenerationTarget; @@ -304,18 +307,33 @@ Dictionary MaybeGetArchAssemblies (Dictionary additionalProviders) { - if (androidRuntime != Xamarin.Android.Tasks.AndroidRuntime.MonoVM) { - Log.LogDebugMessage ($"Skipping MonoRuntimeProvider generation for: {androidRuntime}"); - } else { + if (androidRuntime != Xamarin.Android.Tasks.AndroidRuntime.CoreCLR) { // Create additional runtime provider java sources. - string providerTemplateFile = "MonoRuntimeProvider.Bundled.java"; + bool isMonoVM = androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.MonoVM; + string providerTemplateFile = isMonoVM ? + "MonoRuntimeProvider.Bundled.java" : + "NativeAotRuntimeProvider.java"; string providerTemplate = GetResource (providerTemplateFile); foreach (var provider in additionalProviders) { - var contents = providerTemplate.Replace ("MonoRuntimeProvider", provider); - var real_provider = Path.Combine (OutputDirectory, "src", "mono", provider + ".java"); + var contents = providerTemplate.Replace (isMonoVM ? "MonoRuntimeProvider" : "NativeAotRuntimeProvider", provider); + var real_provider = isMonoVM ? + Path.Combine (OutputDirectory, "src", "mono", provider + ".java") : + Path.Combine (OutputDirectory, "src", "net", "dot", "jni", "nativeaot", provider + ".java"); Files.CopyIfStringChanged (contents, real_provider); } + } else { + Log.LogDebugMessage ($"Skipping android.content.ContentProvider generation for: {androidRuntime}"); + } + + // For NativeAOT, generate JavaInteropRuntime.java + if (androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.NativeAOT) { + const string fileName = "JavaInteropRuntime.java"; + string template = GetResource (fileName); + var contents = template.Replace ("@MAIN_ASSEMBLY_NAME@", TargetName); + var path = Path.Combine (OutputDirectory, "src", "net", "dot", "jni", "nativeaot", fileName); + Log.LogDebugMessage ($"Writing: {path}"); + Files.CopyIfStringChanged (contents, path); } // Create additional application java sources. diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs index 7cb28b4942e..0930f930428 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ManifestDocument.cs @@ -673,12 +673,15 @@ XElement CreateApplicationElement (XElement manifest, string applicationClass, L IList AddMonoRuntimeProviders (XElement app) { - if (AndroidRuntime != AndroidRuntime.MonoVM) { - //TODO: implement provider logic for non-Mono runtimes + if (AndroidRuntime == AndroidRuntime.CoreCLR) { + //TODO: implement provider logic for CoreCLR return []; } - app.Add (CreateMonoRuntimeProvider ("mono.MonoRuntimeProvider", null, --AppInitOrder)); + bool isMonoVM = AndroidRuntime == AndroidRuntime.MonoVM; + string packageName = isMonoVM ? "mono" : "net.dot.jni.nativeaot"; + string className = isMonoVM ? "MonoRuntimeProvider" : "NativeAotRuntimeProvider"; + app.Add (CreateMonoRuntimeProvider ($"{packageName}.{className}", null, --AppInitOrder)); var providerNames = new List (); @@ -702,9 +705,9 @@ IList AddMonoRuntimeProviders (XElement app) case "activity": case "receiver": case "service": - string providerName = "MonoRuntimeProvider_" + procs.Count; + string providerName = $"{className}_{procs.Count}"; providerNames.Add (providerName); - app.Add (CreateMonoRuntimeProvider ("mono." + providerName, proc.Value, --AppInitOrder)); + app.Add (CreateMonoRuntimeProvider ($"{packageName}.{providerName}", proc.Value, --AppInitOrder)); break; } } diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj index db23eeb6fe4..dd9b72972a8 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.csproj @@ -204,26 +204,11 @@ - - machine.config - - - MonoRuntimeProvider.Bundled.java - - - proguard_xamarin.cfg - - - ApplicationRegistration.java - - - net.android.init.gradle.kts - JavaInteropTypeManager.java - - Resource.Designer.snk + + %(Filename)%(Extension) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index d93711c4262..3123c94ff3b 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1387,6 +1387,11 @@ because xbuild doesn't support framework reference assemblies. ResourceName="MonoRuntimeProvider.Bundled.java" OutputPath="$(_AndroidIntermediateJavaSourceDirectory)mono\MonoRuntimeProvider.java" /> +