Android Services and AIDL

Android applications are built from 4 types of components:

  1. Activity – Screen (code and GUI)
  2. Service – independent code supplying something
  3. Content Provider – Data service
  4. Broadcast Receiver – component for global events handling

The developer can create multiple components from each type and each one can be an entry point.

In this tutorial i will go over the steps to create and use an android service

To use a service from a client application (2 separate APKs) we are using binder IPC. The Binder is an IPC mechanism built into the kernel (as character device). In the native layer google wrote the libbinder library and with help of AIDL language and tool it make the binder very easy to use

AIDL – Android Interface Definition Language

To create a service we need to define an interface between the client and the server. AIDL is the way we do that , simply add a file with .aidl extension and the AIDL tool supplied with Android SDK will generate a code for using in the server (stub) and the client(proxy).

The best way to build client and server applications is to create the common code in a library

  • Create an Android Studio project – select “phone or tablet” template no activity – this will be the server application for hosting our services
  • From file menu select new -> New module and select Android Library. Name the library mylib
  • Add a new AIDL file to the library – right click the library and select new -> AIDL -> AIDL file. Name the file ISimpl.aidl
  • Declare a simple interface:

  • Build the module – from the build menu select make module mylib

The generated code 

If you change the view project files and go to mylib/build/generated/source , you will found a generated java file ISimp.java with the generated code from your AIDL

The generated code looks like this: (I removed the inner methods to simplify the explanation)

The interface in the AIDL file converted into java interface. The Stub class is used by the service implementation In the server app. The proxy class is used by the client application.

Writing the server application

First thing we need to do is adding dependency between the server application and the android library module:

  • Right click on the server application -> Open Module Settings -> Dependencies -> click on the green plus icon on the upper right corner -> Select Module dependency -> select mylib

Add a new java class to the project – SimpServiceImp.java. The class should derived from ISimp.Stub class. The generated Stub class is abstract so we need to implement the missing methods – the members from the interface ISimp:

Now to create an Android Service we need to add another class derived from Service class and implement onBind and return the service implementation (Java does not support multiple inheritance so there is no way to derived from both the Stub and Service)

Create a new class: MySimpService.java

Last thing to do is declare the service in AndroidManifest.xml file:

To install the server app select Run -> Edit Configuration and select Nothing in the Launch list (this will only install the APK without trying to run it). then run the application

Writing the Client application

Add a new module to the project – select Phone & Tablet module , select a simple activity. This will create a new APK module so now our project built from 2 APKs and one AAR

Add a dependency to mylib module

To bind to the service you first need to implement ServiceConnection Interface. You can do it using a separate class or anonymous class but in this simple example we use the MainActivity class:

Before we implement the ServiceConnection interface we need to bind the service – we will do it in onStart event:

We use the service action name as declared in the AndroidManifest.xml file and we need to specify the server package to create an explicit intent

Now add a ISimp member to the class and implement the onServiceConnected method:

The method asInterface returns a Proxy object to use by the client. Now we can add a button with event and call the service using the proxy:

How does it work

We can see the flow from the generated code, when we call add , the add method from the Proxy class is invoked , It serialise the parameters and send it to the binder:

using mRemote.transact the proxy send the request to the binder, then to the service Stub member onTransact:

The function deserialize the parameters, call the service implementation add method (what we implemented above) and serialize the return value

 

Extending the interface

Now we can add more methods to the interface , implement on the service and use from the client

in, out, inout keywords

When using a primitive types , they passed and return by value but if we send an object to a java method, it is passed by reference. To make it work on another process we need to serialize the parameters from the client to the service and serialize it back because maybe the function changed it. To make it more effective we need to specify if the object should be input (from the client to the service only) , output (from the service to the client only) or input and output. We do that with one of the above keywords

For example we want to add a method to calculate array items sum. we need to pass the array to the service but we don’t care about changes done by the service so we add it to the AIDL file with in keyword:

implement on the service implementation class and use it from the client

If we want a function to fill the array with values we need to specify it as out and if we read and write values on the service (get an image, convert it to grey scale) we use inout:

Creating custom types

You can pass a very limited number of types using the binder :

  • All primitives
  • Arrays of primitives
  • String and CharSequence
  • Some data structures (map, list, etc)
  • File Descriptor (very useful)

You can add a new type by implementing Parcelable interface: (do it in the library)

Serialize the object in writeToParcel method and deserialize it on createFromParcel. Note that the order is important (in this example first is integer and second is srting)

We also need to add another aidl file CustomType.aidl with the parcelable definition:

Now we can add the custom type as a parameter in our interface:

Note that we need to import the custom type even if its on the same package

Asynchronous Service

Another useful option is declaring an async method in the service. We do it using oneway keyword and we need to split the operation into 2 interfaces – one for the request and one for the response.

For example we want to sum the array elements asynchronously. We need to create 2 interfaces:

one for the request: IAsync.aidl

And one for the response: IAsyncListener.aidl

Now we implement the service:

And use it from the client

Note that the client derived from the response interface Stub (i.e. the client act as a server for the result)

Thats it. You can download the source example here

This is the basic for any type of service in android , next post will be on native services integrated into AOSP

 

 

Tagged

3 thoughts on “Android Services and AIDL

  1. […] submitted by /u/matoas7 [link] [comments] Source from: […]

  2. Would you say this is a good mechanism to create plugins?

  3. […] December 9, 2017 Liran B.H  2d Comments […]

Leave a Reply

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