02.Android之IPC機制問題

目錄介紹

  • 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萬字],將會陸續發表到網上,轉載請註明出處,謝謝!
  • 鏈接地址:https://github.com/yangchong2...
  • 如果覺得好,可以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.關於我的博客

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