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

Unable to start service MusicService with null: android.app.ForegroundServiceStartNotAllowedException: Service.startForeground() not allowed due to mAllowStartForeground false #2244

Open
bradfloodx opened this issue Jan 31, 2024 · 56 comments
Labels

Comments

@bradfloodx
Copy link
Collaborator

bradfloodx commented Jan 31, 2024

Describe the Bug
Daily crash reports of Unable to start service com.doublesymmetry.trackplayer.service.MusicService with null: android.app.ForegroundServiceStartNotAllowedException: Service.startForeground() not allowed due to mAllowStartForeground false

Steps To Reproduce
Unknown. Will update if I can replicate consistently.

Code To Reproduce
NA

Replicable on Example App?
Not yet.

Environment Info:

How I can Help
Looking into it.

@bradfloodx bradfloodx added the Bug label Jan 31, 2024
@bradfloodx
Copy link
Collaborator Author

bradfloodx commented Jan 31, 2024

Looking at all the older issues related to this, it appears this issue should be fixed in 4.0.1, but it's not for me. Still getting this crash report several times a day :(

@bradfloodx
Copy link
Collaborator Author

Stack trace from BugSnag:

ActivityThread.java:4880 android.app.ActivityThread.handleServiceArgs
Unknown android.app.ActivityThread.-$$Nest$mhandleServiceArgs
ActivityThread.java:2314 android.app.ActivityThread$H.handleMessage
Handler.java:106 android.os.Handler.dispatchMessage
Looper.java:205 android.os.Looper.loopOnce
Looper.java:294 android.os.Looper.loop
ActivityThread.java:8248 android.app.ActivityThread.main
Method.java:-2 java.lang.reflect.Method.invoke
RuntimeInit.java:552 com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run
ZygoteInit.java:971 com.android.internal.os.ZygoteInit.main
Caused By: android.app.ForegroundServiceStartNotAllowedException · Service.startForeground() not allowed due to mAllowStartForeground false: service com.tutusgumboots.evergrace/com.doublesymmetry.trackplayer.service.MusicService
ForegroundServiceStartNotAllowedException.java:54 android.app.ForegroundServiceStartNotAllowedException$1.createFromParcel

@lovegaoshi
Copy link
Contributor

after some research I dont think this is supposed to be fixed in recent versions, really.

The root cause is android disabled starting a foreground service from a background activity since 8 or 12. Because RNTP does kill the foreground service quite liberally, this quickly becomes a problem once the activity is sent to background/cached process. There are ways around it, like disabling battery optimization; but the fact the foreground service is killed and restarted is a problem itself; unlike the flutter alternative (audio_service) RNTP actually does NOT correctly link service back to activity, so it introduces another problem where closing activity may not kill service. So the options are:

  1. do NOT kill foreground service like lovegaoshi@9afe35b
    this will keep the process to be always running, never backgrounded/cached; this will obviously introduce more battery use; I observed ~0.5-1% battery use over 5 hours or so on Samsung S21. do note Youtube (revanced) and AIMP also do this and this is how I intend to go with. flutter's audio_service basically also have this as an option: ForegroundServiceStartNotAllowedException ryanheise/audio_service#994 (comment)

  2. turn off battery optimization, which effectively does 1.

  3. turn on ways to enable starting a foreground service from a background activity like SYSTEM_ALERT_WINDOW

  4. target android 7?

I seriously doubt a real solution exists (some if logic to MS.kt L123) otherwise the flutter folks would have found it already. But no one reported a reliable way to reproduce this bug either. For example, I can force terminate the service, app goes to background, though the notification lingers; if I interact with the notification then this is an exception allowed to start foreground service, I dont really understand how this bug happens

@bradfloodx
Copy link
Collaborator Author

Great info thanks @lovegaoshi I'm going to go with your 1. commit for now and see if it helps my crashes :)

@bradfloodx
Copy link
Collaborator Author

patch-package patch here if anyone else wants to try it

diff --git a/node_modules/react-native-track-player/android/src/main/java/com/doublesymmetry/trackplayer/service/MusicService.kt b/node_modules/react-native-track-player/android/src/main/java/com/doublesymmetry/trackplayer/service/MusicService.kt
index 9d6d869..a0a150e 100644
--- a/node_modules/react-native-track-player/android/src/main/java/com/doublesymmetry/trackplayer/service/MusicService.kt
+++ b/node_modules/react-native-track-player/android/src/main/java/com/doublesymmetry/trackplayer/service/MusicService.kt
@@ -587,9 +587,10 @@ class MusicService : HeadlessJsTaskService() {
                             scope.launch {
                                 delay(stopForegroundGracePeriod.toLong() * 1000)
                                 if (shouldStopForeground()) {
-                                    @Suppress("DEPRECATION")
-                                    stopForeground(removeNotificationWhenNotOngoing)
-                                    Timber.d("Notification has been stopped")
+                                	Timber.d("Notification should have been stopped - quick fix hack")
+                                    //@Suppress("DEPRECATION")
+                                    //stopForeground(removeNotificationWhenNotOngoing)
+                                    //Timber.d("Notification has been stopped")
                                 }
                             }
                         }

