在這個過程當中, 常見的幾個BR_命令:java
BR_TRANSACTION_COMPLETE: binder驅動收到BC_TRANSACTION事件後的應答消息; 對於oneway transaction,當收到該消息,則完成了本次Binder通訊;node
BR_DEAD_REPLY: 回覆失敗,每每是線程或節點爲空. 則結束本次通訊Binder;android
BR_FAILED_REPLY:回覆失敗,每每是transaction出錯致使. 則結束本次通訊Binder;架構
BR_REPLY: Binder驅動向Client端發送迴應消息; 對於非oneway transaction時,當收到該消息,則完整地完成本次Binder通訊;app
規律: BC_TRANSACTION + BC_REPLY = BR_TRANSACTION_COMPLETE + BR_DEAD_REPLY + BR_FAILED_REPLYasync
處於剩餘的BR_命令.函數
binder_write_read結構體用來與Binder設備交換數據的結構, 經過ioctl與mDriverFD通訊,是真正與Binder驅動進行數據讀寫交互的過程。 ioctl()方法通過syscall最終調用到Binder_ioctl()方法.工具
[→ Binder.c]spa
由【小節2.11】傳遞過出來的參數 cmd=BINDER_WRITE_READ
線程
首先,根據傳遞過來的文件句柄指針獲取相應的binder_proc結構體, 再從中查找binder_thread,若是當前線程已經加入到proc的線程隊列則直接返回,若是不存在則建立binder_thread,並將當前線程添加到當前的proc.
當返回值爲-ENOMEM,則意味着內存不足,每每會出現建立binder_thread對象失敗;
當返回值爲-EINVAL,則意味着CMD命令參數無效;
此時arg是一個binder_write_read
結構體,mOut
數據保存在write_buffer,因此write_size>0,但此時read_size=0。首先,將用戶空間bwr結構體拷貝到內核空間,而後執行binder_thread_write()操做.
不斷從binder_buffer所指向的地址獲取cmd, 當只有BC_TRANSACTION
或者BC_REPLY
時, 則調用binder_transaction()來處理事務.
發送的是BC_TRANSACTION時,此時reply=0。
主要功能:
查詢目標進程的過程: handle → binder_ref → binder_node → binder_proc
將BINDER_WORK_TRANSACTION
添加到目標隊列target_list, 首次發起事務則目標隊列爲target_proc->todo
, reply事務時則爲target_thread->todo
; oneway的非reply事務,則爲target_node->async_todo
.
將BINDER_WORK_TRANSACTION_COMPLETE
添加到當前線程的todo隊列
此時當前線程的todo隊列已經有事務, 接下來便會進入binder_thread_read()來處理相關的事務.
當收到的是BINDER_WORK_TRANSACTION_COMPLETE, 則將命令BR_TRANSACTION_COMPLETE寫回用戶空間.
當收到的是BINDER_WORK_TRANSACTION命令, 則將命令BR_TRANSACTION或BR_TRANSACTION寫回用戶空間.
執行完binder_thread_write方法後, 經過binder_transaction()首先寫入BINDER_WORK_TRANSACTION_COMPLETE
寫入當前線程.
這時bwr.read_size > 0, 回到binder_ioctl_write_read方法, 便開始執行binder_thread_read();
在binder_thread_read()方法, 將獲取cmd=BR_TRANSACTION_COMPLETE, 再將cmd和數據寫回用戶空間;
一次Binder_ioctl完成,接着回調用戶空間方法talkWithDriver(),而且剛纔的數據寫入mIn
.
這時mIn有可讀數據, 回到waitForResponse()方法,完成BR_TRANSACTION_COMPLETE過程.
再回退到transact()方法, 對於oneway的操做, 此次Binder通訊便完成, 不然仍是要等待Binder服務端的返回.
對於startService過程, 顯然沒有指定oneway的方式,那麼發起者進程還會繼續停留在waitForResponse()方法,等待收到BR_REPLY消息. 因爲在前面binder_transaction過程當中,除了向本身所在線程寫入了BINDER_WORK_TRANSACTION_COMPLETE
, 還向目標進程(此處爲system_server)寫入了BINDER_WORK_TRANSACTION
命令. 而此時system_server進程的binder線程一旦空閒即是停留在binder_thread_read()方法來處理進程/線程新的事務, 收到的是BINDER_WORK_TRANSACTION
命令, 通過binder_thread_read()後生成命令BR_TRANSACTION
.一樣的流程.
接下來,從system_server
的binder線程一直的執行流: IPC.joinThreadPool –> IPC.getAndExecuteCommand() → IPC.talkWithDriver() ,但talkWithDriver收到事務以後, 便進入IPC.executeCommand(), 接下來,從executeCommand提及.
對於oneway的場景, 則到此所有結束.
對於非oneway, 也就是須要reply的通訊過程,則向Binder驅動發送BC_REPLY命令
[→ Binder.cpp ::BBinder ]
4.4 JavaBBinder.onTransact
[→ android_util_Binder.cpp]
還記得AndroidRuntime::startReg過程嗎, 其中有一個過程即是register_android_os_Binder(),該過程會把gBinderOffsets.mExecTransact即是Binder.java中的execTransact()方法.詳見見Binder系列7—framework層分析文章中的第二節初始化的過程.
另外,此處mObject是在服務註冊addService過程,會調用writeStrongBinder方法, 將Binder對象傳入了JavaBBinder構造函數的參數, 最終賦值給mObject. 在本次通訊過程當中Object爲ActivityManagerNative對象.
此處斗轉星移, 從C++代碼回到了Java代碼. 進入AMN.execTransact, 因爲AMN繼續於Binder對象, 接下來進入Binder.execTransact
[Binder.java]
當發生RemoteException, RuntimeException, OutOfMemoryError, 對於非oneway的狀況下都會把異常傳遞給調用者.
[→ ActivityManagerNative.java]
4.7 AMS.startService
歷經千山萬水, 總算是進入了AMS.startService. 當system_server收到BR_TRANSACTION的過程後, 再經歷一個相似的過程,將事件告知app所在進程service啓動完成.過程基本一致,此處就再也不展開.
本文詳細地介紹如何從AMP.startService是如何經過Binder一步步調用進入到system_server進程的AMS.startService. 整個過程涉及Java framework, native, kernel driver各個層面知識. 僅僅一個Binder IPC調用, 就花費了如此大篇幅來說解, 可見系統之龐大. 整個過程的調用流程:
從通訊流程角度來看整個過程:
前面第二至第四段落,主要講解過程 BC_TRANSACTION –> BR_TRANSACTION_COMPLETE –> BR_TRANSACTION.有興趣的同窗能夠再看看後面3個事務的處理:BC_REPLY –> BR_TRANSACTION_COMPLETE –> BR_REPLY,這兩個流程基本是一致的.
從通訊協議的角度來看這個過程:
Binder客戶端或者服務端向Binder Driver發送的命令都是以BC開頭,例如本文的BC_TRANSACTION
和BC_REPLY
, 全部Binder Driver向Binder客戶端或者服務端發送的命令則都是以BR開頭, 例如本文中的BR_TRANSACTION
和BR_REPLY
.
只有當BC_TRANSACTION
或者BC_REPLY
時, 才調用binder_transaction()來處理事務. 而且都會迴應調用者一個BINDER_WORK_TRANSACTION_COMPLETE
事務, 通過binder_thread_read()會轉變成BR_TRANSACTION_COMPLETE
.
startService過程即是一個非oneway的過程, 那麼oneway的通訊過程以下所述.
上圖是非oneway通訊過程的協議圖, 下圖則是對於oneway場景下的通訊協議圖:
到BR_TRANSACTION_COMPLETE則程序返回,有人可能以爲好奇,爲什麼oneway怎麼還要等待迴應消息? 我舉個例子,你就明白了.
你(app進程)要給遠方的家人(system_server進程)郵寄一封信(transaction), 你須要經過郵寄員(Binder Driver)來完成.整個過程以下:
你把信交給郵寄員(BC_TRANSACTION
);
郵寄員收到信後, 填一張單子給你做爲一份回執(BR_TRANSACTION_COMPLETE
). 這樣你才放心知道郵遞員已肯定接收信, 不然就這樣走了,信到底有沒有交到郵遞員手裏都不知道,這樣的通訊實在太讓人不省心, 長時間收不到遠方家人的回信, 沒法得知是在路的中途信件丟失呢,仍是壓根就沒有交到郵遞員的手裏. 因此說oneway也得知道信是投遞狀態是否成功.
郵遞員利用交通工具(Binder Driver),將信交給了你的家人(BR_TRANSACTION
);
當你收到回執(BR_TRANSACTION_COMPLETE)時內心也不期待家人回信, 那麼這即是一次oneway的通訊過程.
若是你但願家人回信, 那即是非oneway的過程,在上述步驟2後並非直接返回,而是繼續等待着收到家人的回信, 經歷前3個步驟以後繼續執行:
家人收到信後, 立馬寫了個回信交給郵遞員BC_REPLY
;
一樣,郵遞員要寫一個回執(BR_TRANSACTION_COMPLETE
)給你家人;
郵遞員再次利用交通工具(Binder Driver), 將回信成功交到你的手上(BR_REPLY
)
這即是一次完成的非oneway通訊過程.
oneway與非oneway: 都是須要等待Binder Driver的迴應消息BR_TRANSACTION_COMPLETE. 主要區別在於oneway的通訊收到BR_TRANSACTION_COMPLETE則返回,而不會再等待BR_REPLY消息的到來.
想了解更多?
那就趕忙來關注咱們
小米開放平臺公衆號
小米開放平臺官方地址:
小米開放平臺官方交流羣:398616987