Android:從源碼角度來(lái)賞析Binder機(jī)制的優(yōu)美

談到android進(jìn)程間通信,就不得不想到Binder,那么他到底是何方圣神呢?話不多說(shuō),咱們下面一起來(lái)解密一番!

IBinder

首先我們來(lái)看一下Binder的聲明:

public class Binder implements IBinder {...}

喲,那么IBinder又是什么呢?

public interface IBinder {
    
    int FIRST_CALL_TRANSACTION  = 0x00000001;
    int LAST_CALL_TRANSACTION   = 0x00ffffff;
    int PING_TRANSACTION        = ('_'<<24)|('P'<<16)|('N'<<8)|'G';
    int DUMP_TRANSACTION        = ('_'<<24)|('D'<<16)|('M'<<8)|'P';
    int SHELL_COMMAND_TRANSACTION = ('_'<<24)|('C'<<16)|('M'<<8)|'D';
    int INTERFACE_TRANSACTION   = ('_'<<24)|('N'<<16)|('T'<<8)|'F';
    int TWEET_TRANSACTION       = ('_'<<24)|('T'<<16)|('W'<<8)|'T';
    int LIKE_TRANSACTION        = ('_'<<24)|('L'<<16)|('I'<<8)|'K';
    int SYSPROPS_TRANSACTION    = ('_'<<24)|('S'<<16)|('P'<<8)|'R';
    int FLAG_ONEWAY             = 0x00000001;

    public static final int MAX_IPC_SIZE = 64 * 1024;
    public @Nullable String getInterfaceDescriptor() throws RemoteException;
    public boolean pingBinder();
    public boolean isBinderAlive();
    public @Nullable IInterface queryLocalInterface(@NonNull String descriptor);
    public void dump(@NonNull FileDescriptor fd, @Nullable String[] args) throws RemoteException;
    public void dumpAsync(@NonNull FileDescriptor fd, @Nullable String[] args) throws RemoteException;
    public void shellCommand(@Nullable FileDescriptor in, 
            @Nullable FileDescriptor out, @Nullable FileDescriptor err,
            @NonNull String[] args, @Nullable ShellCallback shellCallback,
            @NonNull ResultReceiver resultReceiver) throws RemoteException;
    public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException;
    public interface DeathRecipient {
        public void binderDied();
    }
    public void linkToDeath(@NonNull DeathRecipient recipient, int flags) throws RemoteException;
    public boolean unlinkToDeath(@NonNull DeathRecipient recipient, int flags);
}

哦,原來(lái)IBinder 是一個(gè)定義了跨進(jìn)程傳輸能力的接口。只要實(shí)現(xiàn)了這個(gè)接口,就能將這個(gè)對(duì)象進(jìn)行跨進(jìn)程傳遞。
這些方法中重點(diǎn)關(guān)注 transact(),Binder里面與它對(duì)應(yīng)的是 Binder.onTransact()。


Binder

Binder是官方提供的實(shí)現(xiàn)了IBinder接口的操作,它是 Android IPC 的基礎(chǔ),平常接觸到的各種 Manager(ActivityManager, ServiceManager 等),以及綁定 Service 時(shí)都在使用它進(jìn)行跨進(jìn)程操作。
下面介紹幾個(gè)關(guān)鍵方法:

  • transact()
public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
    if (false) Log.v("Binder", "Transact: " + code + " to " + this);

    if (data != null) {
        data.setDataPosition(0);
    }
    boolean r = onTransact(code, data, reply, flags);
    if (reply != null) {
        reply.setDataPosition(0);
    }
    return r;
}

連接Binder驅(qū)動(dòng),發(fā)起IPC請(qǐng)求。

  • onTransact()
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
    if (code == INTERFACE_TRANSACTION) {
        ......
    } else if (code == DUMP_TRANSACTION) {
        ......
    } else if (code == SHELL_COMMAND_TRANSACTION) {
        ......
    }
    return false;
}

