diff --git a/Configuration.props b/Configuration.props index 788285bd9b9..f20d819c98b 100644 --- a/Configuration.props +++ b/Configuration.props @@ -125,7 +125,7 @@ 35.0.0 34.0.5 - 1.15.1 + 1.17.0 $(NUGET_PACKAGES) $(userprofile)\.nuget\packages $(HOME)/.nuget/packages diff --git a/Directory.Build.props b/Directory.Build.props index b86419905d1..228f6612b7d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -52,7 +52,7 @@ 6.12.0.148 8.0.0 6.0.0 - 2.13.1 + 2.17.3 2.14.1 5.9.2.4 diff --git a/Documentation/docs-mobile/messages/index.md b/Documentation/docs-mobile/messages/index.md index f5cb16b1759..8d46b161ab2 100644 --- a/Documentation/docs-mobile/messages/index.md +++ b/Documentation/docs-mobile/messages/index.md @@ -102,7 +102,8 @@ Please file an issue with the exact error message using the 'Help->Send Feedback or 'Help->Report a Problem' in Visual Studio for Mac. + [XA0138](xa0138.md): %(AndroidAsset.AssetPack) and %(AndroidAsset.AssetPack) item metadata are only supported when `$(AndroidApplication)` is `true`. + [XA0139](xa0139.md): `@(AndroidAsset)` `{0}` has invalid `DeliveryType` metadata of `{1}`. Supported values are `installtime`, `ondemand` or `fastfollow` -+ [XA0140](xa0140.md): ++ [XA0140](xa0140.md): ++ [XA0141](xa0141.md): NuGet package '{0}' version '{1}' contains a shared library '{2}' which is not correctly aligned. See https://developer.android.com/guide/practices/page-sizes for more details ## XA1xxx: Project related diff --git a/Documentation/docs-mobile/messages/xa0141.md b/Documentation/docs-mobile/messages/xa0141.md new file mode 100644 index 00000000000..15bb99a6d04 --- /dev/null +++ b/Documentation/docs-mobile/messages/xa0141.md @@ -0,0 +1,14 @@ +--- +title: .NET for Android warning XA0141 +description: XA0141 warning code +ms.date: 22/07/2024 +--- +# .NET for Android warning XA0141 + +## Issue + +NuGet package '{0}' version '{1}' contains a shared library '{2}' which is not correctly aligned. See https://developer.android.com/guide/practices/page-sizes for more details + +## Solution + +The indicated native shared library must be recompiled and relinked with the 16k alignment, as per URL indicated in the message. diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets index 7b9ebac3621..1ae80b94409 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets @@ -90,7 +90,8 @@ They run in a context of an inner build with a single $(RuntimeIdentifier). RuntimeIdentifier="$(RuntimeIdentifier)" EnableLLVM="$(EnableLLVM)" Profiles="@(AndroidAotProfile)" - StripLibraries="$(_AndroidAotStripLibraries)"> + StripLibraries="$(_AndroidAotStripLibraries)" + ZipAlignmentPages="$(AndroidZipAlignment)"> 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 7fcd3d31fe7..576f3a5406b 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 @@ -48,12 +48,11 @@ - <_AndroidZipAlignment Condition=" '$(_AndroidZipAlignment)' == '' ">4 + 16 diff --git a/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx b/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx index ca26aa0bbec..6dee6524d06 100644 --- a/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx +++ b/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx @@ -1059,4 +1059,12 @@ To use a custom JDK path for a command line build, set the 'JavaSdkDirectory' MS {0} - NuGet package id {1} - NuGet package version - \ No newline at end of file + + NuGet package '{0}' version '{1}' contains a shared library '{2}' which is not correctly aligned. See https://developer.android.com/guide/practices/page-sizes for more details + The following is a literal name and should not be translated: NuGet +{0} - NuGet package id +{1} - NuGet package version +{2} - shared library file name + + + diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/AndroidZipAlign.cs b/src/Xamarin.Android.Build.Tasks/Tasks/AndroidZipAlign.cs index c0508250737..1f8dc2d66f9 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/AndroidZipAlign.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/AndroidZipAlign.cs @@ -7,9 +7,9 @@ namespace Xamarin.Android.Tasks { public class AndroidZipAlign : AndroidRunToolTask { - // Sometime next year the default value should be changed to 16 since it's going to be a Google Play store requirement for - // application submissions - internal const int DefaultZipAlignment = 4; + // Default to 16 since it's going to be a Google Play store requirement for application submissions sometime next year + internal const int DefaultZipAlignment64Bit = 16; + internal const int ZipAlignment32Bit = 4; // This must never change public override string TaskPrefix => "AZA"; @@ -19,7 +19,7 @@ public class AndroidZipAlign : AndroidRunToolTask [Required] public ITaskItem DestinationDirectory { get; set; } - int alignment = DefaultZipAlignment; + int alignment = DefaultZipAlignment64Bit; public int Alignment { get {return alignment;} set {alignment = value;} diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs b/src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs index 45778d60204..d87cc2f418e 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/BuildApk.cs @@ -107,6 +107,8 @@ public class BuildApk : AndroidTask public string ZipFlushSizeLimit { get; set; } + public int ZipAlignmentPages { get; set; } = AndroidZipAlign.DefaultZipAlignment64Bit; + [Required] public string ProjectFullPath { get; set; } @@ -683,6 +685,7 @@ sealed class LibInfo public string Link; public string Abi; public string ArchiveFileName; + public ITaskItem Item; } CompressionMethod GetCompressionMethod (string fileName) @@ -690,7 +693,7 @@ CompressionMethod GetCompressionMethod (string fileName) return uncompressedFileExtensions.Contains (Path.GetExtension (fileName)) ? UncompressedMethod : CompressionMethod.Default; } - void AddNativeLibraryToArchive (ZipArchiveEx apk, string abi, string filesystemPath, string inArchiveFileName) + void AddNativeLibraryToArchive (ZipArchiveEx apk, string abi, string filesystemPath, string inArchiveFileName, ITaskItem taskItem) { string archivePath = MakeArchiveLibPath (abi, inArchiveFileName); existingEntries.Remove (archivePath); @@ -700,6 +703,7 @@ void AddNativeLibraryToArchive (ZipArchiveEx apk, string abi, string filesystemP return; } Log.LogDebugMessage ($"Adding native library: {filesystemPath} (APK path: {archivePath})"); + ELFHelper.AssertValidLibraryAlignment (Log, ZipAlignmentPages, filesystemPath, taskItem); apk.AddEntryAndFlush (archivePath, File.OpenRead (filesystemPath), compressionMethod); } @@ -709,7 +713,7 @@ void AddRuntimeLibraries (ZipArchiveEx apk, string [] supportedAbis) foreach (ITaskItem item in ApplicationSharedLibraries) { if (String.Compare (abi, item.GetMetadata ("abi"), StringComparison.Ordinal) != 0) continue; - AddNativeLibraryToArchive (apk, abi, item.ItemSpec, Path.GetFileName (item.ItemSpec)); + AddNativeLibraryToArchive (apk, abi, item.ItemSpec, Path.GetFileName (item.ItemSpec), item); } } } @@ -762,7 +766,8 @@ private void AddNativeLibraries (ArchiveFileList files, string [] supportedAbis) Path = v.ItemSpec, Link = v.GetMetadata ("Link"), Abi = GetNativeLibraryAbi (v), - ArchiveFileName = GetArchiveFileName (v) + ArchiveFileName = GetArchiveFileName (v), + Item = v, }); AddNativeLibraries (files, supportedAbis, frameworkLibs); @@ -773,7 +778,8 @@ private void AddNativeLibraries (ArchiveFileList files, string [] supportedAbis) Path = v.ItemSpec, Link = v.GetMetadata ("Link"), Abi = GetNativeLibraryAbi (v), - ArchiveFileName = GetArchiveFileName (v) + ArchiveFileName = GetArchiveFileName (v), + Item = v, } ); @@ -854,8 +860,9 @@ void AddNativeLibraries (ArchiveFileList files, string [] supportedAbis, System. string.Join (", ", libs.Where (lib => lib.Abi == null).Select (lib => lib.Path))); libs = libs.Where (lib => lib.Abi != null); libs = libs.Where (lib => supportedAbis.Contains (lib.Abi)); - foreach (var info in libs) - AddNativeLibrary (files, info.Path, info.Abi, info.ArchiveFileName); + foreach (var info in libs) { + AddNativeLibrary (files, info.Path, info.Abi, info.ArchiveFileName, info.Item); + } } private void AddAdditionalNativeLibraries (ArchiveFileList files, string [] supportedAbis) @@ -868,12 +875,13 @@ private void AddAdditionalNativeLibraries (ArchiveFileList files, string [] supp Path = l.ItemSpec, Abi = AndroidRidAbiHelper.GetNativeLibraryAbi (l), ArchiveFileName = l.GetMetadata ("ArchiveFileName"), + Item = l, }); AddNativeLibraries (files, supportedAbis, libs); } - void AddNativeLibrary (ArchiveFileList files, string path, string abi, string archiveFileName) + void AddNativeLibrary (ArchiveFileList files, string path, string abi, string archiveFileName, ITaskItem? taskItem = null) { string fileName = string.IsNullOrEmpty (archiveFileName) ? Path.GetFileName (path) : archiveFileName; var item = (filePath: path, archivePath: MakeArchiveLibPath (abi, fileName)); @@ -882,6 +890,7 @@ void AddNativeLibrary (ArchiveFileList files, string path, string abi, string ar return; } + ELFHelper.AssertValidLibraryAlignment (Log, ZipAlignmentPages, path, taskItem); if (!ELFHelper.IsEmptyAOTLibrary (Log, item.filePath)) { files.Add (item); } else { diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index 6340419ca9d..29a2118a86f 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -80,7 +80,6 @@ public class GeneratePackageManagerJava : AndroidTask public string AndroidSequencePointsMode { get; set; } public bool EnableSGenConcurrent { get; set; } public string? CustomBundleConfigFile { get; set; } - public int ZipAlignmentPages { get; set; } = AndroidZipAlign.DefaultZipAlignment; [Output] public string BuildId { get; set; } @@ -335,7 +334,6 @@ void AddEnvironment () bool haveRuntimeConfigBlob = !String.IsNullOrEmpty (RuntimeConfigBinFilePath) && File.Exists (RuntimeConfigBinFilePath); var jniRemappingNativeCodeInfo = BuildEngine4.GetRegisteredTaskObjectAssemblyLocal (ProjectSpecificTaskObjectKey (GenerateJniRemappingNativeCode.JniRemappingNativeCodeInfoKey), RegisteredTaskObjectLifetime.Build); - uint zipAlignmentMask = MonoAndroidHelper.ZipAlignmentToMask (ZipAlignmentPages); var appConfigAsmGen = new ApplicationConfigNativeAssemblyGenerator (environmentVariables, systemProperties, Log) { UsesMonoAOT = usesMonoAOT, UsesMonoLLVM = EnableLLVM, @@ -359,7 +357,6 @@ void AddEnvironment () JNIEnvRegisterJniNativesToken = jnienv_registerjninatives_method_token, JniRemappingReplacementTypeCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementTypeCount, JniRemappingReplacementMethodIndexEntryCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementMethodIndexEntryCount, - ZipAlignmentMask = zipAlignmentMask, MarshalMethodsEnabled = EnableMarshalMethods, IgnoreSplitConfigs = ShouldIgnoreSplitConfigs (), }; diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs index af3fcf957cd..36ffaefa73b 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GetAotArguments.cs @@ -54,6 +54,8 @@ public abstract class GetAotArguments : AsyncTask public ITaskItem [] Profiles { get; set; } = Array.Empty (); + public int ZipAlignmentPages { get; set; } = AndroidZipAlign.DefaultZipAlignment64Bit; + [Required, Output] public ITaskItem [] ResolvedAssemblies { get; set; } = Array.Empty (); @@ -325,6 +327,29 @@ string GetLdFlags (NdkTools ndk, AndroidTargetArch arch, int level, string toolP ldFlags.Append ("-s"); } + uint maxPageSize; + switch (arch) { + case AndroidTargetArch.Arm64: + case AndroidTargetArch.X86_64: + maxPageSize = MonoAndroidHelper.ZipAlignmentToPageSize (ZipAlignmentPages); + break; + + case AndroidTargetArch.Arm: + case AndroidTargetArch.X86: + maxPageSize = MonoAndroidHelper.ZipAlignmentToPageSize (AndroidZipAlign.ZipAlignment32Bit); + break; + + default: + throw new InvalidOperationException ($"Internal error: unsupported target architecture {arch}"); + } + + if (ldFlags.Length > 0) { + ldFlags.Append (' '); + } + + ldFlags.Append ("-z "); + ldFlags.Append ($"max-page-size={maxPageSize}"); + return ldFlags.ToString (); } diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs index cddfbfb242a..6fb2dac8967 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs @@ -43,7 +43,7 @@ sealed class InputFiles [Required] public string AndroidBinUtilsDirectory { get; set; } - public int ZipAlignmentPages { get; set; } = AndroidZipAlign.DefaultZipAlignment; + public int ZipAlignmentPages { get; set; } = AndroidZipAlign.DefaultZipAlignment64Bit; public override System.Threading.Tasks.Task RunTaskAsync () { @@ -145,10 +145,12 @@ IEnumerable GetLinkerConfigs () targetLinkerArgs.Clear (); string elf_arch; + uint maxPageSize; switch (abi) { case "armeabi-v7a": targetLinkerArgs.Add ("-X"); elf_arch = "armelf_linux_eabi"; + maxPageSize = MonoAndroidHelper.ZipAlignmentToPageSize (AndroidZipAlign.ZipAlignment32Bit); break; case "arm64": @@ -156,14 +158,17 @@ IEnumerable GetLinkerConfigs () case "aarch64": targetLinkerArgs.Add ("--fix-cortex-a53-843419"); elf_arch = "aarch64linux"; + maxPageSize = MonoAndroidHelper.ZipAlignmentToPageSize (ZipAlignmentPages); break; case "x86": elf_arch = "elf_i386"; + maxPageSize = MonoAndroidHelper.ZipAlignmentToPageSize (AndroidZipAlign.ZipAlignment32Bit); break; case "x86_64": elf_arch = "elf_x86_64"; + maxPageSize = MonoAndroidHelper.ZipAlignmentToPageSize (ZipAlignmentPages); break; default: @@ -186,7 +191,6 @@ IEnumerable GetLinkerConfigs () } } - uint maxPageSize = MonoAndroidHelper.ZipAlignmentToPageSize (ZipAlignmentPages); targetLinkerArgs.Add ("-z"); targetLinkerArgs.Add ($"max-page-size={maxPageSize}"); 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 9f93faf206e..9cd8d26ffc0 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 @@ -63,12 +63,11 @@ public sealed class ApplicationConfig public uint jnienv_registerjninatives_method_token; public uint jni_remapping_replacement_type_count; public uint jni_remapping_replacement_method_index_entry_count; - public uint zip_alignment_mask; public uint mono_components_mask; public string android_package_name = String.Empty; } - const uint ApplicationConfigFieldCount = 27; + const uint ApplicationConfigFieldCount = 26; const string ApplicationConfigSymbolName = "application_config"; const string AppEnvironmentVariablesSymbolName = "app_environment_variables"; @@ -327,17 +326,12 @@ static ApplicationConfig ReadApplicationConfig (EnvironmentFile envFile) 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 24: // zip_alignment_mask: uint32_t / .word | .long - Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); - ret.zip_alignment_mask = ConvertFieldToUInt32 ("zip_alignment_mask", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); - break; - - case 25: // mono_components_mask: uint32_t / .word | .long + case 24: // mono_components_mask: uint32_t / .word | .long Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); ret.mono_components_mask = ConvertFieldToUInt32 ("mono_components_mask", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 26: // android_package_name: string / [pointer type] + case 25: // 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; diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfig.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfig.cs index 2b24f2d0347..96fa8af6f5a 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfig.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfig.cs @@ -55,9 +55,6 @@ sealed class ApplicationConfig public uint jni_remapping_replacement_type_count; public uint jni_remapping_replacement_method_index_entry_count; - // 3, for 4-byte alignment (4k memory pages); 15, for 16-byte alignment (16k memory pages) - public uint zip_alignment_mask; - [NativeAssembler (NumberFormat = LLVMIR.LlvmIrVariableNumberFormat.Hexadecimal)] public uint mono_components_mask; public string android_package_name = String.Empty; diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs index 642f5183573..53140f8cf70 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs @@ -183,7 +183,6 @@ sealed class XamarinAndroidBundledAssembly public int JNIEnvRegisterJniNativesToken { get; set; } public int JniRemappingReplacementTypeCount { get; set; } public int JniRemappingReplacementMethodIndexEntryCount { get; set; } - public uint ZipAlignmentMask { get; set; } public MonoComponent MonoComponents { get; set; } public PackageNamingPolicy PackageNamingPolicy { get; set; } public List NativeLibraries { get; set; } @@ -245,7 +244,6 @@ protected override void Construct (LlvmIrModule module) jnienv_registerjninatives_method_token = (uint)JNIEnvRegisterJniNativesToken, jni_remapping_replacement_type_count = (uint)JniRemappingReplacementTypeCount, jni_remapping_replacement_method_index_entry_count = (uint)JniRemappingReplacementMethodIndexEntryCount, - zip_alignment_mask = ZipAlignmentMask, mono_components_mask = (uint)MonoComponents, android_package_name = AndroidPackageName, }; diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ELFHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ELFHelper.cs index a7a00b4af60..1f1e3abbc24 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ELFHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ELFHelper.cs @@ -1,11 +1,14 @@ using System; using System.Collections.Concurrent; using System.IO; +using System.Text; using ELFSharp; using ELFSharp.ELF; using ELFSharp.ELF.Sections; +using ELFSharp.ELF.Segments; using Microsoft.Android.Build.Tasks; +using Microsoft.Build.Framework; using Microsoft.Build.Utilities; using ELFSymbolType = global::ELFSharp.ELF.Sections.SymbolType; @@ -15,6 +18,84 @@ namespace Xamarin.Android.Tasks { static class ELFHelper { + public static void AssertValidLibraryAlignment (TaskLoggingHelper log, int alignmentInPages, string path, ITaskItem? item) + { + if (String.IsNullOrEmpty (path) || !File.Exists (path)) { + return; + } + + log.LogDebugMessage ($"Checking alignment to {alignmentInPages}k page boundary in shared library {path}"); + try { + AssertValidLibraryAlignment (log, MonoAndroidHelper.ZipAlignmentToPageSize (alignmentInPages), path, ELFReader.Load (path), item); + } catch (Exception ex) { + log.LogWarning ($"Attempt to check whether '{path}' is a correctly aligned ELF file failed with exception, ignoring alignment check for the file."); + log.LogWarningFromException (ex, showStackTrace: true); + } + } + + static void AssertValidLibraryAlignment (TaskLoggingHelper log, uint pageSize, string path, IELF elf, ITaskItem? item) + { + if (elf.Class == Class.Bit32 || elf.Class == Class.NotELF) { + log.LogDebugMessage ($" Not a 64-bit ELF image. Ignored."); + return; + } + + var elf64 = elf as ELF; + if (elf64 == null) { + throw new InvalidOperationException ($"Internal error: {elf} is not ELF"); + } + + // We need to find all segments of Load type and make sure their alignment is as expected. + foreach (ISegment segment in elf64.Segments) { + if (segment.Type != SegmentType.Load) { + continue; + } + + var segment64 = segment as Segment; + if (segment64 == null) { + throw new InvalidOperationException ($"Internal error: {segment} is not Segment"); + } + + // TODO: what happens if the library is aligned at, say, 64k while 16k is required? Should we erorr out? + // We will need more info about that, have to wait till Google formally announce the requirement. + // At this moment the script https://developer.android.com/guide/practices/page-sizes#test they + // provide suggests it's a strict requirement, so we test for equality below. + if (segment64.Alignment == pageSize) { + continue; + } + log.LogDebugMessage ($" expected segment alignment of 0x{pageSize:x}, found 0x{segment64.Alignment:x}"); + + (string packageId, string packageVersion) = GetNugetPackageInfo (); + log.LogCodedWarning ("XA0141", packageId, packageVersion, Path.GetFileName (path)); + break; + } + + (string packageId, string packageVersion) GetNugetPackageInfo () + { + const string Unknown = ""; + + if (item == null) { + return (Unknown, Unknown); + } + + string? metaValue = item.GetMetadata ("NuGetPackageId"); + if (String.IsNullOrEmpty (metaValue)) { + return (Unknown, Unknown); + } + + string id = metaValue; + string version; + metaValue = item.GetMetadata ("NuGetPackageVersion"); + if (!String.IsNullOrEmpty (metaValue)) { + version = metaValue; + } else { + version = Unknown; + } + + return (id, version); + } + } + public static bool IsEmptyAOTLibrary (TaskLoggingHelper log, string path) { if (String.IsNullOrEmpty (path) || !File.Exists (path)) { diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs index 54c1303c1f8..24d113a6b66 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/MonoAndroidHelper.cs @@ -713,7 +713,6 @@ internal static void DumpMarshalMethodsToConsole (string heading, IDictionary ZipAlignmentToMaskOrPageSize (alignment, needMask: true); public static uint ZipAlignmentToPageSize (int alignment) => ZipAlignmentToMaskOrPageSize (alignment, needMask: false); static uint ZipAlignmentToMaskOrPageSize (int alignment, bool needMask) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index a919417c349..3bb913af8f5 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1724,7 +1724,6 @@ because xbuild doesn't support framework reference assemblies. UseAssemblyStore="$(AndroidUseAssemblyStore)" EnableMarshalMethods="$(_AndroidUseMarshalMethods)" CustomBundleConfigFile="$(AndroidBundleConfigurationFile)" - ZipAlignmentPages="$(_AndroidZipAlignment)" > @@ -2011,7 +2010,7 @@ because xbuild doesn't support framework reference assemblies. ApplicationSharedLibraries="@(_ApplicationSharedLibrary)" DebugBuild="$(AndroidIncludeDebugSymbols)" AndroidBinUtilsDirectory="$(AndroidBinUtilsDirectory)" - ZipAlignmentPages="$(_AndroidZipAlignment)" + ZipAlignmentPages="$(AndroidZipAlignment)" /> @@ -2093,6 +2092,7 @@ because xbuild doesn't support framework reference assemblies. IncludeFiles="@(AndroidPackagingOptionsInclude)" ZipFlushFilesLimit="$(_ZipFlushFilesLimit)" ZipFlushSizeLimit="$(_ZipFlushSizeLimit)" + ZipAlignmentPages="$(AndroidZipAlignment)" UseAssemblyStore="$(AndroidUseAssemblyStore)"> @@ -2130,6 +2130,7 @@ because xbuild doesn't support framework reference assemblies. IncludeFiles="@(AndroidPackagingOptionsInclude)" ZipFlushFilesLimit="$(_ZipFlushFilesLimit)" ZipFlushSizeLimit="$(_ZipFlushSizeLimit)" + ZipAlignmentPages="$(AndroidZipAlignment)" UseAssemblyStore="$(AndroidUseAssemblyStore)"> @@ -2356,7 +2357,7 @@ because xbuild doesn't support framework reference assemblies.