AIDL stands for Android Interface Definition Language, which is the Android Interface Language for interprocess communication. As the kernel of The Android system is Linux, it adopts the process isolation mechanism, so that different applications run in different processes. Sometimes two applications need to transfer or share some data, so they need to carry out inter-process communication.
There are many ways to communicate between Android processes, such as Messenger, SharePreference, AIDL, Socket, and Content Provider. Messenge, AIDL, and Content Provider all rely on Binder mechanisms to implement their underlying components. In addition, the core process of the startup and communication of the four Android components is also realized by Binder mechanism. Here, we use AIDL to understand the implementation mechanism of Binder.
Before getting to know the mechanics and usage of AIDL, it is important to understand a few concepts that will help further understanding.
Process isolation
The following is from Wikipedia:
Process isolation is a set of different hardware and software techniques designed to protect processes in an operating system from interfering with each other. This technique is used to prevent process A from writing to process B. Process isolation implementation, using virtual address space. The virtual address of process A is different from that of process B. This prevents process A from writing data to process B.
Linux principle of IPC
Linux uses virtual address Space technology. The operating system logically divides virtual memory into User Space and Kernel Space. Common applications run in User Space and system Kernel runs in Kernel Space. User space can only be accessed through system calls to kernel space. When a process executes a system call and gets stuck in kernel code, it enters kernel mode, as opposed to user mode when it executes its own code in user space.
Since process A and process B have different virtual addresses, they are transparent to each other and assume that they have exclusive access to system resources. Of course, they cannot directly interact with each other. However, in some cases, some processes inevitably need to interact with other processes. This interaction Process is called INTER-process Communication (IPC). The essence of IPC is data interaction, so we call the caller and the called caller in the IPC process respectively as the data sender and the data receiver. The process of IPC communication is as follows:
- The data sender process puts the data in an in-memory cache and drops it into kernel mode through system calls
- The kernel program creates a kernel cache in the kernel space and copies data from the memory cache of the data sender user space to the kernel cache in the kernel space through the copy_from_user function
- The data receiver process creates an in-memory cache in its own user space
- The kernel uses copy_to_user to copy data from the kernel cache to the memory cache of the data receiver process
Through the above process, one IPC is completed, but there are two problems with this traditional IPC mechanism:
- Low performance: the whole process of data transfer needs to go through the sender memory cache – kernel cache – receiver memory cache process
- The recipient process does not know in advance how much memory it needs to allocate for the data, so it needs to allocate as much space as possible or call the API beforehand to solve the problem, which is either a waste of space or time.
Principle of Binder IPC
To overcome the shortcomings of Linux’s traditional IPC mechanism, Android introduced the Binder mechanism, which literally means glue, to act as a bridge between different processes and enable them to communicate with each other. Binder is not part of the Linux Kernel, but it benefits from Linux’s LKM(Loadable Kernel Module) mechanism:
A module is a self-contained program that can be compiled separately but cannot be run independently. It is linked to the kernel at runtime and runs in kernel space as part of the kernel
Therefore, binders exist as such modules in the kernel, also known as Binder drivers. To recall from the previous section, the traditional Linux IPC process requires two copies of data. Binder uses another Feature of Linux to implement IPC with only one copy of data: memory mapping:
The memory mapping involved in the Binder IPC mechanism is implemented through Mmap (), a method of memory mapping in operating systems. In simple terms, memory mapping is to map a memory region of user space to kernel space. After the mapping relationship is established, users’ modification of this memory region can directly reflect the kernel space. Conversely, changes made to this area in kernel space can be directly reflected in user space.
Memory mapping can reduce the number of data copies and realize efficient interaction between user space and kernel space. The modification of the two Spaces can be directly reflected in the mapped memory area, thus being timely sensed by the other space. Because of this, memory mapping can provide support for interprocess communication.
Binder IPC communication process is as follows:
- Binder drivers create a data receive cache in kernel space
- Then a memory cache is created in the kernel space and the mapping relationship is established with the data receiving cache. At the same time, the mapping relationship between the data receiving cache and the data receiver’s memory cache is established
- The data sender copies the data from the memory cache to the kernel cache through the system call copy_from_user function. Since the kernel cache has an indirect mapping relationship with the memory cache of the data receiver through the data receiving cache, it is equivalent to directly copying the data to the user space of the receiver. This completes an IPC process.
Binder communication model and process
Binder IPC is more complex than described above. The Binder communication model is based on C/S architecture. The calling process is called Client process and the called process is called Server process. In addition, ServiceManager and Binder drivers are required to implement the IPC process through system calls such as open/mmap/ iOTL to the device file dev/ Binder.
Client, Server, and ServiceManager run in user space, Binder drivers run in kernel space, and Client and Server are implemented by users themselves. The ServiceManager and Binder drivers are provided by the system.
Android Binder design and implementation article has detailed description of Client and Server roles:
Binder drivers: Binder drivers, like routers, are at the heart of communication. The driver is responsible for the establishment of communication between Binder processes, Binder transfer between processes, Binder reference count management, packet transfer and interaction between processes and a series of low-level support.
ServiceManager and Real-name Binder: A ServiceManager is similar to a DNS server. It translates a Binder name into a Client reference to a Binder. Then a Client can obtain a reference to a Binder entity using a Binder name. Binders are real names, just like websites except that they have an IP address and a web address. Server creates a Binder, gives it a character form, a readable and memorable name, and sends the Binder entity with the name to the ServiceManager as a packet through the Binder driver. Tell the ServiceManager to register a Binder named “John” that resides in a Server. The driver creates entity nodes in the kernel and references to the entity by the ServiceManager for the Binder that crosses process boundaries, packaging the name and the new reference to the ServiceManager. The ServiceManger receives the data and retrieves the name and reference from it to fill the lookup table.
Careful readers will notice that Server Manager is one process and Server is another, and that Server registering Binder with ServiceManager necessarily involves interprocess communication. The current implementation of interprocess communication needs interprocess communication, which is just like the egg hatching chicken is the prerequisite to find a chicken to lay eggs! Binder’s implementation is clever: it creates a chicken to lay eggs in advance. ServiceManager and other processes also use Bidner to communicate. ServiceManager is a Server with its own Binder entities, while other processes are clients. This Binder reference is required to register, query, and retrieve Binder. ServiceManager provides a special Binder that has no name and does not require registration. Binder drivers automatically create Binder entities for a process when it registers itself as a ServiceManager using the BINDERSETCONTEXT_MGR command (this is the pre-built chicken). Second, references to the Binder entity are fixed to 0 in all clients without needing to be retrieved by other means. That is, a Server that wants to register its Binder with a ServiceManager must communicate with the ServiceManager’s Binder through the 0 reference. Like the Internet, reference zero is like a DNS address that you have to pre-configure dynamically or manually. Note that Client refers to a ServiceManager. A process or application may be a Server that provides services, but it is still a Client to a ServiceManager.
Client gets references to real name Binder: After Server registers with ServiceManager, Client gets references to real name Binder. The Client also requests access to a Binder reference from the ServiceManager using the reserved reference no. 0: I request access to a Binder reference named John. When the ServiceManager receives the request, the Binder name is retrieved from the request packet, the corresponding entry is found in the lookup table, and the Binder reference is retrieved as a reply sent to the Client that initiated the request. From an object-oriented perspective, Binder entities in The Server now have two references: one in the ServiceManager and one in the Client that initiates the request. If more clients subsequently request the Binder, there will be more references to the Binder in the system, just as there are multiple references to an object in Java.
Therefore, ServiceManager is the core of the Binder IPC communication process and the manager of the context. Binder servers must register with ServerManager before they can provide services to clients. Binder clients need to look up and get references to Binder servers from ServerManager before communicating with servers. The Binder IPC process can be summarized as the following steps:
- A process registers itself as a ServiceManager using BINDER_SET_CONTEXT_MGR through a Binder driver to manage all services
- Each Server registers a Binder entity with ServiceManager through Binder drivers, indicating that it can provide services externally. The Binder driver creates a kernel entity node for the Binder and a ServiceManager reference to the node, and packages the name and reference to the ServiceManager. The ServiceManager receives the packets and fills the names and references in the packets into the lookup table
- With the help of the Binder driver, the Client obtains the reference object corresponding to the Server from the ServiceManager using the Server name. So the Client can interact with the real Server through this reference
Again, teacher Universus:
conclusion
Process isolation improves the security of the operating system and the stability of applications, but it also makes it difficult for IPC. Android has clever Binder mechanisms that enable the system to run smoothly on mobile devices with limited storage space and hardware performance. For more information on Binder usage and analysis at the application layer, see the next article: Understanding Android Binder with AIDL: AIDL usage and Analysis
Refer to the article
Binder principle analysis for Android application engineers
Binder Learning Guide
If you have any questions or different opinions about the content of this article, please leave a comment and we will discuss it together.