我们知道Android系统启动之后,要想启动一个应用程序则需要保证该应用程序的进程先被启动,如果该进程不存在就会请求 Zygote 进程启动需要的应用程序进程。这样在 Zygote 的 Java 框架层(Framework源码层)中会创建一个 Server 端的 Socket,这个 Socket 用来等待 AMS 请求 Zygote 来创建新的应用程序进程(Zygote 进程通过 fork 自身创建应用程序进程),这样应用程序进程就会获得 Zygote 进程在启动时创建的虚拟机实例。与此同时,也创建出了 Binder 线程池 和 消息循环 ,这样运行在应用进程中的应用程序就可以很方便的使用 Binder 进行进程间通信以及处理消息了。
一、Binder 通信模型全景 1.1 四角色模型 Binder 框架定义了四个角色:Server 、Client 、ServiceManager 、Binder驱动 ,这其中前三个位于 用户空间 ,驱动位于 内核空间 。这四个角色的关系和互联网类似:Server 是服务器,Client 是客户终端,SMgr 是域名服务器(DNS),驱动是路由器。
┌─────────────┐ ┌─────────────┐ │ Client │ │ Server │ │ (App进程) │ │ (服务进程) │ │ │ │ │ │ BpBinder │ │ BBinder │ │ └─BpRefBase│ │ └─IBinder │ │ └─handle │ │ └─mObject│ └──────┬──────┘ └──────┬──────┘ │ │ │ ioctl(BINDER_WRITE_READ) │ ioctl(BINDER_WRITE_READ) │ │ ┌──────┴──────────────────────────────────┴──────┐ │ Binder Driver (内核) │ │ │ │ binder_proc (Client) binder_proc (Server) │ │ ├── todo 队列 ├── todo 队列 │ │ ├── threads 链表 ├── threads 链表 │ │ └── nodes 引用表 └── nodes 实体表 │ │ │ │ binder_node ←── 引用(SMgr负责查找)──→ binder_ref│ └────────────────────────────────────────────────┘ │ ┌──────┴──────┐ │ServiceManager│ (servicemanager进程, handle=0) │ binder_context │ │ ├── service列表 │ │ │ ├── "activity" → handle=X │ │ │ ├── "package" → handle=Y │ │ │ └── ... │ └──────────────┘
1.2 ServiceManager 的注册与发现 ServiceManager 是 Binder 体系中的”命名服务”。它是一个特殊的 Binder 服务,固定句柄为 handle=0。
int main () { driver = open ("/dev/binder" , O_RDWR | O_CLOEXEC); ioctl (driver, BINDER_SET_CONTEXT_MGR, 0 ); binder_loop (driver, svcmgr_handler); } int svcmgr_handler (struct binder_state *bs, struct binder_txn *txn, struct binder_io *msg, struct binder_io *reply) { switch (txn->code) { case SVC_MGR_ADD_SERVICE: s = strdup (svcmgr_lookup (txn, ...)); svc->handle = bio_get_ref (msg); svclist_push (svc); break ; case SVC_MGR_GET_SERVICE: svc = svclist_find (svc_name); bio_put_ref (reply, svc->handle); break ; case SVC_MGR_CHECK_SERVICE: break ; } }
注册流程 :
Server 进程 ServiceManager 进程 │ │ │ 1. new BBinder() │ │ 2. defaultServiceManager() │ │ -> 获取 SMgr 的 BpBinder(0) │ │ │ │ 3. addService("myservice", bbinder) │ │ -> BpServiceManager.addService() │ │ -> transact(ADD_SERVICE) │ │ -> Parcel 携带: │ │ - 服务名 "myservice" │ │ - bbinder 的 flat_binder│ │ │ ├─────────────────────────────────────►│ │ │ 4. 收到 flat_binder │ │ 5. 驱动创建 binder_ref │ │ (SMgr->Server的引用) │ │ 6. 存入 svclist: │ │ "myservice" -> handle=X
发现流程 :
Client 进程 ServiceManager 进程 │ │ │ 1. getService("myservice") │ │ -> transact(GET_SERVICE) │ ├─────────────────────────────────────►│ │ │ 2. svclist_find("myservice") │ │ 3. 返回 handle=X │◄─────────────────────────────────────┤ │ │ │ 4. 驱动为 Client 创建 binder_ref │ │ -> BpBinder(handle=X) │ │ 5. 现在 Client 可以向 Server 发请求 │
1.3 Binder 对象在进程间的传递 这是 Binder 最精妙的设计之一——Binder 对象可以在进程之间传递,驱动自动管理其引用:
进程A持有 BBinder(实体) │ │ A 通过 Binder 向 B 传递此 BBinder ▼ 驱动检测到 BINDER_TYPE_BINDER (本地实体 -> 对端) │ │ 在进程B中创建一个 binder_ref,分配一个新的 handle ▼ 进程B获得 BpBinder(handle=K) │ 如果B再传递给C ▼ 驱动检测到 BINDER_TYPE_HANDLE (远程引用 -> 对端) │ │ 在进程C中创建另一个 binder_ref,指向同一个 binder_node ▼ 进程C获得 BpBinder(handle=M)
这样,无论 Binder 对象经过多少层传递,驱动都能正确路由——所有引用最终指向同一个 binder_node。
1.4 内存划分
1.5 传统 IPC 传输数据
1.6 Binder 传输数据
二、Linux 进程间通信机制对比 Binder 是 Android 系统进程间通信(IPC)方式之一,这里为了突出 Android Binder IPC 通信机制的优越性,先分析对比一波 共享内存 、Socket 和本文介绍的 Binder 的数据拷贝。
2.1 三种 IPC 方式的数据拷贝次数
共享内存 :虽然无需拷贝,但控制复杂,难以复用。基于此方案的通信,如果有恶意程序或某个app运行崩溃,会导致关联的应用甚至系统崩溃,这是致命的。
Socket/管道/消息队列 :基于 C/S 架构的通信。socket 作为通用接口,传输效率低效,开销巨大,主要用在跨网络的进程间通信和本机上进程间的低速通信。如果采用 socket 在底层架设一套协议,会加重系统设计的复杂性,且难以保证通信效率。消息队列和管道采用存储-转发方式,即数据先从发送方缓存区拷贝到内核开辟的缓存区中,然后再从内核缓存区拷贝到接收方缓存区,至少两次拷贝。
Binder :基于 C/S 通信模式,传输过程只需一次拷贝,为发送方添加 UID/PID 身份,既支持实名 Binder,也支持匿名 Binder,安全性高。
三、面向对象的 Binder IPC Binder 使用 Client-Server 通信方式:一个进程作为 Server 提供诸如视频/音频解码、视频捕获、地址本查询、网络连接等服务;多个进程作为 Client 向 Server 发起服务请求,获得所需要的服务。
要想实现 Client-Server 通信必须实现以下两点:
Server 必须有确定的访问接入点或者说地址来接受 Client 的请求,并且 Client 可以通过某种途径获知 Server 的地址;
制定 Command-Reply 协议来传输数据。
对 Binder 而言,Binder 可以看成 Server 提供的实现某个特定服务的访问接入点,Client 通过这个”地址”向 Server 发送请求来使用该服务。对 Client 而言,Binder 可以看成是通向 Server 的管道入口,要想和某个 Server 通信首先必须建立这个管道并获得管道入口。
Binder 使用了面向对象思想来描述作为访问接入点的 Binder 和在 Client 中的入口:
Binder 是一个实体位于 Server 中的对象,该对象提供了一套方法用以实现对服务的请求,就象类的成员函数。
遍布于 Client 中的入口可以看成指向这个 Binder 对象的”指针”,一旦获得了这个”指针”就可以调用该对象的方法访问 Server。
四、Binder 驱动深度分析 4.1 驱动注册:binder_init Linux 一切皆文件 。Binder 驱动的初始化从 binder_init 开始:
static int __init binder_init (void ) { int ret; binder_alloc_init(); ret = misc_register(&binder_miscdev); list_add(&binder_devices, &binder_miscdev.list ); return ret; } static struct miscdevice binder_miscdev = { .minor = MISC_DYNAMIC_MINOR, .name = "binder" , .fops = &binder_fops }; static const struct file_operations binder_fops = { .owner = THIS_MODULE, .poll = binder_poll, .unlocked_ioctl = binder_ioctl, .compat_ioctl = binder_ioctl, .mmap = binder_mmap, .open = binder_open, .flush = binder_flush, .release = binder_release, };
4.2 打开设备:binder_open 当用户空间进程调用 open("/dev/binder", O_RDWR) 时:
static int binder_open (struct inode *nodp, struct file *filp) { struct binder_proc *proc ; proc = kzalloc(sizeof (*proc), GFP_KERNEL); proc->tsk = current->group_leader; INIT_LIST_HEAD(&proc->todo); init_waitqueue_head(&proc->wait); proc->threads = RB_ROOT; proc->nodes = RB_ROOT; proc->refs_by_desc = RB_ROOT; proc->refs_by_node = RB_ROOT; hlist_add_head(&proc->proc_node, &binder_procs); filp->private_data = proc; return 0 ; }
关键数据结构 binder_proc:
struct binder_proc { struct hlist_node proc_node ; struct rb_root threads ; struct rb_root nodes ; struct rb_root refs_by_desc ; struct rb_root refs_by_node ; struct list_head todo ; struct binder_alloc alloc ; struct task_struct *tsk ; };
4.3 内存映射:binder_mmap static int binder_mmap (struct file *filp, struct vm_area_struct *vma) { struct binder_proc *proc = filp->private_data; ret = binder_alloc_mmap_handler(&proc->alloc, vma); return ret; }
关键:用户空间地址 + proc->alloc 偏移 = 内核空间地址,实现了”一次拷贝”。
4.4 核心 ioctl:binder_ioctl static long binder_ioctl (struct file *filp, unsigned int cmd, unsigned long arg) { struct binder_proc *proc = filp->private_data; struct binder_thread *thread ; thread = binder_get_thread(proc); switch (cmd) { case BINDER_WRITE_READ: { struct binder_write_read bwr ; copy_from_user(&bwr, ubuf, sizeof (bwr)); if (bwr.write_size > 0 ) { binder_thread_write(proc, thread, bwr.write_buffer, bwr.write_size, &bwr.write_consumed); } if (bwr.read_size > 0 ) { binder_thread_read(proc, thread, bwr.read_buffer, bwr.read_size, &bwr.read_consumed, ...); } copy_to_user(ubuf, &bwr, sizeof (bwr)); break ; } case BINDER_SET_MAX_THREADS: proc->max_threads = (u32)arg; break ; case BINDER_SET_CONTEXT_MGR: binder_context_mgr_node = binder_new_node(proc, ...); binder_context_mgr_uid = current->cred->euid; break ; case BINDER_THREAD_EXIT: binder_free_thread(proc, thread); break ; case BINDER_VERSION: put_user(BINDER_CURRENT_PROTOCOL_VERSION, (int __user *)arg); break ; } return ret; }
4.5 binder_thread_write —— 处理用户空间命令 static int binder_thread_write (struct binder_proc *proc, struct binder_thread *thread, binder_uintptr_t binder_buffer, size_t size, binder_size_t *consumed) { uint32_t cmd; void __user *buffer = (void __user *)binder_buffer; void __user *ptr = buffer + *consumed; while (ptr < buffer + size) { get_user(cmd, (uint32_t __user *)ptr); ptr += sizeof (uint32_t ); switch (cmd) { case BC_TRANSACTION: case BC_REPLY: { struct binder_transaction_data tr ; copy_from_user(&tr, ptr, sizeof (tr)); binder_transaction(proc, thread, &tr, cmd == BC_REPLY); break ; } case BC_INCREFS: case BC_ACQUIRE: binder_inc_refs(proc, thread, ...); break ; case BC_DECREFS: case BC_RELEASE: binder_dec_refs(proc, thread, ...); break ; case BC_REGISTER_LOOPER: thread->looper |= BINDER_LOOPER_STATE_REGISTERED; break ; case BC_ENTER_LOOPER: thread->looper |= BINDER_LOOPER_STATE_ENTERED; break ; case BC_REQUEST_DEATH_NOTIFICATION: binder_request_death_notification(proc, thread, ...); break ; case BC_CLEAR_DEATH_NOTIFICATION: binder_clear_death_notification(proc, thread, ...); break ; } } return 0 ; }
4.6 binder_transaction —— 核心事务处理 static void binder_transaction (struct binder_proc *proc, struct binder_thread *thread, struct binder_transaction_data *tr, int reply) { struct binder_transaction *t ; struct binder_proc *target_proc ; if (reply) { } else { if (tr->target.handle) { struct binder_ref *ref; ref = binder_get_ref_for_node(proc, tr->target.handle); target_proc = ref->proc; target_node = ref->node; } else { target_proc = binder_context_mgr_node->proc; target_node = binder_context_mgr_node; } } t = kzalloc(sizeof (*t), GFP_KERNEL); t->from_euid = task_euid(proc->tsk); t->from_pid = proc->pid; t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size, ...); copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size); binder_translate_binder(t, ...); binder_enqueue_work(target_proc, t->work, &target_proc->todo); wake_up_interruptible(&target_proc->wait); }
五、Binder 用户空间实现 5.1 ProcessState 与 IPCThreadState sp<ProcessState> ProcessState::self () { if (gProcess != NULL ) return gProcess; gProcess = new ProcessState ("/dev/binder" ); return gProcess; } ProcessState::ProcessState (const char * driver) : mDriverFD (open_driver (driver)) , mVMStart (MAP_FAILED) , mMaxThreads (DEFAULT_MAX_BINDER_THREADS) { mVMStart = mmap (0 , BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0 ); }
IPCThreadState* IPCThreadState::self () { if (gHaveTLS.load ()) { return (IPCThreadState*)pthread_getspecific (gTLS); } gHaveTLS.store (true ); IPCThreadState* st = new IPCThreadState; pthread_setspecific (gTLS, st); return st; } status_t IPCThreadState::transact (int32_t handle, uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { err = writeTransactionData (BC_TRANSACTION, flags, handle, code, data); if ((flags & TF_ONE_WAY) == 0 ) { if (reply) { err = waitForResponse (reply); } } return err; } status_t IPCThreadState::waitForResponse (Parcel *reply, status_t *acquireResult) { uint32_t cmd; int32_t err; while (1 ) { if ((err = talkWithDriver ()) < NO_ERROR) break ; cmd = (uint32_t )mIn.readInt32 (); switch (cmd) { case BR_TRANSACTION_COMPLETE: if (!reply && !acquireResult) goto finish; break ; case BR_REPLY: err = mIn.read (reply, ...); goto finish; case BR_DEAD_REPLY: err = DEAD_OBJECT; goto finish; case BR_FAILED_REPLY: err = FAILED_TRANSACTION; goto finish; default : err = executeCommand (cmd); break ; } } finish: return err; } status_t IPCThreadState::talkWithDriver (bool doReceive) { binder_write_read bwr; bwr.write_buffer = (uintptr_t )mOut.data (); bwr.write_size = mOut.dataSize (); bwr.read_buffer = (uintptr_t )mIn.data (); bwr.read_size = mIn.dataCapacity (); status_t err = ioctl (mProcess->mDriverFD, BINDER_WRITE_READ, &bwr); mOut.setDataSize (0 ); return err; }
5.2 Binder 线程池 void IPCThreadState::joinThreadPool (bool isMain) { mOut.writeInt32 (isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); do { result = getAndExecuteCommand (); if (result == TIMED_OUT && !isMain) { break ; } } while (result != -ECONNREFUSED && result != -EBADF); mOut.writeInt32 (BC_EXIT_LOOPER); talkWithDriver (false ); }
线程池管理的关键规则:
主线程 (调用 joinThreadPool(true)):进入后一直等待,不退出,收到 BC_ENTER_LOOPER 命令。
工作线程 (调用 joinThreadPool(false)):收到 BC_REGISTER_LOOPER 命令,空闲超时后自动退出。
最大线程数 :默认 15,由 BINDER_SET_MAX_THREADS ioctl 设置。
驱动会根据队列中的未处理事务数量动态唤醒线程。所有线程忙时,Client 的请求在 todo 队列中等待。
六、Java 层 Binder 实现 6.1 BinderProxy 和 Binder public final class BinderProxy implements IBinder { private final long mNativeData; public boolean transact (int code, Parcel data, Parcel reply, int flags) { return transactNative(code, data, reply, flags); } public static final native int getCallingUid () ; public static final native int getCallingPid () ; } public class Binder implements IBinder { private final long mObject; protected boolean onTransact (int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) { } public static final int getCallingUid () { return BinderProxy.getCallingUid(); } public static final int getCallingPid () { return BinderProxy.getCallingPid(); } }
6.2 AIDL 的代码生成 AIDL(Android Interface Definition Language)是我们日常使用 Binder 的最常用方式。编译器(aidl tool)会根据 .aidl 文件生成 Java 代码:
interface IMyService { String getMessage (int id) ; } public static class Proxy implements IMyService { private IBinder mRemote; @Override public String getMessage (int id) { Parcel _data = Parcel.obtain(); Parcel _reply = Parcel.obtain(); String _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(id); mRemote.transact(Stub.TRANSACTION_getMessage, _data, _reply, 0 ); _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } } public static abstract class Stub extends Binder implements IMyService { @Override public boolean onTransact (int code, Parcel data, Parcel reply, int flags) { switch (code) { case TRANSACTION_getMessage: { data.enforceInterface(DESCRIPTOR); int _arg0 = data.readInt(); String _result = this .getMessage(_arg0); reply.writeNoException(); reply.writeString(_result); return true ; } } return super .onTransact(code, data, reply, flags); } }
6.3 oneway vs 同步调用 mRemote.transact(code, data, reply, 0 ); mRemote.transact(code, data, null , IBinder.FLAG_ONEWAY);
oneway 的内部机制:
Client 端:IPCThreadState::transact 中 flags & TF_ONE_WAY,不等待 BR_REPLY。
驱动层:binder_transaction 中设置 TF_ONE_WAY 标志,不创建回复事务。
Server 端:BBinder::onTransact 正常处理,但返回值被忽略。
oneway 的注意事项:
不能有返回值或 out 参数(reply 为 null)。
调用顺序保证:Binder 驱动保证同一个线程发出的 oneway 调用按顺序到达。
线程池:oneway 调用不会占用 Client 的 Binder 线程(不需要等待回复)。
七、Binder 的安全机制 7.1 UID/PID 验证 uid_t IPCThreadState::getCallingUid () const { return mCallingUid; } pid_t IPCThreadState::getCallingPid () const { return mCallingPid; }
7.2 SELinux 对 Binder 的约束 # system/sepolicy/public/service.te # Binder 服务的 SELinux 控制 type system_server_service, service_manager_type; # 只有特定域可以向 system_server 注册服务 allow { audioserver cameraserver } system_server_service:service_manager add; # system/sepolicy/vendor/ # Binder 调用的 SELinux 控制 binder_call(system_server, appdomain) # 允许 appdomain 调用 system_server binder_call(appdomain, mediaserver) # 允许 mediaserver 调用 appdomain
八、Binder 性能优化与限制 8.1 事务大小限制 Binder 单次事务最大数据量约为 1016KB(1MB - 8KB*2)。超限后会抛出 TransactionTooLargeException。
处理大数据的方式:
使用 ashmem 传递大数据(Binder 只传 fd)。
分批传输。
使用 ContentProvider 的 openFile 接口。
8.2 Binder 线程耗尽 如果 Server 端所有 15 个 Binder 线程都在处理耗时操作(如同步网络请求),新的 Binder 请求会在 Server 的 todo 队列中等待,导致 Client 端超时(ANR)。
最佳实践:
Binder 线程中避免耗时操作(异步化)。
耗时操作交给后台线程池处理。
使用 oneway 调用减少等待。
九、剑指大厂 — 核心面试题 Q1: Binder 有什么优势? – 《ByteDance》
优点:
内存开辟(一次拷贝) :通过 mmap 机制,内核空间和用户空间映射同一块物理内存,数据从 Client 拷贝到内核后,Server 直接通过 mmap 区域读取,无需二次拷贝。传统 IPC(如 Socket)需要两次拷贝(用户空间 -> 内核空间 -> 用户空间)。
风险隔离 :Binder 的 C/S 架构天然实现进程隔离。一个 Server 进程崩溃不影响 Client 进程。相反,共享内存方案中,一个进程崩溃可能破坏共享数据结构,导致关联进程异常。
安全验证 :Binder 驱动在内核层自动记录调用者的 UID/PID,无法伪造。服务端通过 Binder.getCallingUid() 进行权限验证。配合 SELinux 策略,实现多层安全防护。
对象生命周期管理 :Binder 驱动使用强/弱引用计数管理跨进程对象。当 Client 释放引用,驱动自动通知 Server 调整计数。配合 Death Recipient 机制,Client 可以感知 Server 死亡。
Q2: Binder 是如何做到一次拷贝的? – 《Tencent》
内存划分 :内存被操作系统分成两块:用户空间和内核空间。用户空间是用户程序代码运行的地方,内核空间是系统内核运行的地方,可以共享。为了安全,这两者是隔离的,这样即使用户的应用程序崩溃也不会影响到内核。
在 32 位系统(2^32,即总共可访问地址为 4G)中,内核 1G,用户空间 3G。在 64 位系统中,低位 0-47 位才是有效的可变地址(寻址空间 256T),高位 48-63 位全补 0 或 1。一般高位全补 0 对应的地址空间是用户空间,高位全补 1 对应的是内核空间。
Binder 一次拷贝的具体过程:
1. ProcessState::self() 时 mmap 一块物理内存 用户空间地址 = mmap(..., driverFD, 0); 内核空间地址 = proc->alloc.buffer (驱动层面) 2. Client 发送数据: ioctl(BINDER_WRITE_READ) → binder_thread_write() → binder_transaction() → copy_from_user(t->buffer, user_data) // 【唯一的一次拷贝】 // t->buffer 在目标进程的内核缓冲区中 // 而目标进程通过 mmap 映射了同一块物理内存 3. Server 接收数据: ioctl(BINDER_WRITE_READ) → binder_thread_read() → 返回 BR_TRANSACTION 给用户空间 → Parcel 中的数据直接指向 mmap 区域 // Server 无需再经历 copy_to_user
关键:Binder 驱动分配的缓冲区位于目标进程的 mmap 区域内,所以从用户空间拷贝到内核后,目标进程的用户空间可以直接读取,无需第二次拷贝。
Q3: mmap 的原理讲解 – 《Tencent》
MMAP :Linux 通过将一个虚拟内存区域与一个磁盘上的对象(或匿名内存)关联起来,以初始化这个虚拟内存区域的内容,这个过程称为内存映射(memory mapping)。
对文件进行 mmap,会在进程的虚拟内存分配地址空间,建立映射关系。实现这样的映射关系后,就可以对这一段内存采用指针的方式进行读写操作,而系统会自动回写到对应的文件磁盘上。
mmap 在 Binder 中的作用:
映射一块内核缓冲区到用户空间,实现零拷贝数据共享。
大小限制为 1MB - 8KB(约 1016KB),这是单次 Binder 事务的最大数据量。
mmap 是 lazy allocation 的——映射时只建立 VMA,不分配物理页面。只有真正访问时(通过 copy_from_user)才通过 page fault 分配物理页。
Q4: oneway 调用和同步调用的区别是什么?内部如何实现?
区别:
特性
同步调用
oneway 调用
Client 是否等待
是(阻塞)
否(立即返回)
是否有返回值
有
无(void)
线程占用
Client 线程阻塞
Client 线程不阻塞
调用顺序
严格串行
同一 Client 线程保证串行
驱动处理
需要 BR_REPLY 返回
BR_TRANSACTION_COMPLETE 即完成
内部实现:
AIDL 层:FLAG_ONEWAY 标志,reply 为 null。
IPCThreadState 层:检测 TF_ONE_WAY 标志,不调用 waitForResponse。
驱动层:binder_transaction 设置 TF_ONE_WAY,不创建回复事务,直接给 Client 发 BR_TRANSACTION_COMPLETE。
Q5: Binder 线程池为什么要限制 15 个线程?怎么配置?
限制 15 个线程的原因:
防止线程爆炸 :每个 Binder 线程占用一个内核 task_struct 和用户空间栈(约 1MB),过多线程会耗尽内存。
调度效率 :线程过多导致频繁上下文切换,降低吞吐量。
任务粒度 :Binder 事务通常很小(几十微秒到几毫秒),15 个线程已经足够处理大部分并发情况。
历史原因 :早期 Android 设备(512MB RAM)资源有限,15 是一个平衡的选择。
配置方式:
ProcessState::self ()->setThreadPoolMaxThreadCount (20 ); sp<ProcessState> ps = ProcessState::self (); ps->startThreadPool (); ps->giveThreadPoolName ();
注意:不同厂商的 ROM 可能修改了默认值,测试时要考虑兼容性。
核心参考 AOSP 路径:
drivers/android/binder.c — Binder 驱动(Android 10+)
frameworks/native/libs/binder/ProcessState.cpp — 进程单例
frameworks/native/libs/binder/IPCThreadState.cpp — 线程级通信
frameworks/native/libs/binder/BpBinder.cpp — Client 代理
frameworks/native/libs/binder/BBinder.cpp — Server 桩
frameworks/native/libs/binder/Parcel.cpp — 数据封装
frameworks/native/cmds/servicemanager/ServiceManager.cpp — 服务管理
frameworks/base/core/java/android/os/Binder.java — Java 层 Binder
frameworks/base/core/java/android/os/BinderProxy.java — Java 层 Binder 代理
system/tools/aidl/ — AIDL 代码生成工具