02.Android之IPC機制問題

楊充發表於2019-01-07

目錄介紹

  • 2.0.0.1 什麼是Binder?為什麼要使用Binder?Binder中是如何進行執行緒管理的?總結binder講的是什麼?
  • 2.0.0.2 Android中程式和執行緒的關係?什麼是IPC?為何需要進行IPC?多程式通訊可能會出現什麼問題?
  • 2.0.0.3 Binder的工作流程是怎樣的?Binder主要能提供哪些功能?Binder通訊機制原理是怎樣的?
  • 2.0.0.4 Android中為何新增Binder來作為主要的IPC方式?Binder執行機制是怎樣的?Binder機制有什麼優勢?
  • 2.0.0.5 Android中跨程式通訊的幾種方式?實際開發中,有哪些場景使用Binder進行資料傳輸?
  • 2.0.0.6 Android中有哪些基於Binder的IPC方式?簡單對比下?
  • 2.0.0.7 為何說Binder相比傳統的Socket效能更高效?為何說Binder相比傳統IPC安全性更高?
  • 2.0.0.8 Service Manager是如何成為一個守護程式的?Server和Client是如何獲得Service Manager介面的?

好訊息

  • 部落格筆記大彙總【15年10月到至今】,包括Java基礎及深入知識點,Android技術部落格,Python學習筆記等等,還包括平時開發中遇到的bug彙總,當然也在工作之餘收集了大量的面試題,長期更新維護並且修正,持續完善……開源的檔案是markdown格式的!同時也開源了生活部落格,從12年起,積累共計500篇[近100萬字],將會陸續發表到網上,轉載請註明出處,謝謝!
  • 連結地址:github.com/yangchong21…
  • 如果覺得好,可以star一下,謝謝!當然也歡迎提出建議,萬事起於忽微,量變引起質變!所有的筆記將會更新到GitHub上,同時保持更新,歡迎同行提出或者push不同的看法或者筆記!

2.0.0.1 什麼是Binder?為什麼要使用Binder?Binder中是如何進行執行緒管理的?總結binder講的是什麼?

  • 什麼是Binder?
    • 1.直觀來說,Binder是Android中的一個類,它繼承了IBinder介面
    • 2.從IPC角度來說,Binder是Android中的一種跨程式通訊方式,Binder還可以理解為一種虛擬的物理裝置,它的裝置驅動是/dev/binder,該通訊方式在linux中沒有
    • 3.從Android Framework角度來說,Binder是ServiceManager連線各種Manager(ActivityManager、WindowManager,etc)和相應ManagerService的橋樑
    • 4.從Android應用層來說,Binder是客戶端和服務端進行通訊的媒介,當你bindService的時候,服務端會返回一個包含了服務端業務呼叫的Binder物件,通過這個Binder物件,客戶端就可以獲取服務端提供的服務或者資料,這裡的服務包括普通服務和基於AIDL的服務。
  • 為什麼要使用Binder?技術部落格大總結
    • 在傳統的Linux上,我們還是有很多選擇可以用來實現程式間通訊,如管道、SystemV、Socket等。那麼Android為什麼不使用這些原有的技術,而是要使開發一種新的叫Binder的程式間通訊機制呢?
    • 最簡單的回答:效能:相比傳統的Socket更高效;安全:安全性高,支援通訊雙方進行身份驗證。
    • 詳細一點說,主要有兩個方面的原因:
      • 效能方面
        • 在移動裝置上(效能受限制的裝置,比如要省電),廣泛地使用跨程式通訊對通訊機制的效能有嚴格的要求,Binder相對出傳統的Socket方式,更加高效。Binder資料拷貝只需要一次,而管道、訊息佇列、Socket都需要2次,共享記憶體方式一次記憶體拷貝都不需要,但實現方式又比較複雜。
      • 安全方面
        • 傳統的程式通訊方式對於通訊雙方的身份並沒有做出嚴格的驗證,比如Socket通訊ip地址是客戶端手動填入,很容易進行偽造,而Binder機制從協議本身就支援對通訊雙方做身份校檢,因而大大提升了安全性。
      • 還有一些好處,如實現面象物件的呼叫方式,在使用Binder時就和呼叫一個本地例項一樣。
  • Binder中是如何進行執行緒管理的?
    • 每個Binder的Server程式會建立很多執行緒來處理Binder請求,可以簡單的理解為建立了一個Binder的執行緒池吧(雖然實際上並不完全是這樣簡單的執行緒管理方式),而真正管理這些執行緒並不是由這個Server端來管理的,而是由Binder驅動進行管理的。
    • 一個程式的Binder執行緒數預設最大是16,超過的請求會被阻塞等待空閒的Binder執行緒。理解這一點的話,你做程式間通訊時處理併發問題就會有一個底,比如使用ContentProvider時(又一個使用Binder機制的元件),你就很清楚它的CRUD(建立、檢索、更新和刪除)方法只能同時有16個執行緒在跑。
  • 總結binder講的是什麼?
    • 通常意義上來說,Binder就是指Andriod的通訊機制;
    • 對於服務端程式來說,Binder指的是Binder本地物件,對於客戶端程式來說,Binder指的是Binder代理物件。
    • 對於傳輸過程來說,Binder是可以進行跨程式傳遞的物件;

