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.
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 am not trying to create a BOOT_COMPLETED receiver (and doing so would not solve my problem).
Is there a way to determine if BOOT_COMPLETED has occurred? I have a library which is being called before (as well as after) Android has finished booting, and I do not want my library to complete its request if the system has not finished booting. Setting up a BOOT_COMPLETED receiver in every application that may use this library is not a reasonable approach for several reasons.
Are there any Android calls I can make to determine if the device's boot has completed? It appears that there is a property, dev.bootcomplete, which I may have to use if no better method exists.
I'm afraid the only official way of achieving this is to create RECEIVE_BOOT_COMPLETED receiver.
I would advise you not to rely on properties, since they often are OEM specific. Otherwise you may end up with your application working on one Android model, but not another.
Setting up a BOOT_COMPLETED receiver in every application
I guess you mean to say you dont want BOOT_COMPLETED receiver in each activity .
Its very much possible.
You can register BOOT_COMPLETED receiver for Activity A.and once Activity A a gets broadcast it can notify other activities using sendBroadcast (custom broadcast).
To see how to use custom broadcast look here
I want to create an application in which
- Create a listener which listens for outgoing/incoming messages and calls
- UI is shown/hide based on listener results
Shrini,
As dds stated, you will definitely need at least two BroadcastReceivers. You will need one BroadcastReceiver for each incoming call and message that you want to respond to, and one for each outgoing one as well. A BroadcastReceiver may only capture one BroadcastMessage at a time. You will specifically need to capture the Intents sent by the operating system and your Application will need to have the appropriate Permissions for each. That's just setting up the listeners.
Once the BroadcastReceiver has been called you will need to start an Activity for you UI and possibly a Service to do any other processing. In the cases of single-point events (like messages) an Activity is often enough. Calls, however, depend largely upon what you are doing. Since a call has two distinct events, in order to tie them together, many people prefer to use a Service just to hold and watch the call.
In order to best help you, I must inform you that your question is remarkably vague as to what you need to do. Does your custom UI display information about the calls? Does it allow the User to respond or change that information? What kind of messages is your app responding to? SMS? Email? IMs? These are important because each one has different considerations.
Given that the limitation of information provided here, I would recommend researching your topic by downloading and viewing some of the open source projects stored on Google. Here is a Here.
Fuzzical Logic
Create a listener which listens for
outgoing/incoming messages and calls -
UI
To achieve this I think you need to use broadcast receivers to catch the broadcast message when any message activity is going on. You may need 2 in BroadcastReceivers , one for incoming and one for outgoing messages.
In the receivers you need to call your related Activity (your UI) to interact with the user. But note that you should not do any time consuming work in BroadcastReceiver since in BroadcastReceivers are expected to be light weight and killed in 10 seconds after they are invoked. See Broadcast receivers at here