Binder機(jī)制原理

1.Binder是什么?

  • 機(jī)制:Binder是一種進(jìn)程間通信機(jī)制。
  • 驅(qū)動:Binder是一個虛擬物理設(shè)備驅(qū)動
  • 應(yīng)用層:Binder是一個能夠發(fā)起通信的java類

2.多進(jìn)程的使用以及優(yōu)勢

虛擬機(jī)分配給各個進(jìn)程的運行內(nèi)存是有限制的,LMK也會優(yōu)先回收對系統(tǒng)資源占用多的進(jìn)程

  • 突破進(jìn)程內(nèi)存限制
  • 功能穩(wěn)定性 ,獨立的通信進(jìn)程保持長連接的穩(wěn)定性。(極光推送,百度定位)
  • 規(guī)避系統(tǒng)內(nèi)存泄漏:獨立的WebView進(jìn)程阻隔內(nèi)存泄漏導(dǎo)致的問題。
  • 隔離風(fēng)險,對于不穩(wěn)定的功能放入到獨立進(jìn)程,避免導(dǎo)致主進(jìn)程的崩潰.

3.Linux中進(jìn)程間的通信機(jī)制有哪些?與傳統(tǒng)的IPC機(jī)制相比,有哪些優(yōu)勢?

[圖片上傳失敗...(image-27d811-1769743586604)]

Binder 共享內(nèi)存 socket 管道 消息隊列 信號 ,信號量

  • Binder:拷貝一次+內(nèi)存映射 基于CS架構(gòu),易用性強(qiáng)(Service>>binder >>分配uid 【如果是惡意軟件,通過uid找到,很安全】) ,雙向通信

  • 共享內(nèi)存: 無需拷貝 控制復(fù)雜,易用性差 (多線程使用同一塊內(nèi)存時,可能出現(xiàn)死鎖,數(shù)據(jù)不同步問題,訪問接入點事開放的,不安全) mmap原理實現(xiàn) ,雙向通信

  • socket : 拷貝二次 基于CS架構(gòu),效率低,開銷大 (訪問接入點是開放的,不安全),雙向通信

  • 管道Pipe: 拷貝二次,數(shù)據(jù)傳輸也是單向的,一個進(jìn)程向管道寫入數(shù)據(jù),另一個進(jìn)程從管道讀取數(shù)據(jù).
    [圖片上傳失敗...(image-8e0eb8-1769743586604)]

  • 消息隊列:拷貝二次,消息隊列是消息的鏈表,存放在內(nèi)核中,每個消息隊列都有隊列id來標(biāo)識,獨立與發(fā)送和接收進(jìn)程,進(jìn)程終止時,消息隊列中的內(nèi)容不會被刪除,也可以實現(xiàn)隨機(jī)查詢,消息不一定要以先進(jìn)先出的次序讀取,也可以按照消息的類型或者優(yōu)先級讀取.
    [圖片上傳失敗...(image-804230-1769743586604)]

  • 信號 (比如Vsync)是基于事件的異步通知,而不是數(shù)據(jù)的拷貝,當(dāng)某個時間發(fā)生時,內(nèi)核會向目標(biāo)進(jìn)程發(fā)送一個信號,信號會被添加到目標(biāo)進(jìn)程的信號隊列中,當(dāng)進(jìn)程從內(nèi)核態(tài)返回用戶態(tài)時,內(nèi)核會檢查信號隊列,并根據(jù)注冊的信號處理函數(shù)來處理信號.【無需拷貝】

注意:有些資料說是4次拷貝(發(fā)送進(jìn)程的用戶空間>>發(fā)送進(jìn)程內(nèi)核空間緩沖區(qū)>>內(nèi)存>>用戶進(jìn)程內(nèi)核緩沖區(qū)>>用戶進(jìn)程用戶空間),也可以簡化為2次拷貝(用戶空間 >>內(nèi)核緩沖區(qū)>>用戶空間)

