日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Binder实用指南(一) - 理解篇

發(fā)布時間:2025/3/15 编程问答 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Binder实用指南(一) - 理解篇 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

這是關于Android Binder機制的一篇文章,Binder是Android里面非常重要的組成,也是最難理解的一塊知識點,學習Binder最好的方法是深入源碼閱讀,因為Binder相關的知識錯綜復雜,一般初學者也很容易迷失在源碼的汪洋里,本文旨在梳理Binder的架構和流程,并且試著以實用的角度來看待Binder。

一、為什么需要Binder機制?

Android系統(tǒng)中,每個應用程序是由Android的Activity,Service,Broadcast,ContentProvider這四劍客的中一個或多個組合而成,這四劍客所涉及的多進程間的通信底層都是依賴于Binder IPC機制。例如當進程A中的Activity要向進程B中的Service通信,這便需要依賴于Binder IPC。
如果熟悉Android源碼,其實可以知道整個Android系統(tǒng)架構中,也大量采用了Binder機制作為IPC(進程間通信)方案。
Android是在Linux內(nèi)核的基礎上設計的。而在Linux中,已經(jīng)擁有”管道/消息隊列/共享內(nèi)存/信號量/Socket等等”眾多的IPC通信手段;但是,Google為什么單單選擇了Binder,可見Binder肯定有自己獨特的優(yōu)勢:

1.1 Binder能很好的實現(xiàn)C/S架構

Android系統(tǒng),很大一部分都是居于Client-Server架構的設計。Client端有什么需求,直接發(fā)送給Server端去完成,Server處理完畢再將反饋內(nèi)容發(fā)送給Client。Server端與Client端相對獨立,穩(wěn)定性較好。傳統(tǒng)的CS架構只有Socket,但是Socket通信效率相對于其他IPC來說又太低效,而Binder正是基于C/S架構設計的。

1.2 Binder傳輸效率高

Binder只需要進行一次拷貝,把Client端的用戶空間的數(shù)據(jù)即copy_from_user()到內(nèi)核空間,然后將內(nèi)核空間的數(shù)據(jù)映射到Server端的用戶空間。
Binder性能上僅僅次于Linux 共享內(nèi)存的方式,但是共享內(nèi)存的方式,進程間同步又是一個難題。

1.3 Binder安全性極高

Android為每個安裝好的應用程序分配了自己的UID,故進程的UID是鑒別進程身份的重要標志,Client端將任務發(fā)送給Server端,Server端會根據(jù)權限控制策略,判斷UID/PID是否滿足訪問權限。
Client-Server通信過程中,Binder內(nèi)核會為每個Client進程分配了UID/PID來作為鑒別身份的標示,并且在Binder通信時會根據(jù)UID/PID進行有效性檢測。
而如果是傳統(tǒng)的IPC只能由在數(shù)據(jù)包當中填入UID/PID,這個并不是一個可靠的方法。

知乎上有一位答主講得很好,可以看看:

為什么 Android 要采用 Binder 作為 IPC 機制?

