Open jonathanpeppers opened 5 years ago
/cc @JonDouglas
Plausible idea for this: we could add a new Linker step which would record every Java type & method that was referenced and emit a corresponding ProGuard preservation file.
This should allow the full r8/proguard Java-side linker to do as much Java-side linking as possible without breaking the apps.
how do you do android.enableR8.fullMode=true in xamarin? https://developer.android.com/studio/build/shrink-code
@EmilAlipiev if you need android.enableR8.fullMode
, you might file a new issue as a feature request. Xamarin.Android is running r8 in the default, proguard-compatible way.
I don't see any documentation as to what the mode actually does. What flags does it pass to r8.jar
?
I think R8 should be enabled by default but please be advised if you enable it (manually or by default), every app using WebView will currently be crashing due to this:
https://github.com/dotnet/maui/issues/23027
R8 is not currently even usable then by choice if WebView is part of the app.
@jonmdev what is the crash? It feels like MAUI needs to add a proguard rule of their own.
Normally it says something like Java method XYZ did not exist
.
@jonmdev what is the crash? It feels like MAUI needs to add a proguard rule of their own.
Normally it says something like
Java method XYZ did not exist
.
Thanks for the reply. I don't actually know what the error is. It only happens in Release mode so I have no Debugger. The Debugger in Visual Studio also disconnects when you switch away from the app and does not reconnect when you switch back (which is when the crash occurs).
So I have not seen the error, except that it crashes reliably every time as described in that bug report.
My entire bug report code is a default project with only App.xaml.cs replaced with:
namespace WebViewR8Bug {
public partial class App : Application {
public App() {
ContentPage mainPage = new();
this.MainPage = mainPage;
AbsoluteLayout absRoot = new();
mainPage.Content = absRoot;
WebView webView = new();
webView.WidthRequest = 300;
webView.HeightRequest = 300;
webView.Source = "https://google.com";
absRoot.Add(webView);
}
}
}
How do you suggest I capture the error code? Or can you try if there is some way you know?
The repro project is: https://github.com/jonmdev/WebViewR8Bug
Steps To Reproduce:
1) Open Developer Options in Android Phone and set Background Process Limit to 0-1 range. 2) Build Bug Project in Release to Android device with R8 Enabled. 3) Press ||| button on Android bottom tray and navigate to a few other open apps sequentially. 4) Press ||| button on Android bottom tray and navigate back to the Maui App. 5) With R8 enabled, it will then briefly show the splash icon and crash.
adb logcat
will show the error:
It should print out the full stack trace on both the Java and C# side.
adb logcat
will show the error:* https://docs.microsoft.com/xamarin/android/deploy-test/debugging/android-debug-log
It should print out the full stack trace on both the Java and C# side.
That did work to get the error - java.lang.NoSuchFieldException: CREATOR
. Here is the critical section:
Time Device Name Type PID Tag Message
07-08 18:52:37.994 Samsung Warning 1825 ActivityManager crash : com.companyname.r8crashbug,11366
Force finishing activity com.companyname.r8crashbug/crc64ac3e9cc1ca5e515f.MainActivity
07-08 18:52:37.994 Samsung Debug 1825 Debug low && ship && 3rdparty app crash, do not dump
07-08 18:52:37.994 Samsung Info 1825 DropBoxManagerService add tag=data_app_crash isTagEnabled=true flags=0x2
07-08 18:52:37.992 Samsung Info 14352 MonoDroid
07-08 18:52:37.992 Samsung Info 14352 MonoDroid Caused by: java.lang.NoSuchFieldException: CREATOR
at java.lang.Class.getField(Class.java:2337)
at android.os.Parcel.readParcelableCreatorInternal(Parcel.java:5004)
... 34 more
07-08 18:52:37.992 Samsung Info 14352 MonoDroid android.os.BadParcelableException: Parcelable protocol requires a Parcelable.Creator object called CREATOR on class androidx.coordinatorlayout.widget.CoordinatorLayout$SavedState
at android.os.Parcel.readParcelableCreatorInternal(Parcel.java:5027)
at android.os.Parcel.readParcelableInternal(Parcel.java:4873)
at android.os.Parcel.readValue(Parcel.java:4633)
at android.os.Parcel.readValue(Parcel.java:4402)
at android.os.Parcel.readSparseArrayInternal(Parcel.java:5493)
at android.os.Parcel.readValue(Parcel.java:4717)
at android.os.Parcel.readValue(Parcel.java:4402)
at android.os.Parcel.-$$Nest$mreadValue(Unknown Source:0)
at android.os.Parcel$LazyValue.apply(Parcel.java:4500)
at android.os.Parcel$LazyValue.apply(Parcel.java:4459)
at android.os.BaseBundle.unwrapLazyValueFromMapLocked(BaseBundle.java:415)
at android.os.BaseBundle.getValueAt(BaseBundle.java:401)
at android.os.BaseBundle.getValue(BaseBundle.java:381)
at android.os.BaseBundle.getValue(BaseBundle.java:364)
at android.os.BaseBundle.getValue(BaseBundle.java:357)
at android.os.Bundle.getSparseParcelableArray(Bundle.java:1108)
at com.android.internal.policy.PhoneWindow.restoreHierarchyState(PhoneWindow.java:2282)
at android.app.Activity.onRestoreInstanceState(Activity.java:1886)
at crc6488302ad6e9e4df1a.MauiAppCompatActivity.n_onRestoreInstanceState(Native Method)
at crc6488302ad6e9e4df1a.MauiAppCompatActivity.onRestoreInstanceState(SourceFile:1)
at android.app.Activity.performRestoreInstanceState(Activity.java:1839)
at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1503)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:4214)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:225)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:205)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:177)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:98)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2685)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:230)
at android.os.Looper.loop(Looper.java:319)
at android.app.ActivityThread.main(ActivityThread.java:8893)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:608)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
07-08 18:52:37.992 Samsung Info 14352 MonoDroid
--- End of managed Java.Lang.RuntimeException stack trace ---
07-08 18:52:37.992 Samsung Info 14352 MonoDroid Caused by: java.lang.NoSuchFieldException: CREATOR
at java.lang.Class.getField(Class.java:2337)
at android.os.Parcel.readParcelableCreatorInternal(Parcel.java:5004)
... 34 more
07-08 18:52:37.992 Samsung Info 14352 MonoDroid android.os.BadParcelableException: Parcelable protocol requires a Parcelable.Creator object called CREATOR on class androidx.coordinatorlayout.widget.CoordinatorLayout$SavedState
at android.os.Parcel.readParcelableCreatorInternal(Parcel.java:5027)
at android.os.Parcel.readParcelableInternal(Parcel.java:4873)
at android.os.Parcel.readValue(Parcel.java:4633)
at android.os.Parcel.readValue(Parcel.java:4402)
at android.os.Parcel.readSparseArrayInternal(Parcel.java:5493)
at android.os.Parcel.readValue(Parcel.java:4717)
at android.os.Parcel.readValue(Parcel.java:4402)
at android.os.Parcel.-$$Nest$mreadValue(Unknown Source:0)
at android.os.Parcel$LazyValue.apply(Parcel.java:4500)
at android.os.Parcel$LazyValue.apply(Parcel.java:4459)
at android.os.BaseBundle.unwrapLazyValueFromMapLocked(BaseBundle.java:415)
at android.os.BaseBundle.getValueAt(BaseBundle.java:401)
at android.os.BaseBundle.getValue(BaseBundle.java:381)
at android.os.BaseBundle.getValue(BaseBundle.java:364)
at android.os.BaseBundle.getValue(BaseBundle.java:357)
at android.os.Bundle.getSparseParcelableArray(Bundle.java:1108)
at com.android.internal.policy.PhoneWindow.restoreHierarchyState(PhoneWindow.java:2282)
at android.app.Activity.onRestoreInstanceState(Activity.java:1886)
at crc6488302ad6e9e4df1a.MauiAppCompatActivity.n_onRestoreInstanceState(Native Method)
at crc6488302ad6e9e4df1a.MauiAppCompatActivity.onRestoreInstanceState(SourceFile:1)
at android.app.Activity.performRestoreInstanceState(Activity.java:1839)
at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1503)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:4214)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:225)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:205)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:177)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:98)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2685)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:230)
at android.os.Looper.loop(Looper.java:319)
at android.app.ActivityThread.main(ActivityThread.java:8893)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:608)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
07-08 18:52:37.992 Samsung Info 14352 MonoDroid
Exception_EndOfInnerExceptionStack
at Java.Interop.JniEnvironment.InstanceMethods.CallNonvirtualVoidMethod(JniObjectReference , JniObjectReference , JniMethodInfo , JniArgumentValue* )
at Java.Interop.JniPeerMembers.JniInstanceMethods.InvokeVirtualVoidMethod(String , IJavaPeerable , JniArgumentValue* )
at Android.App.Activity.OnRestoreInstanceState(Bundle )
at Microsoft.Maui.MauiAppCompatActivity.OnRestoreInstanceState(Bundle savedInstanceState)
at Android.App.Activity.n_OnRestoreInstanceState_Landroid_os_Bundle_(IntPtr jnienv, IntPtr native__this, IntPtr native_savedInstanceState)
at Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PPL_V(_JniMarshal_PPL_V callback, IntPtr jnienv, IntPtr klazz, IntPtr p0)
--- End of managed Java.Lang.RuntimeException stack trace ---
07-08 18:52:37.992 Samsung Info 14352 MonoDroid java.lang.NoSuchFieldException: CREATOR
at java.lang.Class.getField(Class.java:2337)
at android.os.Parcel.readParcelableCreatorInternal(Parcel.java:5004)
at android.os.Parcel.readParcelableInternal(Parcel.java:4873)
at android.os.Parcel.readValue(Parcel.java:4633)
at android.os.Parcel.readValue(Parcel.java:4402)
at android.os.Parcel.readSparseArrayInternal(Parcel.java:5493)
at android.os.Parcel.readValue(Parcel.java:4717)
at android.os.Parcel.readValue(Parcel.java:4402)
at android.os.Parcel.-$$Nest$mreadValue(Unknown Source:0)
at android.os.Parcel$LazyValue.apply(Parcel.java:4500)
at android.os.Parcel$LazyValue.apply(Parcel.java:4459)
at android.os.BaseBundle.unwrapLazyValueFromMapLocked(BaseBundle.java:415)
at android.os.BaseBundle.getValueAt(BaseBundle.java:401)
at android.os.BaseBundle.getValue(BaseBundle.java:381)
at android.os.BaseBundle.getValue(BaseBundle.java:364)
at android.os.BaseBundle.getValue(BaseBundle.java:357)
at android.os.Bundle.getSparseParcelableArray(Bundle.java:1108)
at com.android.internal.policy.PhoneWindow.restoreHierarchyState(PhoneWindow.java:2282)
at android.app.Activity.onRestoreInstanceState(Activity.java:1886)
at crc6488302ad6e9e4df1a.MauiAppCompatActivity.n_onRestoreInstanceState(Native Method)
at crc6488302ad6e9e4df1a.MauiAppCompatActivity.onRestoreInstanceState(SourceFile:1)
at android.app.Activity.performRestoreInstanceState(Activity.java:1839)
at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1503)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:4214)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:225)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:205)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:177)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:98)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2685)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:230)
at android.os.Looper.loop(Looper.java:319)
at android.app.ActivityThread.main(ActivityThread.java:8893)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:608)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
07-08 18:52:37.992 Samsung Info 14352 MonoDroid
--- End of managed Java.Lang.Exception stack trace ---
07-08 18:52:37.992 Samsung Info 14352 MonoDroid java.lang.NoSuchFieldException: CREATOR
at java.lang.Class.getField(Class.java:2337)
at android.os.Parcel.readParcelableCreatorInternal(Parcel.java:5004)
at android.os.Parcel.readParcelableInternal(Parcel.java:4873)
at android.os.Parcel.readValue(Parcel.java:4633)
at android.os.Parcel.readValue(Parcel.java:4402)
at android.os.Parcel.readSparseArrayInternal(Parcel.java:5493)
at android.os.Parcel.readValue(Parcel.java:4717)
at android.os.Parcel.readValue(Parcel.java:4402)
at android.os.Parcel.-$$Nest$mreadValue(Unknown Source:0)
at android.os.Parcel$LazyValue.apply(Parcel.java:4500)
at android.os.Parcel$LazyValue.apply(Parcel.java:4459)
at android.os.BaseBundle.unwrapLazyValueFromMapLocked(BaseBundle.java:415)
at android.os.BaseBundle.getValueAt(BaseBundle.java:401)
at android.os.BaseBundle.getValue(BaseBundle.java:381)
at android.os.BaseBundle.getValue(BaseBundle.java:364)
at android.os.BaseBundle.getValue(BaseBundle.java:357)
at android.os.Bundle.getSparseParcelableArray(Bundle.java:1108)
at com.android.internal.policy.PhoneWindow.restoreHierarchyState(PhoneWindow.java:2282)
at android.app.Activity.onRestoreInstanceState(Activity.java:1886)
at crc6488302ad6e9e4df1a.MauiAppCompatActivity.n_onRestoreInstanceState(Native Method)
at crc6488302ad6e9e4df1a.MauiAppCompatActivity.onRestoreInstanceState(SourceFile:1)
at android.app.Activity.performRestoreInstanceState(Activity.java:1839)
at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1503)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:4214)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:225)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:205)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:177)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:98)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2685)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:230)
at android.os.Looper.loop(Looper.java:319)
at android.app.ActivityThread.main(ActivityThread.java:8893)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:608)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
07-08 18:52:37.992 Samsung Info 14352 MonoDroid
--- End of managed Java.Lang.Exception stack trace ---
07-08 18:52:37.992 Samsung Info 14352 MonoDroid Java.Lang.RuntimeException: Parcelable protocol requires a Parcelable.Creator object called CREATOR on class androidx.coordinatorlayout.widget.CoordinatorLayout$SavedState
---> Java.Lang.Exception: CREATOR
07-08 18:52:37.985 Samsung Info 14352 MonoDroid UNHANDLED EXCEPTION:
07-08 18:52:37.984 Samsung Warning 14352 monodroid-assembly Shared library 'liblog' not loaded, p/invoke '__android_log_print' may fail
07-08 18:52:37.980 Samsung Error 14352 AndroidRuntime Caused by: java.lang.NoSuchFieldException: CREATOR
at java.lang.Class.getField(Class.java:2337)
at android.os.Parcel.readParcelableCreatorInternal(Parcel.java:5004)
... 34 more
07-08 18:52:37.980 Samsung Error 14352 AndroidRuntime android.os.BadParcelableException: Parcelable protocol requires a Parcelable.Creator object called CREATOR on class androidx.coordinatorlayout.widget.CoordinatorLayout$SavedState
at android.os.Parcel.readParcelableCreatorInternal(Parcel.java:5027)
at android.os.Parcel.readParcelableInternal(Parcel.java:4873)
at android.os.Parcel.readValue(Parcel.java:4633)
at android.os.Parcel.readValue(Parcel.java:4402)
at android.os.Parcel.readSparseArrayInternal(Parcel.java:5493)
at android.os.Parcel.readValue(Parcel.java:4717)
at android.os.Parcel.readValue(Parcel.java:4402)
at android.os.Parcel.-$$Nest$mreadValue(Unknown Source:0)
at android.os.Parcel$LazyValue.apply(Parcel.java:4500)
at android.os.Parcel$LazyValue.apply(Parcel.java:4459)
at android.os.BaseBundle.unwrapLazyValueFromMapLocked(BaseBundle.java:415)
at android.os.BaseBundle.getValueAt(BaseBundle.java:401)
at android.os.BaseBundle.getValue(BaseBundle.java:381)
at android.os.BaseBundle.getValue(BaseBundle.java:364)
at android.os.BaseBundle.getValue(BaseBundle.java:357)
at android.os.Bundle.getSparseParcelableArray(Bundle.java:1108)
at com.android.internal.policy.PhoneWindow.restoreHierarchyState(PhoneWindow.java:2282)
at android.app.Activity.onRestoreInstanceState(Activity.java:1886)
at crc6488302ad6e9e4df1a.MauiAppCompatActivity.n_onRestoreInstanceState(Native Method)
at crc6488302ad6e9e4df1a.MauiAppCompatActivity.onRestoreInstanceState(SourceFile:1)
at android.app.Activity.performRestoreInstanceState(Activity.java:1839)
at android.app.Instrumentation.callActivityOnRestoreInstanceState(Instrumentation.java:1503)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:4214)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:225)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:205)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:177)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:98)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2685)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loopOnce(Looper.java:230)
at android.os.Looper.loop(Looper.java:319)
at android.app.ActivityThread.main(ActivityThread.java:8893)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:608)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)
07-08 18:52:37.980 Samsung Error 14352 AndroidRuntime Process: com.companyname.r8crashbug, PID: 14352
07-08 18:52:37.980 Samsung Error 14352 AndroidRuntime FATAL EXCEPTION: main
07-08 18:52:37.980 Samsung Debug 14352 AndroidRuntime Shutting down VM
Any thoughts or solutions? Thanks.
So, the error is related to androidx.coordinatorlayout.widget.CoordinatorLayout$SavedState
missing a CREATOR
field, reading this post:
I think you could make a Platforms/Android/proguard.txt
file that contains the contents:
-keepnames class * implements android.os.Parcelable {
public static final ** CREATOR;
}
It should preserve static CREATOR
fields on all Parcelable
implementations.
So, the error is related to
androidx.coordinatorlayout.widget.CoordinatorLayout$SavedState
missing aCREATOR
field, reading this post:* https://stackoverflow.com/a/55705308
I think you could make a
Platforms/Android/proguard.txt
file that contains the contents:-keepnames class * implements android.os.Parcelable { public static final ** CREATOR; }
It should preserve static
CREATOR
fields on allParcelable
implementations.
That worked!
I added a Platforms/Android/proguard.cfg file that says:
-keepnames class * implements android.os.Parcelable {
public static final ** CREATOR;
}
I had to mark the file properties as ProGuardConfiguration as shown here: https://learn.microsoft.com/en-us/previous-versions/xamarin/android/deploy-test/release-prep/proguard?tabs=windows
I also found this similar thread where you discussed similar issues: https://github.com/dotnet/maui/issues/13413
Thanks for the solution. I think that will need to be added as a Maui fix. I will update the bug report thread on this one.
Can you commit your changes to:
It seems like this default wildcard should work without update the project file, but then I realized MAUI has a copy:
Can you commit your changes to:
* https://github.com/jonmdev/WebViewR8Bug
Sure, done.
R8 by default?
Context: https://developer.android.com/studio/preview/features/#R8-enabled
We are already planning to enable D8 by default in some future Xamarin.Android release.
In the current Android Studio preview, R8 is enabled by default. (not just D8!)
To turn R8 off, you can add the following to your
build.gradle
:Looking through the details
minifyEnabled
also defaults tofalse
.Given R8's help output:
We think Android Studio is running R8 by default with
--no-minification
.This means:
I suspect the
--no-minification
switch is used, merely because it speeds up the build and perhaps it breaks Java debugging in some way?Investigation
To be confident in what is actually happening, we should create a Java class in Android Studio Preview that is using R8 by default. We should create an instance of the Java type and call it via Java's reflection APIs and see if that breaks.
If such Java reflection fails, then likely the "tree shaking" feature is for sure being used. C# will likely fail in the exact same way as Java refection, unfortunately.
We can test such a configuration in Xamarin.Android by doing:
NOTE: This project should have no proguard configuration files.
We will need to see what happens to a "hello world" Xamarin.Forms app using this combination.
Implementation
A big TODO here. More investigation is needed.