4

We recently implemented foreground service and on Android 9 (Samsung devices only) some users experience some recurring crashes and we don't know what's causing this. Has anyone encountered the same issue? Is there a fix for this issue?

Fatal Exception: android.app.RemoteServiceException Context.startForegroundService() did not then call Service.startForeground()
android.app.ActivityThread$H.handleMessage (ActivityThread.java:1874)
android.os.Handler.dispatchMessage (Handler.java:106)
android.os.Looper.loop (Looper.java:214)
android.app.ActivityThread.main (ActivityThread.java:7073)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:494)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:964)

AndroidManigest.xml

<service
        android:name="com.sotg.base.util.GeoNotification"
        android:exported="true"
        android:foregroundServiceType="location" />

GeoNotificationManager.kt

    override fun startService() {
        val geoService = Intent(context, GeoNotification::class.java)
        geoService.action = GeoNotification.START_SERVICE_ACTION

        // for android Oreo and higher start as foreground
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            context.startForegroundService(geoService)
        } else {
            context.startService(geoService)
        }
    }

    override fun stopService() {

        // Shouldn't initialize the service to stop it when the service is not running.
        if (!GeoNotification.isServiceRunning()) return;

        val geoService = Intent(context, GeoNotification::class.java)
        geoService.action = GeoNotification.STOP_TRACKING_ACTION
        runCatching { context.startService(geoService) }
                .onFailure(analytics::logException)
    }

GoeNotification.java

    private static boolean isServiceRunning;

    public static boolean isServiceRunning() {
        return isServiceRunning;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        isServiceRunning = false;
    }

    @Override
    public void onDestroy() {
        stopTracking();
        super.onDestroy();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (START_SERVICE_ACTION.equals(intent.getAction())) {
            startTracking();
        } else if (STOP_TRACKING_ACTION.equals(intent.getAction())) {
            stopTracking();
        } else {
            Log.w(TAG, "Unknown action for location service");
        }

        // Service restarts if it gets terminated
        // the original Intent is re-delivered to the onStartCommand
        // method when using START_REDELIVER_INTENT.
        return START_REDELIVER_INTENT;
    }

 private void startTracking() {

        if (isServiceRunning) return;

        // create notification and config as foreground only for android Oreo and higher
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForeground(Constants.NOTIFY_SURVEY_GCM, createForegroundNotification(this));
        }

        isServiceRunning = true;

       ...
    }

    private void stopTracking() {

        if (!isServiceRunning) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                stopForeground(true);
            }
            stopSelf();
            return;
        }

        // stop location updates on partner SDKs
       ....
        stopSelf();
        isServiceRunning = false;
    }

    public static Notification createForegroundNotification(Context context) {
            NotificationChannelUtil.INSTANCE.getPreparedManager(context);
            String channel = NotificationChannelUtil.INSTANCE.getSYSTEM_CHANNEL_ID();

            // The PendingIntent to launch activity.
            PendingIntent activityPendingIntent = PendingIntent.getActivity(context, 0,
                    new Intent(context, MainTabActivity.class), 0);

            NotificationCompat.Action settingsAction = NotificationUtil.createSettingAction(context);

            String title = context.getResources().getString(R.string.foreground_service_notification_title);
            String desc = context.getResources().getString(R.string.foreground_service_notification_description);
            String expandedText = context.getResources().getString(R.string.foreground_service_notification_description_expanded);

            NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channel)
                    .setContentIntent(activityPendingIntent)
                    .setSmallIcon(R.drawable.noti)
                    .setContentTitle(title)
                    .setContentText(desc)
                    .setStyle(new NotificationCompat.BigTextStyle()
                            .bigText(expandedText))
                    .addAction(settingsAction)
                    .setColorized(false)
                    .setOngoing(true);

            return builder.build();
        }

Arian A
  • 41
  • 1
  • 4
  • Does this answer your question? [Context.startForegroundService() did not then call Service.startForeground()](https://stackoverflow.com/questions/44425584/context-startforegroundservice-did-not-then-call-service-startforeground) – varunkr Apr 14 '20 at 17:46
  • Is the fact that it doesn't have an accepted answer the only problem? It has several _highly_ upvoted answers - did you try them? – Ryan M Apr 15 '20 at 01:11
  • @RyanM I haven't been able to reproduce this bug. After release some users experienced this issue and I saw the crashes on Firebase. I'll try some of them. Thank you – Arian A Apr 15 '20 at 21:39

2 Answers2

2

I had the same problem with Samsung and Huawei devices with Android Oreo or above. I would get the same errors.

If I remember correctly, since Android Oreo and above it is required to make use of startForeground() when using startService() or startForegroundService().

I solved it by adding the following code to the onCreate function of the service class. I created a notification and launched it with startForeground().

   if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    NotificationChannel mNotificationChannel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_NONE);
    mNotificationChannel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
    mNotificationManager.createNotificationChannel(mNotificationChannel);
    Notification note = new NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("Reboot Sequence")
            .setContentText("Rescheduling Alarms")
            .setSmallIcon(R.drawable.ic_alarm_24dp)
            .build();
    startForeground(1, note);
}

I hope this will help you.

Fatih
  • 123
  • 1
  • 9
0

This happens even if a notification is launched with startForeground(). This problem is caused by bugs in the software on some devices. So it can not be solved in the app code. The only realistic solution is to go to crashes and ANR on the play developer console and find the problem devices. Then go to device manager on the same developer console and exclude those devices. I have seen that Huawei HUAWEI Y5 causes a lot of these crashes.

  • that's not a good solution. For me it happens on S8, S9, S9+, Pixel 6. I can't blame the OS on the device. – Alex Apr 13 '22 at 15:20
  • 1
    If it happens on S8, S9 and S9+ it is probably caused by your app code. I never see this exception on those devices. Then you should update your code according to the recommendations for startForeGroundservice(). But even efter you do this, this exception can occur on some low quality devices. That is what I meant by my answer. – Eyvind Almqvist Jul 23 '22 at 06:54