Skip to content

Commit f51fbae

Browse files
Fix R8 JNI seed configuration inputs
Build the seed R8 configuration from user and library consumer rules instead of final generated configuration, whose baseline native-method rule pins ACW names. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent 7c15701 commit f51fbae

4 files changed

Lines changed: 49 additions & 6 deletions

File tree

src/Xamarin.Android.Build.Tasks/MSBuild/Xamarin/Android/Xamarin.Android.Aapt2.targets

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,9 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved.
245245
ProguardRuleOutput="$(_Aapt2ProguardRules)"
246246
/>
247247
<ItemGroup Condition=" '$(_Aapt2ProguardRules)' != '' And Exists('$(_Aapt2ProguardRules)') ">
248-
<ProguardConfiguration Include="$(_Aapt2ProguardRules)" />
248+
<ProguardConfiguration Include="$(_Aapt2ProguardRules)">
249+
<AndroidGeneratedProguardConfiguration>true</AndroidGeneratedProguardConfiguration>
250+
</ProguardConfiguration>
249251
<FileWrites Include="$(_Aapt2ProguardRules)" />
250252
<FileWrites Include="$(IntermediateOutputPath)android\*\aapt_rules.txt" />
251253
</ItemGroup>

src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.Trimmable.targets

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,16 @@
122122

123123
<Target Name="_AndroidGenerateR8JniSeedMappingInputs"
124124
Condition=" '$(_AndroidEnableR8JniNameRewriting)' == 'true' "
125-
DependsOnTargets="_AndroidCompileR8JniSeedJava;_CalculateProguardConfigurationFiles">
125+
DependsOnTargets="_AndroidCompileR8JniSeedJava">
126126
<ItemGroup>
127127
<_AndroidR8JniSeedClassFile Include="$(_AndroidR8JniSeedJavaClassDirectory)**\*.class" />
128-
<_AndroidR8JniSeedProguardConfiguration Include="@(_ProguardConfiguration)" />
129-
<_AndroidR8JniSeedProguardConfiguration Remove="$(IntermediateOutputPath)proguard\proguard_xamarin.cfg;$(_ProguardProjectConfiguration);$(IntermediateOutputPath)proguard\proguard_project_primary.cfg;$(IntermediateOutputPath)aapt_rules.txt" />
128+
<!-- Seed R8 already disables tree shaking and optimization. Do not use proguard-android.txt:
129+
its native-method rule preserves ACW names. Start from source items so generated ACW,
130+
reachability, primary, Xamarin, and aapt configurations cannot leak into this pass. -->
131+
<_AndroidR8JniSeedProguardConfiguration Include="$(ProguardConfigFiles)" Condition=" '$(ProguardConfigFiles)' != '' " />
132+
<_AndroidR8JniSeedProguardConfiguration
133+
Include="@(ProguardConfiguration)"
134+
Condition=" '$(ProguardConfigFiles)' == '' and '%(ProguardConfiguration.AndroidGeneratedProguardConfiguration)' != 'true' " />
130135
<_AndroidR8JniSeedMapDiagnostics Condition=" '$(AndroidR8IgnoreWarnings)' == 'true' " Include="warning" To="info" />
131136
</ItemGroup>
132137
</Target>

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,12 @@ public void GenerateSeedMappingAllowsAcwObfuscation ()
6565
string applicationConfiguration = Path.Combine (path, "acw-keep.cfg");
6666
string commonConfiguration = Path.Combine (path, "xamarin.cfg");
6767
string customConfiguration = Path.Combine (path, "custom.cfg");
68+
string aarConfiguration = Path.Combine (path, "aar-proguard.txt");
6869
File.WriteAllText (acwMap, "Managed.Peer;com.example.Peer");
6970
File.WriteAllText (customConfiguration, "-dontwarn com.example.**");
71+
File.WriteAllText (aarConfiguration, "-dontwarn com.example.library.**");
72+
var aarConfigurationItem = new TaskItem (aarConfiguration);
73+
aarConfigurationItem.SetMetadata ("OriginalFile", Path.Combine (path, "library.aar"));
7074

