audio_service icon indicating copy to clipboard operation
audio_service copied to clipboard

(AKA ForegroundServiceStartNotAllowedException) Player paused in background or screen lock on Samsung note 10, 20, Samsung S20 (on samsung devices)

Open deep1931 opened this issue 2 years ago • 26 comments

Documented behaviour

Player should work on every device, and should not pause in background.

Actual behaviour

App works on most of the devices, no issue at all, but on Samsung S10, S20 etc, or Samsung Note devices, it paused when we lock the screen or app goes in background.

Minimal reproduction project

Official example: main.dart

Reproduction steps

  1. Download the sample project
  2. Make release APK
  3. Install on Samsung Note or Samsung S mobile
  4. Lock the screen and wait for sometime, then player will pause.
  5. Unlock and the it will start again
  6. Send app in background, or open any other app, wait for few seconds, playback will stop again.

Output of flutter doctor

[✓] Flutter (Channel stable, 2.10.3, on macOS 12.3.1 21E258 darwin-arm, locale en-IN)
[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0)
[✓] Xcode - develop for iOS and macOS (Xcode 13.3.1)
[✗] Chrome - develop for the web (Cannot find Chrome executable at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome)
    ! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.
[!] Android Studio (not installed)
[☠] IntelliJ IDEA Community Edition (the doctor check crashed)
    ✗ Due to an error, the doctor check did not complete. If the error message below is not helpful, please let us know about this issue at
      https://github.com/flutter/flutter/issues.
    ✗ FormatException: Unexpected extension byte (at offset 5)
[✓] VS Code (version 1.66.0)
[✓] Connected device (1 available)
[✓] HTTP Host Availability

Devices exhibiting the bug

Android 12 Samsung S series Samsung Note

deep1931 avatar May 06 '22 09:05 deep1931

Documented behaviour

NA

So it is not a bug then? Surely you mean to reference some documentation that supports your expected behaviour.

I can't test this since I don't have a Samsung, but could it be Samsung's battery optimisation and something that you can override in the Samsung system settings for each app?

ryanheise avatar May 06 '22 16:05 ryanheise

@ryanheise Thanks, I am testing on other devices too, i will update you once i will make sure what is the behaviour on other Android 12 devices. Because on Samsung i have checked all set all battery optimisation settings, other apps like spotify is working fine, but our app have issue.

And another strange thing i have noticed that, when we close all apps in memory and just open our app, then it works well in background as expected, and once we open any app and then it moved to background then paused.

Still i am trying to get proper use case so that it can be diagnosed.

Regards

deep1931 avatar May 07 '22 03:05 deep1931

@deep1931 Did you make any progress on this one? I recently deployed my app to the Play Store and based on the reviews, my users experience the same behavior. Although I cannot reproduce it myself (yet). Already tried on some devices, but seems inconsistent.

As I added Crashlytics to my project, we also discovered that we do get some crashes on Android 12 while in background. Not sure if those are related, but I can imagine they might be. That one looks more or less the same as #918. Same goes for that one (Still not able to reproduce it).
For the latter we'll deploy our new version to the Play Store tonight with the foregroundServiceType in there. Maybe that solves some of the problems. https://stackoverflow.com/questions/69604951/getting-android-app-foregroundservicestartnotallowedexception-in-android-12-sdk. Will let you know if I see any difference.

CeesJanNolen avatar Jun 20 '22 17:06 CeesJanNolen

Reproduction steps will be key to investigating further.

For the latter we'll deploy our new version to the Play Store tonight with the foregroundServiceType in there.

I should also update the official example with this attribute.

ryanheise avatar Jun 20 '22 17:06 ryanheise

Hello,

I have tried to diagnose it, this issue is with Samsung Note and S series, also with Oppo, Xiomi high end devices. Actully this issue is belong to battery optimization. To fix this i have shown battery optimization settings after app start. When we disable battery optimization settings then player started working.

For samsung check this link... https://www.samsung.com/us/support/troubleshooting/TSG01200668/

And regarding crash on Android 12, I am not sure, because I have not faced this issue till date.

Thanks.

deep1931 avatar Jun 21 '22 07:06 deep1931

I've just updated the README Android setup instructions to include foregroundServiceType in the manifest. I could perhaps elaborate more on this, e.g. what to do if an app already has a different foregroundserviceType and needs to combine them, but this'll hopefully do for now.

