doublesymmetry / react-native-track-player

A fully fledged audio module created for music apps. Provides audio playback, external media controls, background mode and more!
https://rntp.dev/
Apache License 2.0
3.18k stars 981 forks source link

android.app.ForegroundServiceStartNotAllowedException - Service.startForeground() not allowed due to mAllowStartForeground false #2231

Open AjayGol opened 6 months ago

AjayGol commented 6 months ago

Describe the Bug Fatal Exception: java.lang.RuntimeException Unable to start service com.doublesymmetry.trackplayer.service.MusicService@43cf99 with null: android.app.ForegroundServiceStartNotAllowedException: Service.startForeground() not allowed due to mAllowStartForeground false: service com.app.android/com.doublesymmetry.trackplayer.service.MusicService

Steps To Reproduce TBH it did not happen to me on debug, but it seems that is happening to my users in production. I have reports from Firebase Crashlytics.

Screenshot 2023-12-31 at 9 30 58 AM

Screenshot 2023-12-31 at 9 31 19 AM

OS: macOS 13.5.2 CPU: (8) arm64 Apple M1 react-native: ^0.68.0 => ^0.68.0 xCode: 15(15A240d)/usr/bin/xcodebuild

Using react-native-track-player@^4.0.1

This is happen on real devices(All Google phone), most of them android 14.

mihaibulic2 commented 6 months ago

i'm also experiencing this issue

lovegaoshi commented 6 months ago

duplicate of https://github.com/doublesymmetry/react-native-track-player/issues/2184 try disabling battery optimization

mihaibulic2 commented 6 months ago

We can't just ask/expect users to disable battery optimizations, it's our problem as the devs, not the user's

lovegaoshi commented 6 months ago

this is a UX improvement set by google since android12. as much as youd like to call this a dev problem unfortunately there aint many options other than listed here: https://developer.android.com/develop/background-work/services/foreground-services#background-start-restriction-exemptions

realistically i see 4 options:

SYSTEM_ALERT_WINDOW battery opt off exact alarm worker

given the flutter folks recommended the first two and didnt implement the latter two, i dont have high hopes these will turn out working right, but if u do pls submit a pr

justinhandley commented 6 months ago

I posted a solution to this here: https://github.com/doublesymmetry/react-native-track-player/issues/2198 - I'm trying to see if we can work it into a patch for RNTP this week - all the code is there that keeps the app awake while audio is playing, but right now it is just app changes and not a pluggable part of RNTP.

lovegaoshi commented 6 months ago

i wonder if wakeLock has any effect on context.startForegroundService? theorrtically it just keeps the background service alive

also not sure how generalizable this should be since Google's against this for battery life reasons

https://developer.android.com/develop/background-work/background-tasks/scheduling/wakelock#cpu

but all in all, its all googles fault

On Thu, Jan 4, 2024, 12:58 PM Justin Handley @.***> wrote:

I posted a solution to this here: #2198 https://github.com/doublesymmetry/react-native-track-player/issues/2198

  • I'm trying to see if we can work it into a patch for RNTP this week - all the code is there that keeps the app awake while audio is playing, but right now it is just app changes and not a pluggable part of RNTP.

— Reply to this email directly, view it on GitHub https://github.com/doublesymmetry/react-native-track-player/issues/2231#issuecomment-1877751576, or unsubscribe https://github.com/notifications/unsubscribe-auth/AZMOVVRAEGEY7KOOFRKOFQ3YM4JXPAVCNFSM6AAAAABBIXSQVKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQNZXG42TCNJXGY . You are receiving this because you commented.Message ID: @.*** com>

NadeemKhanFh commented 5 months ago

Hello, anyone managed to fix this issue, we are also experiencing this issue on production.

justinhandley commented 5 months ago

It isn't simple, but I believe that it is related to this: https://github.com/doublesymmetry/react-native-track-player/issues/2198 - the workaround I put in place there keeps the device from sleeping while audio is playing - it does use more battery, but it gets away from having to ask people toadjust their battery settings. We are in production and are no longer seeing this error.

MenamAfzaal commented 5 months ago

Hi... i'm also experiencing this issue and Firebase Crashlytics 100% stats shows this happens when app is in background state

