[進階] Binder理解和源碼解析

基礎知識

Android進程間的通訊沒有沿用Linux的原有的通訊模式,而是採用新的通訊模式Binder.

先了解下Linux原有的通訊方式:Linux進程間的通信方式和原理

進程通信的應用場景一般包含數據/資源共享,數據傳輸,通知事件,進程控制。主動被動都有了。

Linux原有的幾種通信方式

  • pipe管道
  • 消息隊列(Message)
  • 信號量(Semaphore)
  • 共享內存(Share Memory)
  • 信號(Signal)
  • 跟蹤(Trace)
  • 還有支持支持C/S的Socket

Android爲什麼採用Binder?

Android沒有使用Linux原生的通信機制,而是使用Binder機制。
Binder機制是採用OpenBinder演化而來,採用C/S的通信模式。
在Android中使用它的原因如下

  • socket效率低,開銷大。linux目前只有socket支持C/S
  • 管道和消息隊列效率低。管道和消息採用存儲轉發方式,所以至少需要拷貝2次數據,效率低
  • 共享內存控制機制複雜:共享內存雖然在傳輸時沒有拷貝數據,但其控制機制複雜(比如跨進程通信時,需獲取對方進程的pid,得多種機制協同操作)。
  • Binder安全性更高
    • Linux的IPC機制在本身的實現中,並沒有安全措施,得依賴上層協議來進行安全控制。
    • Binder機制的UID/PID是由Binder機制本身在內核空間添加身份標識,安全性高;並且Binder可以建立私有通道,這是linux的通信機制所無法實現的(Linux訪問的接入點是開放的)

各種IPC方式數據拷貝次數對比

IPC方式 數據拷貝次數
共享內存 0
Binder 1
Socket/管道/消息隊列 2

總之,基於以上原因,Linux上原生機制無法滿足手機的要求,Android需要建立一套新的IPC機制來滿足系統對通信方式的傳輸性能和安全性要求,這就出現了Binder

Binder是什麼

Binder是Android系統中進程間通訊(IPC)的一種方式,像Intent, Messenger, ContentProvider底層都是Binder實現

  • Binder指的是一種通信機制。AIDL使用Binder進行通信,指的就是Binder這種IPC機制。
  • 對於Server進程來說,Binder指的是Binder本地對象。

    • Server端一般會實例一個Binder實現具體的接口,即Server能夠提供的能力(注意因爲Stub是abstract不能直接實例化,實例化的父類Binder對象)
    • 在onBind時將實例傳遞給Client

      ```
      public class BookManagerService extends Service {
          private static final String TAG = BookManagerService.class.getSimpleName();
      
          // book list
          private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<Book>();
          // new book listener RemoteCallbackList used for multi-process listener
          private RemoteCallbackList<INewBookListener> mListenerList = new RemoteCallbackList<INewBookListener>();
          private Binder mBinder = new IBookManager.Stub() {
      
              @Override
              public List<Book> getBookList() throws RemoteException {
                  SystemClock.sleep(2000);
                  return mBookList;
              }
      
              @Override
              public void addBook(Book book) throws RemoteException {
                  mBookList.add(book);
                  onNewBookArrived(book);
              }
          ......
          }
      
          @Override
          public IBinder onBind(Intent intent) {
              if (!verifyPermission()) {
                  return null;
              }
              return mBinder;
          }
      }
      
      ```
      
  • 對於Client來說,Binder指的是Binder代理對象,只是Binder本地對象的一個遠程代理

    • Client通過asInterface方法獲取Proxy代理或通過asBinder方法獲取Binder實例
    • 對這個Binder代理對象的操作,會通過驅動最終轉發到Binder本地對象上去完成,即調用Service的Binder實例的方法。
    • 對於一個擁有Binder對象的使用者而言,它無須關心這是一個Binder代理對象還是Binder本地對象。對於代理對象的操作和對本地對象的操作對它來說沒有區別。因爲實現了同一個接口
        public class BookManagerActivity extends AppCompatActivity {
            private static final String TAG = BookManagerActivity.class.getSimpleName();
    
            private IBookManager mRemoteBookManager;
    
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                super.onCreate(savedInstanceState);
                setContentView(R.layout.activity_book_manager);
                initView();
    
                // bind service : after 5.0 must follow
                // https://developer.android.com/google/play/billing/billing_integrate.html#billing-requests
                Intent intent = new Intent(this, BookManagerService.class);
                intent.setPackage(getPackageName());
                bindService(intent, mServiceConn, Context.BIND_AUTO_CREATE);
            }
    
            private ServiceConnection mServiceConn = new ServiceConnection() {
                public void onServiceConnected(ComponentName className, IBinder service) {
                    mRemoteBookManager = IBookManager.Stub.asInterface(service);
                    if (mRemoteBookManager != null)
                        try {
                            mRemoteBookManager.asBinder().linkToDeath(mDeathRecipient, 0);
                            mRemoteBookManager.registerListener(mNewBookListener);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    Log.d(TAG, "bind service");
                }
    
                public void onServiceDisconnected(ComponentName className) {
                    mRemoteBookManager = null;
                    Log.d(TAG, "onServiceDisconnected, tid = " + Thread.currentThread().getName());
                }
            };
    
            public void addBook(View v) {
                if (mRemoteBookManager == null) {
                    Log.w(TAG, "mRemoteBookManager is null");
                    return;
                }
    
                bookThreadPool.execute(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            int bookId = mRemoteBookManager.getBookSize() + 1;
                            Book newBook = new Book(bookId, "new-" + bookId);
                            mRemoteBookManager.addBook(newBook);
                            Log.d(TAG, "add book:" + newBook);
                        } catch (RemoteException e) {
                            e.printStackTrace();
                        }
                    }
                });
            }
        }
    
  • 對於傳輸過程而言,Binder是可以進行跨進程傳遞的對象;Binder驅動會對具有跨進程傳遞能力的對象做特殊處理:自動完成代理對象和本地對象的轉換

