• ClassNotFoundException when unmarshalling: androidx.fragment.app.FragmentManagerState 神奇的 bug 修复之路


     

    崩溃栈信息:

    java.lang.RuntimeException: Unable to start activity ComponentInfo{global.longbridge.app.android/com.longbridge.wealth.mvp.ui.activity.WealthWithdrawActivity}: android.os.BadParcelableException: ClassNotFoundException when unmarshalling: androidx.fragment.app.FragmentManagerState
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3894)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4077)
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:91)
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:149)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:103)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2458)
    at com.longbridge.common.tracker.apm.hook.b.handleMessage(ProxyHandlerCallback.java:42)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:219)
    at android.app.ActivityThread.main(ActivityThread.java:8387)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1055)
    Caused by: android.os.BadParcelableException: ClassNotFoundException when unmarshalling: androidx.fragment.app.FragmentManagerState
    at android.os.Parcel.readParcelableCreator(Parcel.java:3042)
    at android.os.Parcel.readParcelable(Parcel.java:2964)
    at android.os.Parcel.readValue(Parcel.java:2866)
    at android.os.Parcel.readArrayMapInternal(Parcel.java:3244)
    at android.os.BaseBundle.initializeFromParcelLocked(BaseBundle.java:292)
    at android.os.BaseBundle.unparcel(BaseBundle.java:236)
    at android.os.Bundle.getParcelable(Bundle.java:951)
    at androidx.fragment.app.FragmentActivity$2.onContextAvailable(FragmentActivity.java:148)
    at androidx.activity.contextaware.ContextAwareHelper.dispatchOnContextAvailable(ContextAwareHelper.java:99)
    at androidx.activity.ComponentActivity.onCreate(ComponentActivity.java:297)
    at androidx.fragment.app.FragmentActivity.onCreate(FragmentActivity.java:273)
    at me.imid.swipebacklayout.lib.app.SwipeBackActivity.onCreate(SwipeBackActivity.java:17)
    at com.longbridge.common.base.FBaseActivity.onCreate(FBaseActivity.java:85)
    at com.longbridge.wealth.mvp.ui.activity.WealthWithdrawActivity.onCreate(Unknown Source:8)
    at android.app.Activity.performCreate(Activity.java:8121)
    at android.app.Activity.performCreate(Activity.java:8109)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1320)
    at com.qiyukf.unicorn.l.a.callActivityOnCreate(QiyuInstrumentation.java:258)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3867)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:4077)
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:91)
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:149)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:103)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2458)
    at com.longbridge.common.tracker.apm.hook.b.handleMessage(ProxyHandlerCallback.java:42)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:219)
    at android.app.ActivityThread.main(ActivityThread.java:8387)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1055)

    崩溃原因剖析:

    用户打开了使用到ViewPager+Fragment的页面后,长时间放置在后台当系统内存不足时被系统回收,Fragment的一些信息会在Activity调用onSaveInstanceState把这些信息通过Bundle的方式暂存起来,用户再次唤起此页面时会从暂存的savedInstanceState中尝试恢复页面,在此过程中 Android 10的系统中的BaseBundle.unparcel会抛出异常导致崩溃。
    是一个系统的bug,这异常只会发生在 Android 10 的版本,而且 Android 官方 Issue 那边有条相关的反馈,issue的 状态的 wont fix。 官方的回复是这个问题只会发生在 Android 10 预览版。 安卓 10 已经修复了这个问题,建议厂商升级软件版本。

    尝试的修复方案:

    方案一:
    https://blog.csdn.net/GYBIN02/article/details/115165448
    通过替换classLoader的方式进行修复: bundle.classLoader = context.classLoader
    修复结果:3.10.0正式版通过此方案进行了修复,修复失败
    方案二:
    解决思路就是处理savedInstanceState,不让它恢复android:support:fragments的内容.
    修复结果:通过热修复的方式下发了修复补丁,修复失败
    方案三:
    对指定页面的onCreate函数进行try catch容错处理,如果抛异常了,直接finish。
    修复结果:修复成功
    方案四:
    通过Hook的方式对发现崩溃的地方就行try catch,目前还在寻找hook方案
    遇见的难题:系统代码无法hook,只能对引入的库进行hook,目前在想办法尝试对FragmentActivity进行hook处理。
    修复结果:仍在寻找方案
    方案五:
    问题基本就定位到了,其实就是在activity重建时,传入的savedInstanceState本身ClassLoader是没问题的,问题出在它的子Bundle的子Bundle上,层级结构如下:
    savedInstanceState.getBundle("androidx.lifecycle.BundlableSavedStateRegistry.key").getBundle("android:support:fragment")
    问题是出在这个bundle的ClassLoader上,这里在android 10和9的机器上使用的是BootClassLoader,然后在解parcel的时候就崩溃了。
     
     
     @JvmStatic
        fun intercept(context: Context?, bundle: Bundle?) {
            if (bundle == null) return
            val condition = condition()
            if (context != null && condition) {
                bundle.classLoader = context.javaClass.classLoader
                // 需要修改的是bundle下androidx.lifecycle.BundlableSavedStateRegistry.key中子项的classloader
                bundle.getBundle("androidx.lifecycle.BundlableSavedStateRegistry.key")?.let {
                    it.keySet()?.forEach { key ->
                        (it.get(key) as? Bundle)?.classLoader = context.javaClass.classLoader
                    }
                }
            }
        }
    

      

    总结:
      采用方案5完美解决问题
    干我们这行,啥时候懈怠,就意味着长进的停止,长进的停止就意味着被淘汰,只能往前冲,直到凤凰涅槃的一天!
  • 相关阅读:
    【Linux】解压分卷压缩的zip文件
    kafka数据清理
    在 Kubernetes 上安装 Gitlab CI Runner Gitlab CI 基本概念以及 Runner 的安装
    APM监控--(三)zipkin部署手册
    K8S使用NodePort类型Service
    kubernetes基本概念 pod, service
    rsyslog配置解析
    日志收集之rsyslog to kafka
    linux auditd审计的简单使用和理解
    Nginx的try_files指令使用实例
  • 原文地址:https://www.cnblogs.com/whoislcj/p/15386155.html
Copyright © 2020-2023  润新知