@lovegaoshi
Copy link
Contributor

lovegaoshi commented Feb 2, 2024

I'm seeing some absurd wakelock and cpu use duration that could be RN apps specific, as MusicService doesnt release wakelocks (headlessJsTaskService). One possible solution could be to move wakelock within: see lovegaoshi@2daba94 and lyswhut@bb80e13

though since AS moved their energy profiler to system trace, I dont know where to find wakelock profiling information anymore, if this my suspicion on the wakelock is even correct

@lovegaoshi
Copy link
Contributor

lovegaoshi commented Feb 4, 2024

ive been pretty satisfied with my wakelock patch above and the barrey use, and keeping foregrounf service is veru nice.

the wakelock patch needs to expose wakelock as public and makes more sense to patch after the Aa work.

@bradfloodx
Copy link
Collaborator Author

IMG_6948

do NOT kill foreground service like lovegaoshi@9afe35b

Unfortunately this did not change things for me in prod :(

I'll try your wake lock fix and let you know how that goes :)

@lovegaoshi
Copy link
Contributor

lovegaoshi commented Feb 7, 2024 via email

@TobiDevloft
Copy link

TobiDevloft commented Feb 8, 2024

We are seeing a lot of these errors as well, resulting quite a few crashes for the user. The error does seem to only occur on devices running Android 14.

image

@TobiDevloft
Copy link

Seems to be a duplicate of:

#2231
#2198

and several closed issues.

Is that something you guys have on your radar? @dcvz

@mmmoussa
Copy link
Contributor

We have shipped the workaround of not killing the foreground service and found it to be effective so far. @brad-sf it is likely that you either did not apply the patch correctly or the continued issue you're seeing is from old versions that are still being used by your users.

@StriderHND
Copy link

We have shipped the workaround of not killing the foreground service and found it to be effective so far. @brad-sf it is likely that you either did not apply the patch correctly or the continued issue you're seeing is from old versions that are stibeing used by your user

@mmmoussa this workaround that you mention is avaialble in the current version of the framework? or is located somewhere else?

I just started to investigate this issue and I see a lot of users experiencing this behaviour.

@kyo-torstar
Copy link

kyo-torstar commented Feb 14, 2024

It's getting on my nerves that there are hundreds of reported crashes related to this issue everyday. The app was just deployed with latest version 4.0.1 few days ago and Its downgrading the UX. Is there a workaround for this? @brad-sf how is the result for the wake lock fix?

Screenshot 2024-02-14 at 12 43 09 PM

@NadeemKhanFh
Copy link

@mmmoussa whats this workaround? how can we fix that?

@kyo-torstar
Copy link

this is the crashlytics log I have, and the function caused the crash has a remark related to #1666
Screenshot 2024-02-15 at 9 27 55 AM

@kyo-torstar
Copy link

According to the crash logs, they all happened within the 1st second. I wonder if it is related to the TrackPlayer.setupPlayer() function call while the app is bootstrapping in the background.
Screenshot 2024-02-15 at 9 57 40 AM

@lovegaoshi
Copy link
Contributor

whats ur MS.kt L125?
nightly is stopForeground i doubt that is the one; if it's
startForeground(EMPTY_NOTIFICATION_ID, notification)
and android 14 u can try lovegaoshi@1145e2d (add foreground service type to startForeground) but i doubt it helps

@kyo-torstar
Copy link

Th

whats ur MS.kt L125? nightly is stopForeground i doubt that is the one; if it's startForeground(EMPTY_NOTIFICATION_ID, notification) and android 14 u can try lovegaoshi@1145e2d (add foreground service type to startForeground) but i doubt it helps

its caused by stopForeground(true) on L125 MusicService.kt. But tracing backward, I find the initial call should be onStartCommand, a function triggered by HeadlessJsTaskService. Therefore, on the frontend react native, TrackPlayer.registerPlaybackService function call may cause the crash.
Screenshot 2024-02-15 at 10 21 05 AM

@lovegaoshi
Copy link
Contributor

lovegaoshi commented Feb 15, 2024 via email

@kyo-torstar
Copy link

and can you reliably reproduce instead from crash logs?

On Thu, Feb 15, 2024, 7:27 AM kyo-torstar @.> wrote: Th whats ur MS.kt L125? nightly is stopForeground i doubt that is the one; if it's startForeground(EMPTY_NOTIFICATION_ID, notification) and android 14 u can try @. <lovegaoshi@1145e2d> (add foreground service type to startForeground) but i doubt it helps its caused by stopForeground(true) on L125 MusicService.kt. But tracing backward, I find the initial call should be onStartCommand, a function triggered by HeadlessJsTaskService. Therefore, on the frontend react native, TrackPlayer.registerPlaybackService function call may cause the crash. Screenshot.2024-02-15.at.10.21.05.AM.png (view on web) https://github.com/doublesymmetry/react-native-track-player/assets/120053121/50930d7f-c80f-442d-b249-329617e322ee — Reply to this email directly, view it on GitHub <#2244 (comment)>, or unsubscribe https://github.com/notifications/unsubscribe-auth/AZMOVVX4KYXZDYJOZMG6ZB3YTYSMJAVCNFSM6AAAAABCSFD5U2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTSNBWGMZDENJRG4 . You are receiving this because you were mentioned.Message ID: @.*** com>

we reproduced it few times only but we could not conclude the reliable step to replicate it. It looks random that it may relate to racing conditions upon bootstrap. I modified the startup function as following:

setTimeout(() => {
  TrackPlayer.registerPlaybackService(() =>
    require('@services/TrackPlayerService'),
  );

  setTimeout(async () => {
    await TrackPlayer.setupPlayer();
    await TrackPlayer.updateOptions(options); 
  }, 3000);
}, 3000);

@bradfloodx
Copy link
Collaborator Author

I'm definitely getting LESS of this crash report since trialing the patch fix above.

But yes I agree there also appears to be some remaining crashes related to a race condition because they fire immediately on app launch (according to crash logs).

I'll try the above setTimeout and see if that clears all the errors.

If that's the case I guess we have two issues.. one on launch and one in general usage.

@kyo-torstar
Copy link

kyo-torstar commented Feb 20, 2024

@brad-sf @lovegaoshi
I look deeper, It should be related to the setupPlayer function being called when the app is in the background state. There should be a glimpse of moment the app is in background state when setupPlayer is called. It should be triggered by this

        Intent(context, MusicService::class.java).also { intent ->
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                context.startForegroundService(intent)
            } else {
                context.startService(intent)
            }
            context.bindService(intent, this, Context.BIND_AUTO_CREATE)
        }

