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.