I have 2 Android apps - App1 and App2. I have a bound service - ServiceA in App1. Multiple services and activities in App1 bind to ServiceA and call methods on it. Now, I want to send data from ServiceA to a remote service that exists in App2. I will be using the Messenger API to expose the binder object from ServiceA for inter-process-communication.
From what I understand, all the activities and services dependent on ServiceA in App1 will also now need to use the Messenger API to access the binder. Is this correct?
If yes, is there a way to make changes only to ServiceA so that it can exchange data with the remote service without making changes to it's existing clients?
P.S: The service doesn't need to handle multiple concurrent requests which is one of the main reasons I decided to go with the Messenger API.
You should be able to provide both a Messenger based interface and a direct interface. I've not tested this myself, but you can try this:
In onBind() you receive an Intent. This is the Intent that the client used when calling bindService(). You can use 2 different ACTIONs (or use "extra"s) in the Intent so that you can differentiate between the calls from App1's clients and App2's clients. Then just return either a Messenger based Binder or your current implementation, depending on which client has called onBind().
Let me know how it goes!
Related
I am creating a .aar dependency for Android which contains a class MyService (packageName: "com.example.MyService") which will run in its own process. I have used AIDL (IMyService) to return binder object using the AIDL interface stub so other applications having the AIDL interface can only access the service. MyService also has an intent-filter with action="com.example.myservice.action".
Let's take a scenario where two apps App1 and App2 with the same dependency class (com.example.MyService) and IMyService.aidl have been installed on the same device.
(1) According to docs, if multiple services have the same intent-filter action, an app binding using that action will bind to randomly any one service. In my case, com.example.MyService is available inside both App1 and App2 (inside their respective packages). So assuming App1 has already started the service, will App2 bind to the same already created MyService or create its own MyService and bind to it? Note that both App1 and App2 will be using the same intent (action: "com.example.myservice.action") and the same AIDL.
(2) I want to ensure that only one instance of the service MyService is running on the device. So if App1 is installed first, it will bind to the service (create it if it is not running) using the above specified action intent. Now, when App2 calls bindservice() using the same intent action, it should bind to the same MyService created by App1. Is this possible?
will App2 bind to the same already created MyService or create its own MyService and bind to it?
It will bind to whatever service your explicit Intent dictates. On Android 5.0+, you have to use an explicit Intent to bind to a service. By "explicit" I mean that you use something like setComponent() or setClass() on the Intent, or the Intent constructor that takes a Class as a parameter. This will indicate whether you are binding to App1 or App2.
Is this possible?
Not readily. Between PackageManager (to find out what apps have your desired action string in a service <intent-filter>) and ActivityManager (to try to determine what services are running), you might be able to determine if there is a running service or not that meets your needs. I have never tried this, so I do not know how easy it is and what permissions might be required.
However, there are issues with your plan, such as:
Race conditions. What happens if two apps try talking to the service at around the same time, and both determine that there is no service instance running, so they both start up their own?
Inbound security. Since your service has to accept requests from arbitrary other apps, how are you going to prevent malware from exploiting your service, such as by sending spoof requests?
Outbound security. Since your client has to blindly accept any possible app as being the host to the service, how are you going to prevent malware from creating their own service, using your action string, that intercepts your communications?
Can any Android experts explain when you would use
Context.bindService vs Context.startService to start a Service?
From the docs for Bound Services
A bound service is the server in a client-server interface. A bound service allows components (such as activities) to bind to the service, send requests, receive responses, and even perform interprocess communication (IPC).
In other words binding to a Service allows two-way interaction by exposing methods in the Service which are available through the IBinder via a ServiceConnection.
In contrast, using startService(...) performs more of a one-shot operation. This is only really useful if the Service can work in an autonomous fashion, i.e., it knows what it needs to do and doesn't need to be controlled further other than via any action and or data passed in the Intent used to start it. In general a Service which is started with startService(...) will not communicate directly with the component that started it (such as an Activity). It can however send data or results of an operation using a broadcast or by creating a Notification.
What are the ways to communicate between an Activity and a Service on android?
Today I learnt how to communicate by sending an Intent from Activity and replying back using BroadcastRecevier.
Which are my other options? Does anyone have a tutorial/reference regarding this?
Answer to this question is:
There are several way for an activity to communicate with an service and vice versa. This section dicusses the different ways and gives recommendation which to use.
5.1. Activity binding to local service
If the Service is started in the same process as the Activity, the Activity can directly bind to the service. This is a relatively simple and efficient way to communication.
5.2. Using receiver
You can also use dynamically registered receivers for the communication. For example your activity can dynamically register a receiver and the service sends outs corresponding events.
5.3. AIDL for services in a different process
To bind to a service which runs in a different process you need to use Inter Process Communication (IPC) as the data needs to be send between different processes. For this you need to create a AIDL file which looks similar to an Java interface but ends with the .aidl file extension and is only allowed to extend other AIDL files.
This approach is required if your service should be provided to other applications, otherwise you should prefer a local service.
5.4. Sending Intent data and bundle to the services
The service receives data from the starting Android component and can use this data.
5.5. Handler and Messenger
If the service should be communicating back to the activity it can receive an object of type Messenger via the Intent data it receives from the Activity. If the Messenger is bound to a Handler in the activity the service can send objects of type Message to the activity.
A Messenger is parcelable, which means it can be passed to another process and you can use this object to send Messages to the Handler in the activity.
Messenger provides also the method getBinder() which allows to pass a Messenger to the activity. The Activity can therefore send Messages to the service.
Thanks to http://www.vogella.com/articles/AndroidServices/article.html
Ways to connect Activity to service:
Broadcasts: easiest way, implement a BroadcastReciever in each to listen to actions of others.
Messengers: Very good for multiple types of clients, Both service and client have a Messenger , service provides it Messenger in onBind(), clients sends a register/unregister message with its own messenger in replyTo() of message. Service saves client messenger. Now both can send/recieve messages.
IBinder: If you need full fledged remote IPC . Define an Interface for service with AIDL and pass Implementations to clients in onBind().
Android online reference has explanations of each.
The guys are right, you should really google for answers!
However, I recently learned a neat way to send intents to a service. You can simply call startService(myIntent) to send an intent to your service. If the service is not running, it will be started. If the service is running, you have the possibility to react on the new information.
I have a service that communicates through AIDL with other services. I want that service to be bound by activities in my application. Can the service define two binders\interfaces? I've tried yo use a messenger for communicating with the activities, overriding "onBind" method so that it returns a different binder according to the intent it gets (one for the other services and one for the activities).
But when the activities (that use the same binder) unbind from the service, I have an error "myService has leaked ServiceConnection ... that was originally bound here", which I believe is about the binder the service use to communicate with the other services.
If a service cant use two interfaces, how can I implement the communication between the activities and that service?
thank you,
-Liron
If by
"overriding "onBind" method so that it returns a different binder
according to the intent it gets "
You mean, that you set an extra to your Intent, indicating what to do it won't work.
According to the Docs in onBind(Intent):
Intent: The Intent that was used to bind to this service, as given to
Context.bindService. Note that any extras that were included with the
Intent at that point will not be seen here.
Try to give your intent a custom action and check if that works
AIDL and Messenger are used for IPC with other applications/processes. From the Android API Guide:
Note: Using AIDL is necessary only if you allow clients from different applications to access your service for IPC and want to handle multithreading in your service. If you do not need to perform concurrent IPC across different applications, you should create your interface by implementing a Binder or, if you want to perform IPC, but do not need to handle multithreading, implement your interface using a Messenger. Regardless, be sure that you understand Bound Services before implementing an AIDL.
If your activities are in the same process as the service, you just need to extend Binder.
Extending the Binder class
If your service is private to your own application and runs in the same process as the client (which is common), you should create your
interface by extending the Binder class and returning an instance of
it from onBind(). The client receives the Binder and can use it to
directly access public methods available in either the Binder
implementation or even the Service. This is the preferred technique
when your service is merely a background worker for your own
application. The only reason you would not create your interface this
way is because your service is used by other applications or across
separate processes.
This graphic regarding the bound service lifecycle may help with how you are binding/unbinding (http://developer.android.com/guide/components/bound-services.html#Lifecycle):
In my app I've designed it to have a Service that gets data constantly (for good reason, it's from some sensors) and provides it to two clients:
A UI Activity to display the live data
Another service that logs the data
At any time, both, one or neither of these clients may be running.
I think that this service should be a Bound service, whereas the logging service is a Started service.
The Android documentation for this says I should extend the Binder class, or use a Messenger if I want to access the service from another process.
This service, the logging service and the UI Activity will all be in the same apk, so they'll presumably be in the same process - but what is going to be the best solution here? I suspect the documentation might not be taking into account the possibility that I could have two clients in the same process as the service.
Thanks
The Android documentation clearly says
Extending the Binder class
If your service is private to your own application and runs in the same process as the client (which is common), you should create your interface by extending the Binder class and returning an instance of it from onBind(). The client receives the Binder and can use it to directly access public methods available in either the Binder implementation or even the Service.
This is the preferred technique when your service is merely a background worker for your own application. The only reason you would not create your interface this way is because your service is used by other applications or across separate processes.
Using a Messenger
If you need your interface to work across different processes, you can create an interface for the service with a Messenger. In this manner, the service defines a Handler that responds to different types of Message objects. This Handler is the basis for a Messenger that can then share an IBinder with the client, allowing the client to send commands to the service using Message objects. Additionally, the client can define a Messenger of its own so the service can send messages back.
This is the simplest way to perform interprocess communication (IPC), because the Messenger queues all requests into a single thread so that you don't have to design your service to be thread-safe.
So, the best option is to use a service by extending IBinder class when this service is a local service. When both services are created by using Messenger and AIDL, they are remote services.
imrankhan's preferred solution (Binder) did seem to work, but in the end I opted for a Messenger as in practise I found this solution more flexible and logical to code.