Keep the Flutter engine alive when the service is destroyed mid-playback - #1161
Open
leonardo-oliveir-a wants to merge 1 commit into
Open
Conversation
When the OS stops the AudioService while audio is still playing — e.g. battery saver's App Standby restriction logs "Stopping service due to app idle" after ~9 minutes without user interaction on some devices — the plugin's onDestroy listener unconditionally destroyed the shared Flutter engine. The audio itself is rendered by plugins living in that engine, not by the service, so this needlessly killed the ongoing playback; the process survives, and the next app launch cold-starts from the splash screen. Only dispose the engine when playback is not active. In the normal flows (playback stopped or paused before the service goes away) the behavior is unchanged. When the engine is kept alive, audio continues without the media notification; the engine is reclaimed with the (cached) process by the OS.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
On some devices, enabling battery saver makes App Standby stop the
AudioServiceafter ~9 minutes without user interaction, even while audio is actively playing. Captured on a OnePlus 6T (Android 11) with a production meditation app:When that happens,
AudioService.onDestroy→listener.onDestroy()→disposeFlutterEngine()destroys the shared Flutter engine unconditionally. But the audio is rendered by plugins living in that engine (audioplayers/just_audio/etc.), not by the service itself — so a service stop that would otherwise only remove the media notification ends up killing the ongoing playback. The process survives (verified: same pid before/after), so the user later reopens the app to a cold start from the splash screen with their session gone.The change
In the service-destroyed path, only dispose the engine when playback is not active (
AudioService.instance.isPlaying()still reflects the state at the moment of the kill, since the system stop never goes through the handler). One call site, behavior unchanged for the normal flows where playback was already stopped/paused when the service goes away.Trade-off: when the engine is kept alive, audio continues without the media notification, and the engine lives in a now-cached process until the OS reclaims it — which seems strictly better than silently killing the user's playback.
How to reproduce
adb shell am set-inactive <pkg> trueon a non-allowlisted app).