Repository navigation
Enhanced Fast Deployment doesn't work with Application subclasses #2730
Description
While checking the accuracy of what I had written for the Xamarin.Android 9.2 preview release notes related to Enhanced Fast Deployment, I realized I should check the exact old test case from Xamarin Bugzilla Bug 55050. It turns out the test case fails with a different error with the new version of Enhanced Fast Deployment. The error on an Android 8.0 emulator is very similar to the one seen by a user in Developer Community 435111 (probably only different because I'm using a newer preview version), but the error is different on an Android 7.1 emulator and on an Android 9.0 device, so I am filing a new issue to record all 3 versions of the error message.
Steps to Reproduce
-
Download the test case.
-
Build and install the app with enhanced fast deployment enabled:
msbuild -t:Install -p:DefineConstants=INCLUDE_APP
-
Run the app.
Expected Behavior
The app launches successfully and displays the "HELLO WORLD, CLICK ME!" button. (This is how the test case behaves when Enhanced Fast Deployment is disabled.)
Actual Behavior
The app exits unexpectedly during initialization.
Excerpt from the adb logcat output on Android 9.0 (API level 28) arm64-v8a Google Pixel 3 device
AndroidRuntime: Shutting down VM
--------- beginning of crash
AndroidRuntime: FATAL EXCEPTION: main
AndroidRuntime: Process: scratch.bxc55050, PID: 7870
AndroidRuntime: java.lang.IllegalAccessError: Illegal class access: 'mono.android.Runtime' attempting to access 'mono.android.GCUserPeer' (declaration of 'mono.android.Runtime' appears in /data/app/scratch.bxc55050--x-XSYlRTtX_PyHDVMsL9A==/base.apk)
AndroidRuntime: at mono.android.Runtime.<clinit>(Runtime.java:8)
AndroidRuntime: at mono.android.Runtime.init(Native Method)
AndroidRuntime: at mono.MonoPackageManager.LoadApplication(MonoPackageManager.java:51)
AndroidRuntime: at mono.MonoRuntimeProvider.attachInfo(MonoRuntimeProvider.java:42)
AndroidRuntime: at android.app.ActivityThread.installProvider(ActivityThread.java:6402)
AndroidRuntime: at android.app.ActivityThread.installContentProviders(ActivityThread.java:5949)
AndroidRuntime: at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5864)
AndroidRuntime: at android.app.ActivityThread.access$1100(ActivityThread.java:200)
AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1651)
AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:106)
AndroidRuntime: at android.os.Looper.loop(Looper.java:193)
AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:6680)
AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
ActivityManager: Force finishing activity scratch.bxc55050/md58bfd9258c6beb71a97a5dd7a0600aa01.MainActivityExcerpt from the adb logcat output on Android 8.0 (API level 26) x86 emulator
AndroidRuntime: Shutting down VM
--------- beginning of crash
AndroidRuntime: FATAL EXCEPTION: main
AndroidRuntime: Process: scratch.bxc55050, PID: 6136
AndroidRuntime: java.lang.UnsatisfiedLinkError: No implementation found for void mono.android.Runtime.init(java.lang.String, java.lang.String[], java.lang.String, java.lang.String[], java.lang.ClassLoader, java.lang.String[], java.lang.String[], java.lang.String, int, java.lang.String[]) (tried Java_mono_android_Runtime_init and Java_mono_android_Runtime_init__Ljava_lang_String_2_3Ljava_lang_String_2Ljava_lang_String_2_3Ljava_lang_String_2Ljava_lang_ClassLoader_2_3Ljava_lang_String_2_3Ljava_lang_String_2Ljava_lang_String_2I_3Ljava_lang_String_2)
AndroidRuntime: at mono.android.Runtime.init(Native Method)
AndroidRuntime: at mono.MonoPackageManager.LoadApplication(MonoPackageManager.java:51)
AndroidRuntime: at mono.MonoRuntimeProvider.attachInfo(MonoRuntimeProvider.java:42)
AndroidRuntime: at android.app.ActivityThread.installProvider(ActivityThread.java:6239)
AndroidRuntime: at android.app.ActivityThread.installContentProviders(ActivityThread.java:5805)
AndroidRuntime: at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5722)
AndroidRuntime: at android.app.ActivityThread.-wrap1(Unknown Source:0)
AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1656)
AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:106)
AndroidRuntime: at android.os.Looper.loop(Looper.java:164)
AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:6494)
AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
ActivityManager: Force finishing activity scratch.bxc55050/md58bfd9258c6beb71a97a5dd7a0600aa01.MainActivity
Excerpt from the adb logcat output on Android 7.1 (API level 25) x86 emulator
AndroidRuntime: Shutting down VM
--------- beginning of crash
AndroidRuntime: FATAL EXCEPTION: main
AndroidRuntime: Process: scratch.bxc55050, PID: 31891
AndroidRuntime: java.lang.IllegalAccessError: Illegal class access: 'mono.MonoPackageManager' attempting to access 'mono.MonoPackageManager_Resources' (declaration of 'mono.MonoPackageManager' appears in /data/app/scratch.bxc55050-1/base.apk)
AndroidRuntime: at mono.MonoPackageManager.LoadApplication(MonoPackageManager.java:54)
AndroidRuntime: at mono.MonoRuntimeProvider.attachInfo(MonoRuntimeProvider.java:42)
AndroidRuntime: at android.app.ActivityThread.installProvider(ActivityThread.java:5853)
AndroidRuntime: at android.app.ActivityThread.installContentProviders(ActivityThread.java:5445)
AndroidRuntime: at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5384)
AndroidRuntime: at android.app.ActivityThread.-wrap2(ActivityThread.java)
AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1545)
AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:102)
AndroidRuntime: at android.os.Looper.loop(Looper.java:154)
AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:6119)
AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
ActivityManager: Force finishing activity scratch.bxc55050/md58bfd9258c6beb71a97a5dd7a0600aa01.MainActivityVersion Information
Visual Studio 2019 Int Preview
Xamarin.Android SDK 9.1.103.12 (HEAD/7e1c4688)
VS bug #790706
Activity
dellis1972 commentedon Jul 29, 2019
Looks like this is "mostly" working. The only combination that still doesn't seem to work is
which is a bit weird.
dellis1972 commentedon Sep 18, 2019
I managed to figure out why the combination above does not work.
The problem is this, when we are using enhanced fast deployment we deploy a small subset of our java runtime. This contains the ContentProviders that get the application running. This works for normal applications because they use the
Applicationclass directly. This is provided by the android runtime.In the case of a custom application, we need the java side of the C# class in order to create the object. The problem here is the java code is NOT in the app, but in the
.__override__directory which we use for fast deployment. Seeing as it is theApplicationwhich is responsible for creating the ContentProviders and its the ContentProviders which tell Java where to find the classes.dex files in the.__override__directory this was never going to work.What we need to do is somehow include the
Applicationsubclass and all its dependencies in the apk. We also need to make sure they are excluded from any .dex file which is fast deployed. This is because the android runtime errors if it finds duplicate classes.This is going to take some time to figure out and I suspect it will require changes to the
GenerateJavaStubsTask and it's dependencies.dellis1972 commentedon Sep 18, 2019
Unit test added #3408
dellis1972 commentedon Jan 13, 2020
Still unsure how to fix the last case of a Custom App and FastDev.
Any ideas @jonathanpeppers @pjcollins ? This comment #2730 (comment) pretty much summarises what is going on.
jonathanpeppers commentedon Jan 13, 2020
Maybe we need to figure out how they deploy java code changes with Apply Changes and go about it a different way?
The parts of
Apply Changeswe would need here might be small. We have the benefit of restarting the app, while they are doing a "java hot reload".Bump to xamarin/monodroid/main@93ab95e18 (#8959)