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
16 changes: 16 additions & 0 deletions Documentation/docs-mobile/building-apps/build-properties.md
Original file line number Diff line number Diff line change
Expand Up @@ -1115,6 +1115,22 @@ r8 dex-compiler and shrinker. The default value is a path into the
.NET for Android workload installation. For further information see our
documentation on [D8 and R8][d8-r8].

## AndroidR8ObfuscationMode

An enum-style property that specifies how `r8` obfuscates Java names when
[`$(AndroidLinkTool)`](#androidlinktool) is `r8`. Supported values are:

- `private-members` preserves Java class and interface names and public or
protected member names. Private and package-private members can be
obfuscated, and R8 optimization is enabled.
- `disabled` disables obfuscation, preserves all Java names, and uses the
non-optimizing Android R8 defaults.

This property does not disable R8 code shrinking.

This property was introduced in a .NET 10 servicing release. It defaults to
`disabled` in .NET 10 and to `private-members` in .NET 11 and later.

## AndroidResgenExtraArgs

Specifies
Expand Down
1 change: 1 addition & 0 deletions build-tools/installers/create-installers.targets
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)java_runtime_clr.dex" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)java_runtime_fastdev_clr.dex" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)manifestmerger.jar" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)proguard-android-optimize.txt" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)proguard-android.txt" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)protobuf-net.dll" />
<_MSBuildFiles Include="$(MicrosoftAndroidSdkOutDir)System.CodeDom.dll" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
# Xamarin.Android NativeAOT trimmable typemap configuration.

-dontobfuscate

-keep class net.dot.jni.** { *; <init>(...); }
# Loaded by name from managed code.
-keep class net.dot.android.ApplicationRegistration { *; }
-keep class net.dot.android.crypto.** { *; <init>(...); }
# NativeAOT resolves these interface methods through JNI during startup.
-keep class mono.android.IGCUserPeer { *; }
# Native hosts resolve these package-private fields by name during startup.
-keepclassmembers class mono.android.Runtime {
static java.lang.Class *;
}

