日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析(2)...

發布時間:2025/3/8 Android 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析(2)... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

注意,這里的參數reply = 0,表示這是一個BC_TRANSACTION命令。
??????? 前面我們提到,傳給驅動程序的handle值為0,即這里的tr->target.handle = 0,表示請求的目標Binder對象是Service Manager,因此有:


?

  • target_node?=?binder_context_mgr_node; ?
  • target_proc?=?target_node->proc; ?
  • target_list?=?&target_proc->todo; ?
  • target_wait?=?&target_proc->wait;?
  • ???? 其中binder_context_mgr_node是在Service Manager通知Binder驅動程序它是守護過程時創建的。

    ??????? 接著創建一個待完成事項tcomplete,它的類型為struct binder_work,這是等一會要保存在當前線程的todo隊列去的,表示當前線程有一個待完成的事務。緊跟著創建一個待處理事務t,它的類型為struct binder_transaction,這是等一會要存在到Service Manager的todo隊列去的,表示Service Manager當前有一個事務需要處理。同時,這個待處理事務t也要存放在當前線程的待完成事務transaction_stack列表中去:


    ?

  • t->from_parent?=?thread->transaction_stack; ?
  • thread->transaction_stack?=?t;?
  • ? 這樣表明當前線程還有事務要處理。

    ??????? 繼續往下看,就是分別把tcomplete和t放在當前線程thread和Service Manager進程的todo隊列去了:


    ?

  • 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);?
  • ????? 最后,Service Manager有事情可做了,就要喚醒它了:

  • wake_up_interruptible(target_wait);?
  • ?? 前面我們提到,此時Service Manager正在等待Client的請求,也就是Service Manager此時正在進入到Binder驅動程序的binder_thread_read函數中,并且休眠在target->wait上,具體參考淺談Service Manager成為Android進程間通信(IPC)機制Binder守護進程之路一文。
    ??????? 這里,我們暫時忽略Service Manager被喚醒之后的情景,繼續看當前線程的執行。
    ??????? 函數binder_transaction執行完成之后,就一路返回到binder_ioctl函數里去了。函數binder_ioctl從binder_thread_write函數調用處返回后,發現bwr.read_size大于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?(wait_for_proc_work)?{ ?
  • ????????...... ?
  • ????}?else?{ ?
  • ????????if?(non_block)?{ ?
  • ????????????if?(!binder_has_thread_work(thread)) ?
  • ????????????????ret?=?-EAGAIN; ?
  • ????????}?else?
  • ????????????ret?=?wait_event_interruptible(thread->wait,?binder_has_thread_work(thread)); ?
  • ????} ?
  • ?
  • ????...... ?
  • ?
  • ????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_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); ?
  • ????????????if?(binder_debug_mask?&?BINDER_DEBUG_TRANSACTION_COMPLETE) ?
  • ????????????????printk(KERN_INFO?"binder:?%d:%d?BR_TRANSACTION_COMPLETE\n", ?
  • ????????????????proc->pid,?thread->pid); ?
  • ?
  • ????????????list_del(&w->entry); ?
  • ????????????kfree(w); ?
  • ????????????binder_stats.obj_deleted[BINDER_STAT_TRANSACTION_COMPLETE]++; ?
  • ???????????????????????????????????????????????}?break; ?
  • ????????...... ?
  • ????????} ?
  • ?
  • ????????if?(!t) ?
  • ????????????continue; ?
  • ?
  • ????????...... ?
  • ????} ?
  • ?
  • done: ?
  • ????...... ?
  • ????return?0; ?
  • }?
  • 函數首先是寫入一個操作碼BR_NOOP到用戶傳進來的緩沖區中去。

    ????? 回憶一下上面的binder_transaction函數,這里的thread->transaction_stack != NULL,并且thread->todo也不為空,所以線程不會進入休眠狀態。

    ????? 進入while循環中,首先是從thread->todo隊列中取回待處理事項w,w的類型為BINDER_WORK_TRANSACTION_COMPLETE,這也是在binder_transaction函數里面設置的。對BINDER_WORK_TRANSACTION_COMPLETE的處理也很簡單,只是把一個操作碼BR_TRANSACTION_COMPLETE寫回到用戶傳進來的緩沖區中去。這時候,用戶傳進來的緩沖區就包含兩個操作碼了,分別是BR_NOOP和BINDER_WORK_TRANSACTION_COMPLETE。

    ????? binder_thread_read執行完之后,返回到binder_ioctl函數中,將操作結果寫回到用戶空間中去:


    ?

  • if?(copy_to_user(ubuf,?&bwr,?sizeof(bwr)))?{ ?
  • ????ret?=?-EFAULT; ?
  • ????goto?err; ?
  • }?
  • ??? 最后就返回到IPCThreadState::talkWithDriver函數中了。

    ?????? IPCThreadState::talkWithDriver函數從下面語句:


    ?

  • ioctl(mProcess->mDriverFD,?BINDER_WRITE_READ,?&bwr)?
  • ?? 返回后,首先是清空之前寫入Binder驅動程序的內容:


    ?

  • if?(bwr.write_consumed?>?0)?{ ?
  • ?????if?(bwr.write_consumed?<?(ssize_t)mOut.dataSize()) ?
  • ??????????mOut.remove(0,?bwr.write_consumed); ?
  • ?????else?
  • ??????????mOut.setDataSize(0); ?
  • }?
  • ?? 接著是設置從Binder驅動程序讀取的內容:

  • if?(bwr.read_consumed?>?0)?{ ?
  • ?????mIn.setDataSize(bwr.read_consumed); ?
  • ?????mIn.setDataPosition(0); ?
  • }?
  • ? 然后就返回到IPCThreadState::waitForResponse去了。IPCThreadState::waitForResponse函數的處理也很簡單,就是處理剛才從Binder驅動程序讀入內容了。從前面的分析中,我們知道,從Binder驅動程序讀入的內容就是兩個整數了,分別是BR_NOOP和BR_TRANSACTION_COMPLETE。對BR_NOOP的處理很簡單,正如它的名字所示,什么也不做;而對BR_TRANSACTION_COMPLETE的處理,就分情況了,如果這個請求是異步的,那個整個BC_TRANSACTION操作就完成了,如果這個請求是同步的,即要等待回復的,也就是reply不為空,那么還要繼續通過IPCThreadState::talkWithDriver進入到Binder驅動程序中去等待BC_TRANSACTION操作的處理結果。

    ????? 這里屬于后一種情況,于是再次通過IPCThreadState::talkWithDriver進入到Binder驅動程序的binder_ioctl函數中。不過這一次在binder_ioctl函數中,bwr.write_size等于0,而bwr.read_size大于0,于是再次進入到binder_thread_read函數中。這時候thread->transaction_stack仍然不為NULL,不過thread->todo隊列已經為空了,因為前面我們已經處理過thread->todo隊列的內容了,于是就通過下面語句:


    ?

  • ret?=?wait_event_interruptible(thread->wait,?binder_has_thread_work(thread));?
  • ??? 進入休眠狀態了,等待Service Manager的喚醒。

    ????? 現在,我們終于可以回到Service Manager被喚醒之后的過程了。前面我們說過,Service Manager此時正在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?(wait_for_proc_work)?{ ?
  • ????????...... ?
  • ????????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?{ ?
  • ????????...... ?
  • ????} ?
  • ???? ?
  • ????...... ?
  • ?
  • ????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; ?
  • ????????...... ?
  • ????????} ?
  • ?
  • ????????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.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.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); ?
  • ?
  • ????????...... ?
  • ?
  • ????????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?{ ?
  • ????????????...... ?
  • ????????} ?
  • ????????break; ?
  • ????} ?
  • ?
  • done: ?
  • ?
  • ????*consumed?=?ptr?-?buffer; ?
  • ????...... ?
  • ????return?0; ?
  • }?
  • 這里就是從語句中喚醒了:


    ?

  • ret?=?wait_event_interruptible_exclusive(proc->wait,?binder_has_proc_work(proc,?thread));?
  • ?? Service Manager喚醒過來看,繼續往下執行,進入到while循環中。首先是從proc->todo中取回待處理事項w。這個事項w的類型是BINDER_WORK_TRANSACTION,這是上面調用binder_transaction的時候設置的,于是通過w得到待處理事務t:


    ?

  • t?=?container_of(w,?struct?binder_transaction,?work);?
  • ?? 接下來的內容,就把cmd和t->buffer的內容拷貝到用戶傳進來的緩沖區去了,這里就是Service Manager從用戶空間傳進來的緩沖區了:


    ?

  • 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);?
  • ?? 注意,這里先是把t->buffer的內容拷貝到本地變量tr中,再拷貝到用戶空間緩沖區去。關于t->buffer內容的拷貝,請參考Android系統進程間通信(IPC)機制Binder中的Server啟動過程源代碼分析一文,它的一個關鍵地方是Binder驅動程序和Service Manager守護進程共享了同一個物理內存的內容,拷貝的只是這個物理內存在用戶空間的虛擬地址回去:


    ?

  • 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?*));?
  • ??? 對于Binder驅動程序這次操作來說,這個事項就算是處理完了,就要從todo隊列中刪除了:

  • list_del(&t->work.entry);?
  • 緊接著,還不放刪除這個事務,因為它還要等待Service Manager處理完成后,再進一步處理,因此,放在thread->transaction_stack隊列中:


    ?

  • t->to_parent?=?thread->transaction_stack; ?
  • t->to_thread?=?thread; ?
  • thread->transaction_stack?=?t;?
  • 還要注意的一個地方是,上面寫入的cmd = BR_TRANSACTION,告訴Service Manager守護進程,它要做什么事情,后面我們會看到相應的分析。

    ?????? 這樣,binder_thread_read函數就處理完了,回到binder_ioctl函數中,同樣是操作結果寫回到用戶空間的緩沖區中去:

  • if?(copy_to_user(ubuf,?&bwr,?sizeof(bwr)))?{ ?
  • ????ret?=?-EFAULT; ?
  • ????goto?err; ?
  • }?
  • ? 最后,就返回到frameworks/base/cmds/servicemanager/binder.c文件中的binder_loop函數去了:


    ?

  • void?binder_loop(struct?binder_state?*bs,?binder_handler?func) ?
  • { ?
  • ????int?res; ?
  • ????struct?binder_write_read?bwr; ?
  • ????unsigned?readbuf[32]; ?
  • ?
  • ????bwr.write_size?=?0; ?
  • ????bwr.write_consumed?=?0; ?
  • ????bwr.write_buffer?=?0; ?
  • ???? ?
  • ????readbuf[0]?=?BC_ENTER_LOOPER; ?
  • ????binder_write(bs,?readbuf,?sizeof(unsigned)); ?
  • ?
  • ????for?(;;)?{ ?
  • ????????bwr.read_size?=?sizeof(readbuf); ?
  • ????????bwr.read_consumed?=?0; ?
  • ????????bwr.read_buffer?=?(unsigned)?readbuf; ?
  • ?
  • ????????res?=?ioctl(bs->fd,?BINDER_WRITE_READ,?&bwr); ?
  • ?
  • ????????if?(res?<?0)?{ ?
  • ????????????LOGE("binder_loop:?ioctl?failed?(%s)\n",?strerror(errno)); ?
  • ????????????break; ?
  • ????????} ?
  • ?
  • ????????res?=?binder_parse(bs,?0,?readbuf,?bwr.read_consumed,?func); ?
  • ????????if?(res?==?0)?{ ?
  • ????????????LOGE("binder_loop:?unexpected?reply?!\n"); ?
  • ????????????break; ?
  • ????????} ?
  • ????????if?(res?<?0)?{ ?
  • ????????????LOGE("binder_loop:?io?error?%d?%s\n",?res,?strerror(errno)); ?
  • ????????????break; ?
  • ????????} ?
  • ????} ?
  • }?
  • ?? 這里就是從下面的語句:


    ?

  • res?=?ioctl(bs->fd,?BINDER_WRITE_READ,?&bwr);?
  • ???? 返回來了。接著就進入binder_parse函數處理從Binder驅動程序里面讀取出來的數據:


    ?

  • int?binder_parse(struct?binder_state?*bs,?struct?binder_io?*bio, ?
  • ?????????????????uint32_t?*ptr,?uint32_t?size,?binder_handler?func) ?
  • { ?
  • ????int?r?=?1; ?
  • ????uint32_t?*end?=?ptr?+?(size?/?4); ?
  • ?
  • ????while?(ptr?<?end)?{ ?
  • ????????uint32_t?cmd?=?*ptr++; ?
  • ????????switch(cmd)?{ ?
  • ????????...... ?
  • ????????case?BR_TRANSACTION:?{ ?
  • ????????????struct?binder_txn?*txn?=?(void?*)?ptr; ?
  • ????????????...... ?
  • ????????????if?(func)?{ ?
  • ????????????????unsigned?rdata[256/4]; ?
  • ????????????????struct?binder_io?msg; ?
  • ????????????????struct?binder_io?reply; ?
  • ????????????????int?res; ?
  • ?
  • ????????????????bio_init(&reply,?rdata,?sizeof(rdata),?4); ?
  • ????????????????bio_init_from_txn(&msg,?txn); ?
  • ????????????????res?=?func(bs,?txn,?&msg,?&reply); ?
  • ????????????????binder_send_reply(bs,?&reply,?txn->data,?res); ?
  • ????????????} ?
  • ????????????ptr?+=?sizeof(*txn)?/?sizeof(uint32_t); ?
  • ????????????break; ?
  • ?????????????????????????????} ?
  • ????????...... ?
  • ????????default: ?
  • ????????????LOGE("parse:?OOPS?%d\n",?cmd); ?
  • ????????????return?-1; ?
  • ????????} ?
  • ????} ?
  • ?
  • ????return?r; ?
  • }?
  • 前面我們說過,Binder驅動程序寫入到用戶空間的緩沖區中的cmd為BR_TRANSACTION,因此,這里我們只關注BR_TRANSACTION相關的邏輯。

    ???????? 這里用到的兩個數據結構struct binder_txn和struct binder_io可以參考前面一篇文章Android系統進程間通信(IPC)機制Binder中的Server啟動過程源代碼分析,這里就不復述了。

    ???????? 接著往下看,函數調bio_init來初始化reply變量:


    ?

  • void?bio_init(struct?binder_io?*bio,?void?*data, ?
  • ??????????????uint32_t?maxdata,?uint32_t?maxoffs) ?
  • { ?
  • ????uint32_t?n?=?maxoffs?*?sizeof(uint32_t); ?
  • ?
  • ????if?(n?>?maxdata)?{ ?
  • ????????bio->flags?=?BIO_F_OVERFLOW; ?
  • ????????bio->data_avail?=?0; ?
  • ????????bio->offs_avail?=?0; ?
  • ????????return; ?
  • ????} ?
  • ?
  • ????bio->data?=?bio->data0?=?data?+?n; ?
  • ????bio->offs?=?bio->offs0?=?data; ?
  • ????bio->data_avail?=?maxdata?-?n; ?
  • ????bio->offs_avail?=?maxoffs; ?
  • ????bio->flags?=?0; ?
  • }?
  • ?? 最后,真正進行處理的函數是從參數中傳進來的函數指針func,這里就是定義在frameworks/base/cmds/servicemanager/service_manager.c文件中的svcmgr_handler函數:


    ?

  • int?svcmgr_handler(struct?binder_state?*bs, ?
  • ???????????????????struct?binder_txn?*txn, ?
  • ???????????????????struct?binder_io?*msg, ?
  • ???????????????????struct?binder_io?*reply) ?
  • { ?
  • ????struct?svcinfo?*si; ?
  • ????uint16_t?*s; ?
  • ????unsigned?len; ?
  • ????void?*ptr; ?
  • ????uint32_t?strict_policy; ?
  • ?
  • //????LOGI("target=%p?code=%d?pid=%d?uid=%d\n", ?
  • //?????????txn->target,?txn->code,?txn->sender_pid,?txn->sender_euid); ?
  • ?
  • ????if?(txn->target?!=?svcmgr_handle) ?
  • ????????return?-1; ?
  • ?
  • ????//?Equivalent?to?Parcel::enforceInterface(),?reading?the?RPC ?
  • ????//?header?with?the?strict?mode?policy?mask?and?the?interface?name. ?
  • ????//?Note?that?we?ignore?the?strict_policy?and?don't?propagate?it ?
  • ????//?further?(since?we?do?no?outbound?RPCs?anyway). ?
  • ????strict_policy?=?bio_get_uint32(msg); ?
  • ????s?=?bio_get_string16(msg,?&len); ?
  • ????if?((len?!=?(sizeof(svcmgr_id)?/?2))?|| ?
  • ????????memcmp(svcmgr_id,?s,?sizeof(svcmgr_id)))?{ ?
  • ????????fprintf(stderr,"invalid?id?%s\n",?str8(s)); ?
  • ????????return?-1; ?
  • ????} ?
  • ?
  • ????switch(txn->code)?{ ?
  • ????case?SVC_MGR_GET_SERVICE: ?
  • ????case?SVC_MGR_CHECK_SERVICE: ?
  • ????????s?=?bio_get_string16(msg,?&len); ?
  • ????????ptr?=?do_find_service(bs,?s,?len); ?
  • ????????if?(!ptr) ?
  • ????????????break; ?
  • ????????bio_put_ref(reply,?ptr); ?
  • ????????return?0; ?
  • ?
  • ????...... ?
  • ????} ?
  • ????default: ?
  • ????????LOGE("unknown?code?%d\n",?txn->code); ?
  • ????????return?-1; ?
  • ????} ?
  • ?
  • ????bio_put_uint32(reply,?0); ?
  • ????return?0; ?
  • }?
  • ??? 這里, Service Manager要處理的code是SVC_MGR_CHECK_SERVICE,這是在前面的BpServiceManager::checkService函數里面設置的。

    ??????? 回憶一下,在BpServiceManager::checkService時,傳給Binder驅動程序的參數為:


    ?

  • writeInt32(IPCThreadState::self()->getStrictModePolicy()?|?STRICT_MODE_PENALTY_GATHER);?? ?
  • writeString16("android.os.IServiceManager");?? ?
  • writeString16("media.player");???
  • ?? 這里的語句:


    ?

  • strict_policy?=?bio_get_uint32(msg);?? ?
  • s?=?bio_get_string16(msg,?&len);?? ?
  • s?=?bio_get_string16(msg,?&len);??
  • ???? 其中,會驗證一下傳進來的第二個參數,即"android.os.IServiceManager"是否正確,這個是驗證RPC頭,注釋已經說得很清楚了。

    ?????? 最后,就是調用do_find_service函數查找是存在名稱為"media.player"的服務了?;貞浺幌虑懊嬉黄恼翧ndroid系統進程間通信(IPC)機制Binder中的Server啟動過程源代碼分析,MediaPlayerService已經把一個名稱為"media.player"的服務注冊到Service Manager中,所以這里一定能找到。我們看看do_find_service這個函數:


    ?

  • void?*do_find_service(struct?binder_state?*bs,?uint16_t?*s,?unsigned?len) ?
  • { ?
  • ????struct?svcinfo?*si; ?
  • ????si?=?find_svc(s,?len); ?
  • ?
  • //????LOGI("check_service('%s')?ptr?=?%p\n",?str8(s),?si???si->ptr?:?0); ?
  • ????if?(si?&&?si->ptr)?{ ?
  • ????????return?si->ptr; ?
  • ????}?else?{ ?
  • ????????return?0; ?
  • ????} ?
  • }?
  • ? 這里又調用了find_svc函數:


    ?

  • struct?svcinfo?*find_svc(uint16_t?*s16,?unsigned?len) ?
  • { ?
  • ????struct?svcinfo?*si; ?
  • ?
  • ????for?(si?=?svclist;?si;?si?=?si->next)?{ ?
  • ????????if?((len?==?si->len)?&& ?
  • ????????????!memcmp(s16,?si->name,?len?*?sizeof(uint16_t)))?{ ?
  • ????????????return?si; ?
  • ????????} ?
  • ????} ?
  • ????return?0; ?
  • }?
  • 就是在svclist列表中查找對應名稱的svcinfo了。

    ?????? 然后返回到do_find_service函數中?;貞浺幌虑懊嬉黄恼翧ndroid系統進程間通信(IPC)機制Binder中的Server啟動過程源代碼分析,這里的si->ptr就是指MediaPlayerService這個Binder實體在Service Manager進程中的句柄值了。

    ?????? 回到svcmgr_handler函數中,調用bio_put_ref函數將這個Binder引用寫回到reply參數。我們看看bio_put_ref的實現:


    ?

  • void?bio_put_ref(struct?binder_io?*bio,?void?*ptr) ?
  • { ?
  • ????struct?binder_object?*obj; ?
  • ?
  • ????if?(ptr) ?
  • ????????obj?=?bio_alloc_obj(bio); ?
  • ????else?
  • ????????obj?=?bio_alloc(bio,?sizeof(*obj)); ?
  • ?
  • ????if?(!obj) ?
  • ????????return; ?
  • ?
  • ????obj->flags?=?0x7f?|?FLAT_BINDER_FLAG_ACCEPTS_FDS; ?
  • ????obj->type?=?BINDER_TYPE_HANDLE; ?
  • ????obj->pointer?=?ptr; ?
  • ????obj->cookie?=?0; ?
  • }?
  • ?? 這里很簡單,就是把一個類型為BINDER_TYPE_HANDLE的binder_object寫入到reply緩沖區中去。這里的binder_object就是相當于是flat_binder_obj了,具體可以參考Android系統進程間通信(IPC)機制Binder中的Server啟動過程源代碼分析一文。

    ??????? 再回到svcmgr_handler函數中,最后,還寫入一個0值到reply緩沖區中,表示操作結果碼:

  • bio_put_uint32(reply,?0);?
  • ??? 最后返回到binder_parse函數中,調用binder_send_reply函數將操作結果反饋給Binder驅動程序:


    ?

  • void?binder_send_reply(struct?binder_state?*bs, ?
  • ???????????????????????struct?binder_io?*reply, ?
  • ???????????????????????void?*buffer_to_free, ?
  • ???????????????????????int?status) ?
  • { ?
  • ????struct?{ ?
  • ????????uint32_t?cmd_free; ?
  • ????????void?*buffer; ?
  • ????????uint32_t?cmd_reply; ?
  • ????????struct?binder_txn?txn; ?
  • ????}?__attribute__((packed))?data; ?
  • ?
  • ????data.cmd_free?=?BC_FREE_BUFFER; ?
  • ????data.buffer?=?buffer_to_free; ?
  • ????data.cmd_reply?=?BC_REPLY; ?
  • ????data.txn.target?=?0; ?
  • ????data.txn.cookie?=?0; ?
  • ????data.txn.code?=?0; ?
  • ????if?(status)?{ ?
  • ????????data.txn.flags?=?TF_STATUS_CODE; ?
  • ????????data.txn.data_size?=?sizeof(int); ?
  • ????????data.txn.offs_size?=?0; ?
  • ????????data.txn.data?=?&status; ?
  • ????????data.txn.offs?=?0; ?
  • ????}?else?{ ?
  • ????????data.txn.flags?=?0; ?
  • ????????data.txn.data_size?=?reply->data?-?reply->data0; ?
  • ????????data.txn.offs_size?=?((char*)?reply->offs)?-?((char*)?reply->offs0); ?
  • ????????data.txn.data?=?reply->data0; ?
  • ????????data.txn.offs?=?reply->offs0; ?
  • ????} ?
  • ????binder_write(bs,?&data,?sizeof(data)); ?
  • }?
  • 總結

    以上是生活随笔為你收集整理的Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析(2)...的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。