Awareness API & Android O using BroadcastReceiver - android

I have an Android app which uses the Awareness API to setup a fence when a headset is plugged in.
I have implemented the AwarenessFence using code much like in the examples at: https://developers.google.com/awareness/android-api/fence-register.
I have a PendingIntent defined as:
PendingIntent.getBroadcast(context, 0, new Intent("my.application.packageFENCE_RECEIVER_ACTION"), 0)
Then in my AndroidManifest.xml file I have
<receiver android:name=".fence.FenceDetector$MyFenceReceiver">
<intent-filter>
<action android:name="my.application.packageFENCE_RECEIVER_ACTION" />
</intent-filter>
This is declared in the Manifest due to the fact that I want to receive broadcasts even when my app is in the background.
This all worked fine on Android 7.0 and below, but when I run this on a Android 8.0 I get the error:
BroadcastQueue: Background execution not allowed: receiving Intent { act=my.application.packageFENCE_RECEIVER_ACTION
I assume this is due to the new restrictions for background execution on Android O.
Can anybody tell me how to register a broadcast receiver which can listen to awareness fence triggers when in the background on a Android device running API 26.
Let me know If there is something which is unclear or if I need to elaborate something.
Thanks in advance

I can't test it on device now, but from all I've read, the limitation is only on implicit broadcasts. That means, if you create a explicit broadcast instead, that's all you need to make it work.
That means instead of this:
// implicit intent matching action
PendingIntent.getBroadcast(context, 0,
new Intent("my.application.packageFENCE_RECEIVER_ACTION"), 0)
you do that:
// explicit intent directly targeting your class
PendingIntent.getBroadcast(context, 0,
new Intent(context, FenceDetector.MyFenceReceiver.class), 0)

I did a little digging around and stumbled upon this blog post by CommonsWare. It states the very problem that you're facing.
From the above post :-
One of the more controversial changes in Android O — for apps with a
sufficiently-high targetSdkVersion — is the effective ban on implicit
broadcasts.
So, according to this, I don't think your problem has anything to do with the Awareness API. Instead, it's because of the new behaviour introduced in Android 8.
Unfortunately, though, there doesn't seem to be viable solution to this as of now. Again, phrasing from the same post :-
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.
So, hopefully there would be a better solution for 8 in the near future. Meanwhile, you could consider other options or could consider lowering your targetSDK.

Your understanding is very correct.
Apps that target Android 8.0 or higher can no longer register broadcast receivers for implicit broadcasts in their manifest. An implicit broadcast is a broadcast that does not target that app specifically.
Apps can continue to register for explicit broadcasts in their manifests.
Source
If you are only interested in setup a fence when a headset is plugged in. You can use
Note: A number of implicit broadcasts are currently exempted from this limitation. Apps can continue to register receivers for these broadcasts in their manifests, no matter what API level the apps are targeting. For a list of the exempted broadcasts, see Implicit Broadcast Exceptions.
You can resister for ACTION_HEADSET_PLUG in Android Manifest. In onReceive you can either:
start a NotificationManager.startServiceInForeground() so that you can keep doing work in background.
Find a way to duplicate the service's functionality with a scheduled job. If the service is not doing something immediately noticeable to the user, you should generally be able to use a scheduled job instead. Refer Job Scheduler
Defer background work until the application is naturally in the foreground.
I would suggest to use the combination of Job Scheduler with ACTION_HEADSET_PLUG if long running work needs to be done.
Other wise if a short duration work needs to be done which in onReceive
of you can take help from the following:
A BroadcastReceiver that uses goAsync() to flag that it needs more time to finish after onReceive() is complete. This is especially useful if the work you want to complete in your onReceive() is long enough to cause the UI thread to miss a frame (>16ms), making it better suited for a background thread.
you should not start long running background threads from a broadcast receiver. After onReceive(), the system can kill the process at any time to reclaim memory, and in doing so, it terminates the spawned thread running in the process. To avoid this, you should either call goAsync() (if you want a little more time to process the broadcast in a background thread) or schedule a JobService from the receiver using the JobScheduler, so the system knows that the process continues to perform active work.
Source

Related

WakefulBroadcastReceiver does not works when app is closed

Please help me out, a wakeful broadcast receiver is not called, I have set an Alarm with the help of Alarm Manager using setExactAndAllowIdle() with RTC_WAKEUP but still, my broadcast receiver not getting called when App is closed (means App is swiped from Recent Apps).
I am working on android 8.
Actually, I want to create an Alarm App that fires at the exact time which set, even if the App is closed or the device is locked.
Here is what you need to check out:
Alarm manager is not working with long term tasks
How to use Android AlarmManager in Fragment in Kotlin?
All the information you need can be found in those topics.
It may be because the WakefulBroadcastReceiver has been deprecated as of Android O and should generally not be used anymore. From the documentation:
Deprecated: As of Android O, background check restrictions make this class no longer generally useful. (It is generally not safe to start a service from the receipt of a broadcast, because you don't have any guarantees that your app is in the foreground at this point and thus allowed to do so.) Instead, developers should use android.app.job.JobScheduler to schedule a job, and this does not require that the app hold a wake lock while doing so (the system will take care of holding a wake lock for the job).
https://developer.android.com/reference/kotlin/androidx/legacy/content/WakefulBroadcastReceiver

Do I need to acquire wake lock when invoking a BroadcastReceiver

In the book Pro Android 4 By Satya Komatineni , Dave MacLean I've found:
Android acquires a partial wake lock when invoking a broadcast service and releases it when it returns from the service in the main thread
Does it mean that the Android OS ensures that the device will wake up for the time of going through onReceive of BroadcastReceiver? In my case the BroadcastReceiver should get an intent from Google Play Services (GoogleLocationServices and to be precise Geofences api).
Where is it documented?
EDIT: I've also found it here:
because it is guaranteed that the BroadcastReceiver.onReceive() will be always fully executed before the CPU goes to sleep
There is no such thing as a "broadcast service".
Also, you need to read the entire post containing your second quote, as that is only for a broadcast triggered by AlarmManager. It is AlarmManager, not the broadcast Intent mechanism, that holds the WakeLock. Also, as noted in that blog post, Dianne Hackborn had confirmed this behavior, and she's a core Android engineer.
Does it mean that Adnroid OS ensures that the device will wake up for the time of going thru onReceive of BroadcastReceiver?
Not generally.
In my case the BroadcastReceiver should get intent from Google Play Services (GoogleLocationServices and to be precise Geofences api).
If the Google Play Services documentation does not make any claims regarding the behavior of your receiver with respect to wakefulness, you should assume that you are not inside of a WakeLock. If the work is something that will take 1-2ms, and therefore is probably safe to do in onReceive() anyway, you're welcome to take the risk and skip a WakeLock and hope for the best.
But usually a broadcast like this triggers more work, involving disk I/O and/or network I/O, and you need to get that work off of the main application thread. Frequently, you do that by delegating to an IntentService, as it gives you a background thread with a marker service to let the OS know that you're still doing some work here. And, to ensure that the device will stay awake for that work to complete, use WakefulBroadcastReceiver or my WakefulIntentService, to hold a WakeLock from early in onReceive() until the completion of the work in onHandleIntent().
Where is it documented?
AFAIK, it isn't. Get used to it, as for complex systems, usually only a tiny fraction of the system's behavior winds up being documented.

Why some broadcast receiver can only be registered through either Code or AndroidManifest

Some broadcast receivers only work if they are registered via code rather than defined in AndroidManifest.
For example:
SCREEN_ON, SCREEN_OFF
These actions will only work with receivers registered in code. No errors happen if they are registered in the manifest, but they never get called either.
What are the reasons for this undocumented behavior? Security?
I don't think there is a security issue around this.
Manifest defined broadcast receivers are registered and can receive intents even if the application is not in memory. The opposite doesn't occur.
It could be a performance issue because registering a receiver for this type of events, may drain the user battery.
Main difference between Manifest and Programmatic registering of BroadcastReceiver
I think this is a design decision. We can register our broadcast receivers statically or dynamically. Both receiver types treated slightly different by Android system.
Mainly;
Dynamic broadcast receiver live with application. We can use it multiple times. Most important thing about it, it runs on UI thread.
Statical broadcast receiver live with OS. Package manager handles its life cycle. The transient nature of a statically registered BroadcastReceiver means that its onReceive() method cannot use any functionality which is asynchronous, for example, binding to a Service.
And some broadcast like SCREEN_ON, SCREEN_OFF... can be called continuously. If we can register this kind of broadcast. A lot of number app want to use it. And every time we open device screen, all of this app will be triggered by OS. This is not a good behavior for any kind of OS.
On the other hand, there are some broadcast that is meaningless when we use in code. Such as "BOOT_COMPLETED". It should be registered system-wide, not in UI thread.
I think this kind of decisions depends on security, performance and use case scenario.
P.S.: Long time ago, I had searched but didn't find any documentation for exact reason about it.
It seems this answer is good for me but still this is not telling the reason why some can only be registered in AndroidManifest and some only through code
The primary use of manifest-registered receivers is for broadcasts that may go on while your code is not in memory (e.g., BOOT_COMPLETED, your scheduled alarms via AlarmManager).
This behaviour does not have any relation to security as Diogo Bento mentioned it.
If there is a resource that is precious and prermission is needed before using it, then you have to ask for that permissions, no matter weather you declare your Broadcast Receiver in the manifest or register it in the code. Without the required permissions, both will fail.
I think the reason of the code only actions is that, Googe does not want to let your app being started by that action. SCREEN_ON and SCREEN_OFF is a good example. It would be easy to make an annoying application that would do something as the screen turns on. With this restriction its much harder. If you really need your application to be started as the screen turns on, then you have to do more work to accomplish the same effect. For example you have to maintain a Service that listens for those events.
In addition, most applications care about those screen events only if they are in the foreground, so there is no need to wake up every applications, which not even running. Lets say that you have 10 apps that in a way interested in the SCREEN_ON action. As you turn your screen on, 10 process would have to be started by Android just to ignore those events, because none of them running. And process is one of the most expensive resource from the perspective of an OS...

Do BroadcastReceivers need to be their own process to be independent from the UI (activities)?

So I'm working on an app that uses the AlarmManager to broadcast an intent for my receiver to do a simple task and finish quickly. I want my receiver to run every few minutes so I use setRepeating to ensure this. I don't want to have to worry about the main activity of my app running or being visible when the alarm triggers. In order for my receiver to run separately from the main activity like that, do I need to add android:process=":remote" to the receiver in the manifest? or are they already inherently separate things? The two do not need to communicate. I'm trying my best to kill the activity without canceling any alarms and the receiver seems to be running properly for now, but I'm wondering if it'll continue to work for a few hours or days.
Yes, they're separate. No need to use that attribute.
By the way, how much work do you do in that BroadcastReceiver? Normally, you can't do very much inside the BroadcastReceiver itself, you use it to trigger other things.
Also, I'm wondering how you're doing the following:
"I'm trying my best to kill the activity..."
I'm wondering what problem you were trying to solve here by trying to kill the activity?
To your immediate question - certainly not - it will be a performance killer and is unneeded anyway.
To your design - flawed. You should :
Register an alarm (also take care to re-register it on boot) - see wakeLock does not wait for network connectivity for the code registering the alarm
When the AlarmaManager wakes your receiver up delegate to a WakefulIntentService. The intent service is NOT guaranteed to run when the device is asleep (see Android deep sleep and wake locks).
See also:
PowerManager.PARTIAL_WAKE_LOCK android
PowerManager wakelock not waking device up from service for the WIS skeleton
WakefulIntentService implementation clarifications

Seeking laymans explaination of the pending intent concept

This is a pretty stale question but frankly I'm yet to find it answered in a way that satisfies my curiosity.
Before you, dear reader, leap to the android developer reference to paste me the text, please be aware that I've already read the Intent / Pending Intent documentation and am yet to resolve my confusion.
It strikes me that the Intent model is core to the android system and as such is highly generic. It is because of this that the examples I have seen of its usage tend to be many and varied. This variation obfuscates the concepts I am trying to learn and that is frustrating.
My questions are simply written but perhaps tough to explain in simple terms. I understand that an intent is a message to other activities and that other activities can declare their interest in their manifest. Pending intent, a wrapper for intent, confuses me.
I see documentation referring to permissions and token. I get that, but why is pending intent needed as a separate entity - what behavior does it enable?
What activity / task lifecycle behaviour do pending intents cause?
When is a broadcast receiver required?
What are a broadcast receiver's limitations?
I realise these are seriously newb questions (which I am) but I desperately want to understand these core concepts so I don't have to rely on example / guides / official docs as much.
Any feedback is welcome folks. Thanks.
The main purpose of a PendingIntent is to give another application written permission to do something in your stead. Applications are restricted in what they are allowed to do by, essentially, these two factors:
Visibility. Components like Services or Activities that aren't provided with a publicly visible (or any) intent-filter cannot be called by other applications. They can only be called by your application using explicit intents specifying their package and class name.
Permissions. Each application can request a certain amount of permissions. Those are mostly predefined permissions, but you do have the option to define your own permissions as well, though I never used that. Your application cannot do anything that exceeds those permissions.
Now, with pending intents, you can get past both of those restrictions, if an application that has the required permissions and visibility to do something specifically allows you to do it in her stead. An application could allow you to call one of her private Activities for example, if it gives you a pending intent that contains an explicit intent for said activities.
[edit]
They are used with the alarm manager, for example. It tells the alarm manager what and when to do by giving it a (pending) intent. Since your application probably won't be there any more when the time arrives, the alarm manager will have to send it for you. That would mean that those intents could only do what the alarm manager is allowed to do, not what your application is allowed to do. If the alarm manager was allowed to simply do anything, every application could do anything by using the alarm manager as a proxy. So you have to use pending intents to specifically grant the alarm manager the rights it needs for your particular intent.[/edit]
Apart from that, there isn't too much of a difference to regular intents, at least as far as usage is concerned. It does get a bit more complicated with sticky intents etc, but that's the general gist of it, at least as far as I know.
A broadcast receiver is required when you want to react to certain system events, or events of other applications. A broadcast receiver is invisible, it doesn't create any form of view and doesn't involve any form of user interaction. The advantage is that this can happen irregardless of whether your application (or rather, your activities) are currently running or not.
A broadcast receiver is only granted about 10 seconds to do stuff, after that it gets killed by the system. So if you want to perform any kind of long running processes you'll have to use a background service, or open up an Activity to let your users do stuff.

Categories

Resources