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.
Related
(The title is a bit weird because the words "code" and "app" are apparently forbidden in question titles.)
I have two Android apps, one is a normal unprivileged app and one is a system app with the permission to shut down the system. From my normal app I want to initiate the shutdown. I know the package name and I have full control over both apps. Both are signed with the same key.
What is the most concise way to run code in one app from another?
One way would be a Service that I can then start with intent.setComponent(...); startService(intent), but being a Service implies some background activity is going on, which isn't in my case.
Another way would be a BroadcastReceiver but that doesn't allow me to target a specific component, it requires an identifier whose purpose is conceptually to be received by other apps as well.
Is there another way with better fitting semantics?
but being a Service implies some background activity is going on, which isn't in my case.
Service using AIDL is simply an inter-process communication (IPC) mechanism. What the recipient of that communication does in response to that communication is up to it.
Besides, you have some background activity going on. You wrote:
From my normal app I want to initiate the shutdown
Shutting down a device is "background activity", at least in my interpretation of the expression.
Another way would be a BroadcastReceiver but that doesn't allow me to target a specific component
Sure it does. You can use setComponent() on a broadcast Intent the same way that you do for binding to a Service, or starting a Service, or starting an Activity.
There are downsides of using setComponent(), notably a dependency between the two code bases. Basically, the ComponentName becomes part of the API contract, and since that maps to a Java class name, you are limited in your ability to refactor that class (new name, new package). However, there's nothing stopping you from using setComponent().
For example, I describe using setComponent() for a broadcast in this blog post. In that case, I am deriving the ComponentName values via PackageManager, but that's just in service of this specific example.
Is there another way with better fitting semantics?
For a single interaction, "fire and forget" sort of thing, where you are not looking for any sort of acknowledgment, I'd send an explicit broadcast (i.e., a broadcast of an Intent that uses the ComponentName to identify the recipient). And I'd definitely use a signature-level permission to secure it.
While CommonsWare's answer is excellent and the explicit broadcast with a custom permission is usually the way to go, in this particular case I ran into an issue.
Apps cannot receive broadcasts until they have started an activity because until then they remain in "stopped" state. So an app with only a BroadcastReceiver won't work.
And since I need to have an activity anyway, I put the shutdown code in the activity.
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...
Are there any use cases in which I would want to use a BroadcastReceiver for something other than cross-application communication?
After reading the documentation, it seems like they are targeted at cross-application communication, but the idea of using them with the LocalBroadcastManager is also mentioned. I also read this post, which addresses the general usage of broadcast receivers. Neither seem to hit clearly on why it would be useful to use broadcasts and receivers for anything other than cross-application communication.
Does it have anything to do with their asynchronous nature, or maybe they're just used to move some processing out of the main activity?
Clarification: I guess the term cross-application was too general. I was considering the built-in actions such as
android.hardware.action.NEW_PICTURE
to be coming from applications. What I would like to know is: when is it useful to use a BroadcastReceiver for communication within my app - I guess this would narrow it down to custom intent actions/categories. Sorry if the way I'm asking this is confusing. I've only just recently begun programming with Android and I still don't understand the OS very well.
As it quotes in the post you linked: "A broadcast receiver is a component that responds to system-wide broadcast announcements. Many broadcasts originate from the system."
Therefore, they are useful in "catching" system broadcasts, e.g., when the device has booted up, when the battery level changes, when your Wi-Fi has been turned on, etc.
Personally, I've used a BroadcastReceiver to start my app whenever the device receives a text message. In my case, this is preferred, as my app does not need to be running when the text message is received. Upon receipt, the system will broadcast an intent with an SMS_RECEIVED action. My BroadcastReceiver component, registered to accept this particular type ofbroadcast, will be notified and can then react as needed. In my case, it launches an Activity to notify the user of the text message and choose a particular reply text message.
This is just a specific example. There are many other broadcasts that the system transmits and your Receiver can get. Check this link and this post for more examples.
Clarification:
A LocalBroadcastManager is preferable in instances when you want rather simple way to communicate between app components without an intent being broadcast system-wide. Knowing this, you would want to go this route when the info you're passing is to be used only by your app. A LocalBroadcastManager is more efficient, generally simpler than using an IBinder interface, and can ensure that information isn't leaving your app.
For an example, suppose you have a Service that runs in the background to track and log some constantly changing data; let's say your battery level. The Service can run on its own without user interaction, saving the battery level to the disk as it changes. When you start your activity to view said data, it would use LocalBroadcastManager to register a receiver to accept the info the Service is sending, and update the Activity's UI in real time to reflect this. Since no other app needs the info from your Service, it's better to do this than broadcasting an intent to which any other app could have access.
To sum up, using a LocalBroadcastManager is:
More efficient.
More secure.
Simpler.
I currently have an AlarmManager with BroadcastReceiver implementation as my Alarm. There is one major flaw with this though; it does not go off when force closing the app. I tested out what happens with ICS calendar app, and it goes off even if I force close it. I know some people will say "if the user closes the app in that manner, they do not want it going off." What about task killers? That is the case I am looking for. Its pretty obvious my method cannot accomplish this, and I have looked and looked, but most if not all the examples are like how I implemented it. Any ideas how I can accomplish this?
Edit: So it seems all the research I've done that what I want to do is not possible without having the user install two separate apps, which is not ideal. There is a possibility that Google just made there Calendar app in that way (since they do write the source code), because I tested the top Calendar apps on the market and they all did not go off when the user force closed the app. So this begs the question, simply put, can this even be done in a single application? It is looking slim that it can be done due to Google trying to curb developers from not allowing the user control over random running broadcasts or services, which is understandable. Hopefully this helps others quickly realize there really isn't a real way to actually do this. All you can do is warn the user, that in closing your app in that manner they will not get alarms; enough said.
I would not use a Broadcast Receiver with your alarm
Broadcast Receivers in general provide two functions
1) Listen to broadcasts from the system
2) Allow apps outside of your own to make requests of your app.
Alarm Manager sets up new alarms with:
set(int type, long triggerAtMillis, PendingIntent operation)
Schedule an alarm. (from Android Documentation)
The Pending Intent placed in there is the intent that will be fired when the Alarm is up. You can have this Intent begin a Service by placing the service in the intent.
Ex:
Intent i = new Intent(context, MyService.class)
Where MyService is a class that extends Service. (you can just as easily do an activity, but having activities popping up out of nowhere is terrible design.
A Service is like an Activity that has no UI. Basically you can have it perform some background functions and possibly post a notification to the user that something has occurred.
I started with a standard local android service, and used Binders with Listeners to communicate. Then: I began noticing some serious issues with handling orientation changes, so I decided to skip the whole binder thing, and just go with broadcasting intents (and using startService exclusively) that contain all the data/commands that need to be passed.
My question is: what are some of the pitfalls I have to look out for when using this approach?
Are there any disadvantages?
If you are supporting API Level 4 and above, use setPackage() to make your "broadcast" be a "narrowcast" -- keeping the broadcast within your app. By default, the broadcast is truly broadcast, to all apps, which may or may not be a good thing for your data.
Don't forget to unregister your BroadcastReceiver (i.e., don't register it and forget it). At the same time, you will need to consider what to do if the service wraps up and the activity is long gone (e.g., BACK button). One approach is to use an ordered broadcast with a low-priority manifest-registered receiver that will raise a Notification if no activity handles the broadcast -- this sample app demonstrates what I mean.
You might consider a Messenger instead of the broadcast approach, as it is intrinsically a "narrowcast", probably is a smidge less overhead, and can't be leaked. I am still working through the mechanics of using this with configuration changes, though.