package.json
"react": "16.3.1",
"react-native": "0.55.4",
"react-native-track-player": "^1.1.2",
"react-native-swift": "^1.2.2",
react-native info
Environment:
OS: macOS High Sierra 10.13.6
Node: 8.11.2
Yarn: 1.9.4
npm: 5.6.0
Watchman: 4.9.0
Xcode: Xcode 10.1 Build version 10B61
Android Studio: 3.2 AI-181.5540.7.32.5056338
Packages: (wanted => installed)
react: 16.3.1 => 16.3.1
react-native: 0.55.4 => 0.55.4
I am having more and more of the same crash on Android using the version 1.1.2, here is the stack :
Fatal Exception: java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.xxx/com.guichaguri.trackplayer.service.MusicService }: app is in background uid UidRecord{39a05c9 u0a454 CEM bg:+1m5s685ms idle procs:1 seq(0,0,0)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1538)
at android.app.ContextImpl.startService(ContextImpl.java:1484)
at android.content.ContextWrapper.startService(ContextWrapper.java:663)
at android.content.ContextWrapper.startService(ContextWrapper.java:663)
at com.guichaguri.trackplayer.module.MusicModule.waitForConnection(MusicModule.java:100)
at com.guichaguri.trackplayer.module.MusicModule.getPosition(MusicModule.java:405)
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:160)
at com.facebook.react.bridge.queue.NativeRunnable.run(NativeRunnable.java)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:29)
at android.os.Looper.loop(Looper.java:164)
at com.facebook.react.bridge.queue.MessageQueueThreadImpl$3.run(MessageQueueThreadImpl.java:192)
at java.lang.Thread.run(Thread.java:764)
service.js
module.exports = async function service() {
TrackPlayer.addEventListener('remote-play', () => {
MyPlayer.playTrack(() => {});
});
TrackPlayer.addEventListener('remote-pause', () => {
MyPlayer.pauseTrack(() => {});
});
TrackPlayer.addEventListener('remote-seek', (time) => {
TrackPlayer.seekTo(time.position);
});
TrackPlayer.addEventListener('remote-jump-backward', (time) => {
TrackPlayer.getPosition().then((position) => {
TrackPlayer.seekTo(position - time.interval);
});
});
TrackPlayer.addEventListener('remote-jump-forward', (time) => {
TrackPlayer.getPosition().then((position) => {
TrackPlayer.seekTo(position + time.interval);
});
});
TrackPlayer.addEventListener('remote-stop', () => {
MyPlayer.stopTrack(() => {});
});
TrackPlayer.addEventListener('playback-queue-ended', (infos) => {
console.log('ended', infos);
if (infos && infos.track) {
MyPlayer.stopTrack(() => {});
}
});
};
Is this solved in the newest version 1.1.3? Cause I saw a bug correction that looks like this on the last version. ==> It's not solved in 1.1.3
Is there any workaround or maybe some configuration I am missing?
Thanks a lot
This crash can be caused by multiple reasons, please, try 1.1.3 first so we can make sure it's not related to that.
@Guichaguri I actually don't reproduce myself but I can get crash from my users 👍 It seems to be what you explain in the other thread that seems to speak about it that's why I was wondering.
@Guichaguri Reproduced with latest version 1.1.3
with same exception happening on Android 8 and 9 (65% are from Android 8 and the rest for Android 9)
Fatal Exception: java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.xxx/com.guichaguri.trackplayer.service.MusicService }: app is in background uid UidRecord{d4e96d5 u0a217 CEM bg:+1m3s136ms idle procs:1 seq(36,36,36)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1538)
at android.app.ContextImpl.startService(ContextImpl.java:1484)
at android.content.ContextWrapper.startService(ContextWrapper.java:663)
at android.content.ContextWrapper.startService(ContextWrapper.java:663)
at com.guichaguri.trackplayer.module.MusicModule.waitForConnection(MusicModule.java:100)
at com.guichaguri.trackplayer.module.MusicModule.getPosition(MusicModule.java:405)
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:160)
at com.facebook.react.bridge.queue.NativeRunnable.run(NativeRunnable.java)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:29)
at android.os.Looper.loop(Looper.java:164)
at com.facebook.react.bridge.queue.MessageQueueThreadImpl$3.run(MessageQueueThreadImpl.java:192)
at java.lang.Thread.run(Thread.java:764)
Hello,
@Guichaguri I do get this error as well on the version 1.1.3.
+1. I also see this but only on android 9.0
I am also seeing this in my Crashlytics and Bugsnag reporting.
Android 8 and 9.
I have not seen it happen myself.
Can I take a look into your playback service code?
@Guichaguri I just added it in the first post ;) you are talking about the service.js right?
Mine is a bit more complicated, and doesn't directly call the TrackPlayer methods, but maybe it will be useful.
import Analytics from '../../utils/Analytics';
import { store } from '../../containers/Root';
import TrackPlayer from 'react-native-track-player';
import AudioPlayer, { SIZZLE_ID } from '../AudioPlayer';
import {
audioPlayerStateChange,
audioPlayerTrackChange,
audioPlayerPlay,
audioPlayerPause,
audioPlayerJumpForward,
audioPlayerJumpBack,
audioPlayerStop,
audioPlayerPlayNext,
audioPlayerRemoveQueuedTrack,
audioPlayerRemoveCurrentQueuedTrack,
audioPlayerSeek,
setAudioPlayerIntentToPause
} from '../../actions/audioPlayerActions';
import Device from '../../utils/Device';
import { getAudioPlayerState } from '../../utils/selectors';
import getCurrentlyPlayingTrackFactory from '../../utils/selectors/getCurrentlyPlayingTrackFactory';
let didAddEventListeners = false;
let didPauseTemporarily = false;
let getCurrentlyPlayingTrack = getCurrentlyPlayingTrackFactory();
async function logEventWithCurrentTrackInfo(eventName) {
let params = {};
try {
const currentTrack = getCurrentlyPlayingTrack(store.getState());
if (currentTrack) {
params.showname = currentTrack.album;
params.episodename = currentTrack.title;
}
} catch (e) {
//
}
Analytics.logEvent(eventName, params);
}
module.exports = async function() {
if (didAddEventListeners) {
return;
} else {
didAddEventListeners = true;
}
TrackPlayer.addEventListener('remote-play', data => {
store.dispatch(audioPlayerPlay());
logEventWithCurrentTrackInfo('remote_play');
});
TrackPlayer.addEventListener('remote-pause', data => {
store.dispatch(audioPlayerPause());
logEventWithCurrentTrackInfo('remote_pause');
});
TrackPlayer.addEventListener('remote-stop', data => {
store.dispatch(audioPlayerStop());
logEventWithCurrentTrackInfo('remote_stop');
});
TrackPlayer.addEventListener('remote-jump-forward', data => {
if (data) {
store.dispatch(audioPlayerJumpForward(data.interval));
logEventWithCurrentTrackInfo('remote_jumpforward');
}
});
TrackPlayer.addEventListener('remote-jump-backward', data => {
if (data) {
store.dispatch(audioPlayerJumpBack(data.interval));
logEventWithCurrentTrackInfo('remote_jumpback');
}
});
TrackPlayer.addEventListener('remote-seek', data => {
if (data) {
store.dispatch(audioPlayerSeek(data.position));
logEventWithCurrentTrackInfo('remote_seek');
}
});
TrackPlayer.addEventListener('remote-next', data => {
store.dispatch(audioPlayerJumpForward(AudioPlayer.options.jumpInterval));
logEventWithCurrentTrackInfo('remote_jumpforward');
});
TrackPlayer.addEventListener('remote-previous', data => {
store.dispatch(audioPlayerJumpBack(AudioPlayer.options.jumpInterval));
logEventWithCurrentTrackInfo('remote_jumpback');
});
TrackPlayer.addEventListener('playback-state', data => {
if (data) {
const currentPlayerState = getAudioPlayerState(store.getState());
let playerState = AudioPlayer.getStateForState(data.state);
store.dispatch(audioPlayerStateChange(playerState));
AudioPlayer.monitorProgress();
if (playerState === AudioPlayer.STATE_PLAYING) {
AudioPlayer.startMonitoring();
} else {
AudioPlayer.stopMonitoring();
}
if (playerState === AudioPlayer.STATE_PAUSED) {
if (currentPlayerState === AudioPlayer.STATE_PLAYING) {
store.dispatch(setAudioPlayerIntentToPause());
}
} else {
didPauseTemporarily = false;
}
}
});
TrackPlayer.addEventListener('playback-track-changed', data => {
if (data) {
let { track, position, nextTrack } = data;
if (track && track !== SIZZLE_ID) {
AudioPlayer.storeTrackProgress(track, position);
}
if (nextTrack) {
store.dispatch(audioPlayerTrackChange(track, position, nextTrack));
}
}
});
TrackPlayer.addEventListener('playback-queue-ended', data => {
if (data) {
let { track, position } = data;
if (track) {
if (track === SIZZLE_ID) {
store.dispatch(audioPlayerStop());
} else {
AudioPlayer.storeTrackComplete(track);
store.dispatch(audioPlayerRemoveQueuedTrack(track));
store.dispatch(audioPlayerPlayNext(true));
}
}
} else {
store.dispatch(audioPlayerRemoveCurrentQueuedTrack()).then(() => {
store.dispatch(audioPlayerPlayNext(true));
});
}
});
TrackPlayer.addEventListener('playback-error', data => {
store.dispatch(audioPlayerRemoveCurrentQueuedTrack()).then(() => {
store.dispatch(audioPlayerPlayNext(true));
});
});
if (Device.isAndroid) {
TrackPlayer.addEventListener('remote-duck', data => {
let {
paused: shouldPause,
ducking: shouldDuck,
permanent: permanentLoss
} = data;
if (shouldPause || shouldDuck) {
store.dispatch(audioPlayerPause());
didPauseTemporarily = !permanentLoss;
} else if (didPauseTemporarily) {
didPauseTemporarily = false;
store.dispatch(audioPlayerPlay());
}
});
TrackPlayer.addEventListener('remote-play-id', data => {});
TrackPlayer.addEventListener('remote-play-search', data => {});
TrackPlayer.addEventListener('remote-skip', data => {});
TrackPlayer.addEventListener('remote-set-rating', data => {});
}
};
@Guichaguri any more informations thanks to that or you need more ? 👍
I think that's good, I'll take a better look in the weekend.
@Guichaguri tell us if we can help ;)
@curiousdustin did you find a workaround ?
I haven't gotten around to investigating the cause yet. Like you, @ishigamii , I am getting these crash reports, but I have not experienced the issue in my own testing yet.
@curiousdustin yop sadly can't reproduce this yet too :/ have to try on android 9 cause i have a user telling me it stops instantly going background on Android 9
@Guichaguri any news on this ?
Not only it's pretty hard to reproduce, but also I don't have the reports as you do. This is one of those issues where in the best case scenario we have to keep trying changing stuff until it's fixed.
yes it's pretty hard to reproduce to be honest just got it for the first time on debug phone
After closing the app the player notification was still here and tapping on the notification got me this crash :
Fatal Exception: android.app.RemoteServiceException
Bad notification for startForeground: java.lang.RuntimeException: invalid channel for service notification: null
android.app.ActivityThread.main
Hope it can help 👍
Which Android version were you testing on?
@Guichaguri here is an approximate list of crash android version we can resume that most of the crash happens with Android 8 and 9 like @curiousdustin said :