根據(jù) code 對(duì)傳入的參數(shù) data 做相應(yīng)的處理,然后寫(xiě)入 reply,這樣就能返回操作后的數(shù)據(jù)。

  • attachInterface()
public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
        mOwner = owner;
        mDescriptor = descriptor;
}

這個(gè)方法的作用是將一個(gè)描述符、特定的 IInterface 與當(dāng)前 Binder 綁定起來(lái),這樣后續(xù)調(diào)用 queryLocalInterface 就可以拿到這個(gè) IInterface,那 IInterface 又是什么呢?

public interface IInterface{
    public IBinder asBinder();
}

IInterface 里只定義了一個(gè) asBinder() 方法,這個(gè)方法可以返回當(dāng)前接口關(guān)聯(lián)的 Binder 對(duì)象。


Binder通信機(jī)制

上面只是簡(jiǎn)單介紹了Binder類相關(guān)的信息,具體的詳細(xì)信息可以去查看源碼,但這只是Binder通信機(jī)制的基礎(chǔ)。
要理解Binder通信機(jī)制,首先我們要先來(lái)了解一下Android的內(nèi)存空間:


Linux內(nèi)核模型.png

用戶空間:用戶空間的進(jìn)程是相互獨(dú)立的,彼此之間不能共享
內(nèi)核空間:內(nèi)核空間的內(nèi)存是可以共享的,其大小可以通過(guò)參數(shù)來(lái)配置
Android進(jìn)程間通信其實(shí)質(zhì)就是利用內(nèi)核空間共享來(lái)完成的。

下面我們來(lái)看Binder進(jìn)程間通信的四個(gè)重要角色:


Binder通信的四個(gè)角色.png
  • Client:用戶端進(jìn)程
  • Server:服務(wù)端進(jìn)程
  • Service Manager:運(yùn)行在用戶空間,它負(fù)責(zé)管理 Service 注冊(cè)與查詢等操作
  • Binder驅(qū)動(dòng):負(fù)責(zé)進(jìn)程之間Binder通信的建立,進(jìn)程間通信的核心

下面我們來(lái)總結(jié)一下Binder機(jī)制的整個(gè)運(yùn)行過(guò)程

  1. ServiceManager 初始化
  2. Server 向 ServiceManager 注冊(cè)自己
  3. Client 獲取遠(yuǎn)程服務(wù)
    • Client 向 Server 發(fā)起 IPC 請(qǐng)求
    • Binder 驅(qū)動(dòng)將該請(qǐng)求轉(zhuǎn)發(fā)給 ServiceManager 進(jìn)程,
    • ServiceManager 查找到 對(duì)應(yīng)的 Server 的 Binder 引用后通過(guò) Binder 驅(qū)動(dòng)反饋給 Client(并不是實(shí)際真實(shí)的遠(yuǎn)程Binder對(duì)象,而是Binder驅(qū)動(dòng)里的一個(gè)映射)
    • Client 收到 Server 對(duì)應(yīng)的 Binder 引用后,會(huì)創(chuàng)建一個(gè) Server 對(duì)應(yīng)的遠(yuǎn)程服務(wù)(即 Server 在當(dāng)前進(jìn)程的代理)
  4. Client 通過(guò)代理調(diào)用 Server
    • Client 會(huì)先將請(qǐng)求數(shù)據(jù)從用戶空間拷貝到內(nèi)核空間,然后調(diào)用transact去連接Binder驅(qū)動(dòng)
    • 接著B(niǎo)inder驅(qū)動(dòng)會(huì)去連接遠(yuǎn)程進(jìn)程,并通知遠(yuǎn)程進(jìn)程執(zhí)行onTransact()函數(shù)
  5. Server 返回結(jié)果
    • 執(zhí)行完成后將結(jié)果寫(xiě)入內(nèi)核空間
    • Binder驅(qū)動(dòng)再喚醒客戶端線程獲取數(shù)據(jù)

注意:這個(gè)過(guò)程中客戶端當(dāng)前線程會(huì)被掛起!因此,如果遠(yuǎn)程進(jìn)程是執(zhí)行長(zhǎng)時(shí)間的運(yùn)算,請(qǐng)不要使用主線程去調(diào)用遠(yuǎn)程函數(shù),以防止ANR。