4.Binder通信原理(一次拷貝+ 內(nèi)存映射)

  • 具體過程:
  1. 數(shù)據(jù)接收方進(jìn)程在初始化的時候,會直接調(diào)用mmap函數(shù),通過Binder驅(qū)動,提前在內(nèi)核空間開辟一塊共享的物理內(nèi)存,并映射到自己的用戶空間.
  2. 發(fā)送方進(jìn)程(無需通過Binder驅(qū)動在內(nèi)核開辟共享的物理內(nèi)存)將數(shù)據(jù)直接拷貝到這一塊內(nèi)核緩沖區(qū),由于接收方的用戶空間已經(jīng)映射了同一塊內(nèi)核緩沖區(qū),它無需再次拷貝,可以直接讀取.
  • 在完整的一次Binder遠(yuǎn)程方法調(diào)用中,客戶端和服務(wù)端的角色是動態(tài)轉(zhuǎn)換的
  1. 當(dāng)發(fā)起請求時客戶端是數(shù)據(jù)發(fā)送進(jìn)程,服務(wù)端(AMS)是數(shù)據(jù)接收進(jìn)程。
  2. 當(dāng)返回結(jié)果時服務(wù)端(AMS)是數(shù)據(jù)發(fā)送進(jìn)程,客戶端是數(shù)據(jù)接收進(jìn)程。

這就好比雙方在翻譯官(內(nèi)核)的辦公室里放了一個共享的公文袋(內(nèi)核緩沖區(qū)) 。客戶端直接把文件放進(jìn)公文袋,服務(wù)端伸手就從同一個袋子里拿,省去了翻譯官中間轉(zhuǎn)交的步驟。

[圖片上傳失敗...(image-5c04d9-1769743586604)]

5.MMAP(Memory Map)內(nèi)存映射的原理

  • 虛擬內(nèi)存劃分
    [圖片上傳失敗...(image-28658a-1769743586604)]

  • 內(nèi)存映射原理?

內(nèi)存映射簡單的講:數(shù)據(jù)接收方進(jìn)程在進(jìn)程是初始化內(nèi)核空間的一塊內(nèi)存區(qū)域映射到自己內(nèi)核空間,映射關(guān)系建立后,用戶對這塊內(nèi)存區(qū)域的修改可以直接反應(yīng)到內(nèi)核空間;反之內(nèi)核空間對這段區(qū)域的修改也能直接反應(yīng)到用戶空間提高了通信速度。

6.Binder通過Java代碼是如何實現(xiàn)的呢?

6.1.服務(wù)端,客戶端BookManager.aidl文件,根據(jù)aidl接口,系統(tǒng)自動幫忙生成Stub類繼承Binder并實現(xiàn)BookManager接口【服務(wù)端和客戶端生成的代碼是一樣的,只是調(diào)用邏輯不一樣而已】

interface BookManager{
     List<Book> getBookList();
}

6.2.根據(jù)aidl接口,自動生成BookManager.java類(aidl就是對binder的封裝)

//SDK提供
public interface IBinder {
   int FIRST_CALL_TRANSACTION = 1;
    boolean isBinderAlive();
}
//SDK提供
public class Binder implements IBinder {
    public boolean isBinderAlive() {
        throw new RuntimeException("Stub!");
    }
}
 //SDK提供
public interface IInterface {
    IBinder asBinder();
}

 //系統(tǒng)生成
public interface BookManager extends android.os.IInterface {

      public static abstract class Stub extends Binder implements BookManager {
           //自動生成的TRANSACTION_getBookList  
            static final int  TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
             private static final  String DESCRIPTOR = "com.lypeer.ipcclient.BookManager";  
             public Stub() {
                this.attachInterface(this, DESCRIPTOR);
             }
             //把IBinder對象轉(zhuǎn)BookManager接口的,如果需要的話,就生成一個Proxy代理類
             public static BookManager asInterface(IBinder obj) {
                 if ((obj == null)) {
                      return null;
                 }
                //此處得到的iin==null
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);//iin ==null
                if (((iin != null) && (iin instanceof BookManager))) {
                   return ((com.lypeer.ipcclient.BookManager) iin); //null
                }
                 //因為iin==null,所以此處只會生成一個代理類
                 return new com.lypeer.ipcclient.BookManager.Stub.Proxy(obj);   
             }  
             //返回IBinder的實現(xiàn)類
             public android.os.IBinder asBinder() {
                return this;
              }
   