yes it's pretty hard to reproduce to be honest just got it for the first time on debug phone
After closing the app the player notification was still here and tapping on the notification got me this crash :Fatal Exception: android.app.RemoteServiceException Bad notification for startForeground: java.lang.RuntimeException: invalid channel for service notification: null android.app.ActivityThread.mainHope it can help 👍
Try this: https://github.com/react-native-kit/react-native-track-player/pull/579/files
+1 very hard to reproduce, but seeing it on crash reports (bugsnag). might be crashing in the background?
Android OS notified me that our app has been 'crashing frequently', although I haven't seen it crash personally.
I have a similar problem on crashlytics, I have not reproduced it while testing on devices though but my users experienced it.

We're seeing this crash in crashlytics also.
Just had this happen on my phone. Happened right after a long track finished (+10min), app in background, screen off. The crash is not visible to the user, but next track is not started either (playback-queue-ended is probably not sent).
Has anyone tried @minhtc's solution yet? I'll be looking at this closer next week.
@minhtc , to clarify, does your PR address the original error posted in this thread, or just the error that happens when tapping the notification after this crash?
@Guichaguri , what is the downside to switching from startService() to startForegroundService() as recommended here: https://developer.android.com/about/versions/oreo/background.html#migration?
@curiousdustin I published a new version of my app with @minhtc's fix and will see happens. Since I don't have local repro of this, i will have to wait for my customers to upgrade this, and repro this crash.
@minhtc , to clarify, does your PR address the original error posted in this thread, or just the error that happens when tapping the notification after this crash?
My PR fix bug "Bad notification for startForeground: java.lang.RuntimeException: invalid channel for service notification: null"
does not fix bug "Not allowed to start service Intent".
Looks like @minhtc your fix is working. I don't see the invalid channel error anymore. I have 51% of my DAU using the code that has this fix and I don't see this crash. I however still see the not allowed to start service with this stack
Fatal Exception: java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.shegerapps.amharicradio/com.guichaguri.trackplayer.service.MusicService }: app is in background uid UidRecord{13e4d4a u0a217 TPSL idle procs:1 proclist:17174, seq(0,0,0)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1666)
at android.app.ContextImpl.startService(ContextImpl.java:1611)
at android.content.ContextWrapper.startService(ContextWrapper.java:677)
at android.content.ContextWrapper.startService(ContextWrapper.java:677)
at com.guichaguri.trackplayer.module.MusicModule.waitForConnection(Unknown Source:29)
at com.guichaguri.trackplayer.module.MusicModule.getState(Unknown Source:5)
at java.lang.reflect.Method.invoke(Method.java)
at com.facebook.react.bridge.JavaMethodWrapper.invoke(Unknown Source:148)
at com.facebook.react.bridge.JavaModuleWrapper.invoke(Unknown Source:21)
at com.facebook.react.bridge.queue.NativeRunnable.run(Unknown Source)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(Unknown Source)
at android.os.Looper.loop(Looper.java:214)
at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(Unknown Source:37)
at java.lang.Thread.run(Thread.java:764)
Note sure if this is of help, but in this related issue in the google issue tracker they advise the following workaround:
There is a workaround to avoid application crash. Applications can get the process state in Activity.onResume() by calling ActivityManager.getRunningAppProcesses() and avoid starting Service if the importance level is lower than ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND. If the device hasn’t fully awake, activities would be paused immediately and eventually be resumed again after its fully awake.
For me, these crashes are occurring when TrackPlayer functions are called while the app is in the background and the MusicService service is no longer running.. For example, I track what is being listened to every 5 minutes for analytics purposes.
I am unable to reproduce the crash on my test devices (which are Google Pixel phones), but also see them happening (a lot) in the wild. Mainly on samsung devices.
As a temporary stopgap, I am going to see if using the following function to check if the service is running before calling any other TrackPlayer functions in the background fixes the crashes I am experiencing:
@ReactMethod
public void serviceIsRunning(final Promise promise) {
ReactApplicationContext context = getReactApplicationContext();
ActivityManager manager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo serviceInfo : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceInfo.service.getClassName().equals(MusicService.class.getName())) {
promise.resolve(true);
return;
}
}
promise.resolve(false);
}
@puckey I see that https://developer.android.com/reference/android/app/ActivityManager#getRunningServices(int) is deprecated, and maybe we can use simpler check for that binder is not null?
There also seems to be a problem with that waitForConnection is designed to start service if it was not running and if we check for serviceIsRunning before all TrackPlayer functions that may be called in background, we change behaviour to never start service if it was not already running - would it be always fine while app is in background? Or are there some cases when service should be started?
@puckey I see that https://developer.android.com/reference/android/app/ActivityManager#getRunningServices(int) is deprecated, and maybe we can use simpler check for that
binderis not null?
There also seems to be a problem with that waitForConnection is designed to start service if it was not running and if we check for serviceIsRunning before all TrackPlayer functions that may be called in background, we change behaviour to never start service if it was not already running - would it be always fine while app is in background? Or are there some cases when service should be started?
Good point! Changed it to
@ReactMethod
public void isServiceConnected(final Promise promise) {
promise.resolve(binder != null);
}
I am adding this to all places where I am calling TrackPlayer functionality in the background. Haven't added it to things like TrackPlayer.addEventListener('remote-pause', () => TrackPlayer.pause());, because the fact that TrackPlayer can send the event means it is running.
As anyone tried this solution yet?
I have a [widget][1] which does relatively frequent updates when the device is awake and I was seeing thousands of crashes in just a few days.
The issue trigger
I even noticed the issue even on my Pixel 3 XL when I wouldn't have thought the device to have much load at all. And any and all code paths were covered with
startForeground(). But then I realized that in many cases my service gets the job done really quickly. I believe the trigger for my app was that the service was finishing before the system actually got around to showing a notification.The workaround/solution
I was able to get rid of all crashes. What I did was to remove the call to
stopSelf(). (I was thinking about delaying the stop until I was pretty sure the notification was shown, but I don't want the user to see the notification if it isn't necessary.) When the service has been idle for a minute or the system destroys it normally without throwing any exceptions.if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { stopForeground(true); } else { stopSelf(); }[1]: https://play.google.com/store/apps/details?id=com.roysolberg.android.datacounter
I see related changes in this pr https://github.com/react-native-kit/react-native-track-player/pull/466, @Guichaguri maybe it's easier to use startForegroundService() instead of startService() as curiousdustin suggested above, then calling startForeground and only then stopForeground if we do not need permanent notification? Are there some cons in that approach?
@Guichaguri FWIW, I got a reproducible scenario on my phone (Android 9, Galaxy Note 8). If I start to build the application and I locked my phone until the build is completely done and the application is started. I get the error mentioned above
Not allowed to start service Intent { cmp=com.xxx/com.guichaguri.trackplayer.service.MusicService }: app is in background uid UidRecord{...}
This happens all the time if my phone is locked while the application starts.
@aclement-clevertech I was not able to repro this on emulator. Was this repro only possible on the emulator too or only physical device?
@bemnet4u I reproduced it on both physical and emulator device, both are running Android 9, I will try to provide a small project that manages to reproduce it.
@aclement-clevertech I am able to repro this now with locked screen. I had to change my app to play audio on startup to cause this to happen. I changed this code in MusicService and it seams to solve the issue.
I also want to note that when the crash happened, it didn't actually affect the app no crash dialog was shown to the user.
// context.startService(intent);
ContextCompat.startForegroundService(context, intent);
Also I pushed all "fixes" i made here https://github.com/bemnet4u/react-native-track-player/commits/bemnet4u. None of them mine originally so not sending a pull request... posting here if anyone is interested https://github.com/bemnet4u/react-native-track-player/commits/bemnet4u
@bemnet4u @curiousdustin I think I understood why just using startForegroundService won't work - using it requires us to call startForeground within 5 seconds, or app will crash with
Context.startForegroundService() did not then call Service.startForeground() error.
Calling startForeground requires notification to be shown, and currently player is designed to call it only when playback begins, so if you do not start playing music within 5 seconds after service start, app will crash - that happens now if we just change startService to startForegroundService.
So using startForegroundService would require us to show some notification after service is started, and at that time we have no current track, etc, so it may be only some blank / generic notification, that will look ugly.
But I think we can call stopForeground(true) right after notification is created - actually I've tried that here https://github.com/perushevandkhmelev-agency/react-native-track-player/commit/b1d50dc20ccc1bf5ce662e7a1673f8c6c074ba6d - and it seems to work, but I have tested it only briefly. I'm also not sure that creating separate channel for this setup notification is ok there, but at a first glance it works, and probably is better than using playback notification channel as it may have lower importance or some other settings that fit better for this specific case. I've tried using code for creation blank notification from onStartForeground(), but it was failing with "invalid channel for service notification" on my android 9 device, so I'm not sure if that code is valid or if I was using it incorrectly somehow.
And last thing - actually calling stopForeground(true) may be optional there, as it's called anyway in updateNotification() as audio session is not active on start, but calling it right after notification is created should remove it a bit faster.
upd
@bemnet4u looking through your commits and I see that we've actually implemented a very similar fix :)
upd2
I've also refactored a bit creating these blank notifications, inspired by your code https://github.com/perushevandkhmelev-agency/react-native-track-player/commit/13ed1186dd3d3dc6bbf6990704e59a2970277b74
But anyway even if that helps not to crash, we need that isServiceConnected or similar method, as sometimes we would not want to start a service if it was not running already
@biomancer Have you tested this with users in the wild yet? If @Guichaguri thinks this looks like a good fix, I am happy to do a limited release to a few thousand of my users to see if it brings their ANR rate down.
I've found one more issue related to this service stopping - after restarting you get corrupted playback notification without any actions. I have not seen that issue before as app was just crashing right after service was stopped 😅 And so after fixes that we are discussing here, that issue has showed up.
I've created a separate pr here https://github.com/react-native-kit/react-native-track-player/pull/619 and also applied it in my branch with other fixes, including https://github.com/react-native-kit/react-native-track-player/issues/607 that is also realted to service being stopped (but my branch is based on 1.13 as 1.14 seems to have many issues on ios and I did not have time to catch up with changes and test it).
@puckey I'll release build with these fixes to production too as it looks stable, will try to do it today or tomorrow.
One thing that I did not get - what is the purpose of onStartForeground() method? I see that it's called when handling media button action, but I do not get why we need to stop service via stopSelf(); if was not in foreground. Could somebody please explain it?
Maybe we should call startForeground there unconditionally? Why is there a check for being in background and presence of react context?
@biomancer did you see a decrease in crashes after releasing to production?
@The0racle Yes, crash rate decreased significantly and I do not see this particular crash anymore, but some issues are still left - I get reports that for example users get crash when they start an app and then switch to another app without playing anything (crash is happening after some time passes, probably when background service is stopped, and sometimes when app is reopened after that). Maybe it's not related to this issue, but I'm worried about that media button handling and that it is probably needs to be updated too https://github.com/react-native-kit/react-native-track-player/issues/473#issuecomment-499966313
@dcvz @Guichaguri guys maybe you could explain briefly the idea behind that starting and stopping a service on media button intent in MusicService? When is that called (I guess on some media button events?) and why service needs to be stopped? I've tried sending media button keyevents but it looks that handling them does not touch that code, at least on android 9. If service is running, it's handled in ExoPlayback, and if it's not, then event is just ignored.
Upd. I've got it - it's called when you press actions in notification. Will try to understand next if that should be updated somehow or is fine even with new way to start service.
Also I think that my fix may be not entirely correct in some way - I guess getPosition and other 'query' methods should actually never start background service, but should just resolve to null or something like that. Current implementation may result in bad behaviour if you call these methods from background without checking if service is running - it will just start the service when it's not running and there is no point to do that if nothing is playing, will just drain the battery probably.
Ok, I've finally understood now that onStartCommand is called not only when service starts, but also when we communicate with running service via intent, such as actions from notification (android development is not my field of expertise as you can understand... 😬). But all that startForeground stuff should be called just once on service start, so we should move it from onStartCommand to onCreate that is called once on service creation. I've tried it here https://github.com/perushevandkhmelev-agency/react-native-track-player/commits/edge and it seems to work fine, will test it in production.
I've also found reason for "Module AppRegistry is not a registered callable module (calling startHeadlessTask)" crash I've been seeing in reports for a long time - see https://github.com/perushevandkhmelev-agency/react-native-track-player/commit/ee0de65e5b8ec85cf1ec47a7db1f247967ebb799.
START_STICKY caused cases when service is started by android automatically (it was possible to reproduce it on some devices by restarting an app multiple times, while other devices never did it, so it was not easy to catch), when there is no react context yet, no MusicModule initialized, etc - and when our code tries to register playback service, app crashes with that error.
I'm not sure that it's entirely ok to do that - maybe we should keep it sticky and stop if there is not react context present, but I currently see no reason to restart that service - it will not continue playback by itself anyway, so what's the point? It will be started when needed from the app as I understand it. Would be nice if someone could confirm that this is sane change, I'd create a PR then.
That took longer to read than I expected, you guys have been working like a team 😄
It's a relief that we can finally reproduce this issue, and the solution actually works, but we can go a little deeper and implement a better one.
Starting the service, creating a dummy notification, creating a player, destroying the notification and then stopping the service just to retrieve the position (that would be 0) is a huge performance penalty just for a simple action.
I see three solutions at first glance:
setupPlayer, registerPlaybackService and addEventListener.play and returning default values on getters like getPosition.Throwing rejections looks like the proper solution, but it also may also require adding rejection handling all over the place, depending on how the app works.
Acting might result into an unpredictable state, such as adding a track to the queue and it not being added at all.
Throwing rejections on actions and returning default values on getters combines the best of the options, but the behavior varies depending on the function, which might be confusing.
FYI... @biomancer I deployed your edge branch and I still see this crash.
Fatal Exception: android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground()
at android.app.ActivityThread$H.handleMessage + 1956(ActivityThread.java:1956)
at android.os.Handler.dispatchMessage + 106(Handler.java:106)
at android.os.Looper.loop + 166(Looper.java:166)
at android.app.ActivityThread.main + 6861(ActivityThread.java:6861)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run + 450(RuntimeInit.java:450)
at com.android.internal.os.ZygoteInit.main + 936(ZygoteInit.java:936)
So this fix can be used or not ? @bemnet4u you still has the same amount of crash or less ?
I have also this issue in the 1.1.4
Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{ this.is.private/com.guichaguri.trackplayer.service.MusicService}
and
java.lang.IllegalStateException: Not allowed to start service Intent { cmp=hehehe.com.hehehe/com.guichaguri.trackplayer.service.MusicService }: app is in background uid UidRecord{c87dbbb u0a197 CEM bg:+36m11s594ms idle procs:1 proclist:15426, seq(1441,1441,1441)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1666)
at android.app.ContextImpl.startService(ContextImpl.java:1611)
at android.content.ContextWrapper.startService(ContextWrapper.java:677)
at android.content.ContextWrapper.startService(ContextWrapper.java:677)
at com.guichaguri.trackplayer.module.MusicModule.waitForConnection(MusicModule.java:102)
at com.guichaguri.trackplayer.module.MusicModule.reset(MusicModule.java:298)
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:158)
at com.facebook.react.bridge.queue.NativeRunnable.run(NativeRunnable.java)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:29)
at android.os.Looper.loop(Looper.java:214)
at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:232)
at java.lang.Thread.run(Thread.java:764)
@ishigamii the error still happens but its much lower rate than before. So the fix is helping.
Sorry for delayed response, I confirm in my case that particular crash (Not allowed to start service Intent) is gone completely, and total crash rate for app dropped from 29% to 1.5%. Some notable crashes left are the ones mentioned here https://github.com/react-native-kit/react-native-track-player/issues/607, but I think that is not related to this issue.
Also I see some really rare errors (3-4 in a week, while original issue had thousands of crashes) like that Context.startForegroundService() did not then call Service.startForeground() and I even once got that crash on emulator when it was really unresponsive. Basically it means that device is too busy and it fails to call startForeground in 5 seconds after calling startForegroundService. I'm not sure of how to deal with it, probably we should detect if app is in foreground and use startService initially, so that we do not have an obligation to call startForegroundService in limited time frame. I think I saw that it was solved like that in one of forks of this library.
So, overall the fix helped me, but I use it with newly added method for checking if background service is running, so that I won't start service when I want to just get position or current track.
Currently in my app logic is implemented like that:
// Querying current status of player in background using `react-native-background-timer`
const serviceIsRunning = await TrackPlayer.isServiceRunning() // that is method that is also added in my branch
if (!serviceIsRunning) {
// using TrackPlayer.getCurrentTrack(), TrackPlayer.getPosition(), etc
}
So using that requires to be careful, so I totally agree with @Guichaguri about that these getter methods should not try to start service and should return some default or null values, and overall solution to reject actions but return default values on getters seems good to me.
Currently we use play action like that:
// user presses Play in UI
//...
const serviceIsRunning = await TrackPlayer.isServiceRunning()
if (Platform.OS === 'ios' || !serviceIsRunning) {
try {
await TrackPlayer.setupPlayer(PLAYER_OPTIONS)
} catch (e) {
// some logging for Amplitude
analytics.logEvent('playerManager.setupPlayerFailed', { errorName: e.name, errorMessage: e.message })
}
}
await safely(TrackPlayer.play)
//...
safely is helper method that is used with all actions that require player to be setup and throw otherwise:
import TrackPlayer from 'react-native-track-player'
import { PLAYER_OPTIONS } from 'constants/Player'
export default async function(action, ...args) {
try {
return await action(...args)
} catch (e) {
if (e.message === 'The playback is not initialized') {
// reinitialize player and retry
try {
await TrackPlayer.setupPlayer(PLAYER_OPTIONS)
return await action(...args)
} catch (e) {
console.error(e)
return null
}
}
console.error(e)
return null
}
}
@Guichaguri Can you please point me the solution for https://github.com/react-native-kit/react-native-track-player/issues/623? I am using track-player to play .opus music stream which stops playing after first track is finished.
I would really like to solve this for my users. It is showing up as an over 20% crash rate in Google Play dev console.
Yet, after reading this thread, I am not really sure what to do.
@biomancer's solution seems to make sense, but @Guichaguri seems to be saying there should be a better way.
One thing that sticks out to me about @biomancer's solution is that it feels really odd for a module (RNTP) to require so much carefulness or special cases to use. It seems like the native code should check itself, before it wrecks itself. Instead of needing to check for a running service and what not in JS, it feels like the native part of the module should handle this, so that if all you need to do is start playback, TrackPlayer.play() is sufficient. The Native side of the code could check for the running service and create it if needed and such.
Maybe I'm missing something...
I hope that didn't come across as rude. It is just frustrating to not know what should be done about these crashes. As always thank you to everyone that has helped on this module!
Is there a work around ?
Anyone have any further input on this?
https://developer.android.com/reference/android/content/Context.html#startService%28android.content.Intent%29
fix at MusicModule.java
method:waitForConnection
context.startService(intent); //this line
modify and this:
//Android O above
if (Build.VERSION.SDK_INT>Build.VERSION_CODES.O){
context.startForegroundService(intent);
}else {
context.startService(intent);
}
@Guichaguri This crash is very annoying...
We have 100 crashes per day and sometimes over than 2000 crashes (it seems to be link with push notifications)

