騰訊面試官——說說你對 binder 驅動的瞭解?

作者:Android面試官

原文地址:https://juejin.im/post/5eeea016e51d45740e4273e8

面試官提了一個問題:說說你對 binder 驅動的瞭解。這個問題雖有些 "面試造火箭" 的無奈,可難點就是亮點、價值所在,是篩選面試者的有效手段。如果讓你回答,你能說出多少呢?我們來看看 😎、😨 和 🤔️ 三位同學的回答如何吧


😎 自認爲無所不知,水平已達應用開發天花板,目前月薪 10k

面試官️:說說你對 binder 驅動的瞭解

😎:binder 驅動是很底層的東西,在系統內核中,是 binder 機制的基石。

面試官:沒了嗎?把你瞭解的都說一下

😎:直接讓我說了解不好回答啊,還是問我問題吧

面試官:好,你剛纔提到了系統內核,那介紹一下用戶空間和內核空間吧

😎:不知道,這東西瞭解了也沒什麼用啊!我對業務開發 API 比較瞭解,比如 RecycleView 佈局,我寫的賊溜~

面試官:好的,回去等通知吧


😨 業餘時間經常打遊戲、追劇、熬夜,目前月薪 15k

面試官:說說你對 binder 驅動的瞭解

😨:binder 機制分爲四部分,binder 驅動、Service Manager、客戶端、服務端。類比網絡通信,Service Manager 是 DNS,binder 驅動就是路由器,它運行在內核空間,不同進程間通過 binder 驅動才能通信。

面試官:爲什麼 binder 驅動要運行在內核空間?可以移到用戶空間嗎?

😨:不行,兩個進程的進程空間有不同的虛擬地址映射規則,內存是不共享的,無法直接通信。Linux 把進程空間劃分爲用戶空間和內核空間,分別運行用戶程序和系統內核。

用戶空間和內核空間雖也是隔離的,但可以通過 copy_from_user 將數據從用戶空間拷貝到內核空間,通過 copy_to_user 將數據從內核空間拷貝到用戶空間。

所以 binder 驅動要處於內核空間,才能實現兩個進程間的通信。一般的 IPC 方式需要分別調用這兩個函數,數據就拷貝了兩次,而 binder 將內核空間與目標用戶空間進行了 mmap,只需調 copy_from_user 拷貝一次即可。

面試官:從用戶空間如何調用內核空間的 binder 驅動呢?

😨:這個不瞭解了,我沒看過 binder 源碼,只是知道大概的通信方式

面試官:那你對 binder 驅動還有哪些瞭解,都說說吧

😨:嗯... 沒有了

面試官:好的,回去等通知吧


🤔️ 堅持每天學習、不斷的提升自己,目前月薪 30k

面試官:說說你對 binder 驅動的瞭解

🤔️:簡單畫張圖吧:

 

對 Binder 機制來說,它是 IPC 通信的路由器,負責實現不同進程間的數據交互,是 Binder 機制的核心;對 Linux 系統來說,它是一個字符驅動設備,運行在內核空間,向上層提供 /dev/binder 設備節點及 open、mmap、ioctl 等系統調用。

面試官:你提到了驅動設備,那先說說 Linux 的驅動設備吧

🤔️:Linux 把所有的硬件訪問都抽象爲對文件的讀寫、設置,這一"抽象"的具體實現就是驅動程序。驅動程序充當硬件和軟件之間的樞紐,提供了一套標準化的調用,並將這些調用映射爲實際硬件設備相關的操作,對應用程序來說隱藏了設備工作的細節。

Linux 驅動設備分爲三類,分別是字符設備、塊設備和網絡設備。字符設備就是能夠像字節流文件一樣被訪問的設備。對字符設備進行讀/寫操作時,實際硬件的 I/O 操作一般也緊接着發生。字符設備驅動程序通常都會實現 open、close、read 和 write 系統調用,比如顯示屏、鍵盤、串口、LCD、LED 等。

塊設備指通過傳輸數據塊(一般爲 512 或 1k)來訪問的設備,比如硬盤、SD卡、U盤、光盤等。網絡設備是能夠和其他主機交換數據的設備,比如網卡、藍牙等設備。

字符設備中有一個比較特殊的 misc 雜項設備,設備號爲 10,可以自動生成設備節點。Android 的 Ashmem、Binder 都屬於 misc 雜項設備。

面試官:看過 binder 驅動的 open、mmap、ioctl 方法的具體實現嗎?

🤔️:它們分別對應於驅動源碼 binder.c 中的 binder_open()、binder_mmap()、binder_ioctl() 方法,binder_open() 中主要是創建及初始化 binder_proc ,binder_proc 是用來存放 binder 相關數據的結構體,每個進程獨有一份。

binder_mmap() 的主要工作是建立應用進程虛擬內存在內核中的一塊映射,這樣應用程序和內核就擁有了共享的內存空間,爲後面的一次拷貝做準備。

binder 驅動並不提供常規的 read()、write() 等文件操作,全部通過 binder_ioctl() 實現,所以 binder_ioctl() 是 binder 驅動中工作量最大的一個,它承擔了 binder 驅動的大部分業務。

面試官:僅 binder_ioctl() 一個方法是怎麼實現大部分業務的?

🤔️:binder 機制將業務細分爲不同的命令,調用 binder_ioctl() 時傳入具體的命令來區分業務,比如有讀寫數據的 BINDER_WRITE_READ 命令、 Service Manager 專用的註冊爲 DNS 的命令等等。

BINDER_WRITE_READ 命令最爲關鍵,其細分了一些子命令,比如 BC_TRANSACTION、BC_REPLY 等。BC_TRANSACTION 就是上層最常用的 IPC 調用命令了,AIDL 接口的 transact 方法就是這個命令。

面試官:binder 驅動中要實現這些業務功能,必然要用一些數據結構來存放相關數據,比如你上面說 binder_open() 方法時提到的 binder_proc,你還知道其他的結構體嗎?

🤔️:知道一些,比如:

結構體 說明
binder_proc 描述使用 binder 的進程,當調用 binder_open 函數時會創建
binder_thread 描述使用 binder 的線程,當調用 binder_ioctl 函數時會創建
binder_node 描述 binder 實體節點,對應於一個 serve,即用戶態的 BpBinder 對象
binder_ref 描述對 binder 實體節點的引用,關聯到一個 binder_node
binder_buffer 描述 binder 通信過程中存儲數據的Buffer
binder_work 描述一個 binder 任務
binder_transaction 描述一次 binder 任務相關的數據信息
binder_ref_death 描述 binder_node 即 binder server 的死亡信息

其中主要結構體引用關係如下:

 

面試官:可以,我們再來聊聊別的。

這個問題雖有些 "面試造火箭" 的無奈,可難點就是亮點、價值所在,是篩選面試者的有效手段。如果問你這個問題,你能回答多少呢?

如上圖,這裏有一份按模塊分好的 Binder 源碼,並有關鍵步驟註釋。

相關Android面試題地址:https://shimo.im/docs/VYcc3wyJRpy9jJ83/ 

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