AIDL 原理分析

1.AIDL定義

Android Interface Define Language Android 接口定義語言氛雪。用于服務(wù)器與客戶端通信接口的一種描述語言房匆。可以生成用于IPC的代碼模塊注暗。

1.1AIDL支持?jǐn)?shù)據(jù)類型:

  1.Java中的八種基本數(shù)據(jù)類型坛缕,包括 byte、short捆昏、int赚楚、long、float骗卜、double宠页、boolean、char寇仓。
  2.String 類型举户。
  3.CharSequence類型。
  4.List類型:List中的所有元素必須是AIDL支持的類型之一
  5.Map類型:Map中的所有元素必須是AIDL支持的類型之一

2.AIDL通信原理說明

AIDL文件自動生成接口類遍烦,繼承IInterface俭嘁,主要包含兩部分Stub和Proxy。Stub繼承IBinder服猪,Proxy實現(xiàn)接口類供填,同時持有Stub(IBinder引用)。

2.1實現(xiàn)流程

Stub類中有一個對于當(dāng)前aidl接口的描述罢猪,這個描述信息同時是唯一的近她,通過描述信息會將當(dāng)前接口注冊到Binder驅(qū)動的內(nèi)存中

    private static final String DESCRIPTOR = "com.xue.data.xipcutils.aidl.IXIPCAidlInterface";

客戶端連接服務(wù)器,在serviceConnected中我們獲取到AIDL的接口類膳帕,我們調(diào)用到Stub中asInterface(IBinder)接口粘捎,同時將IBinder傳入。

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            IXIPCAidlInterface ixipcAidlInterface = IXIPCAidlInterface.Stub.asInterface(service);
            xIpcServiceMap.put(clazz, ixipcAidlInterface);
        }
    public static IXIPCAidlInterface asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof IXIPCAidlInterface))) {
        return ((IXIPCAidlInterface)iin);
      }
     //將IBinder對象作為參數(shù)傳入到Proxy中
      return new Proxy(obj);
    }

在Proxy類中將IBinder對象保存危彩,名為mRemote

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

客戶端調(diào)用aidle接口中send(String msg)方法攒磨,實則是在調(diào)用Proxy中的send方法

 Response response =  iXIPCAidlInterface .send(request);

在Proxy的send方法中,會調(diào)用到IBinder 的transact() 汤徽,Binder是IBinder的實現(xiàn)類咧纠,所以會調(diào)用到Binder中的transact方法

  @Override public Response send(Request request) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain(); //參數(shù)
        android.os.Parcel _reply = android.os.Parcel.obtain();//接受者
        Response _result;
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          if ((request!=null)) {
            _data.writeInt(1);
            request.writeToParcel(_data, 0);//參數(shù)序列化 寫入到_data中
          }
          else {
            _data.writeInt(0);
          }
        //調(diào)用IBinder的transact方法
          boolean _status = mRemote.transact(Stub.TRANSACTION_send, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().send(request);
          }
          _reply.readException();
          if ((0!=_reply.readInt())) {
            _result = Response.CREATOR.createFromParcel(_reply);
          }
          else {
            _result = null;
          }
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
        return _result;
      }

Binder中transact方法 又調(diào)用了onTransact方法,前文講到Stub繼承了IBinder,所以調(diào)用到了Stub的onTransact方法

    public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply,
            int flags) throws RemoteException {
        if (false) Log.v("Binder", "Transact: " + code + " to " + this);

        if (data != null) {
            data.setDataPosition(0);
        }
        boolean r = onTransact(code, data, reply, flags);
        if (reply != null) {
            reply.setDataPosition(0);
        }
        return r;
    }

