Android進階(六)Binder機制

1、進程通訊

一、進程隔離:

進程隔離是爲保護操做系統中進程互不干擾而設計的一組不一樣硬件和軟件的技術。進程數據不共享,進程A的虛擬地址和進程B的虛擬地址不一樣,這樣就防止進程A將數據信息寫入進程B,保證了數據的安全性。 java

  • 進程空間分爲內核空間和用戶空間,內核空間(Kernel)是系統內核運行的空間。用戶空間(User Space)是用戶程序運行的空間,他們之間是隔離的。
  • 內核有訪問的全部權限,用戶空間也能夠經過系統接口去訪問內核空間。用戶空間能夠經過內核空間(相似於中介者)進行相互訪問。

二、Linux進程間IPC方式:

  • 管道
  • 消息隊列
  • 共享內存
  • 套接字
  • 信號量
  • 信號

Linux 下的傳統 IPC 通訊原理: android

傳輸過程:
內存緩存區 --> 內核緩存區 --> 內存緩存區,須要 2 次數據拷貝;

三、Binder機制的特色

(1)傳輸性能

  • Binder數據拷貝只須要一次,而消息隊列、管道、Socket等須要兩次,共享內存一次拷貝都不須要。Binder性能僅次於共享內存。

(2)穩定性緩存

  • Binder基於C/S架構,Server端和Client端相對獨立,穩定性好。
  • 共享內存沒有Server端和Client端的區分,可能存在同步死鎖等問題。Binder穩定性優於共享內存。

(3)安全性安全

  • 傳統的Linux通訊方式沒法獲取對方進程的UID,因此訪問接入點是開放的,不安全。
  • Android爲每一個應用程序分配了本身的UID,做爲自身的標識。Binder的方式能夠經過UID創建私有通道,Binder的安全性更高。

2、Binder機制實現原理

一、內存映射

Binder IPC正是基於內存映射(mmap)來實現的 bash

Binder通訊過程:

  • 首先 Binder 驅動在內核空間建立一個數據接收緩存區;
  • 接着在內核空間開闢一塊內核緩存區,創建內核緩存區和內核中數據接收緩存區之間的映射關係,以及內核中數據接收緩存區和接收進程用戶空間地址的映射關係;
  • 發送方進程經過系統調用 copy_from_user() 將數據 copy 到內核中的內核緩存區,因爲內核緩存區和接收進程的用戶空間存在內存映射,所以也就至關於把數據發送到了接收進程的用戶空間,這樣便完成了一次進程間的通訊。

二、Binder通訊模型

  • 包括 Client、Server、ServiceManager、Binder 驅動。
  • 其中 Client、Server、Service Manager 運行在用戶空間,Binder 驅動運行在內核空間。
  • 對於Client,Binder是Server本地對象的一個引用,這個引用其實是一個代理對象,Client經過這個代理對象來間接訪問Server的本地對象。
  • 對於Server,Binder是提供具體實現的本地對象,需向ServiceManager註冊。
  • Binder驅動是鏈接Client來Server的橋樑,負責將代理對象轉化爲本地對象,並將Server的執行結果返回給Client。
  • ServiceManager它保存了Server Binder字符名稱和Binder引用的映射,Client經過它來找到Server的Binder引用。

三、Binder通訊過程:

  • 一個進程使用 BINDERSETCONTEXT_MGR 命令經過 Binder 驅動將本身註冊成爲 ServiceManager;
  • Server 經過驅動向 ServiceManager 中註冊 Binder,代表能夠對外提供服務。驅動爲這個 Binder 建立位於內核中的實體節點以及 ServiceManager 對實體的引用,將名字以及新建的引用打包傳給 ServiceManager,ServiceManger 將其填入查找表。
  • Client 經過名字,在 Binder 驅動的幫助下從 ServiceManager 中獲取到對 Binder 實體的引用,經過這個引用就能實現和 Server 進程的通訊。

3、AIDL

一、AIDL使用的基本步驟

(1)生成AIDL接口(new->AIDL->AIDL File)架構

interface MyWindowManager {
    void sysout();
}
複製代碼

生成AIDL文件以後,比起之前多了一個叫作 aidl 的包,並且他的層級是和 java 包相同的。
(2)編譯MyWindowManager.aidl生成Java文件ide

