由于后台执行限制,Android O上的FirebaseMessagingService崩溃 [英] FirebaseMessagingService Crashes on Android O due to background execution limits

查看:58
本文介绍了由于后台执行限制,Android O上的FirebaseMessagingService崩溃的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于新的后台执行限制,我们的应用在Android O上崩溃了.我们使用的是Firebase版本10.2.1,该版本添加了对Android O的支持.

好像是Firebase的问题?还是需要一些更改来支持我们这一点?

java.lang.IllegalStateException: Not allowed to start service Intent { act=com.google.firebase.INSTANCE_ID_EVENT pkg=my.package.name cmp=my.package.name/my.package.name.MyFcmIdService (has extras) }: app is in background uid UidRecord{30558fa u0a327 RCVR idle procs:1 seq(0,0,0)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1505)
at android.app.ContextImpl.startService(ContextImpl.java:1461)
at android.content.ContextWrapper.startService(ContextWrapper.java:644)
at android.support.v4.content.WakefulBroadcastReceiver.startWakefulService(WakefulBroadcastReceiver.java:99)
at com.google.firebase.iid.zzg.b(zzg.java:9)
at com.google.firebase.iid.zzg.a(zzg.java:72)
at com.google.firebase.iid.zzg.a(zzg.java:2)
at com.google.firebase.iid.FirebaseInstanceIdService.a(FirebaseInstanceIdService.java:23)
at com.google.firebase.iid.FirebaseInstanceIdService.a(FirebaseInstanceIdService.java:34)
at com.google.firebase.iid.FirebaseInstanceId.<init>(FirebaseInstanceId.java:31)
at com.google.firebase.iid.FirebaseInstanceId.getInstance(FirebaseInstanceId.java:47)
at com.google.firebase.iid.FirebaseInstanceId.a(FirebaseInstanceId.java:4)
at com.google.firebase.iid.FirebaseInstanceIdService.a(FirebaseInstanceIdService.java:19)
at com.google.firebase.iid.FirebaseInstanceIdService.b(FirebaseInstanceIdService.java:35)
at com.google.firebase.iid.zzb$zza$1.run(zzb.java:24)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)

更新升级到11.4.2可解决此问题.

解决方案

@KaMyLL是正确的.我的应用程序也遇到了同样的问题,可以通过用JobIntentService替换IntentService(我们已经在onTokenRefresh()中启动)来解决它.

因为我发现JobSchedulerJobIntentService文档有些混乱,所以我想用一些代码片段来介绍所有内容.我希望这对遇到此问题的每个人都清楚.

是什么原因导致此问题?

由于Android 8新增了背景执行限制 ,当应用程序可能在后台运行时,您不应再启动后台服务:

应用程序位于前台时,它可以自由创建和运行前台和后台服务.当应用进入后台时,它会有几分钟的窗口,仍允许其创建和使用服务.在该窗口的末尾,该应用程序被认为是空闲的.此时,系统将停止应用程序的后台服务,就像该应用程序已调用服务的Service.stopSelf()方法一样.

还有:

在许多情况下,您的应用程序可以用JobScheduler作业代替后台服务.

因此对于Android 7.x及更低版本,(据我所知)在后台运行应用程序时使用startService()是没有问题的.但是在Android 8中,这会导致崩溃.因此,您现在应该使用JobScheduler. JobSchedulerIntentService之间的行为差​​异是IntentService立即执行.另一方面,不能保证排队到JobScheduler的作业立即执行. Android OS将确定何时有合适的时间这样做,以便提高能源效率.因此可能会有延迟.到目前为止,我还不知道这可能需要多长时间. 因此,一种解决方案是检查操作系统版本并使用if-else分支代码.幸运的是,支持库可以帮助我们以更优雅的方式解决此问题,而无需重复任何代码:JobIntentService,基本上可以为您实现这一切.

如何重现该问题?

