CannotDeliverBroadcastException only on Pixel devices running Android 12
Asked Answered
P

4

30

I'm seeing a crash come through Crashlytics that I'm unable to reproduce or locate the cause of. The crash only ever happens on Google Pixel devices running Android 12, and the crash always happens in the background.

Image showing the crash only happens on Pixel devices running Android 12

This is the crash log from 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)

I've looked at similar questions (like this and this) but Crashlytics is showing that these users all have plenty of free memory, and nowhere in our codebase are we calling registerReceiver or sendBroadcast so the solutions in that second question aren't any help.

Based on limited logs I'm pretty sure the crash happens when the user receives a push notification, but I have a Google Pixel 4a running Android 12 and I haven't been able to reproduce it at all when sending myself notifications.

We have a custom FirebaseMessagingService to listen for notifications that we register in the Manifest and a couple of BroadcastReceivers that listen for geofencing updates and utilize WorkManager to do some work when a transition is detected. The only thing that's changed with any of those recently is we updated WorkManager to initialize itself using Android's app startup library, but I'm not sure if that's even relevant since the crash logs give me no information, and if there was a problem with our implementation it wouldn't limit itself to just Pixel devices running Android 12.

Has anyone see this before or is there a bug exclusively on Pixel devices that run Android 12? I've spent hours digging into this and am at a complete loss.

Plovdiv answered 7/7, 2022 at 18:50 Comment(8)
I have the same issue, with the same devices (100% Google on Android 12), same unhelpful stack trace. I doubt my minimal use of broadcasts could cause this, but I've pushed countless updates to no avail. I'm not even sure that the "crash" is visible. I may have seen it on previous Android versions, but my logs don't go that far back. Hopefully Android 13 will address it.Dutchman
Any update on the issue? also facing similar crash on Android 13?Periphrastic
Based on our logs, I don't think users are seeing this crash. The usual setup is the user puts our app in the background and hours later it crashes. And we aren't sending any broadcasts either. I'm thinking this may be a cause of one of our libraries, but we haven't been able to locate which oneKalidasa
@SidakpreetN Also seeing crashes on Android 13.Kalidasa
I got this on mine too. Funny this is that I'm not using a thread/loop, broadcast or anything similar in my app at all. Only thing that comes to mind is the admob, it might be using it.Elvera
@BrianM No admob here, just Firebase Crashlytics/Analytics/Remote Config, and Google Cast. Given that it doesn’t seem to be user visible I’m not worrying too much. The lack of data about the specific broadcast in the exception message is the most annoying thing.Dutchman
Noticed this on my Pixel 6 with Android 13 Beta, while the app was in the background. Using FCM, no admob.Wether
Same here, 100% Android 13 devices, all PixelImide
R
17

With reference to Android 13, rather than earlier issues on 12, there is a Google tracker issue here, which at the time of writing is assigned but awaiting a meaningful response.

A summary of the issue is that it only occurs on 13, and only on Pixel devices.

CommonsWare has a blog entry on this here, and the only other clue I found anywhere was in the changelog for GrapheneOS, here, which has this line entry:

Sandboxed Google Play compatibility layer: don't report CannotDeliverBroadcastException to the user

We use this Play library and experience the fault, so it's possible Graphene have encountered this and had to put in an OS fix.

Update:

I tentatively believe that we as an app have suppressed this issue, and stopped it polluting our stats.

We set an exception handler to absorb it, which is what GrapheneOS are doing - credit to them.

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
        }
    }
}

We have to operate off class name strings because the CannotDeliverBroadcastException class is hidden and not available to us.

We install this handler early in the Application.onCreate() method, like this:

val defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler()
Thread.setDefaultUncaughtExceptionHandler(
    CustomUncaughtExceptionHandler(defaultUncaughtExceptionHandler)
)

I might be a bit premature with this, but so far this has resulted in none of these crashes appearing in Play Console. A few did appear in our other reporting platform, where what is/isn't reported has always varied.

To be clear, I'm not suggesting this is a good approach, or one that you should necessarily take. It requires a client release and it risks masking exceptions not relating to this root cause. Fixing or ignoring this issue at the point of collection is Google's responsibility. However, it has seemingly stopped the impact on our headline reliability statistics, so I thought I'd share it as a possibility.

