AIDL淺析

AIDL(Android Interface Definition Language)来累,即Android接口定義語言视乐。為了實現(xiàn)Android系統(tǒng)中進程與進程之間的通信(IPC)陨舱,而提供的一種通信方式宅广。

建立步驟

AndroidStudio為例氛改,具體步驟如下:

  1. java同級目錄下創(chuàng)建一個名為aidl的目錄恬口;
  2. 創(chuàng)建一個aidl文件;
  3. 執(zhí)行rebuild project即可自動生成.java文件弥锄,它的完整路徑是:app->build->generated->source->aidl->debug->com->lypeer->ipcclient->BookManager.jav丧靡;
圖1.png

圖2.png

類圖

類圖.png

在AIDL接口中有靜態(tài)內(nèi)部類類Stub和add()蟆沫、subtraction()方法,在靜態(tài)內(nèi)部類中存在內(nèi)部類Proxy温治。

代碼分析

  1. RemoteService初始化的執(zhí)行流程是RemoteService()->onCreate()->onBind()饭庞,這里我們將AIDL定義的接口方法進行了重寫,實現(xiàn)了具體功能罐盔。接著在onBind()方法里將Stub對象即IBinder對象返回出去但绕。
public class RemoteService extends Service {
    private IBinder iBinder;
    public RemoteService() {
    }
    @Override
    public void onCreate() {
        super.onCreate();
        //初始化Binder救崔,就是初始化Stub惶看,就是將Stub中的DESCRIPTION描述標(biāo)識依附到到Interface中記錄下來。方便客戶端獲取AIDL對象六孵,調(diào)用接口方法纬黎。
        iBinder = new MyBinder();
    }

    @Override
    public IBinder onBind(Intent intent) {
        return  iBinder;
    }

    class MyBinder extends IMyAidlInterface.Stub{
        @Override
        public void add(int a, int b) throws RemoteException {
              //add()方法的具體實現(xiàn)
        }
        @Override
        public int subtraction(int a, int b) throws RemoteException {
              ////subtraction()方法的具體實現(xiàn)
            return 0;
        }
    }
}
  1. 客戶端調(diào)用bindService以后,Service中的onCreate()劫窒、onBinder()方法依次執(zhí)行本今。會將IBinder對象返回到onServiceConnected方法中。從而借助于Stub中的asInterface方法去獲取本地AIDL對象或者實例化Proxy獲取遠(yuǎn)程AIDL對象主巍,進而調(diào)用接口中的方法冠息。
//綁定服務(wù)
bindService(new Intent(this, RemoteService.class), new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        //在RemoteService初始化的時候會生成IBinder對象,服務(wù)連接成功會返回IBinder孕索。

        //通過IMyAidlInterface.Stub中的asInterface方法根據(jù)Stub的DESCRIPTOR獲取AIDL對象,調(diào)用接口中的方法
        IMyAidlInterface aidlInterface = IMyAidlInterface.Stub.asInterface(iBinder);
        try {
            aidlInterface.add(1,1);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {

    }
},BIND_AUTO_CREATE);
  1. asInterface方法中執(zhí)行了很重要的代碼逛艰,它會先根據(jù)DESCRIPTION搜索本地是否存在AIDL對象,如果存在搞旭,則return散怖;否則就實例化Proxy,創(chuàng)建遠(yuǎn)程IBinder代理對象肄渗。
/**
 * Cast an IBinder object into an com.yolo.h5demo.IMyAidlInterface interface,
 * generating a proxy if needed.
 */
public static com.yolo.h5demo.IMyAidlInterface asInterface(android.os.IBinder obj) {
    if ((obj == null)) {
        return null;
    }
        //搜索本地是否已經(jīng)有可用的對象了
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin != null) && (iin instanceof com.yolo.h5demo.IMyAidlInterface))) {
        return ((com.yolo.h5demo.IMyAidlInterface) iin);
    }
        //新建遠(yuǎn)程Proxy對象镇眷,內(nèi)部實例化Binder
    return new com.yolo.h5demo.IMyAidlInterface.Stub.Proxy(obj);
}
  1. Proxy就是客戶端和服務(wù)端通信的代理類了,通過transact方法處理客戶端與服務(wù)端的數(shù)據(jù)流。正是由于asInterface獲取到IBinder代理對象即Proxy翎嫡,才會執(zhí)行transact方法將客戶端數(shù)據(jù)和請求發(fā)送到服務(wù)端欠动。
