Binder系列6—獲取服務(getService)
一、 獲取服務
在Native層的服務註冊,我們選擇以media為例來展開講解,先來看看media的類關係圖。
1.1 類圖
圖解:
藍色: 代表獲取MediaPlayerService服務相關的類;
綠色: 代表Binder架構中與Binder驅動通訊過程中的最為核心的兩個類;
紫色: 代表註冊服務和獲取服務的公共介面/父類;
二. 獲取Media服務
2.1 getMediaPlayerService
[-> framework/av/media/libmedia/IMediaDeathNotifier.cpp]
其中defaultServiceManager()過程在上一篇文章獲取ServiceManager已講過,返回BpServiceManager。
在請求獲取名為”media.player”的服務過程中,採用不斷迴圈獲取的方法。由於MediaPlayerService服務可能還沒向ServiceManager註冊完成或者尚未啟動完成等情況,故則binder返回為NULL,休眠0.5s後繼續請求,直到獲取服務為止。
2.2 BpSM.getService
[-> IServiceManager.cpp ::BpServiceManager]
通過BpServiceManager來獲取MediaPlayer服務:檢索服務是否存在,當服務存在則返回相應的服務,當服務不存在則休眠1s再繼續檢索服務。該迴圈進行5次。為什麼是迴圈5次呢,這估計跟Android的ANR時間為5s相關。如果每次都無法獲取服務,迴圈5次,每次迴圈休眠1s,忽略checkService()的時間,差不多就是5s的時間
2.3 BpSM.checkService
[-> IServiceManager.cpp ::BpServiceManager]
檢索指定服務是否存在, 其中remote()為BpBinder。
2.4 BpBinder::transact
[-> BpBinder.cpp]
Binder代理類呼叫transact()方法,真正工作還是交給IPCThreadState來進行transact工作,
2.4.1 IPCThreadState::self
[-> IPCThreadState.cpp]
TLS是指Thread local storage(執行緒本地儲存空間),每個執行緒都擁有自己的TLS,並且是私有空間,執行緒之間不會共享。通過pthread_getspecific/pthread_setspecific函式可以獲取/設定這些空間中的內容。從執行緒本地儲存空間中獲得儲存在其中的IPCThreadState物件。
2.4.2 IPCThreadState初始化
[-> IPCThreadState.cpp]
每個執行緒都有一個IPCThreadState,每個IPCThreadState中都有一個mIn、一個mOut。成員變數mProcess儲存了ProcessState變數(每個程式只有一個)。
mIn 用來接收來自Binder裝置的資料,預設大小為256位元組;
mOut用來儲存發往Binder裝置的資料,預設大小為256位元組。
2.5 IPC::transact
[-> IPCThreadState.cpp]
2.6 IPC.writeTransactionData
[-> IPCThreadState.cpp]
其中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]
2.8 IPC.talkWithDriver
[-> IPCThreadState.cpp]
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]
2.9.1 unflatten_binder
[-> Parcel.cpp]
2.9.2 getStrongProxyForHandle
[-> ProcessState.cpp]
readStrongBinder的功能是flat_binder_object解析並建立BpBinder物件.
2.9.3 lookupHandleLocked
根據handle值來查詢對應的handle_entry.
二. 總結
請求服務(getService)過程,就是向servicemanager程式查詢指定服務,當執行binder_transaction()時,會區分請求服務所屬程式情況。
當請求服務的程式與服務屬於不同程式,則為請求服務所在程式建立binder_ref物件,指向服務程式中的binder_node;
最終readStrongBinder(),返回的是BpBinder物件;
當請求服務的程式與服務屬於同一程式,則不再建立新物件,只是引用計數加1,並且修改type為BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER。
最終readStrongBinder(),返回的是BBinder物件的真實子類;
相關文章
- net6 類中獲取服務
- 獲取AFP服務資訊
- Kali Linux常用服務配置教程獲取IP地址Linux
- 如何獲取服務的 git 分支及 commit 版本號GitMIT
- Binder面試系列之二面試
- Android系統服務編寫例項-Binder(Java層AIDL)AndroidJavaAI
- Android Binder原理(三)系統服務的註冊過程Android
- 服務端如何獲取客戶端請求IP地址服務端客戶端
- ArcGIS切片服務獲取切片方案xml檔案(conf.xml)XML
- 在容器服務中獲取客戶端真實源 IP客戶端
- Binder基礎業務分析
- Nginx服務系列——代理Nginx
- Nginx代理後服務端使用remote_addr獲取真實IPNginx服務端REM
- 服務端渲染中的資料獲取:結合 useRequestHeaders 與 useFetch服務端Header
- 如何實現公平公正的資料獲取及服務生態?
- 阿里雲簡訊服務的使用-----獲取簡訊驗證碼阿里
- Nginx服務系列——靜態資源web服務NginxWeb
- go微服務系列(二) - 服務註冊/服務發現Go微服務
- Linux下玩轉nginx系列(六)---nginx實現cache(快取)服務LinuxNginx快取
- spring cloud系列教程第八篇-修改服務名稱及獲取註冊中心註冊者的資訊SpringCloud
- 服務端使用 nodejs 獲取帶參微信小程式碼圖片服務端NodeJS微信小程式
- ADAMoracle實現更公平公正的資料獲取及服務生態Oracle
- go微服務系列(三) - 服務呼叫(http)Go微服務HTTP
- Angular6 服務端渲染Angular服務端
- K8S叢集儲存服務相關日誌獲取指南K8S
- thinkphp6 使用FFMpeg獲取影片資訊PHP
- Nginx服務系列——負載均衡Nginx負載
- SpringBoot系列——admin服務監控Spring Boot
- PostgreSQL 原始碼解讀(121)- MVCC#6(獲取事務號-實現函式)SQL原始碼MVCC#函式
- 微服務Consul系列之服務部署、搭建、使用微服務
- 【Azure 雲服務】如何從Azure Cloud Service中獲取專案的部署檔案Cloud
- angular6自定義服務serviceAngular
- centos6安裝telnet服務CentOS
- Docker_Docker服務編排6Docker
- tp6 路由匹配引數獲取問題路由
- Binder
- 獲取任務的執行結果
- Docker 系列 - 03 - 入門 & Node 服務Docker