Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Xamarin.Android.Build.Tasks] fix proguard rules for R8 compatibility
Context: https://www.guardsquare.com/en/products/proguard/manual/usage#keepoptionmodifiers Context: https://www.guardsquare.com/en/products/proguard/manual/examples Fixes: dotnet#2684 Using R8 on a pre-Android 8.0 device was crashing with: E/mono (16220): Unhandled Exception: E/mono (16220): Java.Lang.LinkageError: no non-static method "Landroid/runtime/UncaughtExceptionHandler;.<init>()V" E/mono (16220): at Java.Interop.JniEnvironment+InstanceMethods.GetMethodID (Java.Interop.JniObjectReference type, System.String name, System.String signature) [0x0005b] in <7d7bcc9ee9cc460db8abcdb9a9622733>:0 E/mono (16220): at Java.Interop.JniType.GetConstructor (System.String signature) [0x0000c] in <7d7bcc9ee9cc460db8abcdb9a9622733>:0 E/mono (16220): at Java.Interop.JniPeerMembers+JniInstanceMethods.GetConstructor (System.String signature) [0x00035] in <7d7bcc9ee9cc460db8abcdb9a9622733>:0 E/mono (16220): at Java.Interop.JniPeerMembers+JniInstanceMethods.FinishCreateInstance (System.String constructorSignature, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x00036] in <7d7bcc9ee9cc460db8abcdb9a9622733>:0 E/mono (16220): at Java.Lang.Object..ctor () [0x00054] in <d77389624c8c4948a12589c4bd4500eb>:0 E/mono (16220): at Android.Runtime.UncaughtExceptionHandler..ctor (Java.Lang.Thread+IUncaughtExceptionHandler defaultHandler) [0x00000] in <d77389624c8c4948a12589c4bd4500eb>:0 E/mono (16220): at Android.Runtime.JNIEnv.Initialize (Android.Runtime.JnienvInitializeArgs* args) [0x00202] in <d77389624c8c4948a12589c4bd4500eb>:0 E/mono (16220): --- End of managed Java.Lang.LinkageError stack trace --- E/mono (16220): java.lang.NoSuchMethodError: no non-static method "Landroid/runtime/UncaughtExceptionHandler;.<init>()V" E/mono (16220): at mono.android.Runtime.init(Native Method) E/mono (16220): at mono.MonoPackageManager.LoadApplication(:21) E/mono (16220): at mono.MonoRuntimeProvider.attachInfo(:1) E/mono (16220): at android.app.ActivityThread.installProvider(ActivityThread.java:5853) E/mono (16220): at android.app.ActivityThread.installContentProviders(ActivityThread.java:5445) E/mono (16220): at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5384) E/mono (16220): at android.app.ActivityThread.-wrap2(ActivityThread.java) E/mono (16220): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1545) E/mono (16220): at android.os.Handler.dispatchMessage(Handler.java:102) E/mono (16220): at android.os.Looper.loop(Looper.java:154) E/mono (16220): at android.app.ActivityThread.main(ActivityThread.java:6119) E/mono (16220): at java.lang.reflect.Method.invoke(Native Method) E/mono (16220): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886) E/mono (16220): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776) Looking into it, the following method was present when using ProGuard, but not R8: #1 : (in Landroid/runtime/UncaughtExceptionHandler;) name : '<init>' type : '()V' access : 0x10001 (PUBLIC CONSTRUCTOR) code - registers : 4 ins : 1 outs : 4 insns size : 22 16-bit code units catches : (none) positions : 0x0000 line=22 0x0003 line=23 0x0010 line=24 locals : 0x0000 - 0x0016 reg=3 this Landroid/runtime/UncaughtExceptionHandler; Then I looked at `proguard_xamarin.cfg`, and noticed something strange: -keep class android.runtime.** { <init>(***); } It seemed this rule was being ignored? All the other *working* rules were using `<init>(...);` to refer to the instance constructor. When I reviewed ProGuard's documented syntax/grammar: [@annotationtype] [[!]public|final|abstract|@ ...] [!]interface|class|enum classname [extends|implements [@annotationtype] classname] [{ [@annotationtype] [[!]public|private|protected|static|volatile|transient ...] <fields> | (fieldtype fieldname); [@annotationtype] [[!]public|private|protected|static|synchronized|native|abstract|strictfp ...] <methods> | <init>(argumenttype,...) | classname(argumenttype,...) | (returntype methodname(argumenttype,...)); [@annotationtype] [[!]public|private|protected|static ... ] *; ... }] It seems `(...)` is the proper way to specify a match against any set of arguments. Looking through ProGuard's examples, I can't find any usage of `(***)`. It must *happen* to work, but is undocumented. R8 does not appear to accept the `(***)` syntax at all. ~~ Other changes ~~ I expanded upon the `DexUtils` class so it can look for methods within classes. I also adjusted one test to verify this problem is solved.
- Loading branch information