您好,登錄后才能下訂單哦!
????????在上文中分析了 binder 驅動的框架以及它是怎么注冊服務、獲取服務和使用服務的整個過程,接下來就來看看 binder transaction stack 機制。
????????我們在前面也有提到進程 A 向進程 B 相互發數據,模式是進程 A 先發一個 BC_TRANSACTION 給進程 B,進程 B 收到之后給進程 A 回復一個 BR_TRANSACTION 表示數據已經收到了。然后進程 B 向進程 A 發送一個 BC_REPLY 用以發送進程 B 需要向進程 A 回復的相關數據,進程 A 收到數據后向進程 B 發送一個 BR_REPLY 表示回復的數據已經收到。它們是通過驅動來進行數據的交互的,只有這四種模式是涉及到兩進程的,其他的模式只是 app 和驅動的交互,用于改變/報告狀態。
????????那么就有兩個問題了,需要發給誰?回給誰呢?要回答這兩個問題,我們先來看看 test_client(A)和 test_server(B)是怎么工作的。根據我們之前的代碼分析,可知:在 svcmgr_publish 注冊服務時序調用 binder_call 函數,而在 binder_call 函數中構造參數時 cmd 為 BC_TRANSACTION。由此可知 test_client 先發送一個 BC_TRANSACTION 給 test_server。并且構造的是 write 相關的數據,最后調用 ioctl 來發送 BINDER_WRITE_READ。那么我們進到 binder_ioctl 函數中看看。找到 BINDER_WRITE_READ 命令,根據之前的構造的 write 相關的數據可知進入到 binder_thread_write 函數中。在 binder_thread_write 函數中找到 BC_TRANSACTION 命令,我們看到在里面做了一個 binder_transaction 的動作。
????????我們在進到 binder_transaction 函數中看看是怎樣完成的:
???????????a. 一開始,非“雙向傳輸”。所以,數據將放在 test_server 的 binder_proc.todo 鏈表中;
????????????b. 入 A 棧,test_client.binder_thread.transaction_stack 中:.from = test_client、.to_proc = test_server、.to_thread= test_server;
????????????c. 數據放入 test_server.binder_proc.todo 鏈表中,喚醒 test_server.binder_proc.wait 上的線程。
????????對于 test_server 來說,收到一個 BR_TRANSACTION,那么便在 binder_thread_read 函數中做相關的事情:
????????????a. 從 test_server.binder_proc.todo 鏈表中取出數據,進行處理;
????????????b. 入 B 棧,test_server.binder_thread.transaction_stack 中:.from = test_client、.to_proc = test_server、.to_thread= test_server;
????????對于同一個 binder_transaction 來說,通過 .from_parent 放入發送者的棧,通過 .to_parent 放入接收者的棧。
????????然后 B 向 A 發送一個 BC_REPLY,也是在 binder_transaction 函數中完成的:
????????????a. 從棧中取出 test_server.binder_thread.transaction_stack 中的相關數據(.from、.to_proc、.to_thread),由 .from 可知回復給 test_client;
????????????b. 出棧(test_server),即 test_server.binder_thread.transaction_stack = NULL;
????????????c. 數據 copy_from_user 到 test_client;
????????????d. 出棧(test_client),即 test_client.binder_thread.transaction_stack = NULL;
????????????e. 放入 todo 鏈表,并喚醒。
????????最后進程 A 收到數據后向進程 B 發送一個 BR_REPLY。返回給用戶空間,這塊就不涉及到棧的操作了。
????????至此,兩進程的交互過程已完成。
????上面涉及到的相關代碼如下:
int?svcmgr_publish(struct?binder_state?*bs,?uint32_t?target,?const?char?*name,?void?*ptr) { ????int?status; ????unsigned?iodata[512/4]; ????struct?binder_io?msg,?reply; ????bio_init(&msg,?iodata,?sizeof(iodata),?4); ????bio_put_uint32(&msg,?0);??//?strict?mode?header ????bio_put_string16_x(&msg,?SVC_MGR_NAME); ????bio_put_string16_x(&msg,?name); ????bio_put_obj(&msg,?ptr); ????if?(binder_call(bs,?&msg,?&reply,?target,?SVC_MGR_ADD_SERVICE))????//?注冊服務 ????????return?-1; ????status?=?bio_get_uint32(&reply); ????binder_done(bs,?&msg,?&reply); ????return?status; }
binder_call 函數如下
int?binder_call(struct?binder_state?*bs, ????????????????struct?binder_io?*msg,?struct?binder_io?*reply, ????????????????uint32_t?target,?uint32_t?code) { ????int?res; ????struct?binder_write_read?bwr; ????struct?{ ????????uint32_t?cmd; ????????struct?binder_transaction_data?txn; ????}?__attribute__((packed))?writebuf; ????unsigned?readbuf[32]; ????if?(msg->flags?&?BIO_F_OVERFLOW)?{ ????????fprintf(stderr,"binder:?txn?buffer?overflow\n"); ????????goto?fail; ????} ????//?構造參數 ????writebuf.cmd?=?BC_TRANSACTION; ????writebuf.txn.target.handle?=?target; ????writebuf.txn.code?=?code; ????writebuf.txn.flags?=?0; ????writebuf.txn.data_size?=?msg->data?-?msg->data0; ????writebuf.txn.offsets_size?=?((char*)?msg->offs)?-?((char*)?msg->offs0); ????writebuf.txn.data.ptr.buffer?=?(uintptr_t)msg->data0; ????writebuf.txn.data.ptr.offsets?=?(uintptr_t)msg->offs0; ????bwr.write_size?=?sizeof(writebuf); ????bwr.write_consumed?=?0; ????bwr.write_buffer?=?(uintptr_t)?&writebuf; ????hexdump(msg->data0,?msg->data?-?msg->data0); ????for?(;;)?{ ????????bwr.read_size?=?sizeof(readbuf); ????????bwr.read_consumed?=?0; ????????bwr.read_buffer?=?(uintptr_t)?readbuf; ????????res?=?ioctl(bs->fd,?BINDER_WRITE_READ,?&bwr);????//?調用?ioctl?發數據 ????????if?(res?<?0)?{ ????????????fprintf(stderr,"binder:?ioctl?failed?(%s)\n",?strerror(errno)); ????????????goto?fail; ????????} ????????res?=?binder_parse(bs,?reply,?(uintptr_t)?readbuf,?bwr.read_consumed,?0); ????????if?(res?==?0)?return?0; ????????if?(res?<?0)?goto?fail; ????} fail: ????memset(reply,?0,?sizeof(*reply)); ????reply->flags?|=?BIO_F_IOERROR; ????return?-1; }
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_work?*tcomplete; ????size_t?*offp,?*off_end; ????size_t?off_min; ????struct?binder_proc?*target_proc; ????struct?binder_thread?*target_thread?=?NULL; ????struct?binder_node?*target_node?=?NULL; ????struct?list_head?*target_list; ????wait_queue_head_t?*target_wait; ????struct?binder_transaction?*in_reply_to?=?NULL; ????struct?binder_transaction_log_entry?*e; ????uint32_t?return_error?=?BR_OK; ????e?=?binder_transaction_log_add(&binder_transaction_log); ????e->call_type?=?reply???2?:?!!(tr->flags?&?TF_ONE_WAY); ????e->from_proc?=?proc->pid; ????e->from_thread?=?thread->pid; ????e->target_handle?=?tr->target.handle; ????e->data_size?=?tr->data_size; ????e->offsets_size?=?tr->offsets_size; ????if?(reply)?{ ????????in_reply_to?=?thread->transaction_stack; ????????if?(in_reply_to?==?NULL)?{ ????????????binder_user_error("binder:?%d:%d?got?reply?transaction?" ??????????????????????"with?no?transaction?stack\n", ??????????????????????proc->pid,?thread->pid); ????????????return_error?=?BR_FAILED_REPLY; ????????????goto?err_empty_call_stack; ????????} ????????binder_set_nice(in_reply_to->saved_priority); ????????if?(in_reply_to->to_thread?!=?thread)?{ ????????????binder_user_error("binder:?%d:%d?got?reply?transaction?" ????????????????"with?bad?transaction?stack," ????????????????"?transaction?%d?has?target?%d:%d\n", ????????????????proc->pid,?thread->pid,?in_reply_to->debug_id, ????????????????in_reply_to->to_proc?? ????????????????in_reply_to->to_proc->pid?:?0, ????????????????in_reply_to->to_thread?? ????????????????in_reply_to->to_thread->pid?:?0); ????????????return_error?=?BR_FAILED_REPLY; ????????????in_reply_to?=?NULL; ????????????goto?err_bad_call_stack; ????????} ????????thread->transaction_stack?=?in_reply_to->to_parent; ????????target_thread?=?in_reply_to->from; ????????if?(target_thread?==?NULL)?{ ????????????return_error?=?BR_DEAD_REPLY; ????????????goto?err_dead_binder; ????????} ????????if?(target_thread->transaction_stack?!=?in_reply_to)?{ ????????????binder_user_error("binder:?%d:%d?got?reply?transaction?" ????????????????"with?bad?target?transaction?stack?%d,?" ????????????????"expected?%d\n", ????????????????proc->pid,?thread->pid, ????????????????target_thread->transaction_stack?? ????????????????target_thread->transaction_stack->debug_id?:?0, ????????????????in_reply_to->debug_id); ????????????return_error?=?BR_FAILED_REPLY; ????????????in_reply_to?=?NULL; ????????????target_thread?=?NULL; ????????????goto?err_dead_binder; ????????} ????????target_proc?=?target_thread->proc; ????}?else?{ ????????if?(tr->target.handle)?{ ????????????struct?binder_ref?*ref; ????????????ref?=?binder_get_ref(proc,?tr->target.handle); ????????????if?(ref?==?NULL)?{ ????????????????binder_user_error("binder:?%d:%d?got?" ????????????????????"transaction?to?invalid?handle\n", ????????????????????proc->pid,?thread->pid); ????????????????return_error?=?BR_FAILED_REPLY; ????????????????goto?err_invalid_target_handle; ????????????} ????????????target_node?=?ref->node; ????????}?else?{ ????????????target_node?=?binder_context_mgr_node; ????????????if?(target_node?==?NULL)?{ ????????????????return_error?=?BR_DEAD_REPLY; ????????????????goto?err_no_context_mgr_node; ????????????} ????????} ????????e->to_node?=?target_node->debug_id; ????????target_proc?=?target_node->proc; ????????if?(target_proc?==?NULL)?{ ????????????return_error?=?BR_DEAD_REPLY; ????????????goto?err_dead_binder; ????????} ????????if?(security_binder_transaction(proc->tsk,?target_proc->tsk)?<?0)?{ ????????????return_error?=?BR_FAILED_REPLY; ????????????goto?err_invalid_target_handle; ????????} ????????if?(!(tr->flags?&?TF_ONE_WAY)?&&?thread->transaction_stack)?{ ????????????struct?binder_transaction?*tmp; ????????????tmp?=?thread->transaction_stack; ????????????if?(tmp->to_thread?!=?thread)?{ ????????????????binder_user_error("binder:?%d:%d?got?new?" ????????????????????"transaction?with?bad?transaction?stack" ????????????????????",?transaction?%d?has?target?%d:%d\n", ????????????????????proc->pid,?thread->pid,?tmp->debug_id, ????????????????????tmp->to_proc???tmp->to_proc->pid?:?0, ????????????????????tmp->to_thread?? ????????????????????tmp->to_thread->pid?:?0); ????????????????return_error?=?BR_FAILED_REPLY; ????????????????goto?err_bad_call_stack; ????????????} ????????????while?(tmp)?{ ????????????????if?(tmp->from?&&?tmp->from->proc?==?target_proc) ????????????????????target_thread?=?tmp->from; ????????????????tmp?=?tmp->from_parent; ????????????} ????????} ????} ????if?(target_thread)?{ ????????e->to_thread?=?target_thread->pid; ????????target_list?=?&target_thread->todo; ????????target_wait?=?&target_thread->wait; ????}?else?{ ????????target_list?=?&target_proc->todo; ????????target_wait?=?&target_proc->wait; ????} ????e->to_proc?=?target_proc->pid; ????/*?TODO:?reuse?incoming?transaction?for?reply?*/ ????t?=?kzalloc(sizeof(*t),?GFP_KERNEL); ????if?(t?==?NULL)?{ ????????return_error?=?BR_FAILED_REPLY; ????????goto?err_alloc_t_failed; ????} ????binder_stats_created(BINDER_STAT_TRANSACTION); ????tcomplete?=?kzalloc(sizeof(*tcomplete),?GFP_KERNEL); ????if?(tcomplete?==?NULL)?{ ????????return_error?=?BR_FAILED_REPLY; ????????goto?err_alloc_tcomplete_failed; ????} ????binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE); ????t->debug_id?=?++binder_last_id; ????e->debug_id?=?t->debug_id; ????if?(reply) ????????binder_debug(BINDER_DEBUG_TRANSACTION, ?????????????????"binder:?%d:%d?BC_REPLY?%d?->?%d:%d,?" ?????????????????"data?%p-%p?size?%zd-%zd\n", ?????????????????proc->pid,?thread->pid,?t->debug_id, ?????????????????target_proc->pid,?target_thread->pid, ?????????????????tr->data.ptr.buffer,?tr->data.ptr.offsets, ?????????????????tr->data_size,?tr->offsets_size); ????else ????????binder_debug(BINDER_DEBUG_TRANSACTION, ?????????????????"binder:?%d:%d?BC_TRANSACTION?%d?->?" ?????????????????"%d?-?node?%d,?data?%p-%p?size?%zd-%zd\n", ?????????????????proc->pid,?thread->pid,?t->debug_id, ?????????????????target_proc->pid,?target_node->debug_id, ?????????????????tr->data.ptr.buffer,?tr->data.ptr.offsets, ?????????????????tr->data_size,?tr->offsets_size); ????if?(!reply?&&?!(tr->flags?&?TF_ONE_WAY)) ????????t->from?=?thread; ????else ????????t->from?=?NULL; #if?defined(CONFIG_MACH_P4NOTE)?||?defined(CONFIG_MACH_SP7160LTE)?||?defined(CONFIG_MACH_TAB3)?||?defined(CONFIG_MACH_KONA) ????/*?workaround?code?for?invalid?binder?proc?*/ ????if?(!proc->tsk)?{ ????????binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, ?????????????????"binder:?%d:%d?invalid?proc\n", ?????????????????proc->pid,?thread->pid); ????????return_error?=?BR_FAILED_REPLY; ????????goto?err_binder_alloc_buf_failed; ????} #endif ????t->sender_euid?=?proc->tsk->cred->euid; ????t->to_proc?=?target_proc; ????t->to_thread?=?target_thread; ????t->code?=?tr->code; ????t->flags?=?tr->flags; ????t->priority?=?task_nice(current); ????t->buffer?=?binder_alloc_buf(target_proc,?tr->data_size, ????????tr->offsets_size,?!reply?&&?(t->flags?&?TF_ONE_WAY)); ????if?(t->buffer?==?NULL)?{ ????????return_error?=?BR_FAILED_REPLY; ????????goto?err_binder_alloc_buf_failed; ????} ????t->buffer->allow_user_free?=?0; ????t->buffer->debug_id?=?t->debug_id; ????t->buffer->transaction?=?t; ????t->buffer->target_node?=?target_node; ????if?(target_node) ????????binder_inc_node(target_node,?1,?0,?NULL); ????offp?=?(size_t?*)(t->buffer->data?+?ALIGN(tr->data_size,?sizeof(void?*))); ????if?(copy_from_user(t->buffer->data,?tr->data.ptr.buffer,?tr->data_size))?{ ????????binder_user_error("binder:?%d:%d?got?transaction?with?invalid?" ????????????"data?ptr\n",?proc->pid,?thread->pid); ????????return_error?=?BR_FAILED_REPLY; ????????goto?err_copy_data_failed; ????} ????if?(copy_from_user(offp,?tr->data.ptr.offsets,?tr->offsets_size))?{ ????????binder_user_error("binder:?%d:%d?got?transaction?with?invalid?" ????????????"offsets?ptr\n",?proc->pid,?thread->pid); ????????return_error?=?BR_FAILED_REPLY; ????????goto?err_copy_data_failed; ????} ????if?(!IS_ALIGNED(tr->offsets_size,?sizeof(size_t)))?{ ????????binder_user_error("binder:?%d:%d?got?transaction?with?" ????????????"invalid?offsets?size,?%zd\n", ????????????proc->pid,?thread->pid,?tr->offsets_size); ????????return_error?=?BR_FAILED_REPLY; ????????goto?err_bad_offset; ????} ????off_end?=?(void?*)offp?+?tr->offsets_size; ????off_min?=?0; ????for?(;?offp?<?off_end;?offp++)?{ ????????struct?flat_binder_object?*fp; ????????if?(*offp?>?t->buffer->data_size?-?sizeof(*fp)?|| ????????????*offp?<?off_min?|| ????????????t->buffer->data_size?<?sizeof(*fp)?|| ????????????!IS_ALIGNED(*offp,?sizeof(void?*)))?{ ????????????binder_user_error("%d:%d?got?transaction?with?invalid?offset,?%zd?(min?%zd,?max?%zd)\n", ???????????????????????????????proc->pid,?thread->pid,?*offp,?off_min, ???????????????????????????????(t->buffer->data_size?-?sizeof(*fp))); ????????????return_error?=?BR_FAILED_REPLY; ????????????goto?err_bad_offset; ????????} ????????fp?=?(struct?flat_binder_object?*)(t->buffer->data?+?*offp); ????????off_min?=?*offp?+?sizeof(struct?flat_binder_object); ????????switch?(fp->type)?{ ????????case?BINDER_TYPE_BINDER: ????????case?BINDER_TYPE_WEAK_BINDER:?{ ????????????struct?binder_ref?*ref; ????????????struct?binder_node?*node?=?binder_get_node(proc,?fp->binder); ????????????if?(node?==?NULL)?{ ????????????????node?=?binder_new_node(proc,?fp->binder,?fp->cookie); ????????????????if?(node?==?NULL)?{ ????????????????????return_error?=?BR_FAILED_REPLY; ????????????????????goto?err_binder_new_node_failed; ????????????????} ????????????????node->min_priority?=?fp->flags?&?FLAT_BINDER_FLAG_PRIORITY_MASK; ????????????????node->accept_fds?=?!!(fp->flags?&?FLAT_BINDER_FLAG_ACCEPTS_FDS); ????????????} ????????????if?(fp->cookie?!=?node->cookie)?{ ????????????????binder_user_error("binder:?%d:%d?sending?u%p?" ????????????????????"node?%d,?cookie?mismatch?%p?!=?%p\n", ????????????????????proc->pid,?thread->pid, ????????????????????fp->binder,?node->debug_id, ????????????????????fp->cookie,?node->cookie); ????????????????goto?err_binder_get_ref_for_node_failed; ????????????} ????????????if?(security_binder_transfer_binder(proc->tsk,?target_proc->tsk))?{ ????????????????return_error?=?BR_FAILED_REPLY; ????????????????goto?err_binder_get_ref_for_node_failed; ????????????} ????????????ref?=?binder_get_ref_for_node(target_proc,?node); ????????????if?(ref?==?NULL)?{ ????????????????return_error?=?BR_FAILED_REPLY; ????????????????goto?err_binder_get_ref_for_node_failed; ????????????} ????????????if?(fp->type?==?BINDER_TYPE_BINDER) ????????????????fp->type?=?BINDER_TYPE_HANDLE; ????????????else ????????????????fp->type?=?BINDER_TYPE_WEAK_HANDLE; ????????????fp->handle?=?ref->desc; ????????????binder_inc_ref(ref,?fp->type?==?BINDER_TYPE_HANDLE, ???????????????????????&thread->todo); ????????????binder_debug(BINDER_DEBUG_TRANSACTION, ?????????????????????"????????node?%d?u%p?->?ref?%d?desc?%d\n", ?????????????????????node->debug_id,?node->ptr,?ref->debug_id, ?????????????????????ref->desc); ????????}?break; ????????case?BINDER_TYPE_HANDLE: ????????case?BINDER_TYPE_WEAK_HANDLE:?{ ????????????struct?binder_ref?*ref?=?binder_get_ref(proc,?fp->handle); ????????????if?(ref?==?NULL)?{ ????????????????binder_user_error("binder:?%d:%d?got?" ????????????????????"transaction?with?invalid?" ????????????????????"handle,?%ld\n",?proc->pid, ????????????????????thread->pid,?fp->handle); ????????????????return_error?=?BR_FAILED_REPLY; ????????????????goto?err_binder_get_ref_failed; ????????????} ????????????if?(security_binder_transfer_binder(proc->tsk,?target_proc->tsk))?{ ????????????????return_error?=?BR_FAILED_REPLY; ????????????????goto?err_binder_get_ref_failed; ????????????} ????????????if?(ref->node->proc?==?target_proc)?{ ????????????????if?(fp->type?==?BINDER_TYPE_HANDLE) ????????????????????fp->type?=?BINDER_TYPE_BINDER; ????????????????else ????????????????????fp->type?=?BINDER_TYPE_WEAK_BINDER; ????????????????fp->binder?=?ref->node->ptr; ????????????????fp->cookie?=?ref->node->cookie; ????????????????binder_inc_node(ref->node,?fp->type?==?BINDER_TYPE_BINDER,?0,?NULL); ????????????????binder_debug(BINDER_DEBUG_TRANSACTION, ?????????????????????????"????????ref?%d?desc?%d?->?node?%d?u%p\n", ?????????????????????????ref->debug_id,?ref->desc,?ref->node->debug_id, ?????????????????????????ref->node->ptr); ????????????}?else?{ ????????????????struct?binder_ref?*new_ref; ????????????????new_ref?=?binder_get_ref_for_node(target_proc,?ref->node); ????????????????if?(new_ref?==?NULL)?{ ????????????????????return_error?=?BR_FAILED_REPLY; ????????????????????goto?err_binder_get_ref_for_node_failed; ????????????????} ????????????????fp->handle?=?new_ref->desc; ????????????????binder_inc_ref(new_ref,?fp->type?==?BINDER_TYPE_HANDLE,?NULL); ????????????????binder_debug(BINDER_DEBUG_TRANSACTION, ?????????????????????????"????????ref?%d?desc?%d?->?ref?%d?desc?%d?(node?%d)\n", ?????????????????????????ref->debug_id,?ref->desc,?new_ref->debug_id, ?????????????????????????new_ref->desc,?ref->node->debug_id); ????????????} ????????}?break; ????????case?BINDER_TYPE_FD:?{ ????????????int?target_fd; ????????????struct?file?*file; ????????????if?(reply)?{ ????????????????if?(!(in_reply_to->flags?&?TF_ACCEPT_FDS))?{ ????????????????????binder_user_error("binder:?%d:%d?got?reply?with?fd,?%ld,?but?target?does?not?allow?fds\n", ????????????????????????proc->pid,?thread->pid,?fp->handle); ????????????????????return_error?=?BR_FAILED_REPLY; ????????????????????goto?err_fd_not_allowed; ????????????????} ????????????}?else?if?(!target_node->accept_fds)?{ ????????????????binder_user_error("binder:?%d:%d?got?transaction?with?fd,?%ld,?but?target?does?not?allow?fds\n", ????????????????????proc->pid,?thread->pid,?fp->handle); ????????????????return_error?=?BR_FAILED_REPLY; ????????????????goto?err_fd_not_allowed; ????????????} ????????????file?=?fget(fp->handle); ????????????if?(file?==?NULL)?{ ????????????????binder_user_error("binder:?%d:%d?got?transaction?with?invalid?fd,?%ld\n", ????????????????????proc->pid,?thread->pid,?fp->handle); ????????????????return_error?=?BR_FAILED_REPLY; ????????????????goto?err_fget_failed; ????????????} ????????????if?(security_binder_transfer_file(proc->tsk,?target_proc->tsk,?file)?<?0)?{ ????????????????fput(file); ????????????????return_error?=?BR_FAILED_REPLY; ????????????????goto?err_get_unused_fd_failed; ????????????} ????????????target_fd?=?task_get_unused_fd_flags(target_proc,?O_CLOEXEC); ????????????if?(target_fd?<?0)?{ ????????????????fput(file); ????????????????return_error?=?BR_FAILED_REPLY; ????????????????goto?err_get_unused_fd_failed; ????????????} ????????????task_fd_install(target_proc,?target_fd,?file); ????????????binder_debug(BINDER_DEBUG_TRANSACTION, ?????????????????????"????????fd?%ld?->?%d\n",?fp->handle,?target_fd); ????????????/*?TODO:?fput??*/ ????????????fp->handle?=?target_fd; ????????}?break; ????????default: ????????????binder_user_error("binder:?%d:%d?got?transactio" ????????????????"n?with?invalid?object?type,?%lx\n", ????????????????proc->pid,?thread->pid,?fp->type); ????????????return_error?=?BR_FAILED_REPLY; ????????????goto?err_bad_object_type; ????????} ????} ????if?(reply)?{ ????????BUG_ON(t->buffer->async_transaction?!=?0); ????????binder_pop_transaction(target_thread,?in_reply_to); ????}?else?if?(!(t->flags?&?TF_ONE_WAY))?{ ????????BUG_ON(t->buffer->async_transaction?!=?0); ????????t->need_reply?=?1; ????????t->from_parent?=?thread->transaction_stack; ????????thread->transaction_stack?=?t; ????}?else?{ ????????BUG_ON(target_node?==?NULL); ????????BUG_ON(t->buffer->async_transaction?!=?1); ????????if?(target_node->has_async_transaction)?{ ????????????target_list?=?&target_node->async_todo; ????????????target_wait?=?NULL; ????????}?else ????????????target_node->has_async_transaction?=?1; ????} ????t->work.type?=?BINDER_WORK_TRANSACTION; ????list_add_tail(&t->work.entry,?target_list); ????tcomplete->type?=?BINDER_WORK_TRANSACTION_COMPLETE; ????list_add_tail(&tcomplete->entry,?&thread->todo); ????if?(target_wait) ????????wake_up_interruptible(target_wait); ????return; err_get_unused_fd_failed: err_fget_failed: err_fd_not_allowed: err_binder_get_ref_for_node_failed: err_binder_get_ref_failed: err_binder_new_node_failed: err_bad_object_type: err_bad_offset: err_copy_data_failed: ????binder_transaction_buffer_release(target_proc,?t->buffer,?offp); ????t->buffer->transaction?=?NULL; ????binder_free_buf(target_proc,?t->buffer); err_binder_alloc_buf_failed: ????kfree(tcomplete); ????binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); err_alloc_tcomplete_failed: ????kfree(t); ????binder_stats_deleted(BINDER_STAT_TRANSACTION); err_alloc_t_failed: err_bad_call_stack: err_empty_call_stack: err_dead_binder: err_invalid_target_handle: err_no_context_mgr_node: ????binder_debug(BINDER_DEBUG_FAILED_TRANSACTION, ?????????????"binder:?%d:%d?transaction?failed?%d,?size?%zd-%zd\n", ?????????????proc->pid,?thread->pid,?return_error, ?????????????tr->data_size,?tr->offsets_size); ????{ ????????struct?binder_transaction_log_entry?*fe; ????????fe?=?binder_transaction_log_add(&binder_transaction_log_failed); ????????*fe?=?*e; ????} ????BUG_ON(thread->return_error?!=?BR_OK); ????if?(in_reply_to)?{ ????????thread->return_error?=?BR_TRANSACTION_COMPLETE; ????????binder_send_failed_reply(in_reply_to,?return_error); ????}?else ????????thread->return_error?=?return_error; }
binder_thread_write 函數如下
int?binder_thread_write(struct?binder_proc?*proc,?struct?binder_thread?*thread, ????????????void?__user?*buffer,?int?size,?signed?long?*consumed) { ????uint32_t?cmd; ????void?__user?*ptr?=?buffer?+?*consumed; ????void?__user?*end?=?buffer?+?size; ????while?(ptr?<?end?&&?thread->return_error?==?BR_OK)?{ ????????if?(get_user(cmd,?(uint32_t?__user?*)ptr)) ????????????return?-EFAULT; ????????ptr?+=?sizeof(uint32_t); ????????if?(_IOC_NR(cmd)?<?ARRAY_SIZE(binder_stats.bc))?{ ????????????binder_stats.bc[_IOC_NR(cmd)]++; ????????????proc->stats.bc[_IOC_NR(cmd)]++; ????????????thread->stats.bc[_IOC_NR(cmd)]++; ????????} ????????switch?(cmd)?{ ????????/*?省略無關代碼?*/ ????????case?BC_TRANSACTION: ????????case?BC_REPLY:?{ ????????????struct?binder_transaction_data?tr; ????????????if?(copy_from_user(&tr,?ptr,?sizeof(tr))) ????????????????return?-EFAULT; ????????????ptr?+=?sizeof(tr); ????????????binder_transaction(proc,?thread,?&tr,?cmd?==?BC_REPLY); ????????????break; ????????} ????????/*?省略無關代碼?*/ ????????default: ????????????printk(KERN_ERR?"binder:?%d:%d?unknown?command?%d\n", ???????????????????proc->pid,?thread->pid,?cmd); ????????????return?-EINVAL; ????????} ????????*consumed?=?ptr?-?buffer; ????} ????return?0; }
binder_thread_read 函數如下
static?int?binder_thread_read(struct?binder_proc?*proc, ??????????????????struct?binder_thread?*thread, ??????????????????void??__user?*buffer,?int?size, ??????????????????signed?long?*consumed,?int?non_block) { ????void?__user?*ptr?=?buffer?+?*consumed; ????void?__user?*end?=?buffer?+?size; ????int?ret?=?0; ????int?wait_for_proc_work; ????if?(*consumed?==?0)?{ ????????if?(put_user(BR_NOOP,?(uint32_t?__user?*)ptr)) ????????????return?-EFAULT; ????????ptr?+=?sizeof(uint32_t); ????} retry: ????wait_for_proc_work?=?thread->transaction_stack?==?NULL?&& ????????????????list_empty(&thread->todo); ????if?(thread->return_error?!=?BR_OK?&&?ptr?<?end)?{ ????????if?(thread->return_error2?!=?BR_OK)?{ ????????????if?(put_user(thread->return_error2,?(uint32_t?__user?*)ptr)) ????????????????return?-EFAULT; ????????????ptr?+=?sizeof(uint32_t); ????????????if?(ptr?==?end) ????????????????goto?done; ????????????thread->return_error2?=?BR_OK; ????????} ????????if?(put_user(thread->return_error,?(uint32_t?__user?*)ptr)) ????????????return?-EFAULT; ????????ptr?+=?sizeof(uint32_t); ????????thread->return_error?=?BR_OK; ????????goto?done; ????} ????thread->looper?|=?BINDER_LOOPER_STATE_WAITING; ????if?(wait_for_proc_work) ????????proc->ready_threads++; ????binder_unlock(__func__); ????if?(wait_for_proc_work)?{ ????????if?(!(thread->looper?&?(BINDER_LOOPER_STATE_REGISTERED?| ????????????????????BINDER_LOOPER_STATE_ENTERED)))?{ ????????????binder_user_error("binder:?%d:%d?ERROR:?Thread?waiting?" ????????????????"for?process?work?before?calling?BC_REGISTER_" ????????????????"LOOPER?or?BC_ENTER_LOOPER?(state?%x)\n", ????????????????proc->pid,?thread->pid,?thread->looper); ????????????wait_event_interruptible(binder_user_error_wait, ?????????????????????????binder_stop_on_user_error?<?2); ????????} ????????binder_set_nice(proc->default_priority); ????????if?(non_block)?{ ????????????if?(!binder_has_proc_work(proc,?thread)) ????????????????ret?=?-EAGAIN; ????????}?else ????????????ret?=?wait_event_interruptible_exclusive(proc->wait,?binder_has_proc_work(proc,?thread)); ????}?else?{ ????????if?(non_block)?{ ????????????if?(!binder_has_thread_work(thread)) ????????????????ret?=?-EAGAIN; ????????}?else ????????????ret?=?wait_event_interruptible(thread->wait,?binder_has_thread_work(thread)); ????} ????binder_lock(__func__); ????if?(wait_for_proc_work) ????????proc->ready_threads--; ????thread->looper?&=?~BINDER_LOOPER_STATE_WAITING; ????if?(ret) ????????return?ret; ????while?(1)?{ ????????uint32_t?cmd; ????????struct?binder_transaction_data?tr; ????????struct?binder_work?*w; ????????struct?binder_transaction?*t?=?NULL; ????????if?(!list_empty(&thread->todo)) ????????????w?=?list_first_entry(&thread->todo,?struct?binder_work,?entry); ????????else?if?(!list_empty(&proc->todo)?&&?wait_for_proc_work) ????????????w?=?list_first_entry(&proc->todo,?struct?binder_work,?entry); ????????else?{ ????????????if?(ptr?-?buffer?==?4?&&?!(thread->looper?&?BINDER_LOOPER_STATE_NEED_RETURN))?/*?no?data?added?*/ ????????????????goto?retry; ????????????break; ????????} ????????if?(end?-?ptr?<?sizeof(tr)?+?4) ????????????break; ????????switch?(w->type)?{ ????????case?BINDER_WORK_TRANSACTION:?{ ????????????t?=?container_of(w,?struct?binder_transaction,?work); ????????}?break; ????????case?BINDER_WORK_TRANSACTION_COMPLETE:?{ ????????????cmd?=?BR_TRANSACTION_COMPLETE; ????????????if?(put_user(cmd,?(uint32_t?__user?*)ptr)) ????????????????return?-EFAULT; ????????????ptr?+=?sizeof(uint32_t); ????????????binder_stat_br(proc,?thread,?cmd); ????????????binder_debug(BINDER_DEBUG_TRANSACTION_COMPLETE, ?????????????????????"binder:?%d:%d?BR_TRANSACTION_COMPLETE\n", ?????????????????????proc->pid,?thread->pid); ????????????list_del(&w->entry); ????????????kfree(w); ????????????binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); ????????}?break; ????????case?BINDER_WORK_NODE:?{ ????????????struct?binder_node?*node?=?container_of(w,?struct?binder_node,?work); ????????????uint32_t?cmd?=?BR_NOOP; ????????????const?char?*cmd_name; ????????????int?strong?=?node->internal_strong_refs?||?node->local_strong_refs; ????????????int?weak?=?!hlist_empty(&node->refs)?||?node->local_weak_refs?||?strong; ????????????if?(weak?&&?!node->has_weak_ref)?{ ????????????????cmd?=?BR_INCREFS; ????????????????cmd_name?=?"BR_INCREFS"; ????????????????node->has_weak_ref?=?1; ????????????????node->pending_weak_ref?=?1; ????????????????node->local_weak_refs++; ????????????}?else?if?(strong?&&?!node->has_strong_ref)?{ ????????????????cmd?=?BR_ACQUIRE; ????????????????cmd_name?=?"BR_ACQUIRE"; ????????????????node->has_strong_ref?=?1; ????????????????node->pending_strong_ref?=?1; ????????????????node->local_strong_refs++; ????????????}?else?if?(!strong?&&?node->has_strong_ref)?{ ????????????????cmd?=?BR_RELEASE; ????????????????cmd_name?=?"BR_RELEASE"; ????????????????node->has_strong_ref?=?0; ????????????}?else?if?(!weak?&&?node->has_weak_ref)?{ ????????????????cmd?=?BR_DECREFS; ????????????????cmd_name?=?"BR_DECREFS"; ????????????????node->has_weak_ref?=?0; ????????????} ????????????if?(cmd?!=?BR_NOOP)?{ ????????????????if?(put_user(cmd,?(uint32_t?__user?*)ptr)) ????????????????????return?-EFAULT; ????????????????ptr?+=?sizeof(uint32_t); ????????????????if?(put_user(node->ptr,?(void?*?__user?*)ptr)) ????????????????????return?-EFAULT; ????????????????ptr?+=?sizeof(void?*); ????????????????if?(put_user(node->cookie,?(void?*?__user?*)ptr)) ????????????????????return?-EFAULT; ????????????????ptr?+=?sizeof(void?*); ????????????????binder_stat_br(proc,?thread,?cmd); ????????????????binder_debug(BINDER_DEBUG_USER_REFS, ?????????????????????????"binder:?%d:%d?%s?%d?u%p?c%p\n", ?????????????????????????proc->pid,?thread->pid,?cmd_name,?node->debug_id,?node->ptr,?node->cookie); ????????????}?else?{ ????????????????list_del_init(&w->entry); ????????????????if?(!weak?&&?!strong)?{ ????????????????????binder_debug(BINDER_DEBUG_INTERNAL_REFS, ?????????????????????????????"binder:?%d:%d?node?%d?u%p?c%p?deleted\n", ?????????????????????????????proc->pid,?thread->pid,?node->debug_id, ?????????????????????????????node->ptr,?node->cookie); ????????????????????rb_erase(&node->rb_node,?&proc->nodes); ????????????????????kfree(node); ????????????????????binder_stats_deleted(BINDER_STAT_NODE); ????????????????}?else?{ ????????????????????binder_debug(BINDER_DEBUG_INTERNAL_REFS, ?????????????????????????????"binder:?%d:%d?node?%d?u%p?c%p?state?unchanged\n", ?????????????????????????????proc->pid,?thread->pid,?node->debug_id,?node->ptr, ?????????????????????????????node->cookie); ????????????????} ????????????} ????????}?break; ????????case?BINDER_WORK_DEAD_BINDER: ????????case?BINDER_WORK_DEAD_BINDER_AND_CLEAR: ????????case?BINDER_WORK_CLEAR_DEATH_NOTIFICATION:?{ ????????????struct?binder_ref_death?*death; ????????????uint32_t?cmd; ????????????death?=?container_of(w,?struct?binder_ref_death,?work); ????????????if?(w->type?==?BINDER_WORK_CLEAR_DEATH_NOTIFICATION) ????????????????cmd?=?BR_CLEAR_DEATH_NOTIFICATION_DONE; ????????????else ????????????????cmd?=?BR_DEAD_BINDER; ????????????if?(put_user(cmd,?(uint32_t?__user?*)ptr)) ????????????????return?-EFAULT; ????????????ptr?+=?sizeof(uint32_t); ????????????if?(put_user(death->cookie,?(void?*?__user?*)ptr)) ????????????????return?-EFAULT; ????????????ptr?+=?sizeof(void?*); ????????????binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION, ?????????????????????"binder:?%d:%d?%s?%p\n", ??????????????????????proc->pid,?thread->pid, ??????????????????????cmd?==?BR_DEAD_BINDER?? ??????????????????????"BR_DEAD_BINDER"?: ??????????????????????"BR_CLEAR_DEATH_NOTIFICATION_DONE", ??????????????????????death->cookie); ????????????if?(w->type?==?BINDER_WORK_CLEAR_DEATH_NOTIFICATION)?{ ????????????????list_del(&w->entry); ????????????????kfree(death); ????????????????binder_stats_deleted(BINDER_STAT_DEATH); ????????????}?else ????????????????list_move(&w->entry,?&proc->delivered_death); ????????????if?(cmd?==?BR_DEAD_BINDER) ????????????????goto?done;?/*?DEAD_BINDER?notifications?can?cause?transactions?*/ ????????}?break; ????????} ????????if?(!t) ????????????continue; ????????BUG_ON(t->buffer?==?NULL); ????????if?(t->buffer->target_node)?{ ????????????struct?binder_node?*target_node?=?t->buffer->target_node; ????????????tr.target.ptr?=?target_node->ptr; ????????????tr.cookie?=??target_node->cookie; ????????????t->saved_priority?=?task_nice(current); ????????????if?(t->priority?<?target_node->min_priority?&& ????????????????!(t->flags?&?TF_ONE_WAY)) ????????????????binder_set_nice(t->priority); ????????????else?if?(!(t->flags?&?TF_ONE_WAY)?|| ?????????????????t->saved_priority?>?target_node->min_priority) ????????????????binder_set_nice(target_node->min_priority); ????????????cmd?=?BR_TRANSACTION; ????????}?else?{ ????????????tr.target.ptr?=?NULL; ????????????tr.cookie?=?NULL; ????????????cmd?=?BR_REPLY; ????????} ????????tr.code?=?t->code; ????????tr.flags?=?t->flags; ????????tr.sender_euid?=?t->sender_euid; ????????if?(t->from)?{ ????????????struct?task_struct?*sender?=?t->from->proc->tsk; ????????????tr.sender_pid?=?task_tgid_nr_ns(sender, ????????????????????????????current->nsproxy->pid_ns); ????????}?else?{ ????????????tr.sender_pid?=?0; ????????} ????????tr.data_size?=?t->buffer->data_size; ????????tr.offsets_size?=?t->buffer->offsets_size; ????????tr.data.ptr.buffer?=?(void?*)t->buffer->data?+ ????????????????????proc->user_buffer_offset; ????????tr.data.ptr.offsets?=?tr.data.ptr.buffer?+ ????????????????????ALIGN(t->buffer->data_size, ????????????????????????sizeof(void?*)); ????????if?(put_user(cmd,?(uint32_t?__user?*)ptr)) ????????????return?-EFAULT; ????????ptr?+=?sizeof(uint32_t); ????????if?(copy_to_user(ptr,?&tr,?sizeof(tr))) ????????????return?-EFAULT; ????????ptr?+=?sizeof(tr); ????????binder_stat_br(proc,?thread,?cmd); ????????binder_debug(BINDER_DEBUG_TRANSACTION, ?????????????????"binder:?%d:%d?%s?%d?%d:%d,?cmd?%d" ?????????????????"size?%zd-%zd?ptr?%p-%p\n", ?????????????????proc->pid,?thread->pid, ?????????????????(cmd?==?BR_TRANSACTION)???"BR_TRANSACTION"?: ?????????????????"BR_REPLY", ?????????????????t->debug_id,?t->from???t->from->proc->pid?:?0, ?????????????????t->from???t->from->pid?:?0,?cmd, ?????????????????t->buffer->data_size,?t->buffer->offsets_size, ?????????????????tr.data.ptr.buffer,?tr.data.ptr.offsets); ????????list_del(&t->work.entry); ????????t->buffer->allow_user_free?=?1; ????????if?(cmd?==?BR_TRANSACTION?&&?!(t->flags?&?TF_ONE_WAY))?{ ????????????t->to_parent?=?thread->transaction_stack; ????????????t->to_thread?=?thread; ????????????thread->transaction_stack?=?t; ????????}?else?{ ????????????t->buffer->transaction?=?NULL; ????????????kfree(t); ????????????binder_stats_deleted(BINDER_STAT_TRANSACTION); ????????} ????????break; ????} done: ????*consumed?=?ptr?-?buffer; ????if?(proc->requested_threads?+?proc->ready_threads?==?0?&& ????????proc->requested_threads_started?<?proc->max_threads?&& ????????(thread->looper?&?(BINDER_LOOPER_STATE_REGISTERED?| ?????????BINDER_LOOPER_STATE_ENTERED))?/*?the?user-space?code?fails?to?*/ ?????????/*spawn?a?new?thread?if?we?leave?this?out?*/)?{ ????????proc->requested_threads++; ????????binder_debug(BINDER_DEBUG_THREADS, ?????????????????"binder:?%d:%d?BR_SPAWN_LOOPER\n", ?????????????????proc->pid,?thread->pid); ????????if?(put_user(BR_SPAWN_LOOPER,?(uint32_t?__user?*)buffer)) ????????????return?-EFAULT; ????} ????return?0; }
??????? 前面我們分析的是 binder transaction stack 機制,接下來看下 transaction stack 機制雙向服務。
????????此時如果有 3 個進程:P1 進程提供 S1 服務,線程用 t1, t1' ... 表示;P2 進程提供 S2 服務,線程用 t2, t2' ... 表示;P3 進程提供 S3 服務,線程用 t3, t3' ... 表示;假設 t1 ==> t2 ==> t3,那么 t3 把數據發給誰?那么 t3 把數據放到 P1 的 binder_proc.todo 鏈表,讓 P1 使用新線程 t1' 來處理,還是把數據放到 t1 的 binder_thread.todo 鏈表,讓 t1 來處理呢?
??????? 從進程 A 到進程 B:
????????????1. 進程 A 發送 BC_TRANSACTION,TR 通過 from_parent 入棧;
????????????2. 進程 B 回復 BR_TRANSACTION,TR 通過 to_parent 入棧;
????????????3. 進程 B 發送 BC_REPLY,TR 通過 to_parent 入棧,TR通 過 from_parent 出棧;
????????????4. 進程 A 回復 BR_REPLY;
????????從 t1 ==> t2: t1.sp -> TR1.from_parent -> NULL;
????????????TR1.from = t1, TR1.to_proc = P2;
????????從 t2 ==> t3: t2.sp -> TR1.to_parent -> NULL;t2.sp -> TR2.from_parent -> TR1.to_parent -> NULL;
????????????TR1.from = t1, TR1.to_proc = P2;
????????從 t3 ==> ?: t3.sp -> TR2.to_parent -> NULL;我們先來分析下 binder_transaction 函數中下面這段代碼
while?(tmp)?{ ????if?(tmp->from?&&?tmp->from->proc?==?target_proc) ????????target_thread?=?tmp->from; ????tmp?=?tmp->from_parent; }
????????????a. TR2 -> from = t2 -> proc = P2;
????????????b. tmp = TR1
????????????c. TR1 -> from = t1 -> proc = P1;target_thread = t1。
????????從這里我們就可以知道 t3 發給的是 t1,因此 TR2.from_parent -> TR1.from_parent -> NULL;t3.sp -> TR3.from_parent -> TR2.to_parent -> NULL;
????????那么 t1 收到 t3 的 BR_TRANSACTION,t1.sp -> TR3.to_parent -> TR1.from_parent -> NULL;
????????t1 發出 BC_REPLY,t1.sp -> TR1.from_parent -> NULL 入棧;t3.sp -> TR2.to_parent -> NULL 出棧;
????????t3 收到 BR_REPLY,處理 TR2,發出 BC_REPLY。t3.sp -> TR2.to_parent -> NULL;從 t3.sp 中,取出 TR2,TR2.from = t2,所以回復 t2;t3.sp -> NULL 出棧,t2.sp -> TR1.to_parent -> NULL。
????????t2 收到 BR_REPLY,處理 TR1,發出 BR_REPLY。從 t2.sp 中取出棧頂,TR1.from = t1,所以回復 t1;t2.sp = NULL,t1.sp = NULL;
????????t1 收到 BR_REPLY,處理完畢。
????????
????????那么 binder_server 的多線程是怎么工作的,client 發出請求,server 提供服務。如果 server 忙不過來時,創建多線程:
????????????1. 驅動判斷是否“忙不過來”;
????????????2. 驅動向 APP 發請求,創建新線程;
????????????3. APP 創建新線程。
????????代碼如下:
if?(proc->requested_threads?+?proc->ready_threads?==?0?&& ????proc->requested_threads_started?<?proc->max_threads?&& ????(thread->looper?&?(BINDER_LOOPER_STATE_REGISTERED?| ????BINDER_LOOPER_STATE_ENTERED))?/*?the?user-space?code?fails?to?*/ ?????/*spawn?a?new?thread?if?we?leave?this?out?*/)?{ ????proc->requested_threads++; ????binder_debug(BINDER_DEBUG_THREADS, ?????????"binder:?%d:%d?BR_SPAWN_LOOPER\n", ?????????proc->pid,?thread->pid); ????if?(put_user(BR_SPAWN_LOOPER,?(uint32_t?__user?*)buffer)) ????????return?-EFAULT; }
????驅動向 APP 發出“創建新線程請求”的條件:
????????1. proc->requested_treads = 0;“未處理的新線程請求”= 0
????????2. proc->requesteds = 0,空閑線程數為 0
????????3. 已啟動的線程數 < max_threads
??? 那么怎么寫 APP 呢?
????????1. 設置 max_threads
????????2. 收到 BR_SPAWN_LOOPER 后,創建新線程
????????3. 新線程發出 ioctl:BC_REGISTER_LOOPER
????????4. 像主線程一樣,進入一個循環:read driver,處理。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。