lovegaoshi commented 5 months ago

okay, I'm willing to investigate further, there's clearly something wrong with how the MusicService is started. I'm not an android expert but if I just observe what's in dev options -> running services: apparently the MusicService is only started or at least observed when the playback is currently in play for RNTP; you can see how youtube or any other music apps will sometimes only show 1 process but 0 service, and the service will kick in when the playback is started. IMO the service should linger because the notification still exists, but it seems to get killed randomly. when that happened and once playback is triggered again, service will attempt to onStartCommand and StartForeground which presumably triggers this error when the app is in cached process. The most obvious way to prevent this is to keep process alive, not cached, I'm seeing this behavior for AIMP and youtube (revanced) as their process never goes into caching. I dunno how realistically this applies to RN apps however, especially since I made terrible RN apps that are battery hogs. outside that one can disable battery optimization that the running process will never go into cache as well, which has been suggested in this thread and before. TBH I'm very perplexed by when a service would be registered or not, I couldnt get podverse to show up at all, AIMP and YTB doesnt show for a while then I was able to see services attached to them...

mihaibulic2 commented 5 months ago

Thanks for offering to investigate — I was hoping to look more into it too, but I've been busy with work / it doesn't look like I'll be getting free time any time soon. But If anayone has figured a solid way to repro, I'm happy to try out any PRs.

lovegaoshi commented 5 months ago

ok. For those interested:

enable dev options and watch the RNTP app in the running state and cache state. When playing the process should have musicService attached. when the app goes into the cache state,

notification posted with id=1, ongoing=false Notification has been stopped

will be triggered and foreground service is therefore lost. when the app is resumed, the active foreground service is no longer attached to the activity, or there's something buggy about this that AppKilledBehavior will no longer connect to the current MusicService; now swiping to close app will not kill playback if configured.

Can MusicService even be kept as foreground when app goes into cached? it doesnt seem like so

Also I have my app on unrestricted battery for a good 5 hours, and it used ~1% battery and ~250MB RAM; AIMP on the other hand used 80MB RAM and ~0.5% battery. I dont think its unrealistic to ask for unrestricted battery use.

lovegaoshi commented 5 months ago

if anyone can disable stopForeground like this https://github.com/lovegaoshi/react-native-track-player/commit/9afe35b163c84bf69ba484699dc8aac94dfc00cb and report back findings it would be nice. I cannot reproduce the error message what so ever

chrisfougner commented 5 months ago

We saw a spike in this crash starting yesterday. They're all Android 14 on Google Pixel devices (6a and 8). Not sure exactly how to create a minimal reproducible sample, but maybe see if it's easier to reproduce on one of those devices if you have one available.

lovegaoshi commented 5 months ago

ur welcome to try https://github.com/doublesymmetry/react-native-track-player/commit/1145e2da93647cab93bf118cbf22177433fbe642 for android 14 though i doubt it matters. unless someone can reliably reproduce this error there aint much to do other than not stopping tje foreground service to begin with

iphonic commented 5 months ago

@dcvz @lovegaoshi Anything on this seems many users getting affected, today only 5 users have the same issue.

iphonic commented 5 months ago

ur welcome to try 1145e2d for android 14 though i doubt it matters. unless someone can reliably reproduce this error there aint much to do other than not stopping tje foreground service to begin with

It is happening in Android 14 too, see attached, I can give you log

Screenshot 2024-02-09 at 1 44 02 PM
lovegaoshi commented 5 months ago

you're triggering this via setupPlayer? so this happens at app start up?

iphonic commented 5 months ago

you're triggering this via setupPlayer? so this happens at app start up?

As per the stacktrace and the session log we have, it doesn't crash at startup, but when it tries to play audio for the first time