To minimize the possibility of this from happening, we can do something like

TrackPlayer.registerPlaybackService(() =>
  require('@services/TrackPlayerService'),
);
const setupDelay = 1000;

const useTrackPlayer = () => {
  const [isServiceRegistered, setIsServiceRegistered] = useState(false);
  useEffect(() => {
      let initTimer = setTimeout(() => {
        if (state.appState === 'active' && !isServiceRegistered) {
          // inside this function calls:
          // await TrackPlayer.setupPlayer();
          // await TrackPlayer.updateOptions(options);
          // setIsServiceRegistered(true);
          initAudioPlayer(playerStatus); 
        }
      }, setupDelay);
  
      return () => {
        clearTimeout(initTimer);
      };
    }, [state, isServiceRegistered]);
}

This is a temp workaround, the solution should be applied at the setupPlayer function in MusicService.kt, a foreground has to be done

if (isAppOnForeground((context))) {
  // promise.reject here
}
...
Intent(context, MusicService::class.java).also { intent ->
...

The Java implementation from https://reactnative.dev/docs/headless-js-android

    private boolean isAppOnForeground(Context context) {
        /**
         We need to check if app is in foreground otherwise the app will crash.
         https://stackoverflow.com/questions/8489993/check-android-application-is-in-foreground-or-not
         **/
        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> appProcesses =
                activityManager.getRunningAppProcesses();
        if (appProcesses == null) {
            return false;
        }
        final String packageName = context.getPackageName();
        for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
            if (appProcess.importance ==
                    ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND &&
                    appProcess.processName.equals(packageName)) {
                return true;
            }
        }
        return false;
    }

@lovegaoshi
Copy link
Contributor

But why is your app in the background state when it's starting up? unless I immediately press back when opening the app, and startService is caught in that way?
it would really help if there's a reproducible repo; I've never seen the example app or my app going ANR when starting up.

@kyo-torstar
Copy link