2.0.0.2 Android中程式和執行緒的關係?什麼是IPC?為何需要進行IPC?多程式通訊可能會出現什麼問題?

  • Android中程式和執行緒的關係?
    • 一個APP一般對應一個程式和有限個執行緒
      • 一般對應一個程式,當然,可以在AndroidMenifest中給四大元件指定屬性android:process開啟多程式模式
      • 有限個執行緒:執行緒是一種受限的系統資源,不可無限制的產生且執行緒的建立和銷燬都有一定的開銷。
  • 什麼是IPC?
  • 為何需要進行IPC?
    • 程式間通訊的必要性
    • 所有執行在不同程式的四大元件,只要它們之間需要通過記憶體在共享資料,都會共享失敗。這是由於Android為每個應用分配了獨立的虛擬機器,不同的虛擬機器在記憶體分配上有不同的地址空間,這會導致在不同的虛擬機器中訪問同一個類的物件會產生多份副本。技術部落格大總結
  • 多程式造成的影響可總結為以下四方面
    • 靜態變數和單例模式失效:由獨立的虛擬機器造成
    • 執行緒同步機制失效:由獨立的虛擬機器造成
    • SharedPreference的不可靠下降:不支援兩個程式同時進行讀寫操作,即不支援併發讀寫,有一定機率導致資料丟失
    • Application多次建立:Android系統會為新的程式分配獨立虛擬機器,相當於系統又把這個應用重新啟動了一次。

2.0.0.3 Binder的工作流程是怎樣的?Binder主要能提供哪些功能?Binder通訊機制原理是怎樣的?

  • Binder的工作流程是怎樣的?
    • 1客戶端首先獲取伺服器端的代理物件。所謂的代理物件實際上就是在客戶端建立一個服務端的“引用”,該代理物件具有服務端的功能,使其在客戶端訪問服務端的方法就像訪問本地方法一樣。
    • 2客戶端通過呼叫伺服器代理物件的方式向伺服器端傳送請求。
    • 3代理物件將使用者請求通過Binder驅動傳送到伺服器程式。
    • 4伺服器程式處理使用者請求,並通過Binder驅動返回處理結果給客戶端的伺服器代理物件。
    • 5客戶端收到服務端的返回結果。
  • binder工作流程圖如下所示:
    • image
  • Binder主要能提供哪些功能?
    • 用驅動程式來推進程式間的通訊。
    • 通過共享記憶體來提高效能。
    • 為程式請求分配每個程式的執行緒池。
    • 針對系統中的物件引入了引用計數和跨程式的物件引用對映。
    • 程式間同步呼叫。
  • Binder通訊機制原理是怎樣的?
    • image
    • Server程式向ServiceManager註冊,告訴ServiceManager我是誰,我有什麼,我能做什麼。就好比徐同學(Server程式)有一臺筆記本(computer物件),這檯筆記本有個add方法。這時對映關係表就生成了。技術部落格大總結
    • Client程式向ServiceManager查詢,我要呼叫Server程式的computer物件的add方法,可以看到這個過程經過Binder驅動,這時候Binder驅動就開始發揮他的作用了。當向ServiceManager查詢完畢,是返回一個computer物件給Client程式嗎?其實不然,Binder驅動將computer物件轉換成了computerProxy物件,並轉發給了Client程式,因此,Client程式拿到的並不是真實的computer物件,而是一個代理物件,即computerProxy物件。很容易理解這個computerProxy物件也是有add方法,(如果連add方法都沒有,豈不是欺騙了Client?),但是這個add方法只是對引數進行一些包裝而已。
    • 當Client程式呼叫add方法,這個訊息傳送給Binder驅動,這時驅動發現,原來是computerProxy,那麼Client程式應該是需要呼叫computer物件的add方法的,這時驅動通知Server程式,呼叫你的computer物件的add方法,將結果給我。然後Server程式就將計算結果傳送給驅動,驅動再轉發給Client程式,這時Client程式還蒙在了鼓裡,他以為自己呼叫的是真實的computer物件的add方法,其實他只是呼叫了代理而已。不過Client最終還是拿到了計算結果。