I'd be interested to know how your latest deployment to the Play Store goes, or whether you end up needing to also open the battery optimisation settings.

ryanheise avatar Jun 21 '22 16:06 ryanheise

@deep1931 On your Samsung, have you found any difference in behaviour from just setting the foregroundServiceType alone, and without opening the battery optimisation settings?

I am contemplating a note in the README about how to open the battery optimisation settings but only if foregroundServiceType alone does not help on the Samsung.

ryanheise avatar Jun 28 '22 10:06 ryanheise

Hello @ryanheise

Right now I dnt have the Samsung device, but very soon i will check and revert back to you regarding this.

Thanks.

deep1931 avatar Jun 30 '22 03:06 deep1931

It is also happening on Samsung Note 10 plus. We also got a lot of report from Realmi, Oppo and Xiaomi. For my Samsung Note 10 plus, power saving mode it off.

alexaung avatar Jul 18 '22 19:07 alexaung

And foregroundServiceType is set too?

ryanheise avatar Jul 19 '22 01:07 ryanheise

Yes

<service android:name="com.ryanheise.audioservice.AudioService"
        android:foregroundServiceType="mediaPlayback"
        android:exported="true" tools:ignore="Instantiatable">
          <intent-filter>
            <action android:name="android.media.browse.MediaBrowserService" />
          </intent-filter>
        </service>

alexaung avatar Jul 19 '22 04:07 alexaung

Do you find this happens with the official example as well? That could help the investigation.

ryanheise avatar Jul 19 '22 04:07 ryanheise

I have tested with the official example_playlist and it only give me error on debug mode but working as expected in release mode.

Sample official example_playlist

Step to reproduce

  1. play
  2. Open facebook and scroll to see some video for a while (some time not happen immediately). Our app will be in background but I did not close it.
  3. In debug mode, you will get the following error when some audio or video play on facebook. In release mode, just paused and play again as expected.
Exception has occurred.
PlatformException (PlatformException(error, startForegroundService() not allowed due to mAllowStartForeground false: service com.ryanheise.audioserviceexample/com.ryanheise.audioservice.AudioService, null, android.app.ForegroundServiceStartNotAllowedException: startForegroundService() not allowed due to mAllowStartForeground false: service com.ryanheise.audioserviceexample/com.ryanheise.audioservice.AudioService
	at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel(ForegroundServiceStartNotAllowedException.java:54)
	at android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel(ForegroundServiceStartNotAllowedException.java:50)
	at android.os.Parcel.readParcelable(Parcel.java:3345)
	at android.os.Parcel.createExceptionOrNull(Parcel.java:2432)
	at android.os.Parcel.createException(Parcel.java:2421)
	at android.os.Parcel.readException(Parcel.java:2404)
	at android.os.Parcel.readException(Parcel.java:2346)
	at android.app.IActivityManager$Stub$Proxy.startService(IActivityManager.java:6933)
	at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1926)
	at android.app.ContextImpl.startForegroundService(ContextImpl.java:1892)
	at android.content.ContextWrapper.startForegroundService(ContextWrapper.java:796)
	at androidx.core.content.ContextCompat$Api26Impl.startForegroundService(ContextCompat.java:931)
	at androidx.core.content.ContextCompat.startForegroundService(ContextCompat.java:703)
	at com.ryanheise.audioservice.AudioService.enterPlayingState(AudioService.java:649)
	at com.ryanheise.audioservice.AudioService.setState(AudioService.java:505)
	at com.ryanheise.audioservice.AudioServicePlugin$AudioHandlerInterface.onMethodCall(AudioServicePlugin.java:885)
	at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:262)
	at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:295)
	at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$DartMessenger(DartMessenger.java:319)
	at io.flutter.embedding.engine.dart.DartMessenger$$ExternalSyntheticLambda0.run(Unknown Source:12)
	at android.os.Handler.handleCallback(Handler.java:938)
	at android.os.Handler.dispatchMessage(Handler.java:99)
	at android.os.Looper.loopOnce(Looper.java:226)
	at android.os.Looper.loop(Looper.java:313)
	at android.app.ActivityThread.main(ActivityThread.java:8663)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:567)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1135)
Caused by: android.os.RemoteException: Remote stack trace:
	at com.android.server.am.ActiveServices.startServiceLocked(ActiveServices.java:771)
	at com.android.server.am.ActiveServices.startServiceLocked(ActiveServices.java:679)
	at com.android.server.am.ActivityManagerService.startService(ActivityManagerService.java:14071)
	at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:2951)
	at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:3034)

))

