android進程間通訊(2)–理解Binder及AIDL使用
前言:之前一篇文章記錄了Bundle和文件共享的方式來進行進程間通訊,但并不是所有場景都適用的,比如A進程正在進行一個計算,計算完成后要啟動B進程并把計算結果傳遞給B進程,但是計算結果不支持放入Bundle,又或者A進程有個封裝好的方法,B進程想要調用A進程里面的方法,使用Bundle則行不通了。因此android提供了一種進程間通訊方式Binder。Binder是Android系統(tǒng)最主要的IPC方式,其中Messenger,AIDL,ContentProvider底層實現(xiàn)都是Binder。由于Binder的實現(xiàn)比較復雜,這里只記錄基本原理。
1.Binder機制
了解binder首先要解決幾個疑問:1.什么是Binder? 2.Binder的實現(xiàn)原理?3.Binder的具體應用有哪些?
(1).什么是binder
直觀來說,Binder是android中的一個類,它實現(xiàn)了IBinder接口。從IPC角度說,Binder是android中的一種跨進程通訊方式。Binder可以理解為一種虛擬的物理設備,它的設備驅動是/dev/binder,該通訊的方式在Linux中沒有。從Android Framework角度來說,Binder是ServiceManager連接各種Manager比如ActivityManager,WindowManager,InputManager,ResourceManager等等和相應的ManagerService的橋梁。從安卓應用層來說,Binder是客戶端和服務端進行通訊的媒介。
(2).Binder實現(xiàn)原理
個人覺得想要理解Binder的實現(xiàn)原理,首先要理解以下兩個方面的東西。1.Android的體系架構;2.計算機的內存管理。
<1>.Android體系架構
首先來看一下android架構圖,圖片來自網(wǎng)絡。

1.內核層:Linux 內核和各類硬件設備的驅動,binder驅動/dev/binder位于這一層
2.類庫層:由于類庫層多是c/c++編寫的native代碼,所以又叫C庫層
3.應用程序框架層:這一層可以理解為 Android SDK,提供四大組件,View 繪制體系等平時開發(fā)中用到的基礎部件,因為該層主要是java編寫,所以又叫java庫層
4.應用層:開發(fā)人員開發(fā)的應用程序層
其實在內核層和類庫層還有一層是HAL,硬件抽象層:封裝「內核層」硬件驅動,提供可供「系統(tǒng)服務層」調用的統(tǒng)一硬件接口
<2>計算機內存管理
1.早期的機器并沒有任何的虛擬地址的概念,被稱為“實模式”內存管理。而后期發(fā)展出來的設備提供了虛擬地址的硬件實現(xiàn)。最早的操作系統(tǒng)中,并沒有嚴格意義的內存保護機制,對于內存的訪問約束完全在于程序編寫者的自覺性,這種做法并不靠譜。為了管理內存和保護內存,提出了虛擬內存和進程概念。虛擬內存是一個抽象的概念,它為每個進程提供了一個假象,即每個進程都在獨占的使用主存,每個進程看到的內存都是一致的,稱為虛擬地址空間。如下圖所示,在Linux中,地址空間的最上面區(qū)域是保留給操作系統(tǒng)的代碼和數(shù)據(jù)的,這對所有進程來說都一樣,地址空間的底部區(qū)域存放用戶進程定義的代碼和數(shù)據(jù)。

也正是因為這樣,每個進程都有自己獨立的內存空間,沒有辦法直接訪問它管轄以外的內存空間,所以進程間通訊要通過系統(tǒng)提供的IPC方式進行通訊。而Binder則是android上主要的IPC方式。
從內存訪問的角度來看,Binder的作用就是讓兩個進程可以訪問同一塊內存空間,實現(xiàn)數(shù)據(jù)交換,如圖:圖片來自http://gityuan.com/2015/10/31/binder-prepare/

每個Android的進程,只能運行在自己進程所擁有的虛擬地址空間。對應一個4GB的虛擬地址空間,其中3GB是用戶空間,1GB是內核空間,當然內核空間的大小是可以通過參數(shù)配置調整的。對于用戶空間,不同進程之間彼此是不能共享的,而內核空間卻是可共享的。Client進程向Server進程通信,恰恰是利用進程間可共享的內核內存空間來完成底層通信工作的,Client端與Server端進程往往采用ioctl等方法跟內核空間的驅動進行交互
<3>Binder實現(xiàn)機制
Android系統(tǒng)Binder機制中的四個組件Client、Server、Service Manager和Binder驅動程序的關系如下圖所示:

1. Client、Server和Service Manager實現(xiàn)在用戶空間中,Binder驅動程序實現(xiàn)在內核空間中
2. Binder驅動程序和Service Manager在Android平臺中已經(jīng)實現(xiàn),開發(fā)者只需要在用戶空間實現(xiàn)自己的Client和Server
3. Binder驅動程序提供設備文件/dev/binder與用戶空間交互,Client、Server和Service Manager通過open和ioctl文件操作函數(shù)與Binder驅動程序進行通信
4. Client和Server之間的進程間通信通過Binder驅動程序間接實現(xiàn)
5. Service Manager是一個守護進程,用來管理Server,并向Client提供查詢Server接口的能力
2.Binder具體應用
從Binder的實現(xiàn)機制可以知道,使用Binder需要創(chuàng)建Client(客戶端)和Server(服務端)。應用層使用Binder進行進程間通訊具體實現(xiàn)有Messenger,AIDL,ContentProvider,由于Messenger底層是AIDL,Contentprovider涉及到數(shù)據(jù)庫。這里只記錄AIDL的使用方式。
服務端創(chuàng)建:
步驟1.首先新建一個工程,并在app的module的mian文件下創(chuàng)建文件夾aidl,如圖:

步驟2:創(chuàng)建.aidl文件,如圖中的hdcPearAIDL.aidl文件,并添加兩個方法,hdcPearAIDL.aidl內容如下:
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項目之后會在build>generated->source->aidl->debug->下面生成hdcPearAIDL的java文件,這文件是系統(tǒng)自動生成的,如下圖:

步驟3.創(chuàng)建服務并注冊,如下圖:

服務內容如下,AidlService繼承Service,重寫onBind()方法,并返回IBinder的實例。并在iBinder里面實現(xiàn)接口定義的方法,提供給其他進程調用。
/**
* 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文件,可以將服務端的aidl文件直接copy過來,如下圖:

步驟2:綁定服務,在客戶端的activity的onCreate方法里面綁定服務,在onServiceConnected()方法返回hdcPearAIDL對象,可以使用aidl對象來調用服務端的方法。
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();
//綁定服務端的service
intent.setAction("pear.cn.hdcsdktest.services.AidlService");
//新版本(5.0后)必須顯式intent啟動 綁定服務
intent.setComponent(new ComponentName("pear.cn.hdcsdktest","pear.cn.hdcsdktest.services.AidlService"));
//綁定的時候服務端自動創(chuàng)建
bindService(intent,serviceConnection, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(serviceConnection);
}
}
總結
1.Binder是android中最主要的IPC方式
2.Binder實現(xiàn)原理涉及到android框架體系以及操作系統(tǒng)的內存管理機制
3.Messager,AIDL,ContentProvider的底層原理是Binder