aidl基礎(chǔ)用法和原理解析

aidl是android中非常重要的進(jìn)程間通信的方式毡泻,底層還是用的binder來實(shí)現(xiàn)的求冷。今天就重點(diǎn)講解一下aidl的使用和原理;

基礎(chǔ)使用

aidl本質(zhì)上也是采用的c/s架構(gòu),首先創(chuàng)建一個server端:

server端

  • 1.右鍵生成aidl文件
interface IMyAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
    String getName();
    void setName(String name);
}

basicTypes這個可以刪掉的护姆。這個方法是介紹了基礎(chǔ)的用法蝗砾,可以用哪些變量先较;后面就可以自定義方法了。

  • 2.創(chuàng)建service
@Override
    public IBinder onBind(Intent intent) {
        return new Like();
    }

    class Like extends IMyAidlInterface.Stub{
        @Override
        public String getName() throws RemoteException {
            return "i'm yours";
        }

        @Override
        public void setName(String name) throws RemoteException {
        }
    }

創(chuàng)建一個內(nèi)部類遥诉,繼承自aidl.stub拇泣。然后重寫方法;
然后在onBind方法中return 這個內(nèi)部類的對象矮锈。

Client端

client端的寫法就很簡單了霉翔。

Intent intent= new Intent(action);
        intent.setPackage(packagename);
        bindService(intent, new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        }, Context.BIND_AUTO_CREATE);

就是一個bindservice的過程;這樣兩個app就能通信啦苞笨。怎么樣债朵,是不是很簡單,接下來講下實(shí)現(xiàn)的原理瀑凝;

原理分析

要知道原理首先肯定得知道在編譯aidl文件時(shí)序芦,發(fā)生了什么。觀察看目錄知道其實(shí)是生成了一個同名的java文件粤咪,下面我們來研究這個java文件里都有啥谚中。

/**
    public static class Default implements com.qikun.demo.IMyAidlInterface {
        @Override
        public void setName(java.lang.String name) throws android.os.RemoteException {
        }

        @Override
        public java.lang.String getName() throws android.os.RemoteException {
            return null;
        }

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

首先生成了一個默認(rèn)的實(shí)現(xiàn)了此接口的類,叫default寥枝;
重點(diǎn)看stub類宪塔,此類實(shí)現(xiàn)了IMyAidlInterface的接口并繼承了binder。

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

將服務(wù)端的ibinder對象轉(zhuǎn)化為客戶端所需要的接口對象囊拜。

如果有必要的話某筐,產(chǎn)生一個代理對象Proxy。否則直接查詢本地的對象冠跷,就解決了同一個進(jìn)程里使用aidl的困境)
來分析一下這個proxy代理對象是怎么回事:
首先南誊,proxy構(gòu)造需要傳入一個ibinder對象身诺;

@Override
            public java.lang.String getName() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.lang.String _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    boolean _status = mRemote.transact(Stub.TRANSACTION_getName, _data, _reply, 0);
                    if (!_status && getDefaultImpl() != null) {
                        return getDefaultImpl().getName();
                    }
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

一個data,一個reply抄囚,都是parcel對象霉赡。注意最核心的代碼:

mRemote.transact(Stub.TRANSACTION_getName, _data, _reply, 0);

mRemote其實(shí)就是proxy初始化的時(shí)候傳入進(jìn)來的binder對象。transact是什么方法呢怠苔?

/**
     * Perform a generic operation with the object.
     * 
     * @param code The action to perform.  This should
     * be a number between {@link #FIRST_CALL_TRANSACTION} and
     * {@link #LAST_CALL_TRANSACTION}.
     * @param data Marshalled data to send to the target.  Must not be null.
     * If you are not sending any data, you must create an empty Parcel
     * that is given here.
     * @param reply Marshalled data to be received from the target.  May be
     * null if you are not interested in the return value.
     * @param flags Additional operation flags.  Either 0 for a normal
     * RPC, or {@link #FLAG_ONEWAY} for a one-way RPC.
     *
     * @return Returns the result from {@link Binder#onTransact}.  A successful call
     * generally returns true; false generally means the transaction code was not
     * understood.
     */
    public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags)
        throws RemoteException;

