Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions Documentation/docs-mobile/messages/xa0141.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
---
title: .NET for Android warning XA0141
description: XA0141 warning code
ms.date: 07/22/2024
ms.date: 01/08/2025
---
# .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
Future versions of Android on arm64 will require that native libraries use 16 KB page sizes.
This requires that the mentioned native libraries be recompiled, and all apps using those
native libraries be rebuilt to contain the fixed versions of the native libraries.

See the Android SDK [Support 16 KB page sizes](https://developer.android.com/guide/practices/page-sizes)
documentation for more information.

## Solution

The indicated native shared library must be recompiled and relinked with the 16k alignment, as per URL indicated in the message.
The indicated native shared library must be recompiled and relinked with the 16k alignment, as per
the Android SDK [Support 16 KB page sizes](https://developer.android.com/guide/practices/page-sizes)
documentation.

## Example messages

> warning XA0141: Android 16 will require 16 KB page sizes, Shared library 'libface_detector_v2_jni.so' does not have a 16 KB page size.
> Please inform the authors of the NuGet package 'Xamarin.GooglePlayServices.Vision.Face.Contour.Internal' version '116.1.0.19'
> which contains 'lib/net8.0-android34.0/play-services-vision-face-contour-internal.aar'.
> See https://developer.android.com/guide/practices/page-sizes for more details.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ projects.
<_AarSearchDirectory Include="@(_ReferencePath->'%(RootDir)%(Directory)')" />
<_AarSearchDirectory Include="@(_ReferenceDependencyPaths->'%(RootDir)%(Directory)')" />
<_AarDistinctDirectory Include="@(_AarSearchDirectory->Distinct())" />
<_AarFromLibraries Include="%(_AarDistinctDirectory.Identity)*.aar" />
<_AarFromLibraries Include="%(_AarDistinctDirectory.Identity)*.aar" NuGetPackageId="%(_AarDistinctDirectory.NuGetPackageId)" NuGetPackageVersion="%(_AarDistinctDirectory.NuGetPackageVersion)"/>
</ItemGroup>
<ItemGroup Condition=" '@(_AarFromLibraries->Count())' != '0' ">
<!--
Expand Down
5 changes: 3 additions & 2 deletions src/Xamarin.Android.Build.Tasks/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1063,11 +1063,12 @@ To use a custom JDK path for a command line build, set the 'JavaSdkDirectory' MS
{1} - NuGet package version</comment>
</data>
<data name="XA0141" xml:space="preserve">
<value>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</value>
<value>Android 16 will require 16 KB page sizes, shared library '{3}' does not have a 16 KB page size. Please inform the authors of the NuGet package '{0}' version '{1}' which contains '{2}'. See https://developer.android.com/guide/practices/page-sizes for more details.</value>
<comment>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
{2} - Source location path
{3} - shared library file name
</comment>
</data>
<data name="XA4249" xml:space="preserve">
Expand Down
55 changes: 37 additions & 18 deletions src/Xamarin.Android.Build.Tasks/Tasks/GetImportedLibraries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class GetImportedLibraries : AndroidTask
};

[Required]
public string TargetDirectory { get; set; }
public ITaskItem[] ExtractedDirectories { get; set; }

public string CacheFile { get; set;}

Expand All @@ -35,22 +35,37 @@ public class GetImportedLibraries : AndroidTask

public override bool RunTask ()
{
if (!Directory.Exists (TargetDirectory)) {
Log.LogDebugMessage ("Target directory was not found");
return true;
}

var manifestDocuments = new List<ITaskItem> ();
var nativeLibraries = new List<ITaskItem> ();
var jarFiles = new List<ITaskItem> ();
foreach (var file in Directory.EnumerateFiles (TargetDirectory, "*", SearchOption.AllDirectories)) {
if (file.EndsWith (".so", StringComparison.OrdinalIgnoreCase)) {
if (AndroidRidAbiHelper.GetNativeLibraryAbi (file) != null)
nativeLibraries.Add (new TaskItem (file));
} else if (file.EndsWith (".jar", StringComparison.OrdinalIgnoreCase)) {
jarFiles.Add (new TaskItem (file));
} else if (file.EndsWith (".xml", StringComparison.OrdinalIgnoreCase)) {
if (Path.GetFileName (file) == "AndroidManifest.xml") {
foreach (var extractedDirectory in ExtractedDirectories) {
if (!Directory.Exists (extractedDirectory.ItemSpec)) {
continue;
}
string originalFile = extractedDirectory.GetMetadata (ResolveLibraryProjectImports.OriginalFile);
string nuGetPackageId = extractedDirectory.GetMetadata (ResolveLibraryProjectImports.NuGetPackageId);
string nuGetPackageVersion = extractedDirectory.GetMetadata (ResolveLibraryProjectImports.NuGetPackageVersion);
foreach (var file in Directory.EnumerateFiles (extractedDirectory.ItemSpec, "*", SearchOption.AllDirectories)) {
if (file.EndsWith (".so", StringComparison.OrdinalIgnoreCase)) {
if (AndroidRidAbiHelper.GetNativeLibraryAbi (file) != null)
nativeLibraries.Add (new TaskItem (file, new Dictionary<string, string> {
[ResolveLibraryProjectImports.OriginalFile] = originalFile,
[ResolveLibraryProjectImports.NuGetPackageId] = nuGetPackageId,
[ResolveLibraryProjectImports.NuGetPackageVersion] = nuGetPackageVersion,
}));
continue;
}
if (file.EndsWith (".jar", StringComparison.OrdinalIgnoreCase)) {
jarFiles.Add (new TaskItem (file, new Dictionary<string, string> {
[ResolveLibraryProjectImports.OriginalFile] = originalFile,
[ResolveLibraryProjectImports.NuGetPackageId] = nuGetPackageId,
[ResolveLibraryProjectImports.NuGetPackageVersion] = nuGetPackageVersion,
}));
continue;
}
if (file.EndsWith (".xml", StringComparison.OrdinalIgnoreCase)) {
if (Path.GetFileName (file) != "AndroidManifest.xml")
continue;
// there could be ./AndroidManifest.xml and bin/AndroidManifest.xml, which will be the same. So, ignore "bin" ones.
var directory = Path.GetFileName (Path.GetDirectoryName (file));
if (IgnoredManifestDirectories.Contains (directory))
Expand All @@ -60,7 +75,11 @@ public override bool RunTask ()
Log.LogCodedWarning ("XA4315", file, 0, Properties.Resources.XA4315, file);
continue;
}
manifestDocuments.Add (new TaskItem (file));
manifestDocuments.Add (new TaskItem (file, new Dictionary<string, string> {
[ResolveLibraryProjectImports.OriginalFile] = originalFile,
[ResolveLibraryProjectImports.NuGetPackageId] = nuGetPackageId,
[ResolveLibraryProjectImports.NuGetPackageVersion] = nuGetPackageVersion,
}));
}
}
}
Expand All @@ -73,9 +92,9 @@ public override bool RunTask ()
var document = new XDocument (
new XDeclaration ("1.0", "UTF-8", null),
new XElement ("Paths",
new XElement ("ManifestDocuments", ManifestDocuments.Select(e => new XElement ("ManifestDocument", e.ItemSpec))),
new XElement ("NativeLibraries", NativeLibraries.Select(e => new XElement ("NativeLibrary", e.ItemSpec))),
new XElement ("Jars", Jars.Select(e => new XElement ("Jar", e.ItemSpec)))
new XElement ("ManifestDocuments", ManifestDocuments.ToXElements ("ManifestDocument", ResolveLibraryProjectImports.KnownMetadata)),
new XElement ("NativeLibraries", NativeLibraries.ToXElements ("NativeLibrary", ResolveLibraryProjectImports.KnownMetadata)),
new XElement ("Jars", Jars.ToXElements ("Jar", ResolveLibraryProjectImports.KnownMetadata))
));
document.SaveIfChanged (CacheFile);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ public class ReadLibraryProjectImportsCache : AndroidTask
[Output]
public ITaskItem [] ProguardConfigFiles { get; set; }

[Output]
public ITaskItem [] ExtractedDirectories { get; set; }

public override bool RunTask ()
{
Log.LogDebugMessage ("Task ReadLibraryProjectImportsCache");
Expand All @@ -74,13 +77,15 @@ public override bool RunTask ()
ResolvedResourceDirectoryStamps = doc.GetPathsAsTaskItems ("ResolvedResourceDirectoryStamps"
, "ResolvedResourceDirectoryStamp");
ProguardConfigFiles = doc.GetPathsAsTaskItems ("ProguardConfigFiles", "ProguardConfigFile");
ExtractedDirectories = doc.GetPathsAsTaskItems ("ExtractedDirectories", "ExtractedDirectory");

Log.LogDebugTaskItems (" Jars: ", Jars);
Log.LogDebugTaskItems (" ResolvedAssetDirectories: ", ResolvedAssetDirectories);
Log.LogDebugTaskItems (" ResolvedResourceDirectories: ", ResolvedResourceDirectories);
Log.LogDebugTaskItems (" ResolvedEnvironmentFiles: ", ResolvedEnvironmentFiles);
Log.LogDebugTaskItems (" ResolvedResourceDirectoryStamps: ", ResolvedResourceDirectoryStamps);
Log.LogDebugTaskItems (" ProguardConfigFiles: ", ProguardConfigFiles);
Log.LogDebugTaskItems (" ExtractedDirectories: ", ExtractedDirectories);

return !Log.HasLoggedErrors;
}
Expand Down
Loading
Loading