歡迎訪問我的個人博客,原文鏈接:http://wensibo.top/2017/07/03/Binder/ ,未經(jīng)允許不得轉(zhuǎn)載!

前言
大家好,好久不見,距離上篇文章已經(jīng)有35天之久了,因為身體不舒服害了一場病,不過現(xiàn)在已經(jīng)好多了;另外這個月是考試月,當(dāng)然得花多點(diǎn)時間復(fù)習(xí)功課了;再者這段時間依舊在看書,同時也在研究Android源碼,準(zhǔn)備了不少干貨想與大家一起分享。7月剛到,該放假的也都差不多放假了,該實習(xí)的也已經(jīng)在實習(xí)了,而我。。。還是準(zhǔn)備秋招吧!多看書多打碼多提升自己的眼界。
今天想要和大家一起分享的是Android中的Binder機(jī)制,講真這絕對是Android中很深奧的一個點(diǎn),如果能夠徹底弄懂它,這對初級程序員來說絕對會是一件具有里程碑意義的事件,當(dāng)然我也研究了許久,終于琢磨出點(diǎn)所以然,所以就拿出來和大家一起分享分享。另外這篇文章將會通過一個小實例來講解Binder,大家可以點(diǎn)擊這里,也歡迎大家fork和star。話不多說讓我們開始吧!
IPC
為了弄懂IPC的來龍去脈,我將從以下三個方面為大家來講解,希望對大家理解IPC會有幫助
什么是IPC
IPC是Inter Process Communication的縮寫,其意思就是進(jìn)程間的通信,也就是兩個進(jìn)程之間的通信過程。我們都知道在Android系統(tǒng)中,每個應(yīng)用都運(yùn)行在一個進(jìn)程上,具有自己的DVM實例,而且進(jìn)程之間是相互隔離的,也就是說各個進(jìn)程之間的數(shù)據(jù)是互相獨(dú)立,互不影響的,而如果一個進(jìn)程崩潰了,也不會影響到另一個進(jìn)程。
采取這樣的設(shè)計是有一定道理的,例如這樣的前提下將互相不影響的系統(tǒng)功能分拆到不同的進(jìn)程里面去,有助于提升系統(tǒng)的穩(wěn)定性,畢竟我們都不想自己的應(yīng)用進(jìn)程崩潰會導(dǎo)致整個手機(jī)系統(tǒng)的崩潰。
進(jìn)程之間隔離是不錯的選擇,可是如果進(jìn)程之間想要互相通信,進(jìn)行數(shù)據(jù)交互的時候那該怎么辦呢?例如我們在自己的應(yīng)用中想要訪問手機(jī)通訊錄中的聯(lián)系人,很顯然這是兩個不同的進(jìn)程,如果Android沒有提供一種進(jìn)程之間交流的機(jī)制,那么這種功能將無法實現(xiàn)。
不過由于Android系統(tǒng)使用的是Linux內(nèi)核,而在Linux系統(tǒng)中進(jìn)程之間的交互是有一套機(jī)制的,所以Android也借鑒了其中的一些機(jī)制,從而形成了Android的IPC機(jī)制。
上面只是粗略的講解了IPC是啥,關(guān)于它的使用和原理我將一一為大家呈上。
為什么要用IPC
上一點(diǎn)中我舉了訪問手機(jī)通訊錄的例子。但你可能覺得我不需要用到這種功能,那么我就不用管IPC啦!其實不然,IPC在我們的應(yīng)用開發(fā)過程中隨處可見,下面我將舉一個例子來說明他的重要性。
我們在MainActivity中修改一個靜態(tài)變量,接著在另一個進(jìn)程的SecondActivity中去訪問該變量,看看能否讀取已經(jīng)修改過的變量。
1、新建一個Student類,并聲明一個靜態(tài)變量
public class Student {
public static String name="BOB";
}
2、在MainActivity的onCreate方法中修改name的值,并打印log
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Student.name = "JACK";
Log.d("MainActivity:Sname=", Student.name);
}
3、將SecondActivity設(shè)置為新進(jìn)程,并在其onCreate方法中訪問name
<!-- 在清單文件中通過android:process屬性為SecondActivity指定特定的進(jìn)程:com.bob.aidltest:second -->
<activity
android:name=".SecondActivity"
android:process=":second">
</activity>
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second_activity);
Log.d("SecondActivity:Sname=" , Student.name);
}
}
4、通過log,可以看到在MainActivity中修改了name的值,但是在SecondActivity中卻無法讀取修改后的值