示例分析

上面講了一些理論上的Binder進(jìn)程間通信的知識(shí),可以清晰的看出Binder采用的是C/S架構(gòu)的模式來(lái)進(jìn)行進(jìn)程間通信的,而其核心點(diǎn)也就是內(nèi)核空間的Binder驅(qū)動(dòng)。下面呢,我們會(huì)通過(guò)一個(gè)具體的實(shí)例從源碼的角度來(lái)解析Binder的進(jìn)程間通信。

首先我們這里給出一副價(jià)值200萬(wàn)的圖(一點(diǎn)也不夸張哈?。?/p>

Binder通信架構(gòu).png
  1. AIDL(Android Interface Definition Language),即Android接口定義語(yǔ)言。通俗來(lái)講就是定義一個(gè)大家都懂的語(yǔ)言,這樣進(jìn)程間交流才不會(huì)有障礙。
  2. Stub:接收底層C/C++Binder引用的回調(diào)。
  • function:就是我們定義的一些接口方法。
  • Proxy:用來(lái)訪問(wèn)底層的Binder驅(qū)動(dòng)。
  1. 本地服務(wù):就是在我們當(dāng)前進(jìn)程里的服務(wù)(后面會(huì)有具體的涉及)。
  2. Binder驅(qū)動(dòng):這里看圖就行了,不做過(guò)多解釋。

OK!價(jià)值200萬(wàn)的圖大家趕緊收好。接下來(lái)我們就具體來(lái)分析源碼。


一、AIDL創(chuàng)建
  1. 新建com.wf.testaidl.bean.Person類,并實(shí)現(xiàn)Parcelable
public class Person implements Parcelable {...}
  1. 在main下面新建aidl文件夾并創(chuàng)建aidl文件(注意:包名和類名必須相同
目錄結(jié)構(gòu).png
  1. 編寫(xiě)aidl接口
// Person.aidl
package com.wf.testaidl.bean;

// Declare any non-default types here with import statements
parcelable Person;

Preson.aidl做一下映射避免下面文件編譯的時(shí)候報(bào)錯(cuò)。

// PersonAidl.aidl
package com.wf.testaidl;

// Declare any non-default types here with import statements
import com.wf.testaidl.bean.Person;

interface PersonAidl {
    /**
     * 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);*/

    void addPerson(in Person person);
    List<Person> getPersonList();
}

這個(gè)文件就具體定義了我們需要的接口。

  1. Make Project
    編譯成功后會(huì)生成app\build\generated\source\aidl\debug\com\wf\testaidl\PersonAidl.java文件。


二、解析PersonAidl.java源碼
package com.wf.testaidl;
public interface PersonAidl extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.wf.testaidl.PersonAidl {
        ...
        private static class Proxy implements com.wf.testaidl.PersonAidl {...}
        ...
    }
        
    /**
     * 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);*/
    public void addPerson(com.wf.testaidl.bean.Person person) throws android.os.RemoteException;
    public java.util.List<com.wf.testaidl.bean.Person> getPersonList() throws android.os.RemoteException;
}

是不是很熟悉,沒(méi)錯(cuò)就是我們上面那幅200萬(wàn)的圖。這里可以很清晰的看出PersonAidl里面包含了我們定義的接口方法和一個(gè)靜態(tài)內(nèi)部抽象類Stub,這個(gè)Stub繼承了Binder并且實(shí)現(xiàn)了PersonAidl接口,這個(gè)Stub里面又定義了一個(gè)Proxy同樣實(shí)現(xiàn)了PersonAidl接口。


Stub
ok!接下來(lái)我們來(lái)看看這個(gè)神奇Stub。

    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.wf.testaidl.PersonAidl {
        private static final java.lang.String DESCRIPTOR = "com.wf.testaidl.PersonAidl";

        public Stub() {...}

        /**
         * Cast an IBinder object into an com.wf.testaidl.PersonAidl interface,
         * generating a proxy if needed.
         */
        public static com.wf.testaidl.PersonAidl asInterface(android.os.IBinder obj) {...}

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

        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {...}

        private static class Proxy implements com.wf.testaidl.PersonAidl {...}
        
        static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }

上面就是這個(gè)Stub的整個(gè)的一個(gè)結(jié)構(gòu),這里有兩個(gè)方法名映射的int常量,這個(gè)后面我們會(huì)用到。
下面我們就來(lái)一步一步的分析它里面的代碼。

  1. DESCRIPTOR
private static final java.lang.String DESCRIPTOR = "com.wf.testaidl.PersonAidl";

這個(gè)很簡(jiǎn)單吧,就是用一個(gè)靜態(tài)常量來(lái)存儲(chǔ)了我們AIDL的類名,有什么用呢?后面你就知道了。

  1. Stub() 構(gòu)造函數(shù)
public Stub() {
    this.attachInterface(this, DESCRIPTOR);
}

構(gòu)造函數(shù)里面就調(diào)了一個(gè)方法,而這個(gè)attachInterface自己沒(méi)有,那么是誰(shuí)的呢?沒(méi)錯(cuò),是它爹Binder的。

private IInterface mOwner;
private String mDescriptor;

public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
    mOwner = owner;
    mDescriptor = descriptor;
}