二、Binder原理

  • Binder采用Client-Server架構,包含Client、Server、ServiceManager、Binder驅(qū)動四個組件。
  • 應用程序都運行在用戶空間,每個應用程序都有它自己獨立的內(nèi)存空間;若不同的應用程序之間涉及到通信,需要通過內(nèi)核進行中轉,因為需要用到內(nèi)核的copy_from_user()和copy_to_user()等函數(shù)
  • Server進程要先注冊Service到ServiceManager,Client進程使用某Server的Service前,須先向ServiceManager中獲取相應的Service,然后使用Service。
  • 三、Binder驅(qū)動層



    當用戶空間調(diào)用open()方法,最終會調(diào)用binder驅(qū)動的binder_open()方法;mmap()/ioctl()方法也是同理,從用戶態(tài)進入內(nèi)核態(tài),都依賴于系統(tǒng)調(diào)用過程。

    3.1 binder_init

    注冊misc設備,指定相應文件操作的方法。

    3.2 binder_open

    創(chuàng)建binder_proc對象,并把當前進程等信息保存到binder_proc對象,該對象管理IPC所需的各種信息并擁有其他結構體的根結構體;再把binder_proc對象保存到文件指針filp,以及把binder_proc加入到全局鏈表binder_procs。

    3.3 binder_mmap

    在內(nèi)核虛擬地址空間,申請一塊與用戶虛擬內(nèi)存相同大小的內(nèi)存;然后再申請1個page大小的物理內(nèi)存,再將同一塊物理內(nèi)存分別映射到內(nèi)核虛擬地址空間和用戶虛擬內(nèi)存空間,從而實現(xiàn)了用戶空間的Buffer和內(nèi)核空間的Buffer同步操作的功能。

    3.4 binder_ioctl

    負責在兩個進程間收發(fā)IPC數(shù)據(jù)和IPC reply數(shù)據(jù)。調(diào)用流程比如:

    123456789101112 //step 1:binder_write_read bwr;ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) // step 2:binder_ioctl(filp, BINDER_WRITE_READ, &bwr) // step 3:binder_ioctl_write_read(filp, BINDER_WRITE_READ, &bwr, thread) // step 4:copy_from_user(&bwr, ubuf, sizeof(bwr))binder_thread_write(proc, thread, bwr.write_buffer, bwr.write_size, &bwr.write_consumed);binder_thread_read(proc, thread, bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);copy_to_user(...)

    binder_thread_write():處理Binder請求碼,以”BC_“開頭,簡稱BC碼,用于從IPC層傳遞到Binder Driver層;
    binder_thread_read():生成Binder響應碼,以”BR_“開頭,簡稱BR碼,用于從Binder Driver層傳遞到IPC層;

    四、Binder通信流程

    例如當名為BatteryStatsService的Client向ServiceManager注冊服務的過程中,IPC層的數(shù)據(jù)組成為:
    Handle=0,RPC代碼為ADD_SERVICE_TRANSACTION,RPC數(shù)據(jù)為BatteryStatsService,Binder協(xié)議為BC_TRANSACTION。
    整個流程圖大致如下:



    handle為0正是指向ServiceManager。

    五、啟動ServiceManager

    ServiceManager啟動時序圖:

  • 打開binder驅(qū)動,并調(diào)用mmap()方法分配128k的內(nèi)存映射空間:binder_open();
  • 通知binder驅(qū)動使其成為守護進程:binder_become_context_manager();
  • 驗證selinux權限,判斷進程是否有權注冊或查看指定服務;
  • 進入循環(huán)狀態(tài),等待Client端的請求:binder_loop()。
  • 六、獲取ServiceManager

    獲取Service Manager是通過defaultServiceManager()方法來完成,當進程注冊服務(addService)或 獲取服務(getService)的過程之前,都需要先調(diào)用defaultServiceManager()方法來獲取gDefaultServiceManager對象。

  • 獲取ProcessState對象,在其構造函數(shù)中調(diào)用open_driver函數(shù)打開Binder驅(qū)動,并將句柄保存到mDriverFD;
  • 調(diào)用gProcess->getContextObject函數(shù)來獲得一個句柄值為0的Binder引用,即BpBinder;
  • 通過interface_cast構造一個BpServiceManager對象,所以gDefaultServiceManager最終為new BpServiceManager(new BpBinder(0))。
  • 七、addService

    以Native層的服務以media服務為例,注冊MediaPlayerService的時序圖如下:

  • defaultServiceManager()返回的是BpServiceManager,會調(diào)用BpServiceManager.addService方法
  • addService()通過remote()中保存的BpBinder調(diào)用到IPCThreadState的transact方法;
  • IPCThreadState::transact會調(diào)用writeTransactionData()傳輸數(shù)據(jù)傳輸數(shù)據(jù),然后和驅(qū)動交互,驅(qū)動把請求轉發(fā)給ServiceManager執(zhí)行真正的注冊服務;
  • 得到驅(qū)動的返回后,調(diào)用BBinder,最終調(diào)用到BnMediaPlayerService的onTransact方法;
  • 開啟兩個線程不斷和Binder進行交互,獲取Client請求。
  • 獲取服務的流程基本也是差不多的,不再累述。

    八、Binder架構

    binder在framework層,采用JNI技術來調(diào)用native(C/C++)層的binder架構,從而為上層應用程序提供服務。 我們知道native層中,binder是C/S架構,分為Bn端(Server)和Bp端(Client)。對于java層在命名與架構上非常相近,同樣實現(xiàn)了一套IPC通信架構。

    1.BinderProxy類代碼Client端,Binder類代表Server端
    2.framework層的Binder邏輯是建立在Native層架構基礎之上的,核心邏輯都是交予Native層方法來處理

    比如addService流程:
    1.java層通過getIServiceManager獲得ServiceManagerProxy對象,通過該對象的BinderProxy,最終會調(diào)用BpBinder對象,由BpBinder來完成通信。
    2.Binder驅(qū)動將Client端的請求轉發(fā)給BBinder的transact方法,然后由其子類JavaBBinder調(diào)用。后者會調(diào)用指定Service的方法,并返回給驅(qū)動。

    九、Binder類圖

    9.1 Native Binder類圖

    9.2 Framework Binder類圖

    十、Binder其他

    介紹一些Binder其他比較重要的點,方便理清Binder的一些疑問。比如Binder實體和引用,比如ProcessState和IPCThreadState,比如數(shù)據(jù)結構怎么傳遞等。

    10.1 Binder中各個角色的關系

    1. Binder實體 : binder_node

    Binder實體,是各個Server以及ServiceManager在內(nèi)核中的存在形式。
    Binder實體實際上是內(nèi)核中?binder_node?結構體的對象,它的作用是在內(nèi)核中保存Server和ServiceManager的信息(例如,Binder實體中保存了Server對象在用戶空間的地址)。簡言之,Binder實體是Server在Binder驅(qū)動中的存在形式,內(nèi)核通過Binder實體可以找到用戶空間的Server對象。
    在上圖中,Server和ServiceManager在Binder驅(qū)動中都對應的存在一個Binder實體。

    2. Binder引用 : binder_ref

    所謂Binder引用,實際上是內(nèi)核中binder_ref結構體的對象,它的作用是在表示”Binder實體”的引用。換句話說,每一個Binder引用都是某一個Binder實體的引用,通過Binder引用可以在內(nèi)核中找到它對應的Binder實體。
    如果將Server看作是Binder實體的話,那么Client就好比Binder引用。Client要和Server通信,它就是通過保存一個Server對象的Binder引用,再通過該Binder引用在內(nèi)核中找到對應的Binder實體,進而找到Server對象,然后將通信內(nèi)容發(fā)送給Server對象。
    Binder實體和Binder引用都是內(nèi)核(即Binder驅(qū)動)中的數(shù)據(jù)結構。每一個Server在內(nèi)核中就表現(xiàn)為一個Binder實體,而每一個Client則表現(xiàn)為一個Binder引用。這樣,每個Binder引用都對應一個Binder實體,而每個Binder實體則可以多個Binder引用。

    3. 遠程服務

    Server都是以服務的形式注冊到ServiceManager中進行管理的。如果將Server本身看作是”本地服務”的話,那么Client中的”遠程服務”就是本地服務的代理。如果你對代理模式比較熟悉的話,就很容易理解了,遠程服務就是本地服務的一個代理,通過該遠程服務Client就能和Server進行通信。

    10.2 進程和線程的關系

    圖解:
    1.Binder驅(qū)動通過binder_procs鏈表記錄所有創(chuàng)建的binder_proc結構體,binder驅(qū)動層的每一個binder_proc結構體都與用戶空間的一個用于binder通信的進程一一對應。
    2.每個進程有且只有一個ProcessState對象,這是通過單例模式來保證的。
    3.每個進程中可以有很多個線程,每個線程對應一個IPCThreadState對象,IPCThreadState對象也是單例模式,即一個線程對應一個IPCThreadState對象,在Binder驅(qū)動層也有與之相對應的結構,那就是Binder_thread結構體。在binder_proc結構體中通過成員變量rb_root threads,來記錄當前進程內(nèi)所有的binder_thread。

    Binder線程池:
    每個Server進程在啟動時會創(chuàng)建一個binder線程池,并向其中注冊一個Binder線程;之后Server進程也可以向binder線程池注冊新的線程,或者Binder驅(qū)動在探測到?jīng)]有空閑binder線程時會主動向Server進程注冊新的的binder線程。對于一個Server進程有一個最大Binder線程數(shù)限制,默認為16個binder線程,例如Android的system_server進程就存在16個線程。對于所有Client端進程的binder請求都是交由Server端進程的binder線程來處理的。

    10.3 Binder數(shù)據(jù)傳輸

    當Client向Server發(fā)送請求時,Client會將數(shù)據(jù)打包成上述格式,然后通過ioctl()發(fā)送給Binder驅(qū)動。

  • 用戶空間的進程調(diào)用ioctl(fd,BINDER_WRITE_READ,&bwr)時傳遞給Binder驅(qū)動的信息。fd是Binder驅(qū)動的文件句柄,BINDER_WRITE_READ是ioctl()的一個標識,而bwr是傳遞的數(shù)據(jù),write_buffer是請求數(shù)據(jù)的內(nèi)容,而write_consumed是用來記錄請求數(shù)據(jù)中已經(jīng)被Binder驅(qū)動處理過的數(shù)據(jù)的大小。
  • ioctl會走到binder_thread_writebinder_thread_read。這層的數(shù)據(jù)是”事務指令”+”binder_transaction_data結構體”組成的。data是保存事務中具體數(shù)據(jù)的內(nèi)存地址。具體調(diào)用流程可以參考#3.4章節(jié)
  • 這層是有效數(shù)據(jù)。如果該請求是傳遞給ServiceManager進行處理的,則有效數(shù)據(jù)是:消息頭+”Server的相關信息”。消息頭是用來進行有效性檢查的,而”Server的相關信息”則是請求要處理的信息。
  • 十一、源碼目錄

    從上之下, 整個Binder架構所涉及的總共有以下5個目錄:

    12345 /framework/base/core/java/ (Java)/framework/base/core/jni/ (JNI)/framework/native/libs/binder (Native)/framework/native/cmds/servicemanager/ (Native)/kernel/drivers/staging/android (Driver)

    11.1 Java framework

    12345678910111213 /framework/base/core/java/android/os/ - IInterface.java- IBinder.java- Parcel.java- IServiceManager.java- ServiceManager.java- ServiceManagerNative.java- Binder.java /framework/base/core/jni/ - android_os_Parcel.cpp- AndroidRuntime.cpp- android_util_Binder.cpp (核心類)

    11.2 Native framework

    1234567891011121314 /framework/native/libs/binder - IServiceManager.cpp- BpBinder.cpp- Binder.cpp- IPCThreadState.cpp (核心類)- ProcessState.cpp (核心類)/framework/native/include/binder/ - IServiceManager.h- IInterface.h/framework/native/cmds/servicemanager/ - service_manager.c- binder.c

    11.3 Kernel

    123 /kernel/drivers/staging/android/- binder.c- uapi/binder.h
    原文地址:?https://maoao530.github.io/2016/12/21/android-binder-01/

    總結

    以上是生活随笔為你收集整理的Binder实用指南(一) - 理解篇的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。