Android Interprocess Communication (IPC) with Messenger (Remote Bound Services)

Interprocess Communication is the communication of threads across process boundaries. This type of communication is supported through the binder framework in Android. In the article on Services earlier, we discussed Bound Services that has a client-server interface. A bound service is the server which allows clients (components such as activities) to bind to the Service and then send requests and receive responses. The code we discussed works across threads in the same process but will fail in the case of remote services where the Service is running in a different process altogether.

Using a Messenger

If we want this interface to work across different processes, we can use Messenger which’ll allow messages to be passed across process boundaries between client (client component) and server (service). With this technique we can perform interprocess communication (IPC) without the need to use AIDL directly.

What's the one thing every developer wants? More screens! Enhance your coding experience with an external monitor to increase screen real estate.

Note: A Messenger is coupled with a Handler. Hence, executing all the tasks (passing messages) is sequential by design as the messages are processed on a single thread by the Handler to which it belongs whereas AIDL can execute tasks concurrently on binder threads.

Following is the list of steps involved in this process:

  • The Service should implement (contain) a Handler instance that receives a callback (using handleMessage() for instance) for each call from the client.
  • The Handler is used to create a Messenger object which in itself is actually a reference to the Handler.
  • The Messenger creates an IBinder (via getBinder()) that the Service returns to clients from onBind().
  • Clients use the IBinder object in its ServiceConnection implementation to instantiate the Messenger object that references the Service’s Handler which the client uses to send Message (with send() for instance) objects to the Service’s Handler. So the Service receives the messages in its Handler.handleMessage().

At a higher level the flow is basically like this:

  • The Service passes a Messenger reference to the client processes.
  • Using that reference, the client sends messages to the server process as many times as it wants to.
  • This entire passing/communication mechanism takes place through the Binder framework.

Time to get dirty with some code! Here’s a simple Service class example that uses the Messenger interface:

public class MessengerService extends Service {

    private String TAG = "MessengerService";

    // Message codes to check against Message.what
    //
    // Message.what is a User-defined message code so
    // that the recipient can identify what the message is about.
    static final int MSG_SAY_HELLO = 1;

    // Messenger object used by clients to send messages to IncomingHandler
    Messenger mMessenger = new Messenger(new TestHandler());

    // Incoming messages Handler
    class IncomingHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_SAY_HELLO:
                    Bundle bundle = msg.getData();
                    String hello = (String) bundle.get("hello");

                    Toast.makeText(getApplicationContext(), hello, Toast.LENGTH_SHORT).show();
                    break;
                default:
                    super.handleMessage(msg);
            }

        }
    }

    public MessengerService() {
    }

    @Override
    public void onCreate() {
        Log.d(TAG, "onCreate called");
    }

    /*
    Return our Messenger interface for sending messages to
    the service by the clients.
    */
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind done");
        return mMessenger.getBinder();
    }

    @Override
    public boolean onUnbind(Intent intent) {
        return false;
    }

}

Now in the client all you need to do is create a Messenger based on the IBinder received in the ServiceConnection implementation and send messages using send(). So here’s an example:

boolean isBound = false;
Messenger mMessenger;

private ServiceConnection serviceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        isBound = true;

        // Create the Messenger object
        mMessenger = new Messenger(service);

        // Create a Message
        // Note the usage of MSG_SAY_HELLO as the what value
        Message msg = Message.obtain(null, MessengerService.MSG_SAY_HELLO, 0, 0);

        // Create a bundle with the data
        Bundle bundle = new Bundle();
        bundle.putString("hello", "world");

        // Set the bundle data to the Message
        msg.setData(bundle);

        // Send the Message to the Service (in another process)
        try {
            mMessenger.send(msg);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        // unbind or process might have crashes
        mMessenger = null;
        isBound = false;
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    Intent intent = new Intent(this, MessengerService.class);
    bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
}

A client component binds to a Service by calling bindService() which leads to calling the onBind() method that returns an IBinder for interacting with the Service. This binding process is asynchronous hence bindService() returns immediately and won’t return the IBinder to the client. To receive IBinder we’ll have to code a ServiceConnection implementation which’ll receive the IBinder in its onServiceConnected() callback method.

