If a process intends to receive incoming Binder transactions, it must maintain a pool of threads specifically dedicated to interacting with the Binder kernel driver.
Binder Thread Pool Per Process
In Android, every process that uses Binder (which is almost all of them) has a Binder thread pool. These threads spend their lives in a tight loop: invoking ioctl(BINDER_WRITE_READ), blocking until the kernel driver wakes them up with a BR_TRANSACTION, executing the requested Java or C++ method, and then returning a reply.
You can easily identify these threads in a crash dump or trace; their names usually start with Binder: followed by the process ID (e.g., Binder:1042_1).
ProcessState and IPCThreadState
The native library libbinder manages the thread pool using two singleton classes per process:
ProcessState: This is a true singleton for the entire process. It is responsible for opening/dev/binder, callingmmap()to set up the shared memory region, and defining the maximum number of threads the pool can hold.IPCThreadState: This is a thread-local singleton. Every thread in the Binder pool has its ownIPCThreadStateinstance. This class handles the actual formatting ofbinder_transaction_datastructs and making theioctlcalls to talk to the kernel.
Max Thread Count and Thread Spawning
By default, an Android application process is configured to have a maximum of 15 Binder threads (DEFAULT_MAX_BINDER_THREADS). The system_server, handling thousands of IPCs a second, configures its pool to have 31 threads.
The thread pool is managed dynamically by the kernel driver.
- When a process starts, it registers a main Binder thread.
- If the kernel needs to deliver a transaction but sees that all current threads in the pool are busy processing other requests, it will send a
BR_SPAWN_LOOPERcommand to the process. - Upon receiving this,
IPCThreadStatewill spawn a new native thread, which immediately registers itself with the driver. - This continues until the process hits its maximum thread limit. If all threads are busy and the limit is reached, incoming transactions queue up in the driver until a thread becomes free.
Main Thread vs Binder Threads
It is a critical architectural rule in Android that Binder transactions are never executed on the UI Main Thread.
When an app receives a Binder call (for instance, a remote service invoking a callback), the execution happens on one of the background Binder:X_Y threads. If the callback needs to update the UI, the developer must explicitly use a Handler or Activity.runOnUiThread() to post the work over to the application's main Looper thread. Failing to do so will result in a CalledFromWrongThreadException.