上面的第一句引述指出,该应用程序仍然具有几分钟的窗口,仍允许在其中创建和使用服务." ,因此为了重现和调试问题(以Firebase中的onTokenRefresh()为例),您可以在使用startService()启动服务之前设置一个断点.关闭应用程序,然后等待5-10分钟.继续执行,您将在此问题中看到IllegalStateException. 能够将问题重现为基础,以确保我们的修复程序能够真正解决问题.

如何将我的IntenService迁移到JobIntentService?

我以FirebaseInstanceIdService.onTokenRefresh()为例:

a)将BIND_JOB_SERVICE权限添加到您的服务:

<service android:name=".fcm.FcmRegistrationJobIntentService"
   android:exported="false"
   android:permission="android.permission.BIND_JOB_SERVICE"/>

b)而不是从IntentService扩展,而只是从android.support.v4.app.JobIntentService扩展,将onHandleIntent(Intent)方法重命名为onHandleWork(Intent),并添加enqueueWork(Context,Intent)便捷函数:

public class FcmRegistrationJobIntentService extends JobIntentService 
{
    // Unique job ID for this service.
    static final int JOB_ID = 42;

    // Convenience method for enqueuing work in to this service.
    public static void enqueueWork(Context context, Intent work) {
        enqueueWork(context, FcmRegistrationJobIntentService.class, JOB_ID, work);
    }

    @Override
    protected void onHandleWork(@NonNull Intent intent) {
        // the code from IntentService.onHandleIntent() ...
    }
}

c)使用enqueueWork()便捷功能开始工作:

public class ComfyFirebaseInstanceIdService extends FirebaseInstanceIdService {
    @Override
    public void onTokenRefresh() {
        Intent intent = new Intent(this, FcmRegistrationJobIntentService.class);
        // startService(intent);
        FcmRegistrationJobIntentService.enqueueWork(this, intent);
    }
}

我希望这个例子对您有所帮助.至少在执行了这些步骤之后,我再也无法在Android 8设备上重现该问题,并且它仍然可以在我的Android 7设备上正常工作.

更新

不推荐使用FirebaseInstanceIdService,我们应该将其从代码中删除,而应使用FirebaseMessagingService中的 onNewToken . /p>

Our app is crashing on Android O due to the new background execution limits. We are on Firebase version 10.2.1, which is the one that added Android O support.

Seems like an issue with Firebase? Or is there some change needed to support this on our end?

java.lang.IllegalStateException: Not allowed to start service Intent { act=com.google.firebase.INSTANCE_ID_EVENT pkg=my.package.name cmp=my.package.name/my.package.name.MyFcmIdService (has extras) }: app is in background uid UidRecord{30558fa u0a327 RCVR idle procs:1 seq(0,0,0)}
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1505)
at android.app.ContextImpl.startService(ContextImpl.java:1461)
at android.content.ContextWrapper.startService(ContextWrapper.java:644)
at android.support.v4.content.WakefulBroadcastReceiver.startWakefulService(WakefulBroadcastReceiver.java:99)
at com.google.firebase.iid.zzg.b(zzg.java:9)
at com.google.firebase.iid.zzg.a(zzg.java:72)
at com.google.firebase.iid.zzg.a(zzg.java:2)
at com.google.firebase.iid.FirebaseInstanceIdService.a(FirebaseInstanceIdService.java:23)
at com.google.firebase.iid.FirebaseInstanceIdService.a(FirebaseInstanceIdService.java:34)
at com.google.firebase.iid.FirebaseInstanceId.<init>(FirebaseInstanceId.java:31)
at com.google.firebase.iid.FirebaseInstanceId.getInstance(FirebaseInstanceId.java:47)
at com.google.firebase.iid.FirebaseInstanceId.a(FirebaseInstanceId.java:4)
at com.google.firebase.iid.FirebaseInstanceIdService.a(FirebaseInstanceIdService.java:19)
at com.google.firebase.iid.FirebaseInstanceIdService.b(FirebaseInstanceIdService.java:35)
at com.google.firebase.iid.zzb$zza$1.run(zzb.java:24)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)

