Binder是怎麼跨進程傳輸的?
- Parcel的writeStrongBinder和readStrongBinder
- Binder在Parcel中存儲原理,flat_binder_object
- 說清楚binder_node, binder_ref
- 目標進程根據binder_ref的handle創建BpBinder
- 由BpBinder再往上到BinderProxy到業務層的Proxy
這篇文章還是看源碼:
1、定義AIDL的接口(目的發佈binder)
2、根據對應的AIDL接口生成的類,把數據寫到Parcel中,調用transact一層一層發給驅動,通過WriteStrongBinder,把binder對象寫到Parcel中,然後調用
3、服務端onTransact回調
接下來分析一下上面 第二條:客戶端是怎麼傳遞Binder對象過去的
1、把java傳過來的Parcel寫到native的Parcel中
2、通過Java層的binder找到natice層的binder
PS: Binder可能是實體:我的理解,在同一個進程的時候傳進來的是當前的stub對象
如果代理對象,就是在不同的進程,傳過來的是客戶端的代理對象
3、native層writeStrongBinder 如何寫到native層的Parcel的,如下:
flat_binder_object在Parcel中的儲存方式,我們把flat_binder_object存在mObjects中,另一個進程就是根據偏移量取出來
上面總結:
根據java層的Parcel,找出對應的native層的binder,然後把binder封裝成flat_binder_object對象,存在mObjects中,最終寫在了native的Parcel中整體流程。
到了Binder驅動層怎麼處理的?
binder_node = 服務進程引用
binder_ref = 對應客戶端的引用,但指向的都是binder_node
binder驅動會爲每個客戶端的引用維護一個handle,存在binder_ref中。
總結就是把binder的代理對象handle寫在flat_binder_object中
服務端怎麼讀出來的?
1、在java層parcel中讀取數據,到native層讀取
跨進程傳遞binder,傳的是binder實體對象,但是到了binder層會轉成binder的代理對象
根據handle值返回對應的BpBinder對象
根據native層的binder對象返回對應java層的binder對象
總結:
Binder對象跨進程的傳輸:
整體的流程:
1、在客戶端中,通過parcel方法writeStrongBinder,把binder寫進java層的Parcel中
2、然後調動用trasact把parcel一層一層傳給binder驅動,然後在返回服務端
3、服務端在onTransact中接收數據,通過parcel的方法readStrongBinder讀出來binder
PS:ServerManager中的addServer方法會傳遞binder實體註冊在SM中。後面文章我會在出一個它的源碼
客戶端流程:
分析writeStrongBinder流程:
1、調用native的方法有兩個參數:
參數1:native層對應的parcel指針,也就是通過它找到對應的native層的Parcel數據,
參數2:Binder對象,這個binder對象可能是Binder實體,也可能是代理對象
解釋一下爲什麼是binder實體,後者是代理對象
Binder實體:同一個進程asInterface獲取的是本地的binder Stub
代理對象: 也可能是代理對象,說明是兩個進程asInterface獲取的是客戶端代理對象
2、調用native層nativewriteStrongBinder
a、根據傳過來的指針找到native層對應的parcel對象
b、通過java層的binder對象找到native層的binder對象
c、然後調用writeStrongBinder把native的binder寫到parcel中
- 1、創建一個flat_binder_object 然後把binder賦值到裏面
- 2、然後把flat_binder_object寫在Parcel中
- 3、Parcel中有一個mObjects數組,用來保存flat_binder_object在緩衝區的偏移
以上是在Binder驅動之前操作,然後我們看下到了Binder驅動怎麼處理的呢?
3、到達驅動之後先取出對應的flat_binder_object,然後取出來對應的Binder對象,
- a、判斷驅動裏面有沒有binder實體對象的binder_node,沒有就創建一個
- b、查找目標進程有沒有binder引用對象,沒有就創建一個 --binder_ref
- c、然後把客戶端對應的handle值賦值給flat_binder_object。所以handle就是binder代理對象
總結:binder驅動會把binder實體轉成代理對象handle
binder_node = 服務進程引用
binder_ref = 對應客戶端的引用,但指向的都是binder_node
binder驅動會爲每個客戶端的引用維護一個handle,存在binder_ref中。
服務端接收流程:
1、在readStrongBinder中,調用nativeReadStrongBinder。
2、根據java層傳下來的引用找到native層對應的Parcel,然後在裏面讀取binder。readStrongBinder
3、在Parcel中讀出flat_binder_object,然後取出type
- type == BINDER_TYPE_BINDER : 同一個進程,cookie是binder實體對象
- ype == BINDER_TYPE_HANDLE : 不同進程,傳過來的是handle值,代理對象,根據handle值返回一個Bpbinder(handle是一個索引,在數組中查看,沒有查到就new一個BpBinder)
4、跟好友native binder對象返回對應java層的binder對象
如果native的binder對象是實體就返回java層的javaBBinder
如果是代理對象就new一個dialing對象,而且binderProxy對象會保存一個native層的binder對象指針