Background execution not allowed:

The CommonsBlog
Android O and the Implicit Broadcast Ban

One of the more controversial changes in Android O — for apps with a sufficiently-high targetSdkVersion — is the effective ban on implicit broadcasts. Let’s take a deeper dive into what this means and why we are here.
WTF? (W = What)

On Android O, code like this no longer works the way that you expect:

sendBroadcast(new Intent(“this.is.an.implicit.broadcast”));

Normally, this broadcast would be received by all receivers that are registered for that custom action string. Even on O, two sets of receivers will still receive the broadcast:
Those whose apps have targetSdkVersion of 25 or lower
Those that were registered via registerReceiver() of some already-running process

However, manifest-registered receivers of apps with a higher targetSdkVersion will not receive the broadcast. Instead, a message like this one will appear in LogCat:

04-11 14:12:36.340 753-763/? W/BroadcastQueue: Background execution not allowed: receiving Intent { act=android.intent.action.PACKAGE_REMOVED dat=package:com.commonsware.cwac.cam2.demo flg=0x4000010 (has extras) } to com.commonsware.android.sysevents.pkg/.OnPackageChangeReceiver

WTF? (W = Why)

You might think that the concern was tied to the battery, as this seems like another front in the ongoing “war on background processing” that has been going on since Doze mode was introduced in Android 6.0.

As it turns out, battery is of secondary importance. The real reason is process churn.

Quoting a Google engineer, who may or may not be Dianne Hackborn:

To help understand what is going on, I need to clarify that the purpose of this change is not directly related to battery use, but rather to address long-standing issues we have had in the platform where devices that are under memory pressure can get in to bad thrashing states. Very often these states are due to broadcasts: some broadcast or broadcasts are being sent relatively frequently, which a lot of applications are listening to through their manifest (so need to be launched to receive it), but there is not enough RAM to keep all of those app proceses in cache, so the system ends up continually thrashing through processes each time the broadcast is sent.

This is an issue regardless of whether the device is currently plugged in to power. In fact, this can more frequently be an issue on Android TV devices (which are always plugged in to power) because they tend to be fairly tight on RAM!

Certainly, there are plenty of system-sent implicit broadcasts that have lots of registered receivers. Years ago, I ran some code to count how many apps registered for ACTION_BOOT_COMPLETED, and an off-the-shelf device had 70-odd such receivers. Hence, when ACTION_BOOT_COMPLETED goes out, Android needs to fork 70-odd processes, create 70-odd receivers, and deliver 70-odd broadcasts. As a result, process lifetime tends to be fairly short, as Android needs to keep terminating processes to free up system RAM for yet more processes.

(ironically, ACTION_BOOT_COMPLETED is not affected by the ban, as while there are lots of registrants, that broadcast goes out infrequently)
WTF? (W = Who)

This affects:

Implicit broadcasts sent by the system, except for a handful of whitelisted ones and those that are actually explicit broadcasts that happen to have an action string

Implicit broadcasts sent by apps, intended to be delivered to other apps

Implicit broadcasts sent by apps, intended to be delivered only to themselves, based off of old programming patterns that used system broadcasts instead of an in-process event bus (e.g., LocalBroadcastManager)

Most developers will worry most about the system-sent broadcasts, as those are numerous.
WTFW? (W = What’s and Workaround, Respectively)

If you are using broadcasts for communicating between app components within a single process, switch to using LocalBroadcastManager.

If you are using broadcasts for communicating between app components within multiple processes of your own, switch to using explicit broadcasts.

If you are receiving system-sent implicit broadcasts (e.g., ACTION_PACKAGE_ADDED), keep your targetSdkVersion at 25 or lower, until we figure out better workarounds that (hopefully) do not involve polling.

If you are sending implicit broadcasts, you can break through the ban by finding the receivers and sending individual explicit broadcasts instead:

private static void sendImplicitBroadcast(Context ctxt, Intent i) {
PackageManager pm=ctxt.getPackageManager();
List matches=pm.queryBroadcastReceivers(i, 0);

for (ResolveInfo resolveInfo : matches) {
Intent explicit=new Intent(i);
ComponentName cn=
new ComponentName(resolveInfo.activityInfo.applicationInfo.packageName,
resolveInfo.activityInfo.name);

explicit.setComponent(cn);
ctxt.sendBroadcast(explicit);

}
}

Unfortunately, this brings back the process churn, and if lots of developers do this, there may be reprisals from Google. You might try introducing some delay between the broadcasts, inside the loop, to spread out the impact. However, this starts to get tricky if you spread it out over more than a few seconds (e.g., do you now need an IntentService and a WakeLock? what if your process is terminated before the broadcast loop is completed?).

If you are receiving implicit broadcasts from another app, ask the developer of that app what the plan is for Android O. Perhaps they will use the above technique, or perhaps they will switch to some alternative communications pattern.

Find out about new posts on the CommonsBlog via the Atom feed, or follow @CommonsWare on Twitter!
— Apr 11, 2017 Tweet
Meta

Atom Feed
@CommonsWare Twitter Feed
Older Posts

Copyright © 2017 CommonsWare, LLC — All Rights Reserved

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值