這里就從官方文檔注釋大概知道意思:

  • 1.code表示要執(zhí)行什么動作同廉;
  • 2.data和reply就是一個傳入值一個返回值;
  • 3.flag只有0和flag_oneway柑司,0表示client需要等待server返回迫肖,而flag_oneway表示這是一個單項(xiàng)的活動,無需等待攒驰。所以參數(shù)為0時(shí)表示可能會有阻塞蟆湖,這里要多注意.

okay,讓我們再回到stub里面來玻粪,關(guān)注一下onTransact方法:

 @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            java.lang.String descriptor = DESCRIPTOR;
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(descriptor);
                    return true;
                }
                case TRANSACTION_setName: {
                    data.enforceInterface(descriptor);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    this.setName(_arg0);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_getName: {
                    data.enforceInterface(descriptor);
                    java.lang.String _result = this.getName();
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
                default: {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

可以看到stub根據(jù)不同的code去執(zhí)行不同的方法隅津;

小結(jié)

通過以上的源碼分析能夠得出一次aidl的IPC(inter-process communication)大致流程:

  • a.客戶端通過bindService綁定服務(wù)端的service
  • b.拿到service之后拿到ibinder對象,再通過接口的Stub.asInterface將ibinder對象轉(zhuǎn)化為接口對象劲室。
  • c.拿到接口對象之后調(diào)用接口的api伦仍,api里通過binder.transact方法調(diào)起遠(yuǎn)程通信,如果flag是0很洋,等待結(jié)果回來充蓝。
  • d.遠(yuǎn)程接收到后,通過寫入?yún)?shù)到reply參數(shù)中去喉磁,然后再調(diào)用binder.transact方法返回谓苟。

這里再稍微提一下binder機(jī)制。因?yàn)檫@個實(shí)在是太重要了對于android系統(tǒng)來說协怒。
首先android系統(tǒng)不同進(jìn)程是不共享空間的涝焙,但是內(nèi)核空間是共享的,因此binder 驅(qū)動層肯定是在內(nèi)核空間的孕暇,相當(dāng)于一個底層中轉(zhuǎn)站的概念仑撞。后續(xù)將花大篇幅介紹binder。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載妖滔,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者派草。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市铛楣,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌艺普,老刑警劉巖簸州,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鉴竭,死亡現(xiàn)場離奇詭異,居然都是意外死亡岸浑,警方通過查閱死者的電腦和手機(jī)搏存,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來矢洲,“玉大人璧眠,你說我怎么就攤上這事《谅玻” “怎么了责静?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長盖桥。 經(jīng)常有香客問我灾螃,道長,這世上最難降的妖魔是什么揩徊? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任腰鬼,我火速辦了婚禮,結(jié)果婚禮上塑荒,老公的妹妹穿的比我還像新娘熄赡。我一直安慰自己,他們只是感情好齿税,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布彼硫。 她就那樣靜靜地躺著,像睡著了一般偎窘。 火紅的嫁衣襯著肌膚如雪乌助。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天陌知,我揣著相機(jī)與錄音他托,去河邊找鬼。 笑死仆葡,一個胖子當(dāng)著我的面吹牛赏参,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播沿盅,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼把篓,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了腰涧?” 一聲冷哼從身側(cè)響起韧掩,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎窖铡,沒想到半個月后疗锐,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體坊谁,經(jīng)...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年滑臊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了口芍。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡雇卷,死狀恐怖鬓椭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情关划,我是刑警寧澤小染,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站祭玉,受9級特大地震影響氧映,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜脱货,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一岛都、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧振峻,春花似錦臼疫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至凤价,卻和暖如春鸽斟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背利诺。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工富蓄, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人慢逾。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓立倍,卻偏偏與公主長得像,于是被迫代替她去往敵國和親侣滩。 傳聞我的和親對象是個殘疾皇子口注,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評論 2 354

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