-keepclassmembers class * extends android.view.View {
*** set*(...);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# This is Xamarin-specific (and enhanced) configuration.

-dontobfuscate

-keep class android.support.multidex.MultiDexApplication { <init>(); }
-keep class net.dot.jni.** { *; <init>(); }
-keep class mono.MonoRuntimeProvider* { *; <init>(...); }
Expand All @@ -22,6 +20,8 @@
-keepclassmembers class md52ce486a14f4bcd95899665e9d932190b.** { *; <init>(...); }

# .NET runtime
# Loaded by name from managed code.
-keep class net.dot.android.ApplicationRegistration { *; }
-keep class net.dot.android.crypto.** { *; <init>(...); }

# Android's template misses fluent setters...
Expand Down
22 changes: 22 additions & 0 deletions src/Xamarin.Android.Build.Tasks/Tasks/R8.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ public class R8 : D8
public string? BuildMetadataFileOutput { get; set; }
public ITaskItem []? ProguardConfigurationFiles { get; set; }
public bool UseTrimmableNativeAotProguardConfiguration { get; set; }
public string ObfuscationMode { get; set; } = "private-members";

// User-authored AndroidJavaSource (Bind != true) .java files. These have no managed peer and are
// therefore absent from the acw-map, so they must be kept explicitly when shrinking is enabled.
Expand Down Expand Up @@ -191,6 +192,9 @@ protected override string CreateResponseFile ()
}
if (!ProguardCommonXamarinConfiguration.IsNullOrWhiteSpace ()) {
using (var xamcfg = File.CreateText (ProguardCommonXamarinConfiguration)) {
WriteObfuscationRules (xamcfg, ObfuscationMode);
xamcfg.WriteLine ();
xamcfg.Flush ();
if (UseTrimmableNativeAotProguardConfiguration) {
using var stream = GetEmbeddedResourceStream ("proguard_trimmable_nativeaot.cfg");
stream.CopyTo (xamcfg.BaseStream);
Expand Down Expand Up @@ -252,6 +256,24 @@ protected override string CreateResponseFile ()
return responseFile;
}

internal static void WriteObfuscationRules (TextWriter writer, string obfuscationMode)
{
if (string.Equals (obfuscationMode, "disabled", StringComparison.OrdinalIgnoreCase)) {
writer.WriteLine ("-dontobfuscate");
return;
}

writer.WriteLine ("-keep,allowshrinking,allowoptimization class **");
writer.WriteLine ("-keepclassmembers,allowshrinking,allowoptimization class ** {");
writer.WriteLine (" public protected *;");
writer.WriteLine ("}");
// Managed interface proxy selection observes Class.getInterfaces(), which R8 cannot infer.
writer.WriteLine ("-keep,allowoptimization interface ** {");
writer.WriteLine (" public protected *;");
writer.WriteLine ("}");
writer.WriteLine ("-keep,allowshrinking class * implements **");
}

// ProGuard "global" options that affect the whole build and are not allowed inside
// a library's proguard.txt (the file packaged inside an .aar's root). AGP 9.0
// introduced the same restriction — see "Behavior changes" in the AGP 9.0 release
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Xml.Linq;
using Microsoft.Build.Framework;
using NUnit.Framework;
Expand All @@ -17,7 +18,9 @@ namespace Xamarin.Android.Build.Tests
public class PackagingTest : BaseTest
{
[Test]
public void CheckR8MetadataFilesExist ([Values (AndroidRuntime.CoreCLR, AndroidRuntime.NativeAOT)] AndroidRuntime runtime)
public void CheckR8MetadataFilesExist (
[Values (AndroidRuntime.CoreCLR, AndroidRuntime.NativeAOT)] AndroidRuntime runtime,
[Values ("disabled", "private-members")] string obfuscationMode)
{
const bool isRelease = true;
if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) {
Expand All @@ -29,6 +32,7 @@ public void CheckR8MetadataFilesExist ([Values (AndroidRuntime.CoreCLR, AndroidR
};
proj.SetRuntime (runtime);
proj.SetProperty (proj.ReleaseProperties, KnownProperties.AndroidLinkTool, "r8");
proj.SetProperty (proj.ReleaseProperties, KnownProperties.AndroidR8ObfuscationMode, obfuscationMode);
// Projects must set $(AndroidCreateProguardMappingFile) to true to opt in
proj.SetProperty (proj.ReleaseProperties, "AndroidCreateProguardMappingFile", true);
proj.SetProperty ("AndroidPackageFormat", "aab");
Expand All @@ -41,7 +45,14 @@ public void CheckR8MetadataFilesExist ([Values (AndroidRuntime.CoreCLR, AndroidR
FileAssert.Exists (aab, $"'{aab}' should have been generated.");
using (var zip = ZipHelper.OpenZip (aab)) {
Assert.IsTrue (zip.Any (e => e.FullName == "BUNDLE-METADATA/com.android.tools.build.obfuscation/proguard.map"), $"AAB file `{aab}` should contain the ProGuard mapping.");
Assert.IsTrue (zip.Any (e => e.FullName == "BUNDLE-METADATA/com.android.tools/r8.json"), $"AAB file `{aab}` should contain the R8 build metadata.");
var metadata = zip.SingleOrDefault (e => e.FullName == "BUNDLE-METADATA/com.android.tools/r8.json");
Assert.IsNotNull (metadata, $"AAB file `{aab}` should contain the R8 build metadata.");
using var stream = new MemoryStream ();
metadata.Extract (stream);
stream.Position = 0;
using var document = JsonDocument.Parse (stream);
var options = document.RootElement.GetProperty ("options");
Assert.AreEqual (obfuscationMode == "private-members", options.GetProperty ("isOptimizationsEnabled").GetBoolean ());
}

Assert.IsTrue (b.Build (proj), "second build should have succeeded.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,34 @@ public void ReadJavaPackage (string content, string? expected)
File.Delete (path);
}
}

[Test]
public void WritePrivateMemberObfuscationRules ()
{
using var writer = new StringWriter ();
R8.WriteObfuscationRules (writer, "private-members");

var expected = """
-keep,allowshrinking,allowoptimization class **
-keepclassmembers,allowshrinking,allowoptimization class ** {
public protected *;
}
-keep,allowoptimization interface ** {
public protected *;
}
-keep,allowshrinking class * implements **

""";
Assert.AreEqual (expected.ReplaceLineEndings (System.Environment.NewLine), writer.ToString ());
}

[Test]
public void WriteDisabledObfuscationRules ()
{
using var writer = new StringWriter ();
R8.WriteObfuscationRules (writer, "disabled");

Assert.AreEqual ("-dontobfuscate" + System.Environment.NewLine, writer.ToString ());
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public static class KnownProperties
public const string AndroidEnableDesugar = "AndroidEnableDesugar";
public const string AndroidManifestMerger = "AndroidManifestMerger";
public const string AndroidLinkTool = "AndroidLinkTool";
public const string AndroidR8ObfuscationMode = "AndroidR8ObfuscationMode";
public const string UseJackAndJill = "UseJackAndJill";
public const string AotAssemblies = "AotAssemblies";
public const string AndroidEnableProfiledAot = "AndroidEnableProfiledAot";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"Size": 3036
},
"classes.dex": {
"Size": 402716
"Size": 382236
},
"lib/arm64-v8a/libassembly-store.so": {
"Size": 2529368
Expand Down Expand Up @@ -59,5 +59,5 @@
"Size": 1904
}
},
"PackageSize": 6751675
"PackageSize": 6743483
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"Size": 6652
},
"classes.dex": {
"Size": 3238292
"Size": 2794604
},
"kotlin/annotation/annotation.kotlin_builtins": {
"Size": 928
Expand All @@ -29,16 +29,16 @@
"Size": 2396
},
"lib/arm64-v8a/libassembly-store.so": {
"Size": 9453656
"Size": 9458208
},
"lib/arm64-v8a/libclrjit.so": {
"Size": 2818032
"Size": 2818048
},
"lib/arm64-v8a/libcoreclr.so": {
"Size": 4844000
"Size": 4843824
},
"lib/arm64-v8a/libmonodroid.so": {
"Size": 203592
"Size": 204872
},
"lib/arm64-v8a/libSystem.Globalization.Native.so": {
"Size": 72432
Expand Down Expand Up @@ -2231,5 +2231,5 @@
"Size": 794696
}
},
"PackageSize": 16064019
"PackageSize": 15830547
}
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved.
<AndroidEnableDesugar Condition=" '$(AndroidEnableDesugar)' == '' ">False</AndroidEnableDesugar>
<AndroidD8IgnoreWarnings Condition=" '$(AndroidD8IgnoreWarnings)' == '' ">True</AndroidD8IgnoreWarnings>
<AndroidR8IgnoreWarnings Condition=" '$(AndroidR8IgnoreWarnings)' == '' ">True</AndroidR8IgnoreWarnings>
<AndroidR8ObfuscationMode Condition=" '$(AndroidR8ObfuscationMode)' == '' ">private-members</AndroidR8ObfuscationMode>
<AndroidCreateProguardMappingFile Condition="'$(AndroidCreateProguardMappingFile)' == '' And '$(AndroidLinkTool)' == 'r8'">True</AndroidCreateProguardMappingFile>

<!-- Figure out which is the main packaging format we want-->
Expand Down Expand Up @@ -975,6 +976,7 @@ because xbuild doesn't support framework reference assemblies.
<_PropertyCacheItems Include="AndroidEnableProfiledAot=$(AndroidEnableProfiledAot)" />
<_PropertyCacheItems Include="AndroidDexTool=$(AndroidDexTool)" />
<_PropertyCacheItems Include="AndroidLinkTool=$(AndroidLinkTool)" />
<_PropertyCacheItems Include="AndroidR8ObfuscationMode=$(AndroidR8ObfuscationMode)" />
<_PropertyCacheItems Include="AndroidLinkResources=$(AndroidLinkResources)" />
<_PropertyCacheItems Include="AndroidBundleToolExtraArgs=$(AndroidBundleToolExtraArgs)" />
<_PropertyCacheItems Include="AndroidKeyStore=$(AndroidKeyStore)" />
Expand Down Expand Up @@ -2026,7 +2028,8 @@ because xbuild doesn't support framework reference assemblies.
<_ProguardConfiguration Include="$(ProguardConfigFiles)" />
</ItemGroup>
<ItemGroup Condition=" '$(ProguardConfigFiles)' == '' ">
<_ProguardConfiguration Include="$(MSBuildThisFileDirectory)proguard-android.txt" />
<_ProguardConfiguration Include="$(MSBuildThisFileDirectory)proguard-android.txt" Condition=" '$(AndroidR8ObfuscationMode)' == 'disabled' " />
<_ProguardConfiguration Include="$(MSBuildThisFileDirectory)proguard-android-optimize.txt" Condition=" '$(AndroidR8ObfuscationMode)' != 'disabled' " />
Comment thread
jonathanpeppers marked this conversation as resolved.
<_ProguardConfiguration Include="$(IntermediateOutputPath)proguard\proguard_xamarin.cfg" Condition=" '$(AndroidLinkTool)' != '' " />
<_ProguardConfiguration Include="$(_ProguardProjectConfiguration)" Condition=" '$(AndroidLinkTool)' != '' " />
<_ProguardConfiguration Include="$(IntermediateOutputPath)proguard\proguard_project_primary.cfg" Condition=" '$(AndroidLinkTool)' != '' " />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ Copyright (C) 2018 Xamarin. All rights reserved.
BuildMetadataFileOutput="$(_AndroidR8BuildMetadataFile)"
ProguardConfigurationFiles="@(_ProguardConfiguration)"
UseTrimmableNativeAotProguardConfiguration="$(_UseTrimmableNativeAotProguardConfiguration)"
ObfuscationMode="$(AndroidR8ObfuscationMode)"
EnableShrinking="$(_R8EnableShrinking)"
EnableMultiDex="$(AndroidEnableMultiDex)"
MultiDexMainDexListFile="$(_AndroidMainDexListFile)"
Expand Down
16 changes: 11 additions & 5 deletions src/proguard-android/proguard-android.targets
Original file line number Diff line number Diff line change
@@ -1,29 +1,35 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<_Destination>$(MicrosoftAndroidSdkOutDir)proguard-android.txt</_Destination>
<_OptimizeDestination>$(MicrosoftAndroidSdkOutDir)proguard-android-optimize.txt</_OptimizeDestination>
</PropertyGroup>

<Target Name="_GenerateProGuardRules"
BeforeTargets="Build"
Inputs="$(MSBuildThisFile);build.gradle;settings.gradle"
Outputs="$(_Destination)">
Outputs="$(_Destination);$(_OptimizeDestination)">
<Exec
Command="&quot;$(GradleWPath)&quot; extractProguardFiles $(GradleArgs)"
EnvironmentVariables="JAVA_HOME=$(JavaSdkDirectory);APP_HOME=$(GradleHome)"
WorkingDirectory="$(MSBuildThisFileDirectory)"
/>
<ItemGroup>
<_ProguardRules Include="$(MSBuildThisFileDirectory)build\intermediates\default_proguard_files\global\proguard-android.txt-*" />
<_ProguardRules Include="$(MSBuildThisFileDirectory)build\intermediates\default_proguard_files\global\proguard-android.txt-*">
<Destination>$(_Destination)</Destination>
</_ProguardRules>
<_ProguardRules Include="$(MSBuildThisFileDirectory)build\intermediates\default_proguard_files\global\proguard-android-optimize.txt-*">
<Destination>$(_OptimizeDestination)</Destination>
</_ProguardRules>
</ItemGroup>
<Copy
SourceFiles="@(_ProguardRules)"
DestinationFiles="$(_Destination)"
DestinationFiles="@(_ProguardRules->'%(Destination)')"
/>
<Touch Files="$(_Destination)" />
<Touch Files="$(_Destination);$(_OptimizeDestination)" />
</Target>

<Target Name="_CleanProguardRules" BeforeTargets="Clean">
<Delete Files="$(_Destination)" />
<Delete Files="$(_Destination);$(_OptimizeDestination)" />
<Exec
Command="&quot;$(GradleWPath)&quot; clean $(GradleArgs)"
EnvironmentVariables="JAVA_HOME=$(JavaSdkDirectory);APP_HOME=$(GradleHome)"
Expand Down
Loading
Loading