What's happening ?
@Guichaguri , any input on the suggestion by @LiWeiQiangAndroid ?
It seems @biomancer has done a decent amount of investigation into using startForegroundService, but in your last reply you kind of dismissed his approach.
Also can anyone clear up how this crash actually affects users? Is the main app actually crashing / quitting when this occurs? Or is it just the player activity running in the background that crashes / quits? If it is just the player, what is the result? Is it restarted when needed?
Hey fellas, I think I've understood in details what's happening here and it's explained in my messages above, but I did not create any PRs as I'm a bit lost on how track player API should behave.
@Guichaguri suggested that getters would return default values and actions would reject if service is not running, and I actually have implemented this approach in my branch here https://github.com/perushevandkhmelev-agency/react-native-track-player/commits/edge-2 among other fixes cherry-picked from forks or added by me (see my commits since Aug 29, 2019).
And while I'm using this in my production build (not yet released, but it seems to be working just fine and will be published soon), I've understood that that actually getPosition did reject on errors, so I mimicked that for now there, and also I understood that changing all actions to reject if service running is not really intuitive, as now you will have to write js code always expecting that this call to track player may throw an exception. That actually broke some of my code, even though in most cases I did expect it and was using safely function that I described above https://github.com/react-native-kit/react-native-track-player/issues/473#issuecomment-510438390 , but not in all.
Currently my approach in js code is to:
1) Check if service is running via method TrackPlayer.serviceIsRunning() before trying to use any getter methods, as knowing if service running at all is actually more valuable, then default getter value.
2) Keep every action wrapped in that safely function as I have shown before to be sure that app will try to resetup player if service was not running. I also check TrackPlayer.serviceIsRunning() in some places which are more likely to be run with killed service to get rid of extra try -> reject -> throw -> catch -> setup ->try again flow, but that is more an optimization and probably not required.
That works, but doesn't look like nice API to me and seems really inconsistent and incomplete, so I'm not sure what to do here. I will use it for now in my app as it's not a problem to keep all these things in mind for me now given how much I've spent time to dig into it, but I don't think that we should release it as final/public. I don't know - maybe we should at least add TrackPlayer.serviceIsRunning() method as first band aid step, that alone will actually be enough to allow writing a code that won't crash an app (by checking if service is running before EVERY call to TrackPlayer except setup ones), as now there is no way to accomplish it even with that extra boilerplate.
At the same time I've found one fork that tries some different approach and actually rewires all event handling, etc, https://github.com/wakingupllc/react-native-track-player/pull/5, but I didn't understand if that was working and worth it, and the overall idea behind these changes. I've asked if guys could explain it a bit and create a pr, but there is no response for now.
@curiousdustin
Also can anyone clear up how this crash actually affects users? Is the main app actually crashing / quitting when this occurs? Or is it just the player activity running in the background that crashes / quits? If it is just the player, what is the result? Is it restarted when needed?
Yeah, the app crashes completely, but in our case crash was usually caused by trying to get player position and current track in background every 5 seconds, so app would crash usually while it's in background. And how that looked somehow heavily depended on device and/or probably on some settings - as I know exactly that in many cases there were no visual indicators for users when app crashed in background, and also it was happening silently when I reproduced the issue myself (stop the playback, minimize the app, wait for one minute, and playback service is killed, at least on my Huawei Mate 10 pro, and any call to TrackPlayer from background service or from the app if it was restored to foreground would cause that crash), but at the same time many users reported some really embarrassing things like that they see repeating crash alerts from our app all the time, even if they were not actually starting the app since boot. Probably service was autorestarting because of sticky flag and crashing again and again, spamming users with errors.
yikes, so yeah, seems like it can cause a wide variety of user visible symptoms. :(
We are also checking position in the background every 5 seconds or so, just as you mentioned.
This is important to keep track of user progress both for analytics and for saving their place in a track. (think podcast or audio book)
@curiousdustin Yeah, we use the same approach.
As you can see I actually have based my branch on yours, so we have matching versions, etc, so as temporary workaround you probably may just cherry-pick commits from my repo and use these TrackPlayer.serviceIsRunning() and safely techniques from here https://github.com/react-native-kit/react-native-track-player/issues/473#issuecomment-510438390 as I do until some other recommended way of handling that issue will appear.
Hey fellas, I am experiencing this crash while my app is playing the tracks on background Mode. If I stay on the player screen, all is well, but when I go to background mode, it just need like 30 seconds to 1 minute in order to crash the entire application.
@matheus-erthal yes, that happens if you call get / control methods of TrackPlayer in background after service have been stopped. The fastest workaround for now is to fork my repo and use my edge-2 branch, or at least to cherry-pick https://github.com/perushevandkhmelev-agency/react-native-track-player/commit/aa6e1eaa9c322a186c4fe00f6b44374061c4bf1f and to read await TrackPlayer.serviceIsRunning() before making any getter/action call to TrackPlayer, and reacting if service is not running - setting it up or skipping the call, depending on what is desired for application at that moment.
If you use not just this one commit but the whole branch, I must say that it also includes possible fixes for crashes mentioned here https://github.com/react-native-kit/react-native-track-player/issues/607, but I have not yet tested that in production (and cannot reproduce them locally to check), I'll create a PR after verifying if that helped, and also few other fixes from PRs that are not merged yet, but working good enough to be useful.
Is there any update on when a fix (or the helper function above) might be released? We've currently got forked versions of the library for other bugs, so don't really want to depend on another one!
@Guichaguri Any more updates on this issue? Otherwise it seems @biomancer's fix is the best option at this time.
@curiousdustin : I am facing same issue from the launch of my app(launched before 2 and a half month)
Fatal Exception: android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{3efd578 u0 com.my.app/com.guichaguri.trackplayer.service.MusicService}
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1855)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:6986)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1445)
Most painful things for me is crashing i am keep getting in android samsung 9 series device. These crashes are happening in samsung 9 series device and it is on massive level.
I had attached screenshots of issues' last 15 days of Crashlytics.
And the list of Samsung devices