Fatal Exception: android.app.ForegroundServiceStartNotAllowedException: startForegroundService() not allowed due to mAllowStartForeground false: service com.hellomind/com.doublesymmetry.trackplayer.service.MusicService 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:4882) at android.os.Parcel.readParcelable(Parcel.java:4864) at android.os.Parcel.createExceptionOrNull(Parcel.java:3064) at android.os.Parcel.createException(Parcel.java:3053) at android.os.Parcel.readException(Parcel.java:3036) at android.os.Parcel.readException(Parcel.java:2978) at android.app.IActivityManager$Stub$Proxy.startService(IActivityManager.java:6437) at android.app.ContextImpl.startServiceCommon(ContextImpl.java:2002) at android.app.ContextImpl.startForegroundService(ContextImpl.java:1967) at android.content.ContextWrapper.startForegroundService(ContextWrapper.java:847) at android.content.ContextWrapper.startForegroundService(ContextWrapper.java:847) at com.doublesymmetry.trackplayer.module.MusicModule.setupPlayer(MusicModule.kt:239) at java.lang.reflect.Method.invoke(Method.java) at com.facebook.react.bridge.JavaMethodWrapper.invoke(JavaMethodWrapper.java:372) at com.facebook.react.bridge.JavaModuleWrapper.invoke(JavaModuleWrapper.java:188) at com.facebook.jni.NativeRunnable.run(NativeRunnable.java) at android.os.Handler.handleCallback(Handler.java:958) at android.os.Handler.dispatchMessage(Handler.java:99) at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:27) at android.os.Looper.loopOnce(Looper.java:230) at android.os.Looper.loop(Looper.java:319) at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:228)

lovegaoshi commented 5 months ago

the trace log specifically occurs at MM.setupPlayer which is the RN module, where TP.setupPlayer calls it, not when audio is first played; do you use await TP.setupPlayer? and why is your app no longer in foreground when the first audio plays?

iphonic commented 5 months ago

the trace log specifically occurs at MM.setupPlayer which is the RN module, where TP.setupPlayer calls it, not when audio is first played; do you use await TP.setupPlayer? and why is your app no longer in foreground when the first audio plays?

Yes using await TrackPlayer.setupPlayer(); The app is in Foreground, audio can't be started from the background.

So basically the setup is like await TrackPlayer.setupPlayer(); is defined in App.js in componentDidMount() and the Audio plays at a later stage on a different screen having a list of sessions. However I can't replicate any crash in Android 12, it seems happening in Android 14, works fine in iOS.

lovegaoshi commented 5 months ago

so your app reliably crushes with this exception on android 14? is your component rerendered somehow and triggering componentDidMount again? if you console.log within that is it called twice? and if you insert a timber.d right at context.startforegroundservice(intent) (MM L239) is this called twice? if you also put a console.log inside TrackPlayer.setupPlayer is that called twice too?

iphonic commented 5 months ago

so your app reliably crushes with this exception on android 14? is your component rerendered somehow and triggering componentDidMount again? if you console.log within that is it called twice? and if you insert a timber.d right at context.startforegroundservice(intent) (MM L239) is this called twice? if you also put a console.log inside TrackPlayer.setupPlayer is that called twice too?

No, it doesn't get called twice.

lovegaoshi commented 5 months ago

then when is your TP.setupPlayer called? if its truly on component render your app cannot be in background at all

iphonic commented 5 months ago

then when is your TP.setupPlayer called? if its truly on component render your app cannot be in background at all

The app can play Audio in the background but once the Audio has been started, not before.

lovegaoshi commented 5 months ago

wdym play audio in the background, via the notification panel? i'm still not clear why/how youre triggering TP.setupPlayer. if you put a console.log within TP.setupPlayer theoretically you should see it once upon app start, thats it. since youre saying it doesnt fire twice but this is observed with the traceback, something doesnt add up

iphonic commented 5 months ago

wdym play audio in the background, via the notification panel? i'm still not clear why/how youre triggering TP.setupPlayer. if you put a console.log within TP.setupPlayer theoretically you should see it once upon app start, thats it. since youre saying it doesnt fire twice but this is observed with the traceback, something doesnt add up

I am breaking configurations in steps as follows

Step1 index.js <=== Entry point of the Application

import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
AppRegistry.registerComponent(appName, () => App);

Step2 Inside App.js

import TrackPlayer from 'react-native-track-player';
import {PlaybackService} from './playbackservice';

TrackPlayer.registerPlaybackService(() => PlaybackService);

export default class App extends Component {
  constructor(props) {
     super(props);
   }
  async componentDidMount() { <=== This is called once in the whole lifecycle of the Application
      await TrackPlayer.setupPlayer();
  }
  render(){
     ...
   }
}