Update Upgrading to 11.4.2 resolves this issue.

解决方案

@KaMyLL is right. I had the same issue with our app and could solve it by replacing the IntentService (which we have started within onTokenRefresh()) with an JobIntentService.

Because I found the JobScheduler and JobIntentService docs a bit confusing, I would like to some everything up with some code snippets. I hope this makes everything clear to everyone having this issue.

What is causing this issue?

Due to the new Background Execution Limits of Android 8, you should not start background services anymore when the app could be in background:

While an app is in the foreground, it can create and run both foreground and background services freely. When an app goes into the background, it has a window of several minutes in which it is still allowed to create and use services. At the end of that window, the app is considered to be idle. At this time, the system stops the app's background services, just as if the app had called the services' Service.stopSelf() methods.

And also:

In many cases, your app can replace background services with JobScheduler jobs.

So for Android 7.x and below, using startService() when the app is in background is (as far as I know) no problem. But in Android 8, this results in a crash. In consequence, you should use a JobScheduler now. The behavioral difference between JobScheduler and an IntentService is that an IntentService is executed immediately. On the other hand, a job enqueued to a JobScheduler is not guaranteed to be executed immediately. The Android OS will determine when there is a good point of time to do so in order to be more energy efficient. So there might be a delay. And I have no idea so far how long this could take. So one solution could be to check the OS version and branch your code using if-else. Fortunately, the support library helps us to solve this in a more elegant way without duplicating any code: JobIntentService, which basically does this for you under the hood.

How to reproduce the issue?

The first quote above states that the app still "has a window of several minutes in which it is still allowed to create and use services.", so in order to reproduce and debug the issue (with the example of onTokenRefresh() in Firebase), you could set a breakpoint before your start your service with startService(). Close the app and wait there for 5-10 minutes. Continue the execution and you will see the IllegalStateException from this question. Being able to reproduce the issue as fundamental to make sure that our fixes really solve the problem.

How to migrate my IntenService to JobIntentService?

I use FirebaseInstanceIdService.onTokenRefresh() as an example:

a) Add the BIND_JOB_SERVICE permission to your service:

<service android:name=".fcm.FcmRegistrationJobIntentService"
   android:exported="false"
   android:permission="android.permission.BIND_JOB_SERVICE"/>

b) Instead of extending from IntentService, simply extend from android.support.v4.app.JobIntentService, rename the onHandleIntent(Intent) method to onHandleWork(Intent), and add a enqueueWork(Context, Intent) convenient function:

public class FcmRegistrationJobIntentService extends JobIntentService 
{
    // Unique job ID for this service.
    static final int JOB_ID = 42;

    // Convenience method for enqueuing work in to this service.
    public static void enqueueWork(Context context, Intent work) {
        enqueueWork(context, FcmRegistrationJobIntentService.class, JOB_ID, work);
    }

    @Override
    protected void onHandleWork(@NonNull Intent intent) {
        // the code from IntentService.onHandleIntent() ...
    }
}

c) Start the job using the enqueueWork() convenient function:

public class ComfyFirebaseInstanceIdService extends FirebaseInstanceIdService {
    @Override
    public void onTokenRefresh() {
        Intent intent = new Intent(this, FcmRegistrationJobIntentService.class);
        // startService(intent);
        FcmRegistrationJobIntentService.enqueueWork(this, intent);
    }
}

I hope this example is helpful. At least after following these steps, I was not able to reproduce the issue on my Android 8 device anymore, and it continues to work an my Android 7 device.

Update

as FirebaseInstanceIdService deprecated we should remove this from the code, and use onNewToken from FirebaseMessagingService instead.

这篇关于由于后台执行限制,Android O上的FirebaseMessagingService崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