【Android】IPC臂拓、AIDL厚脉、Binder

IPC:Inter Process Communication,跨進(jìn)程間通信胶惰。

AIDL:Android Interface Definition Language傻工,Android接口定義語(yǔ)言,用于生成可以在Android設(shè)備上兩個(gè)進(jìn)程之間進(jìn)行進(jìn)程間通信的代碼孵滞。

Binder:是Android中一種跨進(jìn)程通信的方式中捆。從Android FrameWork角度來(lái)說(shuō),Binder是ServiceManager連接各種Manager和相應(yīng)ManagerService的橋梁坊饶。從Android應(yīng)用層的角度來(lái)說(shuō)泄伪, BInder是客戶端和服務(wù)端進(jìn)行通信的媒介。

三者的關(guān)系:
AIDL是基于Binder機(jī)制實(shí)現(xiàn)Android上的IPC匿级。

一蟋滴、AIDL實(shí)踐

先從例子出發(fā),從例子理解aidl痘绎。AIDL涉及一個(gè)服務(wù)端和一個(gè)客戶端津函。
1、服務(wù)端
(1)新建一個(gè)工程孤页,AIDLServer尔苦。
(2)右鍵新建一個(gè)AIDL File,刪掉里面的方法,寫(xiě)上自己的方法聲明蕉堰。

// IMyAidlInterface.aidl
package com.cm.aidlserver;

interface IMyAidlInterface {
    void callF1();
    int callF2();
}

(3)選擇Build -> Rebuild Project,會(huì)自動(dòng)根據(jù)接口生成Java文件悲龟。位置在app/build/generated/source/aidl下面屋讶。可以先大概看一下生成的內(nèi)容须教,本質(zhì)還是一個(gè)繼承了接口的接口皿渗。里面的內(nèi)容等下解釋。
(4)上面生成的只是個(gè)接口轻腺,是必須要實(shí)現(xiàn)的乐疆。
新建一個(gè)服務(wù)service。

package com.cm.aidlserver;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

public class MyService extends Service {
    public MyService() {
    }

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

    private IBinder myBinder = new IMyAidlInterface.Stub() {
        @Override
        public void callF1() throws RemoteException {
            Log.i("chenming server", "callerF1");
        }

        @Override
        public int callF2() throws RemoteException {
            Log.i("chenming server", "callerF2");
            return 0;
        }
    };
}

在onBind方法中返回對(duì)應(yīng)的binder對(duì)象贬养,binder對(duì)象為IMyAidlInterface.Stub的實(shí)例對(duì)象挤土,實(shí)現(xiàn)了其中的抽象方法,即我們定義的aidl中聲明的方法误算。

為了可以在客戶端調(diào)用仰美,需要在xml中將外界調(diào)用設(shè)置為true。

<service
    android:name=".MyService"
    android:enabled="true"
    android:exported="true">
</service>

2儿礼、客戶端
(1)新建一個(gè)工程咖杂,AIDLClient。
(2)將服務(wù)器的AIDL文件復(fù)制到該工程中蚊夫,選擇Build -> Rebuild Project诉字,會(huì)自動(dòng)根據(jù)接口生成和服務(wù)端一樣的Java接口文件。
(3)為了可以調(diào)用服務(wù)端的方法知纷,需要通過(guò)binder進(jìn)行調(diào)用壤圃,因此在客戶端中要定義該binder。

IMyAidlInterface iMyAidlInterface;

(4)然后綁定服務(wù)端的提供的服務(wù)屈扎。

Intent intent = new Intent();
intent.setComponent(new ComponentName("com.cm.aidlserver", "com.cm.aidlserver.MyService"));
bindService(intent, conn, BIND_AUTO_CREATE);

(5)綁定成功之后會(huì)回調(diào)對(duì)應(yīng)的方法埃唯,在方法中初始化binder。

private ServiceConnection conn = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
        iMyAidlInterface = IMyAidlInterface.Stub.asInterface(iBinder);
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        iMyAidlInterface = null;
    }
};

通過(guò)IMyAidlInterface.Stub.asInterface(iBinder)初始化binder鹰晨。
(6)調(diào)用對(duì)應(yīng)的方法墨叛,以調(diào)用callF1方法為例,調(diào)用如下模蜡。

private void callF1() {
    try {
        iMyAidlInterface.callF1();
    } catch (RemoteException e) {
        e.printStackTrace();
    }
}

從log可以看出漠趁,可以通過(guò)客戶端調(diào)用服務(wù)端的方法。

注意:原生系統(tǒng)中忍疾,可以通過(guò)這個(gè)方法進(jìn)行贝炒活,即當(dāng)Client端啟動(dòng)的時(shí)候卤妒,會(huì)通過(guò)binder service拉起Server端甥绿,但是由于國(guó)產(chǎn)手機(jī)的系統(tǒng)都經(jīng)過(guò)了優(yōu)化字币,會(huì)攔截關(guān)聯(lián)啟動(dòng),解決方法有兩個(gè)共缕,一個(gè)是先啟動(dòng)server再用client去調(diào)用洗出,另一個(gè)是打開(kāi)手機(jī)里面的關(guān)聯(lián)啟動(dòng)允許即可(以華為手機(jī)為例,打開(kāi)手機(jī)管家->啟動(dòng)管理图谷,找到AIDLServer改成手動(dòng)管理翩活,允許關(guān)聯(lián)啟動(dòng))。

