From 7a772f03fc7e5d9330d89a976c5e8e0b655e1588 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Wed, 22 Jan 2025 12:23:30 -0600 Subject: [PATCH] [NativeAOT] add sample that runs successfully (#9636) Context: https://github.com/dotnet/java-interop/tree/9b1d8781e8e322849d05efac32119c913b21c192/samples/Hello-NativeAOTFromAndroid "Import" the [Hello-NativeAOTFromAndroid][0] from dotnet/java-interop, and update it to use `Mono.Android.dll` and parts of the .NET for Android build system. It currently relies on `[InternalsVisibleTo("NativeAOT")]` within `Mono.Android.dll` for access to things like: * `Android.Runtime.JNIEnvInit.InitializeJniRuntime()` There are a couple MSBuild changes still left: TODO: * `$(_ExtraTrimmerArgs)` needs to be specified for trimmer warnings to not be displayed twice. This is the same thing done in xamarin/xamarin-macios. * `@(TrimmerRootAssembly)` needs to be set for illink's "already trimmed" output for ILC. We exclude `System.Private.CoreLib.dll` from this list. * Remove use of `Java.Runtime.Environment.dll`, and otherwise allow the sample to be built from the .NET for Android workload packs. * "MOAR Integration": sample depends upon a manually specified "type map" dictionary. This needs to be automagic to be useful. * Figure out what to do about C++: do we dynamically link against and bundle `libc++_shared.so`? Statically link against `libc++_static.a`? [0]: https://github.com/dotnet/java-interop/commit/78d59371a9e27aa601bc32a07a529d09e2f7c796 --- .../stage-msbuild-emulator-tests.yaml | 8 + samples/NativeAOT/AndroidManifest.xml | 13 ++ samples/NativeAOT/JavaInteropRuntime.cs | 54 ++++++ samples/NativeAOT/JavaInteropRuntime.java | 15 ++ samples/NativeAOT/Logging.cs | 77 ++++++++ samples/NativeAOT/MainActivity.cs | 18 ++ samples/NativeAOT/NativeAOT.csproj | 36 ++++ .../NativeAOT/NativeAotRuntimeProvider.java | 51 ++++++ samples/NativeAOT/NativeAotTypeManager.cs | 164 ++++++++++++++++++ samples/NativeAOT/NativeAotValueManager.cs | 10 ++ .../Resources/layout/activity_main.xml | 13 ++ .../Resources/mipmap-anydpi-v26/appicon.xml | 4 + .../mipmap-anydpi-v26/appicon_round.xml | 4 + .../Resources/mipmap-hdpi/appicon.png | Bin 0 -> 2178 bytes .../mipmap-hdpi/appicon_background.png | Bin 0 -> 97 bytes .../mipmap-hdpi/appicon_foreground.png | Bin 0 -> 1276 bytes .../Resources/mipmap-mdpi/appicon.png | Bin 0 -> 1524 bytes .../mipmap-mdpi/appicon_background.png | Bin 0 -> 92 bytes .../mipmap-mdpi/appicon_foreground.png | Bin 0 -> 1273 bytes .../Resources/mipmap-xhdpi/appicon.png | Bin 0 -> 3098 bytes .../mipmap-xhdpi/appicon_background.png | Bin 0 -> 100 bytes .../mipmap-xhdpi/appicon_foreground.png | Bin 0 -> 1805 bytes .../Resources/mipmap-xxhdpi/appicon.png | Bin 0 -> 4674 bytes .../mipmap-xxhdpi/appicon_background.png | Bin 0 -> 108 bytes .../mipmap-xxhdpi/appicon_foreground.png | Bin 0 -> 1926 bytes .../Resources/mipmap-xxxhdpi/appicon.png | Bin 0 -> 6832 bytes .../mipmap-xxxhdpi/appicon_background.png | Bin 0 -> 117 bytes .../mipmap-xxxhdpi/appicon_foreground.png | Bin 0 -> 2801 bytes .../values/ic_launcher_background.xml | 4 + .../NativeAOT/Resources/values/strings.xml | 4 + .../Android.Runtime/JNIEnvInit.cs | 10 +- .../Properties/AssemblyInfo.cs.in | 2 + .../Microsoft.Android.Sdk.NativeAOT.targets | 11 +- .../Tests/InstallAndRunTests.cs | 26 +++ 34 files changed, 521 insertions(+), 3 deletions(-) create mode 100644 samples/NativeAOT/AndroidManifest.xml create mode 100644 samples/NativeAOT/JavaInteropRuntime.cs create mode 100644 samples/NativeAOT/JavaInteropRuntime.java create mode 100644 samples/NativeAOT/Logging.cs create mode 100644 samples/NativeAOT/MainActivity.cs create mode 100644 samples/NativeAOT/NativeAOT.csproj create mode 100644 samples/NativeAOT/NativeAotRuntimeProvider.java create mode 100644 samples/NativeAOT/NativeAotTypeManager.cs create mode 100644 samples/NativeAOT/NativeAotValueManager.cs create mode 100644 samples/NativeAOT/Resources/layout/activity_main.xml create mode 100644 samples/NativeAOT/Resources/mipmap-anydpi-v26/appicon.xml create mode 100644 samples/NativeAOT/Resources/mipmap-anydpi-v26/appicon_round.xml create mode 100644 samples/NativeAOT/Resources/mipmap-hdpi/appicon.png create mode 100644 samples/NativeAOT/Resources/mipmap-hdpi/appicon_background.png create mode 100644 samples/NativeAOT/Resources/mipmap-hdpi/appicon_foreground.png create mode 100644 samples/NativeAOT/Resources/mipmap-mdpi/appicon.png create mode 100644 samples/NativeAOT/Resources/mipmap-mdpi/appicon_background.png create mode 100644 samples/NativeAOT/Resources/mipmap-mdpi/appicon_foreground.png create mode 100644 samples/NativeAOT/Resources/mipmap-xhdpi/appicon.png create mode 100644 samples/NativeAOT/Resources/mipmap-xhdpi/appicon_background.png create mode 100644 samples/NativeAOT/Resources/mipmap-xhdpi/appicon_foreground.png create mode 100644 samples/NativeAOT/Resources/mipmap-xxhdpi/appicon.png create mode 100644 samples/NativeAOT/Resources/mipmap-xxhdpi/appicon_background.png create mode 100644 samples/NativeAOT/Resources/mipmap-xxhdpi/appicon_foreground.png create mode 100644 samples/NativeAOT/Resources/mipmap-xxxhdpi/appicon.png create mode 100644 samples/NativeAOT/Resources/mipmap-xxxhdpi/appicon_background.png create mode 100644 samples/NativeAOT/Resources/mipmap-xxxhdpi/appicon_foreground.png create mode 100644 samples/NativeAOT/Resources/values/ic_launcher_background.xml create mode 100644 samples/NativeAOT/Resources/values/strings.xml diff --git a/build-tools/automation/yaml-templates/stage-msbuild-emulator-tests.yaml b/build-tools/automation/yaml-templates/stage-msbuild-emulator-tests.yaml index aa27d4dc9a4..e4f6c6a5564 100644 --- a/build-tools/automation/yaml-templates/stage-msbuild-emulator-tests.yaml +++ b/build-tools/automation/yaml-templates/stage-msbuild-emulator-tests.yaml @@ -49,6 +49,14 @@ stages: artifactName: $(TestAssembliesArtifactName) downloadPath: ${{ parameters.xaSourcePath }}/bin/Test$(XA.Build.Configuration) + # Currently needed for samples/NativeAOT + - template: /build-tools/automation/yaml-templates/run-dotnet-preview.yaml@self + parameters: + project: Xamarin.Android.sln + arguments: -t:PrepareJavaInterop -c $(XA.Build.Configuration) --no-restore + displayName: prepare java.interop $(XA.Build.Configuration) + continueOnError: false + - template: /build-tools/automation/yaml-templates/start-stop-emulator.yaml parameters: xaSourcePath: ${{ parameters.xaSourcePath }} diff --git a/samples/NativeAOT/AndroidManifest.xml b/samples/NativeAOT/AndroidManifest.xml new file mode 100644 index 00000000000..70e89c99003 --- /dev/null +++ b/samples/NativeAOT/AndroidManifest.xml @@ -0,0 +1,13 @@ + + + + + + + + \ No newline at end of file diff --git a/samples/NativeAOT/JavaInteropRuntime.cs b/samples/NativeAOT/JavaInteropRuntime.cs new file mode 100644 index 00000000000..4e54afeb3ba --- /dev/null +++ b/samples/NativeAOT/JavaInteropRuntime.cs @@ -0,0 +1,54 @@ +using Android.Runtime; +using Java.Interop; +using System.Runtime.InteropServices; + +namespace NativeAOT; + +static class JavaInteropRuntime +{ + static JniRuntime? runtime; + + [UnmanagedCallersOnly (EntryPoint="JNI_OnLoad")] + static int JNI_OnLoad (IntPtr vm, IntPtr reserved) + { + try { + AndroidLog.Print (AndroidLogLevel.Info, "JavaInteropRuntime", "JNI_OnLoad()"); + LogcatTextWriter.Init (); + return (int) JniVersion.v1_6; + } + catch (Exception e) { + AndroidLog.Print (AndroidLogLevel.Error, "JavaInteropRuntime", $"JNI_OnLoad() failed: {e}"); + return 0; + } + } + + [UnmanagedCallersOnly (EntryPoint="JNI_OnUnload")] + static void JNI_OnUnload (IntPtr vm, IntPtr reserved) + { + AndroidLog.Print(AndroidLogLevel.Info, "JavaInteropRuntime", "JNI_OnUnload"); + runtime?.Dispose (); + } + + // symbol name from `$(IntermediateOutputPath)obj/Release/osx-arm64/h-classes/net_dot_jni_hello_JavaInteropRuntime.h` + [UnmanagedCallersOnly (EntryPoint="Java_net_dot_jni_nativeaot_JavaInteropRuntime_init")] + static void init (IntPtr jnienv, IntPtr klass) + { + try { + var options = new JreRuntimeOptions { + EnvironmentPointer = jnienv, + TypeManager = new NativeAotTypeManager (), + ValueManager = new NativeAotValueManager (), + UseMarshalMemberBuilder = false, + JniGlobalReferenceLogWriter = new LogcatTextWriter (AndroidLogLevel.Debug, "NativeAot:GREF"), + JniLocalReferenceLogWriter = new LogcatTextWriter (AndroidLogLevel.Debug, "NativeAot:LREF"), + }; + runtime = options.CreateJreVM (); + + // Entry point into Mono.Android.dll + JNIEnvInit.InitializeJniRuntime (runtime); + } + catch (Exception e) { + AndroidLog.Print (AndroidLogLevel.Error, "JavaInteropRuntime", $"JavaInteropRuntime.init: error: {e}"); + } + } +} \ No newline at end of file diff --git a/samples/NativeAOT/JavaInteropRuntime.java b/samples/NativeAOT/JavaInteropRuntime.java new file mode 100644 index 00000000000..1eb07e9f2e5 --- /dev/null +++ b/samples/NativeAOT/JavaInteropRuntime.java @@ -0,0 +1,15 @@ +package net.dot.jni.nativeaot; + +import android.util.Log; + +public class JavaInteropRuntime { + static { + Log.d("JavaInteropRuntime", "Loading NativeAOT.so..."); + System.loadLibrary("NativeAOT"); + } + + private JavaInteropRuntime() { + } + + public static native void init(); +} diff --git a/samples/NativeAOT/Logging.cs b/samples/NativeAOT/Logging.cs new file mode 100644 index 00000000000..5073ba9e5a3 --- /dev/null +++ b/samples/NativeAOT/Logging.cs @@ -0,0 +1,77 @@ +// NOTE: logging methods below are need temporarily due to: +// 1) linux-bionic BCL doesn't redirect stdout/stderr to logcat +// 2) Android.Util.Log won't work until we initialize the Java.Interop.JreRuntime + +using System.IO; +using System.Runtime.InteropServices; +using System.Text; + +namespace NativeAOT; + +internal sealed class LogcatTextWriter : TextWriter { + + public static void Init () + { + // This method is a no-op, but it's necessary to ensure the static + // constructor is executed. + } + + static LogcatTextWriter () + { + Console.SetOut (new LogcatTextWriter (AndroidLogLevel.Info)); + Console.SetError (new LogcatTextWriter (AndroidLogLevel.Error)); + } + + AndroidLogLevel Level; + string Tag; + + internal LogcatTextWriter (AndroidLogLevel level, string tag = "NativeAotFromAndroid") + { + Level = level; + Tag = tag; + } + + public override Encoding Encoding => Encoding.UTF8; + public override string NewLine => "\n"; + + public override void WriteLine (string? value) + { + if (value == null) { + AndroidLog.Print (Level, Tag, ""); + return; + } + ReadOnlySpan span = value; + while (!span.IsEmpty) { + if (span.IndexOf ('\n') is int n && n < 0) { + break; + } + var line = span.Slice (0, n); + AndroidLog.Print (Level, Tag, line.ToString ()); + span = span.Slice (n + 1); + } + AndroidLog.Print (Level, Tag, span.ToString ()); + } +} + +static class AndroidLog { + + [DllImport ("log", EntryPoint = "__android_log_print", CallingConvention = CallingConvention.Cdecl)] + private static extern void __android_log_print(AndroidLogLevel level, string? tag, string format, string args, IntPtr ptr); + + internal static void Print(AndroidLogLevel level, string? tag, string message) => + __android_log_print(level, tag, "%s", message, IntPtr.Zero); + +} + +internal enum AndroidLogLevel +{ + Unknown = 0x00, + Default = 0x01, + Verbose = 0x02, + Debug = 0x03, + Info = 0x04, + Warn = 0x05, + Error = 0x06, + Fatal = 0x07, + Silent = 0x08 +} \ No newline at end of file diff --git a/samples/NativeAOT/MainActivity.cs b/samples/NativeAOT/MainActivity.cs new file mode 100644 index 00000000000..545983d62fe --- /dev/null +++ b/samples/NativeAOT/MainActivity.cs @@ -0,0 +1,18 @@ +using Android.Runtime; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace NativeAOT; + +[Register("my/MainActivity")] // Required for typemap in NativeAotTypeManager +[Activity(Label = "@string/app_name", MainLauncher = true)] +public class MainActivity : Activity +{ + protected override void OnCreate(Bundle? savedInstanceState) + { + base.OnCreate(savedInstanceState); + + // Set our view from the "main" layout resource + SetContentView(Resource.Layout.activity_main); + } +} \ No newline at end of file diff --git a/samples/NativeAOT/NativeAOT.csproj b/samples/NativeAOT/NativeAOT.csproj new file mode 100644 index 00000000000..e392eaa7646 --- /dev/null +++ b/samples/NativeAOT/NativeAOT.csproj @@ -0,0 +1,36 @@ + + + $(DotNetAndroidTargetFramework) + 21 + Exe + enable + enable + net.dot.hellonativeaot + 1 + 1.0 + apk + true + + true + ..\..\product.snk + + android-arm64 + + true + true + + + + + + android-x64 + <_NuGetFolderOnCI>..\..\bin\Build$(Configuration)\nuget-unsigned + $(_NuGetFolderOnCI) + <_FastDeploymentDiagnosticLogging>true + + + + + + + \ No newline at end of file diff --git a/samples/NativeAOT/NativeAotRuntimeProvider.java b/samples/NativeAOT/NativeAotRuntimeProvider.java new file mode 100644 index 00000000000..b87f23f25c7 --- /dev/null +++ b/samples/NativeAOT/NativeAotRuntimeProvider.java @@ -0,0 +1,51 @@ +package net.dot.jni.nativeaot; + +import android.util.Log; + +public class NativeAotRuntimeProvider + extends android.content.ContentProvider +{ + private static final String TAG = "NativeAotRuntimeProvider"; + + public NativeAotRuntimeProvider() { + Log.d(TAG, "NativeAotRuntimeProvider()"); + } + + @Override + public boolean onCreate() { + Log.d(TAG, "NativeAotRuntimeProvider.onCreate()"); + return true; + } + + @Override + public void attachInfo(android.content.Context context, android.content.pm.ProviderInfo info) { + Log.d(TAG, "NativeAotRuntimeProvider.attachInfo(): calling JavaInteropRuntime.init()…"); + JavaInteropRuntime.init(); + super.attachInfo (context, info); + } + + @Override + public android.database.Cursor query(android.net.Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { + throw new RuntimeException ("This operation is not supported."); + } + + @Override + public String getType(android.net.Uri uri) { + throw new RuntimeException ("This operation is not supported."); + } + + @Override + public android.net.Uri insert(android.net.Uri uri, android.content.ContentValues initialValues) { + throw new RuntimeException ("This operation is not supported."); + } + + @Override + public int delete(android.net.Uri uri, String where, String[] whereArgs) { + throw new RuntimeException ("This operation is not supported."); + } + + @Override + public int update(android.net.Uri uri, android.content.ContentValues values, String where, String[] whereArgs) { + throw new RuntimeException ("This operation is not supported."); + } +} \ No newline at end of file diff --git a/samples/NativeAOT/NativeAotTypeManager.cs b/samples/NativeAOT/NativeAotTypeManager.cs new file mode 100644 index 00000000000..29499d17847 --- /dev/null +++ b/samples/NativeAOT/NativeAotTypeManager.cs @@ -0,0 +1,164 @@ +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using Java.Interop; +using Java.Interop.Tools.TypeNameMappings; + +namespace NativeAOT; + +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/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), + }; + + public NativeAotTypeManager () + { + AndroidLog.Print (AndroidLogLevel.Info, "NativeAotTypeManager", $"# jonp: NativeAotTypeManager()"); + } + + public override void RegisterNativeMembers ( + JniType nativeClass, + [DynamicallyAccessedMembers (MethodsAndPrivateNested)] + Type type, + ReadOnlySpan methods) + { + AndroidLog.Print (AndroidLogLevel.Info, "NativeAotTypeManager", $"# jonp: RegisterNativeMembers: nativeClass={nativeClass} type=`{type}`"); + + if (methods.IsEmpty) { + AndroidLog.Print (AndroidLogLevel.Info, "NativeAotTypeManager", "methods.IsEmpty"); + return; + } + + int methodCount = CountMethods (methods); + if (methodCount < 1) { + AndroidLog.Print (AndroidLogLevel.Info, "NativeAotTypeManager", $"methodCount < 1: {methodCount}"); + 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!; + } + + AndroidLog.Print (AndroidLogLevel.Info, "NativeAotTypeManager", $"# jonp: Delegate.CreateDelegate callbackDeclaringType={callbackDeclaringType}, callbackString={callbackString}"); + 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; + } + + AndroidLog.Print (AndroidLogLevel.Info, "NativeAotTypeManager", $"# jonp: needToRegisterNatives={needToRegisterNatives}"); + + if (needToRegisterNatives) { + AndroidLog.Print (AndroidLogLevel.Info, "NativeAotTypeManager", $"# jonp: RegisterNatives: nativeClass={nativeClass} type=`{type}` natives={natives.Length} nativesIndex={nativesIndex}"); + JniEnvironment.Types.RegisterNatives (nativeClass.PeerReference, natives, nativesIndex); + } + } + + + protected override IEnumerable GetTypesForSimpleReference (string jniSimpleReference) + { + AndroidLog.Print (AndroidLogLevel.Info, "NativeAotTypeManager", $"# jonp: GetTypesForSimpleReference: jniSimpleReference=`{jniSimpleReference}`"); + if (typeMappings.TryGetValue (jniSimpleReference, out var target)) { + Console.WriteLine ($"# jonp: GetTypesForSimpleReference: jniSimpleReference=`{jniSimpleReference}` -> `{target}`"); + yield return target; + } + foreach (var t in base.GetTypesForSimpleReference (jniSimpleReference)) { + AndroidLog.Print (AndroidLogLevel.Info, "NativeAotTypeManager", $"# jonp: GetTypesForSimpleReference: jniSimpleReference=`{jniSimpleReference}` -> `{t}`"); + yield return t; + } + } + + protected override IEnumerable GetSimpleReferences (Type type) + { + return base.GetSimpleReferences (type) + .Concat (CreateSimpleReferencesEnumerator (type)); + } + + IEnumerable CreateSimpleReferencesEnumerator (Type type) + { + if (typeMappings == null) + yield break; + foreach (var e in typeMappings) { + if (e.Value == type) + yield return e.Key; + } + } + + 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/samples/NativeAOT/NativeAotValueManager.cs b/samples/NativeAOT/NativeAotValueManager.cs new file mode 100644 index 00000000000..8fb2c55d4e2 --- /dev/null +++ b/samples/NativeAOT/NativeAotValueManager.cs @@ -0,0 +1,10 @@ +using Android.Runtime; + +namespace NativeAOT; + +// TODO: make a NativeAOT-specific implementation of AndroidValueManager +// This is enough for "Hello World" to launch +internal class NativeAotValueManager : AndroidValueManager +{ + +} diff --git a/samples/NativeAOT/Resources/layout/activity_main.xml b/samples/NativeAOT/Resources/layout/activity_main.xml new file mode 100644 index 00000000000..f94985291bf --- /dev/null +++ b/samples/NativeAOT/Resources/layout/activity_main.xml @@ -0,0 +1,13 @@ + + + + \ No newline at end of file diff --git a/samples/NativeAOT/Resources/mipmap-anydpi-v26/appicon.xml b/samples/NativeAOT/Resources/mipmap-anydpi-v26/appicon.xml new file mode 100644 index 00000000000..7751f69514d --- /dev/null +++ b/samples/NativeAOT/Resources/mipmap-anydpi-v26/appicon.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/samples/NativeAOT/Resources/mipmap-anydpi-v26/appicon_round.xml b/samples/NativeAOT/Resources/mipmap-anydpi-v26/appicon_round.xml new file mode 100644 index 00000000000..7751f69514d --- /dev/null +++ b/samples/NativeAOT/Resources/mipmap-anydpi-v26/appicon_round.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/samples/NativeAOT/Resources/mipmap-hdpi/appicon.png b/samples/NativeAOT/Resources/mipmap-hdpi/appicon.png new file mode 100644 index 0000000000000000000000000000000000000000..0abfc1b581c52b479e48d5a33b56e27e03eaa867 GIT binary patch literal 2178 zcma*pX*|^19|!OmMpZ1UX4wv}K|=z=Lls{e_C z$08JNAQVE~&ENakd?Xsw0|(Dv+Pwhib_xK~PO$=XP;5GU0k$13X3wm(%dvg(5uD)^s5Q_)kK48qG7eeFSQOAs~s-ZIsuTiNacqnu!qLVnZ~e8 z6fD!zjOt<1?Qci*$5Jus^_CjXFzU5dnsr!>Zk#$5r#^twpyD*U@#-|Z1{JSC!)sCr z8Z-jXnlu7@fB+vPYSM^s0Nox=vj_St&HgOi0iZ>9(55?T(H((4M|T3~02m}4Itge5 zorGYJbQ#VFhO;i+S(o7g&||oqXSn{tbk%3L>NCmu3^LFL46*^!4RC?!4lrbT0E_@E zkBdxC0208ujAVHMj9K0&mbVFj?QP1Yn6N0O0JaanjOAm-_BChwTClI6+5VOz{#GM_ zHh|GPA7-Vq}`fHyFHs3`SnrMY~H=O zyx6(?xVeJ(xzf~cWhvjv(-&%T78@QfHWn{7l>nBSN|#<$F1J>5-Zia!c)t4K#cKE4 zA3be9s2_d|efml3;nI4!^jRQ|23GN<& zfzi?N|IYp72kGe<85s}%o!s1_qN0}8*4G^!ot>D&hHpV2k&~9@CibNEWs+NsgTo=Y zkiHr}H$1J}H0fDD9LgNBAtoX%1>wnXCB7GNKNHXX!#x5ygySCbv=Z|*eWW%UV(uqT zZs=i0q#S=X=Mu3Tve9~4iaXu?&35rG?>h<>a0#9hai9#U6TA=`x9&Ky0G!@L^yzYHcU&K{Py)G zLq6-*fxXOv!?welF6qsPbDF(gEd^wBf!Q)^vjnHg8~Ix(t)yvMb6b7l6vl4p)cW*HIltJum<+)k*W zHo}Wa;Ud;GFS_NvDJQl`#2U0Up;gDNu?dp?;<26U5-7LH#_qqd)p- zccS_T=v4HYS5U6dq&S$j8z64f{A%x?&{$P;0be3gPK*4UOaK~>3XW)4%VgA!XybAAt)HYL)Mt+#=a6cFhdtQt${mqN+7U|-? z_<`)<(amvE8yV5+glVrQs5&WuHb%=TDYtS;UXAR5N%s8SJT!818z=O2wyVGjT(FF?Zz#n*UxoPaRsDGjGdR)4pr=q zbo*&o@a`c9p^aR2!Q=q+Rh8JGY`8RZ7;XkX8j+*-pMO>Ur*l(7W9nboXX3Buji8fyZ#)?YxEgF%SbJ1`@Ck~237#Gy zqjHz3vOcQMqZ=48<>a|n^#c=i`lC|wDB4*(J+{WIOSfttk<#l+jO;?n3=__bCj1d` zrz@E>t@IUl@+~{jRsykzb`J3O9O*Fx4W>$deB*HP(Y(7cH86jgRVSUs-(KE*8ho5p z9;IHuE*zR-u{~~wGda|(edsRgOR10HCC$=lecZ};te@ZP=pC8&#+*LinUJ>4&Du64 z!-ywSoaWpIoxlHHP$4IruD6G2AM>dkAb~bJ<2CN>KW#LW7qKgG>0QFT%)aE!U!Ma@ M3#@s)spp^n1!tBY8UO$Q literal 0 HcmV?d00001 diff --git a/samples/NativeAOT/Resources/mipmap-hdpi/appicon_background.png b/samples/NativeAOT/Resources/mipmap-hdpi/appicon_background.png new file mode 100644 index 0000000000000000000000000000000000000000..513e69d8412c314411a5940370e552c59fd6bbef GIT binary patch literal 97 zcmeAS@N?(olHy`uVBq!ia0vp^i$Iu>8A$%HX^8+*%mF?ju7TQDY)?)43FJz8x;TbZ s#JxSh$P45hQuw`m+i~{Oj0_A9c;7HE3Rk-M0EHPmUHx3vIVCg!0A>pr+5i9m literal 0 HcmV?d00001 diff --git a/samples/NativeAOT/Resources/mipmap-hdpi/appicon_foreground.png b/samples/NativeAOT/Resources/mipmap-hdpi/appicon_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..99d3a291bc382dd1afc9c28845623ef77fc14c15 GIT binary patch literal 1276 zcmeAS@N?(olHy`uVBq!ia0vp^i$Iuz8AyKBd8Wz0z&InoC&U%V{XYr@UkDtSd^H0Y zH|-@se!&ckOe}2d9GqO-ynOrufrHF3KJ>D89HqxGL}xr=zmy;bgN zx63@@DR=GI;fEeA@((>McJ%&v=#iPY_{nRVh-}?F*E4fh-A!6HUF8_7wWpq>$Q$eb zGvBM+7LJSjp`O&CvhJGlqrE!UE6z$51}^S!p8q4E?0VmdjK%%jWlvuC+wI9(FS;?@ zvAgVu-D5HNP2z91cjpQI&J3T`fBN>@j#;@S_L6}I(`qJFo4AMEQIg#JC*|*!Ev{b$ zS3cIZuYNv#>x_7hn^B@UB^Ote7Ve2PT{Jn~v-`@gYg((_A9s{IVCO&C_y5O|$Ke|; ze*1rF?rOP>6O7N!Il14}T4bw7tft&F=1_AhYpE@jujC3FbdGTzjLW-T^PtT2qgMN4d(KVlG}dif;>xv_d)b$mJKy&y969dXCzfl@ zbv4RFef<>4qVmP}Ildjx&YXDbnU>O~nssN4!=rNqrtzQMB$jFMxF_Oa>uNz;?Iu;} zRNYDWw+i*Vly+^ucGcy!(CrVA15qy0|sZ#H3{cP!MwQcHR-A5lY7I7SXbX5G@ zv}OA$dX9SA+e~G*%GkSQy4hv1_~z->Ea*vvfuZ5Po%ec+%^8`mKyse0elF{r5}E)4 Cmmqim literal 0 HcmV?d00001 diff --git a/samples/NativeAOT/Resources/mipmap-mdpi/appicon.png b/samples/NativeAOT/Resources/mipmap-mdpi/appicon.png new file mode 100644 index 0000000000000000000000000000000000000000..7b5a2e2bf8dc4d63e6490db8b5e269a63b05841e GIT binary patch literal 1524 zcmbuF_#Nit)318A1FIm-vIV1Z-!VgR-uhUEv+lI3T~_P1pDgS29kfun4) zHNXk5W(R<@VF%c70&UoVAdj&Fk8y$kTTU=w2XN2YbH0@V?Lec`VHdE%OU zab4j|U7@6|NJ1--y!=DbP%3FClQaV5(k7rn+FU7Zu9CJ?OFJ9px|-*EUM=+ewfMGe zVW4a2L(dmhFU0DD*g!wT8Gv|$(D2am7<*-WY;{7gD*C)OBU+b;)}_n{Pf%{HFkL4?W4!xeTYB9xR>RMmFv(bC@g z-S@^OC=}WpN2hmmba%gd_x0-r*!iEiqvFU1*LMStbt1XmX64W?AaR;$?U>`6PBnCe zF&rYilOdOs+J-eWOv3i{F38)%m3ZC8S*i%deF}rMd+PTNQ%0Xw+bWD=I2?;OXXn#Y z)@ZYsSxpQ&KEI_eUrhY9GJ>ynkTKT148NB-W0~Icyf>uDUZq&Efd*YO%F1Rgg^W;W-f!C|S3yjxGz9~$7(;As32%PB~J%k0Rd zY2u(Vm(doK*81`p4M*q9UF4=hj8=D+VM(&kwq-`Eyf%4|%Nct8q7q@Gt(~cmambzh zmaM5ZMea;3JD`z_oR-gI;H@mbO0J-_u9e|80b+qHnxT zBA@)pC^*`wzLs$3ko#{+5qW-hgQ={G<%I0q`O8NvNkv??BPHF+KVKFww{?N zV_dmhf#8N_$bsjoK3837EBIDTRo9N}F*B`0B|iAb zD|r4iIIv4mPBvTl!X@AD{DagK?Gk;njB53r23AiF`$Ve`nFdvkFJn4W2%o8KNX2GE zkW@&bBIWBA+Kpm|4I9+M&S{KZ+Gi%<7Cw_?u;H|UDCA6hQ4W1)MYEWV&Vm%*8Pu6eERqL0_sU3kz5}2=pso}G6 eExkeq-7T16_EhYylCAjde>WcIfvt6>-24YipY?nI literal 0 HcmV?d00001 diff --git a/samples/NativeAOT/Resources/mipmap-mdpi/appicon_background.png b/samples/NativeAOT/Resources/mipmap-mdpi/appicon_background.png new file mode 100644 index 0000000000000000000000000000000000000000..9e2d1e4d8d4ec9945deffbde04bfd430830a62b1 GIT binary patch literal 92 zcmeAS@N?(olHy`uVBq!ia0vp^IUvl)3?#R%INArKm;-!5Tm!YQ*q)m76UY_uba4!+ nh)Z4|B*D5kL8PZC(1449Erfy5Q}4VcP@cil)z4*}Q$iB}vRW1{ literal 0 HcmV?d00001 diff --git a/samples/NativeAOT/Resources/mipmap-mdpi/appicon_foreground.png b/samples/NativeAOT/Resources/mipmap-mdpi/appicon_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..a28d342c1c7106283d3e5b6f03f2d761a9d8a28c GIT binary patch literal 1273 zcmeAS@N?(olHy`uVBq!ia0vp^IUvlz3?z5#SpJ`Zf$@5PPlzj!`+pP+yAX(+=)M~m zwR1{>{DK)CH+t|g2}(z@oQn2o^7X!YXa9vg@0d-0zwy+(`*QL zb&^Bzm*{6M>%wmi)7h^dw>a|AmaSIJJaEBx&MQCczN%ZDWwmkI>DOt$Mc#Oy-23uf zCMP5|3r#vWe?zfLO2D%x8ZQ>MOWu?{bID(M+GXbtTgA@l{JG!X+v7G{TyJks?$dk0 z528YJj}_FVcN~&ZS}!BJ#dk3S1Cyzzi(^Pd+}kTp%V#Hu9C+xx=Ik+#?P(^W8E%_& zw0!UGUH$sbT_A{kFK?|;l7Hjn&2x<(QlHz!Klt#p{N8ESANvKJI22n1K*WSIJm)|6 z>P&e5@MoQUL(H+&Ox-_xz3!}y>zel=bgx)awRy43^nFa;QO_*id9WO)o|D{kv$5>l z8=pH)YjRjuMcqCS5a0RY(~6BnDeJ!W-*wnLd%Mo@G9Eqg-Luz3Z29(;vgO@&8Se7jc(rQ+rLUz#?+3p9rPo!Fba3s>TiJ$XRy}9qU6i-U70wlme$8Zj zU+c(K?Z%A)))uV~cU6fMTZ(xrzw_!%%8QpXdAI*q%s2mSzLpIUdxQH!|2#t$n3dPvGv`=h)ae{F+UU^E$3K3FBI ztDWytI(Bc9;j2x~oMPISLN=Hl`z{~ARrXKv^EDsEXn|+R2d_zRC(r*CCDPz?evg6X zVWIO43LL^&G5^%gaPO}bcQm$DSQc)I$z JtaD0e0s!klQ0D*u literal 0 HcmV?d00001 diff --git a/samples/NativeAOT/Resources/mipmap-xhdpi/appicon.png b/samples/NativeAOT/Resources/mipmap-xhdpi/appicon.png new file mode 100644 index 0000000000000000000000000000000000000000..b28b73c65453fdaf28b076d881696793e8c9bbee GIT binary patch literal 3098 zcmV+#4CV8QP)mAG*{xi(%e~m`(X|XO>D66P-k|3s4Kl5?*=M3 zEP%0Yz8&A1hxd8rZeVT)MrV30-q&XKEY?_Vp+p=B(}vuLzXmPLbwsVN)k z?*lL;h3a_Rn?g%j+>=GEh0uN|NZCJc`NpNExqT^{gYE3(B7_qR9}5 z2p0K7)z5EuIMKD@fp!PsAo0@x;-|61rzr6$N_@(IL3SBKx`2E_G(`T=dy|xSy5EyD zP-~&o4v=(!{4D7SN_@f~zXtCHiV|oE{<`HeTe}EXOeOdhfW*#?YZt!0%XED^==?{f zE4qK0-2Isfm};+p`l;&f7gYe{eo+ND+z(YiagvIV1rcG{%)jm=oKfz4Rlzm1oW`!6 zb0h_k-y|U(BEQi=K3f4m>}Xd2Pkxe;pM=Thi5Cb!2wyC$fTU3YRwdMzzm+7MF;V2% z{i88Hi}A%355So(%l)9-pU?SktAHXJMfmR%&M0@Iy;gxGz~?Z&u%Xs3;6|=w0 zp8X9ToL}e2{!}*mxof}@)#$;Fw>h8gHAV#_Y}WvSY6`*`<<6G?W9S9tHf86# zeRe;Q<-eo?YD@ucquh=0E5J<{uVDD_$aJo(}-h^v6{K?-oY ztLt@gKcwsrGymN?pafq5w^Qzd5kNWfMg2aQ{cXzG&sG3TJmY*(1yIuUx}SuS^MMM8 zMgU>vi*i3t+#hECM$Dyd+z^> z6X93DGG)hm%zRnbqmunzXFskNUT6PbBkBLE3rz%H0W!yHI$xIidF6h^`A;Mf-%llAJXh6nhMZ#yxsL} z+5&*NpI7b|=YKdAAaFW6&u^4uy<6r>-|5nOy`pKSYu~RrauCjb60Wl!i}+9@$j$LK z*Oy6LAC&X+)cxUAK$%;YBPZQU<~xa3yW=J5`~78qGKUqQWPb0b z8Q?RXXvfMv^Y_n%_g3r`wt)O%WVa?5wFzSQ?$N$0a+`31)<;X zJ7td}Dgx=a{(bN~V%Lt9y@mjrs=LsccP=5Fwde8UsK4`LZbxGO%p$bs%A>;Wj zr}fPt+lwPaZm8&VWWFK5-#>5&Kr(+*l?MSHJC1rg{0Sg+el9AYUO@yt@7W5lR!8fH z=AScJFRB2N`JM#870}n=zXC)egc?CA*{<5<@D*UK7k0jb|2*66kPAOp0j16g_~5-^ zv}08-`c8e14cqJRUT5yhXSAcu)!oLgw=X?r?A!2u@Xv#p?{oQb8b{(uw5|4-fvt4k zT+^+T{ox7Vf&6;Gn=7aS$QtPW1g)9fnXP~_K?MK;ymxxoIJczJ^;n(H%fC636<|1x zezNtrcIU&35K09INtVs;f!4D1UqixDfAx1~jjtg&Pu^$n6+k*DNPu&v>;lMUJ^Y<6 zUVvwb07V*oe zoR6>qB=dez_D53zQ`Ftgk}nc~yumtrXvjvwi+fH=1<>h&2G0(ot@vUKp78`KfEB=t z`$G{x-Ra5fJ6XXjhZo>S>-!P;?Ah6qSwcU$a0P8y(v4aG0Z6>yPiCUiIs(*o3uiqq z|C$qE3sV7wdd|d{Vp25l#Qa~e=eZ6TP_F%U@Ktg{mba5Py8=C zw%D8n`TkAQ+l8|phX7m!2)mxbTnYeWJ2*H4PA@j5gGh`q)MW$#xY1NEbxr zL#}5#6)T{ctpJYn{Hg#Kw?k7*SO9aXxxMZf`f%uqFiwO5oQ4Ger<~lRQxrj}J%1zu zu$c~KJ9JKmJF98U@p%Dut?RdqkYD=wDPu?nt?w^~uK}3~5Y6``pX~xGfXjYW=Z9AT zI!?#HALB=VeEu{#@Y}QK7f+rrZ>$R{fE9p%d=g(Yvk_Im;F)36T-jxeoI&9K59!)0 z=d*KuQ3UC9J&{y^-SH`*;|bZXy>!ko2(xaSxK#iFxsXaLpi+Mrw|Dz-@NB2B0t)k} z0+uS~I{`UG$G?LmGk+`RRRkcve*I5_#ye$O1z-V4#CR0|y2GU+fR6ja5x{l=EeW2> z$?UjF{_wMtwio|IV^4RvU0y1|Y84caPC13l!re5^iw&NL)TarWoa>0FS z!vK12tNA@ZY#Fd&4ZgNO6HYQ}eir{<2}tyj>xEb6hbBO+&GGg<`#D_r<~V<&Ty|D1}d+2^|hOU3OAU z+41ntZZI4V_4$gYnZ0&95k`=@!~Hm3MFgSi^T7GxRzQG`XUSI0did~^kIdJ&!#vR-<2GY6R;z5u+#HC?XlcsJKe^FDXZ z54QqzNcKWDnDyeHRw6sS9Cn|d_X23UUB&Tku9pcAk@G_rfX#Akf_bMypUIMZMoY`_ z5odl*D?nQW9mjicy;AfPjxYiII^I3w#eKcAzlRCWW#&gBfG?DIbG#?l=g|4l3qWQw zT&6EBQOtHn#wT3+dWYi+6&xR-^K)APC7MoGcKpb2eYgSu84i=25d7Yr?MfN%C+j25 z{AdL5>TrqMbsewj`dm3bGy$|S-O=dt4>5Wv6F#cmJA@ws+=G!-ClI+W?c z`Mhq%k09rVUjfBxsPX7_o!H4Y*M}*<`0AooxKEd5x{Jd-J3S8xXR+w+)*9*}1+Vs3PHMrVw5mJ&Q|NR)^A{Ghpg9x&(oZ;|7vP)yK1GRtk`ht$D;Om+Chprm zx8Oi`#a#yxj|Bl>zJ-Y+19K)G=)Ql#zWsz7%F#H#Pf+4TxR&M_`Nm(yD8QJEF$Moo z8NSYxU!5SYop4}qQ9!vFN4W~*NqUw5*5eGx)8WQq+=_7rRr^kiuTo67N?^U-J1GZu zP)^2DjzW8&Cuym!r~k-J^dG#1;tN+1ZecK%a&aT&CX&b6jvi%yrtsAa>si91!z3OO oB8C(3idVei6|Z>3Yox6I1HnHZ)6o}3k^lez07*qoM6N<$f&~%~2mk;8 literal 0 HcmV?d00001 diff --git a/samples/NativeAOT/Resources/mipmap-xhdpi/appicon_background.png b/samples/NativeAOT/Resources/mipmap-xhdpi/appicon_background.png new file mode 100644 index 0000000000000000000000000000000000000000..658be3fb6a3bf5656c0a725e6a5fca3dc6cfb7e5 GIT binary patch literal 100 zcmeAS@N?(olHy`uVBq!ia0vp^H$a$?8Axt^w|^awVh->LaShbIVtZ=RPas#u)5S5Q sBJS-0Lq;I)kizff+m7l*@B!Hj3>M-G7#L-mj@N)Vp00i_>zopr0REvH0{{R3 literal 0 HcmV?d00001 diff --git a/samples/NativeAOT/Resources/mipmap-xhdpi/appicon_foreground.png b/samples/NativeAOT/Resources/mipmap-xhdpi/appicon_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..70a542ac03c49ac1b30da6135d8b48016e1017fe GIT binary patch literal 1805 zcmeAS@N?(olHy`uVBq!ia0vp^H$a$!8A$H?clSO61Cx1xPlzj!`+pRSh5(5nkh%M5 z5isfODGBlmW?*DuW?^Mx=iubx=HcZR5E2#<6%&_`l9rK`S5Q<|QB~K_)Y8_`)zddH zG%_|ZHM6j^ws&xJa&~cbbNBG{_VM-e4+snj4hanlkBUxAN={AB$jr*k%P%Y{E-A05 ztg5c5Z)|FAY3u0h>h9^AFmck<=`&`|nLB^sqQy&AtX#8h{l-n3x9!-qci+K7hmRaP ze)9CW^A|2%zIy$}&0Dwc-n;+c@sp>|p1*kc>h+tq?>>C|^!dxzZ{L6X{Pp|K-+x{m zR}C2$m`{4TIEGZjy*a?h3G@}y0=X~$bFG=q8Us0~V8P>KclIyrT4b^B`9TwA?-nlw zuU-Zv*UZpmOT;}?Lnj0UtEM>9Nm0d5rd-|$=+PS|`*DYV~ zPQNzm{I7X8v*(}GD}J%+@y&zL{5rbDs}!b~g&ddBciU)Qd61z{T(Z4>^0KDhK##X) zCe5mNZ8$mPW35&0kL%|@tTvW=aOgr$!>PZC$s)h5>{B_+xvy%?M6J5BOL`l`toO&M zGmH4&WGzWQ-PU}w{cnS|Df^n478{PTEBT(Wo2?aO;NAcJSO21)?`5LT3p0LlpC(zQ zy-DJNLnzx0hBJ2Mv3e6En7?gvS$y*3#f%U8AA5df=CIy$W~X&yLaDkY`~16H;SD$K z)Yn;W+?F9QA&ui8*HWG8=7T<07UkdCV`O+(>+Is(>9d<(3cNY2w6#aPVvR=+^EDr_ zh_4-IcSckvxlW6C$!ol=X05#b4Mnz|HScen&5hk5X`}kowU(}3w_j{M|43$iYleZ54`@ZPsiM0n0?5+^}tno=mT*75r)I=4(O}7G7gngVi&N_MB@mZa^J^j5_|J|lf(~|%0%QN+Z5Px#L#d(jT4PT$7Zxqoj zFE=><`Tm7n%LPt)xMo+sWx8i+e8iB&I4(*)F5wRA2YF$?=GGR@xT6Ig$$x zdgOoC$b4s!D!uFDJIhI)A9!b}uD4nxd&`IW$^8X4xumxww$6CA@RY{RIZEOzljqGn z&ZXITwB&`Z*ynBsMS}^Yw>-RbHp$xO^)DBYXgR-b>WsRgoYtuCI|Y1#KArA6CCt+7 zJ3uQ9SY-sPE*kW{P3+Pq{}zwl&c|3xntK9yRvd$@?2>^=dTh9Oh literal 0 HcmV?d00001 diff --git a/samples/NativeAOT/Resources/mipmap-xxhdpi/appicon.png b/samples/NativeAOT/Resources/mipmap-xxhdpi/appicon.png new file mode 100644 index 0000000000000000000000000000000000000000..f9af1173ead9da4de599b034ca8c81aab47fda54 GIT binary patch literal 4674 zcmaJ_c{~%2``4_6=8lZ8awds6iiTm?Rv1~13AwK*$7Hlvg*jp}a)jm1S?Hipx#pJK ziQJ6P=2m?B{QrCX{&?Qcf6wcA-haHG=XuANo1u7l#CbS4ICwE=Ac%|Maucl|GU%a!o zv-x{|GxJx)-cVlfGq<#Zo}$LT%d6WxI-Q!sHv_x>KX~+3(9EhcbS7R_e9kom_SZQp z{bTFr3qjz1n|yz?o7oGWQ(tZRFXr7h=J^5NX^EG=@M(Ica_8?c1hy zU*G6OZ(Z7WhvhZA9dIwhv6P44VSH|q&g3i0gy27aWj)v0-z>OK8Z6BO9p4Zk`#H9L z?f*P0pPCAmzo>Hg?w>8U{d*H{XXgf+aW1~9*IVHugKiR5x|hT4_CHDeY4yVgsMb#H zakg(B55RA?jHi_BE-jyDL+Vt@50*hy!w>FfE!6g0rryk~8jqxFDWuX6RhxuO3A6Tv})X1#J_MyV8W9uX!-e|`U;?wACpZW!S4mvp3=i;6& zY4Py!bO*fy&t&Rp<$}tq%nX!K&%Sq{GDB> zSiSpn23aK#cxw^NZ6+6p2+s@*I zuJHQ?V)Eh!Fn;5oJD06n58g^yc$}BgtLXNO@R1eXSW13@wYFR6<&P#8piUu7V5k|`#77K7maAlT-ADqL^G;CNXuCF|j+~4Jmo4FHUDx>XMZUHkp zO%8#ek#s3;z;76pg2-|J44&n)uL0w_dl3!*r%kP2hYG9L`isc!r`OgAQvI^<86gPz z^0w!%rX+MOi5?6{C>2^EC=2NMzYK@_4h+y=GS_VBZy>7PQtk;^16+-pjWIG@pb`!FIw(tIG)X` z5xL=I+XoUiWr9vZO;bwPjIO#9%X+2i=_uUp;28lAQ7bA57-@8b90HmaRy5;k&WRKh za^f_V11Vi7BrDN8>;zbfxGdAJMa9*XP!@k8;sy?IgQ|C)KS17Cvrin-L{aMg`9}Wg zk0Nd=Db|))aSWHe9K@I@gtjo@lC-XySQJ$a980bz)MiU zC*yI@Jb9&B4Q8)EkapiXYqKBQG}KVT)K@!AM2srPlyYmlqs&f~5z{k>qZ<1#TDbBV zfk-$$9pzu%X){+VXuh3fv)?aIZ9d4+Ivlem(71pFd^C7QEhY>-~(*9sh|KdDUHl@F<;*W3z`IfE1>DQGgDp6yo z&UI^FahQa|+TX3l#%GhDK8_n5fhwFg#yp`nn0Fb~b!oE@hmF^t5P?Wrg(-DYz}rfc z9D8w=vR=<{9ioPN}H^#4cID&w-PPl!Ra<`eET3b^yri1WX zPHWrbA(9RuHcFFRP8vng2L;;A+hmCVhOQhk=PoY}A$H3ib#|HID)s4hTBbl~g2}biLOIOvLOVhU)Px8{8L>ozzIX;Ura) zdwI>~M|3TDLW>W0GOpa&m=isez?%*7$d=^K$v;T=?sq8-MYm6ENY?l| z0pC+&6EZ#d%k;&a0B6M%6E9WSMt>9hzMuFI#{V7hh*;|}TsfiH|5+j7s1N~*f$EZ<+D8sfmv2t%j<>Go-J{-THDrMEIZc2oh$Fkg18fnV0YN<`pQSMHil zK}9&g>#OmrN9F@&hilaXx2bO$-Wa(;ozIAp8#d=$UbbC*P5a;zj^Ei($-Xj2s)vN@ zI>rp^Det_~`_l{2P?kpQch`4J?#6id3El9}CwL56$w&J7@;%pa)D=*#^ zhc8&&hV~9*rjS>EY3Evbi4Kq)Cie|KH*Ow*3HVf2x0ZEQ3h=r<)Oaf5hTdQ45(v%x zdD=ULczAA(Qh1^bAxIxC&sninWzSXd8^{Y?Z zxF-DtO*pqJbcO+Tgn_>NLfwbukol>}$!H9earU?%aVM6GjC(R$s%ZJ-;l$#z zgOJ$0`jf#8Io3{5d``-Mzb?JU+I4$#I+&HGrpAOef?lQ})ZF&UN@_+B@aaWr^xM=H zjlP%ai($WK+lrPH_qNL0s=_kTK`epdydD!das7agrXkAO^^MWj=t?gG9R%gg^W?q6 zK7i^Y4N}RfP7T$+Z2~+g4!o=0CK2F)bj`jG#$cfC_Z~U(lveMsf))^SNG|?PBj3GA zzS^oPv-$BMGD-S+`20J4(q%V32N27TOC1Fr8QmIooD){$U?B$(i0N0syezKAZ$LLf z{WZrX^>#xPYl*uOHvzz3iRD zN%x_s_rN;52|X+WFXg_b@JmX$Smen@kf_#2|QP?H8^{m5I-&TeYQ>O%nh7vDS3Jm`-7 z+(FoFr&^D+>+O~yZ?jU!c-cbc(@_Ng(7P{>_g6kJ4pEaV{2?b)`ZiRNyecS&eyW$Q z!~Yl&)$SrlexGhEtLOh`q2@i1#XTG~ae4Qp6F~Avg@1e2vXBrO=bs=;7T=*Io#9=$ zElNSeoA3Yp(f0Dq=^5a4hHg0m@CJzbCyWCH8D2bSVXU9;Wm?vQ@W)CW+gnmSjne!{ z6oe!#&@Sv=4nSDZg-evYx_o)1w5F|{`s>5fm1sxx*_$Vm5%cPa_CRL8;ERr-RHK2O zz0l#QhodRV3k-s?)(F21A3 z_nBCI4g%O+{l;dm<)|7$Z*az}&cKzqU6sE76bZzK&0&jp+^zcre(9Gcbl;Qp&$vU! zSCYGgi&LsUP_NN%F`KU~ukq_|#7 z3}BG$bVQD7z_Kx>hiW=i{Y+uykS>N(h#Q~ZT{k%44PBIkW$(0KJ}rj+SecHY-&zu` zA~SclE!^#oXP276`1AmeE(UM*O56fD55-vb@q)PuJg;C6SHGCC0>6ZcE;JaX`y?Rz z=MS=jK?X+_>T>;{m%QGW%uMdag<+)@B~@L`%osx)VVuMTWeJdwZwh z*tmObl@FaTgNi~?UY!#~wr;-Xu9B%s95B^=ufc1?rH$K)AhIU%HugY%6<#hp&5CrJ4_ z-=F5#W+Tj~SF;vij%zW6?$ESty=6NyEbB)?I}hvett`xue8GGG?urtqUix&7`JQoqA-KY zE9k$C_<)28E_CB2uBcKi)b9?LIKR^2n<3iO)R|?P4JC=?D$6AN0P=L1>y4p>6+D^9 zMEI11q74f@N>P@>BEh(()5mA^I>ddf>j;u^ z)5vJJoFQG@sK!DrfnH&mJMel0VK|Lg)?z}U_ihp*>&!lThu**>DHs~1VLG@xW#r8S zi)X+<4eC|*q;`#XUB%58{beMU17LN#G;km1KN#*TK!b%Kp65 zh-%ZDaqzn8vQ*FHHc?KIL=Dw3PXUh|^R_dbH#jM0WWjVlBN?zNSRG@TLC6wPFxR{( z@8xo4f%dO)St_)N;U?bt;1p)MxU1^@tUr*4f*53ar#wC7Ycl&>s31WST;QL!t;x{C~8yfw@2Kb zJ9&y%iekgO_5XXSW-yZ=Z+a5ih1zqaPGG63B=$*tXGQ4iyE`SYyi^WP_3;2c(`!X* zW>zvNH?b} zC*aU({9Zo4!k+srvN)HFpK?F3x%Sza?u>&-J3re?zb?Mc6nNs7y{W{kA-OB&VKSzk z`@=0aXIZ5VR|be`wd=8tZSE!x!-@Ox8$Tjlkr0X5^*QNQ zP08hdu{Agqo^EMDIQtdXfAVB;WX uNJZS+1B{$N-XVkE%gv4_M#})%aBzUpRD*$Wxm}zqNXXOG&t;ucLK6Vqh8R8o literal 0 HcmV?d00001 diff --git a/samples/NativeAOT/Resources/mipmap-xxhdpi/appicon_foreground.png b/samples/NativeAOT/Resources/mipmap-xxhdpi/appicon_foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..cb63bfb9f8e0d0578ca53d46cf8cfeac7cb44689 GIT binary patch literal 1926 zcmeAS@N?(olHy`uVBq!ia0y~yU~~at4rZW8hROCX3=B+S0X`wFK<@uhFd71=At2GU zlnIzJHkJhW1v4-*F|)9;v2$>8ar5x<3kV7ci-?MeOUlT~$tx%-scC3x>FDVj7#f?J zSy)Xy8X(l0c=;%+LxT+jdb^;JJsEX%lga^2i-CW5Ys40gF2FR(T>X$vT8DJ6s~=+f!R z7I8G;($dK2@rn&#jC6H~DRg&r)mR$Trn&U#Kj+{{RmTjb+>3V7DZcmR^p?5${`bE5 zR4;4QRGNA~>E_eKgC&RTJ(C}*C^8gu7Cw*qqOfUx=jq0Z!c^r=)yMt|Z?u~w5X&m4 z93*^mbEu%Q(4zHz5)%ai4ULmroKn_)1c|(NIMT71JB@E+)KgZmUtct4o}2Mr+EpM} z@L>M_4FNrj4Lv{4$Jh0@HETUjb(L1C77>mV-dlMsvucn;-G3{r^l_Q;xtX~+^ zvV=@lZqHIO4b<}e(IId+^HqnU{kbbHKP~3WbL%|r_V1um$GpiCZZr#>Q@X0w=Az<~ zFX=FAQ5Q3lugZ}kh81BN_qrbDDk+`|VL0%rZcD+_BJ+s?=UMu?YdbC`KFU#2{H4Ww zyp8S13_am2B}Jz<3|S|nTLd@-{d|<%C%67PD(GZl@7Q;r)v4o(ON4osT)r;TYsUPE zuBK^o%LEoCaXCuy{OR~NeeSBt9c53I=kZn@`L58RUH>v{SzidRso*ycjtjEdEgl`e zv{*ibaVZKZ9kF$1IG?8I;?&YC%yA({)n(qnrc76cn`$i{zAdKB93K=tIVK7`oY2D1 zYXwxbWt(zCvHkUbaF4V6j}6D^c0UO_gyz9-xj8$EqO*P z0;%`Zgcki|ywoGg;P6dE9~cUgxO0CocLSh7P16Add z&ZZucJKxW-w1tDgytckNDEWbV%eR}rL?`j=^=#H+tuDdMDJ&Cmm^yAMcbgfmx#D7& zv|ng}^`C=HJJ(jaoL(XHpxCHh_~56g*BzREss|oaF}j?PylkRgc;e cRV*+t$ftaLdFqvjxFSfsr>mdKI;Vst0Fk9dIsgCw literal 0 HcmV?d00001 diff --git a/samples/NativeAOT/Resources/mipmap-xxxhdpi/appicon.png b/samples/NativeAOT/Resources/mipmap-xxxhdpi/appicon.png new file mode 100644 index 0000000000000000000000000000000000000000..1d948d6b5d88179d9aaae8cdfc063f9fe8e08807 GIT binary patch literal 6832 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 BO?ChP literal 0 HcmV?d00001 diff --git a/samples/NativeAOT/Resources/values/ic_launcher_background.xml b/samples/NativeAOT/Resources/values/ic_launcher_background.xml new file mode 100644 index 00000000000..6ec24e6413c --- /dev/null +++ b/samples/NativeAOT/Resources/values/ic_launcher_background.xml @@ -0,0 +1,4 @@ + + + #2C3E50 + \ No newline at end of file diff --git a/samples/NativeAOT/Resources/values/strings.xml b/samples/NativeAOT/Resources/values/strings.xml new file mode 100644 index 00000000000..8d13608953c --- /dev/null +++ b/samples/NativeAOT/Resources/values/strings.xml @@ -0,0 +1,4 @@ + + HelloNativeAOT + Hello, NativeAOT on Android! + diff --git a/src/Mono.Android/Android.Runtime/JNIEnvInit.cs b/src/Mono.Android/Android.Runtime/JNIEnvInit.cs index 19ff11a0913..cb1f39a8ec5 100644 --- a/src/Mono.Android/Android.Runtime/JNIEnvInit.cs +++ b/src/Mono.Android/Android.Runtime/JNIEnvInit.cs @@ -48,7 +48,7 @@ internal struct JnienvInitializeArgs { internal static IntPtr java_class_loader; internal static JniMethodInfo? mid_Class_forName; - internal static AndroidRuntime? androidRuntime; + internal static JniRuntime? androidRuntime; [UnmanagedCallersOnly] static unsafe void RegisterJniNatives (IntPtr typeName_ptr, int typeName_len, IntPtr jniClass, IntPtr methods_ptr, int methods_len) @@ -78,6 +78,14 @@ static Type TypeGetType (string typeName) => ((AndroidTypeManager)androidRuntime!.TypeManager).RegisterNativeMembers (jniType, type, methods); } + // NOTE: should have different name than `Initialize` to avoid: + // * Assertion at /__w/1/s/src/mono/mono/metadata/icall.c:6258, condition `!only_unmanaged_callers_only' not met + internal static void InitializeJniRuntime (JniRuntime runtime) + { + androidRuntime = runtime; + ValueManager = runtime.ValueManager; + } + [UnmanagedCallersOnly] internal static unsafe void Initialize (JnienvInitializeArgs* args) { diff --git a/src/Mono.Android/Properties/AssemblyInfo.cs.in b/src/Mono.Android/Properties/AssemblyInfo.cs.in index 14f600a3113..9d8b6f5694b 100644 --- a/src/Mono.Android/Properties/AssemblyInfo.cs.in +++ b/src/Mono.Android/Properties/AssemblyInfo.cs.in @@ -45,5 +45,7 @@ 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: 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.NativeAOT.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets index 868a8fa9f19..de6970db4d0 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 @@ -30,8 +30,10 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android. BeforeTargets="SetupProperties"> - <_NdkSysrootAbi>aarch64-linux-android - <_NdkClangPrefix>aarch64-linux-android21- + <_NdkAbi Condition=" '$(RuntimeIdentifier)' == 'android-arm64' ">aarch64 + <_NdkAbi Condition=" '$(RuntimeIdentifier)' == 'android-x64' ">x86_64 + <_NdkSysrootAbi>$(_NdkAbi)-linux-android + <_NdkClangPrefix>$(_NdkAbi)-linux-android21- <_NdkPrebuiltAbi Condition=" $([MSBuild]::IsOSPlatform('windows')) ">windows-x86_64 <_NdkPrebuiltAbi Condition=" $([MSBuild]::IsOSPlatform('osx')) ">darwin-x86_64 <_NdkPrebuiltAbi Condition=" $([MSBuild]::IsOSPlatform('linux')) ">linux-x86_64 @@ -49,11 +51,14 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android. --> <_OriginalSuppressTrimAnalysisWarnings>$(SuppressTrimAnalysisWarnings) true + + <_ExtraTrimmerArgs>$(_ExtraTrimmerArgs) --notrimwarn <_OriginalRuntimeIdentifier>$(RuntimeIdentifier) linux-bionic-arm64 + linux-bionic-x64 <_targetOS>linux @@ -78,6 +83,8 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android. + + diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs index 2883e771a10..2954bec5eae 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs @@ -5,6 +5,7 @@ using System.Text; using System.Xml.Linq; using System.Xml.XPath; +using Microsoft.VisualStudio.TestPlatform.Utilities; using Mono.Cecil; using NUnit.Framework; @@ -1304,5 +1305,30 @@ public static void logEvent(String eventName) {{ RunProjectAndAssert (proj, builder); } + [Test] + public void NativeAOTSample () + { + string [] properties = [ + $"AndroidNdkDirectory={AndroidNdkPath}", + "Configuration=Release", + ]; + var projectDirectory = Path.Combine (XABuildPaths.TopDirectory, "samples", "NativeAOT"); + try { + var dotnet = new DotNetCLI (Path.Combine (projectDirectory, "NativeAOT.csproj")); + Assert.IsTrue (dotnet.Build (target: "Run", parameters: properties), "`dotnet build -t:Run` should succeed"); + + bool didLaunch = WaitForActivityToStart ("my", "MainActivity", + Path.Combine (projectDirectory, "logcat.log"), 30); + Assert.IsTrue (didLaunch, "Activity should have started."); + } catch { + foreach (var file in Directory.GetFiles (projectDirectory, "*.log", SearchOption.AllDirectories)) { + TestContext.AddTestAttachment (file); + } + foreach (var bl in Directory.GetFiles (projectDirectory, "*.binlog", SearchOption.AllDirectories)) { + TestContext.AddTestAttachment (bl); + } + throw; + } + } } }