Binder是怎麼跨進程傳輸的?——源碼分析(三)

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對象指針

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章