仅在运行 Android 12 的 Pixel 设备上出现 CannotDeliverBroadcastException

Tom*_*son 29 android broadcastreceiver google-pixel android-12

我发现 Crashlytics 发生了崩溃,但我无法重现或找到其原因。该崩溃仅发生在运行 Android 12 的 Google Pixel 设备上,并且崩溃始终发生在后台。

显示崩溃的图片仅发生在运行 Android 12 的 Pixel 设备上

这是来自 Crashlytics 的崩溃日志:

Fatal Exception: android.app.RemoteServiceException$CannotDeliverBroadcastException: can't deliver broadcast
   at android.app.ActivityThread.throwRemoteServiceException(ActivityThread.java:1939)
   at android.app.ActivityThread.access$2700(ActivityThread.java:256)
   at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2190)
   at android.os.Handler.dispatchMessage(Handler.java:106)
   at android.os.Looper.loopOnce(Looper.java:201)
   at android.os.Looper.loop(Looper.java:288)
   at android.app.ActivityThread.main(ActivityThread.java:7870)
   at java.lang.reflect.Method.invoke(Method.java)
   at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
Run Code Online (Sandbox Code Playgroud)

我看过类似的问题(比如thisthis),但 Crashlytics 显示这些用户都有足够的可用内存,并且我们的代码库中没有任何地方可以调用registerReceiversendBroadcast所以第二个问题中的解决方案没有任何帮助。

根据有限的日志,我很确定当用户收到推送通知时会发生崩溃,但我有一台运行 Android 12 的 Google Pixel 4a,在向自己发送通知时根本无法重现它。

我们有一个习惯FirebaseMessagingService来监听我们在清单中注册的通知,还有一些BroadcastReceiver监听地理围栏更新并WorkManager在检测到转换时利用来执行一些工作。最近唯一改变的是我们更新为使用Android 的应用程序启动库WorkManager来初始化自身,但我不确定这是否相关,因为崩溃日志没有给我任何信息,以及我们的实现是否存在问题它不会仅限于运行 Android 12 的 Pixel 设备。

有人以前见过这个吗?或者运行 Android 12 的 Pixel 设备上是否存在专门的错误?我花了几个小时深入研究这个问题,但完全不知所措。

Rob*_*ham 16

关于 Android 13,而不是 12 上的早期问题,这里有一个 Google 跟踪器问题,在撰写本文时已分配该问题,但正在等待有意义的响应。

该问题的摘要是,它仅发生在 13 上,并且仅发生在 Pixel 设备上。

CommonsWare在此处有一个关于此问题的博客条目,我在任何地方找到的唯一其他线索是在 GrapheneOS 的变更日志中,此处有以下行条目:

沙盒化 Google Play 兼容层:不向用户报告 CannotDeliverBroadcastException

我们使用这个 Play 库并遇到了这个错误,因此 Graphene 可能遇到了这个问题,并且不得不进行操作系统修复。

更新:

我暂时相信我们作为一个应用程序已经抑制了这个问题,并阻止它污染我们的统计数据。

我们设置了一个异常处理程序来吸收它,这就是 GrapheneOS 正在做的事情——归功于他们。

class CustomUncaughtExceptionHandler(
    private val uncaughtExceptionHandler: Thread.UncaughtExceptionHandler) : Thread.UncaughtExceptionHandler {

    override fun uncaughtException(thread: Thread, exception: Throwable) {
        if (shouldAbsorb(exception)) {
            return
        }
        uncaughtExceptionHandler.uncaughtException(thread, exception)
    }

    /**
     * Evaluate whether to silently absorb uncaught crashes such that they
     * don't crash the app. We generally want to avoid this practice - we would
     * rather know about them. However in some cases there's nothing we can do
     * about the crash (e.g. it is an OS fault) and we would rather not have them
     * pollute our reliability stats.
     */
    private fun shouldAbsorb(exception: Throwable): Boolean {
        return when (exception::class.simpleName) {

            "CannotDeliverBroadcastException" -> true

            else -> false
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我们必须对类名字符串进行操作,因为 CannotDeliverBroadcastException 类是隐藏的,我们无法使用。

我们在 Application.onCreate() 方法的早期安装这个处理程序,如下所示:

val defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler()
Thread.setDefaultUncaughtExceptionHandler(
    CustomUncaughtExceptionHandler(defaultUncaughtExceptionHandler)
)
Run Code Online (Sandbox Code Playgroud)

我对此可能有点不成熟,但到目前为止,这还没有导致 Play 管理中心中出现任何崩溃。有一些确实出现在我们的其他报告平台中,其中报告的内容/未报告的内容始终各不相同。

需要明确的是,我并不是说这是一种好方法,或者您必须采取的方法。它需要客户端版本,并且有掩盖与此根本原因无关的异常的风险。Google 有责任在收集数据时解决或忽略此问题。然而,它似乎已经停止了对我们标题可靠性统计数据的影响,所以我想我会分享它作为一种可能性。

  • 看来谷歌终于承认了这个问题,并表示他们将在[此处](https://issuetracker.google.com/issues/245258072#comment60)解决这个问题,同时也支持您发布的快速修复。所以我会接受这个答案,我们终于可以将其标记为已解决! (3认同)