ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Follow publication

Android IPC Mechanisms #1 — AIDL

You should use this method if you need a multithreaded IPC structure. If you are not going to perform concurrent operations, you can choose Messenger instead of AIDL.

In this method, an application calls the method in another application on the same device, namely RPC (Remote Procedure Call). Since these methods can be called from many different processes/threads simultaneously, we need to take care that the mechanism we will handle calls is thread-safe.

So what is AIDL?

If you are familiar with the concept of IPC, you consider AIDL as Android-IDL (Interface Definition Language). This method is known as AIDL because the interface where the applications/processes shake hands for the communication to be established is created in the AIDL language. AIDL is a language that has Java syntax.

Let’s begin!

Let’s create two applications that can communicate with each other. In the rest of the article, I will refer to these applications as server and client for simplicity. You can access the source codes of the applications from the link at the end of the article.

Let’s code a scenario that includes the following functionalities:

  • The client gets the server’s PID and how many connection requests have been received to the server.
  • The client gets the count of how many connection requests have been received to the server.
  • The client sends information of self such as its PID and package name to the server application. The server displays them as the last connected client info on the UI.

It will look like this when the sample is finished:

In this method, communication is based on Binder architecture. Calling bindService is a way to start a service. A component within the application or the remote process can bind to the service. A binder object is returned to the component(activity, service) that is bind. We will not go further into the details of the Bound Service concept as it is not the subject of this article.

In this example, the client will bind to the service of the server application. Thus the client can access the methods defined in the server application.

Let’s Create the Server Application

First, let’s create a new project. I named it IPCServer.

Create an AIDL file

We create our AIDL file containing the methods to be called from the client by right-clicking on the project explorer section on the left and following the path

New-> AIDL-> AIDL File

When we create it in this way, our file will automatically be created in the same directory as java and res, in the aidl folder. For example in this project, in src/main/aidl/com/pmirkelam/ipcserver/directory.

Modify the AIDL file

Now, let’s modify this file. We will add our own methods instead of the basicTypes method.

getPid: Get the process ID of the server application

getConnectionCount: Get the information about how many times the server application has received a client connection request during its life-cycle.

setDisplayedValue: The client set some information about itself to the server such as package name, PID, and arbitrary text. The server will display this information on its GUI.

There are some restrictions for the parameters and return types that AIDL methods take. You can find below all the types that can be used as parameters and return values. If we want to use a class that we have defined, it needs to be parcelable so that parsed to a level that the operating system can understand.

  • All primitive types in the Java programming language (such as int, long, char, boolean, and so on)
  • Arrays of primitive types such as int[]
  • String
  • CharSequence
  • List: All elements in the List must be one of the supported data types in this list or one of the other AIDL-generated interfaces or parcelables you've declared. A List may optionally be used as a parameterized type class (for example, List<String>). The actual concrete class that the other side receives is always an ArrayList, although the method is generated to use the List interface.
  • Map: All elements in the Map must be one of the supported data types in this list or one of the other AIDL-generated interfaces or parcelables you've declared. Parameterized type maps, (such as those of the form Map<String,Integer>) are not supported. The actual concrete class that the other side receives is always a HashMap, although the method is generated to use the Map interface. Consider using a Bundle as an alternative to Map.

in, out, and inout prefixes

All non-primitive parameters require a directional tag indicating which way the data goes. Either in, outor inout.

In AIDL, the out tag specifies an output-only parameter. In other words, it's a parameter that contains no interesting data on input, but will be filled with data during the method.

For example, a method that copies an array of bytes might be specified like this:

void copyArray(in byte[] source, out byte[] dest);

The inout tag indicates that the parameter has meaning on both input and output. For example:

void charsToUpper(inout char[] chars);

This is important because the contents of every parameter must be marshalled (serialized, transmitted, received, and deserialized). The in/out tags allow the Binder to skip the marshalling step for better performance.

Thanks to Gladed for this explanation.

Generate Stub

After creating our AIDL file, perform the steps to build project:

Build -> Rebuild Project

Then we see that a file with the same name but with a .java extension is automatically generated. This is an interface that has an abstract subclass called Stub, which implements the methods we have defined. In the service of the server, we will extend our binder object from the Stub class.

IIPCExample.java has generated

Define data classes

  • Create Client data class
  • Create a singleton RecentClient class where we will keep the last connected client. A list of connected clients could also be kept here, but in this example, we will only show the details of the last connected client on the UI.

Create a service.

  • Create our binder object by extending from the Stub class. Here we fill the methods.
  • Return our binder object to the client with bind.
  • Update our RecentClient object when the client bind and unbind so the UI is updated.

Note: If you are going to perform concurrent operations, Coroutines can be used in the methods of the binder object.

Define service on Manifest

  • Do not forget to add an intent filter to our service in Manifest. This way, the service will be marked as exported by default. The “exported” expression means that the service can be accessed from other processes.
  • We will use the action name we have given here in the client application also.

Create an XML file for Activity

String resource file

Use ViewBinding

For code simplicity, we can choose to use the ViewBinding library. Let’s declare that we will use it.

Modify the Activity

  • Now we can update Activity according to client info
  • The last connected client will be displayed. The layout will be hidden if there is no connected client.

We have completed the server application!

Let’s Create the Client Application

First, create a new project. I named it IPCServer.

In the rest of the article, we will use the same application for other IPC methods (Broadcast, Messenger). For this reason, while creating the project, let’s choose Bottom Navigation Activity from the activity gallery. With AIDL, Messenger and Broadcast options.

Copy-paste the AIDL file

After opening the project, we need to add exactly the same AIDL file that we created in the server application, then build again. We can create the file again by following the path

New-> AIDL-> AIDL File.

The point to note here is that the directory where the file is located is the same in both applications. When we create the file with the help of IDE, it will automatically be created under the directory src/main/aidl/com/pmirkelam/ipcclient/ and we need to update it to

src/main/aidl/com/pmirkelam/ipcserver/.

  • Copy file content, including the same package name

Set UI related things

  • Edit the menu file in the/res/menu/ directory
  • Edit the navigation file in the /res/navigation/ directory
  • Edit the string resource file
  • Change the colors in the theme to make it look different from the server
  • Do not make changes in the Activity XML file
  • Let’s configure navigation and binding in Activity

Create a fragment

  • Create the fragment XML file
  • Create the connect-disconnect button.
  • Add a hidden layout that will appear when the connection is established. In this layout. The layout includes the information received from the server application.

Put bussiness logic on Fragment

  • Do the view binding stuff in Fragment
  • Bind to the server service when the Connect button is pressed
  • If the service has not yet been created while bind, we add the BIND_AUTO_CREATE flag for automatic creation.
  • Let’s listen for connection situations by implementing the ServiceConnection interface.
  • When the connection is established, let’s send the message, packet name and PID. Then print the responses on GUI.
  • When the connection is broken, we leave behind clean by unBind to the service. When the operating system needs memory, it can kill background services in applications that have not user interaction for a while. In Bound Services, as long as there is at least one bound client, background services are not killed, except in extreme cases. In order not to cause waste of resources, let’s not stay bound to the service even though we do not use it.

We have completed our client application! When calling methods on the server, the flow in the graphical interface will be like this:

In this example, only the client can send a message to the server. So what can we do when the server needs to send a message to the client?

  • For example, the client called a long-running-blocking method of the server, and when the process is finished the server must return a callback to the client.
  • It is possible to implement this mechanism by giving another AIDL as a parameter to the AIDL method, as in the example below.
  • AIDL works synchronously by default. The oneway keyword is a prefix that should be added in asynchronous usage as follows.

However, if you need such an asynchronous structure and you are not going to do concurrent operations, using Messenger method instead of AIDL would be a more meaningful solution.

In Messenger, you can establish two-way communication and return a callback to the client without making such an effort.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Published in ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Responses (7)

Write a response