kyo-torstar commented Feb 20, 2024

Screenshot 2024-02-20 at 1 23 54 PM

the crash logs all show that they happen less than a second. It could be the reason the setupPlayer function is called during app start. e.g. I put setupPlayer in the App.tsx function body, for example

useEffect(() => {
  setupPlayer()
}, []) 

@trix0
Copy link

trix0 commented Feb 27, 2024

@kyo-torstar
Copy link

kyo-torstar commented Feb 27, 2024

Related to https://issuetracker.google.com/issues/307329994 ?

possibly, but it looks like no one can reproduce it locally. This was what I thought when I was trying to reproduce the crash as I experience no crash. However, I found several crash logs related to my tests later. I think the app was crashed and was restarted when It was brought back from background / during bootstrap.

@kyo-torstar
Copy link

update to potential fix: https://issuetracker.google.com/issues/307329994#comment56
further reference: https://stackoverflow.com/questions/77680265/service-startforeground-not-allowed-due-to-mallowstartforeground-false-androi

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    if (intent != null) {
        startForeground();    //or wherever you call it: check the Intent before!
    }
}

@Nadimkhan120
Copy link

@kyo-torstar where we will write this code?

@newme616
Copy link

I have the same issue

@khc196
Copy link

khc196 commented Mar 20, 2024

after some research I dont think this is supposed to be fixed in recent versions, really.

The root cause is android disabled starting a foreground service from a background activity since 8 or 12. Because RNTP does kill the foreground service quite liberally, this quickly becomes a problem once the activity is sent to background/cached process. There are ways around it, like disabling battery optimization; but the fact the foreground service is killed and restarted is a problem itself; unlike the flutter alternative (audio_service) RNTP actually does NOT correctly link service back to activity, so it introduces another problem where closing activity may not kill service. So the options are:

  1. do NOT kill foreground service like lovegaoshi@9afe35b
    this will keep the process to be always running, never backgrounded/cached; this will obviously introduce more battery use; I observed ~0.5-1% battery use over 5 hours or so on Samsung S21. do note Youtube (revanced) and AIMP also do this and this is how I intend to go with. flutter's audio_service basically also have this as an option: ForegroundServiceStartNotAllowedException ryanheise/audio_service#994 (comment)
  2. turn off battery optimization, which effectively does 1.
  3. turn on ways to enable starting a foreground service from a background activity like SYSTEM_ALERT_WINDOW
  4. target android 7?

I seriously doubt a real solution exists (some if logic to MS.kt L123) otherwise the flutter folks would have found it already. But no one reported a reliable way to reproduce this bug either. For example, I can force terminate the service, app goes to background, though the notification lingers; if I interact with the notification then this is an exception allowed to start foreground service, I dont really understand how this bug happens

  1. works for me. Thanks.

@Nadimkhan120
Copy link

@khc196 how did you manage to get it work?

@kyo-torstar
Copy link

We need to find a way to reproduce the crash. It may not be reliably to reproduce it but it should increase the chance of experiencing it. Does the crash impact the user experience or it only crashes after the app is killed manually.

@ymkwon3
Copy link

ymkwon3 commented Mar 22, 2024

I'm not sure if it's true yet, but when I used the device care optimization widget on the home screen, the error occurred with a probability of 100%.

  1. Run the application
  2. Click the home screen button
  3. Click the Optimize widget on the home screen
  4. In that case, when the service scheduling time comes, an intent null value is received and an error occurs.

@lovegaoshi
Copy link
Contributor

lovegaoshi commented Mar 22, 2024

@ymkwon3 thanks for the lead!i still cant reproduce though

I finally saw this error with the example app, though the way reproduced I saw the error after PROCESS ENDED. so i dont think it affects UX in any way bc app is dead anyways (specifically for RN apps at least, as service cannot linger with activity being shut down. native is another story).

@kyo-torstar
Copy link

@lovegaoshi @ymkwon3
I found a reliable way to reproduce it 100% and it is more common in terms of usage. This is related to the notification channel setup by the library. Steps to reproduce:

  1. start the app with the library initialized
  2. put the app to background
  3. go to settings of the app and turn the notification off
  4. wait for 5-20 seconds
  5. the app crashes in the background

i tried to turn off the notification channel and the app can still play music in the background. What is the reason behind for subscribing those notification channels?
Screenshot 2024-04-01 at 2 53 51 PM

@lovegaoshi
Copy link
Contributor

@kyo-torstar thanks for another lead! i think this is an expected OS behavior though that the app is killed/restarted upon removing certain permissions. any music app will close like that
the temp channel is from #1974

