preface
Binder as the core mechanism of Android, Binder is essential for understanding Android system. There are many articles about Binder, but every time I read it, I always feel confused about what Binder mechanism is. Why use binder mechanisms? How does the Binder mechanism work? It is not enough to understand the binder mechanism, but to analyze it from the perspective of the overall system of Android. After I found a lot of materials, I really understood the binder mechanism, and I believe that you can understand the binder mechanism after reading this article.
What is Binder?
To understand Binder, you need to know IPC, inter-Process Communication, which is a framework for interprocess communication provided by Android. Used to send messages between multiple processes, synchronize and share memory. The existing interprocess communication modes are as follows:
Binder frame diagram of Android system is as follows:
Key points:
Binder is an interprocess communication framework provided by Android.
2, the system service ActivityManagerService, LocationManagerService, are in a separate process, such as use of binder and applications to communicate.
2. Android system framework
1. Android application layer and system service layer are not in the same process, and system service is in a separate process.
2. Different applications in Android belong to different processes.
Android applications and system services run in different processes for security, stability, and memory management reasons, but applications and system services need to communicate and share data.
advantages
Security: Each process runs separately to ensure isolation of the application layer from the system layer.
Stability: If one process crashes it will not cause other processes to crash.
Memory allocation: If a process is no longer needed, it can be removed from memory and reclaimed.
3, Binder communication
Client requests a service. For example, an Activity requests an ActivityManagerService. Since the Activity and ActivityManagerService are in two different processes, this is a straightforward request process.
But be careful
struct binder_write_read {
signed long write_size;/* bytes to write */
signed long write_consumed; /* bytes consumed by driver */
unsigned long write_buffer;
signed long read_size; /* bytes to read */
signed long read_consumed; /* bytes consumed by driver */
unsigned long read_buffer;
};
Copy the code
However, there is still a problem that client and service need to communicate with binder driver directly, but actually client and service do not want to know the relevant protocol of binder, so client adds proxy proxy. The Service further handles its interaction with the binder by adding stubs.
Furthermore, how does the client actually get which service? As shown below:
$ adb shell service list
Found 71 services: 0 sip:
[android.net.sip.ISipService] 1Phone: [com. Android. Internal. Telephony. ITelephony]...20Location: [android. Location. ILocationManager]...55 activity: [android.app.IActivityManager]
56 package: [android content. PM. IPackageManager]...67 SurfaceFlinger: [android.ui.ISurfaceComposer]
68 media.camera: [android.hardware.ICameraService]
69 media.player: [android.media.IMediaPlayerService]
70 media.audio_flinger: [android.media.IAudioFlinger]
Copy the code
Here is a more complete communication flow between client and service:
4. Binder frame
Before looking at the Binder framework, let’s look at the complete process of requesting a service from a client.
Service acquisition process:
The first step: When a client requests a service, such as calling context.getSystemService() in an activity, the serviceManager uses getService (name), The getService(name) method in the ServiceManagerNative class in the Native layer is then called.
The second step: ServiceManagerNative sends a SVG_MGR_GET_SERVICE command through its Binder, We then call do_find_service () via svcmgr_handler() to find the service in svc_list.
Step 3: After finding the corresponding service, the Binder will send the service to ServiceManagerNative, and then to serviceManager, and finally the client can use it.
Note: The service is stored in Svclist, which is a linked list, so the service invoked by the client must be registered with Svclist first.
Registration process:
Step 1: The Service calls the addService method in the serviceManager, and then the addService (name) method in the ServiceManagerNative class.
The second step: ServiceManagerNative sends an SVG_MGR_ADD_SERVICE instruction through Binder, and then adds the corresponding service to svc_list by calling do_add_service () via svcmgr_handler().
Important: All services must be registered in svc_list before they can be invoked by clients. Svc_list stores these services as linkedList.
Android is divided into application layer, framework layer, native layer and kernel layer. Binder design has different abstractions on each layer. The diagram below:
1. Java layer AIDL.
2. Framework layer, Android.os.binder.
The most important data structure in the framework layer is Transaction, which has the following defaults:
3. Native layer: libbinder.cpp
In the native layer, it’s mainly libBinder
4. Kernel layer
5. Design patterns used in Binder
In Android, client does not interact with binder directly. Client interacts directly with Manager, which interacts with managerProxy. That is, clients interact with binder through managerProxy. Services also interact with Binder not directly, but through stubs. The diagram below.
6. Binder and memory mapping MMAP
Binder IPC is implemented based on memory mapping (Mmap), but Mmap () is typically used on file systems with physical media.
For example, the user area in the process cannot directly interact with the physical device. If you want to read the data from the disk into the user area of the process, you need to copy it twice (disk -> kernel space -> user space). This is often the case where mmap() comes into play, reducing the number of data copies by mapping between the physical media and user space, replacing I/O reads with in-memory reads, and increasing file read efficiency.
Binder does not have physical media, so Binder drivers use mmap() not to map between physical media and user space, but to create a cache space for data reception in kernel space.
A complete Binder IPC communication process usually looks like this:
First, the Binder driver creates a data receive cache in kernel space. Then, a kernel cache is created in the kernel space, and the mapping relationship between the kernel cache and the kernel data receiving cache, as well as the mapping relationship between the kernel data receiving cache and the user space address of the receiving process is established. The sender process uses the system call copyfromuser() to copy the data to the kernel cache in the kernel. Since there is memory mapping between the kernel cache and the user space of the receiving process, the data is sent to the user space of the receiving process, thus completing an inter-process communication. The diagram below:
reference
1, rts.lab.asu.edu/web_438/pro…
2, rts.lab.asu.edu/web_438/pro…