那么,這個(gè)方法干了一個(gè)什么事兒呢?它就是把自己和這個(gè)DESCRIPTOR保存在了當(dāng)前這個(gè)類里,做了一個(gè)關(guān)聯(lián)關(guān)系,那么有什么用呢?我們繼續(xù)往后面看。

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

這個(gè)方法主要就干了一個(gè)事兒,那就是當(dāng)發(fā)起IPC請(qǐng)求時(shí)把我們從Binder驅(qū)動(dòng)拿到的這個(gè)IBinder描述轉(zhuǎn)換成一個(gè)具體的AIDL接口對(duì)象,后面才能調(diào)用相應(yīng)的接口方法。這里面首先調(diào)用了一個(gè)queryLocalInterface,我們來(lái)看看為什么要先調(diào)用這個(gè)方法呢?

public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
    if (mDescriptor.equals(descriptor)) {
        return mOwner;
    }
    return null;
}

這里可以看出它是拿這個(gè)descriptor去判斷是不是調(diào)用的自己,是就直接返回自己(明白了上面那個(gè)attachInterface的作用了吧)。這又是為什么呢?這里就有一個(gè)要注意的點(diǎn)了,上面我們給出的那個(gè)200萬(wàn)的圖是不是有一個(gè)本地服務(wù),那么為什么會(huì)有一個(gè)本地服務(wù)呢?這里我就要反問(wèn)一個(gè)問(wèn)題了:是不是我們需要訪問(wèn)的服務(wù)一定是在不同的進(jìn)程呢?答案是不是的,我們也有可能會(huì)訪問(wèn)自己的服務(wù),對(duì)吧!好了,那么我想你應(yīng)該明白了這里為什么會(huì)有一個(gè)queryLocalInterface了吧。
好了,我們接著往下看,如果我們?cè)L問(wèn)的不是自己就需要拿這個(gè)IBinder描述去創(chuàng)建一個(gè)遠(yuǎn)程的AIDL接口對(duì)象。

  1. onTransact()
@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_addPerson: {
            data.enforceInterface(DESCRIPTOR);
            com.wf.testaidl.bean.Person _arg0;
            if ((0 != data.readInt())) {
                _arg0 = com.wf.testaidl.bean.Person.CREATOR.createFromParcel(data);
            } else {
                _arg0 = null;
            }
            this.addPerson(_arg0);
            reply.writeNoException();
            return true;
        }
        case TRANSACTION_getPersonList: {
            data.enforceInterface(DESCRIPTOR);
            java.util.List<com.wf.testaidl.bean.Person> _result = this.getPersonList();
            reply.writeNoException();
            reply.writeTypedList(_result);
            return true;
        }
    }
    return super.onTransact(code, data, reply, flags);
 }

