You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[Xamarin.Android.Build.Tasks] fix proguard rules for R8 compat (dotnet#2735)
Fixes: dotnet#2684
Context: https://www.guardsquare.com/en/products/proguard/manual/usage#keepoptionmodifiers
Context: https://www.guardsquare.com/en/products/proguard/manual/examples
Using R8 on a pre-Android 8.0 device was crashing with:
Unhandled Exception:
Java.Lang.LinkageError: no non-static method "Landroid/runtime/UncaughtExceptionHandler;.<init>()V"
at Java.Interop.JniEnvironment+InstanceMethods.GetMethodID (Java.Interop.JniObjectReference type, System.String name, System.String signature) [0x0005b] in <7d7bcc9ee9cc460db8abcdb9a9622733>:0
at Java.Interop.JniType.GetConstructor (System.String signature) [0x0000c] in <7d7bcc9ee9cc460db8abcdb9a9622733>:0
at Java.Interop.JniPeerMembers+JniInstanceMethods.GetConstructor (System.String signature) [0x00035] in <7d7bcc9ee9cc460db8abcdb9a9622733>:0
at Java.Interop.JniPeerMembers+JniInstanceMethods.FinishCreateInstance (System.String constructorSignature, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x00036] in <7d7bcc9ee9cc460db8abcdb9a9622733>:0
at Java.Lang.Object..ctor () [0x00054] in <d77389624c8c4948a12589c4bd4500eb>:0
at Android.Runtime.UncaughtExceptionHandler..ctor (Java.Lang.Thread+IUncaughtExceptionHandler defaultHandler) [0x00000] in <d77389624c8c4948a12589c4bd4500eb>:0
at Android.Runtime.JNIEnv.Initialize (Android.Runtime.JnienvInitializeArgs* args) [0x00202] in <d77389624c8c4948a12589c4bd4500eb>:0
--- End of managed Java.Lang.LinkageError stack trace ---
java.lang.NoSuchMethodError: no non-static method "Landroid/runtime/UncaughtExceptionHandler;.<init>()V"
at mono.android.Runtime.init(Native Method)
at mono.MonoPackageManager.LoadApplication(:21)
at mono.MonoRuntimeProvider.attachInfo(:1)
at android.app.ActivityThread.installProvider(ActivityThread.java:5853)
at android.app.ActivityThread.installContentProviders(ActivityThread.java:5445)
at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5384)
at android.app.ActivityThread.-wrap2(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1545)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
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;
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.
I reviewed [ProGuard's documented syntax/grammar][0]:
[@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 *happened* to work, but is undocumented.
R8 does not appear to accept the `(***)` syntax at all.
Update `proguard_xamarin.cfg` so that it uses `(...)`, not `(***)`,
allowing R8 to properly process `proguard_xamarin.cfg`.
~~ 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.
[0]: https://www.guardsquare.com/en/products/proguard/manual/usage#classspecification
Assert.IsTrue(StringAssertEx.ContainsText(File.ReadAllLines(proguardProjectPrimary),"-keep class md52d9cf6333b8e95e8683a477bc589eda5.MainActivity"),"`md52d9cf6333b8e95e8683a477bc589eda5.MainActivity` should exist in `proguard_project_primary.cfg`!");
0 commit comments