[✓] Flutter (Channel stable, 3.0.5, on macOS 12.4 21F79 darwin-x64, locale en-GB) • Flutter version 3.0.5 at /Users/aungmyooo/Development/flutter • Upstream repository https://github.com/flutter/flutter.git • Framework revision f1875d570e (6 days ago), 2022-07-13 11:24:16 -0700 • Engine revision e85ea0e79c • Dart version 2.17.6 • DevTools version 2.12.2

[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0) • Android SDK at /Users/aungmyooo/Library/Android/sdk • Platform android-33, build-tools 31.0.0 • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840) • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 13.4.1) • Xcode at /Applications/Xcode.app/Contents/Developer • CocoaPods version 1.11.3

[✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2021.2) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/6351-dart • Java version OpenJDK Runtime Environment (build 11.0.12+0-b1504.28-7817840)

[✓] VS Code (version 1.69.1) • VS Code at /Applications/Visual Studio Code.app/Contents • Flutter extension version 3.44.0

[✓] Connected device (4 available) • SM N975F (mobile) • RF8M82Y3K9A • android-arm64 • Android 12 (API 31) • iPhone (mobile) • 06e02964e429eeebf29550b03ef955abe09891ef • ios • iOS 15.5 19F77 • macOS (desktop) • macos • darwin-x64 • macOS 12.4 21F79 darwin-x64 • Chrome (web) • chrome • web-javascript • Google Chrome 103.0.5060.114 ! Error: iPhone is busy: Fetching debug symbols for iPhone. Xcode will continue when iPhone is finished. (code -10)

[✓] HTTP Host Availability • All required HTTP hosts are available

• No issues found!

just_audio: ^0.9.28 audio_service: ^0.18.7 path_provider: ^2.0.11 audio_service: ^0.18.7

alexaung avatar Jul 19 '22 06:07 alexaung

Another input. It is not happening in android 11.

alexaung avatar Jul 19 '22 16:07 alexaung

I'll look into the error in debug mode, but if the example is working in release mode, are you able to see what you're doing differently from the example?

ryanheise avatar Jul 19 '22 16:07 ryanheise

Nothing much. I just scrolling facebook news feed. In debug mode, when feed reach the video post and automatically play, then error come up. I did same in release mode. It is ok. I watch a lot of videos on news feed.

alexaung avatar Jul 19 '22 16:07 alexaung

I just scrolling facebook news feed. In debug mode, when feed reach the video post and automatically play, then error come up. I did same in release mode. It is ok. I watch a lot of videos on news feed.

I understand that, but just to be clear, I'm asking about only release mode which you said is OK, so it would be interesting to compare what are the code differences between the working example (at least in release mode) and your own project. For example, comparing any differences in the AudioServiceConfig or in the implementation of certain methods that could stop the service, such as stop and onTaskRemoved.

ryanheise avatar Jul 19 '22 16:07 ryanheise

Ok. I did not change anything. Just tested with debug mode and release mode with same official example repo.

alexaung avatar Jul 19 '22 16:07 alexaung

I guess you misunderstood my question. Just to be clear, I'm asking ONLY about release mode, which you said is OK (quote "it is ok"). So let's focus this question on release mode (not debug mode). The question is about why your app is failing in release mode (as reported from Realmi, Oppo and Xiaomi), but the official example works in release mode (as reported by you). What is the code difference to explain that? To find the answers, you could take a look at the difference in AudioServiceConfig parameters, and implementations of stop and onTaskRemoved in particular, to see if you're doing anything different in your project/app compared to the official example.

ryanheise avatar Jul 19 '22 17:07 ryanheise

Ok. Found the issue. There is androidStopForegroundOnPause: true, in AudioServiceConfig. I added because want to clear the notification when paused. I did not aware that os will killed even thought it is clearly mention in documentation.

alexaung avatar Jul 19 '22 18:07 alexaung

Still ideally that configuration option should not make the OS so eager to kill the app. That issue has come up before but I haven't gotten to the bottom of it yet, unless the phone is truly running low on ram.

ryanheise avatar Jul 20 '22 01:07 ryanheise

Actually, androidStopForegroundOnPause defaults to true anyway, and the example_playlist.dart example you said you tested just uses the default. So maybe that can't be the difference?