Stub類的onTransact方法,源碼中可以看到在onTransct中直接調(diào)用到了 this.send(_arg0)方法泻骤,實則就是我們服務(wù)器端的方法漆羔。

    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
      String descriptor = DESCRIPTOR;
      switch (code)
        ............
        case TRANSACTION_send:
        {
          data.enforceInterface(descriptor);
          Request _arg0;
          ............
          //反序列化獲取到request參數(shù)
            _arg0 = Request.CREATOR.createFromParcel(data);
          
        //將客戶端的請求信息帶入到服務(wù)端梧奢, 然后由服務(wù)端調(diào)用方法并返回數(shù)據(jù)
          Response _result = this.send(_arg0);
          reply.writeNoException();
          if ((_result!=null)) {
            reply.writeInt(1);
            _result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
          }
       ...........
    }

再來看下我們服務(wù)端的send方法

public class XIPCService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }
    /**
     *注冊binder
     */
    private IXIPCAidlInterface.Stub binder = new IXIPCAidlInterface.Stub() {
        @Override
        public Response send(Request request) throws RemoteException {
             Response  response = new Response();
            response.setData("主線程返回數(shù)據(jù)給你");
            return response;
        }
    };
}

總結(jié)下

1.進(jìn)程A訪問進(jìn)程B,進(jìn)程A通過bindService啟動進(jìn)程B演痒。
2.進(jìn)程B在創(chuàng)建的時候就創(chuàng)建了自己的IBinder引用亲轨,是Stub類型的AIDL對象。
3.當(dāng)我們進(jìn)程A去訪問進(jìn)程的B的時候鸟顺,在建立連接后惦蚊,會拿到這個IBinder引用,通過asInterface產(chǎn)生這個進(jìn)程的Proxy對象讯嫂。
4.拿到IBinder引用后蹦锋, 進(jìn)程A可以通過這個引用去訪問對應(yīng)的進(jìn)程B,通過調(diào)用transcat方法欧芽。而transcat方法調(diào)用其實就是去連接Binder驅(qū)動莉掂,寫入數(shù)據(jù)。
5.調(diào)用transcat方法會調(diào)用同進(jìn)程Stub的onTransact方法
6.最終服務(wù)端進(jìn)程方法被調(diào)用

基于使用aidl進(jìn)程間通信千扔,鄙人手寫了一下進(jìn)程間通信框架憎妙,感興趣的童鞋可以看下,順手點個贊喲~
XIPCUtils

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末曲楚,一起剝皮案震驚了整個濱河市厘唾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌龙誊,老刑警劉巖抚垃,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異趟大,居然都是意外死亡讯柔,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進(jìn)店門护昧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人粗截,你說我怎么就攤上這事惋耙。” “怎么了熊昌?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵绽榛,是天一觀的道長。 經(jīng)常有香客問我婿屹,道長灭美,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任昂利,我火速辦了婚禮届腐,結(jié)果婚禮上铁坎,老公的妹妹穿的比我還像新娘。我一直安慰自己犁苏,他們只是感情好硬萍,可當(dāng)我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著围详,像睡著了一般朴乖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上助赞,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天买羞,我揣著相機(jī)與錄音,去河邊找鬼雹食。 笑死畜普,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的婉徘。 我是一名探鬼主播漠嵌,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼盖呼!你這毒婦竟也來了儒鹿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤几晤,失蹤者是張志新(化名)和其女友劉穎约炎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蟹瘾,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡圾浅,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了憾朴。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狸捕。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖众雷,靈堂內(nèi)的尸體忽然破棺而出灸拍,到底是詐尸還是另有隱情,我是刑警寧澤砾省,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布鸡岗,位于F島的核電站,受9級特大地震影響编兄,放射性物質(zhì)發(fā)生泄漏轩性。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一狠鸳、第九天 我趴在偏房一處隱蔽的房頂上張望揣苏。 院中可真熱鬧悯嗓,春花似錦、人聲如沸舒岸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛾派。三九已至俄认,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間洪乍,已是汗流浹背眯杏。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留壳澳,地道東北人岂贩。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像巷波,于是被迫代替她去往敵國和親萎津。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容