            private static class Proxy implements BookManager{
                private android.os.IBinder mRemote;
                 Proxy(android.os.IBinder remote) {
                      mRemote = remote;
                 }
                 public IBinder asBinder()  {
                    return mRemote;
                 } 
                //客戶端調(diào)用getBookList
                 public   List<Book> getBookList() {
                       Parcel _data = android.os.Parcel.obtain();
                       Parcel _reply = android.os.Parcel.obtain();
                       List<Book> _result;
                         try {
                              _data.writeInterfaceToken(DESCRIPTOR);
                               //直接調(diào)用服務(wù)端transact方法
                               boolean _status = mRemote.transact(Stub.TRANSACTION_getBooks, _data, _reply, 0);
                               if (!_status && getDefaultImpl() != null) {
                                   return getDefaultImpl().getBookList();
                               }
                               _reply.readException();
                               _result = _reply.createTypedArrayList(com.lypeer.ipcclient.Book.CREATOR);
                              }finally{
                               _reply.recycle();
                               _data.recycle();
                          }
                         return _result;
                  }
           }
            // 服務(wù)端執(zhí)行onTransact根據(jù)code碼進(jìn)行處理
            public boolean onTransact(int code,Parcel data ,Parcel reply,int flags){
                    java.lang.String descriptor = DESCRIPTOR;
                    switch(code){
                         case TRASACTION_getBookLIst:{
                                //檢查客戶端調(diào)用的接口是否與服務(wù)端提供的接口一致
                                data.enforceInterface(descriptor);
                                List<com.lypeer.ipcclient.Book> _result = this.getBookList();
                                reply.writeNoException();
                                reply.writeTypedList(_result);
                                return true;
                         }
                     }
            }
      }
}

6.3.客戶端調(diào)用

public class AIDLActivity extends AppCompatActivity {
      private BookManager mBookManager = null;
      protected void onStart() {
           attemptToBindService();
    }

   //嘗試與服務(wù)器建立連接
   private void attemptToBindService() {
        Intent intent = new Intent();
        intent.setAction("com.lypeer.aidl");
        intent.setPackage("com.lypeer.ipcserver");
        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
    }
      private ServiceConnection mServiceConnection = new ServiceConnection() {
         public void onServiceConnected(ComponentName name, IBinder service) {
            Log.e(getLocalClassName(), "service connected");
            mBookManager = BookManager.Stub.asInterface(service); //得到Proxy對象
            mBound = true;
            if (mBookManager != null) {
                try {
                    mBooks = mBookManager.getBooks();
                    Log.e(getLocalClassName(), mBooks.toString());
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
         }
        public void onServiceDisconnected(ComponentName name) {
            Log.e(getLocalClassName(), "service disconnected");
            mBound = false;
        }
    };
    //mBookManager.getBookList>>Proxy.getBookList>>Proxy.mRemote.onTransact(Stub.TRANSACTION_getBookList)
    public getBookList(){
           if(mBookManager!=null){
              //回調(diào)Proxy類中的getBookList();
              mBookManager.getBookList();
           }
    }
}

6.4.服務(wù)端實現(xiàn)代碼

public class AIDLService extends Service{
        //包含Book對象的list
       private List<Book> bookList = new ArrayList<>();
        //實現(xiàn)抽象類Stub,Stub實現(xiàn)了BookManager接口
       private final BookManager.Stub mBookManager=new BookManager.Stub(){
               public List<Book> getBookList(){
                    return bookList;
               }
        }
       public void onCreate() {
            Book book = new Book();
            book.setName("Android開發(fā)藝術(shù)探索");
            book.setPrice(28);
            bookList.add(book);
            super.onCreate();
      }
      public IBinder onBind(Intent intent) {
          return mBookManager;
      }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容