Skip to content

Commit

Permalink
[Xamarin.Android.Build.Tasks] Add %(NuGetPackage*) to TaskItems (#9559)
Browse files Browse the repository at this point in the history
Fixes: #9544

Context: 64bb147

[Google announced][0] that future versions of Android would require
that native libraries use 16 KB page sizes on arm64.  At present, the
timeline for *when* 16 KB page sizes will be required is unknown,
though we assume it will be with Android 16 or later.

In order to get ahead of this, .NET 9 added an XA0141 warning in
64bb147.

The problem is, this warning is not entirely actionable:

	dotnet new android
	dotnet add package Xamarin.GooglePlayServices.Vision.Face.Contour.Internal --version 116.1.0.19
	dotnet build -c Release

results in:

	warning XA0141: NuGet package '<unknown>' version '<unknown>' contains a shared library 'libface_detector_v2_jni.so'
	  which is not correctly aligned. See https://developer.android.com/guide/practices/page-sizes for more details
	warning XA0141: NuGet package '<unknown>' version '<unknown>' contains a shared library 'libface_detector_v2_jni.so'
	  which is not correctly aligned. See https://developer.android.com/guide/practices/page-sizes for more details

What are customers supposed to *do* with this?

The original assumption was that the NuGet package and Version would
be available as metadata items on the MSBuild Items.  Unfortunately
that was not the case, so the data the user gets is empty.

Add the required metadata to all NuGet Package references resolved by
the project.  This will allow us to propagate that data throughout
the build Items as they are transformed.  This means we can provide a
decent error message to the user:

	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.

[0]: https://android-developers.googleblog.com/2024/08/adding-16-kb-page-size-to-android.html
  • Loading branch information
dellis1972 authored and jonpryor committed Jan 28, 2025
1 parent ace5169 commit 63cfce4
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 70 deletions.
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: 22/07/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 @@ -1072,11 +1072,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

0 comments on commit 63cfce4

Please # to comment.