I am not personly able to regenerate the issue because I don't have a hint of how can I regenerate it. but if someone knows how we can regenerate it then please let me know.
@curiousdustin : I am implementing @biomancer solution. But can anyone provide me a sequence of regeneration.
@LiWeiQiangAndroid: does this comment changes worked for you?
https://github.com/react-native-kit/react-native-track-player/issues/473#issuecomment-524541538
Thanks in advance
@jariwalabhavesh Me too, smae.
But I can't fix it because I can't simulate same situation.
@Saehanseul
I am able to regenerate the same error using comment
I had just put the above comment code in java file and I start getting the same error message in firebase crashlytics.
also, I am working on @biomancer 's solution he had provided here.
It looks like service is not started before I was setting up an audio player. I am working on it and looks like we need to add checks for services running status before performing any action on track player. Which will stop crashing it. But still, I am working on it and let you know that like other functionality of the player is working fine or not.
I will update here soon. I may take a week or more because I will come up with the next one-week firebase crash stats after release build with this fix.
This issue is happening with version 1.1.8, any solutions found yet?
java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.xxx/com.guichaguri.trackplayer.service.MusicService }: app is in background uid UidRecord{4d77fb1 u0a225 LAST bg:+1m39s187ms idle change:cached procs:1 seq(159,159,159)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1551)
at android.app.ContextImpl.startService(ContextImpl.java:1492)
at android.content.ContextWrapper.startService(ContextWrapper.java:650)
at android.content.ContextWrapper.startService(ContextWrapper.java:650)
at com.guichaguri.trackplayer.module.MusicModule.waitForConnection(MusicModule.java:106)
at com.guichaguri.trackplayer.module.MusicModule.updateOptions(MusicModule.java:182)
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:158)
at com.facebook.react.bridge.queue.NativeRunnable.run(NativeRunnable.java)
at android.os.Handler.handleCallback(Handler.java:790)
at android.os.Handler.dispatchMessage(Handler.java:99)
at com.facebook.react.bridge.queue.MessageQueueThreadHandler.dispatchMessage(MessageQueueThreadHandler.java:29)
at android.os.Looper.loop(Looper.java:192)
at com.facebook.react.bridge.queue.MessageQueueThreadImpl$4.run(MessageQueueThreadImpl.java:232)
at java.lang.Thread.run(Thread.java:764)
still nothing concluded about this? @biomancer did you just abandon using this library and instead are just maintaining your own personal fork? Was any of this addressed in @Guichaguri 's 1.2.2 release about a month ago? very unsure about the best way of dealing with this - would prefer not to have to band-aid all our checking code with isServiceRunning
Even so - why is that PR still open? This is a pretty serious bug, causing lots of issues. It's quite disheartening to see huge issues like this still open with no real resolve.
Of course, I understand that this is an open-source library, and it's difficult to maintain - so thank you for all your work on this. It would be great to hear about the status of problems like this.
@octodhruv yes, I am using the fork with fixes that I mentioned above, it's stable and we have no notable issues with it (neither with the new fixes and flow nor overall), at least in the way we use it, so we are sticking to it until we are required to upgrade for some reason.
Upd. Not that sure about stable though, we are seeing some random crashes on ios with that build like EXC_BAD_ACCESS
Exception 1, Code 8, Subcode 8 >
Attempted to dereference garbage pointer 0x8000000000000008, but I'm not sure that it's related to fork, could not figure it out for now, but anyway that is not related to current issue and I'm not sure if that it's related to using the fork
Still happening in 1.2.2
@biomancer : Can you provide your fork link so I can also try that and check for the result. If it will work then I will also be using your fork until it fixed here.
Please share repo link
@jariwalabhavesh sure, it's the one I mention in comments above, https://github.com/perushevandkhmelev-agency/react-native-track-player/tree/edge-2
Here are some code samples and explanation https://github.com/react-native-kit/react-native-track-player/issues/473#issuecomment-510438390 and https://github.com/react-native-kit/react-native-track-player/issues/473#issuecomment-527936277
@biomancer that's great i tried your fork also while building my app & also @Drazail fork , which also has some of the fixes and features, i would be very happy if we guys can collaborate on a single fork so that we can make this module a better one . my app is related to streaming so i can test all the streaming functionality and we can also reduce the bugs and also introduce features. i would like to know your thoughts about this . also other people who are using it can help.
@biomancer using your fork we solved the issue with android, but on iOS app stops playing after 2-3 hours, how to deal with this issue?
@octodhruv and @ashishfeels were you guys able to fix the issue on iOS, when player stops playing in the background after 2-3 hours? did you go through this issue ?
@Sathyanarayan09 Hi - we've haven't experienced this problem. But then most of the audio files we're playing are around max. 30mins long, so I don't think should be an issue. This also could be a native iOS thing, to deal with audio left on? I'm not sure though....
@Sathyanarayan09 we haven't yet build the app for ios so can't tell about that sorry. may be @drazail can help .
@octodhruv Thanks for the response, we are also playing long audio tracks like (30min and more), but did you'r app pass testing for long duration play at background? ie
step 1. Start the play
step 2. Keep the app in background
step 3. Lock the phone and check periodically like every hour to see if the tracks are playing.
after 2-3 hours of not bringing the app to foreground it fails at some point, can you please confirm this test passes with you'r app, this will be a great help for us. Thank you.
@ashishfeels thank you for the response.
@Sathyanarayan09 we haven't yet build the app for ios so can't tell about that sorry. may be @Drazail can help .
we do not use this lib on iOS.
@dcvz any thought here please?
@biomancer : After the implementation of your edge-2 branch. Crashes are reduced. That is a relief for me. But I started getting the same crash error with the Samsung 8 series device. Before it was only with Samsung 9 series device(Which was fixed by the implementation of your fork repo)

Do you also face crashes with the Samsung Series 8 devices? Do you have any idea why crashes started with Samsung 8 devices?? You can go through my comment here where I had mentioned that I was getting error only on Samsung 9 devices and now 9 device issue resolve and start with Samsung 8 devices.
I've spent some time trying to stick all the peaces together, so maybe my comment will help somebody out there.
Above mentioned bug indeed showed on android versions 8 and 9 (mostly samsung devices + huawei).
IllegalStateException
Not allowed to start service Intent { cmp=com.myapp/com.guichaguri.trackplayer.service.MusicService }: app is in background uid UidRecord{9545c51 u0a238 CAC bg:+1m3s329ms idle procs:1 seq(0,0,0)}
To reproduce the bug I've used @aclement-clevertech suggestion. When I started to build my app (react-native run android or through android studio) I locked the screen and waited for build to finish and error would appeared every time.
@biomancer 's solution is to add .isServiceRunning() function in native code like in his commit and then create a safely() helper in javascript, which checks if service is running and through which all TrackPlayer methods can be safely called comment.
It's a working solution. I've implemented it in my code and it works perfectly. I'm going to test it on our users and observe sentry reports :)
But as @curiousdustin said in this comment it probably should be a concern of native code to safely run, check if service is started and catch errors.
@vasylenko06 I think the final solution should be the one Guichaguri suggested here - https://github.com/react-native-kit/react-native-track-player/pull/725#issuecomment-565636166 - it looks like somewhat expected behaviour. I actually implemented something very similar in my fork (commits https://github.com/react-native-kit/react-native-track-player/commit/e234c23c086ae474eb83418d7e82eaec1b98660c and https://github.com/react-native-kit/react-native-track-player/commit/cf06b801d6cf6857dcca9179ec37bacf9fc4b4e4), but had no time yet to convert it to the way @Guichaguri suggested, it currently has a bit different behaviour.
@biomancer i see that @Guichaguri gave a suggestion, but not exactly a solution (i don't know much about writing native code so i can't create a solution by myself :( ). Could you please explain does your solution requires any additional implementation from JS side? Or it adds a method to accept or reject action depending on availability of service?
@vasylenko06 it requires using this checks for availability or handling rejections for control/setter methods, here is how we use it in our code https://github.com/react-native-kit/react-native-track-player/issues/473#issuecomment-510438390 and https://github.com/react-native-kit/react-native-track-player/issues/473#issuecomment-527936277.
It is really similar to what Guichaguri has suggested, but his suggestion has better naming than my implementation and also as I understand he suggest rejecting for getter methods like getting current track, rate, etc, in my implementation they return some default blank values instead (not sure what approach is better, but I had no issues with it). I guess my implementation with suggested name fixes will do, but I had no time unfortunately lately to do it, check everything and update that https://github.com/react-native-kit/react-native-track-player/pull/725 pr.
@biomancer thank you for detailed explanation! I will implement your solution in our app, make some tests and then we'll try it out with our users. Thanks again for your time 👍
Most helpful comment
We're seeing this crash in crashlytics also.
Just had this happen on my phone. Happened right after a long track finished (+10min), app in background, screen off. The crash is not visible to the user, but next track is not started either (playback-queue-ended is probably not sent).