Reputation: 1741
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.
Upvotes: 11
Views: 2222
Reputation: 14660
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);
}
...
Upvotes: 3
Reputation: 41
for some foreground services that need to do works that need to access location
, microphone
, mediaProjection
, phoneCall
, camera
, dataSync
, connectedDevice
and mediaPlayback
, you must specify "foregroundServiceType"
in manifest and set ServiceInfo
for service when calling startForeground
in service. I think this solves your problem.
Edit
You should start your service
like this in your onStartCommand
of your service:
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q){
startForeground(NOTIFICATION_ID, notification)
}
else{
startForeground(NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK)
}
are you do it?
Upvotes: -2