通過以上的實驗,大家應(yīng)該明白了一點(diǎn):在不同的進(jìn)程之間訪問同一個靜態(tài)變量是行不通的。其原因是:每一個進(jìn)程都分配有一個獨(dú)立的虛擬機(jī),不同的虛擬機(jī)在內(nèi)存分配上有不同的地址空間,這就導(dǎo)致在不同的虛擬機(jī)上訪問同一個對象會產(chǎn)生多個副本。例如我們在MainActivity中訪問的name的值只會影響當(dāng)前進(jìn)程,而對其他進(jìn)程不會造成影響,所以在SecondActivity中訪問name時依舊只能訪問自己進(jìn)程中的副本。
Android中解決IPC的方法
上面也講到,為了解決這些跨進(jìn)程的問題,Android沿用了一些Linux的進(jìn)程管理機(jī)制,使得進(jìn)程之間能夠進(jìn)行交互,下面我將列出一些常見的IPC方式,需要指出的是本文主要講解Binder機(jī)制,所以會注重講解AIDL,其他方式請讀者自行查閱相關(guān)資料。
| 名稱 | 特點(diǎn) | 使用場景 |
|---|---|---|
| Bundle | 只能傳輸實現(xiàn)了Serializable或者Parcelable接口或者一些Android支持的特殊對象 | 適合用于四大組件之間的進(jìn)程交互 |
| 文件 | 不能做到進(jìn)程間的即時通信,并且不適合用于高并發(fā)的場景 | 適合用于SharedPreference以及IO操作 |
| ContentProvider | 可以訪問較多的數(shù)據(jù),支持一對多的高并發(fā)訪問,因為ContentProvider已經(jīng)自動做好了關(guān)于并發(fā)的機(jī)制 | 適合用于一對多的數(shù)據(jù)共享并且需要對數(shù)據(jù)進(jìn)行頻繁的CRUD操作 |
| Socket | 通過網(wǎng)絡(luò)傳輸字節(jié)流,支持一對多的實時通信,但是實現(xiàn)起來比較復(fù)雜 | 適合用于網(wǎng)絡(luò)數(shù)據(jù)共享 |
| Messenger | 底層原理是AIDL,只是對其做了封裝,但是不能很好的處理高并發(fā)的場景,并且傳輸?shù)臄?shù)據(jù)只能支持Bundle類型 | 低并發(fā)的一對多的即時通信 |
| AIDL | 功能強(qiáng)大,使用Binder機(jī)制(接下來會講解),支持一對多的高并發(fā)實時通信,但是需要處理好線程同步 | 一對多并且有遠(yuǎn)程進(jìn)程通信的場景 |
Binder
終于來到這篇文章的重頭戲了,上面講到Android解決IPC的方法中有一種是AIDL,它使用的原理就是Binder,只有理解了Binder,我們才算是理解了Android跨進(jìn)程通信的原理。在這里我會帶大家看看Android中有哪一些重要的地方使用到了Binder,接著我們會通過一個實例來了解如何使用Binder,最后我們會分析Binder的源碼來理解他的工作流程。
Binder在Android中的運(yùn)用
說起B(yǎng)inder在Android的使用場景,可以說是無處不在,我列出一些最常見的場景:
- 四大組件的生命周期都是使用Binder機(jī)制進(jìn)行管理的
- View的工作原理也使用了Binder
- WindowManager的工作機(jī)制同樣使用了Binder
以上三個方面只是最常見的場景,但是卻幾乎包括了我們開發(fā)的整個流程。我們開發(fā)的應(yīng)用都離不開四大組件,而四大組件也正是依靠Binder機(jī)制運(yùn)行的;對于我們最常見的View,他是如何顯示的,View又是如何響應(yīng)我們的動作的,這其中也用到了Binder(關(guān)于這些內(nèi)容我會在后續(xù)的文章中為大家分析)??梢哉f了解Binder對于我們的開發(fā)是很有幫助的,那接下來我們就來看看我們該如何使用Binder進(jìn)行進(jìn)程間的通信吧!
如何使用Binder
現(xiàn)在我們需要實現(xiàn)這樣的功能:客戶端與服務(wù)端位于不同的進(jìn)程,客戶端需要向服務(wù)端添加學(xué)生,同時客戶端還可以向服務(wù)端發(fā)起查詢學(xué)生列表的請求。
1、創(chuàng)建Student.java,Student.aidl,IStudentManager.aidl
- Student.java
package com.bob.aidltest.aidl;
import android.os.Parcel;
import android.os.Parcelable;
/**
* Created by bob on 17-7-3.
* 所有需要在Binder傳遞的數(shù)據(jù)類型都需要實現(xiàn)Parcelable接口
*/
public class Student implements Parcelable{
public static String name="BOB";
public int s_id;
public String s_name;
public String s_gender;
public Student(Parcel in) {
s_id = in.readInt();
s_name = in.readString();
s_gender = in.readString();
}
public Student(int s_id, String s_name, String s_gender) {
this.s_id = s_id;
this.s_name = s_name;
this.s_gender = s_gender;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(s_id);
dest.writeString(s_name);
dest.writeString(s_gender);
}
public static final Creator<Student> CREATOR = new Creator<Student>() {
@Override
public Student createFromParcel(Parcel in) {
return new Student(in);
}
@Override
public Student[] newArray(int size) {
return new Student[size];
}
};
@Override
public String toString() {
return String.format("[StudentID: %s , StudentName: %s , StudentGender: %s]", s_id, s_name, s_gender);
}
}
- Student.aidl
// Student1.aidl
package com.bob.aidltest.aidl;
parcelable Student;
- IStudentManager.aidl
// IStudentManager.aidl
package com.bob.aidltest.aidl;
import com.bob.aidltest.aidl.Student;
interface IStudentManager {
List<Student> getStudentList();
void addStudent(in Student student);
}
創(chuàng)建完畢之后手動編譯項目(Build-->ReBuild Project),接著就會在app/build/generated/source/aidl/debug/com/bob/aidltest/aidl/IStudentManager.java中看到自動生成的IStudentManager接口,如下圖:

2、分析IStudentManager.java
先來看看自動生成的代碼:
public interface IStudentManager extends android.os.IInterface
{
/** 內(nèi)部類Stub,繼承自Binder并且實現(xiàn)了IStudentManager接口,因此他也是一個Binder對象,這個內(nèi)部類是需要在服務(wù)端手動實現(xiàn)的,并且會通過onBind方法返回給客戶端 */
public static abstract class Stub extends android.os.Binder implements com.bob.aidltest.aidl.IStudentManager
{
private static final java.lang.String DESCRIPTOR = "com.bob.aidltest.aidl.IStudentManager";
/** 構(gòu)造方法 */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* 將服務(wù)端的Binder對象轉(zhuǎn)換為客戶端的所需的AIDL接口類型的對象,客戶端拿到這個對象就可以通過這個對象遠(yuǎn)程訪問服務(wù)端的方法
*/
public static com.bob.aidltest.aidl.IStudentManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.bob.aidltest.aidl.IStudentManager))) {
return ((com.bob.aidltest.aidl.IStudentManager)iin);
}
return new com.bob.aidltest.aidl.IStudentManager.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
/**
* 運(yùn)行在服務(wù)端進(jìn)程的Binder線程池中;當(dāng)客戶端進(jìn)程發(fā)起遠(yuǎn)程請求時,遠(yuǎn)程請求會要求系統(tǒng)底層執(zhí)行回調(diào)該方法
* @param code 客戶端進(jìn)程請求方法標(biāo)識符。服務(wù)端進(jìn)程會根據(jù)該標(biāo)識確定所請求的目標(biāo)方法
* @param data 目標(biāo)方法的參數(shù),他是客戶端進(jìn)程傳進(jìn)來的,當(dāng)我們調(diào)用addStudent(Student student)方法時,參數(shù)就是Student對象
* @param reply 目標(biāo)方法執(zhí)行后的結(jié)果,將會返回給客戶端,例如當(dāng)我們調(diào)用getStudentList,返回的就是一個Student的列表
*/
@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_getStudentList:
{
data.enforceInterface(DESCRIPTOR);
java.util.List<com.bob.aidltest.aidl.Student> _result = this.getStudentList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addStudent:
{
data.enforceInterface(DESCRIPTOR);
com.bob.aidltest.aidl.Student _arg0;
if ((0!=data.readInt())) {
_arg0 = com.bob.aidltest.aidl.Student.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addStudent(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
/**
* 代理的內(nèi)部類,他實現(xiàn)了IStudentManager接口,這個代理類就是服務(wù)端返回給客戶端的AIDL接口對象,客戶端可以通過這個代理類訪問服務(wù)端的方法
*/
private static class Proxy implements com.bob.aidltest.aidl.IStudentManager
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public java.util.List<com.bob.aidltest.aidl.Student> getStudentList() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.bob.aidltest.aidl.Student> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getStudentList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.bob.aidltest.aidl.Student.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public void addStudent(com.bob.aidltest.aidl.Student student) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((student!=null)) {
_data.writeInt(1);
student.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addStudent, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_getStudentList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addStudent = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public java.util.List<com.bob.aidltest.aidl.Student> getStudentList() throws android.os.RemoteException;
public void addStudent(com.bob.aidltest.aidl.Student student) throws android.os.RemoteException;
}
可能看了上面的注釋大家還是一頭霧水,那就先看看這個類的結(jié)構(gòu)圖吧:

有關(guān)這個類的細(xì)節(jié)我們待會講,現(xiàn)在只需要知道我們需要在服務(wù)端手動實現(xiàn)Proxy類并實現(xiàn)其中的方法。
創(chuàng)建StudentManagerService.java,并為其指定進(jìn)程
/**
* Created by bob on 17-7-3.
* 服務(wù)端代碼
*/
public class StudentManagerService extends Service {
private static final String TAG = "StudentManagerService";
//判斷Service是否銷毀
private AtomicBoolean mIsServiceDestroyed = new AtomicBoolean(false);
//適合用于進(jìn)程間傳輸?shù)牧斜眍? private CopyOnWriteArrayList<Student> mStudentList = new CopyOnWriteArrayList<Student>();
@Override
public void onCreate() {
super.onCreate();
//在服務(wù)端手動添加兩位默認(rèn)的學(xué)生
mStudentList.add(new Student(1, "BOB", "man"));
mStudentList.add(new Student(2, "MAY", "woman"));
}
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onDestroy() {
mIsServiceDestroyed.set(false);
super.onDestroy();
}
private Binder mBinder = new IStudentManager.Stub() {
@Override
public List<Student> getStudentList() throws RemoteException {
SystemClock.sleep(5000);//休眠5s模擬耗時操作
return mStudentList;
}
@Override
public void addStudent(Student student) throws RemoteException {
mStudentList.add(student);
}
};
}
在清單文件中指定服務(wù)的進(jìn)程
<service
android:name=".StudentManagerService"
android:process=":remote">
</service>
可以看到這個服務(wù)類跟普通的服務(wù)類相差并不大,唯一的區(qū)別在于它創(chuàng)建了一個IStudentManager.Stub的匿名內(nèi)部類并且實現(xiàn)了其中的方法,在onBind方法中將這個IBinder對象返回給客戶端。這里需要說明一下:Binder是實現(xiàn)了IBinder接口的,所以他同時也是一個IBinder對象。
在客戶端愉快的綁定Service吧!
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity_Client";
private static final int MESSAGE_QUERY_STUDENTLIST=1;
private int student_size = 3;
private IStudentManager mRemoteStudentManager;
private ServiceConnection mConnection=new ServiceConnection() {
//onServiceConnected與onServiceDisconnected都是在主線程中的,所以如果里面如果涉及到服務(wù)端的耗時操作那么需要在子線程中進(jìn)行
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//獲取到IStudentManager對象
final IStudentManager studentManager =IStudentManager.Stub.asInterface(service);
mRemoteStudentManager = studentManager;
}
@Override
public void onServiceDisconnected(ComponentName name) {
mRemoteStudentManager = null;
Log.d(TAG, "onServiceDisconnected.threadname:" + Thread.currentThread().getName());
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, StudentManagerService.class);
bindService(intent, mConnection, BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
unbindService(mConnection);
super.onDestroy();
}
//將服務(wù)端返回的數(shù)據(jù)顯示在界面上
private Handler mHandler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_QUERY_STUDENTLIST:
Toast.makeText(MainActivity.this, msg.obj.toString(),Toast.LENGTH_SHORT).show();
default:
super.handleMessage(msg);
}
}
};
/**
* 在客戶端向服務(wù)端添加一名學(xué)生
* @param view
*/
public void addStudent(View view) {
if (mRemoteStudentManager != null) {
try{
int student_id = student_size+ 1;
Student newStudent;
if (student_id % 2 == 0) {
newStudent= new Student(student_id, "新學(xué)生" + student_id, "man");
} else {
newStudent= new Student(student_id, "新學(xué)生" + student_id, "woman");
}
mRemoteStudentManager.addStudent(newStudent);
Log.d(TAG, "添加一位學(xué)生:" + newStudent.toString());
}catch(Exception e){
e.printStackTrace();
}
}
}
/**
* 在客戶端向服務(wù)端發(fā)起查詢學(xué)生的請求
* @param view
*/
public void get_student_list(View view) {
Toast.makeText(this, "正在獲取學(xué)生列表", Toast.LENGTH_SHORT).show();
//由于服務(wù)端的查詢操作是耗時操作,所以客戶端需要開啟子線程進(jìn)行工作
new Thread(new Runnable() {
@Override
public void run() {
if (mRemoteStudentManager != null) {
try{
final List<Student> students = mRemoteStudentManager.getStudentList();
student_size = students.size();
Log.d(TAG, "從服務(wù)器成功獲取到學(xué)生列表:" + students.toString());
mHandler.obtainMessage(MESSAGE_QUERY_STUDENTLIST, students).sendToTarget();
}catch(Exception e){
e.printStackTrace();
}
}
}
}).start();
}
}
可以看到我們在客戶端只需要綁定遠(yuǎn)程的服務(wù)端,服務(wù)端就會返回一個IBinder對象,接著我們需要調(diào)用IStudentManager.Stub.asInterface()方法,將這個IBinder對象轉(zhuǎn)換為我們客戶端可用的AIDL接口對象,拿到這個對象之后我們就可以遠(yuǎn)程調(diào)用服務(wù)端的方法了。是不是很容易?
但是需要注意的一點(diǎn)是為了模擬耗時操作,我們在服務(wù)端的getStudentList的方法中使用休眠以模擬耗時操作,所以客戶端在調(diào)用該方法時不能直接在主線程中調(diào)用,而是應(yīng)該開啟一個子線程,在子線程中調(diào)用這個耗時的操作。
看看效果
首先我們獲取學(xué)生列表,接著連續(xù)添加4個學(xué)生,再次查看學(xué)生列表,最終的結(jié)果如下圖,可以看到我們已經(jīng)實現(xiàn)了兩個進(jìn)程之間的交互,接下來我們將分析Binder的原理。