2.0.0.4 Android中為何新增Binder來作為主要的IPC方式?Binder執行機制是怎樣的?Binder機制有什麼優勢?

  • Binder執行機制是怎樣的?
    • Binder基於Client-Server通訊模式,除了Client端和Server端,還有兩角色一起合作完成程式間通訊功能。
    • Binder通訊的四個角色:
      • Client程式:使用服務的程式。
      • Server程式:提供服務的程式。
      • ServiceManager程式:ServiceManager的作用是將字元形式的Binder名字轉化成Client中對該Binder的引用,使得Client能夠通過Binder名字獲得對Server中Binder實體的引用。
      • Binder驅動:驅動負責程式之間Binder通訊的建立,Binder在程式之間的傳遞,Binder引用計數管理,資料包在程式之間的傳遞和互動等一系列底層支援。
    • 接觸這些概念可能會覺得難於理解,讀者可以把四個角色和熟悉的網際網路進行類比:Server是伺服器,Client是客戶終端,ServiceManager是域名伺服器(DNS),驅動是路由器。
  • Binder機制有什麼優勢
    • 傳輸效率高、可操作性強:傳輸效率主要影響因素是記憶體拷貝的次數,拷貝次數越少,傳輸速率越高。從Android程式架構角度分析:對於訊息佇列、Socket和管道來說,資料先從傳送方的快取區拷貝到核心開闢的快取區中,再從核心快取區拷貝到接收方的快取區,一共兩次拷貝
    • 技術部落格大總結
    • 對於Binder來說,資料從傳送方的快取區拷貝到核心的快取區,而接收方的快取區與核心的快取區是對映到同一塊實體地址的,節省了一次資料拷貝的過程
    • 由於共享記憶體操作複雜,綜合來看,Binder的傳輸效率是最好的。
    • 實現C/S架構方便:Linux的眾IPC方式除了Socket以外都不是基於C/S架構,而Socket主要用於網路間的通訊且傳輸效率較低。Binder基於C/S架構 ,Server端與Client端相對獨立,穩定性較好。
    • 安全性高:傳統Linux IPC的接收方無法獲得對方程式可靠的UID/PID,從而無法鑑別對方身份;而Binder機制為每個程式分配了UID/PID且在Binder通訊時會根據UID/PID進行有效性檢測。