二便贵、AIDL原理分析

客戶端怎么跨進(jìn)程調(diào)用server端的方法的呢菠镇?

這個(gè)需要從AIDL自動(dòng)生成的Java類(lèi)分析。

查看生成的Java類(lèi)IMyAidlInterface.java承璃,接下來(lái)一行行解讀利耍。

首先,該類(lèi)是一個(gè)繼承自接口的接口盔粹,從上面實(shí)現(xiàn)可以知道具體的是實(shí)現(xiàn)是在service中堂竟。

然后,定義了一個(gè)抽象類(lèi)Stub玻佩,這個(gè)類(lèi)本質(zhì)就是一個(gè)binder出嘹,這個(gè)類(lèi)里面有以下的成員與方法:
(1)DESCRIPTOR成員,是Binder的唯一標(biāo)識(shí)
(2)asInterface方法
傳入?yún)?shù)為一個(gè)Binder咬崔,返回一個(gè)IMyAidlInterface税稼,是用于將服務(wù)端的Binder對(duì)象轉(zhuǎn)換成客戶端所需的AIDL接口類(lèi)型的對(duì)象。
里面先調(diào)用queryLocalInterface方法垮斯,這個(gè)方法可以從源碼里面看見(jiàn)當(dāng)客戶端和服務(wù)端為同一個(gè)進(jìn)程的時(shí)候郎仆,返回服務(wù)端的AIDL接口類(lèi)型的對(duì)象,不同進(jìn)程的時(shí)候返回null兜蠕。所以根據(jù)iin進(jìn)行判斷扰肌,如果返回不為null,說(shuō)明在同一個(gè)進(jìn)程內(nèi)調(diào)用熊杨,直接返回AIDL接口類(lèi)型的對(duì)象曙旭,為null的時(shí)候說(shuō)明不在同一個(gè)進(jìn)程內(nèi)調(diào)用,返回封裝后的對(duì)象Stub.Proxy晶府。
(3)asBinder方法桂躏,返回當(dāng)前的binder對(duì)象。
(4)onTransact方法川陆。當(dāng)客戶端發(fā)起跨進(jìn)程請(qǐng)求的時(shí)候剂习,遠(yuǎn)程請(qǐng)求會(huì)通過(guò)系統(tǒng)底層封裝后交到該方法處理。原型如下:

public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)

code為請(qǐng)求參數(shù),根據(jù)這個(gè)參數(shù)來(lái)確定調(diào)用哪個(gè)方法鳞绕,data用以傳遞方法參數(shù)失仁,reply用以傳遞結(jié)果即返回值。該方法的返回值標(biāo)記是否調(diào)用成功们何。
(5)對(duì)于每個(gè)方法定義一個(gè)code陶因。

static final int TRANSACTION_callF1 = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_callF2 = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);

(6)從上面知道,如果是同一個(gè)進(jìn)程調(diào)用的是Stub的方法垂蜗,如果不同進(jìn)程,調(diào)用的是Stub.Proxy里面的方法解幽,以其中一個(gè)方法Stub.Proxy的callF1方法為例贴见,分析如下。
首先創(chuàng)建輸入?yún)?shù)_data和輸出參數(shù)_reply躲株,然后將該方法的參數(shù)寫(xiě)入_data片部,然后調(diào)用transact方法發(fā)送RPC(遠(yuǎn)程過(guò)程調(diào)用),同時(shí)線程掛起霜定,然后服務(wù)端的onTransact會(huì)被調(diào)用档悠,等到結(jié)果返回之后繼續(xù)執(zhí)行,將結(jié)果寫(xiě)入_reply中望浩。

可以看見(jiàn)辖所,AIDL是基于Binder機(jī)制實(shí)現(xiàn)的,通過(guò)AIDL自動(dòng)生成的接口里面的Binder的子類(lèi)實(shí)現(xiàn)遠(yuǎn)程接口調(diào)用磨德,整個(gè)流程如下圖所示缘回。

注意:由于客戶端在通過(guò)binder調(diào)用服務(wù)端的時(shí)候,會(huì)把線程掛起典挑,因此酥宴,一般需要另開(kāi)線程執(zhí)行,如果在主線程執(zhí)行您觉,如果這個(gè)方法是耗時(shí)方法拙寡,會(huì)導(dǎo)致ANR情況。

調(diào)用流程圖.png

三琳水、深入理解Binder

上面從主要從應(yīng)用層的角度分析AIDL肆糕,可以看出AIDL底層是基于Binder實(shí)現(xiàn)的,那么Binder底層原理是怎么樣的呢在孝?

首先擎宝,先理解進(jìn)程內(nèi)存空間的關(guān)系,如下圖所示浑玛。

進(jìn)程間地址空間關(guān)系.png