Binder的原理
進(jìn)程的機(jī)制
首先我們需要了解進(jìn)程之間為什么不能直接進(jìn)行通信,以下是兩個進(jìn)程的示意圖:

從上面的圖我們可以得到以下幾點(diǎn):
- 一個進(jìn)程空間分為:用戶態(tài)和內(nèi)核態(tài),即把進(jìn)程內(nèi)用戶和內(nèi)核隔離開來
- 進(jìn)程之間,由于Android系統(tǒng)為每個進(jìn)程分配了一個獨(dú)立的虛擬機(jī),用戶空間和內(nèi)核空間的數(shù)據(jù)不可交互
- Binder作為進(jìn)程間的介質(zhì),充當(dāng)了中介,使得進(jìn)程間的內(nèi)核態(tài)可以通過Binder進(jìn)行數(shù)據(jù)交互
IPC交互示意圖

圖中總共有四個元素,分別是充當(dāng)客戶端的Activity,服務(wù)端的StudentManagerService,充當(dāng)服務(wù)管理者的IStudentManager以及充當(dāng)訪問介質(zhì)的Binder驅(qū)動。他們的職責(zé)如下:
- StudentManagerService: 服務(wù)提供者,這里面會有許多我們常用的服務(wù),在本例中提供的服務(wù)就是添加學(xué)生以及獲取學(xué)生列表。而在系統(tǒng)中則包括有ActivityService 、 WindowMananger等服務(wù),這些系統(tǒng)服務(wù)提供的功能,對四大組件以及Window的工作提供的保障。
- Activity: 服務(wù)調(diào)用者,一般就是我們的應(yīng)用,在這里我們通過調(diào)用StudentManagerService的服務(wù)來完成工作。
- IStudentManager: 他是負(fù)責(zé)管理服務(wù)的,在其內(nèi)部通過map集合來存儲Service與Binder的映射關(guān)系,這樣客戶端在向其請求服務(wù)的時候就能夠返回特定的Binder。
- Binder驅(qū)動: 他是IStudentManager連接各種Service的橋梁,同時也是客戶端與服務(wù)端交流的橋梁。
總結(jié)起來說,應(yīng)用程序(Activity)首先向IStudentManager發(fā)送請求StudentManagerService的服務(wù),IStudentManager查看已經(jīng)注冊在里面的服務(wù)的列表,找到相應(yīng)的服務(wù)后,通過Binder驅(qū)動將其中的Binder對象返回給客戶端,從而完成對服務(wù)的請求。
源碼分析
我們主要分析的就是IStudentManager這個類,從上面得到講解我們已經(jīng)知道它包含了兩個類:Stub和Proxy。先來看看Proxy類
//Proxy.java
public java.util.List<com.bob.aidltest.aidl.Student> getStudentList() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.bob.aidltest.aidl.Student> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getStudentList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.bob.aidltest.aidl.Student.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public void addStudent(com.bob.aidltest.aidl.Student student) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((student!=null)) {
_data.writeInt(1);
student.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addStudent, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
上面截取了Proxy的兩個方法,其中Proxy是運(yùn)行在客戶端的,他是用服務(wù)端返回來的Binder對象調(diào)用了public static IStudentManager asInterface(IBinder obj)方法返回來的。
既然Proxy運(yùn)行在客戶端,那么客戶端也是通過Proxy來調(diào)用遠(yuǎn)程服務(wù)端的方法的,也就是說我們將調(diào)用方法需要用到的參數(shù)傳遞給Proxy,接著由Proxy來訪問服務(wù)端,所以我們能夠看到,Proxy將我們的參數(shù)寫進(jìn)了_data,而_reply則代表從服務(wù)端返回來的結(jié)果。
從代碼中我們還看到客戶端在將數(shù)據(jù)傳遞給服務(wù)端之后就處于阻塞狀態(tài),直到服務(wù)端返回結(jié)果,所以如果調(diào)用的服務(wù)端方法是一個耗時方法,那么我們就需要在子線程中進(jìn)行工作了。
數(shù)據(jù)準(zhǔn)備好之后當(dāng)然是需要傳遞了,可以看到Proxy通過transact方法講數(shù)據(jù)傳遞出去了,接下來就來看transact方法:
//Binder#transact
public final boolean transact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
if (false) Log.v("Binder", "Transact: " + code + " to " + this);
if (data != null) {
data.setDataPosition(0);
}
//調(diào)用了Binder的onTransact
boolean r = onTransact(code, data, reply, flags);
if (reply != null) {
reply.setDataPosition(0);
}
return r;
}
可以看到transact方法實際上調(diào)用了Binder的onTransact,而這里的Binder就是指Stub了,我們看一下Stub的定義:
public static abstract class Stub extends android.os.Binder implements com.bob.aidltest.aidl.IStudentManager
可以看到Stub確實繼承了Binder并且也實現(xiàn)了IStudentManager接口,接下來我們繼續(xù)看Stub中的onTransact方法:
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_getStudentList:
{
data.enforceInterface(DESCRIPTOR);
java.util.List<com.bob.aidltest.aidl.Student> _result = this.getStudentList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
case TRANSACTION_addStudent:
{
data.enforceInterface(DESCRIPTOR);
com.bob.aidltest.aidl.Student _arg0;
if ((0!=data.readInt())) {
_arg0 = com.bob.aidltest.aidl.Student.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addStudent(_arg0);
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
可以看到,服務(wù)端通過客戶端傳遞過來的code常量來判斷客戶端需要調(diào)用的是哪個方法,接著就執(zhí)行該方法,執(zhí)行完之后如果有數(shù)據(jù)返回則將結(jié)果寫入reply,接著Proxy就可以收到結(jié)果了。而整個通信過程也就結(jié)束了。
最后我借用Carson_Ho的一張流程圖來描述這個完整的流程:

后記
Binder機(jī)制在Android中的作用舉足輕重,本文只是通過Java代碼分析其工作流程,由于博主不擅長C/C++,所以無法研究native,不過本文依舊完整的闡述了Binder的整個運(yùn)行機(jī)制,希望通過本文大家能夠?qū)inder機(jī)制有更深刻的理解,關(guān)于Binder在Android系統(tǒng)中的更多運(yùn)用我會在后續(xù)的文章中為大家奉上,希望大家多多支持。