This article was reprinted from: 70082302
An overview of inter-process communication mechanisms in Android-binder
Recently in the study of binder mechanism, on-line access to a large number of information, but also see Lao Luo's binder series of blogs and innost in-depth understanding of the binder series of blogs, all from the bottom of the story, all C code, although learned C and C + +, but the various functions of the fancy jump, I have doubts about life. It's not an exaggeration to say that every time you look at it, it's a new thing. Later saw Gityuan's blog saw some illustrations as if the new continent was discovered.
The following is a schematic introduction of the binder mechanism, I believe you read this article, there must be some gains.
What is Binder?
Binder is a way of interprocess communication (IPC) in an Android system and is one of the most important features of the Android system. The four components of Android Activity,service,broadcast,contentprovider, different apps and so on are all running in different processes, which are the bridges between these processes. Just as its name is "adhesives", it binds the components of the system together and is the bridge of the various components.
Understanding Binder plays a very important role in understanding the entire Android system, and if you don't know about it, it's hard to get a deeper understanding of the Android system mechanism.
1. Binder Architecture
- Binder Communication uses the C/S architecture, which, from a component perspective, includes Client, Server, ServiceManager, and Binder drivers, where ServiceManager is used to manage the various services in the system.
- Binders are encapsulated at the framework layer, invoking the binder architecture of the Native (c/C + +) layer through JNI technology.
- Binder drives the communication with the binder in the Native layer in the form of an IOCTL.
2. Binder mechanism
First need to register the service side, only registered the server, the client has the goal of communication, the server through the ServiceManager registration service, the process of registration is to Binder-driven global linked list Binder_procs Insert server information (Binder_proc structure, each BINDER_PROC structure has a todo queue), and then caches the registered service to the ServiceManager svcinfo list.
With the service side, the client can communicate with the server, before the communication needs to get to the service, get the service agent, can also be understood as a reference. For example, the following code:
//获取WindowManager服务引用WindowManager wm = (WindowManager)getSystemService(getApplication().WINDOW_SERVICE);
The way to get to the server is through ServiceManager to the Svcinfo list of agents to return to the server, Svcinfo list is all registered Services address Book, save all registered service information.
With the service side reference we can send the request to the server, through the Binderproxy request parameters sent to ServiceManager, through the way of shared memory using kernel method Copy_from_user () to copy our parameters to the kernel space, At this point our client enters a wait state, and then the Binder driver inserts a transaction into the TODO queue on the server, then executes the result of the Copy_to_user () and copies the results of the kernel to the user space (it just executes the copy command and does not copy the data. Binder only makes one copy), wakes up the waiting client and responds back to the result, thus completing a communication.
How is not very simple, the above is the Binder mechanism of the main mode of communication, the following we look at the specific implementation.
3. Binder Driver
Let's start by understanding how user space interacts with kernel space.
Learn some concepts first
User space/Kernel space
A detailed explanation can refer to the Kernel Space Definition, as follows:
Kernel space is the runtime of the Linux kernel, and user space is the runtime of the program. For security, they are isolated, and the kernel is unaffected even if the user's program crashes.
Kernel space can execute arbitrary commands and invoke all the resources of the system; User space can only perform simple operations, cannot invoke system resources directly, and must pass the system interface (also called system call) to issue instructions to the kernel.
System call/kernel state/user state
Although the logical extraction of user space and kernel space, but inevitably, there are always some user space to access the kernel resources, such as application access to files, the network is a very common thing, how to do?
Kernel space can be accessed by user processes only through the use of system calls.
The only way for the user to access the kernel space is the system call, through this unified portal interface, all the resource access is executed under the control of the kernel, so as to avoid the unauthorized access to the system resources by the user program, thus guaranteeing the security and stability of the system. User software is mixed, if they mess up the system to play bad how to do? Therefore, some privileged operations must be delivered to a secure and reliable kernel.
When a task (process) executes a system call and is executed in kernel code, we say that the process is in the kernel runtime (or simply the kernel state) at which time the processor is in the highest privileged (level 0) kernel code. When the process executes the user's own code, it is said to be in the user's running state (user state). That is, the processor is running in the least privileged (level 3) user code. The processor can execute those privileged CPU commands when the privilege level is high.
Kernel modules/Drivers
With system calls, user space can access kernel space, so what if one user space wants to communicate with another user space? It's natural to think of adding support to the OS kernel; traditional Linux communication mechanisms such as sockets, pipelines, etc. are supported by the kernel, but Binder is not part of the Linux kernel, how does it access kernel space? Linux's dynamic loadable kernel module (Loadable Kernel module,lkm) solves this problem, and the module is a standalone program that can be compiled separately but not run independently. It is linked to the kernel at run time as part of the kernel running in kernel space. In this way, the Android system can be completed by adding a kernel module running in the kernel space, the user process through this module as a bridge, you can complete the communication.
In the Android system, this kernel module, which runs in kernel space, is responsible for each user process through binder communication, called Binder driver;
Drivers generally refer to device drivers (Devices Driver), which are special programs that enable computers and devices to communicate. Equivalent to the hardware interface, the operating system only through this interface, to control the work of hardware equipment;
The driver is the interface of the operating hardware, in order to support binder communication process, Binder uses a "hardware", so this module is called the driver.
Familiar with the above concepts, let's take a look at the above diagram, in User space Binder_open (), Binder_mmap (), Binder_ioctl () These methods invoke the kernel space Binder driver method through system call. Kernel space and user space shared memory through the Copy_from_user (), Copy_to_user () kernel method to complete the data transfer between user space and kernel space memory. The binder driver has a global binder_procs linked list that preserves process information on the server side.
4. Binder Processes and Threads
For the underlying binder driver, all created Binder_proc structures are recorded through the Binder_procs linked list, and each BINDER_PROC structure of the binder drive layer corresponds to a process one by one for binder communication in the user space. And each process has only one Processstate object, which is guaranteed by a singleton pattern. In each process can have many threads, each thread corresponds to a Ipcthreadstate object, Ipcthreadstate object is also a singleton mode, that is, a thread corresponding to a Ipcthreadstate object, in the Binder drive layer also has a corresponding structure, That's the binder_thread structure. All binder_thread in the current process are recorded in the Binder_proc struct through the member variable Rb_root threads.
Binder thread Pool: Each server process creates a binder thread pool at startup and registers a binder threads with it, and the server process can also register a new thread with the binder thread pool, or the binder driver detects that there is no idle Binde The R thread is actively registering a new binder thread with the Server process. There is a maximum binder thread limit for a Server process, which defaults to 16 binder threads, such as Android's system_server process, which has 16 threads. Binder requests for all client-side processes are handled by the binder thread of the Server-side process.
5. ServiceManager Start
Understand the binder driver, how to communicate with the binder driver? That is through ServiceManager, a lot of articles called ServiceManager is Binder-driven daemon, big housekeeper, in fact, the role of ServiceManager is very simple is to provide the function of query services and registration services. Let's take a look at the ServiceManager startup process.
-ServiceManager is divided into the framework layer and the native layer, the framework layer is only the native layer is packaged for easy invocation, the diagram shows the native layer of the ServiceManager boot process.
The boot of ServiceManager is initiated by the INIT process parsing init.rc file called the main () method entry in SERVICE_MANAGER.C when the system is booting. The native layer has a binder.c that encapsulates some method of interacting with the binder driver.
The start of ServiceManager is divided into three steps, first open the driver to create the global list Binder_procs, and then save your current process information to the Binder_procs linked list, and finally turn on the loop constantly processing the data in shared memory, and processing br_xxx Command (IOCTL command, BR can be understood as binder reply driver processing the response).
6. ServiceManager Registration Service
To register the Mediaplayerservice server, we register the service through the ServiceManager AddService () method.
First, ServiceManager sends the bc_transaction command to the binder driver (the IOCTL command, which the BC can understand as a request command sent by the Binder client clients) to carry the add_service_transaction. command, while the thread registering the service enters the wait state waitforresponse (). The Binder driver receives a request command to add a registered service transaction to the ServiceManager todo queue. The task of a transaction is to create a server-side process Binder_node information and insert it into the Binder_procs linked list.
After the transaction is processed, the br_transaction command is sent, and the ServiceManager receives the command and adds the registered service to the Svcinfo list. The last send Br_reply command wakes up the waiting thread, notifying the registration success.
7. ServiceManager Access Service
The process of getting a service is similar to registering, the opposite process. Register the service through the ServiceManager GetService () method.
First ServiceManager sends the bc_transaction command to the Binder driver to carry the check_service_transaction command, while the thread that gets the service enters the wait state waitforresponse ().
The Binder driver receives the request command to the ServiceManager send bc_transaction query the registered service, querying to the thread that directly responds to the br_reply wakeup wait. If the query is not available, it will respond once to the service in the Binder_procs linked list.
8. Make a full communication
When we use Binder, we basically call the framework layer encapsulation method, AIDL is the framework layer provides a fool is the way to use. Assuming the service is already registered, let's look at how the client executes the service-side approach.
First we get the Binderproxy proxy object to the server through ServiceManager, by calling Binderproxy to pass the parameter, the method ID (for example: automatically generated in transaction_test,aidl) to ServiceManager, while the client thread enters the wait state.
ServiceManager copies request data such as user-space parameters to the kernel space and inserts a transaction that executes the execution method to the server. The transaction finishes the notification ServiceManager copies the execution result from the kernel space to the user space, wakes up the waiting thread, responds to the result, and ends the communication.
Summarize
Well, here's just a logical introduction to the work of the next binder mechanism, want to deeply understand the binder mechanism, but also have to work hard to see the source, although the process is very painful. Once again do not understand to come again, to tell the truth I understand the ability is poor, followed the blog thought to see not more than 10 times. Efforts will always have a harvest, enjoy the native layer of the various methods of the charm of the jump. In the end you will find the door of the new World open to you.
A lot of online information, personal feel better than the following:
1. Bander Design and implementation
2. Lao Luo's Android interprocess communication (IPC) Mechanism Binder Brief introduction and Learning Plan series
3. Innost's in-depth understanding Binder Series
4. Gityuan Binder Series (Android 6.0 based)
5. Binder Learning Guide
Resources
- Binder Series
- Binder Learning Guide
More articles:
Https://github.com/jeanboydev/Android-ReadTheFuckingSourceCode
Welcome long Press-----QR code in the identification chart
or sweep your attention to my public number.
An article about Brief Encounter's Android Binder interprocess communication mechanism "turn"