android O 对后台服务的限制

https://www.jianshu.com/p/1af2ce1f985c

 

现象


android o版本(8.0)及以上版本,当应用处于后台时执行startService时,会抛出如下异常:

image

Caused by: java.lang.IllegalStateException: Not allowed to start service ... app is in background uid UidRecord ...

初步理解为由于app处于后台时startServic不被允许

原因分析


从android O版本开始,google为了控制资源使用增加了两项后台限制:

  • 后台服务

  • 广播

其中对于后台服务的限制,指的是如果应用处于后台,则不允许直接使用startService。

那什么是后台应用?后台的对立面是前台,google对于前台的定义如下:

  • 具有可见的activity(不管该activity已启动还是已暂停)

  • 具有前台服务

  • 有关联的前台应用(如壁纸,通知侦听器等)

具体可参考官方链接:

https://developer.android.com/about/versions/oreo/background

解决方案


既然我们使用了后台服务,必然是一些无需用户感知的场景,故考虑替换为前台服务的可能性不大;

从google对前台应用的解释入手,可以通过制造前台场景的方式使自己的应用处于前台;

官方还提及了JobScheduler替代后台服务的方案,可以根据的业务场景选择是否使用;

startService的方式也不需要完全放弃。为了适配8.0手机,需要先判断应用是否在前台再决定是否使用startService;

判断应用是否在前台的方式很多,主要原理有两种:

  • 通过AM判断应用前台activity个数

  • 通过actvitiy生命周期回调计数(Activity回调、ActivityLifecycleCallbacks)判断是否有前台界面

实现的方式很多,自行google

设置targetSdk < 26也可以实现该新特性规避。

源码分析


startService大致流程如下:

ContextImpl#startServce ->

ContextImpl#startServceCommon ->

AMS#startService ->

ActiveServices#startServiceLocked ->

AMS#checkAllowBackgroundLocked

8.0.0

ContextImpl.java#startServiceCommon

image

红框中为日志信息的来源

ActivityServices.java#startServiceLocked

image

另一处Log信息的来源:app is in background

r.startRequested第一次初始化,默认为false;fgRequired为传入的值false,故可以进入后续逻辑;

通过AMS#getAppStartModeLocked获取的allowed为决定值,意思是是否允许后台运行,返回值有多种类型(从代码提交中可以看出原先是boolean,现在是int)。

google 在一年前(2016~2017)针对后台应用的判断以及后台执行限制做了大量的提交,从记录中可以看到:

image

image

之前提到通过设置targetSdk<26的方式就可以,但是这仅仅是从8.0特性的代码层面分析得知,这种方式并不能阻止7.x系统中对后台服务的限制。

ActiveServices.java # startServiceLocked

image

7.1.1 AMS 是否允许后台服务启动所关心的主要还是 当前进程的优先级 和 是否有后台运行权限

image

8.0 AMS 中间的流程较7.x稍微复杂一些,大致流程如下:

AMS # getAppStartModeLocked ->

AMS # appServicesRestrictedInBackgroundLocked ->

AMS # appRestrictedInBackgroundLocked

image

这里相当于是后台服务特权的检查,只要满足三者之一:

  • 有persistent权限

  • 后台运行白名单

  • 电源优化白名单

就直接可以使用后台服务,前两个均为系统应用才能设置;

均不满足则继续走后面的判断流程,重点来了,8.0中优先判断targetSdk是否在O版本及以上,是则直接返回不允许,否才会判断是否有后台运行权限!

image

所以,如果需要有后台运行的逻辑,8.0以下版本优先开启后台运行权限,8.0及以上版本优先开启电源优化白名单

随着Android版本的更新,早先年使用的保活黑科技逐渐都失效了,现在需要着重在产品层面设计,引导用户开启相关权限才是迫在眉睫的需求。

总之,Google对后台的限制越来越严格,不仅限制了各种拉活行为,也限制了抢占后台资源的行为,各大app需要提前做好高版本适配。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 8.0 及以上版本,为了增强应用程序的安全性,Android 引入了后台限制,禁止未在前台运行的应用程序启动服务。如果您想在后台启动服务,需要使用 `startForegroundService()` 方法。这个方法会启动一个前台服务,然后你可以在服务启动后在通知栏显示一个通知,以此来告知用户服务正在运行。 以下是一个使用 `startForegroundService()` 的示例代码: ``` if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // 创建一个 NotificationChannel NotificationChannel channel = new NotificationChannel("channel_id", "channel_name", NotificationManager.IMPORTANCE_DEFAULT); // 向系统注册 NotificationChannel NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.createNotificationChannel(channel); } // 创建一个 Intent,启动你的服务 Intent serviceIntent = new Intent(this, YourService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // 在 Android 8.0 及以上版本上,需要调用 startForegroundService() 方法启动服务。 startForegroundService(serviceIntent); } else { // 在 Android 8.0 以下版本上,可以直接调用 startService() 方法启动服务。 startService(serviceIntent); } ``` 注意:如果你使用的是 `startForeground()` 方法,会在 Android 8.0 及以上版本上抛出 `IllegalStateException` 异常,因为 Android 8.0 及以上版本禁止在后台启动服务

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值