Linux memory space with Binder Driver

Android is based on the Linux operating system, so you need to understand the Linux kernel first. Android processes, like Linux processes, run in the process’s own virtual address space. A 4GB virtual address space, 3GB for user space, and 1GB for kernel space.

How can a process with a separate space pass data to another process? Obviously through kernel space shared by both processes. From the perspective of the kernel, a process is just a job unit. Although the user space of each process is relatively independent, the task data and code running in the kernel space are shared with each other.Linux itself provides IPC facilities for two processes to communicate through the kernel. Binder in Android is much more functional, not only for IPC communication, but also for calling another process’s functions to support RPC operations between processes.IPC :(Inter Process Communication)

RPC: (Reomote Procedure Call) Remote Procedure Call

Binder communication is divided into two processes: Client and Service. Client and Service are opposites. Whoever sends a message is a Client, and whoever receives a message is a Service

How do processes call functions remotely from one another?

The client calls foo on the Server side through IPC calls by passing Binder IPC data to the Server side. Binder drivers act as middlemen to receive IPC data from the client and pass it to the Server side. IPC data contains information about function calls:Service number, RPC data and code, Binder protocolThree parts.

  • Service number (Handle) : It is used to distinguish different services. The Driver layer uses the Handle value to determine which service to transfer IPC data to, which is the number of the target service
  • RPC data: Used to specify functions (including function names and parameters) to be called for the specified service
  • Binder protocol: Used to represent IPC data processing (BINDRE_WRITE_READ is the main protocol used to transmit IPC data)

Above is the role of various protocols in Binder

This picture shows the process of data transmission with Binder, which reflects the layered management of binder mechanism (service layer, RPC layer, IPC layer, driver layer, which will be explained later). Binder is divided into Native layer and Java layer, and each layer has its corresponding layered mechanism.

Context Manager (ServiceMananger) process and the process of registration, retrieval, and invocation

In the Android system, a special process named Context Manager (ServiceMananger) assigns a Handle number to each service and provides functions such as adding and retrieving. The Handle of Context Manager itself is 0. Binder drivers look for services based on handles in IPC data, which is the addressing process.

registered

In order to do this, the Service Server must register its Service with the Context Mananger. During the registration process, the Service Server passes IPC data to the Driver layer, which contains the RPC code (ADD_SERVICE, Add service),RPC data (the name of the registered service), and the target Handle value is 0 (i.e. the Handle of the ContextManager). The Driver layer receives the IPC data, parses the Handle=0, and finds the ContextManager. After receiving the data, the ContextManager will register the service in its service list according to the service name in the IPC data and assign the Handle number.

Binder drivers generate a binder node when a Service Server registers its services with the Context Manager. References to Binder nodes are then generated so that the ContextManager can identify the generated Binder nodes and connect them together. According to the order in which they are generated, the reference data is numbered and inserted into the Ipc data. Passed to the ContextManager, which registers the service in its own service list based on the service name and Binder node number in the IPC data.

retrieve

After registration, the service can be called by other processes, but the call process needs to be implemented by ContextManager, i.e. service retrieval process. Assuming that service A has been registered with ContextMananger, client B now wants to call A. B first transmits IPC data containing RPC code (GET_SERVICE), RPC data (requested service name) and Handle 0 to ContextManager through Binder Driver, which gets the service name after parsing. Search for the corresponding Handle number in its own service list and send the found handler number to the Binder Driver. The Binder Driver finds the reference data based on the service number that is passed and generates the reference data on client B.

call

Finally, client B saves the received reference data number into Handler, including RPC codes and RPC data related to Service functions into IPC data, and sends them to the specified Service Server, namely Service A, through BinderDriver, and calls relevant functions in A.

Binder Driver function analysis

Let’s start with a few important constructs for the Driver layer:

  • Binder_proc: Describes a process that is using a binder process communication mechanism. When a process calls the open function, the Binder driver creates a binder_proc structure for it, which is stored in a global hash list to manage various information required by binder IPC and has Pointers to other structures in binder.

  • Binder_buffer: Used to describe a kernel buffer used to pass data between processes. Each process using Binder communication mechanism has a list of kernel buffers in Binder drivers that hold the kernel buffers assigned to it by the driver

  • Binder_node: A Binder entity for each Service component in the Driver layer that describes its state in the kernel

Here are three very important functions

– 1.binder_open

Binder Drivers first call binder_open(), which is connected to the system function open(). When a process calls open(), The Binder Driver node file “dev/ Binder” is passed as an argument to the called function, and the Binder Driver file descriptor is returned to the process as a return value. This file descriptor is passed as an argument to the function when mmap() and IOCtl () are called.

The binder_open() function generates the binder_proc structure for the process that opens Driver

– 2.binder_mmap()

The process calls the binder_mmap() function to map a Buffer in kernel space to receive IPC data. Mmap () is a mapping function that maps a specific region of user space to a specific region of kernel space. When data is transferred from kernel space to user space, copy_to_user is called to copy the data into user space, and binder processes call mmap() to create binder Mmap areas mapped to user space

Binder drivers use the mmap() function to create a buffer in kernel space that receives IPC data, depending on the size specified by the user process.In other words, process A copies data from user space COPY_from_user to process B’s buffer in the kernel space. Then process B’s buffer is mapped to process B’s user space and physical memory, reducing the copying processThis is why binder performance is superior

– 3.binder_ioctl

Binder drivers control binder_ioctl() by calling the binder_ioctl() function. The Driver analyzes the ioctl commands passed along with the ioctl call. The BINDER_WRITE_READ command of the IOCtl is used to request the Binder Driver to send or receive IPC data and reply data.

The binder_ioctl function is responsible for sending and receiving IPC data and ipc reply data between two processes. Therefore, this function must involve both the sending and receiving processes.

  • (1). Process A waits to receive IPC data
  • (2). Process B passes the BINDER_WRITE_READ command and sends ipc data when calling ioctl
  • (3).B enters the wait mode and waits to receive the reply data
  • (4).A receives IPC data and sends the data to user space
  • (5).A sends reply data
  • (6).B receives the reply data and sends the data to user space

Ioctl (file descriptor, BINDER_WRITE_READ,& BWR)The first argument is the file descriptor taken when open is called, the second argument is the command, and the third argument is the structure of BINDER_WRITER_READ, as follows:

Finally, data transfer is carried out by parsing BWR data.

Note: The pictures in this article are from “Android Framework Decryption” by Kim Tae-yeon (Han). This book analyzes the overall architecture of Android from several aspects. Although the version is a little old, the overall idea of Android is unchanged, and learning this book is very beneficial.