2.0.0.5 Android中跨程式通訊的幾種方式?實際開發中,有哪些場景使用Binder進行資料傳輸?

  • Android中跨程式通訊的幾種方式?
    • Android 跨程式通訊,像intent,contentProvider,廣播,service都可以跨程式通訊。
      • intent:這種跨程式方式並不是訪問記憶體的形式,它需要傳遞一個uri,比如說打電話。
      • contentProvider:這種形式,是使用資料共享的形式進行資料共享。
      • service:遠端服務,aidl
      • 廣播技術部落格大總結
  • 實際開發中,有哪些場景使用Binder進行資料傳輸?
    • 通過AIDL實現方式解釋Binder資料傳輸的具體過程
      • 服務端中的Service給與其繫結的客戶端提供Binder物件,客戶端通過AIDL介面中的asInterface()將這個Binder物件轉換為代理Proxy,並通過它發起RPC請求。客戶端發起請求時會掛起當前執行緒,並將引數寫入data然後呼叫transact(),RPC請求會通過系統底層封裝後由服務端的onTransact()處理,並將結果寫入reply,最後返回撥用結果並喚醒客戶端執行緒。
    • AIDL原理是什麼?如何優化多模組都使用AIDL的情況?
      • AIDL(Android Interface Definition Language,Android介面定義語言):如果在一個程式中要呼叫另一個程式中物件的方法,可使用AIDL生成可序列化的引數,AIDL會生成一個服務端物件的代理類,通過它客戶端實現間接呼叫服務端物件的方法。
      • AIDL的本質是系統提供了一套可快速實現Binder的工具。關鍵類和方法:
      AIDL介面:繼承IInterface。
      Stub類:Binder的實現類,服務端通過這個類來提供服務。
      Proxy類:伺服器的本地代理,客戶端通過這個類呼叫伺服器的方法。
      asInterface():客戶端呼叫,將服務端的返回的Binder物件,轉換成客戶端所需要的AIDL介面型別物件。返回物件:
          若客戶端和服務端位於同一程式,則直接返回Stub物件本身;
          否則,返回的是系統封裝後的Stub.proxy物件。
      asBinder():根據當前呼叫情況返回代理Proxy的Binder物件。
      onTransact():執行服務端的Binder執行緒池中,當客戶端發起跨程式請求時,遠端請求會通過系統底層封裝後交由此方法來處理。
      transact():執行在客戶端,當客戶端發起遠端請求的同時將當前執行緒掛起。之後呼叫服務端的onTransact()直到遠端請求返回,當前執行緒才繼續執行。
      複製程式碼
      • 當有多個業務模組都需要AIDL來進行IPC,此時需要為每個模組建立特定的aidl檔案,那麼相應的Service就會很多。必然會現系統資源耗費嚴重、應用過度重量級的問題。解決辦法是建立Binder連線池,即將每個業務模組的Binder請求統一轉發到一個遠Service中去執行,從而避免重複建立Service。
      • 工作原理:每個業務模組建立自己的AIDL介面並實現此介面,然後向服務端提供自己的唯一標識和其對應的Binder物件。服務端只需要一個Service,伺服器提供一個queryBinder介面,它會根據業務模組的特徵來返回相應的Binder對像,不同的業務模組拿到所需的Binder物件後就可進行遠端方法的呼叫了。

2.0.0.6 Android中有哪些基於Binder的IPC方式?簡單對比下?

  • image

2.0.0.7 為何說Binder相比傳統的Socket效能更高效?為何說Binder相比傳統IPC安全性更高?

  • 為何說Binder相比傳統的Socket效能更高效?
    • 跨程式通訊中,只有socket支援Client-Server的通訊方式,但是socket作為一款通用介面,其傳輸效率低,開銷大,主要用在跨網路的程式間通訊和本機上程式間的低速通訊。
    • 訊息佇列和管道採用儲存-轉發方式,即資料先從傳送方快取區拷貝到核心開闢的快取區中,然後再從核心快取區拷貝到接收方快取區,至少有兩次拷貝過程。
    • 共享記憶體雖然無需拷貝,但控制複雜,難以使用。
  • 為何說Binder相比傳統IPC安全性更高?
    • 首先傳統IPC的接收方無法獲得對方程式可靠的UID和PID(使用者ID程式ID),從而無法鑑別對方身份。Android為每個安裝好的應用程式分配了自己的UID,故程式的UID是鑑別程式身份的重要標誌。使用傳統IPC只能由使用者在資料包裡填入UID和PID,但這樣不可靠,容易被惡意程式利用。可靠的身份標記只有由IPC機制本身在核心中新增。其次傳統IPC訪問接入點是開放的,無法建立私有通道。比如命名管道的名稱,systemV的鍵值,socket的ip地址或檔名都是開放的,只要知道這些接入點的程式都可以和對端建立連線,不管怎樣都無法阻止惡意程式通過猜測接收方地址獲得連線。
    • 基於以上原因,Android需要建立一套新的IPC機制來滿足系統對通訊方式,傳輸效能和安全性的要求,這就是Binder。
    • Binder基於Client-Server通訊模式,傳輸過程只需一次拷貝,為傳送發新增UID/PID身份,既支援實名Binder也支援匿名Binder,安全性高。技術部落格大總結