Step3 In a Different screen say ScreenA.js on button click

 async onPlayAction = (e) => { 
       await TrackPlayer.reset();
       await TrackPlayer.add(tracks);
       await TrackPlayer.play();
 }

Let me know where I am doing wrong? Thanks.

iphonic commented 3 months ago

wdym play audio in the background, via the notification panel? i'm still not clear why/how youre triggering TP.setupPlayer. if you put a console.log within TP.setupPlayer theoretically you should see it once upon app start, thats it. since youre saying it doesnt fire twice but this is observed with the traceback, something doesnt add up

I am breaking configurations in steps as follows

Step1 index.js <=== Entry point of the Application

import {AppRegistry} from 'react-native';
import App from './App';
import {name as appName} from './app.json';
AppRegistry.registerComponent(appName, () => App);

Step2 Inside App.js

import TrackPlayer from 'react-native-track-player';
import {PlaybackService} from './playbackservice';

TrackPlayer.registerPlaybackService(() => PlaybackService);

export default class App extends Component {
  constructor(props) {
     super(props);
   }
  async componentDidMount() { <=== This is called once in the whole lifecycle of the Application
      await TrackPlayer.setupPlayer();
  }
  render(){
     ...
   }
}

Step3 In a Different screen say ScreenA.js on button click

 async onPlayAction = (e) => { 
       await TrackPlayer.reset();
       await TrackPlayer.add(tracks);
       await TrackPlayer.play();
 }

Let me know where I am doing wrong? Thanks.

@lovegaoshi Anything on above, the issue still exist? Thanks.

lovegaoshi commented 3 months ago

unless you can reproduce with the example app reliably.

i dont see this error what so ever with sentry so you're kinda on your own, or pay to consult with ds

On Thu, Apr 4, 2024, 7:51 PM Ved Prakash @.***> wrote:

wdym play audio in the background, via the notification panel? i'm still not clear why/how youre triggering TP.setupPlayer. if you put a console.log within TP.setupPlayer theoretically you should see it once upon app start, thats it. since youre saying it doesnt fire twice but this is observed with the traceback, something doesnt add up

I am breaking configurations in steps as follows

Step1 index.js <=== Entry point of the Application

import {AppRegistry} from 'react-native'; import App from './App'; import {name as appName} from './app.json'; AppRegistry.registerComponent(appName, () => App);

Step2 Inside App.js

import TrackPlayer from 'react-native-track-player'; import {PlaybackService} from './playbackservice';

TrackPlayer.registerPlaybackService(() => PlaybackService);

export default class App extends Component { constructor(props) { super(props); } async componentDidMount() { <=== This is called once in the whole lifecycle of the Application await TrackPlayer.setupPlayer(); } render(){ ... } }

Step3 In a Different screen say ScreenA.js on button click

async onPlayAction = (e) => { await TrackPlayer.reset(); await TrackPlayer.add(tracks); await TrackPlayer.play(); }

Let me know where I am doing wrong? Thanks.

@lovegaoshi https://github.com/lovegaoshi Anything on above, the issue still exist? Thanks.

— Reply to this email directly, view it on GitHub https://github.com/doublesymmetry/react-native-track-player/issues/2231#issuecomment-2038710504, or unsubscribe https://github.com/notifications/unsubscribe-auth/AZMOVVSZEKPV542Z6D755YTY3YGTFAVCNFSM6AAAAABBIXSQVKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMZYG4YTANJQGQ . You are receiving this because you were mentioned.Message ID: @.*** com>

taromorimoto commented 2 months ago

Has anyone found a way to fix or somehow get around this error? I'm seeing these identical errors inPlay Store and Firebase Crashlytics for Android 14. Using react-native-track-player 4.1.1.

devartwa commented 1 month ago

Has anyone found a way to fix or somehow get around this error? I'm seeing these identical errors inPlay Store and Firebase Crashlytics for Android 14. Using react-native-track-player 4.1.1.

Same here!!

nateshmbhat commented 3 weeks ago

any solution for this ? 😢

lrobak0 commented 2 weeks ago

I have the same issue