diff --git a/Documentation/docs-mobile/messages/xa1040.md b/Documentation/docs-mobile/messages/xa1040.md index 14e461a9c34..b686356767a 100644 --- a/Documentation/docs-mobile/messages/xa1040.md +++ b/Documentation/docs-mobile/messages/xa1040.md @@ -8,24 +8,23 @@ ms.date: 02/24/2025 ## Example messages ``` -warning XA1040: The CoreCLR runtime on Android is an experimental feature and not yet suitable for production use. File issues at: https://github.com/dotnet/android/issues warning XA1040: The NativeAOT runtime on Android is an experimental feature and not yet suitable for production use. File issues at: https://github.com/dotnet/android/issues ``` ## Issue -MonoVM is the default, supported runtime for .NET for Android. +CoreCLR is the default, supported runtime for .NET for Android. Mono is also supported. -Other runtimes are currently experimental, such as: +You can opt into other runtimes via: -* CoreCLR, used via `$(UseMonoRuntime)=false` +* CoreCLR, default +* MonoVM, used via `$(UseMonoRuntime)=true` * NativeAOT, used via `$(PublishAot)=true` ## Solution To silence this warning, you can either: -* Use MonoVM by removing `$(UseMonoRuntime)=false` or - `$(PublishAot)=true` from your project file. +* Use CoreCLR by removing `$(PublishAot)=true` from your project file. * Set `$(EnablePreviewFeatures)` to `true` in your project file. diff --git a/build-tools/automation/yaml-templates/stage-package-tests.yaml b/build-tools/automation/yaml-templates/stage-package-tests.yaml index c9325782918..d101018c23a 100644 --- a/build-tools/automation/yaml-templates/stage-package-tests.yaml +++ b/build-tools/automation/yaml-templates/stage-package-tests.yaml @@ -86,7 +86,7 @@ stages: testName: Mono.Android.NET_Tests-Interpreter project: tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj testResultsFiles: TestResult-Mono.Android.NET_Tests-$(XA.Build.Configuration)Interpreter.xml - extraBuildArgs: -p:TestsFlavor=Interpreter -p:UseInterpreter=True + extraBuildArgs: -p:TestsFlavor=Interpreter -p:UseInterpreter=True -p:UseMonoRuntime=true artifactSource: bin/Test$(XA.Build.Configuration)/$(DotNetTargetFramework)-android/Mono.Android.NET_Tests-Signed.aab artifactFolder: $(DotNetTargetFramework)-Interpreter @@ -154,7 +154,7 @@ stages: testName: Mono.Android.NET_Tests-NoAot project: tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj testResultsFiles: TestResult-Mono.Android.NET_Tests-$(XA.Build.Configuration)NoAot.xml - extraBuildArgs: -p:TestsFlavor=NoAot -p:RunAOTCompilation=false + extraBuildArgs: -p:TestsFlavor=NoAot -p:RunAOTCompilation=false -p:UseMonoRuntime=true artifactSource: bin/Test$(XA.Build.Configuration)/$(DotNetTargetFramework)-android/Mono.Android.NET_Tests-Signed.aab artifactFolder: $(DotNetTargetFramework)-NoAot @@ -164,7 +164,7 @@ stages: testName: Mono.Android.NET_Tests-TrimModePartial project: tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj testResultsFiles: TestResult-Mono.Android.NET_Tests-$(XA.Build.Configuration)TrimModePartial.xml - extraBuildArgs: -p:TestsFlavor=TrimModePartial -p:TrimMode=partial + extraBuildArgs: -p:TestsFlavor=TrimModePartial -p:TrimMode=partial -p:UseMonoRuntime=true artifactSource: bin/Test$(XA.Build.Configuration)/$(DotNetTargetFramework)-android/Mono.Android.NET_Tests-Signed.aab artifactFolder: $(DotNetTargetFramework)-TrimModePartial @@ -174,7 +174,7 @@ stages: testName: Mono.Android.NET_Tests-AotLlvm project: tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj testResultsFiles: TestResult-Mono.Android.NET_Tests-$(XA.Build.Configuration)AotLlvm.xml - extraBuildArgs: -p:TestsFlavor=AotLlvm -p:EnableLLVM=true -p:AndroidEnableProfiledAot=false + extraBuildArgs: -p:TestsFlavor=AotLlvm -p:EnableLLVM=true -p:AndroidEnableProfiledAot=false -p:UseMonoRuntime=true artifactSource: bin/Test$(XA.Build.Configuration)/$(DotNetTargetFramework)-android/Mono.Android.NET_Tests-Signed.aab artifactFolder: $(DotNetTargetFramework)-AotLlvm @@ -184,7 +184,7 @@ stages: testName: Mono.Android.NET_Tests-IsAssignableFrom project: tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj testResultsFiles: TestResult-Mono.Android.NET_Tests-$(XA.Build.Configuration)IsAssignableFrom.xml - extraBuildArgs: -p:TestsFlavor=IsAssignableFrom -p:IncludeCategories=Intune -p:_AndroidIsAssignableFromCheck=false + extraBuildArgs: -p:TestsFlavor=IsAssignableFrom -p:IncludeCategories=Intune -p:_AndroidIsAssignableFromCheck=false -p:UseMonoRuntime=true artifactSource: bin/Test$(XA.Build.Configuration)/$(DotNetTargetFramework)-android/Mono.Android.NET_Tests-Signed.aab artifactFolder: $(DotNetTargetFramework)-IsAssignableFrom diff --git a/build-tools/scripts/TestApks.targets b/build-tools/scripts/TestApks.targets index fa028e8c3bb..10558b6ff14 100644 --- a/build-tools/scripts/TestApks.targets +++ b/build-tools/scripts/TestApks.targets @@ -18,7 +18,7 @@ - android-arm64;android-x86;android-x64; + android-arm64;android-x86;android-x64; 29 arm64-v8a x86_64 diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets index 8970efad815..09c1e4f87b3 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets @@ -22,11 +22,9 @@ See: https://github.com/dotnet/sdk/blob/955c0fc7b06e2fa34bacd076ed39f61e4fb61716/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets#L16 --> <_GetChildProjectCopyToPublishDirectoryItems>false - false - true - <_AndroidRuntime Condition=" '$(PublishAot)' == 'true' and '$(UseMonoRuntime)' != 'true' ">NativeAOT - <_AndroidRuntime Condition=" '$(PublishAot)' != 'true' and '$(UseMonoRuntime)' != 'true' ">CoreCLR - <_AndroidRuntime Condition=" '$(_AndroidRuntime)' == '' ">MonoVM + <_AndroidRuntime Condition=" '$(PublishAot)' == 'true' ">NativeAOT + <_AndroidRuntime Condition=" '$(PublishAot)' != 'true' and '$(UseMonoRuntime)' == 'true' ">MonoVM + <_AndroidRuntime Condition=" '$(_AndroidRuntime)' == '' ">CoreCLR true diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs index 5a135444ca7..b9e5a42e610 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs @@ -84,6 +84,8 @@ public void BuildBasicApplicationReleaseWithCustomAotProfile () IsRelease = true, AndroidEnableProfiledAot = true, }; + // A Mono-only test + proj.SetRuntime (AndroidRuntime.MonoVM); proj.SetProperty (proj.ActiveConfigurationProperties, "AndroidExtraAotOptions", "--verbose"); byte [] custom_aot_profile = XamarinAndroidCommonProject.GetResourceContents ("Xamarin.ProjectTools.Resources.Base.custom.aotprofile"); @@ -109,25 +111,51 @@ public void BuildBasicApplicationReleaseProfiledAotWithoutDefaultProfile () StringAssertEx.DoesNotContainRegex (@$"Using profile data file.*dotnet\.aotprofile", b.LastBuildOutput, "Should not use default AOT profile", RegexOptions.IgnoreCase); } + static IEnumerable Get_BuildAotApplicationWithSpecialCharactersInProjectData () + { + var ret = new List (); + + foreach (AndroidRuntime runtime in new[] { AndroidRuntime.MonoVM, AndroidRuntime.CoreCLR }) { + AddTestData ("テスト", false, false, runtime); + AddTestData ("テスト", true, true, runtime); + AddTestData ("テスト", true, false, runtime); + AddTestData ("随机生成器", false, false, runtime); + AddTestData ("随机生成器", true, true, runtime); + AddTestData ("随机生成器", true, false, runtime); + AddTestData ("中国", false, false, runtime); + AddTestData ("中国", true, true, runtime); + AddTestData ("中国", true, false, runtime); + } + + return ret; + + void AddTestData (string testName, bool isRelease, bool aot, AndroidRuntime runtime) + { + ret.Add (new object[] { + testName, + isRelease, + aot, + runtime, + }); + } + } + [Test] - [TestCase ("テスト", false, false)] - [TestCase ("テスト", true, true)] - [TestCase ("テスト", true, false)] - [TestCase ("随机生成器", false, false)] - [TestCase ("随机生成器", true, true)] - [TestCase ("随机生成器", true, false)] - [TestCase ("中国", false, false)] - [TestCase ("中国", true, true)] - [TestCase ("中国", true, false)] - public void BuildAotApplicationWithSpecialCharactersInProject (string testName, bool isRelease, bool aot) + [TestCaseSource (nameof (Get_BuildAotApplicationWithSpecialCharactersInProjectData))] + public void BuildAotApplicationWithSpecialCharactersInProject (string testName, bool isRelease, bool aot, AndroidRuntime runtime) { + if (aot && runtime == AndroidRuntime.CoreCLR) { + Assert.Ignore ("AOT + CoreCLR == NativeAOT; Not supported yet here"); + return; + } + var rootPath = Path.Combine (Root, "temp", TestName); var proj = new XamarinAndroidApplicationProject () { ProjectName = testName, IsRelease = isRelease, AotAssemblies = aot, }; - proj.SetAndroidSupportedAbis ("armeabi-v7a", "arm64-v8a", "x86", "x86_64"); + proj.SetRuntime (runtime); using (var builder = CreateApkBuilder (Path.Combine (rootPath, proj.ProjectName))){ Assert.IsTrue (builder.Build (proj), "Build should have succeeded."); } @@ -393,6 +421,8 @@ public void AotAssembliesInIDE () IsRelease = true, AotAssemblies = true, }; + // Mono-only test + proj.SetRuntime (AndroidRuntime.MonoVM); proj.SetAndroidSupportedAbis (supportedAbis); using var b = CreateApkBuilder (); Assert.IsTrue (b.RunTarget (proj, target: "Build")); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs index 3baca768f99..fa75a9e8d74 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs @@ -248,6 +248,8 @@ public void CheckMonoComponentsMask (bool enableProfiler, bool useInterpreter, b IsRelease = !debugBuild, }; + // Mono-only test + proj.SetRuntime (AndroidRuntime.MonoVM); proj.SetProperty (proj.ActiveConfigurationProperties, "AndroidEnableProfiler", enableProfiler.ToString ()); proj.SetProperty (proj.ActiveConfigurationProperties, "UseInterpreter", useInterpreter.ToString ()); @@ -260,40 +262,35 @@ public void CheckMonoComponentsMask (bool enableProfiler, bool useInterpreter, b string objPath = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath); List envFiles = EnvironmentHelper.GatherEnvironmentFiles (objPath, String.Join (";", abis), true); - EnvironmentHelper.ApplicationConfig app_config = EnvironmentHelper.ReadApplicationConfig (envFiles); + var app_config = (EnvironmentHelper.ApplicationConfig_MonoVM)EnvironmentHelper.ReadApplicationConfig (envFiles, AndroidRuntime.MonoVM); Assert.That (app_config, Is.Not.Null, "application_config must be present in the environment files"); Assert.IsTrue (app_config.mono_components_mask == expectedMask, "Expected Mono Components mask 0x{expectedMask:x}, got 0x{app_config.mono_components_mask:x}"); } } - static object [] CheckAssemblyCountsSource = new object [] { - new object[] { - /*isRelease*/ false, - /*aot*/ false, - }, - new object[] { - /*isRelease*/ true, - /*aot*/ false, - }, - new object[] { - /*isRelease*/ true, - /*aot*/ true, - }, - }; [Test] - [TestCaseSource (nameof (CheckAssemblyCountsSource))] [NonParallelizable] - public void CheckAssemblyCounts (bool isRelease, bool aot) + public void CheckAssemblyCounts ([Values (true, false)] bool isRelease, [Values (true, false)] bool aot, + [Values (AndroidRuntime.MonoVM, AndroidRuntime.CoreCLR)] AndroidRuntime runtime) { + if (isRelease == false && aot == true) { + Assert.Ignore ("Not testing AOT with Debug builds"); + return; + } + + bool aotAssemblies = aot && runtime == AndroidRuntime.MonoVM; var proj = new XamarinFormsAndroidApplicationProject { IsRelease = isRelease, EmbedAssembliesIntoApk = true, - AotAssemblies = aot, + AotAssemblies = aotAssemblies, }; + proj.SetRuntime (runtime); - var abis = new [] { "armeabi-v7a", "x86" }; - proj.SetRuntimeIdentifiers (abis); + var targetArches = new [] { AndroidTargetArch.Arm64, AndroidTargetArch.X86_64 }; + var abis = targetArches.Select (arch => MonoAndroidHelper.ArchToAbi (arch)); + + proj.SetRuntimeIdentifiers (targetArches); proj.SetProperty (proj.ActiveConfigurationProperties, "AndroidUseAssemblyStore", "True"); using (var b = CreateApkBuilder ()) { @@ -301,10 +298,10 @@ public void CheckAssemblyCounts (bool isRelease, bool aot) string objPath = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath); List envFiles = EnvironmentHelper.GatherEnvironmentFiles (objPath, String.Join (";", abis), true); - EnvironmentHelper.ApplicationConfig app_config = EnvironmentHelper.ReadApplicationConfig (envFiles); + EnvironmentHelper.IApplicationConfig app_config = EnvironmentHelper.ReadApplicationConfig (envFiles, runtime); Assert.That (app_config, Is.Not.Null, "application_config must be present in the environment files"); - if (aot) { + if (aotAssemblies) { foreach (var env in envFiles) { StringAssert.Contains ("libaot-Mono.Android.dll.so", File.ReadAllText (env.Path)); } @@ -312,13 +309,17 @@ public void CheckAssemblyCounts (bool isRelease, bool aot) string apk = Path.Combine (Root, b.ProjectDirectory, proj.OutputPath, $"{proj.PackageName}-Signed.apk"); var helper = new ArchiveAssemblyHelper (apk, useAssemblyStores: true); + uint numberOfAssembliesInApk = runtime switch { + AndroidRuntime.MonoVM => ((EnvironmentHelper.ApplicationConfig_MonoVM)app_config).number_of_assemblies_in_apk, + AndroidRuntime.CoreCLR => ((EnvironmentHelper.ApplicationConfig_CoreCLR)app_config).number_of_assemblies_in_apk, + _ => throw new NotSupportedException ($"Unsupported runtime '{runtime}'") + }; - foreach (string abi in abis) { - AndroidTargetArch arch = MonoAndroidHelper.AbiToTargetArch (abi); + foreach (AndroidTargetArch arch in targetArches) { Assert.AreEqual ( - app_config.number_of_assemblies_in_apk, + numberOfAssembliesInApk, helper.GetNumberOfAssemblies (arch: arch), - $"Assembly count must be equal between ApplicationConfig and the archive contents for architecture {arch} (ABI: {abi})" + $"Assembly count must be equal between ApplicationConfig and the archive contents for architecture {arch} (ABI: {MonoAndroidHelper.ArchToAbi (arch)})" ); } } @@ -355,6 +356,8 @@ public static string GetLinkedPath (ProjectBuilder builder, bool isRelease, stri [TestCaseSource (nameof (RuntimeChecks))] public void CheckWhichRuntimeIsIncluded (string supportedAbi, bool debugSymbols, bool? optimize, bool? embedAssemblies, string expectedRuntime) { var proj = new XamarinAndroidApplicationProject (); + // MonoVM-only test + proj.SetRuntime (Android.Tasks.AndroidRuntime.MonoVM); proj.SetAndroidSupportedAbis (supportedAbi); proj.SetProperty (proj.ActiveConfigurationProperties, "DebugSymbols", debugSymbols); if (optimize.HasValue) @@ -1300,7 +1303,6 @@ public void EnvironmentVariables (bool useInterpreter, string packageNamingPolic proj.SetProperty ("AndroidPackageNamingPolicy", packageNamingPolicy); if (!string.IsNullOrEmpty (diagnosticConfiguration)) proj.SetProperty ("DiagnosticConfiguration", diagnosticConfiguration); - proj.SetAndroidSupportedAbis ("armeabi-v7a", "x86"); using (var b = CreateApkBuilder ()) { Assert.IsTrue (b.Build (proj), "build should have succeeded."); var environment = b.Output.GetIntermediaryPath (Path.Combine ("__environment__.txt")); @@ -1704,16 +1706,38 @@ public void CheckLintResourceFileReferencesAreFixed () } [Test] - public void SimilarAndroidXAssemblyNames ([Values(true, false)] bool publishTrimmed) + [TestCase (true, AndroidRuntime.MonoVM)] + [TestCase (false, AndroidRuntime.MonoVM)] + [TestCase (true, AndroidRuntime.CoreCLR)] + [TestCase (false, AndroidRuntime.CoreCLR)] + // TODO: [TestCase (false, AndroidRuntime.NativeAOT)] + public void SimilarAndroidXAssemblyNames (bool publishTrimmed, AndroidRuntime runtime) { + if (!publishTrimmed && runtime == AndroidRuntime.CoreCLR) { + // This currently fails with the following exception: + // + // error XALNS7015: System.NotSupportedException: Writing mixed-mode assemblies is not supported + // at Mono.Cecil.ModuleWriter.Write(ModuleDefinition module, Disposable`1 stream, WriterParameters parameters) + // at Mono.Cecil.ModuleWriter.WriteModule(ModuleDefinition module, Disposable`1 stream, WriterParameters parameters) + // at Mono.Cecil.ModuleDefinition.Write(String fileName, WriterParameters parameters) + // at Mono.Cecil.AssemblyDefinition.Write(String fileName, WriterParameters parameters) + // at Xamarin.Android.Tasks.SaveChangedAssemblyStep.ProcessAssembly(AssemblyDefinition assembly, StepContext context) in src/Xamarin.Android.Build.Tasks/Tasks/AssemblyModifierPipeline.cs:line 197 + // at Xamarin.Android.Tasks.AssemblyPipeline.Run(AssemblyDefinition assembly, StepContext context) in src/Xamarin.Android.Build.Tasks/Utilities/AssemblyPipeline.cs:line 26 + // at Xamarin.Android.Tasks.AssemblyModifierPipeline.RunPipeline(AssemblyPipeline pipeline, ITaskItem source, ITaskItem destination) in src/Xamarin.Android.Build.Tasks/Tasks/AssemblyModifierPipeline.cs:line 175 + Assert.Ignore ("CoreCLR: fails because of a Mono.Cecil lack of support"); + return; + } + + bool aotAssemblies = runtime == AndroidRuntime.MonoVM && publishTrimmed; var proj = new XamarinAndroidApplicationProject { IsRelease = true, - AotAssemblies = publishTrimmed, + AotAssemblies = aotAssemblies, PackageReferences = { new Package { Id = "Xamarin.AndroidX.CustomView", Version = "1.1.0.17" }, new Package { Id = "Xamarin.AndroidX.CustomView.PoolingContainer", Version = "1.0.0.4" }, } }; + proj.SetRuntime (runtime); proj.SetProperty (KnownProperties.PublishTrimmed, publishTrimmed.ToString()); proj.MainActivity = proj.DefaultMainActivity.Replace ("//${AFTER_ONCREATE}", "AndroidX.CustomView.PoolingContainer.PoolingContainer.IsPoolingContainer (null);"); using var builder = CreateApkBuilder (); 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 6e8c70e7d1d..af3f8246fbb 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 @@ -51,6 +51,8 @@ public void MarshalMethodsDefaultEnabledStatus (bool isRelease, bool marshalMeth IsRelease = isRelease, EnableMarshalMethods = marshalMethodsEnabled, }; + // MonoVM-only test + proj.SetRuntime (Android.Tasks.AndroidRuntime.MonoVM); proj.SetRuntimeIdentifiers (abis); bool shouldMarshalMethodsBeEnabled = isRelease && marshalMethodsEnabled; @@ -68,19 +70,25 @@ public void MarshalMethodsDefaultEnabledStatus (bool isRelease, bool marshalMeth String.Join (";", supportedArches.Select (arch => MonoAndroidHelper.ArchToAbi (arch))), true ); - EnvironmentHelper.ApplicationConfig app_config = EnvironmentHelper.ReadApplicationConfig (envFiles); + var app_config = (EnvironmentHelper.ApplicationConfig_MonoVM)EnvironmentHelper.ReadApplicationConfig (envFiles, Android.Tasks.AndroidRuntime.MonoVM); Assert.That (app_config, Is.Not.Null, "application_config must be present in the environment files"); Assert.AreEqual (app_config.marshal_methods_enabled, shouldMarshalMethodsBeEnabled, $"Marshal methods enabled status should be '{shouldMarshalMethodsBeEnabled}', but it was '{app_config.marshal_methods_enabled}'"); } } + // TODO: fix for CoreCLR + // Currently it fails with: + // + // Microsoft.Android.Sdk.AssemblyResolution.targets(198,5): error MSB4096: The item "obj/Release/UnnamedProject.pdb" in item list "ResolvedSymbols" does not define a value for metadata "DestinationSubPath". In order to use this metadata, either qualify it by specifying %(ResolvedSymbols.DestinationSubPath), or ensure that all items in this list define a value for this metadata. [Test] public void CompressedWithoutLinker () { var proj = new XamarinAndroidApplicationProject { IsRelease = true }; + // Mono-only test, at least for now + proj.SetRuntime (AndroidRuntime.MonoVM); proj.SetProperty (proj.ReleaseProperties, KnownProperties.AndroidLinkMode, AndroidLinkMode.None.ToString ()); using (var b = CreateApkBuilder ()) { Assert.IsTrue (b.Build (proj), "Build should have succeeded."); @@ -333,18 +341,19 @@ public static string GetLinkedPath (ProjectBuilder builder, bool isRelease, stri } [Test] - public void BuildReleaseArm64 ([Values (false, true)] bool forms) + public void BuildReleaseArm64 ([Values (false, true)] bool forms, [Values (AndroidRuntime.MonoVM, AndroidRuntime.CoreCLR)] AndroidRuntime runtime) { var proj = forms ? new XamarinFormsAndroidApplicationProject () : new XamarinAndroidApplicationProject (); + proj.SetRuntime (runtime); proj.IsRelease = true; proj.AotAssemblies = false; // Release defaults to Profiled AOT for .NET 6 proj.SetAndroidSupportedAbis ("arm64-v8a"); proj.SetProperty ("LinkerDumpDependencies", "True"); proj.SetProperty ("AndroidUseAssemblyStore", "False"); - var flavor = (forms ? "XForms" : "Simple") + "DotNet"; + var flavor = (forms ? "XForms" : "Simple") + "DotNet" + "." + runtime.ToString (); var apkDescFilename = $"BuildReleaseArm64{flavor}.apkdesc"; var apkDescReference = "reference.apkdesc"; byte [] apkDescData = XamarinAndroidCommonProject.GetResourceContents ($"Xamarin.ProjectTools.Resources.Base.{apkDescFilename}"); @@ -609,17 +618,55 @@ static void Test () }, }; + static IEnumerable Get_BuildBasicApplicationFSharpData () + { + var ret = new List (); + + // TODO: AndroidRuntime.NativeAOT doesn't work yet. Fails with + // + // Microsoft.Android.Sdk.Aot.targets(123,5): error : Runtime critical type System.RuntimeMethodHandle not found + foreach (AndroidRuntime runtime in new[] { AndroidRuntime.MonoVM, AndroidRuntime.CoreCLR }) { + AddTestData (isRelease: false, aot: false, runtime); + AddTestData (isRelease: true, aot: false, runtime); + AddTestData (isRelease: true, aot: true, runtime); + } + + return ret; + + void AddTestData (bool isRelease, bool aot, AndroidRuntime runtime) + { + ret.Add (new object[] { + isRelease, + aot, + runtime, + }); + } + } + [Test] - [TestCaseSource (nameof (BuildBasicApplicationFSharpSource))] + [TestCaseSource (nameof (Get_BuildBasicApplicationFSharpData))] [Category ("Minor"), Category ("FSharp")] [NonParallelizable] // parallel NuGet restore causes failures - public void BuildBasicApplicationFSharp (bool isRelease, bool aot) + public void BuildBasicApplicationFSharp (bool isRelease, bool aot, AndroidRuntime runtime) { + if (runtime == AndroidRuntime.NativeAOT) { + if (!aot) { + Assert.Ignore ("NativeAOT disabled for !aot"); + return; + } + } else if (runtime == AndroidRuntime.CoreCLR) { + if (aot) { + Assert.Ignore ("CoreCLR + AOT == NativeAOT"); + return; + } + } + var proj = new XamarinAndroidApplicationProject { Language = XamarinAndroidProjectLanguage.FSharp, IsRelease = isRelease, AotAssemblies = aot, }; + proj.SetRuntime (runtime); using var b = CreateApkBuilder (); Assert.IsTrue (b.Build (proj), "Build should have succeeded."); } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildWithLibraryTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildWithLibraryTests.cs index ad947b5faf0..0f5f2d8c739 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildWithLibraryTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildWithLibraryTests.cs @@ -9,6 +9,7 @@ using Mono.Cecil; using NUnit.Framework; using Xamarin.ProjectTools; +using Xamarin.Android.Tasks; namespace Xamarin.Android.Build.Tests { @@ -47,9 +48,31 @@ public class BuildWithLibraryTests : BaseTest }, }; + static IEnumerable Get_DotNetBuildLibraryParams () + { + var source = new List (); + var runtimes = new List { + AndroidRuntime.MonoVM, + AndroidRuntime.CoreCLR, + }; + + foreach (object[] args in DotNetBuildLibrarySource) { + foreach (AndroidRuntime runtime in runtimes) { + source.Add (new object[] { + args[0], + args[1], + args[2], + runtime, + }); + } + } + + return source; + } + [Test] - [TestCaseSource (nameof (DotNetBuildLibrarySource))] - public void DotNetBuildLibrary (bool isRelease, bool duplicateAar, bool useDesignerAssembly) + [TestCaseSource (nameof (Get_DotNetBuildLibraryParams))] + public void DotNetBuildLibrary (bool isRelease, bool duplicateAar, bool useDesignerAssembly, AndroidRuntime runtime) { var path = Path.Combine ("temp", TestName); var env_var = "MY_ENVIRONMENT_VAR"; @@ -73,6 +96,7 @@ public void DotNetBuildLibrary (bool isRelease, bool duplicateAar, bool useDesig }, } }; + libC.SetRuntime (runtime); libC.OtherBuildItems.Add (new AndroidItem.AndroidAsset ("Assets\\bar\\bar.txt") { BinaryContent = () => Array.Empty (), }); @@ -147,6 +171,7 @@ public Foo () }, } }; + libB.SetRuntime (runtime); libB.OtherBuildItems.Add (new AndroidItem.AndroidEnvironment ("env.txt") { TextContent = () => $"{env_var}={env_val}", }); @@ -215,6 +240,7 @@ public Foo () } } }; + appA.SetRuntime (runtime); appA.AddReference (libB); if (duplicateAar) { // Test a duplicate @(AndroidLibrary) item with the same path of LibraryB.aar @@ -259,7 +285,7 @@ public Foo () // Check environment variable if (isRelease) { var environmentFiles = EnvironmentHelper.GatherEnvironmentFiles (intermediate, "x86_64", required: true); - var environmentVariables = EnvironmentHelper.ReadEnvironmentVariables (environmentFiles); + var environmentVariables = EnvironmentHelper.ReadEnvironmentVariables (environmentFiles, runtime); Assert.IsTrue (environmentVariables.TryGetValue (env_var, out string actual), $"Environment should contain {env_var}"); Assert.AreEqual (env_val, actual, $"{env_var} should be {env_val}"); } @@ -370,15 +396,15 @@ public void BuildWithNativeLibraries ([Values (true, false)] bool isRelease) ProjectName = "Library1", IsRelease = isRelease, OtherBuildItems = { - new AndroidItem.EmbeddedNativeLibrary ("foo\\armeabi-v7a\\libtest.so") { + new AndroidItem.EmbeddedNativeLibrary ("foo\\arm64-v8a\\libtest.so") { BinaryContent = () => new byte[10], - MetadataValues = "Link=libs\\armeabi-v7a\\libtest.so", + MetadataValues = "Link=libs\\arm64-v8a\\libtest.so", }, - new AndroidItem.EmbeddedNativeLibrary ("foo\\x86\\libtest.so") { + new AndroidItem.EmbeddedNativeLibrary ("foo\\x86_64\\libtest.so") { BinaryContent = () => new byte[10], - MetadataValues = "Link=libs\\x86\\libtest.so", + MetadataValues = "Link=libs\\x86_64\\libtest.so", }, - new AndroidItem.AndroidNativeLibrary ("armeabi-v7a\\libRSSupport.so") { + new AndroidItem.AndroidNativeLibrary ("arm64-v8a\\libRSSupport.so") { BinaryContent = () => new byte[10], }, }, @@ -390,13 +416,13 @@ public void BuildWithNativeLibraries ([Values (true, false)] bool isRelease) new BuildItem ("ProjectReference","..\\Library1\\Library1.csproj"), }, OtherBuildItems = { - new AndroidItem.EmbeddedNativeLibrary ("foo\\armeabi-v7a\\libtest1.so") { + new AndroidItem.EmbeddedNativeLibrary ("foo\\arm64-v8a\\libtest1.so") { BinaryContent = () => new byte[10], - MetadataValues = "Link=libs\\armeabi-v7a\\libtest1.so", + MetadataValues = "Link=libs\\arm64-v8a\\libtest1.so", }, - new AndroidItem.EmbeddedNativeLibrary ("foo\\x86\\libtest1.so") { + new AndroidItem.EmbeddedNativeLibrary ("foo\\x86_64\\libtest1.so") { BinaryContent = () => new byte[10], - MetadataValues = "Link=libs\\x86\\libtest1.so", + MetadataValues = "Link=libs\\x86_64\\libtest1.so", }, }, }; @@ -407,12 +433,11 @@ public void BuildWithNativeLibraries ([Values (true, false)] bool isRelease) new BuildItem ("ProjectReference","..\\Library2\\Library2.csproj"), }, OtherBuildItems = { - new AndroidItem.AndroidNativeLibrary ("armeabi-v7a\\libRSSupport.so") { + new AndroidItem.AndroidNativeLibrary ("arm64-v8a\\libRSSupport.so") { BinaryContent = () => new byte[10], }, } }; - proj.SetRuntimeIdentifiers (["armeabi-v7a", "x86"]); var path = Path.Combine (Root, "temp", string.Format ("BuildWithNativeLibraries_{0}", isRelease)); using (var b1 = CreateDllBuilder (Path.Combine (path, dll2.ProjectName))) { Assert.IsTrue (b1.Build (dll2), "Build should have succeeded."); @@ -423,23 +448,23 @@ public void BuildWithNativeLibraries ([Values (true, false)] bool isRelease) var apk = Path.Combine (Root, builder.ProjectDirectory, proj.OutputPath, $"{proj.PackageName}-Signed.apk"); FileAssert.Exists (apk); - Assert.IsTrue (StringAssertEx.ContainsText (builder.LastBuildOutput, "warning XA4301: APK already contains the item lib/armeabi-v7a/libRSSupport.so; ignoring."), + Assert.IsTrue (StringAssertEx.ContainsText (builder.LastBuildOutput, "warning XA4301: APK already contains the item lib/arm64-v8a/libRSSupport.so; ignoring."), "warning about skipping libRSSupport.so should have been raised"); using (var zipFile = ZipHelper.OpenZip (apk)) { - var data = ZipHelper.ReadFileFromZip (zipFile, "lib/x86/libtest.so"); - Assert.IsNotNull (data, "libtest.so for x86 should exist in the apk."); - data = ZipHelper.ReadFileFromZip (zipFile, "lib/armeabi-v7a/libtest.so"); - Assert.IsNotNull (data, "libtest.so for armeabi-v7a should exist in the apk."); - data = ZipHelper.ReadFileFromZip (zipFile, "lib/x86/libtest1.so"); - Assert.IsNotNull (data, "libtest1.so for x86 should exist in the apk."); - data = ZipHelper.ReadFileFromZip (zipFile, "lib/armeabi-v7a/libtest1.so"); - Assert.IsNotNull (data, "libtest1.so for armeabi-v7a should exist in the apk."); - data = ZipHelper.ReadFileFromZip (zipFile, "lib/armeabi-v7a/libRSSupport.so"); - Assert.IsNotNull (data, "libRSSupport.so for armeabi-v7a should exist in the apk."); - data = ZipHelper.ReadFileFromZip (zipFile, "lib/x86/libSystem.Native.so"); - Assert.IsNotNull (data, "libSystem.Native.so for x86 should exist in the apk."); - data = ZipHelper.ReadFileFromZip (zipFile, "lib/armeabi-v7a/libSystem.Native.so"); - Assert.IsNotNull (data, "libSystem.Native.so for armeabi-v7a should exist in the apk."); + var data = ZipHelper.ReadFileFromZip (zipFile, "lib/x86_64/libtest.so"); + Assert.IsNotNull (data, "libtest.so for x86_64 should exist in the apk."); + data = ZipHelper.ReadFileFromZip (zipFile, "lib/arm64-v8a/libtest.so"); + Assert.IsNotNull (data, "libtest.so for arm64-v8a should exist in the apk."); + data = ZipHelper.ReadFileFromZip (zipFile, "lib/x86_64/libtest1.so"); + Assert.IsNotNull (data, "libtest1.so for x86_64 should exist in the apk."); + data = ZipHelper.ReadFileFromZip (zipFile, "lib/arm64-v8a/libtest1.so"); + Assert.IsNotNull (data, "libtest1.so for arm64-v8a should exist in the apk."); + data = ZipHelper.ReadFileFromZip (zipFile, "lib/arm64-v8a/libRSSupport.so"); + Assert.IsNotNull (data, "libRSSupport.so for arm64-v8a should exist in the apk."); + data = ZipHelper.ReadFileFromZip (zipFile, "lib/x86_64/libSystem.Native.so"); + Assert.IsNotNull (data, "libSystem.Native.so for x86_64 should exist in the apk."); + data = ZipHelper.ReadFileFromZip (zipFile, "lib/arm64-v8a/libSystem.Native.so"); + Assert.IsNotNull (data, "libSystem.Native.so for arm64-v8a should exist in the apk."); } } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/EnvironmentContentTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/EnvironmentContentTests.cs index 1d8ff21e199..6c76ce284c4 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/EnvironmentContentTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/EnvironmentContentTests.cs @@ -7,6 +7,7 @@ using Mono.Cecil; using NUnit.Framework; using Xamarin.ProjectTools; +using Xamarin.Android.Tasks; namespace Xamarin.Android.Build.Tests { @@ -15,9 +16,14 @@ public class EnvironmentContentTests : BaseTest { [Test] [NonParallelizable] - public void BuildApplicationWithMonoEnvironment ([Values ("", "Normal", "Offline")] string sequencePointsMode) + public void BuildApplicationWithMonoEnvironment ([Values ("", "Normal", "Offline")] string sequencePointsMode, + [Values (AndroidRuntime.MonoVM, AndroidRuntime.CoreCLR)] AndroidRuntime runtime) { - const string supportedAbis = "armeabi-v7a;x86"; + string supportedAbis = runtime switch { + AndroidRuntime.MonoVM => "armeabi-v7a;x86", + AndroidRuntime.CoreCLR => "arm64-v8a;x86_64", + _ => throw new NotSupportedException ($"Unsupported runtime '{runtime}'") + }; var lib = new XamarinAndroidLibraryProject { ProjectName = "Library1", @@ -27,6 +33,7 @@ public void BuildApplicationWithMonoEnvironment ([Values ("", "Normal", "Offline }, }, }; + lib.SetRuntime (runtime); var app = new XamarinFormsAndroidApplicationProject () { IsRelease = true, AndroidLinkModeRelease = AndroidLinkMode.Full, @@ -34,6 +41,7 @@ public void BuildApplicationWithMonoEnvironment ([Values ("", "Normal", "Offline new BuildItem ("ProjectReference","..\\Library1\\Library1.csproj"), }, }; + app.SetRuntime (runtime); //LinkSkip one assembly that contains __AndroidLibraryProjects__.zip string linkSkip = "FormsViewGroup"; app.SetProperty ("AndroidLinkSkip", linkSkip); @@ -46,7 +54,7 @@ public void BuildApplicationWithMonoEnvironment ([Values ("", "Normal", "Offline string intermediateOutputDir = Path.Combine (Root, appb.ProjectDirectory, app.IntermediateOutputPath); List envFiles = EnvironmentHelper.GatherEnvironmentFiles (intermediateOutputDir, supportedAbis, true); - Dictionary envvars = EnvironmentHelper.ReadEnvironmentVariables (envFiles); + Dictionary envvars = EnvironmentHelper.ReadEnvironmentVariables (envFiles, runtime); Assert.IsTrue (envvars.Count > 0, $"No environment variables defined"); string monoDebugVar; @@ -57,7 +65,7 @@ public void BuildApplicationWithMonoEnvironment ([Values ("", "Normal", "Offline if (!String.IsNullOrEmpty (sequencePointsMode)) Assert.IsTrue (monoDebugVar.IndexOf ("gen-compact-seq-points", StringComparison.Ordinal) >= 0, "The values from Mono.env should have been merged into environment"); - EnvironmentHelper.AssertValidEnvironmentSharedLibrary (intermediateOutputDir, AndroidSdkPath, AndroidNdkPath, supportedAbis); + EnvironmentHelper.AssertValidEnvironmentSharedLibrary (intermediateOutputDir, AndroidSdkPath, AndroidNdkPath, supportedAbis, runtime); var assemblyDir = Path.Combine (Root, appb.ProjectDirectory, app.IntermediateOutputPath, "android", "assets"); var rp = new ReaderParameters { ReadSymbols = false }; @@ -82,6 +90,9 @@ public void CheckMonoDebugIsAddedToEnvironment ([Values ("", "Normal", "Offline" var proj = new XamarinAndroidApplicationProject () { IsRelease = true, }; + + // Mono-only test + proj.SetRuntime (AndroidRuntime.MonoVM); proj.SetProperty ("_AndroidSequencePointsMode", sequencePointsMode); proj.SetAndroidSupportedAbis (supportedAbis); using (var b = CreateApkBuilder ()) { @@ -89,7 +100,7 @@ public void CheckMonoDebugIsAddedToEnvironment ([Values ("", "Normal", "Offline" string intermediateOutputDir = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath); List envFiles = EnvironmentHelper.GatherEnvironmentFiles (intermediateOutputDir, supportedAbis, true); - Dictionary envvars = EnvironmentHelper.ReadEnvironmentVariables (envFiles); + Dictionary envvars = EnvironmentHelper.ReadEnvironmentVariables (envFiles, AndroidRuntime.MonoVM); Assert.IsTrue (envvars.Count > 0, $"No environment variables defined"); string monoDebugVar; @@ -101,7 +112,7 @@ public void CheckMonoDebugIsAddedToEnvironment ([Values ("", "Normal", "Offline" Assert.AreEqual ("gen-compact-seq-points", monoDebugVar, "environment should contain MONO_DEBUG=gen-compact-seq-points"); } - EnvironmentHelper.AssertValidEnvironmentSharedLibrary (intermediateOutputDir, AndroidSdkPath, AndroidNdkPath, supportedAbis); + EnvironmentHelper.AssertValidEnvironmentSharedLibrary (intermediateOutputDir, AndroidSdkPath, AndroidNdkPath, supportedAbis, AndroidRuntime.MonoVM); } } @@ -115,6 +126,8 @@ public void CheckConcurrentGC () var expectedDefaultValue = "major=marksweep"; var expectedUpdatedValue = "major=marksweep-conc"; var supportedAbis = "armeabi-v7a;arm64-v8a"; + // MonoVM-only test + proj.SetRuntime (Android.Tasks.AndroidRuntime.MonoVM); proj.SetAndroidSupportedAbis (supportedAbis); using (var b = CreateApkBuilder ()) { @@ -123,14 +136,14 @@ public void CheckConcurrentGC () var intermediateOutputDir = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath); // AndroidEnableSGenConcurrent=False by default List envFiles = EnvironmentHelper.GatherEnvironmentFiles (intermediateOutputDir, supportedAbis, true); - Dictionary envvars = EnvironmentHelper.ReadEnvironmentVariables (envFiles); + Dictionary envvars = EnvironmentHelper.ReadEnvironmentVariables (envFiles, AndroidRuntime.MonoVM); Assert.IsTrue (envvars.ContainsKey (gcVarName), $"Environment should contain '{gcVarName}'."); Assert.AreEqual (expectedDefaultValue, envvars[gcVarName], $"'{gcVarName}' should have been '{expectedDefaultValue}' when concurrent GC is disabled."); proj.SetProperty ("AndroidEnableSGenConcurrent", "True"); Assert.IsTrue (b.Build (proj), "Second build should have succeeded."); envFiles = EnvironmentHelper.GatherEnvironmentFiles (intermediateOutputDir, supportedAbis, true); - envvars = EnvironmentHelper.ReadEnvironmentVariables (envFiles); + envvars = EnvironmentHelper.ReadEnvironmentVariables (envFiles, AndroidRuntime.MonoVM); Assert.IsTrue (envvars.ContainsKey (gcVarName), $"Environment should contain '{gcVarName}'."); Assert.AreEqual (expectedUpdatedValue, envvars[gcVarName], $"'{gcVarName}' should have been '{expectedUpdatedValue}' when concurrent GC is enabled."); } @@ -151,7 +164,7 @@ public void CheckForInvalidHttpClientHandlerType () } [Test] - public void CheckHttpClientHandlerType () + public void CheckHttpClientHandlerType ([Values (AndroidRuntime.MonoVM, AndroidRuntime.CoreCLR)] AndroidRuntime runtime) { var proj = new XamarinAndroidApplicationProject () { IsRelease = true, @@ -161,6 +174,7 @@ public void CheckHttpClientHandlerType () var expectedUpdatedValue = "Xamarin.Android.Net.AndroidMessageHandler"; var supportedAbis = "armeabi-v7a;arm64-v8a"; + proj.SetRuntime (runtime); proj.SetAndroidSupportedAbis (supportedAbis); proj.PackageReferences.Add (new Package() { Id = "System.Net.Http", Version = "*" }); proj.MainActivity = proj.DefaultMainActivity.Replace ("//${AFTER_ONCREATE}", "var _ = new System.Net.Http.HttpClient ();"); @@ -170,14 +184,14 @@ public void CheckHttpClientHandlerType () Assert.IsTrue (b.Build (proj), "Build should have succeeded."); var intermediateOutputDir = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath); List envFiles = EnvironmentHelper.GatherEnvironmentFiles (intermediateOutputDir, supportedAbis, true); - Dictionary envvars = EnvironmentHelper.ReadEnvironmentVariables (envFiles); + Dictionary envvars = EnvironmentHelper.ReadEnvironmentVariables (envFiles, runtime); Assert.IsTrue (envvars.ContainsKey (httpClientHandlerVarName), $"Environment should contain '{httpClientHandlerVarName}'."); Assert.AreEqual (expectedDefaultValue, envvars[httpClientHandlerVarName]); proj.SetProperty ("AndroidHttpClientHandlerType", expectedUpdatedValue); Assert.IsTrue (b.Build (proj), "Second build should have succeeded."); envFiles = EnvironmentHelper.GatherEnvironmentFiles (intermediateOutputDir, supportedAbis, true); - envvars = EnvironmentHelper.ReadEnvironmentVariables (envFiles); + envvars = EnvironmentHelper.ReadEnvironmentVariables (envFiles, runtime); Assert.IsTrue (envvars.ContainsKey (httpClientHandlerVarName), $"Environment should contain '{httpClientHandlerVarName}'."); Assert.AreEqual (expectedUpdatedValue, envvars[httpClientHandlerVarName]); } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs index dbb0bd836f3..e04d738a1a8 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs @@ -41,6 +41,10 @@ public void BasicApplicationRepetitiveBuild () } } + // TODO: fix for CoreCLR + // Currently fails with + // + // The target _Sign should have *not* been skipped. [Test] public void BasicApplicationRepetitiveReleaseBuild () { @@ -53,6 +57,8 @@ public class Foo { } }" }; + // Mono-only test, for now + proj.SetRuntime (AndroidRuntime.MonoVM); proj.Sources.Add (foo); Assert.IsTrue (b.Build (proj), "first build failed"); var firstBuildTime = b.LastBuildTime; @@ -304,14 +310,20 @@ public TestMe createTestMe () { } [Test] - public void ResolveNativeLibrariesInManagedReferences () + public void ResolveNativeLibrariesInManagedReferences ([Values (AndroidRuntime.MonoVM, AndroidRuntime.CoreCLR)] AndroidRuntime runtime) { + string abi = runtime switch { + AndroidRuntime.MonoVM => "armeabi-v7a", + AndroidRuntime.CoreCLR => "arm64-v8a", + _ => throw new NotSupportedException ($"Unsupported runtime '{runtime}'") + }; + var lib = new XamarinAndroidLibraryProject () { ProjectName = "Lib", IsRelease = true, ProjectGuid = Guid.NewGuid ().ToString (), OtherBuildItems = { - new BuildItem (AndroidBuildActions.EmbeddedNativeLibrary, "libs/armeabi-v7a/libfoo.so") { + new BuildItem (AndroidBuildActions.EmbeddedNativeLibrary, $"libs/{abi}/libfoo.so") { TextContent = () => string.Empty, Encoding = Encoding.ASCII, } @@ -332,14 +344,15 @@ public Class1 () }, }, }; - var so = lib.OtherBuildItems.First (x => x.Include () == "libs/armeabi-v7a/libfoo.so"); + lib.SetRuntime (runtime); + var so = lib.OtherBuildItems.First (x => x.Include () == $"libs/{abi}/libfoo.so"); var lib2 = new XamarinAndroidLibraryProject () { ProjectName = "Lib2", ProjectGuid = Guid.NewGuid ().ToString (), IsRelease = true, OtherBuildItems = { - new BuildItem (AndroidBuildActions.EmbeddedNativeLibrary, "libs/armeabi-v7a/libfoo2.so") { + new BuildItem (AndroidBuildActions.EmbeddedNativeLibrary, $"libs/{abi}/libfoo2.so") { TextContent = () => string.Empty, Encoding = Encoding.ASCII, }, @@ -363,6 +376,7 @@ public Class2 () }, }, }; + lib2.SetRuntime (runtime); var path = Path.Combine (Root, "temp", TestName); using (var libbuilder = CreateDllBuilder (Path.Combine(path, "Lib"))) { @@ -378,12 +392,27 @@ public Class2 () new BuildItem.ProjectReference (@"..\Lib2\Lib2.csproj", "Lib2", lib2.ProjectGuid), } }; - app.SetAndroidSupportedAbis ("armeabi-v7a"); + app.SetRuntime (runtime); + + if (runtime == AndroidRuntime.MonoVM) { + // Using `SetRuntimeIdentifier` would change the intermediate path (by adding the RID component to it) and, thus, the way this test used to work. + // Keep it as it was. + app.SetAndroidSupportedAbis (abi); + } else { + app.SetRuntimeIdentifier (abi); + } + using (var builder = CreateApkBuilder (Path.Combine (path, "App"))) { Assert.IsTrue (builder.Build (app), "app 1st. build failed"); - var libfoo = ZipHelper.ReadFileFromZip (Path.Combine (Root, builder.ProjectDirectory, app.OutputPath, app.PackageName + "-Signed.apk"), - "lib/armeabi-v7a/libfoo.so"); + // TODO: appending of the RID to the output path should probably be fixed in the project class instead of here (and elsewhere) + string apkFile = Path.Combine (Root, builder.ProjectDirectory, app.OutputPath); + if (runtime == AndroidRuntime.CoreCLR) { + apkFile = Path.Combine (apkFile, MonoAndroidHelper.AbiToRid (abi)); + } + apkFile = Path.Combine (apkFile, app.PackageName + "-Signed.apk"); + + var libfoo = ZipHelper.ReadFileFromZip (apkFile, $"lib/{abi}/libfoo.so"); Assert.IsNotNull (libfoo, "libfoo.so should exist in the .apk"); so.TextContent = () => "newValue"; @@ -394,11 +423,9 @@ public Class2 () Assert.IsNotNull (libfoo, "libfoo.so should exist in the .apk"); - libfoo = ZipHelper.ReadFileFromZip (Path.Combine (Root, builder.ProjectDirectory, app.OutputPath, app.PackageName + "-Signed.apk"), - "lib/armeabi-v7a/libfoo.so"); + libfoo = ZipHelper.ReadFileFromZip (apkFile, $"lib/{abi}/libfoo.so"); Assert.AreEqual (so.TextContent ().Length, libfoo.Length, "compressed size mismatch"); - var libfoo2 = ZipHelper.ReadFileFromZip (Path.Combine (Root, builder.ProjectDirectory, app.OutputPath, app.PackageName + "-Signed.apk"), - "lib/armeabi-v7a/libfoo2.so"); + var libfoo2 = ZipHelper.ReadFileFromZip (apkFile, $"lib/{abi}/libfoo2.so"); Assert.IsNotNull (libfoo2, "libfoo2.so should exist in the .apk"); Directory.Delete (path, recursive: true); } @@ -983,7 +1010,7 @@ public void CasingOnJavaLangObject () } [Test] - public void GenerateJavaStubsAndAssembly ([Values (true, false)] bool isRelease) + public void GenerateJavaStubsAndAssembly ([Values (true, false)] bool isRelease, [Values (AndroidRuntime.MonoVM, AndroidRuntime.CoreCLR)] AndroidRuntime runtime) { var targets = new [] { "_GenerateJavaStubs", @@ -992,7 +1019,21 @@ public void GenerateJavaStubsAndAssembly ([Values (true, false)] bool isRelease) var proj = new XamarinAndroidApplicationProject { IsRelease = isRelease, }; - proj.SetAndroidSupportedAbis ("armeabi-v7a"); + proj.SetRuntime (runtime); + + string abi = runtime switch { + AndroidRuntime.MonoVM => "armeabi-v7a", + AndroidRuntime.CoreCLR => "arm64-v8a", + _ => throw new NotSupportedException ($"Unsupported runtime '{runtime}'") + }; + if (runtime == AndroidRuntime.MonoVM) { + // Using `SetRuntimeIdentifier` would change the intermediate path (by adding the RID component to it) and, thus, the way this test used to work. + // Keep it as it was. + proj.SetAndroidSupportedAbis (abi); + } else { + proj.SetRuntimeIdentifier (abi); + } + proj.OtherBuildItems.Add (new AndroidItem.AndroidEnvironment ("Foo.txt") { TextContent = () => "Foo=Bar", }); @@ -1002,7 +1043,7 @@ public void GenerateJavaStubsAndAssembly ([Values (true, false)] bool isRelease) foreach (var target in targets) { Assert.IsFalse (b.Output.IsTargetSkipped (target), $"`{target}` should *not* be skipped!"); } - AssertAssemblyFilesInFileWrites (proj, b); + AssertAssemblyFilesInFileWrites (proj, b, abi, runtime); // Change C# file and AndroidEvironment file proj.MainActivity += Environment.NewLine + "// comment"; @@ -1012,30 +1053,35 @@ public void GenerateJavaStubsAndAssembly ([Values (true, false)] bool isRelease) foreach (var target in targets) { Assert.IsFalse (b.Output.IsTargetSkipped (target), $"`{target}` should *not* be skipped!"); } - AssertAssemblyFilesInFileWrites (proj, b); + AssertAssemblyFilesInFileWrites (proj, b, abi, runtime); // No changes Assert.IsTrue (b.Build (proj), "third build should have succeeded."); foreach (var target in targets) { Assert.IsTrue (b.Output.IsTargetSkipped (target), $"`{target}` should be skipped!"); } - AssertAssemblyFilesInFileWrites (proj, b); + AssertAssemblyFilesInFileWrites (proj, b, abi, runtime); } } readonly string [] ExpectedAssemblyFiles = new [] { - Path.Combine ("android", "environment.armeabi-v7a.o"), - Path.Combine ("android", "environment.armeabi-v7a.ll"), - Path.Combine ("android", "typemaps.armeabi-v7a.o"), - Path.Combine ("android", "typemaps.armeabi-v7a.ll"), - Path.Combine ("app_shared_libraries", "armeabi-v7a", "libxamarin-app.so") + Path.Combine ("android", "environment.@ABI@.o"), + Path.Combine ("android", "environment.@ABI@.ll"), + Path.Combine ("android", "typemaps.@ABI@.o"), + Path.Combine ("android", "typemaps.@ABI@.ll"), + Path.Combine ("app_shared_libraries", "@ABI@", "libxamarin-app.so") }; - void AssertAssemblyFilesInFileWrites (XamarinAndroidApplicationProject proj, ProjectBuilder b) + void AssertAssemblyFilesInFileWrites (XamarinAndroidApplicationProject proj, ProjectBuilder b, string abi, AndroidRuntime runtime) { var intermediate = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath); + if (runtime == AndroidRuntime.CoreCLR) { + intermediate = Path.Combine (intermediate, MonoAndroidHelper.AbiToRid (abi)); + } + var lines = File.ReadAllLines (Path.Combine (intermediate, $"{proj.ProjectName}.csproj.FileListAbsolute.txt")); - foreach (var file in ExpectedAssemblyFiles) { + foreach (var fileRaw in ExpectedAssemblyFiles) { + string file = fileRaw.Replace ("@ABI@", abi); var path = Path.Combine (intermediate, file); CollectionAssert.Contains (lines, path, $"{file} is not in FileWrites!"); FileAssert.Exists (path); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/InvalidConfigTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/InvalidConfigTests.cs index 6e523662b2d..b04982fb8ae 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/InvalidConfigTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/InvalidConfigTests.cs @@ -1,5 +1,6 @@ using NUnit.Framework; using System.IO; +using Xamarin.Android.Tasks; using Xamarin.ProjectTools; namespace Xamarin.Android.Build.Tests @@ -49,6 +50,8 @@ public void SettingCombinations (bool isRelease, bool useInterpreter, bool publi IsRelease = isRelease, EnableDefaultItems = true, }; + // MonoVM-only test + proj.SetRuntime (Android.Tasks.AndroidRuntime.MonoVM); proj.SetProperty ("UseInterpreter", useInterpreter.ToString ()); proj.SetProperty ("PublishTrimmed", publishTrimmed.ToString ()); proj.SetProperty ("RunAOTCompilation", aot.ToString ()); @@ -107,6 +110,8 @@ public void XA0119Interpreter () IsRelease = true, AotAssemblies = true, }; + // Mono-only test + proj.SetRuntime (AndroidRuntime.MonoVM); proj.SetProperty ("UseInterpreter", "true"); using (var builder = CreateApkBuilder ()) { builder.ThrowOnBuildFailure = false; diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/ManifestTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/ManifestTest.cs index 77653127501..3ee368f0e2c 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/ManifestTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/ManifestTest.cs @@ -471,6 +471,7 @@ public void DirectBootAwareAttribute () }, }; + // TODO: make it work on CoreCLR and NativeAOT [Test] [TestCaseSource(nameof (VersionCodeTestSource))] public void VersionCodeTests (bool seperateApk, string abis, string versionCode, bool useLegacy, string versionCodePattern, string versionCodeProperties, bool shouldBuild, string expectedVersionCode) @@ -480,6 +481,10 @@ public void VersionCodeTests (bool seperateApk, string abis, string versionCode, MinSdkVersion = "21", SupportedOSPlatformVersion = "21.0", }; + + // MonoVM-only test, for now (changing anything in the test data changes the codes, each case must be + // investigated and verified manually) + proj.SetRuntime (AndroidRuntime.MonoVM); proj.SetProperty ("Foo", "1"); proj.SetProperty ("GenerateApplicationManifest", "false"); // Disable $(AndroidVersionCode) support proj.SetProperty (proj.ReleaseProperties, KnownProperties.AndroidCreatePackagePerAbi, seperateApk); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs index d987bad2987..effdb063866 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/PackagingTest.cs @@ -57,14 +57,15 @@ public void CheckR8InfoMessagesToNotBreakTheBuild () } [Test] - public void CheckDebugModeWithTrimming () + public void CheckDebugModeWithTrimming ([Values (AndroidRuntime.MonoVM, AndroidRuntime.CoreCLR)] AndroidRuntime runtime) { - bool usesAssemblyStores = false; + bool usesAssemblyStores = runtime == AndroidRuntime.CoreCLR; var proj = new XamarinAndroidApplicationProject { ProjectName = "MyApp", IsRelease = false, EmbedAssembliesIntoApk = true, }; + proj.SetRuntime (runtime); proj.SetProperty ("PublishTrimmed", "true"); proj.SetProperty ("AndroidUseAssemblyStore", usesAssemblyStores.ToString ()); @@ -83,16 +84,25 @@ public void CheckDebugModeWithTrimming () [Test] [NonParallelizable] // Commonly fails NuGet restore - public void CheckIncludedAssemblies ([Values (false, true)] bool usesAssemblyStores) + public void CheckIncludedAssemblies ([Values (false, true)] bool usesAssemblyStores, [Values (AndroidRuntime.MonoVM, AndroidRuntime.CoreCLR)] AndroidRuntime runtime) { + if (!usesAssemblyStores && runtime == AndroidRuntime.CoreCLR) { + Assert.Ignore ("CoreCLR only supports builds with assembly stores."); + return; + } + var proj = new XamarinAndroidApplicationProject { IsRelease = true }; AndroidTargetArch[] supportedArches = new[] { - AndroidTargetArch.Arm, + runtime switch { + AndroidRuntime.MonoVM => AndroidTargetArch.Arm, + AndroidRuntime.CoreCLR => AndroidTargetArch.Arm64, + _ => throw new NotSupportedException ($"Unsupported runtime '{runtime}'") + } }; - + proj.SetRuntime (runtime); proj.SetProperty ("AndroidUseAssemblyStore", usesAssemblyStores.ToString ()); proj.SetRuntimeIdentifiers (supportedArches); proj.PackageReferences.Add (new Package { @@ -129,9 +139,12 @@ public void CheckIncludedAssemblies ([Values (false, true)] bool usesAssemblySto "System.Collections.dll", "System.Collections.Concurrent.dll", "System.Text.RegularExpressions.dll", - "libarc.bin.so", }; + if (runtime == AndroidRuntime.MonoVM) { + expectedFiles.Add ("libarc.bin.so"); + } + using (var b = CreateApkBuilder ()) { Assert.IsTrue (b.Build (proj), "build should have succeeded."); var apk = Path.Combine (Root, b.ProjectDirectory, @@ -191,13 +204,15 @@ public void CheckClassesDexIsIncluded () [Test] [Parallelizable (ParallelScope.Self)] - public void CheckIncludedNativeLibraries ([Values (true, false)] bool compressNativeLibraries) + public void CheckIncludedNativeLibraries ([Values (true, false)] bool compressNativeLibraries, + [Values (AndroidRuntime.MonoVM, AndroidRuntime.CoreCLR, AndroidRuntime.NativeAOT)] AndroidRuntime runtime) { var proj = new XamarinAndroidApplicationProject () { IsRelease = true, }; + proj.SetRuntime (runtime); proj.PackageReferences.Add(KnownPackages.SQLitePCLRaw_Core); - proj.SetAndroidSupportedAbis ("x86"); + proj.SetAndroidSupportedAbis ("x86_64"); proj.SetProperty (proj.ReleaseProperties, "AndroidStoreUncompressedFileExtensions", compressNativeLibraries ? "" : "so"); using (var b = CreateApkBuilder ()) { b.ThrowOnBuildFailure = false; @@ -207,7 +222,7 @@ public void CheckIncludedNativeLibraries ([Values (true, false)] bool compressNa CompressionMethod method = compressNativeLibraries ? CompressionMethod.Deflate : CompressionMethod.Store; using (var zip = ZipHelper.OpenZip (apk)) { var libFiles = zip.Where (x => x.FullName.StartsWith("lib/", StringComparison.Ordinal) && !x.FullName.Equals("lib/", StringComparison.InvariantCultureIgnoreCase)); - var abiPaths = new string[] { "lib/x86/" }; + var abiPaths = new string[] { "lib/x86_64/" }; foreach (var file in libFiles) { Assert.IsTrue (abiPaths.Any (x => file.FullName.Contains (x)), $"Apk contains an unnesscary lib file: {file.FullName}"); Assert.IsTrue (file.CompressionMethod == method, $"{file.FullName} should have been CompressionMethod.{method} in the apk, but was CompressionMethod.{file.CompressionMethod}"); @@ -379,7 +394,8 @@ public void CheckMetadataSkipItemsAreProcessedCorrectly () } [Test] - public void CheckSignApk ([Values(true, false)] bool useApkSigner, [Values(true, false)] bool perAbiApk) + public void CheckSignApk ([Values(true, false)] bool useApkSigner, [Values(true, false)] bool perAbiApk, + [Values (AndroidRuntime.MonoVM, AndroidRuntime.CoreCLR)] AndroidRuntime runtime) { string ext = Environment.OSVersion.Platform != PlatformID.Unix ? ".bat" : ""; var foundApkSigner = Directory.EnumerateDirectories (Path.Combine (AndroidSdkPath, "build-tools")).Any (dir => Directory.EnumerateFiles (dir, "apksigner"+ ext).Any ()); @@ -409,6 +425,7 @@ public void CheckSignApk ([Values(true, false)] bool useApkSigner, [Values(true, var proj = new XamarinAndroidApplicationProject () { IsRelease = true, }; + proj.SetRuntime (runtime); proj.SetProperty (proj.ReleaseProperties, "AndroidUseApkSigner", useApkSigner); proj.SetProperty (proj.ReleaseProperties, "AndroidKeyStore", "True"); proj.SetProperty (proj.ReleaseProperties, "AndroidSigningKeyStore", keyfile); @@ -417,9 +434,13 @@ public void CheckSignApk ([Values(true, false)] bool useApkSigner, [Values(true, proj.SetProperty (proj.ReleaseProperties, "AndroidSigningStorePass", Uri.EscapeDataString (pass)); proj.SetProperty (proj.ReleaseProperties, KnownProperties.AndroidCreatePackagePerAbi, perAbiApk); if (perAbiApk) { - proj.SetAndroidSupportedAbis ("armeabi-v7a", "x86", "arm64-v8a", "x86_64"); + if (runtime == AndroidRuntime.MonoVM) { + proj.SetAndroidSupportedAbis ("armeabi-v7a", "x86", "arm64-v8a", "x86_64"); + } else { + proj.SetRuntimeIdentifiers (AndroidTargetArch.Arm64, AndroidTargetArch.X86_64); + } } else { - proj.SetAndroidSupportedAbis ("armeabi-v7a", "x86"); + proj.SetRuntimeIdentifiers (AndroidTargetArch.Arm64, AndroidTargetArch.X86_64); } using (var b = CreateApkBuilder (Path.Combine ("temp", TestName, "App"))) { var bin = Path.Combine (Root, b.ProjectDirectory, proj.OutputPath); @@ -435,11 +456,20 @@ public void CheckSignApk ([Values(true, false)] bool useApkSigner, [Values(true, // Make sure the APKs have unique version codes if (perAbiApk) { - int armManifestCode = GetVersionCodeFromIntermediateManifest (Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "armeabi-v7a", "AndroidManifest.xml")); - int x86ManifestCode = GetVersionCodeFromIntermediateManifest (Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "x86", "AndroidManifest.xml")); + var versionList = new List (); + int armManifestCode = Int32.MinValue; + int x86ManifestCode = Int32.MinValue; + if (runtime == AndroidRuntime.MonoVM) { + armManifestCode = GetVersionCodeFromIntermediateManifest (Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "armeabi-v7a", "AndroidManifest.xml")); + x86ManifestCode = GetVersionCodeFromIntermediateManifest (Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "x86", "AndroidManifest.xml")); + versionList.Add (armManifestCode); + versionList.Add (x86ManifestCode); + } + int arm64ManifestCode = GetVersionCodeFromIntermediateManifest (Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "arm64-v8a", "AndroidManifest.xml")); int x86_64ManifestCode = GetVersionCodeFromIntermediateManifest (Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath, "android", "x86_64", "AndroidManifest.xml")); - var versionList = new List { armManifestCode, x86ManifestCode, arm64ManifestCode, x86_64ManifestCode }; + versionList.Add (arm64ManifestCode); + versionList.Add (x86_64ManifestCode); Assert.True (versionList.Distinct ().Count () == versionList.Count, $"APK version codes were not unique - armeabi-v7a: {armManifestCode}, x86: {x86ManifestCode}, arm64-v8a: {arm64ManifestCode}, x86_64: {x86_64ManifestCode}"); } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/LinkerTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/LinkerTests.cs index 870b3e2c6c4..56eab82079f 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/LinkerTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/LinkerTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; @@ -266,11 +267,17 @@ public void WarnAboutAppDomains ([Values (true, false)] bool isRelease) } [Test] - public void RemoveDesigner ([Values (true, false)] bool useAssemblyStore) + public void RemoveDesigner ([Values (true, false)] bool useAssemblyStore, [Values (AndroidRuntime.MonoVM, AndroidRuntime.CoreCLR)] AndroidRuntime runtime) { + if (!useAssemblyStore && runtime == AndroidRuntime.CoreCLR) { + Assert.Ignore ("CoreCLR supports only assembly stores"); + return; + } + var proj = new XamarinAndroidApplicationProject { IsRelease = true, }; + proj.SetRuntime (runtime); proj.SetProperty ("AndroidEnableAssemblyCompression", "False"); proj.SetProperty ("AndroidLinkResources", "True"); proj.SetProperty ("AndroidUseAssemblyStore", useAssemblyStore.ToString ()); @@ -302,8 +309,13 @@ public void RemoveDesigner ([Values (true, false)] bool useAssemblyStore) } [Test] - public void LinkDescription ([Values (true, false)] bool useAssemblyStore) + public void LinkDescription ([Values (true, false)] bool useAssemblyStore, [Values (AndroidRuntime.MonoVM, AndroidRuntime.CoreCLR)] AndroidRuntime runtime) { + if (!useAssemblyStore && runtime == AndroidRuntime.CoreCLR) { + Assert.Ignore ("CoreCLR doesn't support builds without assembly stores."); + return; + } + string assembly_name = "System.Console"; string linker_xml = ""; @@ -315,6 +327,8 @@ public void LinkDescription ([Values (true, false)] bool useAssemblyStore) } } }; + proj.SetRuntime (runtime); + // So we can use Mono.Cecil to open assemblies directly proj.SetProperty ("AndroidEnableAssemblyCompression", "False"); proj.SetProperty ("AndroidUseAssemblyStore", useAssemblyStore.ToString ()); @@ -398,41 +412,58 @@ public AttributedButtonStub (Context context) : base (context) } } - static readonly object [] AndroidAddKeepAlivesSource = new object [] { - // Debug configuration - new object [] { - /* isRelease */ false, - /* AndroidAddKeepAlives=true */ false, - /* AndroidLinkMode=None */ false, - /* should add KeepAlives */ false, - }, - // Debug configuration, AndroidAddKeepAlives=true - new object [] { - /* isRelease */ false, - /* AndroidAddKeepAlives=true */ true, - /* AndroidLinkMode=None */ false, - /* should add KeepAlives */ true, - }, - // Release configuration - new object [] { - /* isRelease */ true, - /* AndroidAddKeepAlives=true */ false, - /* AndroidLinkMode=None */ false, - /* should add KeepAlives */ true, - }, - // Release configuration, AndroidLinkMode=None - new object [] { - /* isRelease */ true, - /* AndroidAddKeepAlives=true */ false, - /* AndroidLinkMode=None */ true, - /* should add KeepAlives */ true, - }, - }; + static IEnumerable Get_AndroidAddKeepAlivesData () + { + var ret = new List (); + + foreach (AndroidRuntime runtime in new[] { AndroidRuntime.MonoVM, AndroidRuntime.CoreCLR }) { + // Debug configuration + AddTestData (isRelease: false, setAndroidAddKeepAlivesTrue: false, setLinkModeNone: false, shouldAddKeepAlives: false, runtime); + + // Debug configuration, AndroidAddKeepAlives=true + AddTestData (isRelease: false, setAndroidAddKeepAlivesTrue: true, setLinkModeNone: false, shouldAddKeepAlives: true, runtime); + + // Release configuration + AddTestData (isRelease: true, setAndroidAddKeepAlivesTrue: false, setLinkModeNone: false, shouldAddKeepAlives: true, runtime); + + // Release configuration, AndroidLinkMode=None + AddTestData (isRelease: true, setAndroidAddKeepAlivesTrue: false, setLinkModeNone: true, shouldAddKeepAlives: true, runtime); + } + + return ret; + + void AddTestData (bool isRelease, bool setAndroidAddKeepAlivesTrue, bool setLinkModeNone, bool shouldAddKeepAlives, AndroidRuntime runtime) + { + ret.Add (new object[] { + isRelease, + setAndroidAddKeepAlivesTrue, + setLinkModeNone, + shouldAddKeepAlives, + runtime + }); + } + } [Test] - [TestCaseSource (nameof (AndroidAddKeepAlivesSource))] - public void AndroidAddKeepAlives (bool isRelease, bool setAndroidAddKeepAlivesTrue, bool setLinkModeNone, bool shouldAddKeepAlives) + [TestCaseSource (nameof (Get_AndroidAddKeepAlivesData))] + public void AndroidAddKeepAlives (bool isRelease, bool setAndroidAddKeepAlivesTrue, bool setLinkModeNone, bool shouldAddKeepAlives, AndroidRuntime runtime) { + if (runtime == AndroidRuntime.CoreCLR && isRelease && !setAndroidAddKeepAlivesTrue && setLinkModeNone && shouldAddKeepAlives) { + // This currently fails with the following exception: + // + // error XALNS7015: System.NotSupportedException: Writing mixed-mode assemblies is not supported + // at Mono.Cecil.ModuleWriter.Write(ModuleDefinition module, Disposable`1 stream, WriterParameters parameters) + // at Mono.Cecil.ModuleWriter.WriteModule(ModuleDefinition module, Disposable`1 stream, WriterParameters parameters) + // at Mono.Cecil.ModuleDefinition.Write(String fileName, WriterParameters parameters) + // at Mono.Cecil.AssemblyDefinition.Write(String fileName, WriterParameters parameters) + // at Xamarin.Android.Tasks.SaveChangedAssemblyStep.ProcessAssembly(AssemblyDefinition assembly, StepContext context) in src/Xamarin.Android.Build.Tasks/Tasks/AssemblyModifierPipeline.cs:line 197 + // at Xamarin.Android.Tasks.AssemblyPipeline.Run(AssemblyDefinition assembly, StepContext context) in src/Xamarin.Android.Build.Tasks/Utilities/AssemblyPipeline.cs:line 26 + // at Xamarin.Android.Tasks.AssemblyModifierPipeline.RunPipeline(AssemblyPipeline pipeline, ITaskItem source, ITaskItem destination) in src/Xamarin.Android.Build.Tasks/Tasks/AssemblyModifierPipeline.cs:line 175 + // at Xamarin.Android.Tasks.AssemblyModifierPipeline.RunTask() in src/Xamarin.Android.Build.Tasks/Tasks/AssemblyModifierPipeline.cs:line 123 + Assert.Ignore ("CoreCLR: fails because of a Mono.Cecil lack of support"); + return; + }; + var proj = new XamarinAndroidApplicationProject { IsRelease = isRelease, OtherBuildItems = { @@ -462,6 +493,7 @@ public unsafe bool MyMethod (Android.OS.IBinder windowToken, [global::Android.Ru } }; + proj.SetRuntime (runtime); proj.SetProperty ("AllowUnsafeBlocks", "True"); // We don't want `[TargetPlatform ("android35")]` to get set because we don't do AddKeepAlives on .NET for Android assemblies @@ -620,11 +652,29 @@ protected override void OnNewIntent (Android.Content.Intent? intent) } } + // TODO: fix for (true, AndroidRuntime.CoreCLR) [Test] - public void DoNotErrorOnPerArchJavaTypeDuplicates ([Values(true, false)] bool enableMarshalMethods) + public void DoNotErrorOnPerArchJavaTypeDuplicates ( + [Values(true, false)] bool enableMarshalMethods, + [Values(AndroidRuntime.MonoVM, AndroidRuntime.CoreCLR)] AndroidRuntime runtime) { + if (enableMarshalMethods == true && runtime == AndroidRuntime.CoreCLR) { + // This currently fails with the following exception: + // + // Xamarin.Android.Common.targets(1603,3): error XARMM7015: System.NotSupportedException: Writing mixed-mode assemblies is not supported + // at Mono.Cecil.ModuleWriter.Write(ModuleDefinition module, Disposable`1 stream, WriterParameters parameters) + // at Mono.Cecil.ModuleWriter.WriteModule(ModuleDefinition module, Disposable`1 stream, WriterParameters parameters) + // at Mono.Cecil.ModuleDefinition.Write(String fileName, WriterParameters parameters) + // at Mono.Cecil.AssemblyDefinition.Write(String fileName, WriterParameters parameters) + // at Xamarin.Android.Tasks.MarshalMethodsAssemblyRewriter.Rewrite(Boolean brokenExceptionTransitions) in src/Xamarin.Android.Build.Tasks/Utilities/MarshalMethodsAssemblyRewriter.cs:line 165 + // at Xamarin.Android.Tasks.RewriteMarshalMethods.RewriteMethods(NativeCodeGenState state, Boolean brokenExceptionTransitionsEnabled) in src/Xamarin.Android.Build.Tasks/Tasks/RewriteMarshalMethods.cs:line 160 + Assert.Ignore ("Fails with Mono.Cecil exception on CoreCLR"); + return; + } + var path = Path.Combine (Root, "temp", TestName); var lib = new XamarinAndroidLibraryProject { IsRelease = true, ProjectName = "Lib1" }; + lib.SetRuntime (runtime); lib.SetProperty ("IsTrimmable", "true"); lib.Sources.Add (new BuildItem.Source ("Library1.cs") { TextContent = () => @" @@ -649,7 +699,10 @@ public abstract class MyRunner { }" }); var proj = new XamarinAndroidApplicationProject { IsRelease = true, ProjectName = "App1" }; - proj.SetRuntimeIdentifiers(["armeabi-v7a", "arm64-v8a", "x86", "x86_64"]); + proj.SetRuntime (runtime); + if (runtime == AndroidRuntime.MonoVM) { + proj.SetRuntimeIdentifiers(["armeabi-v7a", "arm64-v8a", "x86", "x86_64"]); + } proj.References.Add(new BuildItem.ProjectReference (Path.Combine ("..", "Lib1", "Lib1.csproj"), "Lib1")); proj.MainActivity = proj.DefaultMainActivity.Replace ( "base.OnCreate (bundle);", @@ -665,14 +718,20 @@ public abstract class MyRunner { var intermediate = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath); var dll = $"{lib.ProjectName}.dll"; - Assert64Bit ("android-arm", expected64: false); + if (runtime == AndroidRuntime.MonoVM) { + Assert64Bit ("android-arm", expected64: false); + Assert64Bit ("android-x86", expected64: false); + } Assert64Bit ("android-arm64", expected64: true); - Assert64Bit ("android-x86", expected64: false); Assert64Bit ("android-x64", expected64: true); void Assert64Bit(string rid, bool expected64) { - var assembly = AssemblyDefinition.ReadAssembly (Path.Combine (intermediate, rid, "linked", "shrunk", dll)); + string libDir = Path.Combine (intermediate, rid, "linked"); + if (runtime == AndroidRuntime.MonoVM) { + libDir = Path.Combine (libDir, "shrunk"); + } + var assembly = AssemblyDefinition.ReadAssembly (Path.Combine (libDir, dll)); var type = assembly.MainModule.FindType ("Lib1.Library1"); Assert.NotNull (type, "Should find Lib1.Library1!"); var cctor = type.GetTypeConstructor (); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/ArchiveAssemblyHelper.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/ArchiveAssemblyHelper.cs index 59b2b4e6fca..780a4612a14 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/ArchiveAssemblyHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/ArchiveAssemblyHelper.cs @@ -301,9 +301,13 @@ public int GetNumberOfAssemblies (bool forceRefresh = false, AndroidTargetArch a // We must count only .dll.so entries starting with the '-' and '_' characters, as they are the actual managed assemblies. // Other entries in `lib/{arch}` might be AOT shared libraries, which will also have the .dll.so extension. + // + // `.ni.dll.so` are all ignored, they're an artefact of how CoreCLR runtime works (it asks for .ni.dll for every .dll) and + // they are ignored on the runtime. They don't exist in the assembly store except for its index, where they are marked + // to be ignored. var dlls = contents.Where (x => { string fileName = Path.GetFileName (x); - if (!fileName.EndsWith (".dll.so", StringComparison.OrdinalIgnoreCase)) { + if (fileName.EndsWith (".ni.dll.so", StringComparison.OrdinalIgnoreCase) || !fileName.EndsWith (".dll.so", StringComparison.OrdinalIgnoreCase)) { return false; } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/EnvironmentHelper.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/EnvironmentHelper.cs index 7a86601ce43..df1fa6058f3 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/EnvironmentHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/EnvironmentHelper.cs @@ -36,8 +36,38 @@ public EnvironmentFile (string path, string abi) } } - // This must be identical to the like-named structure in src/native/xamarin-app-stub/xamarin-app.hh - public sealed class ApplicationConfig + public interface IApplicationConfig + {}; + + // This must be identical to the ApplicationConfig structure in src/native/clr/include/xamarin-app.hh + public sealed class ApplicationConfig_CoreCLR : IApplicationConfig + { + public bool uses_assembly_preload; + public bool jni_add_native_method_registration_attribute_present; + public bool marshal_methods_enabled; + public bool ignore_split_configs; + public uint number_of_runtime_properties; + public uint package_naming_policy; + public uint environment_variable_count; + public uint system_property_count; + public uint number_of_assemblies_in_apk; + public uint bundled_assembly_name_width; + public uint number_of_dso_cache_entries; + public uint number_of_aot_cache_entries; + public uint number_of_shared_libraries; + public uint android_runtime_jnienv_class_token; + public uint jnienv_initialize_method_token; + public uint jnienv_registerjninatives_method_token; + public uint jni_remapping_replacement_type_count; + public uint jni_remapping_replacement_method_index_entry_count; + public string android_package_name = String.Empty; + public bool managed_marshal_methods_lookup_enabled; + } + + const uint ApplicationConfigFieldCount_CoreCLR = 20; + + // This must be identical to the ApplicationConfig structure in src/native/mono/xamarin-app-stub/xamarin-app.hh + public sealed class ApplicationConfig_MonoVM : IApplicationConfig { public bool uses_mono_llvm; public bool uses_mono_aot; @@ -68,10 +98,11 @@ public sealed class ApplicationConfig public bool managed_marshal_methods_lookup_enabled; } - const uint ApplicationConfigFieldCount = 27; + const uint ApplicationConfigFieldCount_MonoVM = 27; const string ApplicationConfigSymbolName = "application_config"; const string AppEnvironmentVariablesSymbolName = "app_environment_variables"; + const string AppEnvironmentVariableContentsSymbolName = "app_environment_variable_contents"; static readonly object ndkInitLock = new object (); static readonly char[] readElfFieldSeparator = new [] { ' ', '\t' }; @@ -88,10 +119,11 @@ public sealed class ApplicationConfig ".long", }; - static readonly string[] requiredSharedLibrarySymbols = { + static readonly string[] requiredSharedLibrarySymbolsMonoVM = { AppEnvironmentVariablesSymbolName, "app_system_properties", ApplicationConfigSymbolName, + "format_tag", "map_modules", "map_module_count", "java_type_count", @@ -100,6 +132,22 @@ public sealed class ApplicationConfig "mono_aot_mode_name", }; + static readonly string[] requiredSharedLibrarySymbolsCoreCLR = { + "app_system_properties", + "app_system_property_contents", + "format_tag", + "java_to_managed_hashes", + "java_to_managed_map", + "java_type_count", + "managed_to_java_map", + "managed_to_java_map_module_count", + "runtime_properties", + "runtime_properties_data", + AppEnvironmentVariableContentsSymbolName, + AppEnvironmentVariablesSymbolName, + ApplicationConfigSymbolName, + }; + static readonly string executableExtension; static EnvironmentHelper () @@ -169,21 +217,167 @@ static string GetStringContents (NativeAssemblyParser.AssemblerSymbol symbol, En // Reads all the environment files, makes sure they all have identical contents in the // `application_config` structure and returns the config if the condition is true - public static ApplicationConfig ReadApplicationConfig (List envFilePaths) + public static IApplicationConfig ReadApplicationConfig (List envFilePaths, AndroidRuntime runtime) { if (envFilePaths.Count == 0) return null; - ApplicationConfig app_config = ReadApplicationConfig (envFilePaths [0]); + IApplicationConfig app_config = ReadApplicationConfig (envFilePaths [0], runtime); for (int i = 1; i < envFilePaths.Count; i++) { - AssertApplicationConfigIsIdentical (app_config, envFilePaths [0].Path, ReadApplicationConfig (envFilePaths[i]), envFilePaths[i].Path); + AssertApplicationConfigIsIdentical (app_config, envFilePaths [0].Path, ReadApplicationConfig (envFilePaths[i], runtime), envFilePaths[i].Path, runtime); } return app_config; } - static ApplicationConfig ReadApplicationConfig (EnvironmentFile envFile) + static IApplicationConfig ReadApplicationConfig (EnvironmentFile envFile, AndroidRuntime runtime) + { + return runtime switch { + AndroidRuntime.MonoVM => ReadApplicationConfig_MonoVM (envFile), + AndroidRuntime.CoreCLR => ReadApplicationConfig_CoreCLR (envFile), + _ => throw new InvalidOperationException ($"Unsupported runtime '{runtime}'") + }; + } + + static IApplicationConfig ReadApplicationConfig_CoreCLR (EnvironmentFile envFile) + { + NativeAssemblyParser parser = CreateAssemblyParser (envFile); + + if (!parser.Symbols.TryGetValue (ApplicationConfigSymbolName, out NativeAssemblyParser.AssemblerSymbol appConfigSymbol)) { + Assert.Fail ($"Symbol '{ApplicationConfigSymbolName}' not found in LLVM IR file '{envFile.Path}'"); + } + + Assert.IsTrue (appConfigSymbol.Size != 0, $"{ApplicationConfigSymbolName} size as specified in the '.size' directive must not be 0"); + + var pointers = new List (); + var ret = new ApplicationConfig_CoreCLR (); + uint fieldCount = 0; + string[] field; + + foreach (NativeAssemblyParser.AssemblerSymbolItem item in appConfigSymbol.Contents) { + field = GetField (envFile.Path, parser.SourceFilePath, item.Contents, item.LineNumber); + + if (String.Compare (".zero", field[0], StringComparison.Ordinal) == 0) { + continue; // padding, we can safely ignore it + } + + switch (fieldCount) { + case 0: // uses_assembly_preload: bool / .byte + AssertFieldType (envFile.Path, parser.SourceFilePath, ".byte", field [0], item.LineNumber); + ret.uses_assembly_preload = ConvertFieldToBool ("uses_assembly_preload", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); + break; + + case 1: // jni_add_native_method_registration_attribute_present: bool / .byte + AssertFieldType (envFile.Path, parser.SourceFilePath, ".byte", field [0], item.LineNumber); + ret.jni_add_native_method_registration_attribute_present = ConvertFieldToBool ("jni_add_native_method_registration_attribute_present", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); + break; + + case 2: // marshal_methods_enabled: bool / .byte + AssertFieldType (envFile.Path, parser.SourceFilePath, ".byte", field [0], item.LineNumber); + ret.marshal_methods_enabled = ConvertFieldToBool ("marshal_methods_enabled", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); + break; + + case 3: // ignore_split_configs: bool / .byte + AssertFieldType (envFile.Path, parser.SourceFilePath, ".byte", field [0], item.LineNumber); + ret.ignore_split_configs = ConvertFieldToBool ("ignore_split_configs", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); + break; + + case 4: // number_of_runtime_properties: uint32_t / .word | .long + Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); + ret.number_of_runtime_properties = ConvertFieldToByte ("number_of_runtime_properties", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); + break; + + case 5: // package_naming_policy: uint32_t / .word | .long + Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); + ret.package_naming_policy = ConvertFieldToUInt32 ("package_naming_policy", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); + break; + + case 6: // environment_variable_count: uint32_t / .word | .long + Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); + ret.environment_variable_count = ConvertFieldToUInt32 ("environment_variable_count", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); + break; + + case 7: // system_property_count: uint32_t / .word | .long + Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); + ret.system_property_count = ConvertFieldToUInt32 ("system_property_count", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); + break; + + case 8: // number_of_assemblies_in_apk: uint32_t / .word | .long + Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); + ret.number_of_assemblies_in_apk = ConvertFieldToUInt32 ("number_of_assemblies_in_apk", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); + break; + + case 9: // bundled_assembly_name_width: uint32_t / .word | .long + Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); + ret.bundled_assembly_name_width = ConvertFieldToUInt32 ("bundled_assembly_name_width", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); + break; + + case 10: // number_of_dso_cache_entries: uint32_t / .word | .long + Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); + ret.number_of_dso_cache_entries = ConvertFieldToUInt32 ("number_of_dso_cache_entries", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); + break; + + case 11: // number_of_aot_cache_entries: uint32_t / .word | .long + Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); + ret.number_of_aot_cache_entries = ConvertFieldToUInt32 ("number_of_aot_cache_entries", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); + break; + + case 12: // number_of_shared_libraries: uint32_t / .word | .long + Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); + ret.number_of_shared_libraries = ConvertFieldToUInt32 ("number_of_shared_libraries", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); + break; + + case 13: // android_runtime_jnienv_class_token: uint32_t / .word | .long + Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); + ret.android_runtime_jnienv_class_token = ConvertFieldToUInt32 ("android_runtime_jnienv_class_token", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); + break; + + case 14: // jnienv_initialize_method_token: uint32_t / .word | .long + Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); + ret.jnienv_initialize_method_token = ConvertFieldToUInt32 ("jnienv_initialize_method_token", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); + break; + + case 15: // jnienv_registerjninatives_method_token: uint32_t / .word | .long + Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); + ret.jnienv_registerjninatives_method_token = ConvertFieldToUInt32 ("jnienv_registerjninatives_method_token", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); + break; + + case 16: // jni_remapping_replacement_type_count: uint32_t / .word | .long + Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); + ret.jni_remapping_replacement_type_count = ConvertFieldToUInt32 ("jni_remapping_replacement_type_count", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); + break; + + case 17: // jni_remapping_replacement_method_index_entry_count: uint32_t / .word | .long + Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); + ret.jni_remapping_replacement_method_index_entry_count = ConvertFieldToUInt32 ("jni_remapping_replacement_method_index_entry_count", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); + break; + + case 18: // android_package_name: string / [pointer type] + Assert.IsTrue (expectedPointerTypes.Contains (field [0]), $"Unexpected pointer field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); + pointers.Add (field [1].Trim ()); + break; + + case 19: // managed_marshal_methods_lookup_enabled: bool / .byte + AssertFieldType (envFile.Path, parser.SourceFilePath, ".byte", field [0], item.LineNumber); + ret.managed_marshal_methods_lookup_enabled = ConvertFieldToBool ("managed_marshal_methods_lookup_enabled", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); + break; + } + fieldCount++; + } + + Assert.AreEqual (1, pointers.Count, $"Invalid number of string pointers in 'application_config' structure in environment file '{envFile.Path}'"); + + NativeAssemblyParser.AssemblerSymbol androidPackageNameSymbol = GetRequiredSymbol (pointers[0], envFile, parser); + ret.android_package_name = GetStringContents (androidPackageNameSymbol, envFile, parser); + + Assert.AreEqual (ApplicationConfigFieldCount_CoreCLR, fieldCount, $"Invalid 'application_config' field count in environment file '{envFile.Path}'"); + Assert.IsFalse (String.IsNullOrEmpty (ret.android_package_name), $"Package name field in 'application_config' in environment file '{envFile.Path}' must not be null or empty"); + + return ret; + } + + static IApplicationConfig ReadApplicationConfig_MonoVM (EnvironmentFile envFile) { NativeAssemblyParser parser = CreateAssemblyParser (envFile); @@ -194,7 +388,7 @@ static ApplicationConfig ReadApplicationConfig (EnvironmentFile envFile) Assert.IsTrue (appConfigSymbol.Size != 0, $"{ApplicationConfigSymbolName} size as specified in the '.size' directive must not be 0"); var pointers = new List (); - var ret = new ApplicationConfig (); + var ret = new ApplicationConfig_MonoVM (); uint fieldCount = 0; string[] field; @@ -350,7 +544,7 @@ static ApplicationConfig ReadApplicationConfig (EnvironmentFile envFile) NativeAssemblyParser.AssemblerSymbol androidPackageNameSymbol = GetRequiredSymbol (pointers[0], envFile, parser); ret.android_package_name = GetStringContents (androidPackageNameSymbol, envFile, parser); - Assert.AreEqual (ApplicationConfigFieldCount, fieldCount, $"Invalid 'application_config' field count in environment file '{envFile.Path}'"); + Assert.AreEqual (ApplicationConfigFieldCount_MonoVM, fieldCount, $"Invalid 'application_config' field count in environment file '{envFile.Path}'"); Assert.IsFalse (String.IsNullOrEmpty (ret.android_package_name), $"Package name field in 'application_config' in environment file '{envFile.Path}' must not be null or empty"); return ret; @@ -358,23 +552,111 @@ static ApplicationConfig ReadApplicationConfig (EnvironmentFile envFile) // Reads all the environment files, makes sure they contain the same environment variables (both count // and contents) and then returns a dictionary filled with the variables. - public static Dictionary ReadEnvironmentVariables (List envFilePaths) + public static Dictionary ReadEnvironmentVariables (List envFilePaths, AndroidRuntime runtime) { if (envFilePaths.Count == 0) return null; - Dictionary envvars = ReadEnvironmentVariables (envFilePaths [0]); + Dictionary envvars = ReadEnvironmentVariables (envFilePaths [0], runtime); if (envFilePaths.Count == 1) return envvars; for (int i = 1; i < envFilePaths.Count; i++) { - AssertDictionariesAreEqual (envvars, envFilePaths [0].Path, ReadEnvironmentVariables (envFilePaths[i]), envFilePaths[i].Path); + AssertDictionariesAreEqual (envvars, envFilePaths [0].Path, ReadEnvironmentVariables (envFilePaths[i], runtime), envFilePaths[i].Path); } return envvars; } - static Dictionary ReadEnvironmentVariables (EnvironmentFile envFile) + static Dictionary ReadEnvironmentVariables (EnvironmentFile envFile, AndroidRuntime runtime) + { + return runtime switch { + AndroidRuntime.MonoVM => ReadEnvironmentVariables_MonoVM (envFile), + AndroidRuntime.CoreCLR => ReadEnvironmentVariables_CoreCLR_NativeAOT (envFile), + AndroidRuntime.NativeAOT => ReadEnvironmentVariables_CoreCLR_NativeAOT (envFile), + _ => throw new InvalidOperationException ($"Unsupported runtime '{runtime}'") + }; + } + + static Dictionary ReadEnvironmentVariables_CoreCLR_NativeAOT (EnvironmentFile envFile) + { + NativeAssemblyParser parser = CreateAssemblyParser (envFile); + if (!parser.Symbols.TryGetValue (AppEnvironmentVariablesSymbolName, out NativeAssemblyParser.AssemblerSymbol appEnvvarsSymbol)) { + Assert.Fail ($"Symbol '{AppEnvironmentVariablesSymbolName}' not found in LLVM IR file '{envFile.Path}'"); + } + Assert.IsTrue (appEnvvarsSymbol.Size != 0, $"{AppEnvironmentVariablesSymbolName} size as specified in the '.size' directive must not be 0"); + Assert.IsTrue (appEnvvarsSymbol.Contents.Count % 2 == 0, $"{AppEnvironmentVariablesSymbolName} must contain an even number of items (contains {appEnvvarsSymbol.Contents.Count})"); + + if (!parser.Symbols.TryGetValue (AppEnvironmentVariableContentsSymbolName, out NativeAssemblyParser.AssemblerSymbol appEnvvarsContentsSymbol)) { + Assert.Fail ($"Symbol '{AppEnvironmentVariableContentsSymbolName}' not found in LLVM IR file '{envFile.Path}'"); + } + Assert.IsTrue (appEnvvarsContentsSymbol.Size != 0, $"{AppEnvironmentVariableContentsSymbolName} size as specified in the '.size' directive must not be 0"); + Assert.IsTrue (appEnvvarsContentsSymbol.Contents.Count == 1, $"{AppEnvironmentVariableContentsSymbolName} symbol must have a single value."); + + NativeAssemblyParser.AssemblerSymbolItem contentsItem = appEnvvarsContentsSymbol.Contents[0]; + string[] field = GetField (envFile.Path, parser.SourceFilePath, contentsItem.Contents, contentsItem.LineNumber);; + Assert.IsTrue (field[0] == ".asciz", $"{AppEnvironmentVariableContentsSymbolName} must be of '.asciz' type"); + + + var sb = new StringBuilder (); + // We need to get rid of the '"' delimiter llc outputs.. + sb.Append (field[1].Trim ('"')); + + // ...and llc outputs NUL as the octal '\000' sequence, we need an actual NUL... + sb.Replace ("\\000", "\0"); + + // ...and since it's an .asciz variable, the string doesn't contain explicit terminating NUL, but we need one + sb.Append ('\0'); + string contents = sb.ToString (); + var indexes = new List<(uint nameIdx, uint valueIdx)> (); + + // Environment variables are pairs of indexes into the contents array + for (int i = 0; i < appEnvvarsSymbol.Contents.Count; i += 2) { + NativeAssemblyParser.AssemblerSymbolItem varName = appEnvvarsSymbol.Contents[i]; + NativeAssemblyParser.AssemblerSymbolItem varValue = appEnvvarsSymbol.Contents[i + 1]; + + indexes.Add ((GetIndex (varName, "name"), GetIndex (varValue, "value"))); + } + + // Contents array is a collection of strings terminated with the NUL character + var ret = new Dictionary (StringComparer.Ordinal); + foreach (var envvar in indexes) { + Assert.IsTrue (envvar.nameIdx < appEnvvarsContentsSymbol.Size, $"Environment variable name index {envvar.nameIdx} is out of range of the contents array"); + Assert.IsTrue (envvar.valueIdx < appEnvvarsContentsSymbol.Size, $"Environment variable value index {envvar.valueIdx} is out of range of the contents array"); + + ret.Add (GetFromContents (envvar.nameIdx), GetFromContents (envvar.valueIdx)); + } + + return ret; + + uint GetIndex (NativeAssemblyParser.AssemblerSymbolItem item, string name) + { + // If the value is invalid, let it throw. This is by design. + + field = GetField (envFile.Path, parser.SourceFilePath, item.Contents, item.LineNumber); + Assert.IsTrue (expectedUInt32Types.Contains (field[0]), $"Environment variable {name} index field has invalid type '${field[0]}'"); + return UInt32.Parse (field[1], CultureInfo.InvariantCulture); + } + + string GetFromContents (uint idx) + { + var sb = new StringBuilder (); + bool foundNull = false; + + for (int i = (int)idx; i < contents.Length; i++) { + if (contents[i] == '\0') { + foundNull = true; + break; + } + sb.Append (contents[i]); + } + + Assert.IsTrue (foundNull, $"Environment variable contents string starting at index {idx} is not NUL-terminated"); + return sb.ToString (); + } + } + + static Dictionary ReadEnvironmentVariables_MonoVM (EnvironmentFile envFile) { NativeAssemblyParser parser = CreateAssemblyParser (envFile); @@ -436,7 +718,42 @@ static void AssertDictionariesAreEqual (Dictionary d1, string d } } - static void AssertApplicationConfigIsIdentical (ApplicationConfig firstAppConfig, string firstEnvFile, ApplicationConfig secondAppConfig, string secondEnvFile) + static void AssertApplicationConfigIsIdentical (IApplicationConfig firstAppConfig, string firstEnvFile, IApplicationConfig secondAppConfig, string secondEnvFile, AndroidRuntime runtime) + { + switch (runtime) { + case AndroidRuntime.MonoVM: + AssertApplicationConfigIsIdentical ( + (ApplicationConfig_MonoVM)firstAppConfig, + firstEnvFile, + (ApplicationConfig_MonoVM)secondAppConfig, + secondEnvFile + ); + break; + + case AndroidRuntime.CoreCLR: + AssertApplicationConfigIsIdentical ( + (ApplicationConfig_CoreCLR)firstAppConfig, + firstEnvFile, + (ApplicationConfig_CoreCLR)secondAppConfig, + secondEnvFile + ); + break; + + default: + throw new NotSupportedException ($"Unsupported runtime '{runtime}'"); + } + } + + static void AssertApplicationConfigIsIdentical (ApplicationConfig_CoreCLR firstAppConfig, string firstEnvFile, ApplicationConfig_CoreCLR secondAppConfig, string secondEnvFile) + { + Assert.AreEqual (firstAppConfig.uses_assembly_preload, secondAppConfig.uses_assembly_preload, $"Field 'uses_assembly_preload' has different value in environment file '{secondEnvFile}' than in environment file '{firstEnvFile}'"); + Assert.AreEqual (firstAppConfig.marshal_methods_enabled, secondAppConfig.marshal_methods_enabled, $"Field 'marshal_methods_enabled' has different value in environment file '{secondEnvFile}' than in environment file '{firstEnvFile}'"); + Assert.AreEqual (firstAppConfig.environment_variable_count, secondAppConfig.environment_variable_count, $"Field 'environment_variable_count' has different value in environment file '{secondEnvFile}' than in environment file '{firstEnvFile}'"); + Assert.AreEqual (firstAppConfig.system_property_count, secondAppConfig.system_property_count, $"Field 'system_property_count' has different value in environment file '{secondEnvFile}' than in environment file '{firstEnvFile}'"); + Assert.AreEqual (firstAppConfig.android_package_name, secondAppConfig.android_package_name, $"Field 'android_package_name' has different value in environment file '{secondEnvFile}' than in environment file '{firstEnvFile}'"); + } + + static void AssertApplicationConfigIsIdentical (ApplicationConfig_MonoVM firstAppConfig, string firstEnvFile, ApplicationConfig_MonoVM secondAppConfig, string secondEnvFile) { Assert.AreEqual (firstAppConfig.uses_mono_llvm, secondAppConfig.uses_mono_llvm, $"Field 'uses_mono_llvm' has different value in environment file '{secondEnvFile}' than in environment file '{firstEnvFile}'"); Assert.AreEqual (firstAppConfig.uses_mono_aot, secondAppConfig.uses_mono_aot, $"Field 'uses_mono_aot' has different value in environment file '{secondEnvFile}' than in environment file '{firstEnvFile}'"); @@ -462,7 +779,7 @@ public static List GatherEnvironmentFiles (string outputDirecto return environmentFiles; } - public static void AssertValidEnvironmentSharedLibrary (string outputDirectoryRoot, string sdkDirectory, string ndkDirectory, string supportedAbis) + public static void AssertValidEnvironmentSharedLibrary (string outputDirectoryRoot, string sdkDirectory, string ndkDirectory, string supportedAbis, AndroidRuntime runtime) { NdkTools ndk = NdkTools.Create (ndkDirectory); MonoAndroidHelper.AndroidSdk = new AndroidSdkInfo ((arg1, arg2) => {}, sdkDirectory, ndkDirectory, AndroidSdkResolver.GetJavaSdkPath ()); @@ -501,11 +818,18 @@ public static void AssertValidEnvironmentSharedLibrary (string outputDirectoryRo if (!File.Exists (readelf)) { readelf = ndk.GetToolPath ("llvm-readelf", arch, 0); } - AssertSharedLibraryHasRequiredSymbols (envSharedLibrary, readelf); + + string[] requiredSharedLibrarySymbols = runtime switch { + AndroidRuntime.MonoVM => requiredSharedLibrarySymbolsMonoVM, + AndroidRuntime.CoreCLR => requiredSharedLibrarySymbolsCoreCLR, + _ => throw new NotSupportedException ($"Unsupported runtime '{runtime}'") + }; + + AssertSharedLibraryHasRequiredSymbols (envSharedLibrary, readelf, requiredSharedLibrarySymbols); } } - static void AssertSharedLibraryHasRequiredSymbols (string dsoPath, string readElfPath) + static void AssertSharedLibraryHasRequiredSymbols (string dsoPath, string readElfPath, string[] requiredSharedLibrarySymbols) { (List stdout_lines, List _) = RunCommand (readElfPath, $"--dyn-syms \"{dsoPath}\""); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/ProjectExtensions.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/ProjectExtensions.cs index 0b08d64e54a..aacf34be9b1 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/ProjectExtensions.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/ProjectExtensions.cs @@ -7,21 +7,20 @@ public static class ProjectExtensions { /// /// Sets the appropriate MSBuild property to use a specific .NET runtime. - /// NOTE: $(EnablePreviewFeatures) ignores warning XA1040: The CoreCLR/NativeAOT runtime on Android is an experimental feature and not yet suitable for production use. + /// NOTE: $(EnablePreviewFeatures) ignores warning XA1040: The NativeAOT runtime on Android is an experimental feature and not yet suitable for production use. /// public static void SetRuntime (this XamarinProject project, AndroidRuntime runtime) { switch (runtime) { case AndroidRuntime.CoreCLR: project.SetProperty ("UseMonoRuntime", "false"); - project.SetProperty ("EnablePreviewFeatures", "true"); break; case AndroidRuntime.NativeAOT: project.SetProperty ("PublishAot", "true"); project.SetProperty ("EnablePreviewFeatures", "true"); break; default: - // MonoVM or default can just use default settings + project.SetProperty ("UseMonoRuntime", "true"); break; } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs index 9ecd121d354..8a7f1586103 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs @@ -240,7 +240,7 @@ public void DotNetPublish ([Values (false, true)] bool isRelease, [ValueSource(n Assert.Ignore ($"Test for API level {apiLevel} was skipped as it matched the default or latest stable API level."); var targetFramework = $"{dotnetVersion}-{platform}"; - const string runtimeIdentifier = "android-arm"; + const string runtimeIdentifier = "android-arm64"; var proj = new XamarinAndroidApplicationProject { TargetFramework = targetFramework, IsRelease = isRelease, diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.CoreCLR.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.CoreCLR.apkdesc new file mode 100644 index 00000000000..f9b95651b1b --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.CoreCLR.apkdesc @@ -0,0 +1,78 @@ +{ + "Comment": null, + "Entries": { + "AndroidManifest.xml": { + "Size": 3036 + }, + "classes.dex": { + "Size": 397616 + }, + "lib/arm64-v8a/libassemblies.arm64-v8a.blob.so": { + "Size": 3031896 + }, + "lib/arm64-v8a/libclrjit.so": { + "Size": 3191312 + }, + "lib/arm64-v8a/libcoreclr.so": { + "Size": 6213712 + }, + "lib/arm64-v8a/libmonodroid.so": { + "Size": 1369248 + }, + "lib/arm64-v8a/libmscordaccore.so": { + "Size": 2632624 + }, + "lib/arm64-v8a/libmscordbi.so": { + "Size": 1942040 + }, + "lib/arm64-v8a/libSystem.Globalization.Native.so": { + "Size": 71952 + }, + "lib/arm64-v8a/libSystem.IO.Compression.Native.so": { + "Size": 759304 + }, + "lib/arm64-v8a/libSystem.Native.so": { + "Size": 104112 + }, + "lib/arm64-v8a/libSystem.Security.Cryptography.Native.Android.so": { + "Size": 165568 + }, + "lib/arm64-v8a/libxamarin-app.so": { + "Size": 20088 + }, + "META-INF/BNDLTOOL.RSA": { + "Size": 1211 + }, + "META-INF/BNDLTOOL.SF": { + "Size": 2306 + }, + "META-INF/MANIFEST.MF": { + "Size": 2179 + }, + "res/drawable-hdpi-v4/icon.png": { + "Size": 2178 + }, + "res/drawable-mdpi-v4/icon.png": { + "Size": 1490 + }, + "res/drawable-xhdpi-v4/icon.png": { + "Size": 3098 + }, + "res/drawable-xxhdpi-v4/icon.png": { + "Size": 4674 + }, + "res/drawable-xxxhdpi-v4/icon.png": { + "Size": 6832 + }, + "res/layout/main.xml": { + "Size": 544 + }, + "res/xml/splits0.xml": { + "Size": 120 + }, + "resources.arsc": { + "Size": 1904 + } + }, + "PackageSize": 9107237 +} \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.MonoVM.apkdesc similarity index 85% rename from src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc rename to src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.MonoVM.apkdesc index 71b84b09cab..ddd6f0c76c3 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.MonoVM.apkdesc @@ -5,37 +5,37 @@ "Size": 3036 }, "classes.dex": { - "Size": 22428 + "Size": 22400 }, "lib/arm64-v8a/lib__Microsoft.Android.Resource.Designer.dll.so": { "Size": 18288 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 88048 + "Size": 95432 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 118224 + "Size": 121688 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 23488 + "Size": 23664 }, "lib/arm64-v8a/lib_System.Console.dll.so": { - "Size": 24408 + "Size": 24376 }, "lib/arm64-v8a/lib_System.Linq.dll.so": { - "Size": 25488 + "Size": 25456 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 629896 + "Size": 632776 }, "lib/arm64-v8a/lib_System.Runtime.dll.so": { "Size": 20144 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 21528 + "Size": 21496 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { - "Size": 20024 + "Size": 20176 }, "lib/arm64-v8a/libarc.bin.so": { "Size": 19112 @@ -44,10 +44,10 @@ "Size": 36616 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1401624 + "Size": 1386664 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3121008 + "Size": 3122432 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 71952 @@ -56,16 +56,16 @@ "Size": 759304 }, "lib/arm64-v8a/libSystem.Native.so": { - "Size": 104080 + "Size": 104112 }, "lib/arm64-v8a/libSystem.Security.Cryptography.Native.Android.so": { - "Size": 165288 + "Size": 165568 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 19952 + "Size": 19600 }, "META-INF/BNDLTOOL.RSA": { - "Size": 1223 + "Size": 1211 }, "META-INF/BNDLTOOL.SF": { "Size": 3266 @@ -98,5 +98,5 @@ "Size": 1904 } }, - "PackageSize": 3045909 + "PackageSize": 3054101 } \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.CoreCLR.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.CoreCLR.apkdesc new file mode 100644 index 00000000000..2f2c9239740 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.CoreCLR.apkdesc @@ -0,0 +1,2289 @@ +{ + "Comment": null, + "Entries": { + "AndroidManifest.xml": { + "Size": 6652 + }, + "classes.dex": { + "Size": 9449132 + }, + "classes2.dex": { + "Size": 156448 + }, + "kotlin/annotation/annotation.kotlin_builtins": { + "Size": 928 + }, + "kotlin/collections/collections.kotlin_builtins": { + "Size": 3685 + }, + "kotlin/coroutines/coroutines.kotlin_builtins": { + "Size": 200 + }, + "kotlin/internal/internal.kotlin_builtins": { + "Size": 646 + }, + "kotlin/kotlin.kotlin_builtins": { + "Size": 18640 + }, + "kotlin/ranges/ranges.kotlin_builtins": { + "Size": 3399 + }, + "kotlin/reflect/reflect.kotlin_builtins": { + "Size": 2396 + }, + "lib/arm64-v8a/libassemblies.arm64-v8a.blob.so": { + "Size": 13826528 + }, + "lib/arm64-v8a/libclrjit.so": { + "Size": 3191312 + }, + "lib/arm64-v8a/libcoreclr.so": { + "Size": 6213712 + }, + "lib/arm64-v8a/libmonodroid.so": { + "Size": 1369248 + }, + "lib/arm64-v8a/libmscordaccore.so": { + "Size": 2632624 + }, + "lib/arm64-v8a/libmscordbi.so": { + "Size": 1942040 + }, + "lib/arm64-v8a/libSystem.Globalization.Native.so": { + "Size": 71952 + }, + "lib/arm64-v8a/libSystem.IO.Compression.Native.so": { + "Size": 759304 + }, + "lib/arm64-v8a/libSystem.Native.so": { + "Size": 104112 + }, + "lib/arm64-v8a/libSystem.Security.Cryptography.Native.Android.so": { + "Size": 165568 + }, + "lib/arm64-v8a/libxamarin-app.so": { + "Size": 147176 + }, + "META-INF/androidx.activity_activity.version": { + "Size": 6 + }, + "META-INF/androidx.annotation_annotation-experimental.version": { + "Size": 6 + }, + "META-INF/androidx.appcompat_appcompat-resources.version": { + "Size": 6 + }, + "META-INF/androidx.appcompat_appcompat.version": { + "Size": 6 + }, + "META-INF/androidx.arch.core_core-runtime.version": { + "Size": 67 + }, + "META-INF/androidx.asynclayoutinflater_asynclayoutinflater.version": { + "Size": 6 + }, + "META-INF/androidx.browser_browser.version": { + "Size": 60 + }, + "META-INF/androidx.cardview_cardview.version": { + "Size": 6 + }, + "META-INF/androidx.coordinatorlayout_coordinatorlayout.version": { + "Size": 6 + }, + "META-INF/androidx.core_core-ktx.version": { + "Size": 6 + }, + "META-INF/androidx.core_core.version": { + "Size": 7 + }, + "META-INF/androidx.cursoradapter_cursoradapter.version": { + "Size": 6 + }, + "META-INF/androidx.customview_customview.version": { + "Size": 6 + }, + "META-INF/androidx.documentfile_documentfile.version": { + "Size": 6 + }, + "META-INF/androidx.drawerlayout_drawerlayout.version": { + "Size": 6 + }, + "META-INF/androidx.dynamicanimation_dynamicanimation.version": { + "Size": 6 + }, + "META-INF/androidx.emoji2_emoji2-views-helper.version": { + "Size": 6 + }, + "META-INF/androidx.emoji2_emoji2.version": { + "Size": 6 + }, + "META-INF/androidx.fragment_fragment.version": { + "Size": 6 + }, + "META-INF/androidx.interpolator_interpolator.version": { + "Size": 6 + }, + "META-INF/androidx.legacy_legacy-support-core-ui.version": { + "Size": 6 + }, + "META-INF/androidx.legacy_legacy-support-core-utils.version": { + "Size": 6 + }, + "META-INF/androidx.legacy_legacy-support-v4.version": { + "Size": 6 + }, + "META-INF/androidx.lifecycle_lifecycle-livedata-core.version": { + "Size": 6 + }, + "META-INF/androidx.lifecycle_lifecycle-livedata.version": { + "Size": 6 + }, + "META-INF/androidx.lifecycle_lifecycle-process.version": { + "Size": 6 + }, + "META-INF/androidx.lifecycle_lifecycle-runtime.version": { + "Size": 72 + }, + "META-INF/androidx.lifecycle_lifecycle-viewmodel-savedstate.version": { + "Size": 6 + }, + "META-INF/androidx.lifecycle_lifecycle-viewmodel.version": { + "Size": 6 + }, + "META-INF/androidx.loader_loader.version": { + "Size": 6 + }, + "META-INF/androidx.localbroadcastmanager_localbroadcastmanager.version": { + "Size": 6 + }, + "META-INF/androidx.media_media.version": { + "Size": 6 + }, + "META-INF/androidx.navigation_navigation-common.version": { + "Size": 6 + }, + "META-INF/androidx.navigation_navigation-runtime.version": { + "Size": 6 + }, + "META-INF/androidx.navigation_navigation-ui.version": { + "Size": 6 + }, + "META-INF/androidx.preference_preference.version": { + "Size": 6 + }, + "META-INF/androidx.print_print.version": { + "Size": 6 + }, + "META-INF/androidx.profileinstaller_profileinstaller.version": { + "Size": 6 + }, + "META-INF/androidx.recyclerview_recyclerview.version": { + "Size": 6 + }, + "META-INF/androidx.savedstate_savedstate.version": { + "Size": 6 + }, + "META-INF/androidx.slidingpanelayout_slidingpanelayout.version": { + "Size": 6 + }, + "META-INF/androidx.startup_startup-runtime.version": { + "Size": 6 + }, + "META-INF/androidx.swiperefreshlayout_swiperefreshlayout.version": { + "Size": 6 + }, + "META-INF/androidx.tracing_tracing.version": { + "Size": 6 + }, + "META-INF/androidx.transition_transition.version": { + "Size": 6 + }, + "META-INF/androidx.vectordrawable_vectordrawable-animated.version": { + "Size": 6 + }, + "META-INF/androidx.vectordrawable_vectordrawable.version": { + "Size": 6 + }, + "META-INF/androidx.versionedparcelable_versionedparcelable.version": { + "Size": 6 + }, + "META-INF/androidx.viewpager_viewpager.version": { + "Size": 6 + }, + "META-INF/androidx.viewpager2_viewpager2.version": { + "Size": 6 + }, + "META-INF/BNDLTOOL.RSA": { + "Size": 1211 + }, + "META-INF/BNDLTOOL.SF": { + "Size": 90357 + }, + "META-INF/com.android.tools/proguard/coroutines.pro": { + "Size": 1345 + }, + "META-INF/com.android.tools/r8-from-1.6.0/coroutines.pro": { + "Size": 899 + }, + "META-INF/com.android.tools/r8-upto-3.0.0/coroutines.pro": { + "Size": 558 + }, + "META-INF/com.android.tools/r8/coroutines.pro": { + "Size": 1190 + }, + "META-INF/com.google.android.material_material.version": { + "Size": 6 + }, + "META-INF/kotlin-project-structure-metadata.json": { + "Size": 552 + }, + "META-INF/kotlinx_coroutines_android.version": { + "Size": 5 + }, + "META-INF/kotlinx_coroutines_core.version": { + "Size": 5 + }, + "META-INF/MANIFEST.MF": { + "Size": 90230 + }, + "META-INF/maven/com.google.guava/listenablefuture/pom.properties": { + "Size": 96 + }, + "META-INF/maven/com.google.guava/listenablefuture/pom.xml": { + "Size": 2226 + }, + "META-INF/proguard/androidx-annotations.pro": { + "Size": 433 + }, + "META-INF/proguard/coroutines.pro": { + "Size": 1363 + }, + "META-INF/services/kotlinx.coroutines.CoroutineExceptionHandler": { + "Size": 54 + }, + "META-INF/services/kotlinx.coroutines.internal.MainDispatcherFactory": { + "Size": 52 + }, + "res/anim-v21/design_bottom_sheet_slide_in.xml": { + "Size": 616 + }, + "res/anim-v21/design_bottom_sheet_slide_out.xml": { + "Size": 616 + }, + "res/anim-v21/fragment_fast_out_extra_slow_in.xml": { + "Size": 364 + }, + "res/anim-v21/mtrl_bottom_sheet_slide_in.xml": { + "Size": 616 + }, + "res/anim-v21/mtrl_bottom_sheet_slide_out.xml": { + "Size": 616 + }, + "res/anim/abc_fade_in.xml": { + "Size": 388 + }, + "res/anim/abc_fade_out.xml": { + "Size": 388 + }, + "res/anim/abc_grow_fade_in_from_bottom.xml": { + "Size": 852 + }, + "res/anim/abc_popup_enter.xml": { + "Size": 508 + }, + "res/anim/abc_popup_exit.xml": { + "Size": 508 + }, + "res/anim/abc_shrink_fade_out_from_bottom.xml": { + "Size": 852 + }, + "res/anim/abc_slide_in_bottom.xml": { + "Size": 396 + }, + "res/anim/abc_slide_in_top.xml": { + "Size": 396 + }, + "res/anim/abc_slide_out_bottom.xml": { + "Size": 396 + }, + "res/anim/abc_slide_out_top.xml": { + "Size": 396 + }, + "res/anim/abc_tooltip_enter.xml": { + "Size": 388 + }, + "res/anim/abc_tooltip_exit.xml": { + "Size": 388 + }, + "res/anim/btn_checkbox_to_checked_box_inner_merged_animation.xml": { + "Size": 2124 + }, + "res/anim/btn_checkbox_to_checked_box_outer_merged_animation.xml": { + "Size": 2780 + }, + "res/anim/btn_checkbox_to_checked_icon_null_animation.xml": { + "Size": 1196 + }, + "res/anim/btn_checkbox_to_unchecked_box_inner_merged_animation.xml": { + "Size": 2360 + }, + "res/anim/btn_checkbox_to_unchecked_check_path_merged_animation.xml": { + "Size": 2520 + }, + "res/anim/btn_checkbox_to_unchecked_icon_null_animation.xml": { + "Size": 1196 + }, + "res/anim/btn_radio_to_off_mtrl_dot_group_animation.xml": { + "Size": 1656 + }, + "res/anim/btn_radio_to_off_mtrl_ring_outer_animation.xml": { + "Size": 1656 + }, + "res/anim/btn_radio_to_off_mtrl_ring_outer_path_animation.xml": { + "Size": 1028 + }, + "res/anim/btn_radio_to_on_mtrl_dot_group_animation.xml": { + "Size": 1656 + }, + "res/anim/btn_radio_to_on_mtrl_ring_outer_animation.xml": { + "Size": 1656 + }, + "res/anim/btn_radio_to_on_mtrl_ring_outer_path_animation.xml": { + "Size": 1028 + }, + "res/anim/design_snackbar_in.xml": { + "Size": 312 + }, + "res/anim/design_snackbar_out.xml": { + "Size": 312 + }, + "res/anim/enterfromleft.xml": { + "Size": 640 + }, + "res/anim/enterfromright.xml": { + "Size": 468 + }, + "res/anim/exittoleft.xml": { + "Size": 640 + }, + "res/anim/exittoright.xml": { + "Size": 468 + }, + "res/anim/mtrl_card_lowers_interpolator.xml": { + "Size": 400 + }, + "res/anim/nav_default_enter_anim.xml": { + "Size": 460 + }, + "res/anim/nav_default_exit_anim.xml": { + "Size": 460 + }, + "res/anim/nav_default_pop_enter_anim.xml": { + "Size": 460 + }, + "res/anim/nav_default_pop_exit_anim.xml": { + "Size": 460 + }, + "res/animator-v21/design_appbar_state_list_animator.xml": { + "Size": 1216 + }, + "res/animator/design_fab_hide_motion_spec.xml": { + "Size": 796 + }, + "res/animator/design_fab_show_motion_spec.xml": { + "Size": 796 + }, + "res/animator/fragment_close_enter.xml": { + "Size": 1128 + }, + "res/animator/fragment_close_exit.xml": { + "Size": 1128 + }, + "res/animator/fragment_fade_enter.xml": { + "Size": 452 + }, + "res/animator/fragment_fade_exit.xml": { + "Size": 452 + }, + "res/animator/fragment_open_enter.xml": { + "Size": 1128 + }, + "res/animator/fragment_open_exit.xml": { + "Size": 1128 + }, + "res/animator/linear_indeterminate_line1_head_interpolator.xml": { + "Size": 400 + }, + "res/animator/linear_indeterminate_line1_tail_interpolator.xml": { + "Size": 400 + }, + "res/animator/linear_indeterminate_line2_head_interpolator.xml": { + "Size": 400 + }, + "res/animator/linear_indeterminate_line2_tail_interpolator.xml": { + "Size": 400 + }, + "res/animator/mtrl_btn_state_list_anim.xml": { + "Size": 2664 + }, + "res/animator/mtrl_btn_unelevated_state_list_anim.xml": { + "Size": 120 + }, + "res/animator/mtrl_card_state_list_anim.xml": { + "Size": 1208 + }, + "res/animator/mtrl_chip_state_list_anim.xml": { + "Size": 1072 + }, + "res/animator/mtrl_extended_fab_change_size_collapse_motion_spec.xml": { + "Size": 1116 + }, + "res/animator/mtrl_extended_fab_change_size_expand_motion_spec.xml": { + "Size": 1116 + }, + "res/animator/mtrl_extended_fab_hide_motion_spec.xml": { + "Size": 608 + }, + "res/animator/mtrl_extended_fab_show_motion_spec.xml": { + "Size": 820 + }, + "res/animator/mtrl_extended_fab_state_list_animator.xml": { + "Size": 2724 + }, + "res/animator/mtrl_fab_hide_motion_spec.xml": { + "Size": 796 + }, + "res/animator/mtrl_fab_show_motion_spec.xml": { + "Size": 796 + }, + "res/animator/mtrl_fab_transformation_sheet_collapse_spec.xml": { + "Size": 1888 + }, + "res/animator/mtrl_fab_transformation_sheet_expand_spec.xml": { + "Size": 1888 + }, + "res/animator/nav_default_enter_anim.xml": { + "Size": 452 + }, + "res/animator/nav_default_exit_anim.xml": { + "Size": 452 + }, + "res/animator/nav_default_pop_enter_anim.xml": { + "Size": 452 + }, + "res/animator/nav_default_pop_exit_anim.xml": { + "Size": 452 + }, + "res/color-night-v8/material_timepicker_button_stroke.xml": { + "Size": 376 + }, + "res/color-night-v8/material_timepicker_clockface.xml": { + "Size": 376 + }, + "res/color-night-v8/material_timepicker_modebutton_tint.xml": { + "Size": 340 + }, + "res/color-v21/abc_btn_colored_borderless_text_material.xml": { + "Size": 464 + }, + "res/color-v23/abc_btn_colored_borderless_text_material.xml": { + "Size": 500 + }, + "res/color-v23/abc_btn_colored_text_material.xml": { + "Size": 500 + }, + "res/color-v23/abc_color_highlight_material.xml": { + "Size": 544 + }, + "res/color-v23/abc_tint_btn_checkable.xml": { + "Size": 624 + }, + "res/color-v23/abc_tint_default.xml": { + "Size": 1120 + }, + "res/color-v23/abc_tint_edittext.xml": { + "Size": 668 + }, + "res/color-v23/abc_tint_seek_thumb.xml": { + "Size": 500 + }, + "res/color-v23/abc_tint_spinner.xml": { + "Size": 668 + }, + "res/color-v23/abc_tint_switch_track.xml": { + "Size": 664 + }, + "res/color/abc_background_cache_hint_selector_material_dark.xml": { + "Size": 468 + }, + "res/color/abc_background_cache_hint_selector_material_light.xml": { + "Size": 468 + }, + "res/color/abc_btn_colored_text_material.xml": { + "Size": 604 + }, + "res/color/abc_hint_foreground_material_dark.xml": { + "Size": 564 + }, + "res/color/abc_hint_foreground_material_light.xml": { + "Size": 564 + }, + "res/color/abc_primary_text_disable_only_material_dark.xml": { + "Size": 464 + }, + "res/color/abc_primary_text_disable_only_material_light.xml": { + "Size": 464 + }, + "res/color/abc_primary_text_material_dark.xml": { + "Size": 464 + }, + "res/color/abc_primary_text_material_light.xml": { + "Size": 464 + }, + "res/color/abc_search_url_text.xml": { + "Size": 588 + }, + "res/color/abc_secondary_text_material_dark.xml": { + "Size": 464 + }, + "res/color/abc_secondary_text_material_light.xml": { + "Size": 464 + }, + "res/color/abc_tint_btn_checkable.xml": { + "Size": 728 + }, + "res/color/abc_tint_default.xml": { + "Size": 1224 + }, + "res/color/abc_tint_edittext.xml": { + "Size": 772 + }, + "res/color/abc_tint_seek_thumb.xml": { + "Size": 604 + }, + "res/color/abc_tint_spinner.xml": { + "Size": 772 + }, + "res/color/abc_tint_switch_track.xml": { + "Size": 768 + }, + "res/color/checkbox_themeable_attribute_color.xml": { + "Size": 464 + }, + "res/color/design_box_stroke_color.xml": { + "Size": 712 + }, + "res/color/design_error.xml": { + "Size": 464 + }, + "res/color/design_icon_tint.xml": { + "Size": 376 + }, + "res/color/material_cursor_color.xml": { + "Size": 340 + }, + "res/color/material_on_background_disabled.xml": { + "Size": 376 + }, + "res/color/material_on_background_emphasis_high_type.xml": { + "Size": 376 + }, + "res/color/material_on_background_emphasis_medium.xml": { + "Size": 376 + }, + "res/color/material_on_primary_disabled.xml": { + "Size": 376 + }, + "res/color/material_on_primary_emphasis_high_type.xml": { + "Size": 376 + }, + "res/color/material_on_primary_emphasis_medium.xml": { + "Size": 376 + }, + "res/color/material_on_surface_disabled.xml": { + "Size": 376 + }, + "res/color/material_on_surface_emphasis_high_type.xml": { + "Size": 376 + }, + "res/color/material_on_surface_emphasis_medium.xml": { + "Size": 376 + }, + "res/color/material_on_surface_stroke.xml": { + "Size": 376 + }, + "res/color/material_slider_active_tick_marks_color.xml": { + "Size": 520 + }, + "res/color/material_slider_active_track_color.xml": { + "Size": 500 + }, + "res/color/material_slider_halo_color.xml": { + "Size": 500 + }, + "res/color/material_slider_inactive_tick_marks_color.xml": { + "Size": 520 + }, + "res/color/material_slider_inactive_track_color.xml": { + "Size": 520 + }, + "res/color/material_slider_thumb_color.xml": { + "Size": 500 + }, + "res/color/material_timepicker_button_background.xml": { + "Size": 500 + }, + "res/color/material_timepicker_button_stroke.xml": { + "Size": 376 + }, + "res/color/material_timepicker_clock_text_color.xml": { + "Size": 464 + }, + "res/color/material_timepicker_clockface.xml": { + "Size": 376 + }, + "res/color/material_timepicker_modebutton_tint.xml": { + "Size": 376 + }, + "res/color/mtrl_btn_bg_color_selector.xml": { + "Size": 500 + }, + "res/color/mtrl_btn_ripple_color.xml": { + "Size": 948 + }, + "res/color/mtrl_btn_stroke_color_selector.xml": { + "Size": 520 + }, + "res/color/mtrl_btn_text_btn_bg_color_selector.xml": { + "Size": 520 + }, + "res/color/mtrl_btn_text_btn_ripple_color.xml": { + "Size": 948 + }, + "res/color/mtrl_btn_text_color_selector.xml": { + "Size": 500 + }, + "res/color/mtrl_calendar_item_stroke_color.xml": { + "Size": 808 + }, + "res/color/mtrl_calendar_selected_range.xml": { + "Size": 376 + }, + "res/color/mtrl_card_view_foreground.xml": { + "Size": 788 + }, + "res/color/mtrl_card_view_ripple.xml": { + "Size": 768 + }, + "res/color/mtrl_chip_background_color.xml": { + "Size": 848 + }, + "res/color/mtrl_chip_close_icon_tint.xml": { + "Size": 1092 + }, + "res/color/mtrl_chip_surface_color.xml": { + "Size": 340 + }, + "res/color/mtrl_chip_text_color.xml": { + "Size": 520 + }, + "res/color/mtrl_choice_chip_background_color.xml": { + "Size": 848 + }, + "res/color/mtrl_choice_chip_ripple_color.xml": { + "Size": 948 + }, + "res/color/mtrl_choice_chip_text_color.xml": { + "Size": 808 + }, + "res/color/mtrl_error.xml": { + "Size": 464 + }, + "res/color/mtrl_fab_bg_color_selector.xml": { + "Size": 500 + }, + "res/color/mtrl_fab_icon_text_color_selector.xml": { + "Size": 500 + }, + "res/color/mtrl_fab_ripple_color.xml": { + "Size": 948 + }, + "res/color/mtrl_filled_background_color.xml": { + "Size": 808 + }, + "res/color/mtrl_filled_icon_tint.xml": { + "Size": 644 + }, + "res/color/mtrl_filled_stroke_color.xml": { + "Size": 788 + }, + "res/color/mtrl_indicator_text_color.xml": { + "Size": 520 + }, + "res/color/mtrl_navigation_bar_colored_item_tint.xml": { + "Size": 520 + }, + "res/color/mtrl_navigation_bar_colored_ripple_color.xml": { + "Size": 948 + }, + "res/color/mtrl_navigation_bar_item_tint.xml": { + "Size": 520 + }, + "res/color/mtrl_navigation_bar_ripple_color.xml": { + "Size": 1672 + }, + "res/color/mtrl_navigation_item_background_color.xml": { + "Size": 644 + }, + "res/color/mtrl_navigation_item_icon_tint.xml": { + "Size": 624 + }, + "res/color/mtrl_navigation_item_text_color.xml": { + "Size": 624 + }, + "res/color/mtrl_on_primary_text_btn_text_color_selector.xml": { + "Size": 500 + }, + "res/color/mtrl_on_surface_ripple_color.xml": { + "Size": 808 + }, + "res/color/mtrl_outlined_icon_tint.xml": { + "Size": 644 + }, + "res/color/mtrl_outlined_stroke_color.xml": { + "Size": 788 + }, + "res/color/mtrl_popupmenu_overlay_color.xml": { + "Size": 376 + }, + "res/color/mtrl_tabs_colored_ripple_color.xml": { + "Size": 948 + }, + "res/color/mtrl_tabs_icon_color_selector_colored.xml": { + "Size": 500 + }, + "res/color/mtrl_tabs_icon_color_selector.xml": { + "Size": 500 + }, + "res/color/mtrl_tabs_legacy_text_color_selector.xml": { + "Size": 464 + }, + "res/color/mtrl_tabs_ripple_color.xml": { + "Size": 1672 + }, + "res/color/mtrl_text_btn_text_color_selector.xml": { + "Size": 888 + }, + "res/color/radiobutton_themeable_attribute_color.xml": { + "Size": 464 + }, + "res/color/switch_thumb_material_dark.xml": { + "Size": 464 + }, + "res/color/switch_thumb_material_light.xml": { + "Size": 464 + }, + "res/color/test_mtrl_calendar_day_selected.xml": { + "Size": 340 + }, + "res/color/test_mtrl_calendar_day.xml": { + "Size": 340 + }, + "res/drawable-anydpi-v21/ic_call_answer_low.xml": { + "Size": 1320 + }, + "res/drawable-anydpi-v21/ic_call_answer_video_low.xml": { + "Size": 736 + }, + "res/drawable-anydpi-v21/ic_call_answer_video.xml": { + "Size": 772 + }, + "res/drawable-anydpi-v21/ic_call_answer.xml": { + "Size": 1356 + }, + "res/drawable-anydpi-v21/ic_call_decline_low.xml": { + "Size": 1492 + }, + "res/drawable-anydpi-v21/ic_call_decline.xml": { + "Size": 1528 + }, + "res/drawable-hdpi-v4/abc_ab_share_pack_mtrl_alpha.9.png": { + "Size": 272 + }, + "res/drawable-hdpi-v4/abc_btn_check_to_on_mtrl_000.png": { + "Size": 227 + }, + "res/drawable-hdpi-v4/abc_btn_check_to_on_mtrl_015.png": { + "Size": 404 + }, + "res/drawable-hdpi-v4/abc_btn_radio_to_on_mtrl_000.png": { + "Size": 464 + }, + "res/drawable-hdpi-v4/abc_btn_radio_to_on_mtrl_015.png": { + "Size": 563 + }, + "res/drawable-hdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png": { + "Size": 1096 + }, + "res/drawable-hdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png": { + "Size": 1243 + }, + "res/drawable-hdpi-v4/abc_cab_background_top_mtrl_alpha.9.png": { + "Size": 226 + }, + "res/drawable-hdpi-v4/abc_ic_commit_search_api_mtrl_alpha.png": { + "Size": 171 + }, + "res/drawable-hdpi-v4/abc_list_divider_mtrl_alpha.9.png": { + "Size": 167 + }, + "res/drawable-hdpi-v4/abc_list_focused_holo.9.png": { + "Size": 244 + }, + "res/drawable-hdpi-v4/abc_list_longpressed_holo.9.png": { + "Size": 212 + }, + "res/drawable-hdpi-v4/abc_list_pressed_holo_dark.9.png": { + "Size": 208 + }, + "res/drawable-hdpi-v4/abc_list_pressed_holo_light.9.png": { + "Size": 208 + }, + "res/drawable-hdpi-v4/abc_list_selector_disabled_holo_dark.9.png": { + "Size": 228 + }, + "res/drawable-hdpi-v4/abc_list_selector_disabled_holo_light.9.png": { + "Size": 229 + }, + "res/drawable-hdpi-v4/abc_menu_hardkey_panel_mtrl_mult.9.png": { + "Size": 738 + }, + "res/drawable-hdpi-v4/abc_popup_background_mtrl_mult.9.png": { + "Size": 1098 + }, + "res/drawable-hdpi-v4/abc_scrubber_control_off_mtrl_alpha.png": { + "Size": 201 + }, + "res/drawable-hdpi-v4/abc_scrubber_control_to_pressed_mtrl_000.png": { + "Size": 196 + }, + "res/drawable-hdpi-v4/abc_scrubber_control_to_pressed_mtrl_005.png": { + "Size": 272 + }, + "res/drawable-hdpi-v4/abc_scrubber_primary_mtrl_alpha.9.png": { + "Size": 205 + }, + "res/drawable-hdpi-v4/abc_scrubber_track_mtrl_alpha.9.png": { + "Size": 196 + }, + "res/drawable-hdpi-v4/abc_spinner_mtrl_am_alpha.9.png": { + "Size": 345 + }, + "res/drawable-hdpi-v4/abc_switch_track_mtrl_alpha.9.png": { + "Size": 484 + }, + "res/drawable-hdpi-v4/abc_tab_indicator_mtrl_alpha.9.png": { + "Size": 190 + }, + "res/drawable-hdpi-v4/abc_text_select_handle_left_mtrl.png": { + "Size": 278 + }, + "res/drawable-hdpi-v4/abc_text_select_handle_middle_mtrl.png": { + "Size": 396 + }, + "res/drawable-hdpi-v4/abc_text_select_handle_right_mtrl.png": { + "Size": 262 + }, + "res/drawable-hdpi-v4/abc_textfield_activated_mtrl_alpha.9.png": { + "Size": 186 + }, + "res/drawable-hdpi-v4/abc_textfield_default_mtrl_alpha.9.png": { + "Size": 192 + }, + "res/drawable-hdpi-v4/abc_textfield_search_activated_mtrl_alpha.9.png": { + "Size": 178 + }, + "res/drawable-hdpi-v4/abc_textfield_search_default_mtrl_alpha.9.png": { + "Size": 178 + }, + "res/drawable-hdpi-v4/ic_call_answer_low.png": { + "Size": 472 + }, + "res/drawable-hdpi-v4/ic_call_answer_video_low.png": { + "Size": 254 + }, + "res/drawable-hdpi-v4/ic_call_answer_video.png": { + "Size": 254 + }, + "res/drawable-hdpi-v4/ic_call_answer.png": { + "Size": 472 + }, + "res/drawable-hdpi-v4/ic_call_decline_low.png": { + "Size": 375 + }, + "res/drawable-hdpi-v4/ic_call_decline.png": { + "Size": 375 + }, + "res/drawable-hdpi-v4/icon.png": { + "Size": 2178 + }, + "res/drawable-hdpi-v4/notification_bg_low_normal.9.png": { + "Size": 212 + }, + "res/drawable-hdpi-v4/notification_bg_low_pressed.9.png": { + "Size": 225 + }, + "res/drawable-hdpi-v4/notification_bg_normal_pressed.9.png": { + "Size": 225 + }, + "res/drawable-hdpi-v4/notification_bg_normal.9.png": { + "Size": 212 + }, + "res/drawable-hdpi-v4/notify_panel_notification_icon_bg.png": { + "Size": 107 + }, + "res/drawable-ldpi-v4/ic_call_answer_low.png": { + "Size": 270 + }, + "res/drawable-ldpi-v4/ic_call_answer_video_low.png": { + "Size": 199 + }, + "res/drawable-ldpi-v4/ic_call_answer_video.png": { + "Size": 199 + }, + "res/drawable-ldpi-v4/ic_call_answer.png": { + "Size": 270 + }, + "res/drawable-ldpi-v4/ic_call_decline_low.png": { + "Size": 201 + }, + "res/drawable-ldpi-v4/ic_call_decline.png": { + "Size": 201 + }, + "res/drawable-ldrtl-hdpi-v17/abc_spinner_mtrl_am_alpha.9.png": { + "Size": 345 + }, + "res/drawable-ldrtl-mdpi-v17/abc_spinner_mtrl_am_alpha.9.png": { + "Size": 318 + }, + "res/drawable-ldrtl-xhdpi-v17/abc_spinner_mtrl_am_alpha.9.png": { + "Size": 417 + }, + "res/drawable-ldrtl-xxhdpi-v17/abc_spinner_mtrl_am_alpha.9.png": { + "Size": 525 + }, + "res/drawable-ldrtl-xxxhdpi-v17/abc_spinner_mtrl_am_alpha.9.png": { + "Size": 437 + }, + "res/drawable-mdpi-v4/abc_ab_share_pack_mtrl_alpha.9.png": { + "Size": 267 + }, + "res/drawable-mdpi-v4/abc_btn_check_to_on_mtrl_000.png": { + "Size": 214 + }, + "res/drawable-mdpi-v4/abc_btn_check_to_on_mtrl_015.png": { + "Size": 321 + }, + "res/drawable-mdpi-v4/abc_btn_radio_to_on_mtrl_000.png": { + "Size": 324 + }, + "res/drawable-mdpi-v4/abc_btn_radio_to_on_mtrl_015.png": { + "Size": 356 + }, + "res/drawable-mdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png": { + "Size": 754 + }, + "res/drawable-mdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png": { + "Size": 825 + }, + "res/drawable-mdpi-v4/abc_cab_background_top_mtrl_alpha.9.png": { + "Size": 216 + }, + "res/drawable-mdpi-v4/abc_ic_commit_search_api_mtrl_alpha.png": { + "Size": 173 + }, + "res/drawable-mdpi-v4/abc_list_divider_mtrl_alpha.9.png": { + "Size": 167 + }, + "res/drawable-mdpi-v4/abc_list_focused_holo.9.png": { + "Size": 222 + }, + "res/drawable-mdpi-v4/abc_list_longpressed_holo.9.png": { + "Size": 211 + }, + "res/drawable-mdpi-v4/abc_list_pressed_holo_dark.9.png": { + "Size": 207 + }, + "res/drawable-mdpi-v4/abc_list_pressed_holo_light.9.png": { + "Size": 207 + }, + "res/drawable-mdpi-v4/abc_list_selector_disabled_holo_dark.9.png": { + "Size": 217 + }, + "res/drawable-mdpi-v4/abc_list_selector_disabled_holo_light.9.png": { + "Size": 217 + }, + "res/drawable-mdpi-v4/abc_menu_hardkey_panel_mtrl_mult.9.png": { + "Size": 541 + }, + "res/drawable-mdpi-v4/abc_popup_background_mtrl_mult.9.png": { + "Size": 776 + }, + "res/drawable-mdpi-v4/abc_scrubber_control_off_mtrl_alpha.png": { + "Size": 159 + }, + "res/drawable-mdpi-v4/abc_scrubber_control_to_pressed_mtrl_000.png": { + "Size": 145 + }, + "res/drawable-mdpi-v4/abc_scrubber_control_to_pressed_mtrl_005.png": { + "Size": 197 + }, + "res/drawable-mdpi-v4/abc_scrubber_primary_mtrl_alpha.9.png": { + "Size": 203 + }, + "res/drawable-mdpi-v4/abc_scrubber_track_mtrl_alpha.9.png": { + "Size": 194 + }, + "res/drawable-mdpi-v4/abc_spinner_mtrl_am_alpha.9.png": { + "Size": 327 + }, + "res/drawable-mdpi-v4/abc_switch_track_mtrl_alpha.9.png": { + "Size": 395 + }, + "res/drawable-mdpi-v4/abc_tab_indicator_mtrl_alpha.9.png": { + "Size": 186 + }, + "res/drawable-mdpi-v4/abc_text_select_handle_left_mtrl.png": { + "Size": 203 + }, + "res/drawable-mdpi-v4/abc_text_select_handle_middle_mtrl.png": { + "Size": 310 + }, + "res/drawable-mdpi-v4/abc_text_select_handle_right_mtrl.png": { + "Size": 186 + }, + "res/drawable-mdpi-v4/abc_textfield_activated_mtrl_alpha.9.png": { + "Size": 181 + }, + "res/drawable-mdpi-v4/abc_textfield_default_mtrl_alpha.9.png": { + "Size": 178 + }, + "res/drawable-mdpi-v4/abc_textfield_search_activated_mtrl_alpha.9.png": { + "Size": 178 + }, + "res/drawable-mdpi-v4/abc_textfield_search_default_mtrl_alpha.9.png": { + "Size": 178 + }, + "res/drawable-mdpi-v4/ic_call_answer_low.png": { + "Size": 317 + }, + "res/drawable-mdpi-v4/ic_call_answer_video_low.png": { + "Size": 206 + }, + "res/drawable-mdpi-v4/ic_call_answer_video.png": { + "Size": 206 + }, + "res/drawable-mdpi-v4/ic_call_answer.png": { + "Size": 317 + }, + "res/drawable-mdpi-v4/ic_call_decline_low.png": { + "Size": 264 + }, + "res/drawable-mdpi-v4/ic_call_decline.png": { + "Size": 264 + }, + "res/drawable-mdpi-v4/icon.png": { + "Size": 1490 + }, + "res/drawable-mdpi-v4/notification_bg_low_normal.9.png": { + "Size": 215 + }, + "res/drawable-mdpi-v4/notification_bg_low_pressed.9.png": { + "Size": 223 + }, + "res/drawable-mdpi-v4/notification_bg_normal_pressed.9.png": { + "Size": 223 + }, + "res/drawable-mdpi-v4/notification_bg_normal.9.png": { + "Size": 215 + }, + "res/drawable-mdpi-v4/notify_panel_notification_icon_bg.png": { + "Size": 98 + }, + "res/drawable-v21/abc_action_bar_item_background_material.xml": { + "Size": 264 + }, + "res/drawable-v21/abc_btn_colored_material.xml": { + "Size": 1716 + }, + "res/drawable-v21/abc_dialog_material_background.xml": { + "Size": 716 + }, + "res/drawable-v21/abc_edit_text_material.xml": { + "Size": 1172 + }, + "res/drawable-v21/abc_list_divider_material.xml": { + "Size": 516 + }, + "res/drawable-v21/ic_arrow_down_24dp.xml": { + "Size": 644 + }, + "res/drawable-v21/material_cursor_drawable.xml": { + "Size": 588 + }, + "res/drawable-v21/mtrl_navigation_bar_item_background.xml": { + "Size": 264 + }, + "res/drawable-v21/notification_action_background.xml": { + "Size": 1180 + }, + "res/drawable-v21/preference_list_divider_material.xml": { + "Size": 516 + }, + "res/drawable-v23/abc_control_background_material.xml": { + "Size": 304 + }, + "res/drawable-v23/mtrl_popupmenu_background_dark.xml": { + "Size": 1228 + }, + "res/drawable-watch-v20/abc_dialog_material_background.xml": { + "Size": 372 + }, + "res/drawable-xhdpi-v4/abc_ab_share_pack_mtrl_alpha.9.png": { + "Size": 280 + }, + "res/drawable-xhdpi-v4/abc_btn_check_to_on_mtrl_000.png": { + "Size": 281 + }, + "res/drawable-xhdpi-v4/abc_btn_check_to_on_mtrl_015.png": { + "Size": 432 + }, + "res/drawable-xhdpi-v4/abc_btn_radio_to_on_mtrl_000.png": { + "Size": 651 + }, + "res/drawable-xhdpi-v4/abc_btn_radio_to_on_mtrl_015.png": { + "Size": 785 + }, + "res/drawable-xhdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png": { + "Size": 1526 + }, + "res/drawable-xhdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png": { + "Size": 1731 + }, + "res/drawable-xhdpi-v4/abc_cab_background_top_mtrl_alpha.9.png": { + "Size": 229 + }, + "res/drawable-xhdpi-v4/abc_ic_commit_search_api_mtrl_alpha.png": { + "Size": 228 + }, + "res/drawable-xhdpi-v4/abc_list_divider_mtrl_alpha.9.png": { + "Size": 167 + }, + "res/drawable-xhdpi-v4/abc_list_focused_holo.9.png": { + "Size": 244 + }, + "res/drawable-xhdpi-v4/abc_list_longpressed_holo.9.png": { + "Size": 214 + }, + "res/drawable-xhdpi-v4/abc_list_pressed_holo_dark.9.png": { + "Size": 209 + }, + "res/drawable-xhdpi-v4/abc_list_pressed_holo_light.9.png": { + "Size": 209 + }, + "res/drawable-xhdpi-v4/abc_list_selector_disabled_holo_dark.9.png": { + "Size": 236 + }, + "res/drawable-xhdpi-v4/abc_list_selector_disabled_holo_light.9.png": { + "Size": 235 + }, + "res/drawable-xhdpi-v4/abc_menu_hardkey_panel_mtrl_mult.9.png": { + "Size": 966 + }, + "res/drawable-xhdpi-v4/abc_popup_background_mtrl_mult.9.png": { + "Size": 1544 + }, + "res/drawable-xhdpi-v4/abc_scrubber_control_off_mtrl_alpha.png": { + "Size": 267 + }, + "res/drawable-xhdpi-v4/abc_scrubber_control_to_pressed_mtrl_000.png": { + "Size": 267 + }, + "res/drawable-xhdpi-v4/abc_scrubber_control_to_pressed_mtrl_005.png": { + "Size": 391 + }, + "res/drawable-xhdpi-v4/abc_scrubber_primary_mtrl_alpha.9.png": { + "Size": 208 + }, + "res/drawable-xhdpi-v4/abc_scrubber_track_mtrl_alpha.9.png": { + "Size": 198 + }, + "res/drawable-xhdpi-v4/abc_spinner_mtrl_am_alpha.9.png": { + "Size": 448 + }, + "res/drawable-xhdpi-v4/abc_switch_track_mtrl_alpha.9.png": { + "Size": 618 + }, + "res/drawable-xhdpi-v4/abc_tab_indicator_mtrl_alpha.9.png": { + "Size": 194 + }, + "res/drawable-xhdpi-v4/abc_text_select_handle_left_mtrl.png": { + "Size": 335 + }, + "res/drawable-xhdpi-v4/abc_text_select_handle_middle_mtrl.png": { + "Size": 585 + }, + "res/drawable-xhdpi-v4/abc_text_select_handle_right_mtrl.png": { + "Size": 318 + }, + "res/drawable-xhdpi-v4/abc_textfield_activated_mtrl_alpha.9.png": { + "Size": 189 + }, + "res/drawable-xhdpi-v4/abc_textfield_default_mtrl_alpha.9.png": { + "Size": 187 + }, + "res/drawable-xhdpi-v4/abc_textfield_search_activated_mtrl_alpha.9.png": { + "Size": 184 + }, + "res/drawable-xhdpi-v4/abc_textfield_search_default_mtrl_alpha.9.png": { + "Size": 182 + }, + "res/drawable-xhdpi-v4/ic_call_answer_low.png": { + "Size": 623 + }, + "res/drawable-xhdpi-v4/ic_call_answer_video_low.png": { + "Size": 290 + }, + "res/drawable-xhdpi-v4/ic_call_answer_video.png": { + "Size": 290 + }, + "res/drawable-xhdpi-v4/ic_call_answer.png": { + "Size": 623 + }, + "res/drawable-xhdpi-v4/ic_call_decline_low.png": { + "Size": 452 + }, + "res/drawable-xhdpi-v4/ic_call_decline.png": { + "Size": 452 + }, + "res/drawable-xhdpi-v4/icon.png": { + "Size": 3098 + }, + "res/drawable-xhdpi-v4/notification_bg_low_normal.9.png": { + "Size": 221 + }, + "res/drawable-xhdpi-v4/notification_bg_low_pressed.9.png": { + "Size": 252 + }, + "res/drawable-xhdpi-v4/notification_bg_normal_pressed.9.png": { + "Size": 247 + }, + "res/drawable-xhdpi-v4/notification_bg_normal.9.png": { + "Size": 221 + }, + "res/drawable-xhdpi-v4/notify_panel_notification_icon_bg.png": { + "Size": 138 + }, + "res/drawable-xxhdpi-v4/abc_ab_share_pack_mtrl_alpha.9.png": { + "Size": 286 + }, + "res/drawable-xxhdpi-v4/abc_btn_check_to_on_mtrl_000.png": { + "Size": 307 + }, + "res/drawable-xxhdpi-v4/abc_btn_check_to_on_mtrl_015.png": { + "Size": 593 + }, + "res/drawable-xxhdpi-v4/abc_btn_radio_to_on_mtrl_000.png": { + "Size": 984 + }, + "res/drawable-xxhdpi-v4/abc_btn_radio_to_on_mtrl_015.png": { + "Size": 1208 + }, + "res/drawable-xxhdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png": { + "Size": 2463 + }, + "res/drawable-xxhdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png": { + "Size": 2834 + }, + "res/drawable-xxhdpi-v4/abc_cab_background_top_mtrl_alpha.9.png": { + "Size": 237 + }, + "res/drawable-xxhdpi-v4/abc_ic_commit_search_api_mtrl_alpha.png": { + "Size": 224 + }, + "res/drawable-xxhdpi-v4/abc_list_divider_mtrl_alpha.9.png": { + "Size": 171 + }, + "res/drawable-xxhdpi-v4/abc_list_focused_holo.9.png": { + "Size": 245 + }, + "res/drawable-xxhdpi-v4/abc_list_longpressed_holo.9.png": { + "Size": 221 + }, + "res/drawable-xxhdpi-v4/abc_list_pressed_holo_dark.9.png": { + "Size": 212 + }, + "res/drawable-xxhdpi-v4/abc_list_pressed_holo_light.9.png": { + "Size": 212 + }, + "res/drawable-xxhdpi-v4/abc_list_selector_disabled_holo_dark.9.png": { + "Size": 260 + }, + "res/drawable-xxhdpi-v4/abc_list_selector_disabled_holo_light.9.png": { + "Size": 258 + }, + "res/drawable-xxhdpi-v4/abc_menu_hardkey_panel_mtrl_mult.9.png": { + "Size": 1779 + }, + "res/drawable-xxhdpi-v4/abc_popup_background_mtrl_mult.9.png": { + "Size": 2305 + }, + "res/drawable-xxhdpi-v4/abc_scrubber_control_off_mtrl_alpha.png": { + "Size": 322 + }, + "res/drawable-xxhdpi-v4/abc_scrubber_control_to_pressed_mtrl_000.png": { + "Size": 403 + }, + "res/drawable-xxhdpi-v4/abc_scrubber_control_to_pressed_mtrl_005.png": { + "Size": 595 + }, + "res/drawable-xxhdpi-v4/abc_scrubber_primary_mtrl_alpha.9.png": { + "Size": 210 + }, + "res/drawable-xxhdpi-v4/abc_scrubber_track_mtrl_alpha.9.png": { + "Size": 207 + }, + "res/drawable-xxhdpi-v4/abc_spinner_mtrl_am_alpha.9.png": { + "Size": 524 + }, + "res/drawable-xxhdpi-v4/abc_switch_track_mtrl_alpha.9.png": { + "Size": 851 + }, + "res/drawable-xxhdpi-v4/abc_tab_indicator_mtrl_alpha.9.png": { + "Size": 204 + }, + "res/drawable-xxhdpi-v4/abc_text_select_handle_left_mtrl.png": { + "Size": 420 + }, + "res/drawable-xxhdpi-v4/abc_text_select_handle_middle_mtrl.png": { + "Size": 753 + }, + "res/drawable-xxhdpi-v4/abc_text_select_handle_right_mtrl.png": { + "Size": 422 + }, + "res/drawable-xxhdpi-v4/abc_textfield_activated_mtrl_alpha.9.png": { + "Size": 199 + }, + "res/drawable-xxhdpi-v4/abc_textfield_default_mtrl_alpha.9.png": { + "Size": 200 + }, + "res/drawable-xxhdpi-v4/abc_textfield_search_activated_mtrl_alpha.9.png": { + "Size": 187 + }, + "res/drawable-xxhdpi-v4/abc_textfield_search_default_mtrl_alpha.9.png": { + "Size": 186 + }, + "res/drawable-xxhdpi-v4/ic_call_answer_low.png": { + "Size": 884 + }, + "res/drawable-xxhdpi-v4/ic_call_answer_video_low.png": { + "Size": 384 + }, + "res/drawable-xxhdpi-v4/ic_call_answer_video.png": { + "Size": 384 + }, + "res/drawable-xxhdpi-v4/ic_call_answer.png": { + "Size": 884 + }, + "res/drawable-xxhdpi-v4/ic_call_decline_low.png": { + "Size": 628 + }, + "res/drawable-xxhdpi-v4/ic_call_decline.png": { + "Size": 628 + }, + "res/drawable-xxhdpi-v4/icon.png": { + "Size": 4674 + }, + "res/drawable-xxxhdpi-v4/abc_btn_check_to_on_mtrl_000.png": { + "Size": 275 + }, + "res/drawable-xxxhdpi-v4/abc_btn_check_to_on_mtrl_015.png": { + "Size": 476 + }, + "res/drawable-xxxhdpi-v4/abc_btn_radio_to_on_mtrl_000.png": { + "Size": 785 + }, + "res/drawable-xxxhdpi-v4/abc_btn_radio_to_on_mtrl_015.png": { + "Size": 946 + }, + "res/drawable-xxxhdpi-v4/abc_btn_switch_to_on_mtrl_00001.9.png": { + "Size": 2505 + }, + "res/drawable-xxxhdpi-v4/abc_btn_switch_to_on_mtrl_00012.9.png": { + "Size": 2816 + }, + "res/drawable-xxxhdpi-v4/abc_scrubber_control_to_pressed_mtrl_000.png": { + "Size": 415 + }, + "res/drawable-xxxhdpi-v4/abc_scrubber_control_to_pressed_mtrl_005.png": { + "Size": 631 + }, + "res/drawable-xxxhdpi-v4/abc_spinner_mtrl_am_alpha.9.png": { + "Size": 430 + }, + "res/drawable-xxxhdpi-v4/abc_switch_track_mtrl_alpha.9.png": { + "Size": 813 + }, + "res/drawable-xxxhdpi-v4/abc_tab_indicator_mtrl_alpha.9.png": { + "Size": 202 + }, + "res/drawable-xxxhdpi-v4/abc_text_select_handle_left_mtrl.png": { + "Size": 513 + }, + "res/drawable-xxxhdpi-v4/abc_text_select_handle_right_mtrl.png": { + "Size": 513 + }, + "res/drawable-xxxhdpi-v4/ic_call_answer_low.png": { + "Size": 1171 + }, + "res/drawable-xxxhdpi-v4/ic_call_answer_video_low.png": { + "Size": 465 + }, + "res/drawable-xxxhdpi-v4/ic_call_answer_video.png": { + "Size": 465 + }, + "res/drawable-xxxhdpi-v4/ic_call_answer.png": { + "Size": 1171 + }, + "res/drawable-xxxhdpi-v4/ic_call_decline_low.png": { + "Size": 823 + }, + "res/drawable-xxxhdpi-v4/ic_call_decline.png": { + "Size": 823 + }, + "res/drawable-xxxhdpi-v4/icon.png": { + "Size": 6832 + }, + "res/drawable/$avd_hide_password__0.xml": { + "Size": 1176 + }, + "res/drawable/$avd_hide_password__1.xml": { + "Size": 592 + }, + "res/drawable/$avd_hide_password__2.xml": { + "Size": 556 + }, + "res/drawable/$avd_show_password__0.xml": { + "Size": 1136 + }, + "res/drawable/$avd_show_password__1.xml": { + "Size": 592 + }, + "res/drawable/$avd_show_password__2.xml": { + "Size": 556 + }, + "res/drawable/abc_btn_borderless_material.xml": { + "Size": 588 + }, + "res/drawable/abc_btn_check_material_anim.xml": { + "Size": 816 + }, + "res/drawable/abc_btn_check_material.xml": { + "Size": 464 + }, + "res/drawable/abc_btn_default_mtrl_shape.xml": { + "Size": 932 + }, + "res/drawable/abc_btn_radio_material_anim.xml": { + "Size": 816 + }, + "res/drawable/abc_btn_radio_material.xml": { + "Size": 464 + }, + "res/drawable/abc_cab_background_internal_bg.xml": { + "Size": 372 + }, + "res/drawable/abc_cab_background_top_material.xml": { + "Size": 336 + }, + "res/drawable/abc_ic_ab_back_material.xml": { + "Size": 692 + }, + "res/drawable/abc_ic_arrow_drop_right_black_24dp.xml": { + "Size": 1000 + }, + "res/drawable/abc_ic_clear_material.xml": { + "Size": 684 + }, + "res/drawable/abc_ic_go_search_api_material.xml": { + "Size": 640 + }, + "res/drawable/abc_ic_menu_copy_mtrl_am_alpha.xml": { + "Size": 756 + }, + "res/drawable/abc_ic_menu_cut_mtrl_alpha.xml": { + "Size": 1096 + }, + "res/drawable/abc_ic_menu_overflow_material.xml": { + "Size": 792 + }, + "res/drawable/abc_ic_menu_paste_mtrl_am_alpha.xml": { + "Size": 796 + }, + "res/drawable/abc_ic_menu_selectall_mtrl_alpha.xml": { + "Size": 920 + }, + "res/drawable/abc_ic_menu_share_mtrl_alpha.xml": { + "Size": 980 + }, + "res/drawable/abc_ic_search_api_material.xml": { + "Size": 812 + }, + "res/drawable/abc_ic_voice_search_api_material.xml": { + "Size": 828 + }, + "res/drawable/abc_item_background_holo_dark.xml": { + "Size": 1012 + }, + "res/drawable/abc_item_background_holo_light.xml": { + "Size": 1012 + }, + "res/drawable/abc_list_selector_background_transition_holo_dark.xml": { + "Size": 424 + }, + "res/drawable/abc_list_selector_background_transition_holo_light.xml": { + "Size": 424 + }, + "res/drawable/abc_list_selector_holo_dark.xml": { + "Size": 1064 + }, + "res/drawable/abc_list_selector_holo_light.xml": { + "Size": 1064 + }, + "res/drawable/abc_ratingbar_indicator_material.xml": { + "Size": 124 + }, + "res/drawable/abc_ratingbar_material.xml": { + "Size": 124 + }, + "res/drawable/abc_ratingbar_small_material.xml": { + "Size": 124 + }, + "res/drawable/abc_seekbar_thumb_material.xml": { + "Size": 1100 + }, + "res/drawable/abc_seekbar_tick_mark_material.xml": { + "Size": 516 + }, + "res/drawable/abc_seekbar_track_material.xml": { + "Size": 1408 + }, + "res/drawable/abc_spinner_textfield_background_material.xml": { + "Size": 1160 + }, + "res/drawable/abc_star_black_48dp.xml": { + "Size": 640 + }, + "res/drawable/abc_star_half_black_48dp.xml": { + "Size": 600 + }, + "res/drawable/abc_switch_thumb_material.xml": { + "Size": 464 + }, + "res/drawable/abc_tab_indicator_material.xml": { + "Size": 468 + }, + "res/drawable/abc_text_cursor_material.xml": { + "Size": 516 + }, + "res/drawable/abc_textfield_search_material.xml": { + "Size": 756 + }, + "res/drawable/abc_vector_test.xml": { + "Size": 612 + }, + "res/drawable/avd_hide_password.xml": { + "Size": 660 + }, + "res/drawable/avd_show_password.xml": { + "Size": 660 + }, + "res/drawable/btn_checkbox_checked_mtrl.xml": { + "Size": 2688 + }, + "res/drawable/btn_checkbox_checked_to_unchecked_mtrl_animation.xml": { + "Size": 688 + }, + "res/drawable/btn_checkbox_unchecked_mtrl.xml": { + "Size": 2660 + }, + "res/drawable/btn_checkbox_unchecked_to_checked_mtrl_animation.xml": { + "Size": 688 + }, + "res/drawable/btn_radio_off_mtrl.xml": { + "Size": 1728 + }, + "res/drawable/btn_radio_off_to_on_mtrl_animation.xml": { + "Size": 680 + }, + "res/drawable/btn_radio_on_mtrl.xml": { + "Size": 1656 + }, + "res/drawable/btn_radio_on_to_off_mtrl_animation.xml": { + "Size": 680 + }, + "res/drawable/design_fab_background.xml": { + "Size": 372 + }, + "res/drawable/design_ic_visibility_off.xml": { + "Size": 1144 + }, + "res/drawable/design_ic_visibility.xml": { + "Size": 540 + }, + "res/drawable/design_password_eye.xml": { + "Size": 816 + }, + "res/drawable/design_snackbar_background.xml": { + "Size": 484 + }, + "res/drawable/ic_clock_black_24dp.xml": { + "Size": 752 + }, + "res/drawable/ic_keyboard_black_24dp.xml": { + "Size": 852 + }, + "res/drawable/ic_mtrl_checked_circle.xml": { + "Size": 672 + }, + "res/drawable/ic_mtrl_chip_checked_black.xml": { + "Size": 600 + }, + "res/drawable/ic_mtrl_chip_checked_circle.xml": { + "Size": 940 + }, + "res/drawable/ic_mtrl_chip_close_circle.xml": { + "Size": 808 + }, + "res/drawable/material_ic_calendar_black_24dp.xml": { + "Size": 696 + }, + "res/drawable/material_ic_clear_black_24dp.xml": { + "Size": 752 + }, + "res/drawable/material_ic_edit_black_24dp.xml": { + "Size": 716 + }, + "res/drawable/material_ic_keyboard_arrow_left_black_24dp.xml": { + "Size": 712 + }, + "res/drawable/material_ic_keyboard_arrow_right_black_24dp.xml": { + "Size": 700 + }, + "res/drawable/material_ic_menu_arrow_down_black_24dp.xml": { + "Size": 648 + }, + "res/drawable/material_ic_menu_arrow_up_black_24dp.xml": { + "Size": 648 + }, + "res/drawable/mtrl_dialog_background.xml": { + "Size": 716 + }, + "res/drawable/mtrl_dropdown_arrow.xml": { + "Size": 464 + }, + "res/drawable/mtrl_ic_arrow_drop_down.xml": { + "Size": 564 + }, + "res/drawable/mtrl_ic_arrow_drop_up.xml": { + "Size": 564 + }, + "res/drawable/mtrl_ic_cancel.xml": { + "Size": 724 + }, + "res/drawable/mtrl_ic_error.xml": { + "Size": 644 + }, + "res/drawable/mtrl_popupmenu_background_dark.xml": { + "Size": 740 + }, + "res/drawable/mtrl_popupmenu_background.xml": { + "Size": 740 + }, + "res/drawable/mtrl_tabs_default_indicator.xml": { + "Size": 628 + }, + "res/drawable/navigation_empty_icon.xml": { + "Size": 516 + }, + "res/drawable/notification_bg_low.xml": { + "Size": 532 + }, + "res/drawable/notification_bg.xml": { + "Size": 532 + }, + "res/drawable/notification_icon_background.xml": { + "Size": 372 + }, + "res/drawable/notification_tile_bg.xml": { + "Size": 304 + }, + "res/drawable/test_custom_background.xml": { + "Size": 336 + }, + "res/drawable/test_level_drawable.xml": { + "Size": 448 + }, + "res/drawable/tooltip_frame_dark.xml": { + "Size": 484 + }, + "res/drawable/tooltip_frame_light.xml": { + "Size": 484 + }, + "res/interpolator-v21/mtrl_fast_out_linear_in.xml": { + "Size": 400 + }, + "res/interpolator-v21/mtrl_fast_out_slow_in.xml": { + "Size": 400 + }, + "res/interpolator-v21/mtrl_linear_out_slow_in.xml": { + "Size": 400 + }, + "res/interpolator/btn_checkbox_checked_mtrl_animation_interpolator_0.xml": { + "Size": 316 + }, + "res/interpolator/btn_checkbox_checked_mtrl_animation_interpolator_1.xml": { + "Size": 328 + }, + "res/interpolator/btn_checkbox_unchecked_mtrl_animation_interpolator_0.xml": { + "Size": 316 + }, + "res/interpolator/btn_checkbox_unchecked_mtrl_animation_interpolator_1.xml": { + "Size": 328 + }, + "res/interpolator/btn_radio_to_off_mtrl_animation_interpolator_0.xml": { + "Size": 320 + }, + "res/interpolator/btn_radio_to_on_mtrl_animation_interpolator_0.xml": { + "Size": 320 + }, + "res/interpolator/fast_out_slow_in.xml": { + "Size": 400 + }, + "res/interpolator/mtrl_linear.xml": { + "Size": 132 + }, + "res/layout-land/material_clock_period_toggle_land.xml": { + "Size": 1276 + }, + "res/layout-land/material_timepicker.xml": { + "Size": 1884 + }, + "res/layout-land/mtrl_picker_header_dialog.xml": { + "Size": 1440 + }, + "res/layout-ldrtl-v17/material_textinput_timepicker.xml": { + "Size": 1140 + }, + "res/layout-sw600dp-v13/design_layout_snackbar.xml": { + "Size": 528 + }, + "res/layout-sw600dp-v13/mtrl_layout_snackbar.xml": { + "Size": 492 + }, + "res/layout-v21/notification_action_tombstone.xml": { + "Size": 1228 + }, + "res/layout-v21/notification_action.xml": { + "Size": 1052 + }, + "res/layout-v21/notification_template_custom_big.xml": { + "Size": 2456 + }, + "res/layout-v21/notification_template_icon_group.xml": { + "Size": 988 + }, + "res/layout-v22/abc_alert_dialog_button_bar_material.xml": { + "Size": 1584 + }, + "res/layout-v22/material_timepicker_dialog.xml": { + "Size": 3184 + }, + "res/layout-v22/mtrl_alert_dialog_actions.xml": { + "Size": 1764 + }, + "res/layout-v26/abc_screen_toolbar.xml": { + "Size": 1560 + }, + "res/layout-v26/mtrl_calendar_month.xml": { + "Size": 744 + }, + "res/layout-watch-v20/abc_alert_dialog_button_bar_material.xml": { + "Size": 1208 + }, + "res/layout-watch-v20/abc_alert_dialog_title_material.xml": { + "Size": 1352 + }, + "res/layout/abc_action_bar_title_item.xml": { + "Size": 872 + }, + "res/layout/abc_action_bar_up_container.xml": { + "Size": 440 + }, + "res/layout/abc_action_menu_item_layout.xml": { + "Size": 768 + }, + "res/layout/abc_action_menu_layout.xml": { + "Size": 576 + }, + "res/layout/abc_action_mode_bar.xml": { + "Size": 464 + }, + "res/layout/abc_action_mode_close_item_material.xml": { + "Size": 840 + }, + "res/layout/abc_activity_chooser_view_list_item.xml": { + "Size": 1304 + }, + "res/layout/abc_activity_chooser_view.xml": { + "Size": 1684 + }, + "res/layout/abc_alert_dialog_button_bar_material.xml": { + "Size": 1536 + }, + "res/layout/abc_alert_dialog_material.xml": { + "Size": 2648 + }, + "res/layout/abc_alert_dialog_title_material.xml": { + "Size": 1560 + }, + "res/layout/abc_cascading_menu_item_layout.xml": { + "Size": 1868 + }, + "res/layout/abc_dialog_title_material.xml": { + "Size": 1116 + }, + "res/layout/abc_expanded_menu_layout.xml": { + "Size": 388 + }, + "res/layout/abc_list_menu_item_checkbox.xml": { + "Size": 528 + }, + "res/layout/abc_list_menu_item_icon.xml": { + "Size": 780 + }, + "res/layout/abc_list_menu_item_layout.xml": { + "Size": 1396 + }, + "res/layout/abc_list_menu_item_radio.xml": { + "Size": 532 + }, + "res/layout/abc_popup_menu_header_item_layout.xml": { + "Size": 848 + }, + "res/layout/abc_popup_menu_item_layout.xml": { + "Size": 2072 + }, + "res/layout/abc_screen_content_include.xml": { + "Size": 548 + }, + "res/layout/abc_screen_simple_overlay_action_mode.xml": { + "Size": 792 + }, + "res/layout/abc_screen_simple.xml": { + "Size": 832 + }, + "res/layout/abc_screen_toolbar.xml": { + "Size": 1504 + }, + "res/layout/abc_search_dropdown_item_icons_2line.xml": { + "Size": 1916 + }, + "res/layout/abc_search_view.xml": { + "Size": 3472 + }, + "res/layout/abc_select_dialog_material.xml": { + "Size": 1020 + }, + "res/layout/abc_tooltip.xml": { + "Size": 1056 + }, + "res/layout/bottomtablayout.xml": { + "Size": 832 + }, + "res/layout/browser_actions_context_menu_page.xml": { + "Size": 1660 + }, + "res/layout/browser_actions_context_menu_row.xml": { + "Size": 1212 + }, + "res/layout/custom_dialog.xml": { + "Size": 612 + }, + "res/layout/design_bottom_navigation_item.xml": { + "Size": 1528 + }, + "res/layout/design_bottom_sheet_dialog.xml": { + "Size": 1224 + }, + "res/layout/design_layout_snackbar_include.xml": { + "Size": 1444 + }, + "res/layout/design_layout_snackbar.xml": { + "Size": 528 + }, + "res/layout/design_layout_tab_icon.xml": { + "Size": 408 + }, + "res/layout/design_layout_tab_text.xml": { + "Size": 436 + }, + "res/layout/design_menu_item_action_area.xml": { + "Size": 320 + }, + "res/layout/design_navigation_item_header.xml": { + "Size": 440 + }, + "res/layout/design_navigation_item_separator.xml": { + "Size": 472 + }, + "res/layout/design_navigation_item_subheader.xml": { + "Size": 564 + }, + "res/layout/design_navigation_item.xml": { + "Size": 576 + }, + "res/layout/design_navigation_menu_item.xml": { + "Size": 856 + }, + "res/layout/design_navigation_menu.xml": { + "Size": 528 + }, + "res/layout/design_text_input_end_icon.xml": { + "Size": 616 + }, + "res/layout/design_text_input_start_icon.xml": { + "Size": 612 + }, + "res/layout/expand_button.xml": { + "Size": 1720 + }, + "res/layout/fallbacktabbardonotuse.xml": { + "Size": 692 + }, + "res/layout/fallbacktoolbardonotuse.xml": { + "Size": 496 + }, + "res/layout/flyoutcontent.xml": { + "Size": 776 + }, + "res/layout/image_frame.xml": { + "Size": 1088 + }, + "res/layout/main.xml": { + "Size": 544 + }, + "res/layout/material_chip_input_combo.xml": { + "Size": 372 + }, + "res/layout/material_clock_display_divider.xml": { + "Size": 752 + }, + "res/layout/material_clock_display.xml": { + "Size": 1172 + }, + "res/layout/material_clock_period_toggle.xml": { + "Size": 1504 + }, + "res/layout/material_clockface_textview.xml": { + "Size": 476 + }, + "res/layout/material_clockface_view.xml": { + "Size": 1012 + }, + "res/layout/material_radial_view_group.xml": { + "Size": 768 + }, + "res/layout/material_textinput_timepicker.xml": { + "Size": 1092 + }, + "res/layout/material_time_chip.xml": { + "Size": 380 + }, + "res/layout/material_time_input.xml": { + "Size": 1208 + }, + "res/layout/material_timepicker_dialog.xml": { + "Size": 3132 + }, + "res/layout/material_timepicker_textinput_display.xml": { + "Size": 684 + }, + "res/layout/material_timepicker.xml": { + "Size": 1136 + }, + "res/layout/mtrl_alert_dialog_actions.xml": { + "Size": 1620 + }, + "res/layout/mtrl_alert_dialog_title.xml": { + "Size": 956 + }, + "res/layout/mtrl_alert_dialog.xml": { + "Size": 2476 + }, + "res/layout/mtrl_alert_select_dialog_item.xml": { + "Size": 588 + }, + "res/layout/mtrl_alert_select_dialog_multichoice.xml": { + "Size": 940 + }, + "res/layout/mtrl_alert_select_dialog_singlechoice.xml": { + "Size": 940 + }, + "res/layout/mtrl_calendar_day_of_week.xml": { + "Size": 400 + }, + "res/layout/mtrl_calendar_day.xml": { + "Size": 352 + }, + "res/layout/mtrl_calendar_days_of_week.xml": { + "Size": 436 + }, + "res/layout/mtrl_calendar_horizontal.xml": { + "Size": 1176 + }, + "res/layout/mtrl_calendar_month_labeled.xml": { + "Size": 728 + }, + "res/layout/mtrl_calendar_month_navigation.xml": { + "Size": 1748 + }, + "res/layout/mtrl_calendar_month.xml": { + "Size": 688 + }, + "res/layout/mtrl_calendar_months.xml": { + "Size": 428 + }, + "res/layout/mtrl_calendar_vertical.xml": { + "Size": 740 + }, + "res/layout/mtrl_calendar_year.xml": { + "Size": 352 + }, + "res/layout/mtrl_layout_snackbar_include.xml": { + "Size": 952 + }, + "res/layout/mtrl_layout_snackbar.xml": { + "Size": 492 + }, + "res/layout/mtrl_navigation_rail_item.xml": { + "Size": 1464 + }, + "res/layout/mtrl_picker_actions.xml": { + "Size": 984 + }, + "res/layout/mtrl_picker_dialog.xml": { + "Size": 1140 + }, + "res/layout/mtrl_picker_fullscreen.xml": { + "Size": 848 + }, + "res/layout/mtrl_picker_header_dialog.xml": { + "Size": 1440 + }, + "res/layout/mtrl_picker_header_fullscreen.xml": { + "Size": 2728 + }, + "res/layout/mtrl_picker_header_selection_text.xml": { + "Size": 712 + }, + "res/layout/mtrl_picker_header_title_text.xml": { + "Size": 624 + }, + "res/layout/mtrl_picker_header_toggle.xml": { + "Size": 576 + }, + "res/layout/mtrl_picker_text_input_date_range.xml": { + "Size": 1460 + }, + "res/layout/mtrl_picker_text_input_date.xml": { + "Size": 984 + }, + "res/layout/notification_media_action.xml": { + "Size": 564 + }, + "res/layout/notification_media_cancel_action.xml": { + "Size": 744 + }, + "res/layout/notification_template_big_media_custom.xml": { + "Size": 3044 + }, + "res/layout/notification_template_big_media_narrow_custom.xml": { + "Size": 3216 + }, + "res/layout/notification_template_big_media_narrow.xml": { + "Size": 1824 + }, + "res/layout/notification_template_big_media.xml": { + "Size": 1696 + }, + "res/layout/notification_template_lines_media.xml": { + "Size": 2872 + }, + "res/layout/notification_template_media_custom.xml": { + "Size": 2756 + }, + "res/layout/notification_template_media.xml": { + "Size": 1292 + }, + "res/layout/notification_template_part_chronometer.xml": { + "Size": 440 + }, + "res/layout/notification_template_part_time.xml": { + "Size": 440 + }, + "res/layout/preference_category_material.xml": { + "Size": 1768 + }, + "res/layout/preference_category.xml": { + "Size": 384 + }, + "res/layout/preference_dialog_edittext.xml": { + "Size": 1272 + }, + "res/layout/preference_dropdown_material.xml": { + "Size": 712 + }, + "res/layout/preference_dropdown.xml": { + "Size": 2544 + }, + "res/layout/preference_information_material.xml": { + "Size": 2056 + }, + "res/layout/preference_information.xml": { + "Size": 1732 + }, + "res/layout/preference_list_fragment.xml": { + "Size": 812 + }, + "res/layout/preference_material.xml": { + "Size": 2052 + }, + "res/layout/preference_recyclerview.xml": { + "Size": 544 + }, + "res/layout/preference_widget_checkbox.xml": { + "Size": 472 + }, + "res/layout/preference_widget_seekbar_material.xml": { + "Size": 3056 + }, + "res/layout/preference_widget_seekbar.xml": { + "Size": 2896 + }, + "res/layout/preference_widget_switch_compat.xml": { + "Size": 504 + }, + "res/layout/preference_widget_switch.xml": { + "Size": 472 + }, + "res/layout/preference.xml": { + "Size": 2352 + }, + "res/layout/rootlayout.xml": { + "Size": 1352 + }, + "res/layout/select_dialog_item_material.xml": { + "Size": 640 + }, + "res/layout/select_dialog_multichoice_material.xml": { + "Size": 864 + }, + "res/layout/select_dialog_singlechoice_material.xml": { + "Size": 864 + }, + "res/layout/shellcontent.xml": { + "Size": 888 + }, + "res/layout/support_simple_spinner_dropdown_item.xml": { + "Size": 464 + }, + "res/layout/tabbar.xml": { + "Size": 692 + }, + "res/layout/test_action_chip.xml": { + "Size": 488 + }, + "res/layout/test_chip_zero_corner_radius.xml": { + "Size": 640 + }, + "res/layout/test_design_checkbox.xml": { + "Size": 836 + }, + "res/layout/test_design_radiobutton.xml": { + "Size": 840 + }, + "res/layout/test_navigation_bar_item_layout.xml": { + "Size": 1528 + }, + "res/layout/test_reflow_chipgroup.xml": { + "Size": 1060 + }, + "res/layout/test_toolbar_custom_background.xml": { + "Size": 400 + }, + "res/layout/test_toolbar_elevation.xml": { + "Size": 400 + }, + "res/layout/test_toolbar_surface.xml": { + "Size": 392 + }, + "res/layout/test_toolbar.xml": { + "Size": 360 + }, + "res/layout/text_view_with_line_height_from_appearance.xml": { + "Size": 408 + }, + "res/layout/text_view_with_line_height_from_layout.xml": { + "Size": 552 + }, + "res/layout/text_view_with_line_height_from_style.xml": { + "Size": 396 + }, + "res/layout/text_view_with_theme_line_height.xml": { + "Size": 408 + }, + "res/layout/text_view_without_line_height.xml": { + "Size": 364 + }, + "res/layout/toolbar.xml": { + "Size": 496 + }, + "res/xml/image_share_filepaths.xml": { + "Size": 308 + }, + "res/xml/splits0.xml": { + "Size": 8404 + }, + "res/xml/standalone_badge_gravity_bottom_end.xml": { + "Size": 312 + }, + "res/xml/standalone_badge_gravity_bottom_start.xml": { + "Size": 312 + }, + "res/xml/standalone_badge_gravity_top_start.xml": { + "Size": 312 + }, + "res/xml/standalone_badge_offset.xml": { + "Size": 360 + }, + "res/xml/standalone_badge.xml": { + "Size": 268 + }, + "resources.arsc": { + "Size": 812848 + } + }, + "PackageSize": 22578118 +} \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.MonoVM.apkdesc similarity index 98% rename from src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc rename to src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.MonoVM.apkdesc index 312a6fbfa5c..f01fb55fa74 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.MonoVM.apkdesc @@ -35,136 +35,136 @@ "Size": 25424 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 96672 + "Size": 105352 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 539616 + "Size": 568728 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 23544 + "Size": 23664 }, "lib/arm64-v8a/lib_mscorlib.dll.so": { - "Size": 21464 + "Size": 21432 }, "lib/arm64-v8a/lib_netstandard.dll.so": { - "Size": 23112 + "Size": 23072 }, "lib/arm64-v8a/lib_System.Collections.Concurrent.dll.so": { - "Size": 29864 + "Size": 29832 }, "lib/arm64-v8a/lib_System.Collections.dll.so": { - "Size": 34144 + "Size": 34112 }, "lib/arm64-v8a/lib_System.Collections.NonGeneric.dll.so": { - "Size": 25784 + "Size": 25752 }, "lib/arm64-v8a/lib_System.Collections.Specialized.dll.so": { - "Size": 23864 + "Size": 23832 }, "lib/arm64-v8a/lib_System.ComponentModel.dll.so": { - "Size": 19616 + "Size": 19584 }, "lib/arm64-v8a/lib_System.ComponentModel.Primitives.dll.so": { - "Size": 21344 + "Size": 21312 }, "lib/arm64-v8a/lib_System.ComponentModel.TypeConverter.dll.so": { - "Size": 42448 + "Size": 42408 }, "lib/arm64-v8a/lib_System.Console.dll.so": { - "Size": 24448 + "Size": 24416 }, "lib/arm64-v8a/lib_System.Core.dll.so": { - "Size": 19488 + "Size": 19448 }, "lib/arm64-v8a/lib_System.Diagnostics.TraceSource.dll.so": { - "Size": 24720 + "Size": 25400 }, "lib/arm64-v8a/lib_System.dll.so": { - "Size": 19880 + "Size": 19840 }, "lib/arm64-v8a/lib_System.Drawing.dll.so": { - "Size": 19456 + "Size": 19424 }, "lib/arm64-v8a/lib_System.Drawing.Primitives.dll.so": { - "Size": 30072 + "Size": 30040 }, "lib/arm64-v8a/lib_System.Formats.Asn1.dll.so": { - "Size": 50336 + "Size": 50296 }, "lib/arm64-v8a/lib_System.IO.Compression.Brotli.dll.so": { - "Size": 29512 + "Size": 29480 }, "lib/arm64-v8a/lib_System.IO.Compression.dll.so": { - "Size": 33816 + "Size": 33776 }, "lib/arm64-v8a/lib_System.IO.IsolatedStorage.dll.so": { - "Size": 28344 + "Size": 28304 }, "lib/arm64-v8a/lib_System.Linq.dll.so": { - "Size": 48112 + "Size": 48064 }, "lib/arm64-v8a/lib_System.Linq.Expressions.dll.so": { - "Size": 186088 + "Size": 186048 }, "lib/arm64-v8a/lib_System.Net.Http.dll.so": { - "Size": 86200 + "Size": 86160 }, "lib/arm64-v8a/lib_System.Net.Primitives.dll.so": { - "Size": 42232 + "Size": 42192 }, "lib/arm64-v8a/lib_System.Net.Requests.dll.so": { - "Size": 21576 + "Size": 21544 }, "lib/arm64-v8a/lib_System.ObjectModel.dll.so": { - "Size": 27104 + "Size": 27064 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 968048 + "Size": 973912 }, "lib/arm64-v8a/lib_System.Private.DataContractSerialization.dll.so": { - "Size": 216928 + "Size": 218040 }, "lib/arm64-v8a/lib_System.Private.Uri.dll.so": { - "Size": 63336 + "Size": 63328 }, "lib/arm64-v8a/lib_System.Private.Xml.dll.so": { - "Size": 236984 + "Size": 236936 }, "lib/arm64-v8a/lib_System.Private.Xml.Linq.dll.so": { - "Size": 35608 + "Size": 35600 }, "lib/arm64-v8a/lib_System.Runtime.dll.so": { "Size": 20312 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 21536 + "Size": 21496 }, "lib/arm64-v8a/lib_System.Runtime.Numerics.dll.so": { - "Size": 56120 + "Size": 56088 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.dll.so": { - "Size": 19384 + "Size": 19352 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Formatters.dll.so": { - "Size": 20352 + "Size": 20320 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Primitives.dll.so": { - "Size": 21480 + "Size": 21440 }, "lib/arm64-v8a/lib_System.Security.Cryptography.dll.so": { - "Size": 81640 + "Size": 81608 }, "lib/arm64-v8a/lib_System.Text.RegularExpressions.dll.so": { - "Size": 189992 + "Size": 189960 }, "lib/arm64-v8a/lib_System.Xml.dll.so": { - "Size": 19280 + "Size": 19240 }, "lib/arm64-v8a/lib_System.Xml.Linq.dll.so": { - "Size": 19296 + "Size": 19256 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { - "Size": 22096 + "Size": 22240 }, "lib/arm64-v8a/lib_Xamarin.AndroidX.Activity.dll.so": { "Size": 34960 @@ -242,10 +242,10 @@ "Size": 36616 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1408768 + "Size": 1386664 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3120768 + "Size": 3122432 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 71952 @@ -254,13 +254,13 @@ "Size": 759304 }, "lib/arm64-v8a/libSystem.Native.so": { - "Size": 104080 + "Size": 104112 }, "lib/arm64-v8a/libSystem.Security.Cryptography.Native.Android.so": { "Size": 165568 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 350760 + "Size": 350720 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -413,7 +413,7 @@ "Size": 6 }, "META-INF/BNDLTOOL.RSA": { - "Size": 1223 + "Size": 1211 }, "META-INF/BNDLTOOL.SF": { "Size": 98445 @@ -2483,5 +2483,5 @@ "Size": 812848 } }, - "PackageSize": 10898593 + "PackageSize": 10927265 } \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index f52d9f1c47e..be4fe8d8d28 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -570,7 +570,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. diff --git a/tests/MSBuildDeviceIntegration/Tests/AotProfileTests.cs b/tests/MSBuildDeviceIntegration/Tests/AotProfileTests.cs index bbc15d40d64..641b2e4bfae 100644 --- a/tests/MSBuildDeviceIntegration/Tests/AotProfileTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/AotProfileTests.cs @@ -31,6 +31,8 @@ public void BuildBasicApplicationAndAotProfileIt () IsRelease = true, AotAssemblies = false, }; + // MonoVM-only test + proj.SetRuntime (Android.Tasks.AndroidRuntime.MonoVM); proj.SetAndroidSupportedAbis (DeviceAbi); // TODO: only needed in .NET 6+ diff --git a/tests/MSBuildDeviceIntegration/Tests/BundleToolNoAbiSplitTests.cs b/tests/MSBuildDeviceIntegration/Tests/BundleToolNoAbiSplitTests.cs index 59ea0144abc..6265a9a7959 100644 --- a/tests/MSBuildDeviceIntegration/Tests/BundleToolNoAbiSplitTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/BundleToolNoAbiSplitTests.cs @@ -9,11 +9,12 @@ namespace Xamarin.Android.Build.Tests { - [TestFixture] + [TestFixture (AndroidRuntime.MonoVM)] + [TestFixture (AndroidRuntime.CoreCLR)] [Category ("UsesDevice")] public class BundleToolNoAbiSplitTests : DeviceTest { - static readonly string [] Abis = new [] { "armeabi-v7a", "arm64-v8a", "x86", "x86_64" }; + static readonly string [] Abis = ["arm64-v8a", "x86_64"]; XamarinAndroidApplicationProject app; ProjectBuilder appBuilder; @@ -34,6 +35,12 @@ public class BundleToolNoAbiSplitTests : DeviceTest } } }"; + readonly AndroidRuntime runtime; + + public BundleToolNoAbiSplitTests (AndroidRuntime runtime) + { + this.runtime = runtime; + } AndroidItem.AndroidAsset MakeAndroidAsset (string include, string content, string? assetPack = null, string? deliveryType = null) { @@ -121,10 +128,17 @@ public void OneTimeSetUp () String.Join (";", Abis), true ); - EnvironmentHelper.ApplicationConfig app_config = EnvironmentHelper.ReadApplicationConfig (envFiles); + + EnvironmentHelper.IApplicationConfig app_config = EnvironmentHelper.ReadApplicationConfig (envFiles, runtime); Assert.That (app_config, Is.Not.Null, "application_config must be present in the environment files"); - Assert.AreEqual (app_config.ignore_split_configs, true, $"App config should indicate that split configs must be ignored"); + + bool ignoreSplitConfigs = runtime switch { + AndroidRuntime.MonoVM => ((EnvironmentHelper.ApplicationConfig_MonoVM)app_config).ignore_split_configs, + AndroidRuntime.CoreCLR => ((EnvironmentHelper.ApplicationConfig_CoreCLR)app_config).ignore_split_configs, + _ => throw new NotSupportedException ($"Unsupported runtime '{runtime}'") + }; + Assert.AreEqual (ignoreSplitConfigs, true, $"App config should indicate that split configs must be ignored"); } [TearDown] diff --git a/tests/MSBuildDeviceIntegration/Tests/BundleToolTests.cs b/tests/MSBuildDeviceIntegration/Tests/BundleToolTests.cs index a0b4998ce0d..52736371dcd 100644 --- a/tests/MSBuildDeviceIntegration/Tests/BundleToolTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/BundleToolTests.cs @@ -19,7 +19,7 @@ public class BundleToolTests : DeviceTest new object[] { true }, }; - static readonly string [] Abis = new [] { "armeabi-v7a", "arm64-v8a", "x86", "x86_64" }; + static readonly string [] Abis = ["arm64-v8a", "x86_64"]; XamarinAndroidLibraryProject lib; XamarinAndroidApplicationProject app; ProjectBuilder libBuilder, appBuilder; @@ -177,7 +177,6 @@ public void BaseZip () } expectedFiles.Add ($"lib/{abi}/libmonodroid.so"); - expectedFiles.Add ($"lib/{abi}/libmonosgen-2.0.so"); expectedFiles.Add ($"lib/{abi}/libxamarin-app.so"); if (usesAssemblyBlobs) { expectedFiles.Add ($"{blobEntryPrefix}{abi}/lib_System.Private.CoreLib.dll.so"); @@ -237,7 +236,6 @@ public void AppBundle () } expectedFiles.Add ($"base/lib/{abi}/libmonodroid.so"); - expectedFiles.Add ($"base/lib/{abi}/libmonosgen-2.0.so"); expectedFiles.Add ($"base/lib/{abi}/libxamarin-app.so"); if (usesAssemblyBlobs) { expectedFiles.Add ($"{blobEntryPrefix}{abi}/lib_System.Private.CoreLib.dll.so"); diff --git a/tests/MSBuildDeviceIntegration/Tests/DebuggingTest.cs b/tests/MSBuildDeviceIntegration/Tests/DebuggingTest.cs index 00f5cb6fa9f..0937b4d60cf 100755 --- a/tests/MSBuildDeviceIntegration/Tests/DebuggingTest.cs +++ b/tests/MSBuildDeviceIntegration/Tests/DebuggingTest.cs @@ -176,6 +176,8 @@ public void CustomApplicationRunsWithDebuggerAndBreaks (bool embedAssemblies, bo var proj = new XamarinAndroidApplicationProject () { IsRelease = false, }; + // MonoVM-only test + proj.SetRuntime (Android.Tasks.AndroidRuntime.MonoVM); proj.SetAndroidSupportedAbis (DeviceAbi); proj.SetProperty ("EmbedAssembliesIntoApk", embedAssemblies.ToString ()); proj.SetProperty ("AndroidPackageFormat", packageFormat); @@ -383,6 +385,8 @@ public Foo () IsRelease = false, EmbedAssembliesIntoApk = embedAssemblies, }; + // MonoVM-only test + app.SetRuntime (Android.Tasks.AndroidRuntime.MonoVM); if (!useLatestSdk) { lib.TargetFramework = "net9.0-android"; app.TargetFramework = "net9.0-android"; diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs index 58a72be277a..0cb026b588f 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs @@ -107,7 +107,6 @@ public void NativeAssemblyCacheWithSatelliteAssemblies ([Values (true, false)] b EnableMarshalMethods = enableMarshalMethods, }; proj.References.Add (new BuildItem.ProjectReference ($"..\\{lib.ProjectName}\\{lib.ProjectName}.csproj", lib.ProjectName, lib.ProjectGuid)); - proj.SetAndroidSupportedAbis ("armeabi-v7a", "arm64-v8a", "x86", "x86_64"); using (var libBuilder = CreateDllBuilder (Path.Combine (path, lib.ProjectName))) { builder = CreateApkBuilder (Path.Combine (path, proj.ProjectName)); @@ -341,7 +340,6 @@ public class LinkModeFullClass { }); proj.AndroidManifest = proj.AndroidManifest.Replace ("", ""); - proj.SetAndroidSupportedAbis ("armeabi-v7a", "arm64-v8a", "x86", "x86_64"); using (var sr = new StreamReader (typeof (InstallAndRunTests).Assembly.GetManifestResourceStream ("Xamarin.Android.Build.Tests.Resources.LinkDescTest.MainActivityReplacement.cs"))) proj.MainActivity = sr.ReadToEnd (); @@ -386,7 +384,7 @@ public void JsonDeserializationCreatesJavaHandle ([Values (false, true)] bool is proj.SetProperty ("NoWarn", "SYSLIB0011"); if (isRelease || !TestEnvironment.CommercialBuildAvailable) { - proj.SetAndroidSupportedAbis ("armeabi-v7a", "arm64-v8a", "x86", "x86_64"); + proj.SetAndroidSupportedAbis (DeviceAbi); } proj.References.Add (new BuildItem.Reference ("System.Runtime.Serialization")); @@ -475,6 +473,8 @@ public void RunWithInterpreterEnabled ([Values (false, true)] bool isRelease) IsRelease = isRelease, AotAssemblies = false, // Release defaults to Profiled AOT for .NET 6 }; + // MonoVM-only test + proj.SetRuntime (Android.Tasks.AndroidRuntime.MonoVM); var abis = new string[] { "armeabi-v7a", "arm64-v8a", "x86", "x86_64" }; proj.SetAndroidSupportedAbis (abis); proj.SetProperty (proj.CommonProperties, "UseInterpreter", "True"); @@ -553,8 +553,7 @@ public void SingleProject_ApplicationId ([Values (false, true)] bool testOnly) if (testOnly) proj.AndroidManifest = proj.AndroidManifest.Replace ("IL2037 true - $(DefineConstants);CORECLR + $(DefineConstants);CORECLR $(DefineConstants);NATIVEAOT - $(ExcludeCategories):CoreCLRIgnore:SSL:NTLM:RuntimeConfig + $(ExcludeCategories):CoreCLRIgnore:SSL:NTLM:RuntimeConfig $(ExcludeCategories):NativeAOTIgnore:SSL:NTLM:AndroidClientHandler:Export:NativeTypeMap