Binder系列6—獲取服務(getService)

weixin_33709219發表於2018-04-03

一、 獲取服務

在Native層的服務註冊,我們選擇以media為例來展開講解,先來看看media的類關係圖。

1.1 類圖


11462765-ea2e1e76c8143817.png

圖解:

藍色: 代表獲取MediaPlayerService服務相關的類;

綠色: 代表Binder架構中與Binder驅動通訊過程中的最為核心的兩個類;

紫色: 代表註冊服務和獲取服務的公共介面/父類;

二. 獲取Media服務

2.1 getMediaPlayerService

[-> framework/av/media/libmedia/IMediaDeathNotifier.cpp]


11462765-8cdc304e0a0aa69f.png

其中defaultServiceManager()過程在上一篇文章獲取ServiceManager已講過,返回BpServiceManager。

在請求獲取名為”media.player”的服務過程中,採用不斷迴圈獲取的方法。由於MediaPlayerService服務可能還沒向ServiceManager註冊完成或者尚未啟動完成等情況,故則binder返回為NULL,休眠0.5s後繼續請求,直到獲取服務為止。

2.2 BpSM.getService

[-> IServiceManager.cpp ::BpServiceManager]


11462765-9325d452faf6b844.png

通過BpServiceManager來獲取MediaPlayer服務:檢索服務是否存在,當服務存在則返回相應的服務,當服務不存在則休眠1s再繼續檢索服務。該迴圈進行5次。為什麼是迴圈5次呢,這估計跟Android的ANR時間為5s相關。如果每次都無法獲取服務,迴圈5次,每次迴圈休眠1s,忽略checkService()的時間,差不多就是5s的時間

2.3 BpSM.checkService

[-> IServiceManager.cpp ::BpServiceManager]


11462765-4b6c081f7cda53ec.png

檢索指定服務是否存在, 其中remote()為BpBinder。

2.4 BpBinder::transact

[-> BpBinder.cpp]


11462765-1db44c4a8c7e073f.png

Binder代理類呼叫transact()方法,真正工作還是交給IPCThreadState來進行transact工作,

2.4.1 IPCThreadState::self

[-> IPCThreadState.cpp]


11462765-2c8be35cec208bd9.png

TLS是指Thread local storage(執行緒本地儲存空間),每個執行緒都擁有自己的TLS,並且是私有空間,執行緒之間不會共享。通過pthread_getspecific/pthread_setspecific函式可以獲取/設定這些空間中的內容。從執行緒本地儲存空間中獲得儲存在其中的IPCThreadState物件。

2.4.2 IPCThreadState初始化

[-> IPCThreadState.cpp]


11462765-12a8506d6c803615.png

每個執行緒都有一個IPCThreadState,每個IPCThreadState中都有一個mIn、一個mOut。成員變數mProcess儲存了ProcessState變數(每個程式只有一個)。

mIn 用來接收來自Binder裝置的資料,預設大小為256位元組;

mOut用來儲存發往Binder裝置的資料,預設大小為256位元組。

2.5 IPC::transact

[-> IPCThreadState.cpp]


11462765-60aebe7781915557.png

2.6 IPC.writeTransactionData

[-> IPCThreadState.cpp]


11462765-ffdeaa0ee16869f3.png

其中handle的值用來標識目的端,註冊服務過程的目的端為service manager,此處handle=0所對應的是binder_context_mgr_node物件,正是service manager所對應的binder實體物件。binder_transaction_data結構體是binder驅動通訊的資料結構,該過程最終是把Binder請求碼BC_TRANSACTION和binder_transaction_data結構體寫入到mOut。

2.7 IPC.waitForResponse

[-> IPCThreadState.cpp]


11462765-c87a15932ca64a89.png

2.8 IPC.talkWithDriver

[-> IPCThreadState.cpp]


11462765-cb586a318fcafa62.png

binder_write_read結構體用來與Binder裝置交換資料的結構, 通過ioctl與mDriverFD通訊,是真正與Binder驅動進行資料讀寫互動的過程。 先向service manager程式傳送查詢服務的請求(BR_TRANSACTION),見Binder系列3—啟動ServiceManager。當service manager程式收到該命令後,會執行do_find_service() 查詢服務所對應的handle,然後再binder_send_reply()應答 發起者,傳送BC_REPLY協議,然後呼叫binder_transaction(),再向服務請求者的Todo佇列 插入事務。

接下來,再看看binder_transaction過程。

2.8.1 binder_transaction

這個過程非常重要,分兩種情況來說:

當請求服務的程式與服務屬於不同程式,則為請求服務所在程式建立binder_ref物件,指向服務程式中的binder_node;

當請求服務的程式與服務屬於同一程式,則不再建立新物件,只是引用計數加1,並且修改type為BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER。

2.8.2 binder_thread_read

2.9 readStrongBinder

[-> Parcel.cpp]


11462765-a4725ea102396831.png

2.9.1 unflatten_binder

[-> Parcel.cpp]


11462765-9ccd5761b3e4e287.png

2.9.2 getStrongProxyForHandle

[-> ProcessState.cpp]


11462765-99704e2a19b7072d.png

readStrongBinder的功能是flat_binder_object解析並建立BpBinder物件.

2.9.3 lookupHandleLocked


11462765-18370ab69b26e40a.png

根據handle值來查詢對應的handle_entry.

二. 總結

請求服務(getService)過程,就是向servicemanager程式查詢指定服務,當執行binder_transaction()時,會區分請求服務所屬程式情況。

當請求服務的程式與服務屬於不同程式,則為請求服務所在程式建立binder_ref物件,指向服務程式中的binder_node;

最終readStrongBinder(),返回的是BpBinder物件;

當請求服務的程式與服務屬於同一程式,則不再建立新物件,只是引用計數加1,並且修改type為BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER。

最終readStrongBinder(),返回的是BBinder物件的真實子類;

相關文章