@Override
public void add(int a, int b) throws android.os.RemoteException {
    //_data用來存儲流向服務(wù)端的數(shù)據(jù)流,
    //_reply用來存儲服務(wù)端流回客戶端的數(shù)據(jù)流
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    try {
        _data.writeInterfaceToken(DESCRIPTOR);
        _data.writeInt(a);
        _data.writeInt(b);
        ////調(diào)用 transact() 方法將方法id和兩個 Parcel 容器傳過去
        mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
        ////從_reply中取出服務(wù)端執(zhí)行方法的結(jié)果
        _reply.readException();
    } finally {
        _reply.recycle();
        _data.recycle();
    }
}
  1. 服務(wù)端則根據(jù)參數(shù)惑申,通過switch語句執(zhí)行不同操作翁垂,調(diào)用服務(wù)端中對應(yīng)的方法,并將返回結(jié)果寫入reply流
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
    switch (code) {
        case INTERFACE_TRANSACTION: {
            reply.writeString(DESCRIPTOR);
            return true;
        }
        case TRANSACTION_add: {
            data.enforceInterface(DESCRIPTOR);
            int _arg0;
            _arg0 = data.readInt();
            int _arg1;
            _arg1 = data.readInt();
            this.add(_arg0, _arg1);
            reply.writeNoException();
            return true;
        }
        case TRANSACTION_subtraction: {
            data.enforceInterface(DESCRIPTOR);
            int _arg0;
            _arg0 = data.readInt();
            int _arg1;
            _arg1 = data.readInt();
            int _result = this.subtraction(_arg0, _arg1);
            reply.writeNoException();
            reply.writeInt(_result);
            return true;
        }
    }
    return super.onTransact(code, data, reply, flags);
}

補充

正如《Android內(nèi)核剖析》一書所言:重載onTransact()函數(shù)的主要內(nèi)容是把onTransact()函數(shù)的參數(shù)轉(zhuǎn)換為服務(wù)函數(shù)的參數(shù)硝桩,而 onTransact()函數(shù)的參數(shù)來源是客戶端調(diào)用transact()函數(shù)時輸入的沿猜,因此,如果transact()有固定格式的輸入碗脊,那么onTransact()就會有固定格式的輸出啼肩。

Binder框架

客戶端訪問遠(yuǎn)程服務(wù)橄妆,都需要通過mRemote對象,并調(diào)用transact方法祈坠。而在Binder驅(qū)動中也重載了transact方法害碾。

對開發(fā)人員而言,客戶端似乎直接調(diào)用了遠(yuǎn)程服務(wù)的Binder赦拘,而事實上是通過底層Binder驅(qū)動進行了中轉(zhuǎn)慌随。即存在兩個Binder對象,一個是服務(wù)端的躺同,另一個是Binder驅(qū)動中的阁猜。注意服務(wù)端會產(chǎn)生一個隱藏線程處理消息。

各位大神蹋艺,有描述不對之處還望指正剃袍!

參考資料
Binder底層原理與架構(gòu)設(shè)計剖析
AIDL

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市捎谨,隨后出現(xiàn)的幾起案子民效,更是在濱河造成了極大的恐慌,老刑警劉巖涛救,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件畏邢,死亡現(xiàn)場離奇詭異,居然都是意外死亡检吆,警方通過查閱死者的電腦和手機舒萎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來咧栗,“玉大人逆甜,你說我怎么就攤上這事≈掳澹” “怎么了交煞?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長斟或。 經(jīng)常有香客問我素征,道長,這世上最難降的妖魔是什么萝挤? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任御毅,我火速辦了婚禮,結(jié)果婚禮上怜珍,老公的妹妹穿的比我還像新娘端蛆。我一直安慰自己,他們只是感情好酥泛,可當(dāng)我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布今豆。 她就那樣靜靜地躺著嫌拣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪呆躲。 梳的紋絲不亂的頭發(fā)上异逐,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天,我揣著相機與錄音插掂,去河邊找鬼灰瞻。 笑死,一個胖子當(dāng)著我的面吹牛辅甥,可吹牛的內(nèi)容都是我干的酝润。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼肆氓,長吁一口氣:“原來是場噩夢啊……” “哼袍祖!你這毒婦竟也來了底瓣?” 一聲冷哼從身側(cè)響起谢揪,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎捐凭,沒想到半個月后拨扶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡茁肠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年患民,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片垦梆。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡匹颤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出托猩,到底是詐尸還是另有隱情印蓖,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布京腥,位于F島的核電站赦肃,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏公浪。R本人自食惡果不足惜他宛,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望欠气。 院中可真熱鬧厅各,春花似錦、人聲如沸预柒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至人灼,卻和暖如春围段,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背投放。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工奈泪, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人灸芳。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓涝桅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親烙样。 傳聞我的和親對象是個殘疾皇子冯遂,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,901評論 2 355

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

  • Android跨進程通信IPC整體內(nèi)容如下 1、Android跨進程通信IPC之1——Linux基礎(chǔ)2谒获、Andro...
    隔壁老李頭閱讀 10,759評論 13 43
  • Jianwei's blog 首頁 分類 關(guān)于 歸檔 標(biāo)簽 巧用Android多進程蛤肌,微信,微博等主流App都在用...
    justCode_閱讀 5,915評論 1 23
  • 一批狱、Android IPC簡介 IPC是Inter-Process Communication的縮寫裸准,含義就是進程...
    SeanMa閱讀 1,812評論 0 8
  • 簡單說Binder Binder算是Android中比較難懂的一部分內(nèi)容了,但是非常的重要赔硫,要想研究Framewo...
    EsonJack閱讀 1,549評論 0 4
  • 文/趙曉璃 不知你發(fā)現(xiàn)沒有炒俱,很多時候我們都在為了所謂的“最佳選擇”勞神費力。 但如果深究下去爪膊,很多看起來的“選擇”...
    趙曉璃閱讀 4,079評論 14 98