android o版本(8.0)及以上版本,当应用处于后台时执行startService时,会抛出以下异常:java
Caused by: java.lang.IllegalStateException: Not allowed to start service ... app is in background uid UidRecord ...android
初步理解为因为app处于后台时startServic不被容许app
从android O版本开始,google为了控制资源使用增长了两项后台限制:源码分析
后台服务优化
广播ui
其中对于后台服务的限制,指的是若是应用处于后台,则不容许直接使用startService。google
那什么是后台应用?后台的对立面是前台,google对于前台的定义以下:设计
具备可见的activity(无论该activity已启动仍是已暂停)3d
具备前台服务日志
有关联的前台应用(如壁纸,通知侦听器等)
具体可参考官方连接:
developer.android.com/about/versi…
既然咱们使用了后台服务,必然是一些无需用户感知的场景,故考虑替换为前台服务的可能性不大;
从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
红框中为日志信息的来源
ActivityServices.java#startServiceLocked
另外一处Log信息的来源:app is in background
r.startRequested第一次初始化,默认为false;fgRequired为传入的值false,故能够进入后续逻辑;
经过AMS#getAppStartModeLocked获取的allowed为决定值,意思是是否容许后台运行,返回值有多种类型(从代码提交中能够看出原先是boolean,如今是int)。
google 在一年前(2016~2017)针对后台应用的判断以及后台执行限制作了大量的提交,从记录中能够看到:
以前提到经过设置targetSdk<26的方式就能够,可是这仅仅是从8.0特性的代码层面分析得知,这种方式并不能阻止7.x系统中对后台服务的限制。
ActiveServices.java # startServiceLocked
7.1.1 AMS 是否容许后台服务启动所关心的主要仍是 当前进程的优先级 和 是否有后台运行权限
8.0 AMS 中间的流程较7.x稍微复杂一些,大体流程以下:
AMS # getAppStartModeLocked ->
AMS # appServicesRestrictedInBackgroundLocked ->
AMS # appRestrictedInBackgroundLocked
这里至关因而后台服务特权的检查,只要知足三者之一:
有persistent权限
后台运行白名单
电源优化白名单
就直接可使用后台服务,前两个均为系统应用才能设置;
均不知足则继续走后面的判断流程,重点来了,8.0中优先判断targetSdk是否在O版本及以上,是则直接返回不容许,否才会判断是否有后台运行权限!
因此,若是须要有后台运行的逻辑,8.0如下版本优先开启后台运行权限,8.0及以上版本优先开启电源优化白名单。
随着Android版本的更新,早先年使用的保活黑科技逐渐都失效了,如今须要着重在产品层面设计,引导用户开启相关权限才是迫在眉睫的需求。
总之,Google对后台的限制愈来愈严格,不只限制了各类拉活行为,也限制了抢占后台资源的行为,各大app须要提早作好高版本适配。