android進(jìn)程間通訊(2)–理解Binder及AIDL使用
前言:之前一篇文章記錄了Bundle和文件共享的方式來進(jìn)行進(jìn)程間通訊,但并不是所有場景都適用的元咙,比如A進(jìn)程正在進(jìn)行一個(gè)計(jì)算,計(jì)算完成后要啟動B進(jìn)程并把計(jì)算結(jié)果傳遞給B進(jìn)程浸须,但是計(jì)算結(jié)果不支持放入Bundle响蓉,又或者A進(jìn)程有個(gè)封裝好的方法,B進(jìn)程想要調(diào)用A進(jìn)程里面的方法,使用Bundle則行不通了替梨。因此android提供了一種進(jìn)程間通訊方式Binder。Binder是Android系統(tǒng)最主要的IPC方式装黑,其中Messenger副瀑,AIDL,ContentProvider底層實(shí)現(xiàn)都是Binder恋谭。由于Binder的實(shí)現(xiàn)比較復(fù)雜糠睡,這里只記錄基本原理。
1.Binder機(jī)制
了解binder首先要解決幾個(gè)疑問:1.什么是Binder疚颊? 2.Binder的實(shí)現(xiàn)原理狈孔?3.Binder的具體應(yīng)用有哪些?
(1).什么是binder
直觀來說材义,Binder是android中的一個(gè)類均抽,它實(shí)現(xiàn)了IBinder接口。從IPC角度說其掂,Binder是android中的一種跨進(jìn)程通訊方式油挥。Binder可以理解為一種虛擬的物理設(shè)備,它的設(shè)備驅(qū)動是/dev/binder款熬,該通訊的方式在Linux中沒有深寥。從Android Framework角度來說,Binder是ServiceManager連接各種Manager比如ActivityManager贤牛,WindowManager翩迈,InputManager,ResourceManager等等和相應(yīng)的ManagerService的橋梁盔夜。從安卓應(yīng)用層來說,Binder是客戶端和服務(wù)端進(jìn)行通訊的媒介。
(2).Binder實(shí)現(xiàn)原理
個(gè)人覺得想要理解Binder的實(shí)現(xiàn)原理喂链,首先要理解以下兩個(gè)方面的東西返十。1.Android的體系架構(gòu);2.計(jì)算機(jī)的內(nèi)存管理椭微。
<1>.Android體系架構(gòu)
首先來看一下android架構(gòu)圖洞坑,圖片來自網(wǎng)絡(luò)。
1.內(nèi)核層:Linux 內(nèi)核和各類硬件設(shè)備的驅(qū)動蝇率,binder驅(qū)動/dev/binder位于這一層
2.類庫層:由于類庫層多是c/c++編寫的native代碼迟杂,所以又叫C庫層
3.應(yīng)用程序框架層:這一層可以理解為 Android SDK,提供四大組件本慕,View 繪制體系等平時(shí)開發(fā)中用到的基礎(chǔ)部件排拷,因?yàn)樵搶又饕莏ava編寫,所以又叫java庫層
4.應(yīng)用層:開發(fā)人員開發(fā)的應(yīng)用程序?qū)?br>
其實(shí)在內(nèi)核層和類庫層還有一層是HAL锅尘,硬件抽象層:封裝「內(nèi)核層」硬件驅(qū)動监氢,提供可供「系統(tǒng)服務(wù)層」調(diào)用的統(tǒng)一硬件接口
<2>計(jì)算機(jī)內(nèi)存管理
1.早期的機(jī)器并沒有任何的虛擬地址的概念,被稱為“實(shí)模式”內(nèi)存管理藤违。而后期發(fā)展出來的設(shè)備提供了虛擬地址的硬件實(shí)現(xiàn)浪腐。最早的操作系統(tǒng)中,并沒有嚴(yán)格意義的內(nèi)存保護(hù)機(jī)制顿乒,對于內(nèi)存的訪問約束完全在于程序編寫者的自覺性议街,這種做法并不靠譜。為了管理內(nèi)存和保護(hù)內(nèi)存璧榄,提出了虛擬內(nèi)存和進(jìn)程概念特漩。虛擬內(nèi)存是一個(gè)抽象的概念,它為每個(gè)進(jìn)程提供了一個(gè)假象犹菱,即每個(gè)進(jìn)程都在獨(dú)占的使用主存拾稳,每個(gè)進(jìn)程看到的內(nèi)存都是一致的,稱為虛擬地址空間腊脱。如下圖所示访得,在Linux中,地址空間的最上面區(qū)域是保留給操作系統(tǒng)的代碼和數(shù)據(jù)的陕凹,這對所有進(jìn)程來說都一樣悍抑,地址空間的底部區(qū)域存放用戶進(jìn)程定義的代碼和數(shù)據(jù)。
也正是因?yàn)檫@樣杜耙,每個(gè)進(jìn)程都有自己獨(dú)立的內(nèi)存空間搜骡,沒有辦法直接訪問它管轄以外的內(nèi)存空間,所以進(jìn)程間通訊要通過系統(tǒng)提供的IPC方式進(jìn)行通訊佑女。而Binder則是android上主要的IPC方式记靡。
從內(nèi)存訪問的角度來看谈竿,Binder的作用就是讓兩個(gè)進(jìn)程可以訪問同一塊內(nèi)存空間,實(shí)現(xiàn)數(shù)據(jù)交換摸吠,如圖:圖片來自http://gityuan.com/2015/10/31/binder-prepare/
每個(gè)Android的進(jìn)程空凸,只能運(yùn)行在自己進(jìn)程所擁有的虛擬地址空間。對應(yīng)一個(gè)4GB的虛擬地址空間寸痢,其中3GB是用戶空間呀洲,1GB是內(nèi)核空間,當(dāng)然內(nèi)核空間的大小是可以通過參數(shù)配置調(diào)整的啼止。對于用戶空間道逗,不同進(jìn)程之間彼此是不能共享的,而內(nèi)核空間卻是可共享的献烦。Client進(jìn)程向Server進(jìn)程通信滓窍,恰恰是利用進(jìn)程間可共享的內(nèi)核內(nèi)存空間來完成底層通信工作的,Client端與Server端進(jìn)程往往采用ioctl等方法跟內(nèi)核空間的驅(qū)動進(jìn)行交互
<3>Binder實(shí)現(xiàn)機(jī)制
Android系統(tǒng)Binder機(jī)制中的四個(gè)組件Client仿荆、Server贰您、Service Manager和Binder驅(qū)動程序的關(guān)系如下圖所示:
1. Client、Server和Service Manager實(shí)現(xiàn)在用戶空間中拢操,Binder驅(qū)動程序?qū)崿F(xiàn)在內(nèi)核空間中
2. Binder驅(qū)動程序和Service Manager在Android平臺中已經(jīng)實(shí)現(xiàn)锦亦,開發(fā)者只需要在用戶空間實(shí)現(xiàn)自己的Client和Server
3. Binder驅(qū)動程序提供設(shè)備文件/dev/binder與用戶空間交互,Client令境、Server和Service Manager通過open和ioctl文件操作函數(shù)與Binder驅(qū)動程序進(jìn)行通信
4. Client和Server之間的進(jìn)程間通信通過Binder驅(qū)動程序間接實(shí)現(xiàn)
5. Service Manager是一個(gè)守護(hù)進(jìn)程杠园,用來管理Server,并向Client提供查詢Server接口的能力
2.Binder具體應(yīng)用
從Binder的實(shí)現(xiàn)機(jī)制可以知道舔庶,使用Binder需要?jiǎng)?chuàng)建Client(客戶端)和Server(服務(wù)端)抛蚁。應(yīng)用層使用Binder進(jìn)行進(jìn)程間通訊具體實(shí)現(xiàn)有Messenger,AIDL惕橙,ContentProvider瞧甩,由于Messenger底層是AIDL,Contentprovider涉及到數(shù)據(jù)庫弥鹦。這里只記錄AIDL的使用方式肚逸。
服務(wù)端創(chuàng)建:
步驟1.首先新建一個(gè)工程,并在app的module的mian文件下創(chuàng)建文件夾aidl彬坏,如圖:
步驟2:創(chuàng)建.aidl文件朦促,如圖中的hdcPearAIDL.aidl文件,并添加兩個(gè)方法栓始,hdcPearAIDL.aidl內(nèi)容如下:
package pear.cn.hdcsdktest;
interface hdcPearAIDL {
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
int add(int a,int b);
void shellCommand(String cmd);
}
build項(xiàng)目之后會在build>generated->source->aidl->debug->下面生成hdcPearAIDL的java文件务冕,這文件是系統(tǒng)自動生成的,如下圖:
步驟3.創(chuàng)建服務(wù)并注冊幻赚,如下圖:
服務(wù)內(nèi)容如下,AidlService繼承Service禀忆,重寫onBind()方法臊旭,并返回IBinder的實(shí)例。并在iBinder里面實(shí)現(xiàn)接口定義的方法油湖,提供給其他進(jìn)程調(diào)用巍扛。
/**
* Created by hdc on 2016/11/28.
*
*/
public class AidlService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return iBinder;
}
private IBinder iBinder = new hdcPearAIDL.Stub() {
@Override
public void basicTypes(int anInt, long aLong, boolean aBoolean,
float aFloat, double aDouble, String aString) throws RemoteException {
}
@Override
public int add(int a, int b) throws RemoteException {
LogUtil.i("hdcTest"," use the method "+a+"/"+b);
return a+b;
}
@Override
public void shellCommand(String cmd) throws RemoteException {
LogUtil.i("hdcTest"," use the method shellCommand "+cmd);
ShellUtil.execCommand(cmd,ShellUtil.checkSuRoot());
}
};
}
別忘記在AndroidManifest中注冊AidlService。
<service android:name=".services.AidlService">
<intent-filter>
<action android:name="pear.cn.hdcsdktest.services.AidlService"/>
</intent-filter>
</service>
客戶端創(chuàng)建:
步驟1:同樣在app的module的mian文件夾下面創(chuàng)建aidl文件夾和相同包名乏德,相同名字的aidl文件,可以將服務(wù)端的aidl文件直接copy過來吠昭,如下圖:
步驟2:綁定服務(wù)喊括,在客戶端的activity的onCreate方法里面綁定服務(wù),在onServiceConnected()方法返回hdcPearAIDL對象,可以使用aidl對象來調(diào)用服務(wù)端的方法矢棚。
public class MainActivity extends AppCompatActivity {
private hdcPearAIDL aidl;
private ServiceConnection serviceConnection =new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
aidl= hdcPearAIDL.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
aidl=null;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindService();
}
private void bindService() {
Intent intent = new Intent();
//綁定服務(wù)端的service
intent.setAction("pear.cn.hdcsdktest.services.AidlService");
//新版本(5.0后)必須顯式intent啟動 綁定服務(wù)
intent.setComponent(new ComponentName("pear.cn.hdcsdktest","pear.cn.hdcsdktest.services.AidlService"));
//綁定的時(shí)候服務(wù)端自動創(chuàng)建
bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
}
總結(jié)
1.Binder是android中最主要的IPC方式
2.Binder實(shí)現(xiàn)原理涉及到android框架體系以及操作系統(tǒng)的內(nèi)存管理機(jī)制
3.Messager郑什,AIDL,ContentProvider的底層原理是Binder