代碼片一

interface IBookManager {
    // get all book list
    List<Book> getBookList();
    // add one book
    void addBook(in Book book);
    // get book list size
    int getBookSize();
    // register and unregister new book listener
    void registerListener(INewBookListener listener);
    void unregisterListener(INewBookListener listener);
}

編譯器生成的IBookManager

這裏寫圖片描述

全部Code在這裏Github IPC

Binder架構

Binder架構圖(來自網上)

架構圖

詳細架構圖(來自網上)

這裏寫圖片描述

  • Binder 通信採用 C/S 架構:包含 Client、 Server、 ServiceManager 以及 Binder 驅動。
  • ServiceManager 用於管理系統中的各種服務。無論是註冊服務和獲取服務的過程都需要ServiceManager(Native C++層的ServiceManager不是framework java層的ServiceManager
  • Binder 在 framework 層進行了封裝,通過 JNI 技術調用 Native(C/C++)層的 Binder 架構。
  • Binder 在 Native 層以 ioctl 的方式與 Binder 驅動通訊

Binder機制

下圖是Binder機制是如何跨進程。(來自網絡)

每個Android的進程,只能運行在自己進程所擁有的虛擬地址空間。對應一個4GB的虛擬地址空間,其中3GB是用戶空間,1GB是內核空間(大小可以通過參數配置調整)。對於用戶空間,不同進程之間彼此是不能共享的,而內核空間卻是可共享的。Client進程向Server進程通信,恰恰是利用進程間可共享的內核內存空間來完成底層通信工作。Client端與Server端進程往往採用ioctl等方法跟內核空間的驅動進行交互。

ServiceManager是整個Binder通信機制的大管家,是Android進程間通信機制Binder的守護進程。當Service Manager啓動之後,Client端和Server端通信時都需要先獲取Service Manager接口,才能開始通信服務。ServiceManager是由init進程通過解析init.rc文件而創建的。

  • 註冊服務(addService):Server進程要先註冊Service到ServiceManager。該過程:Server是客戶端,ServiceManager是服務端。
  • 獲取服務(getService):Client進程使用某個Service前,須先向ServiceManager中獲取相應的Service。該過程:Client是客戶端,ServiceManager是服務端。
  • 使用服務:Client根據得到的Service信息建立與Service所在的Server進程通信的通路,然後就可以直接與Service交互。該過程:client是客戶端,server是服務端。

這裏寫圖片描述

Binder通信的基本流程

一次完整Binder通信圖(來自網上)

這裏寫圖片描述

深入理解Java層的Binder

  • IBinder是一個接口,它代表了一種跨進程傳輸的能力
    • 只要實現了這個接口,就能將這個對象進行跨進程傳遞。這是驅動底層支持的
    • 在跨進程數據流經驅動的時候,驅動會識別IBinder類型的數據,從而自動完成不同進程Binder本地對象以及Binder代理對象的轉換
  • IBinder負責數據傳輸,IInterface代表的就是遠程server對象具有什麼能力。就是aidl裏面的接口
  • Java層的Binder類,代表的其實就是Binder本地對象。
    • BinderProxy類是Binder類的一個內部類,它代表遠程進程的Binder對象的本地代理;這兩個類都繼承自IBinder, 因而都具有跨進程傳輸的能力;
    • 實際上,在跨越進程的時候,Binder驅動會自動完成這兩個對象的轉換。
  • 在使用AIDL的時候,編譯工具會給我們生成一個Stub的靜態內部類;
    • 繼承了Binder, 說明它是一個Binder本地對象
    • 它實現了IInterface接口,表明它具有遠程Server承諾給Client的能力;
    • Stub是一個抽象類,具體的IInterface的相關實現需要我們手動完成,這裏使用了策略模式。

這篇的深入理解Java層的Binder

Binder源碼解析

framework層的源碼分析可以看這裏

Reference

Android爲什麼選擇binder

一篇文章瞭解相見恨晚的 Android Binder 進程間通訊機制

Binder學習指南

老羅的 Android進程間通信(IPC)機制Binder簡要介紹和學習計劃 系列

Innost的 深入理解Binder 系列

Gityuan的 Binder系列 (基於 Android 6.0) Binder系列—開篇

Android Binder機制原理

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