1. 首页 » 生活常识

Android原生限制后台活动,头号作家详解系统行为管控机制与影响

android允许后台活动

栏目介绍

“头号作家”是由OPPO工程师们解读时下热门技术的专题栏目。在这里,你不仅能看到最新最火的动态趋势,更能与OPPO的优秀工程师们共同学习技术干货。

头号作家

■Dustin

■Android框架层工程师,热爱技术研究,热爱技术分享,目前专注于后台管控相关技术的研究。

前言

Android系统是可以支持多个应用、多个进程同时在后台运行的,而应用每次运行,必然会消耗一定的设备资源。随着用户的使用,大量应用在后台运行,对系统功耗、性能的影响将更加显著,进而导致用户在前台使用占资源较多应用的时候,更容易出现卡顿、发热、甚至前台应用被杀死等直接影响用户体验的情况。在设备资源有限的情况下,保证前台应用的正常运行才是更符合用户体验的。

出于以上原因的考虑,Google大版本更新迭代的时候,也会逐步增加对系统资源的管控,而在Android O版本中,谷歌的做法是推出了“Background Execution Limits”,旨在限制应用的service、broadcast在后台的行为, 通过约束这种非用户主动操作且用户无法感知的应用行为,提升用户体验。

android developer:https://developer.android.google.cn/about/versions/oreo/background

本文将详细介绍这个“Background Execution Limits”这个后台行为限制。首先,讲解限制的应用范围,介绍应用处于哪些状态的时候,会受到这个限制;第二部分是讲解对service的限制的实现;第三部分是讲解对broadcast 的限制。

限制应用范围

android developer告诉我们,前台应用将不会受到限制,而以下三种情况将被视为前台应用:

.具有可见的Activity

.具有前台service

.另一个前台应用已关联到该应用

实际上,除了前台应用,还有一些情况下的应用也不会受到限制。我们直接从代码上来看吧,关键就是AMS的getAppStartModeLocked方法。

1.1getAppStartModeLocked--应用启动模式

在AMS.getAppStartModeLocked这个方法里,有四个返回值,而返回

ActivityManager.APP_START_MODE_NORMAL的,就表示允许后台行为。此方法简易的流程图如下:

android允许后台活动

接下来详细介绍代码流程:

ActivityManagerService.getAppStartModeLocked

android允许后台活动

总结主要逻辑是:

1.uid在mPendingStartActivityUids中,uid即将启动一个activity或者就是一个前台显示,允许后台行为

2. uid为null或不是idle状态时,允许后台行为,1.1.2 介绍什么时候应用会是idle状态。

3.uid是idle状态时,主要看appRestrictedInBackgroundLocked和appServicesRestrictedInBackgroundLocked方法。

1.1.1appServicesRestrictedInBackgroundLocked

appServicesRestrictedInBackgroundLocked方法主要是检查service启动是否有权限。

ActivityManagerService.appServicesRestrictedInBackgroundLocked

android允许后台活动

这里主要逻辑判断几个条件:

1. Persistent属性的app,放行。

2. 应用的uid在uid白名单中(这里只有蓝牙uid),放行。

3. 应用在doze白名单中,放行。看1.1.1.2

4.继续判断appRestrictedInBackgroundLocked方法,看1.1.2

1.1.1.2 isOnDeviceIdleWhitelistLocked

isOnDeviceIdleWhitelistLocked方法是判断各个doze的白名单:

1. mDeviceIdleExceptIdleWhitelist:doze的ExceptIdle白名单,用于豁免除了idle之外的省电功能。

2. mDeviceIdleWhitelist:doze的全白名单,用于豁免所有的省电功能。

3. mDeviceIdleTempWhitelist:doze的临时白名单。

4. mPendingTempWhitelist:pending的临时白名单。

ActivityManagerService.isOnDeviceIdleWhitelistLocked

android允许后台活动

1.1.2appRestrictedInBackgroundLocked

appRestrictedInBackgroundLocked主要是考虑到O以下版本sdk的兼容。

ActivityManagerService.appRestrictedInBackgroundLocked

android允许后台活动

1.2uid什么时候会进入idle

1.1在getAppStartModeLocked方法中提到,uid不是idle状态时,回返回true。那uid什么时候会进入idle呢?简单来说就是应用处于后台超过1分钟,就会被设置进入到idle状态,流程如下:

android允许后台活动

在AMS进行进程优先级(adj)计算的时候,updateOomAdjLocked和updateOomAdjLockedInner方法会调用一次updateUidsLocked,用于更新uid的状态。

ActivityManagerService.updateUidsLocked

android允许后台活动

android允许后台活动

这个方法主要就是在uid的进程状态发生改变的时候,调用isProcStateBackground方法判断是否需要发送延迟

msg处理uid idle,接着看isProcStateBackground是做什么事情的。

1.2.1isProcStateBackground

isProcStateBackground这个方法很简单,就是看procState是否是大于PROCESS_STATE_TRANSIENT_BACKGROUND的。

ActivityManager.isProcStateBackground

android允许后台活动

官方描述中提到的前台应用的范畴,procState都会是小于PROCESS_STATE_TRANSIENT_BACKGROUND(8)的,包括以下procState。