這個(gè)方法就是來(lái)處理我們的IPC請(qǐng)求的,根據(jù)不同的code值最終會(huì)調(diào)到它的實(shí)現(xiàn)類的對(duì)應(yīng)的接口方法,然后將處理后的結(jié)果寫(xiě)入replay返回給客戶端。這里面的代碼都很簡(jiǎn)單,就不一一分析了,相信大家自己也能看明白。

  1. class Proxy這個(gè)我們單獨(dú)放到下一節(jié)來(lái)講。
  2. 此刻我想你一定有一個(gè)問(wèn)題:服務(wù)不是要注冊(cè)到ServiceManager嘛,上面沒(méi)有哪里講到注冊(cè)了啊?其實(shí)它在我們上面講的構(gòu)造函數(shù)里面就已經(jīng)完成了注冊(cè),無(wú)參構(gòu)造函數(shù)的初始化首先會(huì)調(diào)用父類的無(wú)參構(gòu)造函數(shù),那我們就來(lái)看看它的父類Binder的無(wú)參構(gòu)造函數(shù):
public Binder() {
    init();
    ...
}

private native final void init();

從上面我們可以看出它調(diào)用了一個(gè)native方法,就是在這里進(jìn)行注冊(cè)的。那么你又會(huì)問(wèn)了:這里沒(méi)有傳任何數(shù)據(jù)???其實(shí)這里native方法它會(huì)隱式的把this傳過(guò)去,那我們之定義的DESCRIPTOR就注冊(cè)過(guò)去了。
到這里我們的Stub服務(wù)端就基本講完了。



Proxy
上面我們剖析了一下Stub的源碼,理解到了Stub其實(shí)是作為一個(gè)服務(wù)端注冊(cè)到ServiceManager來(lái)響應(yīng)我們的請(qǐng)求的。接下來(lái)我們就來(lái)看我么是怎么樣發(fā)起請(qǐng)求的呢?首先我們來(lái)看一下這個(gè)Proxy是什么。

private static class Proxy implements com.wf.testaidl.PersonAidl {
    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 void addPerson(com.wf.testaidl.bean.Person person) throws android.os.RemoteException {...}

    @Override
    public java.util.List<com.wf.testaidl.bean.Person> getPersonList() throws android.os.RemoteException { ...}
}

Proxy作為一個(gè)Stub的靜態(tài)內(nèi)部類主要用來(lái)發(fā)起跨進(jìn)程的請(qǐng)求,那一個(gè)進(jìn)程為什么既有Stub又有Proxy呢?因?yàn)橐粋€(gè)進(jìn)程它既可以是客戶端也可以是服務(wù)端。好了,接下來(lái)我們一步步分析Proxy的源碼,看看它是怎么工作的。

  1. 構(gòu)造函數(shù)
Proxy(android.os.IBinder remote) {
    mRemote = remote;
}

初始化的時(shí)候傳入一需要訪問(wèn)的進(jìn)程的IBinder描述,也就是我們發(fā)起IPC請(qǐng)求的時(shí)候從ServiceManager里面查詢尋到的IBinder,這樣我們才知道是要去訪問(wèn)哪個(gè)進(jìn)程。

  1. 實(shí)現(xiàn)接口方法addPerson()和getPersonList()
@Override
public void addPerson(com.wf.testaidl.bean.Person person) 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 ((person != null)) {
            _data.writeInt(1);
            person.writeToParcel(_data, 0);
        } else {
            _data.writeInt(0);
        }
        mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);
        _reply.readException();
    } finally {
        _reply.recycle();
        _data.recycle();
    }
}

@Override
public java.util.List<com.wf.testaidl.bean.Person> getPersonList() throws android.os.RemoteException {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    java.util.List<com.wf.testaidl.bean.Person> _result;
    try {
        _data.writeInterfaceToken(DESCRIPTOR);
        mRemote.transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0);
        _reply.readException();
        _result = _reply.createTypedArrayList(com.wf.testaidl.bean.Person.CREATOR);
    } finally {
        _reply.recycle();
        _data.recycle();
    }
    return _result;
}

首先初始化兩個(gè)Parcel對(duì)象,都是通過(guò)Parcel.obtain()去Parcel池(隊(duì)列)里面拿的(節(jié)約內(nèi)存)。然后將我們要訪問(wèn)的進(jìn)程(DESCRIPTOR)和傳遞的參數(shù)寫(xiě)入Parcel。接下來(lái)就調(diào)用IBinder引用的transact()去連接 Binder驅(qū)動(dòng)。

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

這里有一個(gè)很有意思也是最簡(jiǎn)單的做法,它把要訪問(wèn)的方法定義成了一個(gè)int類型的常量TRANSACTION_addPerson和TRANSACTION_getPersonList,這兩個(gè)常量是定義在它外部類stub里面的,這樣IBinder引用拿到后就知道是要去調(diào)用哪個(gè)方法了。
接下來(lái)我們看看這個(gè)transact()做了些什么事情?

public final boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply,
            int flags) throws RemoteException {
    if (false) Log.v("Binder", "Transact: " + code + " to " + this);

    if (data != null) {
        data.setDataPosition(0);
    }
    boolean r = onTransact(code, data, reply, flags);
    if (reply != null) {
        reply.setDataPosition(0);
    }
    return r;
}

當(dāng)Binder驅(qū)動(dòng)拿到我們的請(qǐng)求和數(shù)據(jù)后,它就會(huì)去連接我們要訪問(wèn)的服務(wù)端進(jìn)程,然后通知它回調(diào)onTransact()方法。到這里我們的整個(gè)請(qǐng)求就算完成了。


小結(jié)

  1. 一個(gè)進(jìn)程既可以是服務(wù)端Stub,也可以是客戶端Proxy。
  2. 一個(gè)IPC請(qǐng)求發(fā)起時(shí),首先會(huì)調(diào)用Proxy去連接Binder驅(qū)動(dòng),然后Binder驅(qū)動(dòng)再去連接Stub
  3. 要實(shí)現(xiàn)跨進(jìn)程通信,兩個(gè)進(jìn)程必須要有相同的AIDL接口


三、調(diào)用流程分析
  1. ServiceManager的注冊(cè)和獲取
    上面我們講到了Binder進(jìn)程間通信時(shí)所有的Server都時(shí)由ServiceManager來(lái)管理的,那么你可能會(huì)問(wèn)了ServiceManager也是一個(gè)獨(dú)立進(jìn)程,那么它是什么時(shí)候啟動(dòng)?又是什么時(shí)候注冊(cè)的呢?
    系統(tǒng)啟動(dòng)的時(shí)候會(huì)去執(zhí)行\(zhòng)system\core\rootdir\init.rc,在這里面就啟動(dòng)了ServiceManager,啟動(dòng)之后會(huì)去執(zhí)行service_manager.c,那這里面干了什么呢?
int main(int argc, char **argv)
{
    struct binder_state *bs;
    void *svcmgr = BINDER_SERVICE_MANAGER;

    bs = binder_open(128*1024);

    if (binder_become_context_manager(bs)) {
        ALOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }

    svcmgr_handle = svcmgr;
    binder_loop(bs, svcmgr_handler);
    return 0;
}

打開(kāi)bind驅(qū)動(dòng),并且分配128K大小,緊接著把自己注冊(cè)為Service 大管家,然后就開(kāi)啟loop來(lái)讀取Binder驅(qū)動(dòng)的消息處理各種服務(wù)請(qǐng)求。

  1. 客戶端發(fā)起IPC請(qǐng)求
private PersonAidl mPersonAidl;
//綁定服務(wù)
Intent intent = new Intent(this, AidlService.class);
bindService(intent, new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        mPersonAidl = PersonAidl.Stub.asInterface(service);
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        mPersonAidl = null;
    }
}, BIND_AUTO_CREATE);
//請(qǐng)求接口
mPersonAidl.addPerson(person);
List<Person> personList = mPersonAidl.getPersonList();