@kyo-torstar
Copy link

kyo-torstar commented Apr 1, 2024

@lovegaoshi its interesting to see that, even if i turn off the notification channels, i still can play the music in the background as normal.

Another test that it does not crash is by playing the music in the background before turning the notification off:
start the app with the library initialized

  1. play music and put the app to background
  2. go to settings of the app and turn the notification off
  3. no crash but the music stops

PS: I tried Spotify, i turned off the notification and there is no crash when music is on or off
Edit: The app does not crash if i turn off the "Now Playing" and "temporary_channel" notification, it only crashes when ALL of the notification of the app is turned off

@lovegaoshi
Copy link
Contributor

I dont think the channels actually do anything, turning them on and off have 0 effects; but turning off the notification permission (or any permission, really) will trigger an app close/restart, and this should be universal.

@kyo-torstar
Copy link

@lovegaoshi I did this fix https://github.com/kyo-torstar/react-native-track-player/pull/1/files to avoid foreground notification service from starting when the app is in background. It solves the crash of turning off notification when the app is in background.
@ymkwon3 not sure about your case, I could not replicate with your steps. You may try if my solution works on your case.

@kyo-torstar
Copy link

update: after applying the fix and deploying to the production, that type of crash is finally gone. The fix references startForegroundIfNecessary function to catch the exception in case the foreground service is executed in background.

@erinpeach
Copy link

@kyo-torstar - seconding your success. My team shipped a change based on your fix and haven't see the error re-occur yet in our app. 👏 Awesome job hunting that down and finding a fix.

@dcvz
Copy link
Contributor

dcvz commented Apr 17, 2024

@lovegaoshi I did this fix https://github.com/kyo-torstar/react-native-track-player/pull/1/files to avoid foreground notification service from starting when the app is in background. It solves the crash of turning off notification when the app is in background. @ymkwon3 not sure about your case, I could not replicate with your steps. You may try if my solution works on your case.

This doesn’t exactly stop it from performing the action but it does catch the exception so it doesn’t crash the process, which is still good. Will try to read the latest messages here in the next week.

@devartwa
Copy link

any update?

@Kirillsocivka
Copy link

any update?

+1

@lovegaoshi
Copy link
Contributor

lovegaoshi commented Jun 24, 2024 via email

@ayushmahajan12
Copy link

Hi Team,

I'm experiencing the same issue as mentioned in the above chat. Could you please help with this? According to the Google Console report, my app is crashing multiple times in the background.

Thanks in advance!

@metehankurucu
Copy link

any update?

+1

mayank-paryani added a commit to mayank-paryani/react-native-track-player that referenced this issue Oct 18, 2024
…player.service.MusicService.startAndStopEmptyNotificationToAvoidANR

Update MusicService.kt to FIX [4.0.1] Crash: com.doublesymmetry.trackplayer.service.MusicService.startAndStopEmptyNotificationToAvoidANR 

doublesymmetry#2244 (reference)
@2ducanhpham
Copy link

This crash still happened

@lovegaoshi
Copy link
Contributor

and yet no one posted REPRODUCIBLE steps

u could try a full media3 migration using MediaSessionService. the service lifecycle is then handled by the media3 lib.

@smfunder
Copy link

@lovegaoshi it is happening to me too. It is hard to make reproducible steps, but this is happening to me using firebase with headless task (messaging().setBackgroundMessageHandler()). Basically I quit the app and send a push notification, the app is starting up in background mode. There I have RNTP library that may be firing the setup causing the issue.

It is hard to make a very simple example because it would depend also in Firebase configuration. But I think this is the case, it is firing the app in background and the RNTP is trying to wake up from background.

@lovegaoshi
Copy link
Contributor

specifically to your issue, it might be due to there is no playback within a certain period of time (< 20 seconds) after the foreground media service (MusicService) started. From my observations (i use my own fork, this may not apply if ur using main) this is harmless, does not trigger ANR or a native crash.

I can't really help anyone on main, as there are way too many workarounds in the code to patch around the ever tighter android security requirements versions after versions. I eventually completely migrated to media3 to use MediaLibraryService and left all MusicService start and stop handling to the media3 lib itself. @puckey is merging some of that migration into main. And the media3 team handled most of these service start not allowed exceptions throughout 2022-2024. I've only very occasionally observed this exception when I manually kill the service and trigger a restart, which is not really accessible via normal usage; and even with these exceptions, the service is still fully functional, its a soft one at best.

with that said i dont use firebase and cant promise it works. but i do use headless start/starting up in background mode (for android auto) and it works fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests