Binder 流程梳理 一
以MediaPlayerService 为例addService开始init进程初始化main_mediaserver.cpp,主要代码InitializeIcuOrDie(); spProcessState proc(ProcessState::self()); spIServiceManager sm defaultServiceManager(); ALOGI(ServiceManager: %p, sm.get()); AudioFlinger::instantiate(); MediaPlayerService::instantiate();defaultServiceManager-ProcessState::self()-getContextObject(NULL));spIBinder ProcessState::getContextObject(const spIBinder /*caller*/) { return getStrongProxyForHandle(0); }getStrongProxyForHandle会返回b new BpBinder(handle); handle为0表示service_managerMediaPlayerService::instantiate(); 接下来会调用void MediaPlayerService::instantiate() {defaultServiceManager()-addService(String16(media.player), new MediaPlayerService());}addServicevirtual status_t addService(const String16 name, const spIBinder service, bool allowIsolated) { Parcel data, reply; data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); data.writeString16(name); data.writeStrongBinder(service); data.writeInt32(allowIsolated ? 1 : 0); status_t err remote()-transact(ADD_SERVICE_TRANSACTION, data, reply); return err NO_ERROR ? reply.readExceptionCode() : err; }data中包含nameservice就是MediaPlayerService 因为class BnMediaPlayerService: public BnInterfaceIMediaPlayerService所以他是Ibinder类型data.writeStrongBinder(service);status_t flatten_binder(const spProcessState /*proc*/, const spIBinder binder, Parcel* out) { flat_binder_object obj; obj.flags 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS; if (binder ! NULL) { IBinder *local binder-localBinder(); if (!local) { BpBinder *proxy binder-remoteBinder(); if (proxy NULL) { ALOGE(null proxy); } const int32_t handle proxy ? proxy-handle() : 0; obj.type BINDER_TYPE_HANDLE; obj.binder 0; /* Dont pass uninitialized stack data to a remote process */ obj.handle handle; obj.cookie 0; } else { obj.type BINDER_TYPE_BINDER; obj.binder reinterpret_castuintptr_t(local-getWeakRefs()); obj.cookie reinterpret_castuintptr_t(local); } } else { obj.type BINDER_TYPE_BINDER; obj.binder 0; obj.cookie 0; } return finish_flatten_binder(binder, obj, out); }mediaService是Bbinder所以elseobj.type BINDER_TYPE_BINDER;obj.binder reinterpret_castuintptr_t(local-getWeakRefs());obj.cookie reinterpret_castuintptr_t(local); //这里local就是this强饮用那么data包含了flat_binder_objectstatus_t err remote()-transact(ADD_SERVICE_TRANSACTION, data, reply);其中的mHandleBpBinder::BpBinder(int32_t handle) : mHandle(handle) , mAlive(1) , mObitsSent(0) , mObituaries(NULL)status_t BpBinder::transact( uint32_t code, const Parcel data, Parcel* reply, uint32_t flags) { // Once a binder has died, it will never come back to life. if (mAlive) { status_t status IPCThreadState::self()-transact( mHandle, code, data, reply, flags); if (status DEAD_OBJECT) mAlive 0; return status; } return DEAD_OBJECT; }status_t IPCThreadState::transact(int32_t handle, uint32_t code, const Parcel data, Parcel* reply, uint32_t flags) { status_t err data.errorCheck(); flags | TF_ACCEPT_FDS; if (err NO_ERROR) { err writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL); } if (err ! NO_ERROR) { if (reply) reply-setError(err); return (mLastError err); } if ((flags TF_ONE_WAY) 0) { #if 0 if (code 4) { // relayout ALOGI( CALLING transaction 4); } else { ALOGI( CALLING transaction %d, code); } #endif if (reply) { err waitForResponse(reply); } else { Parcel fakeReply; err waitForResponse(fakeReply); } } else { err waitForResponse(NULL, NULL); } return err; }writeTransactionDatastatus_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags, int32_t handle, uint32_t code, const Parcel data, status_t* statusBuffer) { binder_transaction_data tr; tr.target.ptr 0; /* Dont pass uninitialized stack data to a remote process */ tr.target.handle handle; tr.code code; tr.flags binderFlags; tr.cookie 0; tr.sender_pid 0; tr.sender_euid 0; const status_t err data.errorCheck(); if (err NO_ERROR) { tr.data_size data.ipcDataSize(); tr.data.ptr.buffer data.ipcData(); tr.offsets_size data.ipcObjectsCount()*sizeof(binder_size_t); tr.data.ptr.offsets data.ipcObjects(); } else if (statusBuffer) { tr.flags | TF_STATUS_CODE; *statusBuffer err; tr.data_size sizeof(status_t); tr.data.ptr.buffer reinterpret_castuintptr_t(statusBuffer); tr.offsets_size 0; tr.data.ptr.offsets 0; } else { return (mLastError err); } mOut.writeInt32(cmd); mOut.write(tr, sizeof(tr)); return NO_ERROR; }到这里就需要捋一下err writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);handle 0code ADD_SERVICE_TRANSACTIONdata data (flat_binder_object)uintptr_t Parcel::ipcData() const { return reinterpret_castuintptr_t(mData); }tr.data.ptr.buffer data.ipcData();存的是指针地址组装数据binder_transaction_datastatus_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult) { uint32_t cmd; int32_t err; while (1) { if ((errtalkWithDriver()) NO_ERROR) break; 。。。。。。。 }talkWithDriver中构造binder_write_read bwr;status_t IPCThreadState::talkWithDriver(bool doReceive) { if (mProcess-mDriverFD 0) { return -EBADF; } binder_write_read bwr; // Is the read buffer empty? const bool needRead mIn.dataPosition() mIn.dataSize(); const size_t outAvail (!doReceive || needRead) ? mOut.dataSize() : 0; bwr.write_size outAvail; bwr.write_buffer (uintptr_t)mOut.data(); // This is what well read. if (doReceive needRead) { bwr.read_size mIn.dataCapacity(); bwr.read_buffer (uintptr_t)mIn.data(); } else { bwr.read_size 0; bwr.read_buffer 0; } if ((bwr.write_size 0) (bwr.read_size 0)) return NO_ERROR; bwr.write_consumed 0; bwr.read_consumed 0; status_t err; do { IF_LOG_COMMANDS() { alog About to read/write, write size mOut.dataSize() endl; } #if defined(HAVE_ANDROID_OS) if (ioctl(mProcess-mDriverFD, BINDER_WRITE_READ, bwr) 0) err NO_ERROR; else err -errno; #else err INVALID_OPERATION; #endif if (mProcess-mDriverFD 0) { err -EBADF; } IF_LOG_COMMANDS() { alog Finished read/write, write size mOut.dataSize() endl; } } while (err -EINTR); 。。。 return err; }后面就进入内核了,内核驱动注册file_opreation时ioctl命名为binder_ioctlstatic long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int ret; struct binder_proc *proc filp-private_data; struct binder_thread *thread; unsigned int size _IOC_SIZE(cmd); void __user *ubuf (void __user *)arg; trace_binder_ioctl(cmd, arg); ret wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error 2); if (ret) goto err_unlocked; binder_lock(__func__); thread binder_get_thread(proc); if (thread NULL) { ret -ENOMEM; goto err; } switch (cmd) { case BINDER_WRITE_READ: ret binder_ioctl_write_read(filp, cmd, arg, thread); if (ret) goto err; break; 。。。 ret 0; err: }在这之前我门的跨进程通信会open驱动static int binder_open(struct inode *nodp, struct file *filp) { struct binder_proc *proc; binder_debug(BINDER_DEBUG_OPEN_CLOSE, binder_open: %d:%d\n, current-group_leader-pid, current-pid); proc kzalloc(sizeof(*proc), GFP_KERNEL); if (proc NULL) return -ENOMEM; get_task_struct(current); proc-tsk current; INIT_LIST_HEAD(proc-todo); init_waitqueue_head(proc-wait); proc-default_priority task_nice(current); binder_lock(__func__); binder_stats_created(BINDER_STAT_PROC); hlist_add_head(proc-proc_node, binder_procs); proc-pid current-group_leader-pid; INIT_LIST_HEAD(proc-delivered_death); filp-private_data proc; binder_unlock(__func__); if (binder_debugfs_dir_entry_proc) { char strbuf[11]; snprintf(strbuf, sizeof(strbuf), %u, proc-pid); proc-debugfs_entry debugfs_create_file(strbuf, S_IRUGO, binder_debugfs_dir_entry_proc, proc, binder_proc_fops); } return 0; }static int binder_mmap(struct file *filp, struct vm_area_struct *vma) { int ret; struct vm_struct *area; struct binder_proc *proc filp-private_data; //⭐从file拿到binder_procbinder_open存进去的 const char *failure_string; struct binder_buffer *buffer; // 规则mmap必须是打开/dev/binder的同一个线程别的线程不能mmap if (proc-tsk ! current) return -EINVAL; // 限制最大映射4M用户传更大也强制截断到4MAndroid用户态一般传 BINDER_VM_SIZE 1M‑8K if ((vma-vm_end - vma-vm_start) SZ_4M) vma-vm_end vma-vm_start SZ_4M; // 校验vm_flags禁止非法标志 if (vma-vm_flags FORBIDDEN_MMAP_FLAGS) { ret -EPERM; failure_string bad vm_flags; goto err_bad_arg; } // ⭐关键VM_DONTCOPY(fork不复制该vma)~VM_MAYWRITE**用户态这块内存只允许读不能写** vma-vm_flags (vma-vm_flags | VM_DONTCOPY) ~VM_MAYWRITE; mutex_lock(binder_mmap_lock); if (proc-buffer) { //⭐一个binder_proc只能mmap一次重复调用返回‑EBUSY ret -EBUSY; failure_string already mapped; goto err_already_mapped; } // 1、在内核虚拟地址空间分配一块内核虚拟内存area area get_vm_area(vma-vm_end - vma-vm_start, VM_IOREMAP); if (area NULL) { ret -ENOMEM; failure_string get_vm_area; goto err_get_vm_area_failed; } proc-buffer area-addr; //⭐保存内核虚拟地址 // user_buffer_offset用户虚拟地址 和内核虚拟地址之间偏移量binder内核做地址转换要用 proc-user_buffer_offset vma-vm_start - (uintptr_t)proc-buffer; mutex_unlock(binder_mmap_lock); #ifdef CONFIG_CPU_CACHE_VIPT // VIPT cache 别名对齐处理arm32老平台cache问题现代arm64基本不会触发 #endif // 2、分配pages数组保存这个缓冲区对应的物理page指针数组 proc-pages kzalloc(sizeof(proc-pages[0]) * ((vma-vm_end - vma-vm_start) / PAGE_SIZE), GFP_KERNEL); if (proc-pages NULL) { ret -ENOMEM; failure_string alloc page array; goto err_alloc_pages_failed; } proc-buffer_size vma-vm_end - vma-vm_start; //记录缓冲区总大小 // ⭐设置vma的操作集 binder_vm_opspage fault缺页回调 vma-vm_ops binder_vm_ops; vma-vm_private_data proc; //3、binder_update_page_range分配物理页把物理页同时映射到【内核虚拟地址】【用户虚拟地址】 // 先预分配第一页物理内存 if (binder_update_page_range(proc, 1, proc-buffer, proc-buffer PAGE_SIZE, vma)) { ret -ENOMEM; failure_string alloc small buf; goto err_alloc_small_buf_failed; } buffer proc-buffer; INIT_LIST_HEAD(proc-buffers); list_add(buffer-entry, proc-buffers); buffer-free 1; binder_insert_free_buffer(proc, buffer); //⭐初始化空闲buffer链表binder_buffer内存块管理 proc-free_async_space proc-buffer_size / 2; //oneway异步事务最大占用一半缓冲区 barrier(); proc-files get_files_struct(current); proc-vma vma; //保存用户vma proc-vma_vm_mm vma-vm_mm; return 0; // 下面一大段是出错回滚释放资源 }初始化当前进程表述对象procproc kzalloc(sizeof(*proc), GFP_KERNEL);初始化todo list INIT_LIST_HEAD(proc-todo);filp-private_data proc;服务端映射内核和用户态地址到物理页P客户端调用 copy_from_user 到服务端内核地址一次拷贝服务端通过偏移量获取这块内存这个就是binder的一次拷贝回到binder_ioctl中static int binder_ioctl_write_read(struct file *filp, unsigned int cmd, unsigned long arg, struct binder_thread *thread) { int ret 0; struct binder_proc *proc filp-private_data; unsigned int size _IOC_SIZE(cmd); void __user *ubuf (void __user *)arg; struct binder_write_read bwr; if (size ! sizeof(struct binder_write_read)) { ret -EINVAL; goto out; } if (copy_from_user(bwr, ubuf, sizeof(bwr))) { ret -EFAULT; goto out; } binder_debug(BINDER_DEBUG_READ_WRITE, %d:%d write %lld at %016llx, read %lld at %016llx\n, proc-pid, thread-pid, (u64)bwr.write_size, (u64)bwr.write_buffer, (u64)bwr.read_size, (u64)bwr.read_buffer); if (bwr.write_size 0) { ret binder_thread_write(proc, thread, bwr.write_buffer, bwr.write_size, bwr.write_consumed); trace_binder_write_done(ret); if (ret 0) { bwr.read_consumed 0; if (copy_to_user(ubuf, bwr, sizeof(bwr))) ret -EFAULT; goto out; } } if (bwr.read_size 0) { ret binder_thread_read(proc, thread, bwr.read_buffer, bwr.read_size, bwr.read_consumed, filp-f_flags O_NONBLOCK); trace_binder_read_done(ret); if (!list_empty(proc-todo)) wake_up_interruptible(proc-wait); if (ret 0) { if (copy_to_user(ubuf, bwr, sizeof(bwr))) ret -EFAULT; goto out; } } binder_debug(BINDER_DEBUG_READ_WRITE, %d:%d wrote %lld of %lld, read return %lld of %lld\n, proc-pid, thread-pid, (u64)bwr.write_consumed, (u64)bwr.write_size, (u64)bwr.read_consumed, (u64)bwr.read_size); if (copy_to_user(ubuf, bwr, sizeof(bwr))) { ret -EFAULT; goto out; } out: return ret; }