ActivityManager.PROCESS_STATE_UNKNOWN

android允许后台活动

1.2.2idleUidsLocked

对于ProcState是“Background”的应用,将会在idleUidsLocked中进行逻辑处理。

OomAdjuster.idleUidsLocked

android允许后台活动

idleUidsLocked方法就是将所有active的uid的上次处于后台的时间(uidRec.lastBackgroundTime)拿出来计算,如果lastBackgroundTime是0(procState小于8)或未超过60s,则等到下一次计算idle再处理,否则将idle置为true。

1.3限制应用范围-小结

通过以上对代码的分析走读,可以得知后台限制service主要就是看重uid、UidRecord,即整个包/应用的状态,而不是某个进程的状态,同时也得知了有什么应用不会被限制(大于O的版本):

top或即将是top的应用

进程procState小于8的应用

Persistent属性的应用uid在uid白名单的应用

uid在doze白名单中的应用

应用开发者也可以从以上几点考虑是否能绕过限制。

但如果getAppStartModelocked方法中传入的alwaysRestrict为true,如果静态广播的情况,则无法通过上述条件被放行。

限制后台Service

对于后台service的限制行为主要有两个,startService限制和 stopInBackground。

2.1startService限制

可能不少开发者在编写自己的应用的时候,想通过startService启动一个service,都会遇到过一下这行提示:

android允许后台活动

这就是Android对后台startService的限制。

2.1.1startServiceLocked

了解startService流程的同学都知道,调用Context.startService或Context.startForegroundService之后都会走到

ActiveServices.startServiceLocked,而Android对于后台startservice限制就是在这里做的。

ActiveServices.startServiceLocked

android允许后台活动

android允许后台活动

可见startServiceLocked方法中,如果应用并非起前台服务或被用户限制后台行为:

1. 如果允许getAppStartModeLocked应用启动,继续startService流程。

2. 如果不允许应用启动,是用户主动加进限制名单,返回null,不会抛出异常。

3. 如果不允许应用启动,且不是用户主动加进限制名单,返回一个ComponentName,将会抛出异常。

2.1.2startService抛出异常

在ActiveServices.startServiceLocked中返回的ComponentName最终回到应用侧的

ContextImpl.startServiceCommon中进行处理,最终抛出一个异常。

ContextImpl.startServiceCommon

android允许后台活动

android允许后台活动

2.2stopInBackground

可能不少开发者在编写自己的应用的时候,启动了service,但是过了一段时间,发现这个service被stop了,查看log发现了以下这行提示:

android允许后台活动

这个就涉及到我们前文讲的uid的idle计算过程,将某个uid置为idle之后,会调用ActiveServices.stopInBackgroundLocked。

2.2.1stopInBackgroundLocked

如果应用的uid变为idle,或者应用被限制后台的时候,会调用stopInBackgroundLocked,将此uid下的后台的service都stop了。

ActiveServices.stopInBackgroundLocked

android允许后台活动

android允许后台活动

stopInBackgroundLocked方法就是通过getAppStartModeLocked方法筛选出需要进行限制的service,调用stopServiceLocked进行逻辑处理,这后面的逻辑与应用直接调用Context.stopService方法流程一致,不在这篇文章里做过多阐述。

广播限制

介绍广播限制之前先介绍几个广播基本的概念:

静态注册广播接收器:在应用的AndroidManifest清单中声明注册静态的广播接收器

动态注册广播接收器:运行时使用 Context.registerReceiver()注册动态的广播接收器

显式广播:指定特定的广播接收者发送的广播

隐式广播:不指定特定的广播接收者发送的广播

而这里Android对广播的限制就是,发送隐式广播时,静态注册的广播接收器无法接收到广播,这是怎么实现的呢?我们看看代码。

3.1广播分发流程

首先先看看广播分发流程,我这里大概分为四个部分:

1.处理并行广播并进行分发

2.分发有序广播前的准备工作

3.处理动态注册的receiver

4.处理静态注册的receiver(广播限制的重点在于这部分)

代码解析这里省略很多步骤,重点关注与广播限制相关的地方。

BroadcastQueue.processNextBroadcastLocked

android允许后台活动

android允许后台活动

android允许后台活动

android允许后台活动

3.2广播限制小结

可见后台对广播的限制有几个条件,满足以下条件的广播会被限制:

1. 广播接受者类型:广播接受者是静态注册的广播接收器。

2. 广播接收者应用状态:应用不允许后台启动,即getAppStartModeLocked中返回的不是APP_START_MODE_NORMAL。

3. 广播类型:广播有FLAG_RECEIVER_EXCLUDE_BACKGROUND的flag,限制启动;或者广播是隐式广播

(隐式广播,即在intent中没有指定接受者的包名、组件名且没有

FLAG_RECEIVER_INCLUDE_BACKGROUND的广播)且接受者权限不是Signature的广播,限制启动。

推荐阅读

android允许后台活动

声明:本文由"百度是最好的搜索"发布,不代表"破站"立场,转载联系作者并注明出处:https://www.848586.cn/301799.html