In the previous two parts you could read a lot of things about Android Interface Definition Language. About its origin, theoretical and practical basics, how these basics are implemented in Android system, how AIDL works and how developer can use it (as a result, quite simple) and some other things about Android and computer science.
Well now, everything of this is pretty curious, but I would like to tell you about one more interesting thing. You are using AIDL much more, than you suppose.
WARNING! This article contains a lot of code that will be provided in shortened form. Full versions you can find in your IDE, in AOSP or Android Code Search. Please be careful, cause most of further code can be changed any time by Google developers, that is why some material can be obsolete and partially or completely wrong in the future, but actual for the moment of publication. All code is retrieved from sources, which actual for Android 10.
This series of articles consist of three parts:
- The legend about AIDL. Part 1. The roots
- The legend about AIDL. Part 2. In Action
- The legend about AIDL. Part 3. The crucial ingredient (you are here)
The biggest one
The statement above is quite brave, isn’t it? Let’s research the code and see that AIDL is more important, than any Android application component. The first opponent is Activity.
Bigger, than Activity
This is ridiculous, isn’t it? How much times developers (and their users) are using Activity and how much times they need AIDL? It seems that crushing blow is directed to the hero of article. To prove this incredible fact it needs to look at the content of method, which allow to launch activity — startActivity().
This method is calling another one startActivity(), passing null for parameter options. Depending on this value, second startActivity() calls startActivityForResult() with options or not. Let’s dig deeper.
These two methods have similar behavior as previous two — one calls another one, passing null for parameter options. But second version of startActivityForResult() is quite more interesting, than previous three functions. Get ready for the long research. Let’s start from the top — getting Bundle from transferSpringboardActivityOptions(). According to source code, this method either returns the input Bundle back or will get it from method getActivityOptions().
This function tries to get ActivityOptions instance from fabric method fromBundle(). This function is getting argument of type Bundle (a lot of Bundle for getting Bundle, right?) from static method of ActivityTaskManager and passes the value of field mToken, that has type IBinder. Let’s look inside.
Finally, the AIDL usage as it is! IBinder instance is retrieved with help of static method getService(), that class ServiceManager owns. If you will look at that method body, you see that IBinder implementations are stored in special Map, which called sCache.
Well, this class is a little bit more interesting, cause method addService() will finally lead to one of few classes, that prefer do not use AIDL. It extends Binder and implements special interface by its own — class ServiceManagerNative. Okay, let’s return to getting of ActivityOptions.
To get an instance of service for getting Bundle the IActivityTaskManager.Stub.asInterface() is invoked. But what class is implementing this IActivityTaskManager? Surprisingly it is not ActivityTaskManager itself. It is ActivityTaskManagerService, which extends particular Stub class directly.
And now let’s come back to method startActivityForResult() to avoid very deep digging. After getting Bundle instance it is necessary to get ActivityResult. For this operation method execStartActivity() of class Instrumentation is called. Let’s take a look at code.
And the first line is cast of IBinder instance to IApplicationThread, which is inner nested class in ActivityThread. This is also a special Stub class extension! Well, even ApplicationThread is constructed with AIDL feature. (For curious: the method of Intent prepareToLeaveProcess() will finally lead to interesting class SystemServiceRegistry, that has a lot of interactions with AIDL Stub classes extensions).
In the end, the method startActivity(), that gets IApplicationThread implementation, is called from IActivityTaskManager implementation. I think, that you noticed in code snippet “Methods startActivityForResult() in Activity.java”, that the previous actions are executed inside if block. The section else leads to invocation of ActivityTaskManagerService method too.
Not bad, really? Activity is launched with help of AIDL. “Incredible, but fact”. Of course, the main work is making by ActivityTaskManagerService, but this thing works with help of Binder, therefore it needs to use AIDL generated interface to perform IPC and RPC. Thus AIDL is more significant, than Activity, because work with Activity starts with help of it. AIDL opens the score and it is 1–0.
Bigger, than Service
Started services can be:
Bound services always have the same behavior for user side, but they can be created using three different ways (according to the goal of service):
- Extending Binder class
- Using Messenger
- Using AIDL
Well, the last one is definitely depend on AIDL and can’t exist without it. What about other options? Let’s take a look inside startService() method.
Activity extends ContextThemeWrapper, which inherits class ContextWrapper. But Context is just abstract class. Something is extending it and finally starts service. In this case debug mode helped me during search. This context implementation has pretty simple name — ContextImpl.
There are just two lines of code. The first one makes logging and no more. Now it is time to research startServiceCommon() method.
Here the known AIDL usage — ApplicationThread instance as argument of method. Well, the new class ActvityManager is now on scene. Let’s take a look at method getService().
There is the same situation as for getService() method of ActivityTaskManager. If you want to start service — use IActivityManager implementation. To be more particular — class ActivityManagerService.
Okay, now it is turn of started foreground services. The body of method startForegroundService() contains the invocation of method with the same name, that is located in ContextImpl class.
Sure, it is time to investigate the internals of method in ContextImpl.
From the first sight it looks like that there is no any difference between starting background service and starting foreground service. Except one little detail — second parameter of method startServiceCommon(), which is called requireForeground and has different values for both types of services. And this parameter will be passed to ActivityManagerService. But what about method startForeground()?
ActivityManagerService works again. That’s it. Started services are launched with help of AIDL.
Let’s check, what secret weapon the bound services have against the statement in the beginning. Well, method bindService() invokes the same method from ContextImpl, no surprises for now.
Okay, the first line is an AIDL usage. Not because of “I” in the beginning of interface IServiceConnection, but its final initialization. Because it was simple binding to service, without executor, then block else will give a new value to variable sd. Let’s take a look inside class LoadedApk.
The one more variable sd, that has type ServiceDispatcher, is created with help of following constructor.
As you can see, it is nested class inside another one nested class. And this Stub class object will be returned from method getIServiceConnection(), thus sd inside bindServiceCommon() will be created with help of AIDL. Sure, it is not the only one action of connection, because the original connection instance is created at calling side (ServiceConnection instance in Activity or somewhere else). But the fact, that AIDL usage is necessary more, than one time (don’t forget about ApplicationThread) during interacting with bound service, is quite interesting and important.
Next, you can see something familiar, the retrieving instance of IActivityManager. Sure, it is ActivityManagerService again and it binds to service with help of method bindIsolatedService(). After that necessary operations are performing to create service instance in ServiceConnection callback onServiceConnected() (this callback is invoked by ServiceDispatcher too).
It was about work with local bound service (when IBinder instance is casting to class of local service). Now it is time to investigate creating instance of service, using Messenger. According to documentation, to start using this “sub-type” of bound service, it is necessary to create Messenger instance through constructor, that getting IBinder instance.
It is AIDL usage again! To start work with two of three bound services “sub-types”, the AIDL is necessary. Please note name of last code snippet, it has word “second”. Let’s take a look at the first one and how it is using.
It is not for usage by applications developers, but nice to know, that Messenger instance is based on AIDL.
Well, the interactions with services in application are starting with AIDL. 2–0.
Bigger, than Broadcast Receiver
I think, that you guessed, that sending of Broadcast is performing by old sequence. From Activity to ContextWrapper, then to ContextImpl and finally to method of ActivityManagerService, that is called broadcastIntent().
All right, what about receiving data by BroadcastReceiver instance?
Before to call method onReceive(), next process is happening: ApplicationThread instance gets call of its scheduleReceiver(). As it was mentioned before, the ApplicationThread extends IApplicationThread.Stub. Therefore IPC is performed for getting result by receiver. Next, Handler instance, that located in ActivityThread, is sending result to himself, using its own special key RECEIVER for message. It leads to invocation of private method of ActivityThread — handleReceiver(). There necessary instance of BroadcastReceiver is instantiating by special factory. Finally, method onReceive() is called and gets the data. All of this can be expressed as next scheme.
Sure, the most of work is performed by ActivityThread, but the receiving is beginning in ApplicationThread. Thus, BroadcastReceiver can get messages with help of AIDL, which is also necessary to send these messages. AIDL scores again. 3–0.
ContentProvider, everything depends on you now.
Bigger, than Content Provider?
The “?” is not there by chance. But first things first. Content providers are using for getting data from another application. It is their nature to be used through the IPC. But is AIDL necessary for interaction with it? Let’s imagine that application needs access to contacts.
All right, all right, everybody knows the end of this story, but… surprise is coming.
Well, no any AIDL usage for now. It is strange. Let’s see, how this ContentResolver instance is created.
ContentResolver, that is finally can be used by client side, is an ApplicationContentResolver instance actually. There is no any AIDL. Now it is time to research method query() of ContentResolver. It will finally lead to the overridden method of the ApplicationContentResolver, that called acquireUnstableProvider().
AIDL usage detected. Score is 4–0.
But ContentProvider has some power to perform a counterattack. Please note the mentioned ContentProviderProxy, that will be provided in method query() of ContentResolver. It is not a generated class. It is single class in file ContentProviderNative.java. As you can see, both of those classes are implementing interface IContentProvider.
But it is not an AIDL artificial code! There are no Stub routines. Interface, server-side class (ContentProviderNative) and proxy class are hand-made and Binder and Parcel are used by non-generated way. Even IContentProvider.aidl does not exist.
Okay, ContentProviderNative and ContentProviderProxy are using AIDL generated classes inside, but I think, that this is not bad answer to previous “massive” usage. The AIDL is necessary to start interaction with ContentProvider, but ContentProvider is performing most of IPC by its own. The final score is 4–1.
The explanation of joke
Everybody could see that AIDL is very important, because it is impossible to use four main Android application components without it. But it does not mean that many people underestimated the AIDL and application components are useless without it. I think this is pretty funny conclusion.
The real goal of article was to show, that AIDL is quite significant part of Android system. But system can live without it and nothing changes. Why so? Because the IPC is implemented with help of another powerful component — Binder (see previous article and useful links there). AIDL has nothing to do with this.
AIDL is not for system, it is for the developers, for implementing second important concept — Remote Procedure Call (RPC, read first article for details). It is quite convenient and really solves problems that it was created for. Yes, everything, that is using AIDL, can be changed in the way as usage of ContentProvider, what was considered earlier. But Android system developers don’t hurry to make this.
“Stub routines”, it is not difficult, but they make code quite bigger. AIDL hides all these not very important details of performing IPC and allow to developers to concentrate on their job. Also AIDL guarantees, that all necessary code will be generated in right way and without errors, otherwise, it wouldn’t be so popular in system.
I suppose it means that Android RPC approach implementation does its job quite well. And these “users” (beside the classes, mentioned in this article) can agree with me:
- and much more…
Honestly, this material is not about AIDL itself, but about its usage in Android. As you could see, AIDL has special role in work of four main application components. A lot of specific system elements use it to perform their functions. As a result, AIDL is not only for Android applications, it also helps to entire system.
It was another one big article with a lot of code and it is not easy to understand everything from first time. I think that it can give more knowledge about Activity, Service, Broadcast Receiver and Content Provider and about some things in Android system. AIDL is using to start working with these components and help to perform some of their functions. Hope, that it was useful and interesting for you.
Thank for you time and interest. Stay well and have a good mood.
See you again.
Thanks to my brother, who reviewed this article first and helped me to create it.