Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android 10 BadParcelableException ClassNotFoundException when unmarshalling using Kotlin @Parcelize

In Firebase, I'm getting various crashes in my production app (uses Dexguard), while using Parcelable.

These crashes are now affecting almost 200 users and are grouped into 3 entries on Firebase.

In one entry, crashes are only on Samsung devices, in another, are only Xiaomi devices and in the other, are more brands but 81% are from HMD Global.

ALL these devices are running Android 10 so this might be a problem with this OS version. I can see that the crashes are contained to 5 or 6 custom objects. Other than that, some crashes are related to:

Fatal Exception: android.os.BadParcelableException: ClassNotFoundException when unmarshalling: androidx.fragment.app.FragmentManagerState
   at android.os.Parcel.readParcelableCreator(Parcel.java:3059)
   at android.os.Parcel.readParcelable(Parcel.java:2981)
   at android.os.Parcel.readValue(Parcel.java:2883)
   at android.os.Parcel.readArrayMapInternal(Parcel.java:3261)
   at android.os.BaseBundle.initializeFromParcelLocked(BaseBundle.java:292)
   at android.os.BaseBundle.unparcel(BaseBundle.java:236)
   at android.os.BaseBundle.size(BaseBundle.java:355)
   at android.app.servertransaction.LaunchActivityItem.hashCode(LaunchActivityItem.java:208)
   at java.util.AbstractList.hashCode(AbstractList.java:541)
   at java.util.Objects.hashCode(Objects.java:98)
   at android.app.servertransaction.ClientTransaction.hashCode(ClientTransaction.java:241)
   at android.app.servertransaction.TransactionExecutorHelper.tId(TransactionExecutorHelper.java:266)
   at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:86)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2220)
   at android.os.Handler.dispatchMessage(Handler.java:107)
   at android.os.Looper.loop(Looper.java:237)
   at android.app.ActivityThread.main(ActivityThread.java:8019)
   at java.lang.reflect.Method.invoke(Method.java)
   at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)

In one of my custom objects, I'm having this type of crash (for my other custom objects, the crash is the same).

Fatal Exception: android.os.BadParcelableException: ClassNotFoundException when unmarshalling: com.mypackagename.InfoData
       at android.os.Parcel.readParcelableCreator(Parcel.java:3059)
       at android.os.Parcel.readParcelable(Parcel.java:2981)
       at android.os.Parcel.readValue(Parcel.java:2883)
       at android.os.Parcel.readArrayMapInternal(Parcel.java:3261)
       at android.os.BaseBundle.initializeFromParcelLocked(BaseBundle.java:292)
       at android.os.BaseBundle.unparcel(BaseBundle.java:236)
       at android.os.BaseBundle.size(BaseBundle.java:355)
       at android.app.servertransaction.LaunchActivityItem.hashCode(LaunchActivityItem.java:208)
       at java.util.AbstractList.hashCode(AbstractList.java:541)
       at java.util.Objects.hashCode(Objects.java:98)
       at android.app.servertransaction.ClientTransaction.hashCode(ClientTransaction.java:241)
       at android.app.servertransaction.TransactionExecutorHelper.tId(TransactionExecutorHelper.java:266)
       at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:86)
       at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2220)
       at android.os.Handler.dispatchMessage(Handler.java:107)
       at android.os.Looper.loop(Looper.java:237)
       at android.app.ActivityThread.main(ActivityThread.java:8019)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)

As an example, here is an example of the models that I'm having crashes.

@Parcelize
class NumberDetails(internal var numbers: ArrayList<String> = arrayListOf(), var userState: UserState = UserState.INACTIVE) : Parcelable {

    fun clear() = numbers.clear()

    fun getNumbers(): String = numbers.joinToString("")
}

Another:

@Parcelize
data class InfoData(var needsCheck: Boolean = false, var amount: Double = 0.0, var fee: Double? = null) : Parcelable

And another:

abstract class Screen(open val identifier: String = "") : Parcelable {

    @Parcelize
    data class ActivateScreen(override val identifier: String) : Screen()


   //More entries like above
 }

