[ English | 简体中文 ]
Binder Inter-Process Communication (IPC) Development Guide
Binder is an efficient inter-process communication (IPC) transport mechanism that enables data exchange and remote method invocation between different processes.
1. Core Architecture
The Binder mechanism consists of the following four core components:
- Binder Driver: Resides in kernel space and handles the low-level details of inter-process communication, including packet transmission and thread management.
- ServiceManager: A special daemon process that acts as a context manager, responsible for registering and looking up Binder services.
- Binder Server: Implements specific service functionality and responds to requests from other processes via the Binder mechanism.
- Binder Client: The process that uses services, sending requests to the server and receiving responses via the Binder mechanism.
2. System Configuration and Startup
2.1 Kconfig Configuration
Before using Binder, ensure the following basic configurations are enabled:
CONFIG_DRIVERS_BINDER # Kernel driver switch
CONFIG_ANDROID_BINDER # Binder library switch
CONFIG_ANDROID_SERVICEMANAGER # Binder daemon
CONFIG_BINDER_EXAMPLES # Binder examples switch
If using libuv for event loop polling, enable the following after enabling CONFIG_BINDER_EXAMPLES:
CONFIG_LIBUV # Enable libuv support
2.2 Runtime Startup
Before performing Binder communication, the ServiceManager daemon must be started first:
nsh> servicemanager &
3. How It Works
The Binder communication flow is as follows:
- Developers define communication interfaces through AIDL files.
- The server implements the interface and registers the service with ServiceManager.
- The client queries ServiceManager for a specific service name and obtains a reference to the server's Binder object.
- The client calls predefined interface methods. The proxy code generated by AIDL and the Binder library serialize the parameters and write the request to the kernel driver.
- The Binder driver forwards the client request to the server.
- The server receives the request, performs the specific operation, and returns the result back to the client via the same path.
4. Interface Definition (AIDL)
AIDL (Android Interface Definition Language) is used to define inter-process communication interfaces, simplifying cross-process method invocation.
4.1 Interface Definition Example
Create a simple AIDL interface file:
interface ITestStuff {
void write(int sample);
void read(int idx);
}
4.2 Code Generation
The AIDL tool generates the following C++ files based on the above definition, containing the client proxy class (Bp) and server stub class (Bn):
BnTestStuff.hBpTestStuff.hITestStuff.hITestStuff.cpp
5. Implementation Patterns
Depending on the application scenario, there are three main implementation patterns for Binder servers.
Pattern 1: Binder Thread Pool (Standard Pattern)
This pattern is suitable for standard blocking service calls.
1. Server Implementation
-
Create service instance: Inherit from the AIDL-generated
Bnclass and implement the interface.sp<ITestServer> testServer = new ITestServer; -
Define interface methods:
Status read(int32_t sample) { /* implementation logic */ } Status write(int32_t index) { /* implementation logic */ } -
Register service:
sp<IServiceManager> sm(defaultServiceManager()); sm->addService(String16("aidldemo.service"), testServer); -
Start thread pool: Add the current thread to the Binder thread pool to process requests.
ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool();
2. Client Implementation
-
Get service:
sp<IServiceManager> sm(defaultServiceManager()); sp<IBinder> binder = sm->getService(String16("aidldemo.service")); -
Cast to proxy interface:
sp<ITestStuff> service = interface_cast<ITestStuff>(binder); -
Call interface:
service->write(123); service->read(456);
Pattern 2: Libuv Main Loop (Asynchronous Event-Driven)
This pattern is suitable for applications that need to integrate with the libuv event loop.
1. Server Implementation
-
Create and register service:
sp<ILibuvServer> testServer = new ILibuvServer; // ... implement interface and register with ServiceManager (same as Pattern 1) ... -
Configure Binder polling: Obtain the file descriptor (FD) of the Binder driver.
IPCThreadState::self()->setupPolling(&fd); -
Initialize libuv handle:
uv_poll_init(uv_default_loop(), &binder_handle, fd); -
Start listening: Trigger the callback
uv_binder_cbwhen the FD is readable to process the message queue.uv_poll_start(&binder_handle, UV_READABLE, uv_binder_cb); -
Run event loop:
uv_run(uv_default_loop(), UV_RUN_DEFAULT); -
Release resources:
uv_close((uv_handle_t*)&binder_handle, NULL); IPCThreadState::self()->stopProcess();
2. Client Implementation
Refer to Pattern 1.
Pattern 3: Epoll Main Loop (Native Linux Event-Driven)
This pattern is suitable for applications that use the native epoll mechanism for event management.
1. Server Implementation
-
Create and register service:
// Refer to Pattern 1 to create Bn class instance and register -
Create epoll instance:
int epoll_fd = epoll_create1(EPOLL_CLOEXEC); -
Configure Binder polling:
int fd; IPCThreadState::self()->setupPolling(&fd); -
Register epoll event:
struct epoll_event ev; ev.events = EPOLLIN; epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev); -
Event loop processing:
while (1) { struct epoll_event events[1]; int numEvents = epoll_wait(epoll_fd, events, 1, -1); if (numEvents < 0) { if (errno == EINTR) { continue; } break; } if (numEvents > 0 && (events[0].events & EPOLLIN)) { ALOGI("process binder transaction"); // Process commands and flush buffer IPCThreadState::self()->handlePolledCommands(); IPCThreadState::self()->flushCommands(); // flush BC_FREE_BUFFER } }
2. Client Implementation
Refer to Pattern 1.