Context.startForegroundService() 然后没有仅在 Android 11 三星设备上调用 Service.startForeground()

ozi*_*jnr 8 android android-service samsung-mobile android-11

我仅在运行 android 11 的三星设备上遇到此崩溃。显然该应用程序正在调用startForegroundService(intent)并要求我发布通知,让用户知道我正在运行前台服务,但startForegroundService(intent)从未在应用程序源代码中进行过此调用,三星是否有可能自定义实现 android 11 并startForegroundService(intent)在我打电话时自动调用startService(intent)

堆栈跟踪

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)
Run Code Online (Sandbox Code Playgroud)

我使用context.startService(intent)服务启动服务,服务在应用程序的 OnResume 中启动,上下文是应用程序上下文。

这里也是在清单中声明服务的方式

 <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>
Run Code Online (Sandbox Code Playgroud)

更新:我找到了调用 的原因startForegroundService(Intent),我正在使用来自 android 的以下接收器来帮助处理诸如耳机按钮之类的操作控制设备,因此自从我将应用程序转换为 androidx 它开始使用新的MediaButtonReceiver

 <receiver android:name="androidx.media.session.MediaButtonReceiver">
            <intent-filter>
                <action android:name="android.intent.action.MEDIA_BUTTON" />
            </intent-filter>
 </receiver>
Run Code Online (Sandbox Code Playgroud)

这是Receiver收到事件时执行的代码

@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.");
    }
Run Code Online (Sandbox Code Playgroud)

你可以看到它实际上启动了一个前台服务,我仍在调查崩溃,但至少我知道在应用程序中启动了一个前台服务。

此外,这种崩溃不仅发生在三星,就像我想象的那样,crashlytics 报告将三星崩溃在一起,因为它是来自 android 平台的崩溃,同样崩溃的其他实例发生的频率较低,因此它们在 firebase 的崩溃列表中排名靠后。

Mah*_*ori -2

对于一些前台服务,需要做一些需要访问、、、、、、、、、等工作location,必须在manifest中指定,并在调用service时为service设置。我认为这可以解决你的问题。microphonemediaProjectionphoneCallcameradataSyncconnectedDevicemediaPlayback"foregroundServiceType"ServiceInfostartForeground

编辑

您应该在您的服务service中像这样开始:onStartCommand

if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q){
            startForeground(NOTIFICATION_ID, notification)
        }
        else{
            startForeground(NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK)
        }
Run Code Online (Sandbox Code Playgroud)

你做得到吗?