The first example is an inner class while the second is declared in a file where I already have other stuff (don't know if this matters)

I'm unable to replicate the crash on any of my devices. Any idea why I'm having these crashes only on Android 10 devices?

UPDATE:

While trying to fix a crash that my app had, I was able to reproduce the FragmentManagerState crash, that is, my app crashed and then it crashed again with the FragmentManagerState crash. Although I can replicate my app crash always, the subsequent crash I was only to replicate it ONCE.

This was replicated in an Emulator running Android 10 and with Don't Keep Activities enabled. My app crash only happened due to the Don't Keep Activities enabled (in the markets that I work on, this is common scenario due to low-end devices)

In my app, I can have the following steps:

ActivityA -> ActivityB -> ActivityC -> ActivityD (PdfViewer) -> PickActivity (I/ActivityTaskManager: START u0 {act=android.intent.action.CREATE_DOCUMENT cat=[android.intent.category.OPENABLE] typ=application/pdf cmp=com.android.documentsui/.picker.PickActivity)

In ActivityD, a place where I can preview a PDF, I can click on a button to save the PDF in storage. That click on the button opens the system PickActivity. When I save the PDF and control is passed to ActivityC, my app crashes (only with DNKA enabled) since I'm not properly handling onSavedInstanceState.

From the logs (removed unnecessary stuff here) I can see:

I/ActivityTaskManager: START u0 {act=android.intent.action.CREATE_DOCUMENT cat=[android.intent.category.OPENABLE] typ=application/pdf cmp=com.android.documentsui/.picker.PickActivity (has extras)} from uid 10219
I/ActivityManager: Start proc 9418:com.android.documentsui/u0a50 for activity {com.android.documentsui/com.android.documentsui.picker.PickActivity}
I/ActivityManager: Start proc 9443:com.android.externalstorage/u0a56 for content provider {com.android.externalstorage/com.android.externalstorage.ExternalStorageProvider}
I/ActivityTaskManager: Displayed com.android.documentsui/.picker.PickActivity: +1s133ms
2016-3548/? I/ActivityTaskManager: START u0 {cmp=com.myapp.packagename/com.myapp.package.ActivityC} from uid 10219
2016-2323/? I/ActivityTaskManager: START u0 {cmp=com.myapp.packagename/com.myapp.package.ActivityC} from uid 10219

Then my app crashes due to the lack of proper handling of saved instance state

W/ActivityTaskManager: Activity top resumed state loss timeout for ActivityRecord{bdaedc1 u0 com.myapp.packagename/com.myapp.package.ActivityD t1250}
W/ActivityTaskManager: Activity pause timeout for ActivityRecord{bdaedc1 u0 com.myapp.packagename/com.myapp.package.ActivityD t1250}
W/ActivityTaskManager:   Force finishing activity com.myapp.packagename/com.myapp.package.ActivityC
W/ActivityTaskManager:   Force finishing activity com.myapp.packagename/com.myapp.package.ActivityC
I/ActivityManager: Process com.myapp.packagename (pid 8990) has died: fore TOP 
W/ActivityTaskManager: Force removing ActivityRecord{4b658e u0 com.myapp.packagename/com.myapp.package.ActivityB t1250}: app died, no saved state
W/ActivityTaskManager: Force removing ActivityRecord{210b4e5 u0 com.myapp.packagename/com.myapp.package.Activitya t1250}: app died, no saved state
I/ActivityManager: Start proc 9609:com.myapp.packagename/u0a219 for activity {com.myapp.packagename/com.myapp.package.ActivityD}
W/ActivityTaskManager: Activity top resumed state loss timeout for ActivityRecord{5d7ded3 u0 com.myapp.packagename/com.myapp.package.ActivityC t-1 f}

I now can see by the logs that my app is launched (logs from my application class)

I/ActivityTaskManager: START u0 {flg=0x10008000 cmp=com.myapp.packagename/com.myapp.package.SplashActivity} from uid 10219
I/ActivityTaskManager: START u0 {cmp=com.myapp.packagename/com.myapp.package.SplashActivity} from uid 10219
 W/ActivityTaskManager: startActivity called from finishing ActivityRecord{bdaedc1 u0 com.myapp.packagename/com.myapp.package.ActivityD t1250 f}; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: Intent { cmp=com.myapp.packagename/com.myapp.package.SplashActivity }
W/ActivityTaskManager: Duplicate finish request for ActivityRecord{bdaedc1 u0 com.myapp.packagename/com.myapp.package.ActivityD t1250 f}
W/ActivityTaskManager: Duplicate finish request for ActivityRecord{685f9ab u0 com.myapp.packagename/com.myapp.package.ActivityC t1250 f}
W/ActivityTaskManager: Activity top resumed state loss timeout for ActivityRecord{bdaedc1 u0 com.myapp.packagename/com.myapp.package.ActivityD t1250 f}
W/ActivityTaskManager: Activity pause timeout for ActivityRecord{bdaedc1 u0 com.myapp.packagename/com.myapp.package.ActivityD t1250 f}

And then:

9609-9609/com.myapp.packagename E/Parcel: Class not found when unmarshalling: androidx.fragment.app.FragmentManagerState
    java.lang.ClassNotFoundException: androidx.fragment.app.FragmentManagerState

While analyzing the logs I could see that one of my activities was appearing twice. I managed to reproduce that with fast multiple clicking on the button that launches that activity. I then tried to replicate it. Restarted the flow, double-clicked the button, tried to save the PDF, and after the app crash, I could see the FragmentManagerState crash. I was able to reproduce this only once.

1 - Since all my crashes are related to BadParcelableException (ones from FragmentManagerState and others from other things), and with the above mentioned in mind, could the crashes that I'm seeing on the play store be marked as BadParcelableException but are crashes related to other things in my app, that also triggers the BadParcelableException crashes and PlayStore and Firebase only show the later ones? 2 - Any suggestion on what could I improve to properly log the crashes in my app?

like image 952
Favolas Avatar asked Nov 06 '22 02:11

Favolas


1 Answers

This problem was reported a year ago for your first stack trace, the one referring to FragmentManagerState. It seems to be tied to an Android 10-specific bug.

For your InfoState crash, putting the object into the bundle as a byte[] should clear up the problem. That is not an option for you with FragmentManagerState, though, as that is being done deeper in the Jetpack.

You might want to confirm that you are on the latest androidx.fragment and androidx.activity libraries, in case they added a workaround. Otherwise, you might review the comments on that issue, as some developers reported some solutions, but they are rather specific and may or may not relate to your scenario.

like image 88
CommonsWare Avatar answered Nov 11 '22 09:11

CommonsWare