Binder In Native

來源:互聯網
上載者:User

  關於Binder的設計思想與Driver層實現細節可以看這個:Android Binder設計與實現 - 設計篇,這裡首先簡要概括一下。

  Service的每個Binder實體位於Service所屬的進程種中,Binder實體在驅動中被表示為binder_node,並通過成員refs指向了驅動中所有對這個Binder實體的引用,Binder引用在驅動被表示為binder_ref,並通過成員node指向所引用的Binder實體。

  每個使用Binder的進程都會在它的ProcessState的建構函式中開啟Binder裝置,當開啟Binder設定時會調用驅動的binder_open,在binder_open中,會為使用Binder的進程建立一個binde_proc節點,binder_proc的成員nodes索引了這個進程建立的所有Binder實體,refs_by_desc與refs_by_node則是分別以這個進程引用的Binder實體的引用號與引用的實體在核心中的內在地址為索引構建的紅/黑樹狀結構。這樣每個進程都可以通過自己的binder_proc節點檢索到所有自己建立的Binder實體與所有對其他Binder實體的引用。

  匿名Binder要通過實名Binder傳遞,而實名Binder要向ServiceManager註冊。所以首先一定要有進程通過調用ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0)成為ServiceManager,當有進程申請成為ServiceManager時,驅動就通過binder_new_node建立核心中的第一個binder_node節點。

  資料在驅動中以binder_transaction_date結構傳輸,binder_transaction_data的成員ptr.buffer指向要發送的資料的記憶體位址,在進程間也可以傳送Binder實體或引用,比如發送匿名Binder,當Binder實體或引用在資料中傳輸時,就需要一個方法將Binder實體或引用在資料中的位置指出來,ptr.offsets就指向Binder位移數組,offsets_size指明了Binder位移數組的大小,通過這兩個成員驅動就可以找到傳輸的資料中的所有Binder實體或引用。Binder實體或引用在傳遞時被表示為flat_binder_object,flat_binder_object的type域表示傳輸的Binder的類型,TYPE_BINDER_(WEAK)_TYPE表示傳輸的是Binder實體,TYPE_BINDER_(WEAK)_HANDLE表示的是Binder引用,BINDER_TYPE_FD表示檔案Binder。

  Client要向Service發送請求,一定要獲得對Service的Binder實體的引用,Client向Service發送請求時,以引用號指明要向哪個Service發送請求,引用號0表示向ServiceManager發送請求。

  一般情況下,如果Client要向某一Service進行一個請求,首先會通過向引用號為0的Binder引用發送GET_SERVICE請求獲得自己需要的Service在的引用,然後再向這個引用即這個引用對應的Service發送請求。

  驅動會將所有發送到引用號為0的請求轉寄至ServiceManager,當一個進程向0號引用即ServiceManager請求某一個Service時,ServiceManager會檢測一個表尋找Client請求的Service是否已向自己註冊,當Binder實體向ServiceManager註冊時,ServiceManager會將Binder實體的名字與引用存入一個尋找表中,如果已經註冊,就將Service所註冊的Binder引用返回給請求的進程。

  當ServiceManager將某一進程請求的Service的Binder引用發送給這一進程時,由於傳送的是引用,所以flat_binder_object的type的值是TYPE_BINDER_(WEAK)_HANDLE,驅動通過binder_transaction_date的ptr.offsets和offsets_size知道了返回資料中包含Binder實體或引用,然後通過這兩個成員找出資料中的Binder實體或引用,通過flat_binder_object的type成員知道了返回資料中包含的是Binder引用,然後建立一個對Service的Binder實體的引用並同時儲存到Binder實體在驅動中的節點binder_node的refs成員與Client進程的binder_proc中。

  Client得到了Service的引用就可以以這個引用向Service發送請求了,資料包是binder_transaction_date結構體,其成員target是一個聯合,target.handle表示Client對Service的引用號,target.ptr表示Binder實體在Service進程中的記憶體位址,當Client向Service發送請求時填充target.handle域,驅動根據Client所屬的binder_proc節點與引用號handle獲得Client對Service的Binder實體的引用binder_ref,然後通過binder_ref的node成員獲得Service的Binder實體在核心中的節點binder_node,然後將Client的請求添加到Service進程的等待隊列或Service進程某一線程的等待隊列,Service就可以處理Client的請求了。

 

  接下來看下Native層對Binder的使用。

  Binder被實現為一個字元裝置,應用程式通過ioctl調用與Binder驅動程式進行通訊。首先看實現一個ServiceDemo涉及到的類結構關係。

  RefBase是Android實現指標管理的類,牽扯到引用計數的都繼承自這個類,然後通過sp,wp實現強引用計數與弱引用計數的管理。

  Binder使用Client-Server的通訊方式,要實現一個Server,需要先定義一套介面,Client與Server同時實現這套介面,Server端完成實際的功能,Client端只是對Server端功能調用的封裝,由於這套介面需要跨進程調用,需要對所有介面一一編號,Server端根據介面編號決定調用什麼函數。在中對介面的定義就是IServiceDemo。

  要實現處理序間通訊,首先需要定義通訊的協議,然後嚮應用程式提供通訊的介面,Binder Driver定義了通訊協定,IBinder,BpBinder,BBinder承擔了通訊介面的工作,IBinder定義了通訊的介面,BpBinder是Client訪問服務端的代理對象,負責開啟Binder裝置並與Binder裝置通訊,BBinder作為服務端與Binder裝置通訊的介面。Client通過BpBinder串連Binder Driver,然後Binder Driver通過BBinder與Server通訊,從而完成處理序間通訊。

  IServiceDemo定義了Client與Server通訊的介面,需要Client與Server同時實現,我們已經知道,Client通過BpBinder與Server的BBinder進行通訊,那麼Client端怎麼得到BpBinder,Server端怎麼得到BBinder呢?從可以看到,IServiceDemo繼承自IInterface,其實IInterface就定義了一個方法asBinder,返回一個IBinder對象的指標,應該是通過這個方法獲得BpBinder與BBinder對象了。看asBinder實現可以知道,asBinder直接調用了onAsBinder,onAsBinder是一個虛方法,所以是調用子類的具體實現。我們發現,IInterface有兩個子類BpInterface與BnInterface,在這兩個類中都實現了onAsBinder,在BpInterface中,onAsBinder返回了remote(),remote()其實是返回一個BpBinder對象,後面會看到。在BnInterface中,onAsBinder直接返回this指標,而BnInterface繼承自BBinder,所以BnInterface的onAsBinder返回了一個BBinder對象,BpBinder與BBinder都有了,Client就可以與Server通訊了。

  前面說到remote()返回一個BpBinder對象,那麼這個對象是如何返回的呢?從看到,BnInterface是繼承自BBinder的,但是BpInterface並沒有繼承自BpBinder,但是我們發現,BpInterface的建構函式接收一個IBinder類型的參數,我們看一下BpInterface的建構函式:

template<typename INTERFACE><INTERFACE>::BpInterface( sp<IBinder>& 

  BpInterface繼承自BpRefBase,在BpInterface的初始化列表中調用了父類BpRefBase的建構函式,將IBinder remote傳了過去。再看BpRefBase的建構函式:

BpRefBase::BpRefBase( sp<IBinder>&()), mRefs(NULL), mState(->incStrong();                   mRefs = mRemote->createWeak();  

  直接將BpInterface傳過來的IBinder remote儲存到了成員mRemote中,而remote()函數就直接返回了這個mRemote對象。

  通過BpInterface的建構函式儲存了BpBinder對象,那麼BpInterface的建構函式是什麼時候調用的,而作為建構函式參數傳遞進去的BpBinder又是什麼時候構造的?以ServiceManager為例,實名Binder需要通過addService向ServiceManager註冊,這也是處理序間通訊,那麼我們就需要獲得ServiceManager的BpBinder,即BpInterface的子類BpServiceManager對象,來看一下BpServiceManager的擷取方法:

sp<IServiceManager> (gDefaultServiceManager != NULL)  (gDefaultServiceManager ==        }    }    

  單例模式,看以上代碼的紅色部分,ProcessState代表進程對象,每個進程只有一個,在ProcessState::self()中通過單例模式返回每個進程的ProcessState的唯一執行個體,在ProcessState的函數函數中通過open調用開啟了Binder裝置,並通過mmap建立了記憶體映射。open引起binder driver中的binder_open被調用,binder_open中建立binder_proc節點,初始化todo隊列與wait隊列,並將binder_proc節點儲存在binder_open第二個參數struct file *flip的flip->private_data中及binder_procs中。

sp<IBinder> ProcessState::getContextObject( sp<IBinder>& getStrongProxyForHandle(<IBinder><IBinder>* e = (e !=        IBinder* b = e-> (b == NULL || !e->refs->attemptIncWeak(            e->binder = (b) e->refs = b->=->refs->decWeak(

  handle是0,lookupHandleLocked的返回結果會是NULL,所以會執行紅色部分建立一個BpBinder,defaultServiceManager中紅色部分可以簡化為:

gDefaultServiceManager = interface_cast<IServiceManager>( BpBinder());

  BpBinder有了,我們在前面也知道了BpBinder會做為參數傳遞給BpInterface的建構函式,那麼BpInterface的建構函式是什麼時候調用的?從以上代碼看,應該是interface_cast了,將參數BpBinder轉化為了BpInterface的子類BpServiceManager,再來看interface_cast的實現。

template<typename INTERFACE><INTERFACE> interface_cast( sp<IBinder>&

  INTERFACE即為IServiceManager,繼承自IInterface的類都會聲明DELCARE_META_INTERFACE與IMPLEMENT_META_INTERFACE,看一下IMPLEMENT_META_INTERFACE的實現:

 IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \     android::String16&<I##INTERFACE> android::sp<android::IBinder>&<I##INTERFACE> (obj !== static_cast<I##INTERFACE*>               \             (intr ==                          \            }                                                           \        }                                                               \        ~I##INTERFACE() { }      

  在IMPLEMENT_META_INTERFACE宏中實現了asInterface,上述紅色代碼中,obj即傳進來的BpBinder(0),最上面的圖的注釋中說了BpBinder的queryLocalInterface返回NULL,所以會執行藍色代碼,INTERFACE是Servicemanager,所以會建立一個BpServiceManager對象。BpServiceManager對象有了,對過其asBinder方法返回的BpBinder對象就可以與Server進行通訊了。

 

  Client有了代理對像BpInterface,那麼怎麼通過這個代理對象與Server進行通訊呢?標準方法是下面這樣:

remote()->transact(SET_MASTER_VOLUME, data, &reply);

  前面已經說了,Client通過BpBinder經由Binder驅動、BBinder與Server端通訊,從這裡看確實是這樣,remote()返回BpBinder對象,調用BpBinder的transact來與Server通訊,transact是定義在IBinder中的,BpBinder與BBinder都實現了這個方法。

  在BpBinder::transact的實現中,直接調用了IPCThreadState::transact,前面說過ProcessState代表進程對象,每個進程有一個,在ProcessState的建構函式會打與Binder裝置並進行mmap,而這裡的IPCThreadState就表示線程對象,使用LTS(Local Thread Storage)每個線程有一個IPCThreadState對象,Binder通訊是線程與線程的通訊,這裡我們能通過IPCThreadState::transact與Server端進行通訊。

  IPCThreasState::transact方法首先調用writeTransactionDate將請求資料封裝進binder_transaction_data結構並寫入Parcel mOut中。然後調用waitForResponse。

  waitForResponse會調用talkWithDriver,talkWithDriver通過ioctl(driverFD,BINDER_WIRTE_READ,&binder_write_read)與Binder驅動進行通訊,當Server處理完請求後talkWithDriver成功返回,然後waitForResponse中讀取Binder Driver返回的指令並執行相應的動作。

  在Server中,binder thread的joinThreadPool中會調用taklWithDriver等待Client請求,當有請求到來時talkWithDriver返回,讀取command,調用executeCommand處理請求。在executeCommand中調用BBinder的transact處理請求,BBinder::transact會調用虛方法onTransact來完成具體功能,具體實現就是BnServiceManager::onTransact或BnServiceDemo::onTransact等等。一般會有一個類繼承自BnXXXXX完成具體功能,在BnXXXXX的onTransact中會調用完成相應功能的介面,由於是虛方法,就會調用到具體實作類別。

 

   註冊上下文管理者--ServiceManager

  通過 ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0); 一個進程可以註冊成為上下檔案管理者,在ServiceManager就是執行這條ioctl請求。

  ioctl調用會執行Binder Driver的binder_ioctl函數,binder_ioctl根據第二個參數cmd執行相應的同作,看下BINDER_SET_CONTEXT_MGR對應的處理:

 (binder_context_mgr_node !== - (binder_context_mgr_uid != - (binder_context_mgr_uid != current->cred->                                       ->cred->= -= current->cred->= (binder_context_mgr_node === -->local_weak_refs++->local_strong_refs++->has_strong_ref = ->has_weak_ref = ;

  很簡單,就是通過binder_new_node擷取到一個binder_node儲存到全域變數binder_context_mgr_node中,同時儲存了UID,只能有一個context_manager。

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.