Skip to content

Commit d18c306

Browse files
authored
[Xamarin.Android.Build.Tasks] Add %(NuGetPackage*) to TaskItems (#9559)
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
1 parent 44021d1 commit d18c306

File tree

9 files changed

+192
-70
lines changed

9 files changed

+192
-70
lines changed
Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,28 @@
11
---
22
title: .NET for Android warning XA0141
33
description: XA0141 warning code
4-
ms.date: 07/22/2024
4+
ms.date: 01/08/2025
55
---
66
# .NET for Android warning XA0141
77

88
## Issue
99

10-
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
10+
Future versions of Android on arm64 will require that native libraries use 16 KB page sizes.
11+
This requires that the mentioned native libraries be recompiled, and all apps using those
12+
native libraries be rebuilt to contain the fixed versions of the native libraries.
13+
14+
See the Android SDK [Support 16 KB page sizes](https://developer.android.com/guide/practices/page-sizes)
15+
documentation for more information.
1116

1217
## Solution
1318

14-
The indicated native shared library must be recompiled and relinked with the 16k alignment, as per URL indicated in the message.
19+
The indicated native shared library must be recompiled and relinked with the 16k alignment, as per
20+
the Android SDK [Support 16 KB page sizes](https://developer.android.com/guide/practices/page-sizes)
21+
documentation.
22+
23+
## Example messages
24+
25+
> 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.
26+
> Please inform the authors of the NuGet package 'Xamarin.GooglePlayServices.Vision.Face.Contour.Internal' version '116.1.0.19'
27+
> which contains 'lib/net8.0-android34.0/play-services-vision-face-contour-internal.aar'.
28+
> See https://developer.android.com/guide/practices/page-sizes for more details.

src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AndroidLibraries.targets

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ projects.
2323
<_AarSearchDirectory Include="@(_ReferencePath->'%(RootDir)%(Directory)')" />
2424
<_AarSearchDirectory Include="@(_ReferenceDependencyPaths->'%(RootDir)%(Directory)')" />
2525
<_AarDistinctDirectory Include="@(_AarSearchDirectory->Distinct())" />
26-
<_AarFromLibraries Include="%(_AarDistinctDirectory.Identity)*.aar" />
26+
<_AarFromLibraries Include="%(_AarDistinctDirectory.Identity)*.aar" NuGetPackageId="%(_AarDistinctDirectory.NuGetPackageId)" NuGetPackageVersion="%(_AarDistinctDirectory.NuGetPackageVersion)"/>
2727
</ItemGroup>
2828
<ItemGroup Condition=" '@(_AarFromLibraries->Count())' != '0' ">
2929
<!--

src/Xamarin.Android.Build.Tasks/Properties/Resources.resx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,11 +1063,12 @@ To use a custom JDK path for a command line build, set the 'JavaSdkDirectory' MS
10631063
{1} - NuGet package version</comment>
10641064
</data>
10651065
<data name="XA0141" xml:space="preserve">
1066-
<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>
1066+
<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>
10671067
<comment>The following is a literal name and should not be translated: NuGet
10681068
{0} - NuGet package id
10691069
{1} - NuGet package version
1070-
{2} - shared library file name
1070+
{2} - Source location path
1071+
{3} - shared library file name
10711072
</comment>
10721073
</data>
10731074
<data name="XA4249" xml:space="preserve">

src/Xamarin.Android.Build.Tasks/Tasks/GetImportedLibraries.cs

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ public class GetImportedLibraries : AndroidTask
2020
};
2121

2222
[Required]
23-
public string TargetDirectory { get; set; }
23+
public ITaskItem[] ExtractedDirectories { get; set; }
2424

2525
public string CacheFile { get; set;}
2626

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

3636
public override bool RunTask ()
3737
{
38-
if (!Directory.Exists (TargetDirectory)) {
39-
Log.LogDebugMessage ("Target directory was not found");
40-
return true;
41-
}
42-
4338
var manifestDocuments = new List<ITaskItem> ();
4439
var nativeLibraries = new List<ITaskItem> ();
4540
var jarFiles = new List<ITaskItem> ();
46-
foreach (var file in Directory.EnumerateFiles (TargetDirectory, "*", SearchOption.AllDirectories)) {
47-
if (file.EndsWith (".so", StringComparison.OrdinalIgnoreCase)) {
48-
if (AndroidRidAbiHelper.GetNativeLibraryAbi (file) != null)
49-
nativeLibraries.Add (new TaskItem (file));
50-
} else if (file.EndsWith (".jar", StringComparison.OrdinalIgnoreCase)) {
51-
jarFiles.Add (new TaskItem (file));
52-
} else if (file.EndsWith (".xml", StringComparison.OrdinalIgnoreCase)) {
53-
if (Path.GetFileName (file) == "AndroidManifest.xml") {
41+
foreach (var extractedDirectory in ExtractedDirectories) {
42+
if (!Directory.Exists (extractedDirectory.ItemSpec)) {
43+
continue;
44+
}
45+
string originalFile = extractedDirectory.GetMetadata (ResolveLibraryProjectImports.OriginalFile);
46+
string nuGetPackageId = extractedDirectory.GetMetadata (ResolveLibraryProjectImports.NuGetPackageId);
47+
string nuGetPackageVersion = extractedDirectory.GetMetadata (ResolveLibraryProjectImports.NuGetPackageVersion);
48+
foreach (var file in Directory.EnumerateFiles (extractedDirectory.ItemSpec, "*", SearchOption.AllDirectories)) {
49+
if (file.EndsWith (".so", StringComparison.OrdinalIgnoreCase)) {
50+
if (AndroidRidAbiHelper.GetNativeLibraryAbi (file) != null)
51+
nativeLibraries.Add (new TaskItem (file, new Dictionary<string, string> {
52+
[ResolveLibraryProjectImports.OriginalFile] = originalFile,
53+
[ResolveLibraryProjectImports.NuGetPackageId] = nuGetPackageId,
54+
[ResolveLibraryProjectImports.NuGetPackageVersion] = nuGetPackageVersion,
55+
}));
56+
continue;
57+
}
58+
if (file.EndsWith (".jar", StringComparison.OrdinalIgnoreCase)) {
59+
jarFiles.Add (new TaskItem (file, new Dictionary<string, string> {
60+
[ResolveLibraryProjectImports.OriginalFile] = originalFile,
61+
[ResolveLibraryProjectImports.NuGetPackageId] = nuGetPackageId,
62+
[ResolveLibraryProjectImports.NuGetPackageVersion] = nuGetPackageVersion,
63+
}));
64+
continue;
65+
}
66+
if (file.EndsWith (".xml", StringComparison.OrdinalIgnoreCase)) {
67+
if (Path.GetFileName (file) != "AndroidManifest.xml")
68+
continue;
5469
// there could be ./AndroidManifest.xml and bin/AndroidManifest.xml, which will be the same. So, ignore "bin" ones.
5570
var directory = Path.GetFileName (Path.GetDirectoryName (file));
5671
if (IgnoredManifestDirectories.Contains (directory))
@@ -60,7 +75,11 @@ public override bool RunTask ()
6075
Log.LogCodedWarning ("XA4315", file, 0, Properties.Resources.XA4315, file);
6176
continue;
6277
}
63-
manifestDocuments.Add (new TaskItem (file));
78+
manifestDocuments.Add (new TaskItem (file, new Dictionary<string, string> {
79+
[ResolveLibraryProjectImports.OriginalFile] = originalFile,
80+
[ResolveLibraryProjectImports.NuGetPackageId] = nuGetPackageId,
81+
[ResolveLibraryProjectImports.NuGetPackageVersion] = nuGetPackageVersion,
82+
}));
6483
}
6584
}
6685
}
@@ -73,9 +92,9 @@ public override bool RunTask ()
7392
var document = new XDocument (
7493
new XDeclaration ("1.0", "UTF-8", null),
7594
new XElement ("Paths",
76-
new XElement ("ManifestDocuments", ManifestDocuments.Select(e => new XElement ("ManifestDocument", e.ItemSpec))),
77-
new XElement ("NativeLibraries", NativeLibraries.Select(e => new XElement ("NativeLibrary", e.ItemSpec))),
78-
new XElement ("Jars", Jars.Select(e => new XElement ("Jar", e.ItemSpec)))
95+
new XElement ("ManifestDocuments", ManifestDocuments.ToXElements ("ManifestDocument", ResolveLibraryProjectImports.KnownMetadata)),
96+
new XElement ("NativeLibraries", NativeLibraries.ToXElements ("NativeLibrary", ResolveLibraryProjectImports.KnownMetadata)),
97+
new XElement ("Jars", Jars.ToXElements ("Jar", ResolveLibraryProjectImports.KnownMetadata))
7998
));
8099
document.SaveIfChanged (CacheFile);
81100
}

src/Xamarin.Android.Build.Tasks/Tasks/ReadLibraryProjectImportsCache.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ public class ReadLibraryProjectImportsCache : AndroidTask
5858
[Output]
5959
public ITaskItem [] ProguardConfigFiles { get; set; }
6060

61+
[Output]
62+
public ITaskItem [] ExtractedDirectories { get; set; }
63+
6164
public override bool RunTask ()
6265
{
6366
Log.LogDebugMessage ("Task ReadLibraryProjectImportsCache");
@@ -74,13 +77,15 @@ public override bool RunTask ()
7477
ResolvedResourceDirectoryStamps = doc.GetPathsAsTaskItems ("ResolvedResourceDirectoryStamps"
7578
, "ResolvedResourceDirectoryStamp");
7679
ProguardConfigFiles = doc.GetPathsAsTaskItems ("ProguardConfigFiles", "ProguardConfigFile");
80+
ExtractedDirectories = doc.GetPathsAsTaskItems ("ExtractedDirectories", "ExtractedDirectory");
7781

7882
Log.LogDebugTaskItems (" Jars: ", Jars);
7983
Log.LogDebugTaskItems (" ResolvedAssetDirectories: ", ResolvedAssetDirectories);
8084
Log.LogDebugTaskItems (" ResolvedResourceDirectories: ", ResolvedResourceDirectories);
8185
Log.LogDebugTaskItems (" ResolvedEnvironmentFiles: ", ResolvedEnvironmentFiles);
8286
Log.LogDebugTaskItems (" ResolvedResourceDirectoryStamps: ", ResolvedResourceDirectoryStamps);
8387
Log.LogDebugTaskItems (" ProguardConfigFiles: ", ProguardConfigFiles);
88+
Log.LogDebugTaskItems (" ExtractedDirectories: ", ExtractedDirectories);
8489

8590
return !Log.HasLoggedErrors;
8691
}

0 commit comments

Comments
 (0)