ryanheise avatar Jul 20 '22 02:07 ryanheise

@ryanheise

We also get lots of complaints from our android users that playback pauses after some minutes :(.

Seems that this issue is only on android 12 and 13.

Could this stackTrace (from Sentry) be related?

PlatformException: PlatformException(error, startForegroundService() not allowed due to mAllowStartForeground false: service dk.nota.lyt4/com.ryanheise.audioservice.AudioService, null, )
  File "message_codecs.dart", line 653, in StandardMethodCodec.decodeEnvelope
  File "platform_channel.dart", line 296, in MethodChannel._invokeMethod
  File "<asynchronous suspension>"
  File "method_channel_audio_service.dart", line 19, in MethodChannelAudioService.setState
  File "<asynchronous suspension>"
  File "audio_service.dart", line 1030, in AudioService._observePlaybackState
ForegroundServiceStartNotAllowedException: startForegroundService() not allowed due to mAllowStartForeground false: service dk.nota.lyt4/com.ryanheise.audioservice.AudioService
    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:4804)
    at android.os.Parcel.readParcelable(Parcel.java:4772)
    at android.os.Parcel.createExceptionOrNull(Parcel.java:3035)
    at android.os.Parcel.createException(Parcel.java:3024)
    at android.os.Parcel.readException(Parcel.java:3007)
    at android.os.Parcel.readException(Parcel.java:2949)
    at android.app.IActivityManager$Stub$Proxy.startService(IActivityManager.java:5336)
    at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1901)
    at android.app.ContextImpl.startForegroundService(ContextImpl.java:1877)
    at android.content.ContextWrapper.startForegroundService(ContextWrapper.java:832)
    at s1.a$f.b(Unknown Source:0)
    at s1.a.l(ContextCompat.java:2)
    at com.ryanheise.audioservice.AudioService.n(AudioService.java:1)
    at com.ryanheise.audioservice.AudioService.G(AudioService.java:29)
    at com.ryanheise.audioservice.a$c.onMethodCall(AudioServicePlugin.java:34)
    at xa.k$a.a(MethodChannel.java:2)
    at la.c.l(DartMessenger.java:2)
    at la.c.m(DartMessenger.java:2)
    at la.c.i(Unknown Source:0)
    at la.b.run(Unknown Source:12)
    at android.os.Handler.handleCallback(Handler.java:942)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:240)
    at android.os.Looper.loop(Looper.java:351)
    at android.app.ActivityThread.main(ActivityThread.java:8355)
    at java.lang.reflect.Method.invoke
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:584)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1013)
    at

audio_service: "0.18.9"

AndroidManifest.xml
    <service
      android:name="com.ryanheise.audioservice.AudioService"
      android:foregroundServiceType="mediaPlayback"
      android:exported="true"
      tools:ignore="Instantiatable">
      <intent-filter>
        <action android:name="android.media.browse.MediaBrowserService" />
      </intent-filter>
    </service>

MainActivity.kt

import com.ryanheise.audioservice.AudioServiceFragmentActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

class MainActivity : AudioServiceFragmentActivity() {
  private val channelName = "dk.nota.lyt4/flavor"

  override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
    val messenger = flutterEngine.dartExecutor.binaryMessenger
    MethodChannel(messenger, channelName).setMethodCallHandler { _, result ->
      // Note: this method is invoked on the main thread.
      result.success(BuildConfig.FLAVOR)
    }
    super.configureFlutterEngine(flutterEngine);
  }
}

838 avatar Jan 14 '23 10:01 838

I think it has been reported above that on Samsung devices it also helps to disable the battery optimisation settings.

ryanheise avatar Jan 14 '23 11:01 ryanheise

FYI there is a Flutter plugin called optimization_battery which allows you to launch the battery optimisation settings.

This implements the technique described in this StackOverflow answer.

There is another plugin called android_power_manager which implements a slightly different approach, although according to the same StackOverflow answer, using this approach might result in the Play Store rejecting your app. However, I don't know the full circumstances of that, and some people have reported each of these approaches working.

YMMV so I'd be interested to hear people's experience with whichever approach you use.

ryanheise avatar Jan 14 '23 12:01 ryanheise

@ryanheise

Thanks for the info, seems that the first option will be more suitable, but I'll get back when we have investigated both options :).

838 avatar Jan 15 '23 13:01 838