Why do I get RemoteServiceException for creating/u

2019-04-27 06:01发布

问题:

Background

I have a spare time app that I've been working on for some years (here), and I try to handle as many crashes as I can (I hate seeing crash reports!).

The problem

One recent crash that seem quite new, is this one:

android.app.RemoteServiceException: 
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:1768)
  at android.os.Handler.dispatchMessage (Handler.java:106)
  at android.os.Looper.loop (Looper.java:164)
  at android.app.ActivityThread.main (ActivityThread.java:6494)
  at java.lang.reflect.Method.invoke (Method.java)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:438)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:807)

And that's all that I see...

It seems to occur only for Android 8.1. Since the app has got to be quite popular, I'm very sure it will still occur only on Android 8.1.

What I've tried

Searching the Internet, I could find similar crashes, but in all of them, they had more clues.

So I tried to recall what the recent changes that I've done. The only changes were of migrating the support library to Android-X. The rest of the changes are very minor and I don't think they can be the cause for it.

Because I don't have any further clues, I decided to report about the Android-X part here (more information there, if needed), as I don't believe it's because of me trying to fix issues, and it looks like something very specific.

Later I integrated Firebase Crashlytics, and got this tiny additional clue above each such log:

Fatal Exception: android.app.RemoteServiceException
Bad notification for startForeground: java.lang.RuntimeException: invalid channel for service notification: Notification(channel=channel_id__app_monitor pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x40 color=0x00000000 category=service vis=SECRET)

This is weird, because I do open the service correctly, otherwise it wouldn't have worked at all, and this is especially weird that this occurs only on Android 8.1, and not on 8.0 for example, which has the same requirement of how to start a foreground service.

This problematic notification is of a foreground service that I use to globally monitor app-related events (only from Android O, which has restrictions of BroadcastReceivers). It gets updated on 2 cases:

  1. Locale change
  2. Ticking a checkbox on some dialog that appears at some point (upon clicking on the dialog).

When I've tested both of those, they work fine, on both Android 8.0 and 8.1.

Here's the code to create/update the notification:

    @JvmStatic
    fun getUpdatedAppMonitorNotification(context: Context): Notification {
        val builder = Builder(context, context.getString(R.string.channel_id__app_monitor)).setSmallIcon(R.drawable.ic_stat_app_icon)//
                .setPriority(Notification.PRIORITY_DEFAULT).setCategory(Notification.CATEGORY_SERVICE)
        builder.setVisibility(NotificationCompat.VISIBILITY_SECRET)
        builder.setShowWhen(false)
        if (!PreferenceUtil.getBooleanPref(context, R.string.pref__avoid_showing_app_monitor_notification_dialog, false))
            builder.setContentTitle(context.getString(R.string.app_monitor__notification_title))
        if (VERSION.SDK_INT < VERSION_CODES.P) {
            val mainIntent = Intent(context, MainActivity::class.java)
                    .putExtra(MainActivity.EXTRA_OPENED_FROM_NOTIFICATION, true)
            builder.setContentIntent(PendingIntent.getActivity(context, 0, mainIntent, PendingIntent.FLAG_UPDATE_CURRENT))
        } else {
            val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
                    .putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
                    .putExtra(Settings.EXTRA_CHANNEL_ID, context.getString(R.string.channel_id__app_monitor))
            val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
            builder.setContentIntent(pendingIntent)
        }
        return builder.build()
    }

And the code I use in the service:

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
    NotificationId.initNotificationsChannels(this)
    val notification = getUpdatedAppMonitorNotification(this)
    startForeground(NotificationId.APP_MONITOR, notification)
    ...
    return super.onStartCommand(intent, flags, startId)
}

And this is the code I call from other places, to update the notification:

    @JvmStatic
    fun updateAppMonitorNotification(context: Context) {
        if (VERSION.SDK_INT < VERSION_CODES.O)
            return
        val notification = AppMonitorService.getUpdatedAppMonitorNotification(context)
        val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.notify(NotificationId.APP_MONITOR, notification)
    }

The questions

  1. Why does it occur? Is it about Android X ? Or something wrong with the notification building?

  2. Why does it occur only on Android 8.1 ?

回答1:

OK, I still don't know why this occurs, but a workaround for this that I've found, is to let the service do all of the updating of its notification, by safely just calling it via the context.startForegroundService function.

So far, by using this instead, I still don't see any crashes of this sort.



回答2:

I think this is the problem:

.putExtra(Settings.EXTRA_CHANNEL_ID, context.getString(R.string.channel_id__app_monitor))

You need to put the (unchanging) channel id, not the localized channel name

If you are able to reproduce this you can also look in your bugreport for AppSettings.*[your app] and see if there is a channel with an id matching the one you're trying to use.