Note: Only Activities, Services and Content Providers can bind to a Service. Broadcast receivers cannot do that.

So the entire binding process is implementing a ServiceConnection, binding using bindService() and create a Messenger object out of the IBinder received in onServiceConnected() so that messages can be sent to the Service. When the client component is destroyed, it’ll automatically unbind from the Service but it is always recommended to unbind using unbindService() when you’re done interacting with the Service so that it can shutdown properly while not being used.

Make sure to have this entry in your manifest in order for the Service to work properly in a different process:

<service
    android:name="com.example.app.MessengerService"
    android:process=":my_process">
</service>

So we just saw how to create a Messenger object out of the IBinder received and then send messages to the Service. Wow! We just learnt how to send messages across process boundaries in Android. As you might have noticed, there are no methods to call on the Service by clients but the clients just deliver messages to the Service’s Handler implementation.

Service to Client communication

We saw how to send messages from the Client to the Service, but you can also send messages the other way round leading to a two-way communication/messaging. In order to do this you’ll basically have to create a Messenger object in the Client wrapping a Handler just like we did in the Service class and then send that to our Service in a Message using the replyTo field. Then you can save the reference to the Messenger in your Service and send() Message objects just like we did from Client to Service in our ServiceConnection implementation.

It’s pretty simple but if you’re still confused then there’s some code sample available here and here.

Messenger vs. AIDL

AIDL (Android Interface Definition Language) is basically an IPC mechanism that does the job of decomposing objects into primitives that the operating system can understand and then passing them across processes to perform IPC. Messengers are actually based on AIDL behind the scenes. When using Messenger, it creates a queue of all the client requests that the Service receives one at a time. All this happens on a single thread. In case you want your Service to handle multiple requests simaltaneously then you’ll need to make use of AIDL directly and make sure your Service is capable of multi-threading and also ensure thread-safety.

It is generally not recommended to use AIDL directly as it is a really complicated implementation and you need to ensure thread safety and handle multi threading.

Conclusion

We learnt how easy it is to achieve IPC using a Messenger with Services in Android. In the next article we’ll go through AIDL that you should use directly only if you’re certain that you must use it.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download

Author: Rishabh

Rishabh is a full stack web and mobile developer from India. Follow me on Twitter.

4 thoughts on “Android Interprocess Communication (IPC) with Messenger (Remote Bound Services)”

  1. Hey Rishabh, is it possible to implement a network activity (like socket communication) and sending the progress of each step using Message objects as theService runs on UI thread and NetworkOnMainThreadException would arise if we perform any network activities,

    You see, I have tried extending AsyncTask class to perform all my tasks but I was facing two problems:
    1) I cannot update progress to the UI elements of MainActivity from this service. Btw. the service is called from the activity’s onStart() method.

    2) The communication from Service —> Activity throws a NullPointerException when it is run on any other thread rather than UI Thread.

    Can you help me solve this twisted problem?

  2. Hi, Rishabh!

    Thanks for the article. I have a question. I’m working on an app that is basicly a timer (updates the UI each second) and a media player.
    As of now it’s only activity based, but I’d like to use a service in order to support widget, notification bar icon and in general be able to work in background.
    I have been looking at a bound service using Otto for events and now at AIDL and Messenger, but I’m confused as to which approach will work best. Do you have any suggestions? I basically want the whole “app” in the service, and the activity should only serve as UI and input.

    Thank you!
    -Fred

  3. Hi Rishabh,

    Many thanks for sharing this easy to follow tutorial.

    I just wanted to tell you that I got confused when trying to apply your ideas in a scenario where a component needs to communicate multiple times with the service. In the aforementioned scenario it would be useful to first bind the component with the service, as you are doing in your onCreate() implementation, then upon a user event occurs send the message to the service (not as part of onServiceConnected() method) and onDestroy() unbind with the service.

Leave a Reply

Your email address will not be published. Required fields are marked *

*