相关新闻

kingbase金仓数据库docker部署完整步骤

kingbase金仓数据库docker部署完整步骤

Docker快速体验 本节将讲解在Linux系统中使用docker命令行快速安装KingbaseES。 环境准备 硬件环境要求 KingabaseES Docker 软件包支持通用 X86_64、龙芯、飞腾、鲲鹏等国产CPU硬件体系架构。 软件环境要求 软件包名称版本说明Docker20.10.0及以上版本 创建安装路径 使…

2026/11/6 23:42:44 阅读更多 →
模拟退火算法:原理、实现与在组合优化中的应用

模拟退火算法:原理、实现与在组合优化中的应用

1. 从“淬火”到“寻优”:模拟退火算法的核心思想如果你在解决一个复杂的优化问题时,感觉像在迷宫深处寻找唯一的出口,或者像在崎岖的山脉中寻找最低的谷底,那么模拟退火算法很可能就是你需要的那个“登山向导”。我第一次接触这个…

2026/11/3 9:36:12 阅读更多 →
AI产业链成本拆解:从算力到应用的六层账本与盈利逻辑

AI产业链成本拆解:从算力到应用的六层账本与盈利逻辑

开头先给一个判断:AI 这轮热潮里,钱并不是均匀“撒”给所有人的,而是沿着一条非常清晰的技术链路逐层汇聚。你问“AI 的钱,被谁赚走了”,其实是在问两件事:一是产业链上每一层到底从谁手里收到钱&#xff0…

2026/11/6 17:15:44 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/6 15:21:35 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/6 9:29:27 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/6 22:01:11 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/6 22:01:11 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/6 8:08:42 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/6 22:01:09 阅读更多 →

日新闻

周新闻

月新闻