2.0.0.8 Service Manager是如何成為一個守護程式的?Server和Client是如何獲得Service Manager介面的?

  • Service Manager是如何成為一個守護程式的?
    • Service Manager,它是整個Binder機制的守護程式,用來管理開發者建立的各種Server,並且向Client提供查詢Server遠端介面的功能技術部落格大總結
    • 既然Service Manager元件是用來管理Server並且向Client提供查詢Server遠端介面的功能,那麼,Service Manager就必然要和Server以及Client進行通訊了。我們知道,Service Manger、Client和Server三者分別是執行在獨立的程式當中,這樣它們之間的通訊也屬於程式間通訊了,而且也是採用Binder機制進行程式間通訊,因此,Service Manager在充當Binder機制的守護程式的角色的同時,也在充當Server的角色,然而,它是一種特殊的Server,下面我們將會看到它的特殊之處
    • Service Manager在使用者空間的原始碼位於frameworks/base/cmds/servicemanager目錄下,主要是由binder.h、binder.c和service_manager.c三個檔案組成。Service Manager的入口位於service_manager.c檔案中的main函式:
      int main(int argc, char **argv){
          struct binder_state *bs;
          void *svcmgr = BINDER_SERVICE_MANAGER;
          bs = binder_open(128*1024);
          if (binder_become_context_manager(bs)) {
              LOGE("cannot become context manager (%s)\n", strerror(errno));
              return -1;
          }
          svcmgr_handle = svcmgr;
          binder_loop(bs, svcmgr_handler);
          return 0;
      }
      複製程式碼
    • main函式主要有三個功能:一是開啟Binder裝置檔案;二是告訴Binder驅動程式自己是Binder上下文管理者,即我們前面所說的守護程式;三是進入一個無窮迴圈,充當Server的角色,等待Client的請求
  • Server和Client是如何獲得Service Manager介面的?
    • ServiceManager作為守護程式,Service Manager的職責當然就是為Server和Client服務了。那麼,Server和Client如何獲得Service Manager介面,進而享受它提供的服務呢?
    • Service Manager在Binder機制中既充當守護程式的角色,同時它也充當著Server角色,然而它又與一般的Server不一樣。對於普通的Server來說,Client如果想要獲得Server的遠端介面,那麼必須通過Service Manager遠端介面提供的getService介面來獲得,這本身就是一個使用Binder機制來進行程式間通訊的過程。而對於Service Manager這個Server來說,Client如果想要獲得Service Manager遠端介面,卻不必通過程式間通訊機制來獲得,因為Service Manager遠端介面是一個特殊的Binder引用,它的引用控制程式碼一定是0。
    • 經過一系列的呼叫...
    • 回到defaultServiceManager函式中,最終結果為:gDefaultServiceManager = new BpServiceManager(new BpBinder(0));
    • 這樣,Service Manager遠端介面就建立完成了,它本質上是一個BpServiceManager,包含了一個控制程式碼值為0的Binder引用。技術部落格大總結
  • 在Android系統的Binder機制中,Server和Client拿到這個Service Manager遠端介面之後怎麼用呢?
    • 對Server來說,就是呼叫IServiceManager::addService這個介面來和Binder驅動程式互動了,即呼叫BpServiceManager::addService 。而BpServiceManager::addService又會呼叫通過其基類BpRefBase的成員函式remote獲得原先建立的BpBinder例項,接著呼叫BpBinder::transact成員函式。在BpBinder::transact函式中,又會呼叫IPCThreadState::transact成員函式,這裡就是最終與Binder驅動程式互動的地方了。回憶一下前面的類圖,IPCThreadState有一個PorcessState型別的成中變數mProcess,而mProcess有一個成員變數mDriverFD,它是裝置檔案/dev/binder的開啟檔案描述符,因此,IPCThreadState就相當於間接在擁有了裝置檔案/dev/binder的開啟檔案描述符,於是,便可以與Binder驅動程式互動了。
    • 對Client來說,就是呼叫IServiceManager::getService這個介面來和Binder驅動程式互動了。具體過程上述Server使用Service Manager的方法是差不多的。

關於其他內容介紹

01.關於部落格彙總連結

02.關於我的部落格

相關文章