可以看見(jiàn)雖然不同進(jìn)程的用戶空間是非共享的绍申,但是內(nèi)核空間是共享的,Client進(jìn)程向Server進(jìn)程通信,恰恰是利用進(jìn)程間可共享的內(nèi)核內(nèi)存空間來(lái)完成底層通信工作的极阅。

Binder通信采用C/S架構(gòu)胃碾,基本架構(gòu)圖如下圖所示。

Binder架構(gòu)圖.jpg

Service Manager用于管理系統(tǒng)中的各種服務(wù)筋搏。圖中Client/Server/ServiceManage之間的相互通信都是基于Binder機(jī)制仆百,所以三個(gè)步驟都是C/S架構(gòu)。

首先奔脐,注冊(cè)服務(wù)俄周,這個(gè)過(guò)程Server是客戶端,ServiceManager是服務(wù)端髓迎。

然后峦朗,Client端進(jìn)行服務(wù)獲取,這個(gè)過(guò)程Client是客戶端排龄,ServiceManager是服務(wù)端波势。

最后,使用服務(wù)橄维,Client根據(jù)得到的Service信息建立與Service所在的Server進(jìn)程通信的通路尺铣,然后就可以直接與Service交互。該過(guò)程:client是客戶端争舞,server是服務(wù)端凛忿。

四、例子回顧

首先竞川,啟動(dòng)AIDLServer應(yīng)用后侄非,MyService啟動(dòng),向Service Manager注冊(cè)流译。然后啟動(dòng)AIDLClient通過(guò)綁定服務(wù)獲取對(duì)應(yīng)的服務(wù)逞怨,服務(wù)連接成功之后,調(diào)用IMyAidlInterface.Stub.asInterface獲取客戶端所需的AIDL接口類(lèi)型的對(duì)象福澡,由于是不同的進(jìn)程叠赦,因此會(huì)獲取到對(duì)應(yīng)的代理類(lèi)。調(diào)用方法callF1方法的時(shí)候革砸,會(huì)去調(diào)用對(duì)應(yīng)service里面真正實(shí)現(xiàn)的callF1()除秀。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市算利,隨后出現(xiàn)的幾起案子册踩,更是在濱河造成了極大的恐慌,老刑警劉巖效拭,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件暂吉,死亡現(xiàn)場(chǎng)離奇詭異胖秒,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)慕的,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)阎肝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人肮街,你說(shuō)我怎么就攤上這事风题。” “怎么了嫉父?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵沛硅,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我绕辖,道長(zhǎng)摇肌,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任引镊,我火速辦了婚禮,結(jié)果婚禮上篮条,老公的妹妹穿的比我還像新娘弟头。我一直安慰自己,他們只是感情好涉茧,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布赴恨。 她就那樣靜靜地躺著,像睡著了一般伴栓。 火紅的嫁衣襯著肌膚如雪伦连。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,696評(píng)論 1 312
  • 那天钳垮,我揣著相機(jī)與錄音惑淳,去河邊找鬼。 笑死饺窿,一個(gè)胖子當(dāng)著我的面吹牛歧焦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播肚医,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼绢馍,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了肠套?” 一聲冷哼從身側(cè)響起舰涌,我...
    開(kāi)封第一講書(shū)人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎你稚,沒(méi)想到半個(gè)月后瓷耙,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體朱躺,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年哺徊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了室琢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡落追,死狀恐怖盈滴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情轿钠,我是刑警寧澤巢钓,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站疗垛,受9級(jí)特大地震影響症汹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜贷腕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一背镇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧泽裳,春花似錦瞒斩、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至瀑梗,卻和暖如春烹笔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背抛丽。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工谤职, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人亿鲜。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓柬帕,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親狡门。 傳聞我的和親對(duì)象是個(gè)殘疾皇子陷寝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

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

  • 本文介紹Service與Activity之間的通信叛复,文章包含以下內(nèi)容: 一仔引、Service基本用法 二扔仓、通過(guò)AID...
    developerzjy閱讀 10,498評(píng)論 7 27
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)咖耘,斷路器翘簇,智...
    卡卡羅2017閱讀 134,716評(píng)論 18 139
  • Jianwei's blog 首頁(yè) 分類(lèi) 關(guān)于 歸檔 標(biāo)簽 巧用Android多進(jìn)程,微信儿倒,微博等主流App都在用...
    justCode_閱讀 5,925評(píng)論 1 23
  • 有些人不必刻意聯(lián)系版保, 只需一份惦記。 我一聲夫否,想你彻犁。 你一聲,走起凰慈。 各自忙各自的汞幢, 掐好時(shí)間,就等你微谓。 只愿老來(lái)...
    陳mini閱讀 249評(píng)論 0 0
  • 人生中最難的可能就是堅(jiān)持了森篷。 我的腿已經(jīng)不是我的腿了,我上樓都是四肢著地前行豺型。能不抬腿盡量不抬仲智,走路全靠拖。 話說(shuō)...
    懸崖邊上的金魚(yú)公主閱讀 244評(píng)論 1 0