ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Binder 流程梳理 一

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; }
返回列表