Troubleshooting Android App Crash on Chromebook
One thing is true for all developers - that is, with wide enough distribution, if a user can do something with your app, they will. If you’re building apps for Android, you will eventually have users running your app on their Chromebook. This is great for those looking for a laptop-like experience with your Android app, but what do you do when your app crashes only on Chromebook?
The official ARC developer docs have some great materials on troubleshooting, involving putting the device into “Developer mode” and connecting adb. While that may be great for your development environment, it’s clearly not practical for end users. As it turns out, there’s a much easier way. Here’s what I did:
Have the user reproduce the issue. When the app crashes, they should select the “Send feedback” option. The feedback mechanism may not complete, but that’s okay since it will save feedback to the Chromebook logs.
Next, have the user put the following in the address bar of Chrome chrome://net-internals
and then select “ChromeOS”.
They can then click the “Store System and User Logs” button. After a few moments, a tarball containing logs will show up in their Downloads folder, e.g. combined-logs_20200222-081143.tar.gz
Have them send that to you. In my case, the file was too big for email so I used a file sharing service (e.g. via Google Drive, Dropbox, etc.)
When you receive the tarball, extract it and open the file feedback/arc-bugreport
. If you’re lucky, you’ll find a stack trace of your app crash in there. Mine looked like this:
02-22 08:04:13.732 1608 1608 I art : Rejecting re-init on previously-failed class java.lang.Class<com.greensopinion.rideweather.activity.StatusActivity>: java.lang.LinkageError: Method boolean com.greensopinion.rideweather.activity.StatusActivity.isResumed() overrides final method in class Landroid/app/Activity; (declaration of 'com.greensopinion.rideweather.activity.StatusActivity' appears in /data/app/com.greensopinion.rideweather-1/base.apk:classes2.dex)
02-22 08:04:13.732 1608 1608 I art : at java.lang.Class java.lang.VMClassLoader.findLoadedClass!(java.lang.ClassLoader, java.lang.String) (VMClassLoader.java:-2)
02-22 08:04:13.732 1608 1608 I art : at java.lang.Class java.lang.ClassLoader.findLoadedClass(java.lang.String) (ClassLoader.java:742)
02-22 08:04:13.732 1608 1608 I art : at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String, boolean) (ClassLoader.java:362)
02-22 08:04:13.732 1608 1608 I art : at java.lang.Class java.lang.ClassLoader.loadClass(java.lang.String) (ClassLoader.java:312)
02-22 08:04:13.732 1608 1608 I art : at android.app.Activity android.app.Instrumentation.newActivity(java.lang.ClassLoader, java.lang.String, android.content.Intent) (Instrumentation.java:1078)
02-22 08:04:13.732 1608 1608 I art : at android.app.Activity android.app.ActivityThread.performLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.content.Intent) (ActivityThread.java:2626)
02-22 08:04:13.732 1608 1608 I art : at void android.app.ActivityThread.handleLaunchActivity(android.app.ActivityThread$ActivityClientRecord, android.content.Intent, java.lang.String) (ActivityThread.java:2800)
02-22 08:04:13.732 1608 1608 I art : at void android.app.ActivityThread.-wrap12(android.app.ActivityThread, android.app.ActivityThread$ActivityClientRecord, android.content.Intent, java.lang.String) (ActivityThread.java:-1)
02-22 08:04:13.732 1608 1608 I art : at void android.app.ActivityThread$H.handleMessage(android.os.Message) (ActivityThread.java:1527)
02-22 08:04:13.732 1608 1608 I art : at void android.os.Handler.dispatchMessage(android.os.Message) (Handler.java:102)
02-22 08:04:13.732 1608 1608 I art : at void android.os.Looper.loop() (Looper.java:154)
02-22 08:04:13.732 1608 1608 I art : at void android.app.ActivityThread.main(java.lang.String[]) (ActivityThread.java:6320)
02-22 08:04:13.732 1608 1608 I art : at java.lang.Object java.lang.reflect.Method.invoke!(java.lang.Object, java.lang.Object[]) (Method.java:-2)
02-22 08:04:13.732 1608 1608 I art : at void com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run() (ZygoteInit.java:891)
02-22 08:04:13.732 1608 1608 I art : at void com.android.internal.os.ZygoteInit.main(java.lang.String[]) (ZygoteInit.java:781)
You might wonder why I’d override a final method in android.app.Activity
. Well, the short answer is that I made a mistake. For me the method only showed up on the Chromebook - i.e. not in the Android SDK, in the emulator or on my two Android test devices. It turns out that I should have known, see Fragment.isResumed()
With the stack trace in-hand, it’s a trivial matter to resolve the issue. Best of all, no “Developer mode” required on the Chromebook!
Recent Posts
- Flutter Maps With Vector Tiles
- Raspberry Pi SSH Setup
- Raspberry Pi Development Flow
- Troubleshooting Android App Crash on Chromebook
- Article Index
subscribe via RSS