From 55fa709d6b041db0a70510861fb293985e3c66cf Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Mon, 27 Jan 2020 13:46:30 -0600 Subject: [PATCH] [Xamarin.Android.Build.Tasks] default proguard rules for BroadcastReceiver (#4178) Fixes: https://github.com/xamarin/xamarin-android/issues/4110 A crash was reported when using either Proguard or R8: java.lang.RuntimeException: Unable to get provider mono.MonoRuntimeProvider_1: java.lang.ClassNotFoundException: Didn't find class "mono.MonoRuntimeProvider_1" on path: DexPathList[[zip file "/data/app/myApp-61Sw26LCrQQYfOvCs2GsDw==/base.apk"],nativeLibraryDirectories=[/data/app/myapp-61Sw26LCrQQYfOvCs2GsDw==/lib/arm64, /data/app/myapp-61Sw26LCrQQYfOvCs2GsDw==/base.apk!/lib/arm64-v8a, /system/lib64, /system/product/lib64]] at android.app.ActivityThread.installProvider(ActivityThread.java:7152) at android.app.ActivityThread.installContentProviders(ActivityThread.java:6630) at android.app.ActivityThread.handleBindApplication(ActivityThread.java:6525) at android.app.ActivityThread.access$1400(ActivityThread.java:220) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1883) at android.os.Handler.dispatchMessage(Handler.java:107) at android.os.Looper.loop(Looper.java:224) at android.app.ActivityThread.main(ActivityThread.java:7520) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950) Caused by: java.lang.ClassNotFoundException: Didn't find class "mono.MonoRuntimeProvider_1" on path: DexPathList[[zip file "/data/app/myapp-61Sw26LCrQQYfOvCs2GsDw==/base.apk"],nativeLibraryDirectories=[/data/app/myapp-61Sw26LCrQQYfOvCs2GsDw==/lib/arm64, /data/app/myapp-61Sw26LCrQQYfOvCs2GsDw==/base.apk!/lib/arm64-v8a, /system/lib64, /system/product/lib64]] at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:230) at java.lang.ClassLoader.loadClass(ClassLoader.java:379) at java.lang.ClassLoader.loadClass(ClassLoader.java:312) at android.app.AppComponentFactory.instantiateProvider(AppComponentFactory.java:147) at android.app.ActivityThread.installProvider(ActivityThread.java:7136) This could be reproduced in a new project, just by enabling a Code Shrinker and adding a `BroadcastReceiver`: [BroadcastReceiver(Process = ":remote", Name = "foo.MyReceiver")] public class MyReceiver : BroadcastReceiver { public override void OnReceive(Context context, Intent intent) { } } This generated a file in: obj\Release\100\android\src\mono\MonoRuntimeProvider_1.java We have no default proguard rule in `proguard_xamarin.cfg` that would cover inclusion of this Java class for ProGuard or R8. We can simply add a trailing `*` to the Java class name of an existing rule: -keep class mono.MonoRuntimeProvider* { *; (...); } I also added a test for this scenario that will verify ProGuard & R8. --- .../Resources/proguard_xamarin.cfg | 2 +- .../Xamarin.Android.Build.Tests/BuildTest.cs | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Resources/proguard_xamarin.cfg b/src/Xamarin.Android.Build.Tasks/Resources/proguard_xamarin.cfg index 4629e018dd5..914ef686ac2 100644 --- a/src/Xamarin.Android.Build.Tasks/Resources/proguard_xamarin.cfg +++ b/src/Xamarin.Android.Build.Tasks/Resources/proguard_xamarin.cfg @@ -4,7 +4,7 @@ -keep class android.support.multidex.MultiDexApplication { (); } -keep class com.xamarin.java_interop.** { *; (); } --keep class mono.MonoRuntimeProvider { *; (...); } +-keep class mono.MonoRuntimeProvider* { *; (...); } -keep class mono.MonoPackageManager { *; (...); } -keep class mono.MonoPackageManager_Resources { *; (...); } -keep class mono.android.** { *; (...); } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs index f2a6fca49b3..14f66281616 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs @@ -3607,6 +3607,19 @@ public void Desugar ([Values (true, false)] bool isRelease, [Values ("dx", "d8") DexTool = dexTool, LinkTool = linkTool, }; + + //Add a BroadcastReceiver + proj.Sources.Add (new BuildItem.Source ("MyReceiver.cs") { + TextContent = () => @" +using Android.Content; + +[BroadcastReceiver(Process = "":remote"", Name = ""foo.MyReceiver"")] +public class MyReceiver : BroadcastReceiver +{ + public override void OnReceive(Context context, Intent intent) { } +}", + }); + //Okhttp and Okio //https://github.com/square/okhttp //https://github.com/square/okio @@ -3691,6 +3704,8 @@ public void foo() var dexFile = builder.Output.GetIntermediaryPath (Path.Combine ("android", "bin", "classes.dex")); FileAssert.Exists (dexFile); Assert.IsTrue (DexUtils.ContainsClass (className, dexFile, AndroidSdkPath), $"`{dexFile}` should include `{className}`!"); + className = "Lmono/MonoRuntimeProvider_1;"; + Assert.IsTrue (DexUtils.ContainsClass (className, dexFile, AndroidSdkPath), $"`{dexFile}` should include `{className}`!"); } }