上面我們是通過(guò)顯示意圖來(lái)綁定的,因?yàn)槲覀兪菍?xiě)在一起然后配置在不同進(jìn)程的,當(dāng)然你也可以用隱式意圖來(lái)綁定服務(wù),那么接下來(lái)我們就來(lái)看看bindService做了什么?

@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
    return mBase.bindService(service, conn, flags);
}

那我們就來(lái)看看mBase.bindService又是干了什么?

public abstract boolean bindService(@RequiresPermission Intent service,
            @NonNull ServiceConnection conn, @BindServiceFlags int flags);

我們可以看到它調(diào)用的是一個(gè)抽象方法,那么我們就自然要去找到它的實(shí)現(xiàn)類,最終我們找到了ContextImpl.java里面。

@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags){
    warnIfCallingFromSystemProcess();
    return bindServiceCommon(service, conn, flags, mMainThread.getHandler(), getUser());
}

那么我再來(lái)看看 bindServiceCommon又干了些啥?

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler handler, UserHandle user){
    ...
    int res = ActivityManager.getService().bindService(...)
    ...
}

好,到這里就開(kāi)始跨進(jìn)程訪問(wèn)了,通過(guò)ActivityManagerService去獲取遠(yuǎn)程服務(wù),最終會(huì)在ActivityThread.java的handleBindService()方法里回調(diào)遠(yuǎn)程服務(wù)的onBind方法返回一個(gè)IBinder引用,這樣我們就能通過(guò)這個(gè)IBinder引用去調(diào)用相應(yīng)的接口來(lái)進(jìn)程跨進(jìn)程訪問(wèn)。后面具體的底層源碼這里就不貼出來(lái)了,感興趣的話可以自己去翻閱源碼。

  1. 自定義服務(wù)端注冊(cè)
public class AidlService extends Service {

    private List<Person> mPersons = new ArrayList<>();
    private IBinder mIBinder = new PersonAidl.Stub() {
        @Override
        public void addPerson(Person person) throws RemoteException {
            mPersons.add(person);
        }

        @Override
        public List<Person> getPersonList() throws RemoteException {
            return mPersons;
        }
    };

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

上面的代碼就是我們自定義的一個(gè)服務(wù),它里面實(shí)現(xiàn)了我們的PersonAidl.Stub,上一節(jié)我們分析的Stub源碼里的onTransact最終會(huì)回調(diào)到這里我們具體的實(shí)現(xiàn)。并且這里可以看到它里面實(shí)現(xiàn)了一個(gè)onBind方法來(lái)返回這個(gè)IBinder引用。

<service
    android:name=".service.AidlService"
    android:exported="true"
    android:enabled="true"
    android:process=":aidl"/>

上面這段代碼就是把我們的服務(wù)聲明到aidl進(jìn)程,這里沒(méi)有什么要說(shuō)的,都是很標(biāo)準(zhǔn)的寫(xiě)法。


總結(jié)

好了,到這里呢,我們這次的Binder進(jìn)程間通信機(jī)制的探索就告一段落了。主要掌握以下幾點(diǎn):

  1. Linux內(nèi)存空間分為用戶空間和內(nèi)核空間,用戶空間不能共享,內(nèi)核空間可以共享;
  2. Binder機(jī)制的四個(gè)重要角色:Client、Server、ServiceManager、Binder驅(qū)動(dòng);
  3. Binder機(jī)制采用的是C/S架構(gòu),Binder驅(qū)動(dòng)是他們之間的橋梁亦是整個(gè)架構(gòu)的核心。
  4. Android中Binder主要的表現(xiàn)形式就是AIDL,重點(diǎn)理解Stub和Proxy模式。

以上就是我個(gè)人對(duì)Binder機(jī)制的一個(gè)理解,如果有說(shuō)錯(cuò)的或者理解不到位的地方都可以指出來(lái),我們一起學(xué)習(xí)改正,謝謝!
最后我們給出舉例的源碼地址:https://github.com/WangFion/TestAidl

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容