Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Handle Service.onTimeout to stop crashes on Android 15 #323

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

adil192
Copy link

@adil192 adil192 commented Mar 1, 2025

Motivation

Android 15 adds a 6 hours per day limit to dataSync and mediaProcessing foreground services.
From https://developer.android.com/about/versions/15/behavior-changes-15#datasync-timeout:

The system permits an app's dataSync services to run for a total of 6 hours in a 24-hour period, after which the system calls the running service's Service.onTimeout(int, int) method (introduced in Android 15). At this time, the service has a few seconds to call Service.stopSelf(). When Service.onTimeout() is called, the service is no longer considered a foreground service. If the service does not call Service.stopSelf(), the system throws an internal exception.

For us Flutter users, we get this error:

RemoteServiceException$ForegroundServiceDidNotStopInTimeException
A foreground service of type dataSync did not stop within its timeout: ComponentInfo{com.example.myapp/com.pravera.flutter_foreground_task.service.ForegroundService}

Results

This PR fixes the timeout error, but the app soon tries to restart the foreground service and causes a "Time limit already exhausted" error. If you know how to fix this, I'd appreciate any help.

D/AndroidRuntime(13497): Shutting down VM
E/AndroidRuntime(13497): FATAL EXCEPTION: main
E/AndroidRuntime(13497): Process: com.example.myapp, PID: 13497
E/AndroidRuntime(13497): java.lang.RuntimeException: Unable to start service com.pravera.flutter_foreground_task.service.ForegroundService@b5236c3 with Intent { cmp=com.example.myapp/com.pravera.flutter_foreground_task.service.ForegroundService }: android.app.ForegroundServiceStartNotAllowedException: Time limit already exhausted for foreground service type unknown
E/AndroidRuntime(13497):        at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:5750)
E/AndroidRuntime(13497):        at android.app.ActivityThread.-$$Nest$mhandleServiceArgs(Unknown Source:0)
E/AndroidRuntime(13497):        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2728)
E/AndroidRuntime(13497):        at android.os.Handler.dispatchMessage(Handler.java:107)
E/AndroidRuntime(13497):        at android.os.Looper.loopOnce(Looper.java:257)
E/AndroidRuntime(13497):        at android.os.Looper.loop(Looper.java:342)
E/AndroidRuntime(13497):        at android.app.ActivityThread.main(ActivityThread.java:9614)
E/AndroidRuntime(13497):        at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(13497):        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:619)
E/AndroidRuntime(13497):        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:929)
E/AndroidRuntime(13497): Caused by: android.app.ForegroundServiceStartNotAllowedException: Time limit already exhausted for foreground service type unknown
E/AndroidRuntime(13497):        at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel(ForegroundServiceStartNotAllowedException.java:54)
E/AndroidRuntime(13497):        at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel(ForegroundServiceStartNotAllowedException.java:50)
E/AndroidRuntime(13497):        at android.os.Parcel.readParcelableInternal(Parcel.java:5090)
E/AndroidRuntime(13497):        at android.os.Parcel.readParcelable(Parcel.java:5072)
E/AndroidRuntime(13497):        at android.os.Parcel.createExceptionOrNull(Parcel.java:3252)
E/AndroidRuntime(13497):        at android.os.Parcel.createException(Parcel.java:3241)
E/AndroidRuntime(13497):        at android.os.Parcel.readException(Parcel.java:3224)
E/AndroidRuntime(13497):        at android.os.Parcel.readException(Parcel.java:3166)
E/AndroidRuntime(13497):        at android.app.IActivityManager$Stub$Proxy.setServiceForeground(IActivityManager.java:7410)
E/AndroidRuntime(13497):        at android.app.Service.startForeground(Service.java:863)
E/AndroidRuntime(13497):        at com.pravera.flutter_foreground_task.service.ForegroundService.startForegroundService(ForegroundService.kt:268)
E/AndroidRuntime(13497):        at com.pravera.flutter_foreground_task.service.ForegroundService.onStartCommand(ForegroundService.kt:167)
E/AndroidRuntime(13497):        at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:5732)
E/AndroidRuntime(13497):        ... 9 more
I/Process (13497): Sending signal. PID: 13497 SIG: 9
Lost connection to device.

@adil192
Copy link
Author

adil192 commented Mar 1, 2025

Note:
For testing, you can temporarily (on Android 15) adjust the timeout period in milliseconds.
E.g. adb shell device_config put activity_manager data_sync_fgs_timeout_duration 5000 will make a dataSync fg service timeout after 5 seconds.

When you're done, run adb shell device_config delete activity_manager data_sync_fgs_timeout_duration to go back to the default.

adil192 added 2 commits March 1, 2025 20:43
Might fix this:
RemoteServiceException$ForegroundServiceDidNotStopInTimeException
A foreground service of type dataSync did not stop within its timeout: ComponentInfo{com.example.myapp/com.pravera.flutter_foreground_task.service.ForegroundService}
    Android 15 introduces a new timeout behavior to dataSync for apps targeting Android 15 (API level 35) or higher. This behavior also applies to the new mediaProcessing foreground service type.

    The system permits an app's dataSync services to run for a total of 6 hours in a 24-hour period, after which the system calls the running service's Service.onTimeout(int, int) method (introduced in Android 15). At this time, the service has a few seconds to call Service.stopSelf(). When Service.onTimeout() is called, the service is no longer considered a foreground service. If the service does not call Service.stopSelf(), the system throws an internal exception.

        https://developer.android.com/about/versions/15/behavior-changes-15#datasync-timeout
@adil192 adil192 force-pushed the fix/service-timeout branch from 981b699 to 438a34d Compare March 1, 2025 20:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant