I am getting this crash for only Samsung devices running android 11. Apparently the application is calling startForegroundService(intent)
and requiring me to post a notification for the user to know that I am running a foreground service, but this call to startForegroundService(intent)
was never made in the app source code, is it possible that Samsung made a custom implementation of android 11 and automatically calls startForegroundService(intent)
whenever I call startService(intent)
?
Stack trace
Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{4ab4323 u0 {app package name}/{library package name}.player.PlayerService}
android.app.ActivityThread$H.handleMessage (ActivityThread.java:2240)
android.os.Handler.dispatchMessage (Handler.java:106)
android.os.Looper.loop (Looper.java:246)
android.app.ActivityThread.main (ActivityThread.java:8506)
java.lang.reflect.Method.invoke (Method.java)
com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:602)
com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1130)
I start the service using context.startService(intent)
and the service is started in OnResume of the application and the context is the application context.
Also here is how the service is declared in the manifest
<service
android:name=".player.PlayerService"
android:exported="false"
android:foregroundServiceType="mediaPlayback"
android:stopWithTask="false">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</service>
Update: I found the reason where the call to startForegroundService(Intent)
is made, I am using the following receiver from android to help handle actions control devices like headphone buttons, so since I converted the app to androidx it started using the new MediaButtonReceiver
<receiver android:name="androidx.media.session.MediaButtonReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
This is the code that is executed when the Receiver receives an event
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null
|| !Intent.ACTION_MEDIA_BUTTON.equals(intent.getAction())
|| !intent.hasExtra(Intent.EXTRA_KEY_EVENT)) {
Log.d(TAG, "Ignore unsupported intent: " + intent);
return;
}
ComponentName mediaButtonServiceComponentName =
getServiceComponentByAction(context, Intent.ACTION_MEDIA_BUTTON);
if (mediaButtonServiceComponentName != null) {
intent.setComponent(mediaButtonServiceComponentName);
startForegroundService(context, intent);
return;
}
ComponentName mediaBrowserServiceComponentName = getServiceComponentByAction(context,
MediaBrowserServiceCompat.SERVICE_INTERFACE);
if (mediaBrowserServiceComponentName != null) {
PendingResult pendingResult = goAsync();
Context applicationContext = context.getApplicationContext();
MediaButtonConnectionCallback connectionCallback =
new MediaButtonConnectionCallback(applicationContext, intent, pendingResult);
MediaBrowserCompat mediaBrowser = new MediaBrowserCompat(applicationContext,
mediaBrowserServiceComponentName, connectionCallback, null);
connectionCallback.setMediaBrowser(mediaBrowser);
mediaBrowser.connect();
return;
}
throw new IllegalStateException("Could not find any Service that handles "
+ Intent.ACTION_MEDIA_BUTTON + " or implements a media browser service.");
}
You can see that it actually starts a foreground service, I am still investigating the crash but at least I know that a foreground service is started in the app.
Also, this crash does not only happen in Samsung like I thought, crashlytics reporting grouped Samsung crashed together because its a crash from the android platform, other instances of the same crash happens less frequently so they were way down in the crash list on firebase.
A started service can use the startForeground(int, android. app. Notification) API to put the service in a foreground state, where the system considers it to be something the user is actively aware of and thus not a candidate for killing when low on memory.
From Google's docs on Android 8.0 behavior changes: The system allows apps to call Context. startForegroundService() even while the app is in the background. However, the app must call that service's startForeground() method within five seconds after the service is created.
NO MORE STARTSERVICE - The new context. startForegroundService() method starts a foreground service but with a implicit contract that service will call start foreground within 5 second of its creation. You can also call startService and startForegroundService for different OS version.
context. startForegroundService(intent); Inside the service, usually in onStartCommand() , you can request that your service run in the foreground. To do so, call startForeground() .
After you provided more code, it's still unclear if you call startForeground()
in your PlayerService
or not. It looks like you don't, and that's why you're seeing the crash. On the other hand, if this crash is only happening on Android 11, then you may also have a different problem.
I just made a simple app to reproduce a crash for PlayerService
if startForeground()
is not called. Maybe it will be helpful to you.
Add a dependency to use the androidx MediaButtonReceiver
...
implementation "androidx.media:media:1.2.1"
...
...
<service
android:name=".PlayerService"
android:exported="false"
android:foregroundServiceType="mediaPlayback"
android:stopWithTask="false">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</service>
<receiver android:name="androidx.media.session.MediaButtonReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
...
Emulate the media button event as below
...
@Override
protected void onResume() {
super.onResume();
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
intent.setClass(this, MediaButtonReceiver.class);
intent.putExtra(Intent.EXTRA_KEY_EVENT, "test");
sendBroadcast(intent);
}
...
public class PlayerService extends Service {
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
MediaButtonReceiver.handleIntent(null, intent);
return super.onStartCommand(intent, flags, startId);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
By adding startForeground()
to onCreate()
the problem gets fixed. Please note that the way I prepare parameters and use the method is a draft only. For detailed information, please check the official documentation here.
...
@Override
public void onCreate() {
super.onCreate();
Notification testNotification = new Notification();
int testId = 1;
startForeground(testId, testNotification);
}
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With