public interface MyWindowManager extends android.os.IInterface {
  /** Local-side IPC implementation stub class. */
  //Stub 繼承 Binder, 說明它是一個 Binder 本地對象;實現 IInterface 接口,代表Server能夠提供的方法
  public static abstract class Stub extends android.os.Binder
      implements com.example.myview.binder.MyWindowManager {
    private static final java.lang.String DESCRIPTOR = "com.example.myview.binder.MyWindowManager";

    /** Construct the stub at attach it to the interface. */
    public Stub() {
      this.attachInterface(this, DESCRIPTOR);
    }

    public static com.example.myview.binder.MyWindowManager asInterface(android.os.IBinder obj) {
      if ((obj == null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin != null) && (iin instanceof com.example.myview.binder.MyWindowManager))) {
        return ((com.example.myview.binder.MyWindowManager) iin);
      }
      return new com.example.myview.binder.MyWindowManager.Stub.Proxy(obj);
    }

    @Override
    public android.os.IBinder asBinder() {
      return this;
    }

    @Override
    public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
        throws android.os.RemoteException {
      ......
      return super.onTransact(code, data, reply, flags);
    }

    //Binder本地代理對象
    private static class Proxy implements com.example.myview.binder.MyWindowManager {
      private android.os.IBinder mRemote;

      Proxy(android.os.IBinder remote) {
        mRemote = remote;
      }

      @Override
      public android.os.IBinder asBinder() {
        return mRemote;
      }

      public java.lang.String getInterfaceDescriptor() {
        return DESCRIPTOR;
      }

      @Override
      public void sysout() throws android.os.RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          mRemote.transact(Stub.TRANSACTION_sysout, _data, _reply, 0);
          _reply.readException();
        } finally {
          _reply.recycle();
          _data.recycle();
        }
      }
    }

    static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_sysout = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
  }

  public void sysout() throws android.os.RemoteException;
}
複製代碼
  • MyWindowManager繼承了IInterface,是Client和Server通訊的接口
  • Stub爲靜態抽象內部類,繼承了Binder。其子類須要實現MyWindowManager接口,是Server的Binder的本地對象
  • Stub.Proxy爲靜態內部類,內部包含了IBinder對象,是Server在Client中的本地代理對象,將參數序列化後交給mRemote處理,實現了跟遠程Stub的通訊
  • asInterface方法一般是Client在bindService成功後,由Client來調用的,做用是將綁定成功後返回的IBinder對象轉換爲具體的IInterface接口。Client拿到這個IInterface接口後跟Server進行通訊

(3)Server端提供方法的具體實現工具

public class MyWindowManagerService extends Service {
  @Nullable
  @Override
  public IBinder onBind(Intent intent) {
    return mWindowManager;
  }

  private final MyWindowManager.Stub mWindowManager = new MyWindowManager.Stub() {
    @Override
    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble,
        String aString) throws RemoteException {

    }

    @Override
    public void sysout() throws RemoteException {
      Log.e("hj", "sysout: " );
    }
  };

}
複製代碼

(4)其餘進程的Activity實現跟Service的通訊性能

public class MainActivity extends AppCompatActivity {
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Intent intent = new Intent(this, MyWindowManagerService.class);
    bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
  }

  ServiceConnection mConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
      MyWindowManager windowManager = MyWindowManager.Stub.asInterface(service);
      try {
        windowManager.sysout();
      } catch (RemoteException e) {
        e.printStackTrace();
      }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {

    }
  };
}
複製代碼

二、IBinder/IInterface/Binder/BinderProxy/Stub

  • IBinder : IBinder 是一個接口,表明了一種跨進程通訊的能力。只要實現了這個藉口,這個對象就能跨進程傳輸。
  • IInterface : IInterface 表明的就是 Server 進程對象提供了哪些方法
  • Binder : Java 層的 Binder 類,表明的其實就是 Binder 本地對象。Proxy 類是 Binder 類的一個內部類,它表明遠程進程的 Binder 對象的本地代理;這兩個類都繼承自 IBinder, 於是都具備跨進程傳輸的能力;實際上,在跨越進程的時候,Binder 驅動會自動完成這兩個對象的轉換。
  • Stub : AIDL 的時候,編譯工具會給咱們生成一個名爲 Stub 的靜態內部類;這個類繼承了 Binder, 說明它是一個 Binder 本地對象,它實現了 IInterface 接口,代表它具備 Server 承諾給 Client 的能力;Stub 是一個抽象類,具體的 IInterface 的相關實現須要本身實現。

參考文章:
Android Binder設計與實現 - 設計篇
爲何 Android 要採用 Binder 做爲 IPC 機制?
寫給 Android 應用工程師的 Binder 原理剖析ui

相關文章
相關標籤/搜索