Resh answered 17/10, 2022 at 20:55 Comment(8)
Looks like Google finally acknowledged the problem and said they'll get a fix out here, while also endorsing the quick fix you posted. So I'll accept this as the answer and we can finally mark this as resolved!Plovdiv
Would you recommend calling this straight after super.onCreate()?Geminian
Mark, you can, yes. The only minor consideration is whether you might have any other handlers, e.g. reporting libraries. The last installed handler should get called first, and it will be its decision as to whether the rest of the chain gets called. So if you don't want this to show up in that reporting (Play Console aside), initialise this after the others. Hopefully that makes sense.Resh
You may not see crash log with this approach but your app will be in a unusable state even when user open it. So for me, you should not do that.Cowhide
@Cowhide what evidence do you have for this?Resh
@RobPridham you can test it yourself with any crash. Eg, throw any exception and absorb it in your exception handler.Cowhide
I tried this solution but I still see same crash on crashlytics. Fatal Exception: android.app.RemoteServiceException$CannotDeliverBroadcastException %100 Samsung Device - %100 Android 13 What can I do additional that you mentioned?Peptide
@Rob Pridham Will this portion of code actually prevent the crash from happen? or is it just silence the reporting to play console / firebase? Our app do have functionality the build on broadcast receiver (registered in manifest) - hence we need to actually prevent this crash from happen rather than silence the reporting. thankRobles
K
4

Our team has noticed a significant downtrend in this crash over the past few months. Possible Google has begun to roll out a fix for Pixel devices. We also have the same crash happening for Pixels running Android 13 and it's also seeing a downtrend. Hopefully others are seeing this as well.

enter image description here

Kalidasa answered 16/9, 2022 at 14:18 Comment(1)
Thanks for the update! We aren't seeing the same downtrend yet but also don't have as many users experiencing it as you, so hopefully you're right and they are rolling out a fix. If only Google provided some visibility into the problem!Plovdiv
M
1

I received a pre-launch report of my app showing the same problem:

android.app.RemoteServiceException$CannotDeliverBroadcastException: can't deliver broadcast

Device: google Redfin 64-bit only Android version: Android 13 (SDK 33)

The solution proposed by Rob Pridham fixed the problem. Just in case someone prefers to use Java...

This is the CustomUncaughtExceptionHandler class added to MainActivity:

public static final class CustomUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
        private final Thread.UncaughtExceptionHandler uncaughtExceptionHandler;

        public void uncaughtException(@NotNull Thread thread, @NotNull Throwable exception) {
            Intrinsics.checkNotNullParameter(thread, "thread");
            Intrinsics.checkNotNullParameter(exception, "exception");
            if (!this.shouldAbsorb(exception)) {
                this.uncaughtExceptionHandler.uncaughtException(thread, exception);
            }
        }

        private boolean shouldAbsorb(Throwable exception) {
            String var10000 = Reflection.getOrCreateKotlinClass(exception.getClass()).getSimpleName();
            if (var10000 != null) {
                return "CannotDeliverBroadcastException".equals(var10000);
            }
            return false;
        }

        public CustomUncaughtExceptionHandler(@NotNull Thread.UncaughtExceptionHandler uncaughtExceptionHandler) {
            super();
            Intrinsics.checkNotNullParameter(uncaughtExceptionHandler, "uncaughtExceptionHandler");
            this.uncaughtExceptionHandler = uncaughtExceptionHandler;
        }
    }

This is the code added to Oncreate:

Thread.UncaughtExceptionHandler uncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
assert uncaughtExceptionHandler != null;
Thread.setDefaultUncaughtExceptionHandler(new CustomUncaughtExceptionHandler(uncaughtExceptionHandler));
Mendy answered 5/2, 2023 at 1:49 Comment(0)
P
0

I'm not sure if this will be helpful to anyone, but once we removed WorkManager (which was being initialized via the App Startup library) the crash stopped happening. This was removed alongside a bunch of other code, so I can't say for sure if WorkManager was the problem, if the App Startup library was the problem, or if something else that we removed fixed it.

Plovdiv answered 6/9, 2022 at 20:25 Comment(3)
No WorkManager for me, but I am using JobScheduler which presumably uses the same infrastructure. Perhaps it's related to a broadcast that initiates some form of Job/Work, but I'm yet to recreate it.Dutchman
Weird, not using WorkManager or the work:work-runtime in our app. I have however noticed a downtrend in the crash over the past month.Kalidasa
To add more to the confusion, the crash now started showing back up only for Pixels running Android 13. So I'm back at a loss.Plovdiv

© 2022 - 2024 — McMap. All rights reserved.