Skip to content

Commit d50b519

Browse files
[Xamarin.Android.Build.Tasks] skip proguard.txt files in !app (#8025)
Context: c537dd2 Context: dotnet/android-libraries#729 Context: xamarin/GooglePlayServicesComponents#774 A customer reported a build error such as: C:\Program Files\dotnet\packs\Microsoft.Android.Sdk.Windows\33.0.46\targets\Microsoft.Android.Sdk.AndroidLibraries.targets(77,5): error XACAAR7014: System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown. at System.Text.StringBuilder.ToString() at Xamarin.Android.Tasks.CreateAar.RunTask() at Microsoft.Android.Build.Tasks.AndroidTask.Execute() Somewhere within [`<CreateAar/>`][0]: if (ProguardConfigurationFiles != null) { var sb = new StringBuilder (); foreach (var file in ProguardConfigurationFiles) { sb.AppendLine (File.ReadAllText (file.ItemSpec)); } aar.AddEntry ("proguard.txt", sb.ToString (), Files.UTF8withoutBOM); } The problem appears to be triggered by: 1. Library project `Lib.csproj` which bind `.aar` files include the `proguard.txt` from the `.aar` into the output `Lib.aar`, as `Lib.aar!proguard.txt`. 2. Library project `References.csproj` which has a `@(Reference)` to `Lib.csproj` will include the contents of `Lib.aar!proguard.txt` into `References.aar!proguard.txt`. If `References.csproj` has a `@(PackageReference)` which has `AnotherLib.aar`, then `AnotherLib.aar!proguard.txt` will *also* be copied into `References.aar!proguard.txt`. (Repeat for all `@(Reference)` and `@(projectreference)`.) (Note combinatorial explosion in `proguard.txt` size…) 3. App project `App.csproj` references (2), merging all the contents of all the `proguard.txt` files from all the `.aar` files into a single unified `proguard.txt` file. If the project has lots of library projects or package references, step (3) could OOM. "Lots" of references, such as: ProguardConfigurationFiles= ~\.nuget\packages\xamarin.androidx.versionedparcelable\1.1.1.15\buildTransitive\net6.0-android31.0\..\..\proguard\proguard.txt ~\.nuget\packages\xamarin.androidx.lifecycle.runtime\2.5.1.1\buildTransitive\net6.0-android31.0\..\..\proguard\proguard.txt ~\.nuget\packages\xamarin.androidx.core\1.9.0.1\buildTransitive\net6.0-android31.0\..\..\proguard\proguard.txt ~\.nuget\packages\xamarin.androidx.savedstate\1.2.0.1\buildTransitive\net6.0-android31.0\..\..\proguard\proguard.txt ~\.nuget\packages\xamarin.androidx.recyclerview\1.2.1.7\buildTransitive\net6.0-android31.0\..\..\proguard\proguard.txt ~\.nuget\packages\xamarin.androidx.lifecycle.viewmodel\2.5.1.1\buildTransitive\net6.0-android31.0\..\..\proguard\proguard.txt ~\.nuget\packages\xamarin.androidx.lifecycle.viewmodelsavedstate\2.5.1.1\buildTransitive\net6.0-android31.0\..\..\proguard\proguard.txt ~\.nuget\packages\xamarin.androidx.fragment\1.5.3.1\buildTransitive\net6.0-android31.0\..\..\proguard\proguard.txt ~\.nuget\packages\xamarin.androidx.vectordrawable.animated\1.1.0.14\buildTransitive\net6.0-android31.0\..\..\proguard\proguard.txt ~\.nuget\packages\xamarin.androidx.transition\1.4.1.8\buildTransitive\net6.0-android31.0\..\..\proguard\proguard.txt ~\.nuget\packages\xamarin.androidx.startup.startupruntime\1.1.1.2\buildTransitive\net6.0-android31.0\..\..\proguard\proguard.txt ~\.nuget\packages\xamarin.androidx.lifecycle.process\2.5.1\buildTransitive\net6.0-android31.0\..\..\proguard\proguard.txt ~\.nuget\packages\xamarin.androidx.coordinatorlayout\1.2.0.3\buildTransitive\net6.0-android31.0\..\..\proguard\proguard.txt ~\.nuget\packages\xamarin.androidx.appcompat\1.5.1\buildTransitive\net6.0-android31.0\..\..\proguard\proguard.txt ~\.nuget\packages\xamarin.google.android.material\1.7.0\buildTransitive\net6.0-android31.0\..\..\proguard\proguard.txt ~\.nuget\packages\xamarin.androidx.window\1.0.0.10\buildTransitive\net6.0-android31.0\..\..\proguard\proguard.txt ~\.nuget\packages\xamarin.androidx.navigation.common\2.5.2.1\buildTransitive\net6.0-android31.0\..\..\proguard\proguard.txt ~\.nuget\packages\xamarin.androidx.navigation.ui\2.5.2.1\buildTransitive\net6.0-android31.0\..\..\proguard\proguard.txt ~\.nuget\packages\xamarin.androidx.media\1.6.0.2\buildTransitive\net6.0-android31.0\..\..\proguard\proguard.txt ..\path\to\projectreference\obj\Debug\lp\160\jl\proguard.txt ..\path\to\projectreference\obj\Debug\lp\155\jl\proguard.txt ..\path\to\projectreference\obj\Debug\lp\161\jl\proguard.txt ..\path\to\projectreference\obj\Debug\lp\162\jl\proguard.txt ..\path\to\projectreference\obj\Debug\lp\156\jl\proguard.txt ..\path\to\projectreference\obj\Debug\lp\157\jl\proguard.txt ..\path\to\projectreference\obj\Debug\lp\163\jl\proguard.txt ..\path\to\projectreference\obj\Debug\lp\164\jl\proguard.txt ..\path\to\projectreference\obj\Debug\lp\165\jl\proguard.txt ..\path\to\projectreference\obj\Debug\lp\166\jl\proguard.txt ..\path\to\projectreference\obj\Debug\lp\167\jl\proguard.txt ..\path\to\projectreference\obj\Debug\lp\170\jl\proguard.txt ..\path\to\projectreference\obj\Debug\lp\168\jl\proguard.txt ..\path\to\projectreference\obj\Debug\lp\169\jl\proguard.txt ..\path\to\projectreference\obj\Debug\lp\171\jl\proguard.txt ..\path\to\projectreference\obj\Debug\lp\172\jl\proguard.txt ..\path\to\projectreference\obj\Debug\lp\173\jl\proguard.txt … I believe this problem was partially introduced in c537dd2, but we didn't notice until now. The AndroidX NuGet packages also cause this problem, but in a different way as seen in dotnet/android-libraries#729 and xamarin/GooglePlayServicesComponents#774. A solution here is that `<ResolveLibraryProjectImports/>` should simply ignore `proguard.txt` files in class libraries. They are only actually needed in "app" projects where the `<R8/>` MSBuild task would use them. I could reproduce this in a test using an `.aar` from maven that contains a `proguard.txt`: * <https://mvnrepository.com/artifact/androidx.core/core/1.10.0> And then just assert the `proguard.txt` contents don't make it to `MyClassLibrary.aar`. Note: dotnet/android-libraries#729 and xamarin/GooglePlayServicesComponents#774 update the NuGet Packages so that `proguard.txt` files are only added to `@(ProguardConfiguration)` when `$(AndroidApplication)`=True. This should also help prevent the OOM scenario. [0]: https://github.com/xamarin/xamarin-android/blob/c31f3eda63a16e412a39fa61eb0f885be3c5f543/src/Xamarin.Android.Build.Tasks/Tasks/CreateAar.cs#L108-L114
1 parent af57c52 commit d50b519

File tree

4 files changed

+22
-4
lines changed

4 files changed

+22
-4
lines changed

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ public class ResolveLibraryProjectImports : AndroidTask
4444
[Required]
4545
public bool DesignTimeBuild { get; set; }
4646

47+
public bool AndroidApplication { get; set; }
48+
4749
[Output]
4850
public ITaskItem [] Jars { get; set; }
4951

@@ -442,7 +444,7 @@ void Extract (
442444
resolvedAssetDirectories.Add (new TaskItem (Path.GetFullPath (assetsDir), new Dictionary<string, string> {
443445
{ OriginalFile, aarFullPath },
444446
}));
445-
if (File.Exists (proguardFile)) {
447+
if (AndroidApplication && File.Exists (proguardFile)) {
446448
proguardConfigFiles.Add (new TaskItem (Path.GetFullPath (proguardFile), new Dictionary<string, string> {
447449
{ OriginalFile, aarFullPath },
448450
}));

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/AssertionExtensions.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,19 @@ public static void AssertTargetIsPartiallyBuilt (this BuildOutput output, string
5454
Assert.IsTrue (output.IsTargetPartiallyBuilt (target), $"The target {target} should have been partially built.");
5555
}
5656

57+
[DebuggerHidden]
58+
public static void AssertEntryEquals (this ZipArchive zip, string zipPath, string archivePath, string expected)
59+
{
60+
zip.AssertContainsEntry (zipPath, archivePath);
61+
62+
var entry = zip.ReadEntry (archivePath);
63+
using var stream = new MemoryStream ();
64+
entry.Extract (stream);
65+
stream.Position = 0;
66+
using var reader = new StreamReader (stream);
67+
Assert.AreEqual (expected, reader.ReadToEnd ().Trim ());
68+
}
69+
5770
[DebuggerHidden]
5871
public static void AssertContainsEntry (this ZipArchive zip, string zipPath, string archivePath)
5972
{

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public void DotNetBuildLibrary (bool isRelease, bool duplicateAar, bool useDesig
7979
BinaryContent = () => XamarinAndroidApplicationProject.icon_binary_mdpi,
8080
},
8181
new AndroidItem.ProguardConfiguration ("proguard.txt") {
82-
TextContent = () => @"-ignorewarnings",
82+
TextContent = () => "# LibraryC",
8383
},
8484
}
8585
};
@@ -97,7 +97,7 @@ public void DotNetBuildLibrary (bool isRelease, bool duplicateAar, bool useDesig
9797
FileAssert.Exists (aarPath);
9898
using (var aar = ZipHelper.OpenZip (aarPath)) {
9999
aar.AssertContainsEntry (aarPath, "assets/bar/bar.txt");
100-
aar.AssertContainsEntry (aarPath, "proguard.txt");
100+
aar.AssertEntryEquals (aarPath, "proguard.txt", "# LibraryC");
101101
}
102102

103103
var libB = new XASdkProject (outputType: "Library") {
@@ -139,7 +139,7 @@ public Foo ()
139139
TextContent = () => ResourceData.JavaSourceTestExtension,
140140
},
141141
new AndroidItem.ProguardConfiguration ("proguard.txt") {
142-
TextContent = () => @"-ignorewarnings",
142+
TextContent = () => "# LibraryB",
143143
},
144144
}
145145
};
@@ -185,6 +185,8 @@ public Foo ()
185185
aar.AssertContainsEntry (aarPath, $"libs/{projectJarHash}.jar");
186186
aar.AssertContainsEntry (aarPath, "jni/arm64-v8a/libfoo.so");
187187
aar.AssertContainsEntry (aarPath, "jni/x86/libfoo.so");
188+
// proguard.txt from Library C should not flow to Library B and "double"
189+
aar.AssertEntryEquals (aarPath, "proguard.txt", "# LibraryB");
188190
}
189191

190192
// Check EmbeddedResource files do not exist

src/Xamarin.Android.Build.Tasks/Xamarin.Android.EmbeddedResource.targets

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ This file is used by all project types, including binding projects.
3838
Outputs="$(_AndroidStampDirectory)_ResolveLibraryProjectImports.stamp">
3939
<ResolveLibraryProjectImports
4040
ContinueOnError="$(DesignTimeBuild)"
41+
AndroidApplication="$(AndroidApplication)"
4142
CacheFile="$(_AndroidLibraryProjectImportsCache)"
4243
DesignTimeBuild="$(DesignTimeBuild)"
4344
Assemblies="@(_MonoAndroidReferencePath);@(_MonoAndroidReferenceDependencyPaths)"

0 commit comments

Comments
 (0)