7175
var task = new R8TestTask {
7276
BuildEngine = new MockBuildEngine (TestContext.Out),
@@ -77,7 +81,7 @@ public void GenerateSeedMappingAllowsAcwObfuscation ()
7781
ProguardGeneratedApplicationConfiguration = applicationConfiguration,
7882
ProguardCommonXamarinConfiguration = commonConfiguration,
7983
ProguardMappingFileOutput = Path.Combine (path, "mapping.txt"),
80-
ProguardConfigurationFiles = new ITaskItem [] { new TaskItem (customConfiguration) },
84+
ProguardConfigurationFiles = new ITaskItem [] { new TaskItem (customConfiguration), aarConfigurationItem },
8185
GenerateSeedMapping = true,
8286
EnableObfuscation = true,
8387
IgnoreWarnings = true,
@@ -94,6 +98,7 @@ public void GenerateSeedMappingAllowsAcwObfuscation ()
9498
string configuration = string.Join (Environment.NewLine, configurationFiles.Select (File.ReadAllText));
9599

96100
Assert.That (configurationFiles, Does.Contain (customConfiguration), "Seed R8 should honor user ProGuard rules.");
101+
Assert.That (configurationFiles, Does.Contain (aarConfiguration), "Seed R8 should honor AAR consumer rules.");
97102
Assert.That (configurationFiles, Does.Contain (commonConfiguration), "Seed R8 should honor runtime keep rules.");
98103
Assert.That (configurationFiles, Does.Not.Contain (applicationConfiguration), "Seed R8 must not pass the ACW keep configuration.");
99104
FileAssert.DoesNotExist (applicationConfiguration, "Seed R8 must not generate obfuscation-blocking ACW keep rules.");

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

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,9 @@ public R8JniLibraryPeer () { }
333333
},
334334
};
335335
library.SetRuntime (runtime);
336+
library.OtherBuildItems.Add (new AndroidItem.ProguardConfiguration ("proguard.txt") {
337+
TextContent = () => "-dontwarn com.example.library.**",
338+
});
336339

337340
var app = new XamarinAndroidApplicationProject {
338341
IsRelease = true,
@@ -347,6 +350,28 @@ public R8JniLibraryPeer () { }
347350
app.OtherBuildItems.Add (new AndroidItem.ProguardConfiguration ("r8-jni-rules.pro") {
348351
TextContent = () => proguardRule,
349352
});
353+
app.OtherBuildItems.Add (new AndroidItem.ProguardConfiguration ("generated-acw-keep.cfg") {
354+
TextContent = () => $"-keep class {libraryJavaName.Replace ('/', '.')} {{ *; }}",
355+
Metadata = {
356+
{ "AndroidGeneratedProguardConfiguration", "true" },
357+
},
358+
});
359+
app.Imports.Add (new Import ("CaptureR8JniSeedConfiguration.targets") {
360+
TextContent = () => """
361+
<Project>
362+
<Target Name="_CaptureR8JniSeedConfiguration"
363+
AfterTargets="_AndroidGenerateR8JniSeedMappingInputs"
364+
BeforeTargets="_AndroidGenerateR8JniSeedMapping">
365+
<MakeDir Directories="$(_AndroidR8JniSeedDirectory)" />
366+
<WriteLinesToFile
367+
File="$(_AndroidR8JniSeedDirectory)configuration-items.txt"
368+
Lines="@(_AndroidR8JniSeedProguardConfiguration)"
369+
Overwrite="true"
370+
WriteOnlyWhenDifferent="true" />
371+
</Target>
372+
</Project>
373+
""",
374+
});
350375

351376
string testDirectory = Path.Combine ("temp", $"R8JniNameRewritingReferences_{runtime}_{Guid.NewGuid ():N}");
352377
using var libraryBuilder = CreateDllBuilder (Path.Combine (testDirectory, library.ProjectName));
@@ -357,8 +382,14 @@ public R8JniLibraryPeer () { }
357382
var projectDirectory = Path.Combine (Root, appBuilder.ProjectDirectory);
358383
var seedMapping = FindSingleFile (projectDirectory, "mapping.txt", path => path.Contains ("r8-jni-seed", StringComparison.Ordinal));
359384
var rewriteManifest = FindSingleFile (projectDirectory, "r8-jni-rewrite-manifest.txt");
360-
StringAssert.Contains ($"{libraryJavaName.Replace ('/', '.')} ->", File.ReadAllText (seedMapping));
385+
var seedConfigurationItems = File.ReadAllLines (FindSingleFile (projectDirectory, "configuration-items.txt"));
386+
AssertR8MappingRenamesClass (seedMapping, libraryJavaName);
361387
StringAssert.Contains ($"C\t{libraryJavaName}", File.ReadAllText (rewriteManifest));
388+
Assert.That (seedConfigurationItems, Has.Some.EndsWith ("r8-jni-rules.pro"), "Seed R8 should receive user-authored rules.");
389+
Assert.That (seedConfigurationItems, Has.Some.EndsWith ("proguard.txt"), "Seed R8 should receive AAR consumer rules.");
390+
Assert.IsFalse (seedConfigurationItems.Any (path =>
391+
new [] { "proguard-android.txt", "proguard_xamarin.cfg", "proguard_project_references.cfg", "proguard_project_primary.cfg", "aapt_rules.txt", "generated-acw-keep.cfg" }.Contains (Path.GetFileName (path), StringComparer.Ordinal)),
392+
"Seed R8 should not receive generated or baseline configurations that pin managed peers.");
362393

363394
proguardRule = "-dontwarn com.example.UnusedTwo";
364395
app.Touch ("r8-jni-rules.pro");

0 commit comments

Comments
 (0)