NordicSemiconductor / Android-DFU-Library

Device Firmware Update library and Android app
http://www.nordicsemi.com/dfu
BSD 3-Clause "New" or "Revised" License
753 stars 263 forks source link

Fatal Exception: android.app.ForegroundServiceStartNotAllowedException on Android 13 / 14 #438

Closed PavlosTze closed 2 months ago

PavlosTze commented 4 months ago

Where do you suspect the issue?

Issue related to Android version or specific device

Version

2.4.1 (Latest)

Describe the issue

We have integrated DFU Library in our app and we had some fresh crashes yesterday. 2 of them were with Android 14 and one of them was with Android 13.

Our code to launch the update process is the following:

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            DfuServiceInitiator.createDfuNotificationChannel(context)
        } else {
            dfuServiceInitiator.setForeground(false)
            dfuServiceInitiator.setDisableNotification(true)
        }

        dfuServiceInitiator.setZip(updatePackage)
        dfuServiceInitiator.start(context, DfuService::class.java)

How shall we handle it in newer versions of Android?

Relevant log output

Log of first crash:

Fatal Exception: android.app.ForegroundServiceStartNotAllowedException: startForegroundService() not allowed due to mAllowStartForeground false: service com.weatherxm.app/com.weatherxm.service.DfuService
       at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel(ForegroundServiceStartNotAllowedException.java:54)
       at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel(ForegroundServiceStartNotAllowedException.java:50)
       at android.os.Parcel.readParcelableInternal(Parcel.java:4900)
       at android.os.Parcel.readParcelable(Parcel.java:4882)
       at android.os.Parcel.createExceptionOrNull(Parcel.java:3082)
       at android.os.Parcel.createException(Parcel.java:3071)
       at android.os.Parcel.readException(Parcel.java:3054)
       at android.os.Parcel.readException(Parcel.java:2996)
       at android.app.IActivityManager$Stub$Proxy.startService(IActivityManager.java:5984)
       at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1965)
       at android.app.ContextImpl.startForegroundService(ContextImpl.java:1936)
       at android.content.ContextWrapper.startForegroundService(ContextWrapper.java:840)
       at no.nordicsemi.android.dfu.DfuServiceInitiator.start(DfuServiceInitiator.java:876)

Log of second crash:

Fatal Exception: android.app.ForegroundServiceStartNotAllowedException: Service.startForeground() not allowed due to mAllowStartForeground false: service com.weatherxm.app/com.weatherxm.service.DfuService
       at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel(ForegroundServiceStartNotAllowedException.java:54)
       at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel(ForegroundServiceStartNotAllowedException.java:50)
       at android.os.Parcel.readParcelableInternal(Parcel.java:4775)
       at android.os.Parcel.readParcelable(Parcel.java:4743)
       at android.os.Parcel.createExceptionOrNull(Parcel.java:3006)
       at android.os.Parcel.createException(Parcel.java:2995)
       at android.os.Parcel.readException(Parcel.java:2978)
       at android.os.Parcel.readException(Parcel.java:2920)
       at android.app.IActivityManager$Stub$Proxy.setServiceForeground(IActivityManager.java:6752)
       at android.app.Service.startForeground(Service.java:743)
       at no.nordicsemi.android.dfu.DfuBaseService.startForeground(DfuBaseService.java:1926)
       at no.nordicsemi.android.dfu.DfuBaseService.onHandleIntent(DfuBaseService.java:1153)
       at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:78)
       at android.os.Handler.dispatchMessage(Handler.java:106)
       at android.os.Looper.loopOnce(Looper.java:210)
       at android.os.Looper.loop(Looper.java:299)
       at android.os.HandlerThread.run(HandlerThread.java:67)
philips77 commented 4 months ago

Hi, I saw that on our end as well. In my opinion this can happen when you close the app while the DFU is in progress and at some point, the service tries to upload the second part or retry in case of an error. It has been implemented in a way that the service just restarts itself. This is not possible with the current limitations. For now, I would recommend disabling foreground service, like you do for Android O+. I think a background service can still start a background service. They are just limited to some short period after the app have been closed.

PavlosTze commented 4 months ago

I see, will there be any more limitations if I disable foreground services at the happy path?

philips77 commented 4 months ago

Here you may find more information: https://developer.android.com/about/versions/oreo/background#services

There are 2 fragments worth quoting:

When an app goes into the background, it has a window of several minutes in which it is still allowed to create and use services. At the end of that window, the app is considered to be idle. At this time, the system stops the app's background services, just as if the app had called the services' [Service.stopSelf()](https://developer.android.com/reference/android/app/Service#stopSelf()) methods.

and:

With Android 8.0, there is a complication; the system doesn't allow a background app to create a background service.

I know that an app cannot create a foreground service even if it was sent to background a second before. However, the first paragraph says, that for "services" there is a window of few minutes when it should be able to start background services, with short lifespan. I guess we are in this territory. DFU doesn't take longer than a minute.

PavlosTze commented 4 months ago

I see, thank you. I'll implement it and we will see how it goes, hopefully nothing breaks. I think we can close this issue now. Thanks again!

philips77 commented 4 months ago

Please, share your findings! I never tried it, actually. We may need to rewrite the library to use WorkManager, or at least the deprecated JobIntentService, but don't have resources :(

PavlosTze commented 2 months ago

So far so good @philips77 , no issues with that.