Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Binder機制——初探

Binder機制——初探

編輯:關於Android編程

注意:以下內容中出現的類和部分類的方法只能在Android源碼中或者通過反射機制才能使用,在SDK中編譯是通不過的!!如Android.os.Service; MemeoryFile.getParcelFileDescriptor()等你在SDK中無法使用!這裡的內容只是幫助我們去了解Service、ContentProvider等功能為何能實現跨進程間的通信;它們無非就是通過Binder機制和虛擬內存實現的!!  

簡介

傳統Linux系統的IPC方式 VS Android
  • 傳統的管道(Pipe)、信號(Signal)和跟蹤(Trace),這三項通信手段只能用於父進程與子進程之間,或者兄弟進程之間;
  • 報文隊列(Message)、共享內存(Share Memory)和信號量(Semaphore),插口(Socket)的進程間通信機制;
  • Android系統沒有采用上述提到的各種進程間通信機制,而是采用Binder機制,只需要復制一次效率更高。
Binder組件:
  • 核心組件是Binder驅動程序,運行內核空間;
  • Client、Server和Service Manager運行在用戶空間
  • Service Manager是一個守護進程,用來管理Server,並向Client提供查詢Server接口的能力;
  • Client和Server在Binder驅動和Service Manager提供的基礎設施上,進行Client-Server之間的通信;
  • Service Manager和Binder驅動已經在Android平台中實現好,開發者只要按照規范實現自己的Client和Server組件;(依然很困難)
  • 具體結構如下
\    

實例(Java層應用)

用戶定義了一個aidl文件(如 MyServe.aidl (interface MyServe))隨後編譯後我們得到了一個對應的java類(如MyServe.java)。Activity通過bindService方法獲得一個遠程Service的IBinder對象;通過調用com.yq.MyServe.Stub.asInterface(iBinder);獲得一個MyServe接口的對象,方法內部會判斷返回給你一個繼承自Stub的類——與Acitivity在同一個進程,還是一個Proxy(將遠程調用另一個進程的繼承自Stub的類,通過Parcel傳遞數據)對象。具體aidl編譯後的文件內容為MyServe.java文件內容如下: public interface MyServe extends android.os.IInterface
  • public static abstractclass Stubextends android.os.Binder implements MyServe //服務端跑的代碼
    • private static final java.lang.String DESCRIPTOR = "com.yq.MyServe";
    • public static MyServeasInterface(android.os.IBinder obj)
    • {
    • if ((obj==null)) {return null;}
    • android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
    • if (((iin!=null)&&(iin instanceof com.yq.MyServe)))return ((com.yq.MyServe)iin);//客戶端是本地的一個進程;返回本地的MyServe對象
    • return new com.yq.MyServe.Stub.Proxy(obj);//客戶端是另外一個進程;創建一個MyServe.Stub.Proxy對象返回
    • }
    • public booleanonTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    • {//code對應方法的簽名;data對應參數;reply對應返回值
    • switch (code)
    • {
    • case INTERFACE_TRANSACTION: xx
    • //調用相關方法,從data獲取數據,向reply寫入數據;
    • }
    • }
    • private staticclass Proxyimplements com.yq.MyServe //另外一個進程,客戶端跑的代碼
      • private android.os.IBinder mRemote;
      • Proxy(android.os.IBinder remote) {mRemote = remote;} //獲得外部類Stub的一個對象
      •  
      • public intgetxx()throws android.os.RemoteException //比如客戶端調用了這個方法,內部其實走的是這樣的
      • {
      • android.os.Parcel _data = android.os.Parcel.obtain();
      • android.os.Parcel _reply = android.os.Parcel.obtain();
      • int _result;
      • try {
      • _data.writeInterfaceToken(DESCRIPTOR); //寫入參數
      • mRemote.transact(Stub.TRANSACTION_getPid, _data, _reply, 0);
      • //調用Stub對象的transact方法,其實最後是會調用上面的onTransact方法;最核心的東西
      • //Stub.TRANSACTION_getPid對應onTransact方法的code
      • //_data對應onTransact方法的data
      • //_reply對應onTransact方法的reply
      • _reply.readException();
      • _result = _reply.readInt(); //從reply中讀出數據
      • }
      • finally {
      • _reply.recycle();
      • _data.recycle();
      • }
      • return _result; //返回結果,客戶端最後獲得這個結果
      • } 注意:如果要利用Binder在進程之間傳遞對象,那麼需要實現Parcelable接口:如果通過Bundle傳遞該對象(putParcelable),當通過getParcelable獲取該對象的時候需要先給Bundle設置類加載(setClassLoader),這在跨進程之間通信顯得尤為重要。
public class MyParcelable implements Parcelable {
     private int mData;
     public int describeContents() {
         return 0;
     }
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mData);
     }
     public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { 
         public MyParcelable createFromParcel(Parcel in) {
             return new MyParcelable(in);
         }
         public MyParcelable[] newArray(int size) {
             return new MyParcelable[size];
         }
     };
     private MyParcelable(Parcel in) {
         mData = in.readInt();
     }
 }

 

底層源碼分析

  在正式的分析之前首先做出如下約定:
  • Binder機制中進行如下的分層:用戶層、Binder層、IPCThreadState層、Binder驅動層
  • 本文中使用的“Binder層協議”關鍵字表示該協議主要在Binder程序中出現。
    • 這類協議常用的有:ADD_SERVICE_TRANSACTION、CHECK_SERVICE_TRANSACTION
    • 本文中使用的“IPCThreadState層協議”關鍵字表示該協議主要在IPCThreadState程序中出現。
      • 這類協議常用的有:BC_TRANSACTION、BR_TRANSACTON、BR_TRANSACTON_COMPLETE、BC_REPLY
      • 本文中使用的“Binder驅動協議”關鍵字表示該協議主要在Binder驅動程序中出現。
        • 這類協議常用的有:BINDER_SET_CONTEXT_MGR、BINDER_WRITE_READ、
  Client端通信流程:
  1. Client進程在用戶層將通信數據封裝成Parcelable對象;
  2. Client進程將第一步獲得的Parcelable對象交給Binder層處理(通過調用IBinder的transact方法進入Binder層)。Binder層在對數據進行必要的處理之後,將處理後得到的數據加上一個相關的Binder層協議頭交給IPCThreadState層處理(調用IPCThreadState的Transact方法進入IPCThreadState層);【涉及的Binder層協議有:CHECK_SERVICE_TRANSACTION、GET_SERVICE_TRANSACTION、ADD_SERVICE_TRANSACTION、LIST_SERVICES_TRANSACTION】
  3. Client進程的IPCThreadState層也會對數據進行必要的處理之後,並將處理後得到的數據加上一個相關的IPCThreadState層協議頭交給Binder驅動層進行處理(調用ioctl方法進入Bidner驅動層)。同時IPCThreadState層會一直等待來自Binder驅動層返回的數據,如果Client的請求需要有返回值那麼IPCThreadState層只需要接收兩條數據才可以返回,否則一般情況接收到一條數據就可以結束這次的進程間通信。【涉及的IPCThreadState層協議有:BC_TRANSACTION、BR_TRANSACTION_COMPLETE、BR_REPLY、BR_TRANSACTION、BC_REPLY】
  Server端通信流程:
  • Service通過IPCThreadState::joinThreadPool方法進入循環體中;
    1. Server進程的IPCThreadState層不斷跟Binder驅動層進行交互(icotl方法根據參數的不同可能會導致阻塞),一旦獲取到數據就交給IPCThreadState層的executeCommand方法進行處理,根據接收到的數據所屬IPCThreadState層的哪個協議進行對應的處理。如接收到BR_TRANSACTION協議報文表明這是一個Binder發送來的請求Service處理的協議報文,IPCThreadState層會將得到的數據擦去IPCThreadState層協議頭,然後交給Binder層處理處理(通過調用BBinder的transact方法,BBinder是通過發送來的BR_TRANSACTION協議報文得到的對象)。Binder層對數據處理完畢後,IPCThreadState層將Binder層處理後的數據加上一個BR_REPLY協議頭,發送給Binder驅動層,同時等待Binder驅動層返回一條BR_TRANSACTON_COMPLETE協議報文結束這次進程間通信。
    2. BBinder的transact方法內部會調用其子類(對應Server端的BnXXX)的onTransact方法處理。onTransact方法內部根據接收到的數據所屬哪個Binder層協議,對數據進行不同的處理,這裡可以調用用戶層的相關業務。方法執行完畢後回將到IPCThreadState層,調用IPCThreadState的sendReply方法返回處理後的數據給Binder驅動層。
  Client&Server通信流程(IPCThreadState層)——任何進程間通信都是下面的固定步驟  
  1. Client進程將通信數據封裝成Parcelable對象;
  2. Client進程向Binder驅動程序發送一個BC_TRANSACTION命令協議。Binder驅動根據協議內容找到目標Server進程後,向Client發送一個BR_TRANSACTON_COMPLETE返回協議,表示它的進程間請求已經被接受。Client對返回的BR_TRANSACTON_COMPLETE協議進行處理過後,就會再次進入Binder驅動程序中等待目標Server進程返回進程間通信結果。(這個過程Binder會將Client端數據拷貝到Service通過mmap申請得到的那塊物理空間、Binder驅動將前面得到的物理空間對應的虛擬地址傳遞給Service的用戶空間;Binder對數據的拷貝只會發生在這一個地方
  3. Binder驅動程序在向Client發送BR_TRANSACTON_COMPLETE的同時會向Server發送一個BR_TRANSACTON協議,請求目標Server進程處理進程間通信請求。
  4. Server進程接收到Binder驅動程序發來的BR_TRANSACTON協議,並對它處理之後就會向Binder驅動程序發送一個BC_REPLY命令協議。Binder驅動程序根據BC_REPLY協議內容找到目標Client目標後,會向Server進程發送一個BR_TRANSACTON_COMPLETE協議,表示 它返回的通信結果已經收到。Server對BR_TRANSACTON_COMPLETE協議內容處理過後,一次進程間通信就結束了。接著再次進入驅動程序等待下一次進程間通信請求。
  5. Binder驅動程序在向Server進程發送一個BR_TRANSACTON_COMPLETE協議的同時會向Client發送BR_REPLY返回協議,並且將結果返回給Client。
  正式對源碼進行分析之前,首先對Binder機制中經常出現的幾個類和接口進行簡單的說明: { binder / IInterface.h}
class IInterface : public virtual RefBase

template  //INTERFACE為自定義的一個接口繼承IInterface
class BnInterface : public INTERFACE, public BBinder

template  ///INTERFACE為自定義的一個接口繼承IInterface
class BpInterface : public INTERFACE, public BpRefBase
INTERFACE是進程自定義的Service組件接口、BBinder為Binder本地對象提供了抽象的進程間通信接口、BpRefBase為Binder代理對象提供了抽象的進程間通信接口。 BnInterface為Binder本地對象, Service端使用,對應Binder驅動程序中的Binder實體對象;BpInterface為Binder代理對象,Client端使用,對應Binder驅動程序中的Binder引用對象。用戶需要編寫一個BnXXXX實現BnInterface一個BpXXXX實現BpInterface的類,前者Service端使用,後者Client端使用。 BBinder@{ binder / Binder.h}
class BBinder : public IBinder{ 
public:  ``````````````
    virtual status_t    transact(   uint32_t code,  const Parcel& data,  Parcel* reply,  uint32_t flags = 0); 
    //IPCThreadState就會代用BBinder子類的該方法,該方法內部會調用BnXXXX對onTransact方法的實現。
protected:  ````````````
    virtual status_t    onTransact( uint32_t code,  const Parcel& data, Parcel* reply,  uint32_t flags = 0); 
    //BnXXXX實現BnInterface時就會定義該方法
};

  BpRefBase@{ binder / Binder.h}
class BpRefBase : public virtual RefBase { 
protected: ·······
     BpRefBase(const sp& o);
    inline  IBinder*        remote(){ return mRemote; }
private: ······
    BpRefBase(const BpRefBase& o);
    IBinder* const          mRemote; //note1
};
1、指向一個BpBinder對象 BpBinder@{ binder / BpBinder.h}
class BpBinder : public IBinder { 
public: ·········
    inline  int32_t     handle() const { return mHandle; }
    virtual status_t    transact(   uint32_t code,  const Parcel& data, Parcel* reply, uint32_t flags = 0); //note2
private: ·······
    const   int32_t     mHandle; //note1
};
1、該整數表示一個Client組件的句柄值。每一個Client組件在驅動程序對應一個Binder引用對象。 2、BpBinder的transact方法會把自己的mHandler和進程間通信數據發送給Binder驅動程序。Binder驅動程序根據mHandler找到對應的Binder引用對象,進而找到Binder實體對象(Binder驅動層能夠完成BpBinder到BBinder之間的映射),最後將通信數據發送給Service組件。(對於如何通過BpBinder找到BBBinder推薦查閱博文,搜索關鍵字sp b((BBinder*)tr.cookie)即可) BBinder和BpBinder都是通過IPCThreadSate來和Binder驅動程序交互。 IPCThreadState @{ binder / IPCThreadState.h }
class IPCThreadState { 
public: ········
    static  IPCThreadState*     self(); 
     //當前線程是Binder線程,通過它獲取一個IPCThreadState對象,該對象可以跟Binder驅動層通信。
    status_t   transact(int32_t handle,  uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); 
    //與Binder驅動程序交互,底層通過talkWithDriver實現
private:············
    status_t            sendReply(const Parcel& reply, uint32_t flags);
    status_t            waitForResponse(Parcel *reply,  status_t *acquireResult=NULL); 
    status_t            talkWithDriver(bool doReceive=true); //向Binder驅動發送數據也從Binder驅動接收數據
    status_t            writeTransactionData(int32_t cmd, uint32_t binderFlags, 
                                                     int32_t handle,
                                                     uint32_t code,
                                                     const Parcel& data,
                                                     status_t* statusBuffer);
    status_t            executeCommand(int32_t command);
    const   sp    mProcess; //初始化Binder設備
};
對於每個Binder線程池中它都有一個IPCThreadState對象 Service組件結構圖   \\   Client組件結構圖 \ 上面的分析我們可以簡單的獲得以下幾個結論:
  • Server端:BnXXX.cpp需要實現IXX的自定義方法和BBinder的onTransact方法;BBinder自己實現了transact方法,但是transact方法內部會調用onTransact方法。
  • Client端:BpXXX.cpp需要實現IXX的自定義方法,方法內部是將數據包裝之後利用BpRefBase的remote方法獲得一個BpBinder,隨後調用BpBinder的tranact方法將數據發送給Binder驅動程序。
  • BBinder和BpBinder跟Binder驅動的通信都是通過IPCThreadState來實現的,通過IPCThreadState:self()方法獲取該對象,注意通信的前提Client和Server端的主線程已經注冊為Binder線程。
  要知道Service、Client、Service Manager等用戶態都是通過open、mmap、ioctl訪問Binder驅動程序的。而open對應binder_open、mmap對應binder_mmap、ioctl對應binder_ioctl定義在android / binder.c文件中。下面重點分析一下ServiceManager的注冊和相關重要方法!

service_manager.c

Binder通信機制使用句柄來代表遠程接口,Service Manager在充當守護進程的同時,它充當Server的角色,當它作為遠程接口使用時,它的句柄值便為0,這就是它的特殊之處,其余的Server的遠程接口句柄值都是一個大於0 而且由Binder驅動程序自動進行分配的。init進程負責啟動ServiceManager,init進程是在系統啟動時啟動,因此ServiceManager在系統啟動的時候跟隨系統一同啟動。 main()@{servicemanager / service_manager.c}
void *svcmgr_handle; //ServerManager.c的一個局部變量
int main(int argc, char **argv)
{
    struct binder_state *bs; //note 1
    void *svcmgr = BINDER_SERVICE_MANAGER; //note2
    bs = binder_open(128*1024); //note3
    if (binder_become_context_manager(bs)) { //note4
        return -1;
    }
    svcmgr_handle = svcmgr; //note5
    binder_loop(bs, svcmgr_handler); //note6
    return 0;
}
1、
struct binder_state{
    int fd; //設備描述符
    void *mmaped; //映射空間起始地址
    unsigned mapsize; //映射空間大小
    //映射是將設備文件映射到進程的地址空間,用於緩存進程間通信的數據
}

2、#define BINDER_SERVICE_MANAGER ((void*) 0) //句柄值為0的宏定義 3、打開Binder設備文件;open("/dev/binder", O_RDWR);(建立128K內存映射:mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);) 4、告訴Binder驅動程序自己是Binder上下文管理者,即我們前面所說的守護進程;binder_become_context_manager(bs); 5、保存到全局變量中,一個與ServiceManager對應的虛擬Binder本地對象 6、是進入一個無窮循環,充當Server的角色,等待Client的請求。binder_loop(bs, svcmgr_handler); 下面是對binder_open、binder_become_context_manager、binder_loop進行介紹 binder_open()@{ servicemanager / binder.c}
struct binder_state *binder_open(unsigned mapsize)
{
    struct binder_state *bs;
    bs = malloc(sizeof(*bs));
    if (!bs) { errno = ENOMEM;  return 0; }

    bs->fd = open("/dev/binder", O_RDWR); //note1
    if (bs->fd < 0) {  fprintf(stderr,"binder: cannot open device (%s)\n",strerror(errno)); goto fail_open; }
    bs->mapsize = mapsize;

    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0); //note2
    if (bs->mapped == MAP_FAILED) {fprintf(stderr,"binder: cannot map device (%s)\n", strerror(errno)); goto fail_map;}
    return bs;

fail_map:
    close(bs->fd);
fail_open:
    free(bs);
    return 0;
}
1、該方法最終導致Binder驅動程序的binder_open方法被調用 binder_become_context_manager()@{ servicemanager / binder.c}
#define BINDER_SET_CONTEXT_MGR _IOW('b', 7, int)
int binder_become_context_manager(struct binder_state *bs)
{
    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0); //note1
}
1、該方法會導致Binder驅動的binder_ioctl方法被調用。binder_ioctl方法多次被使用到,已經貼在後面的附錄一中。 通過向Binder驅動層發送BINDER_SET_CONTEXT_MGR協議將自己注冊到Binder驅動程序中。ioctl中最後一個參數,表示當前Service Manager對應的本地Binder對象的地址值,Service Manager對應Binder本地對象值為0;   binder_loop()@{ servicemanager / binder.c}
BC_ENTER_LOOPER = _IO('c', 12),
BINDER_WRITE_READ _IOWR('b', 1, struct binder_write_read)
void binder_loop(struct binder_state *bs, binder_handler func){
    int res;
    struct binder_write_read bwr;
    unsigned readbuf[32];

    bwr.write_size = 0;
    bwr.write_consumed = 0;
    bwr.write_buffer = 0;
    
    readbuf[0] = BC_ENTER_LOOPER;
    binder_write(bs, readbuf, sizeof(unsigned));//note1

    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (unsigned) readbuf;

        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);  //note2
        if (res < 0) {  LOGE("binder_loop: ioctl failed (%s)\n", strerror(errno)); break; }

        res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);  //note3
        if (res == 0) { LOGE("binder_loop: unexpected reply?!\n"); break;}
        if (res < 0) { LOGE("binder_loop: io error %d %s\n", res, strerror(errno)); break; }
    }
}
1、該方法用於將當前線程注冊到Binder驅動程序中,成為Binder線程,Binder驅動程序隨後可以將進程間通信請求交付給該線程進行處理
int binder_write(struct binder_state *bs, void *data, unsigned len)
{
    struct binder_write_read bwr;
    int res;
    bwr.write_size = len;
    bwr.write_consumed = 0;
    bwr.write_buffer = (unsigned) data;
    bwr.read_size = 0; //輸出緩存區為空,則一旦完成注冊,就會退回到用戶空間中。
    bwr.read_consumed = 0;
    bwr.read_buffer = 0;
    res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); //note1
    if (res < 0) {
        fprintf(stderr,"binder_write: ioctl failed (%s)\n", strerror(errno));
    }
    return res;
}
1、向Binder驅動層發送一個BINDER_WRITE_READ協議報文
2、該方法的bwr參數的輸出緩存區長度為readbuf大小,輸入緩存區長度等於0,因此只會調用函數binder_thread_read。如果ServiceManager進程的主線程沒有待處理的工作項,它將會睡眠在Binder驅動程序的binder_thread_read中,等待其它Service和Client向它發送進程間通信請求。 3、解析獲得的readbuf數據,使用binder_handler func處理 binder_parse()@{ servicemanager / binder.c}
int binder_parse(struct binder_state *bs, struct binder_io *bio, uintptr_t ptr, size_t size, binder_handler func) {
    int r = 1;
    uintptr_t end = ptr + (uintptr_t) size;
    while (ptr < end) {
        uint32_t cmd = *(uint32_t *) ptr;
        ptr += sizeof(uint32_t);
        switch(cmd) {
        case BR_NOOP:
            break;
        case BR_TRANSACTION_COMPLETE:
            break;
        case BR_INCREFS:
        case BR_ACQUIRE:
        case BR_RELEASE:
        case BR_DECREFS:
            ptr += sizeof(struct binder_ptr_cookie);
            break;
        case BR_TRANSACTION: {  //note1
            struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
            if ((end - ptr) < sizeof(*txn)) {  return -1;  } 
            binder_dump_txn(txn);
            if (func) {
                unsigned rdata[256/4];
                struct binder_io msg;
                struct binder_io reply;
                int res;
                bio_init(&reply, rdata, sizeof(rdata), 4);
                bio_init_from_txn(&msg, txn);
                res = func(bs, txn, &msg, &reply); //note2
                binder_send_reply(bs, &reply, txn->data.ptr.buffer, res); //note3
            }
            ptr += sizeof(*txn);
            break;
        }
        case BR_REPLY: {
            ......
            break;
        }
        case BR_DEAD_BINDER: {
           ........
            break;
        }
        case BR_FAILED_REPLY:
            r = -1;
            break;
        case BR_DEAD_REPLY:
            r = -1;
            break;
        default:
            return -1;
        }
    }
    return r;
}
1、接收到一個IPCThreadState層協議——BR_TRANSACTION; 2、調用func處理,func等於servicemanager / service_manager.c的svcmgr_handle對象。 3、向Binder驅動器發送BC_REPLY協議報文 svcmgr_handler()@{ servicemanager / service_manager.c}
int svcmgr_handler(struct binder_state *bs, struct binder_txn *txn, struct binder_io *msg,  struct binder_io *reply) {
    struct svcinfo *si;
    uint16_t *s;
    unsigned len;
    void *ptr;
    uint32_t strict_policy;
    if (txn->target != svcmgr_handle)  return -1; 
    strict_policy = bio_get_uint32(msg);
    s = bio_get_string16(msg, &len);
    if ((len != (sizeof(svcmgr_id) / 2)) ||
        memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
        fprintf(stderr,"invalid id %s\n", str8(s));
        return -1;
    }
    switch(txn->code) {
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE:
        s = bio_get_string16(msg, &len);
        ptr = do_find_service(bs, s, len); //從列表中查找服務
        if (!ptr)   break; 
        bio_put_ref(reply, ptr); //這裡是{servicemanager / binder.c}中的方法;ptr是句柄號,將內容寫入到reply中。
        return 0;
    case SVC_MGR_ADD_SERVICE:
        s = bio_get_string16(msg, &len);
        ptr = bio_get_ref(msg);
        if (do_add_service(bs, s, len, ptr, txn->sender_euid))  return -1;  
        break;
    case SVC_MGR_LIST_SERVICES: {
        unsigned n = bio_get_uint32(msg);
        si = svclist;
        while ((n-- > 0) && si)
            si = si->next;
        if (si) {
            bio_put_string16(reply, si->name);
            return 0;
        }
        return -1;
    }
    default:  return -1; 
    }
    bio_put_uint32(reply, 0);
    return 0;
}
binder_send_reply()@{ servicemanager / binder.c}
void binder_send_reply(struct binder_state *bs,  struct binder_io *reply,   binder_uintptr_t buffer_to_free,  int status) { 
    struct {
        uint32_t cmd_free;
        binder_uintptr_t buffer;
        uint32_t cmd_reply;
        struct binder_transaction_data txn;
    } __attribute__((packed)) data;
    data.cmd_free = BC_FREE_BUFFER;
    data.buffer = buffer_to_free;
    data.cmd_reply = BC_REPLY;
    data.txn.target.ptr = 0;
    data.txn.cookie = 0;
    data.txn.code = 0;
    if (status) {
        data.txn.flags = TF_STATUS_CODE;
        data.txn.data_size = sizeof(int);
        data.txn.offsets_size = 0;
        data.txn.data.ptr.buffer = (uintptr_t)&status;
        data.txn.data.ptr.offsets = 0;
    } else {
        data.txn.flags = 0;
        data.txn.data_size = reply->data - reply->data0;
        data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);
        data.txn.data.ptr.buffer = (uintptr_t)reply->data0;
        data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;
    }
    binder_write(bs, &data, sizeof(data)); //在binder_loop()已經介紹過會
}
這裡需要特別注意的是ServiceManager跟普通Service的不同之處還在於。對於普通XXService,Client獲取到一個BpXXService,然後調用它的一個方法,最終通過Binder機制會將數據交給BnXXService的同名方法處理。然而對於ServiceManager,Client獲取到一個BpServiceManager,然後調用它的一個方法,如getService,最終通過Binder機制會將數據交給svcmgr_handler()@{ servicemanager / service_manager.c}處理,而不是交給BnServiceManage處理!!!詳細參考鏈接   ServiceManager注冊:
  1. 調用binder_open(128*1024)方法打開文件描述符和在當前進程給/dev/binder設備描述符映射一個塊空間。
  2. 調用binder_become_context_manager方法注冊自己成為Bidner機制的上下文管理者。方法內部通過ioct方法進入到Binder驅動層,發送一條BINDER_SET_CONTEXT_MGR的Binder驅動層協議的報文。
  3. 調用binder_loop方法進入循環,向Binder驅動器協議發送一條BC_ENTER_LOOPER的IPCThreadState層協議報文,使得當前主線程注冊成為Binder線程;隨後與Binder驅動層交互獲得請求數據交給binder_parse()方法處理。
  4. 根據不同的IPCThreadState層協議報文進行不同處理。如得到BR_TRANSACTION的IPCThreadState層協議報文,會將報文數據解析出來交由svcmgr_handler()方法處理,該方法會解析Binder層協議報文類型,如SVC_MGR_ADD_SERVICE則調用自身的do_add_service方法進行處理,方法執行結束後調用binder_write向IPCThreadState層寫入一個BC_REPLY協議報文。   下面分析一下獲取ServiceManager代理的getDefaultServiceManager方法底層實現。
 

getDefaultServiceManager方法的實現

  getDefaultServiceManager@{binder/IServiceManager.cpp} 對於一個一般的Service組件,Client首先需要通過Binder驅動程序獲得它的一個句柄值,然後才可以根據這個句柄創建一個Binder代理對象(BpBinder),最後再將這個BpBinder轉換成一個實現了特定接口的代理對象。ServiceManager句柄值為0,因此獲取ServiceManager組件就沒有獲取BpBinder的過程。
sp defaultServiceManager()
{
    if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
    {
        AutoMutex _l(gDefaultServiceManagerLock);
        if (gDefaultServiceManager == NULL) {
            gDefaultServiceManager = interface_cast(
                ProcessState::self()->getContextObject(NULL));
        }
    }
    return gDefaultServiceManager;
}
Binder庫中定義了一個gDefaultServiceManager全局變量,而且采用了單例的模式進行實現,getDefaultServiceManager方法獲得的就是該全局變量。在第一次請求該變量的時候會通過如下的方式獲取一個ServiceManager代理。interface_casr (ProcessState:self()->getContextObject(NULL));
  1. ProcessState:self()獲得的是一個ProcessState(是一個單例模式)
    • 構造器中調用open_driver方法;
      • int fd = open("/dev/binder", O_RDWR); //打開/dev/binder設備描述符,將獲取到的文件描述符存儲到ProcessState對象中的一個域中
      • result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads); //告知Binder,其最多可以請求15條線程處理進程間通信
      • mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0); //使用mmap將/dev/binder映射進進程的地址空間中,映射大小為1016KB;
      • ProcessState:self()->getContextObject(NULL)創建一個句柄為0的Binder代理(BpBinder)
        • 直接調用getStrongProxyForHandle(0) //表示要創建的Binder代理對象的句柄為0
          • getStrongProxyForHandle的操作主要有:(方法參數為int32_t handle)
            sp result;
            handle_entry* e = lookupHandleLocked(handle);
            if (e != NULL) {
                    IBinder* b = e->binder;
                    if (b == NULL || !e->refs->attemptIncWeak(this)) {
                        b = new BpBinder(handle); //創建一個BpBinder,該構造器會調用IPCThreadState::self()->incWeakHandle(handle)方法,創建了一個IPCThreadState對象
                        e->binder = b;
                        if (b) e->refs = b->getWeakRefs();
                        result = b;
                    } else {
                        result.force_set(b);
                        e->refs->decWeak(this);
                    }
                }
             return result;
          • interface_casr (const sp& obj)利用第二步得到的Binder代理構建一個ServiceManager代理
            • 等價於new BpServiceManager(obj)   getDefaultServiceManager方法調用結束後,我們首先獲得一個ProcessState對象——單列模式(該對象有打開了/dev/binder描述符,設備描述符向進程映射了一段地址空間)、通過ProcessState的getContextObject方法獲得一個句柄為0的BpBinder對象(該Binder代理構造器中創建了一個IPCThreadState對象——單例模式),最後利用BpBinder創建一個BpServiceManager對象。   getDefaultServiceManager方法讓我們獲得了一個sp對象,之後就可以調用該對象的addService、getService方法添加和獲取指定的Service代理了,下面依次介紹這兩個方法。  

              ServerManager——addService

              下面方法是用戶添加服務的方法 addService@{binder/IServiceManager.cpp}
              virtual status_t addService(const String16& name, const sp& service){
                      Parcel data, reply;
                      data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
                      data.writeString16(name);
                      data.writeStrongBinder(service);
                      status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
                      return err == NO_ERROR ? reply.readExceptionCode() : err;
              }
              前面已經介紹Remote方法獲取的是一個BpBinder對象,調用BpBinder對象的transact方法將數據和當前BpBinder對應的句柄發送給Binder驅動層處理。數據封裝成一個ADD_SERVICE_TRANSACTION的協議報文交給Binder層處理。  
BpBinder::transact()@{ binder / BpBinder.cpp}  
status_t BpBinder::transact(  uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)  //最後一個參數為0表示同步進程間請求,否則異步;默認為0
{
    if (mAlive) {
        status_t status = IPCThreadState::self()->transact(  mHandle, code, data, reply, flags); 
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }
    return DEAD_OBJECT;
}
Binder層的數據繼續包裝成一個IPCThreadState層的BC_TRANSACTION協議報文交給IPCThreadState層處理,調用IPCThreadState對象的transact方法   IPCThreadState::transact()@{ binder / IPCThreadState.cpp}  
status_t IPCThreadState::transact(int32_t handle,  uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { 
    status_t err = data.errorCheck(); //檢查數據知否正確
    flags |= TF_ACCEPT_FDS; //flag設置標志位
    if (err == NO_ERROR) {
        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL); //note1
      
    }
    if ((flags & TF_ONE_WAY) == 0) { //同步請求
        if (reply) { err = waitForResponse(reply); } 
        else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply); //等待Service的返回數據
        }
    }
    else { err = waitForResponse(NULL, NULL); } //不等待Service的返回數據
    return err;
}
1、 將BC_TRANSACTION協議報文數據寫入到binder_transaction_data結構體中。 再將該對象寫入到IPCThreadState中的一個Parcel輸出緩沖區中   IPCThreadState::waitForResponse()@{ binder / IPCThreadState.cpp}  
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult){
    int32_t cmd;
    int32_t err;
    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break; //note1
        err = mIn.errorCheck();
        if (err < NO_ERROR) break;
        if (mIn.dataAvail() == 0) continue;
       
        cmd = mIn.readInt32();  //note2
        switch (cmd) {
        case BR_TRANSACTION_COMPLETE: //note3
            if (!reply && !acquireResult) goto finish;
            break;
       
        case BR_DEAD_REPLY:
            err = DEAD_OBJECT;
            goto finish;
        case BR_FAILED_REPLY:
            err = FAILED_TRANSACTION;
            goto finish;
        case BR_ACQUIRE_RESULT:
            ```````
            goto finish;
       case BR_REPLY: { //note4
                binder_transaction_data tr;
                err = mIn.read(&tr, sizeof(tr));
                if (err != NO_ERROR) goto finish;
                if (reply) { //reply不為空則給它設值
                    if ((tr.flags & TF_STATUS_CODE) == 0) {
                        reply->ipcSetDataReference(
                            reinterpret_cast(tr.data.ptr.buffer),
                            tr.data_size,
                            reinterpret_cast(tr.data.ptr.offsets),
                            tr.offsets_size/sizeof(size_t),
                            freeBuffer, this);
                    } .....
                    }
                } else {
                    ......
                    continue;
                }
            }
            goto finish;
        default:
            err = executeCommand(cmd);
            if (err != NO_ERROR) goto finish;
            break;
        }
    }
finish:
    if (err != NO_ERROR) {
        if (acquireResult) *acquireResult = err;
        if (reply) reply->setError(err);
        mLastError = err;
    }
    return err;
}
1、與Binder驅動程序交互,將前面IPCThreadState::transact()方法中向Parcel輸出緩沖區中寫入的數據傳給Binder驅動 2、讀取Binder驅動返回的協議報文 3、收到來自Binder驅動器層的BR_TRANSACTION_COMPLETE協議報文,如果 if (!reply && !acquireResult)為真則退出giant方法,否則繼續等待下一個協議報文 4、收到來自Binder驅動器層的BR_REPLY:協議報文,讀取報文中的數據交給Parcel *reply。隨後用戶就可以讀取其中的數據了   IPCThreadState::talkWithDriver()@{ binder / IPCThreadState.cpp}
status_t IPCThreadState::talkWithDriver(bool doReceive){
    binder_write_read bwr;
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();
    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
    bwr.write_size = outAvail;
    bwr.write_buffer = (long unsigned int)mOut.data(); //即將寫入到Binder驅動的數據

    if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (long unsigned int)mIn.data(); //獲得Binder驅動返回的數據
    } else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }
    bwr.write_consumed = 0;
    bwr.read_consumed = 0;
    status_t err;
    
    ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) ///note1
    ....
}
1、將獲取到的數據封裝成一個Binder驅動層的BINDER_WRITE_READ協議報文,交給Binder啟動層處理。使用ioctl方法向Binder驅動層傳輸數據,IPCThreadState的mProcess變量的mDriverFD即/dev/driver文件描述符。   綜上addService方法首先將參數String16& name, sp包裝成一個Binder層的ADD_SERVICE_TRANSACTION協議報文,傳給Binder層處理。之後數據包裝成 IPCThreadState層的BC_TRANSACTION協議報文。最後數據又被包裝成Binder驅動層的BINDER_WRITE_READ協議報文交給Binder驅動層處理。  

ServerManager——getService

getService()@{binder/IServiceManager.cpp}
virtual sp getService(const String16& name) const {
        unsigned n;
        for (n = 0; n < 5; n++){
            sp svc = checkService(name);
            if (svc != NULL) return svc;
            sleep(1);
        }
        return NULL;
}
checkService()@{binder/IServiceManager.cpp}
virtual sp checkService( const String16& name) const{
        Parcel data, reply;
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        data.writeString16(name);
        remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
        return reply.readStrongBinder();
}
與addService方法類似,getService方法首先將參數String16& name包裝成一個Binder層的CHECK_SERVICE_TRANSACTION協議報文,傳給Binder層處理。之後數據包裝成 IPCThreadState層的BC_TRANSACTION協議報文。最後數據又被包裝成Binder驅動層的BINDER_WRITE_READ協議報文交給Binder驅動層處理。      

Service——注冊(以mediaServer為例)

main()@{ mediaserver / main_mediaserver.cpp}
int main(int argc, char** argv){
    //獲得一個ProcessState實例,前面已經介紹過
    sp proc(ProcessState::self()); 
    //得到一個ServiceManager對象,前面已經介紹過
    sp sm = defaultServiceManager(); 
    MediaPlayerService::instantiate();//note1
    ProcessState::self()->startThreadPool();//note2
    IPCThreadState::self()->joinThreadPool();//note3
}
1、MediaPlayerService實例化,該方法內部為defaultServiceManager()->addService(String16("media.player"), new MediaPlayerService())方法。service_manager收到addService的請求,然後把對應信息放到自己保存的一個服務list中。具體內容參見前面的addService說明。 2、啟動一個Binder線程池
3、將當前主線程添加到這個Binder線程池中去等待和處理Client進程的通信請求。一旦收到一個請求就調用executeCommand去處理這個命令,
startThreadPool()@{ binder / ProcessState.cpp}  
void ProcessState::startThreadPool() { 
    AutoMutex _l(mLock);
    if (!mThreadPoolStarted) {
        mThreadPoolStarted = true;
        spawnPooledThread(true);
    }
}
spawnPooledThread()@{ binder / ProcessState.cpp}
void ProcessState::spawnPooledThread(bool isMain) { 
    if (mThreadPoolStarted) {
        int32_t s = android_atomic_add(1, &mThreadPoolSeq);
        char buf[32];
        sprintf(buf, "Binder Thread #%d", s);
        sp t = new PoolThread(isMain); //創建PoolThread對象
        t->run(buf); //啟動該線程池
    }
}
joinThreadPool()@{ binder / IPCThreadState.cpp}
void IPCThreadState::joinThreadPool(bool isMain) {  //默認參數為ture
    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); //note1
    status_t result;
    do {
        int32_t cmd;
        ......
        result = talkWithDriver(); //note2
        if (result >= NO_ERROR) {
            size_t IN = mIn.dataAvail();
            if (IN < sizeof(int32_t)) continue;
            cmd = mIn.readInt32();
            result = executeCommand(cmd); //處理從Binder驅動返回回來的協議數據
        }
        ....
        if(result == TIMED_OUT && !isMain) {
            break;  
        }
    } while (result != -ECONNREFUSED && result != -EBADF);
    mOut.writeInt32(BC_EXIT_LOOPER);
    talkWithDriver(false);
}
1、形成一個BC_ENTER_LOOPER 協議報文,將報文寫入mOut的Parcel輸出緩沖區中。isMain == true表示進入到Looper,否則為注冊到Looper; 2、將mOut緩沖區中的數據傳給Binder驅動,上面我們知道這裡會將數據包裝成一個Binder驅動層的BINDER_WRITE_READ協議報文交給Binder驅動層處理 executeCommand()@{ binder / IPCThreadState.cpp}
status_t IPCThreadState::executeCommand(int32_t cmd)
{
    BBinder* obj;
    RefBase::weakref_type* refs;
    status_t result = NO_ERROR;
    switch (cmd) {
    case BR_ERROR:
        result = mIn.readInt32();
        break;
    case BR_OK: 
        break;
    case BR_ACQUIRE:
        refs = (RefBase::weakref_type*)mIn.readInt32();
        obj = (BBinder*)mIn.readInt32();
        obj->incStrong(mProcess.get());
        mOut.writeInt32(BC_ACQUIRE_DONE);
        mOut.writeInt32((int32_t)refs);
        mOut.writeInt32((int32_t)obj);
        break;
    case BR_RELEASE:
        refs = (RefBase::weakref_type*)mIn.readInt32();
        obj = (BBinder*)mIn.readInt32();
        mPendingStrongDerefs.push(obj);
        break;
    case BR_INCREFS:
        refs = (RefBase::weakref_type*)mIn.readInt32();
        obj = (BBinder*)mIn.readInt32();
        refs->incWeak(mProcess.get());
        mOut.writeInt32(BC_INCREFS_DONE);
        mOut.writeInt32((int32_t)refs);
        mOut.writeInt32((int32_t)obj);
        break;
    case BR_DECREFS:
        refs = (RefBase::weakref_type*)mIn.readInt32();
        obj = (BBinder*)mIn.readInt32();
        mPendingWeakDerefs.push(refs);
        break;
    case BR_ATTEMPT_ACQUIRE:
        refs = (RefBase::weakref_type*)mIn.readInt32();
        obj = (BBinder*)mIn.readInt32();  { 
            const bool success = refs->attemptIncStrong(mProcess.get());
            mOut.writeInt32(BC_ACQUIRE_RESULT);
            mOut.writeInt32((int32_t)success);
        }
        break;
   
    case BR_TRANSACTION:{ 
            binder_transaction_data tr;
            result = mIn.read(&tr, sizeof(tr));
            if (result != NO_ERROR) break;
            Parcel buffer;
            buffer.ipcSetDataReference(
                reinterpret_cast(tr.data.ptr.buffer),
                tr.data_size,
                reinterpret_cast(tr.data.ptr.offsets),
                tr.offsets_size/sizeof(size_t), freeBuffer, this);
            const pid_t origPid = mCallingPid;
            const uid_t origUid = mCallingUid;
            mCallingPid = tr.sender_pid;
            mCallingUid = tr.sender_euid;
            mOrigCallingUid = tr.sender_euid;
            int curPrio = getpriority(PRIO_PROCESS, mMyThreadId);
            if (gDisableBackgroundScheduling) {
                if (curPrio > ANDROID_PRIORITY_NORMAL) {
                    setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL);
                }
            } else {
                if (curPrio >= ANDROID_PRIORITY_BACKGROUND) {
                    set_sched_policy(mMyThreadId, SP_BACKGROUND);
                }
            }
            Parcel reply;
            if (tr.target.ptr) {
                sp b((BBinder*)tr.cookie);
                const status_t error = b->transact(tr.code, buffer, &reply, tr.flags); //調用BBinder的transact方法處理,實則底層就是調用具體服務的onTransact方法!
                if (error < NO_ERROR) reply.setError(error);
            } else {
                const status_t error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
                if (error < NO_ERROR) reply.setError(error);
            }
           
            if ((tr.flags & TF_ONE_WAY) == 0) {
                sendReply(reply, 0); //發送一個IPCThreadState層的BC_REPLY協議報文給Binder驅動層
            } else { }
           
            mCallingPid = origPid;
            mCallingUid = origUid;
            mOrigCallingUid = origUid;
        }
        break;
   
    case BR_DEAD_BINDER:
        {
            BpBinder *proxy = (BpBinder*)mIn.readInt32();
            proxy->sendObituary();
            mOut.writeInt32(BC_DEAD_BINDER_DONE);
            mOut.writeInt32((int32_t)proxy);
        } break;
       
    case BR_CLEAR_DEATH_NOTIFICATION_DONE:
        {
            BpBinder *proxy = (BpBinder*)mIn.readInt32();
            proxy->getWeakRefs()->decWeak(proxy);
        } break;
       
    case BR_FINISHED:
        result = TIMED_OUT;
        break;
       
    case BR_NOOP:
        break;
       
    case BR_SPAWN_LOOPER:
        mProcess->spawnPooledThread(false);
        break;
       
    default:
        result = UNKNOWN_ERROR;
        break;
    }
    if (result != NO_ERROR) {
        mLastError = result;
    }
    return result;
}
BBinder::transact()
status_t BBinder::transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { 
   err = onTransact(code, data, reply, flags); //就是調用自己的onTransact函數嘛      
   return err; 
}
sendReply()@{ binder / IPCThreadState.cpp}
status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags)
{
    status_t err;
    status_t statusBuffer;
    err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);
    if (err < NO_ERROR) return err;
    return waitForResponse(NULL, NULL);
}
Service注冊:
  1. 創建一個ProcessState對象,該對象會打開文件描述符和在當前進程給/dev/binder設備描述符映射一個塊空間。
  2. 利用ProcessState的getContextObject(NULL)方法獲取一個句柄為0的IBinder對象,該IBinder對象的創建過程中會創建一個IPCThreadState對象。
  3. 利用IBinder對象創建一個IServerManager對象。
  4. 創建一個當前服務的實例,並調用IServerManager的addService方法,將自己注冊到ServiceMaanger列表中。addService的過程是一個"Client端通信流程",具體後文還會再講
  5. 啟動一個Binder線程池和並將當前主線程加入到Binder線程池中,最終進入到“Server端通信流程” Service循環: IPCThreadState的joinThreadPool方法開啟了一個循環,不斷與Binder驅動進行通信,當獲取到信息就調用executeCommand( cmd )方法對消息進行處理。比如cmd為BR_TRANSACTION,即表明是Binder發送過來的期望Service處理的數據,首先從得到的數據中得到sp對象,隨後調用該對象的transact方法,方法內部會調用BBinder綁定的Service(其實就是當前Service)的onTransact的方法進行處理,處理過後將結果以BC_REPLY協議報文返回Binder,然後調用waitForResponse方法等待Binder返回一個BR_TRANSACTION_COMPLETED協議報文,最後結束這一次的服務。
注意:startThreadPool和joinThreadPool完後確實有兩個線程,主線程和工作線程,而且都在做消息循環。為什麼要這麼做呢?他們參數isMain都是true。不知道google搞什麼。難道是怕一個線程工作量太多,所以搞兩個線程來工作?這種解釋應該也是合理的。網上有人測試過把最後一句屏蔽掉,也能正常工作。但是難道主線程提出了,程序還能不退出嗎?這個...管它的,反正知道有兩個線程在那處理就行了。    

Client景分析(以mediaServer為例)

使用MediaPlayerService的時候,先要創建它的BpMediaPlayerService,一個描述了實現IMediePlayService接口的組件。 defaultServiceManager()->getService(String16(MEDIA_SERVICE));該方法在前面的ServiceManager已經介紹過了,獲得了一個IBinder對象。之後又利用該IBinder包裝成一個IServiceManager對象。當我們調用IServiceManager的一個方法的時候實則調用IBinder的transact方法,首先寫入Binder層的協議報文再通過調用IPCThreadState的transact方法處理,IPCThreadState又會將報文加一個文件頭如BC_TRANSACTION頭,通過ioctl發送到Binder驅動程序,Binder將該報文發給對應的服務端的時候就會返回一個BR_TRANSACTION_COMPLETED協議,Client繼續等待直到Binder發送BR_REPLY,這時候CLIEN讀取該協議的數據返回Client用戶空間,這樣一次進程間通信就結束了。  

總結:

雖然說這是Binder機制——初探,但是內容一點也不少,不過這真的只是Binder的冰山一角。本文只是在open、mmap、ioctl基礎之上對Binder機制進行分析,而對於具體的binder驅動層沒有進行介紹。想了解Binder機制還是需要有一個切入點比較好,如果你還很迷茫不知道何從下手,那麼個人建議按照ServiceManager的注冊、具體Service的注冊、Client對Service的訪問三個步驟來了解Binder機制。 而針對上面的三個步驟又可以細分如下
  • ServiceManager注冊:binder_open() 、binder_become_context_manager() 、binder_loop(){該部分細分:ioctl()、 ioctl、binder_parse}
  • Service注冊:getDefaultServiceManager(){底層實現細分:ProcessState、IPCThreadState、BpBinder、BpServiceManager}、addService(){底層在進程間通信時分析} 、Binder線程池、 IPCThreadState線程注冊為Biinder線程並進入循環{該部分細分: talkWithDriver、executeCommand}
  • Client對Service的訪問:getDefaultServiceManager()、getService(){底層在進程間通信時分析}、進程間通信{該部分細分如下: BpBinder.transact() 、IPCThreadState.transact() 、 IPCThreadState.waitForResponse(){該部分細分: IPCThreadState.talkWithDriver() 、等待Binder驅動層返回協議報文}}
 

附錄一:binder驅動層

binder_ioctl@{ android / binder.c}
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    int ret;
    struct binder_proc *proc = filp->private_data;
    struct binder_thread *thread;
    unsigned int size = _IOC_SIZE(cmd);
    void __user *ubuf = (void __user *)arg;
    trace_binder_ioctl(cmd, arg);
    ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
    if (ret)
        goto err_unlocked;
    binder_lock(__func__);
    thread = binder_get_thread(proc);
    if (thread == NULL) {
        ret = -ENOMEM;
        goto err;
    }
    switch (cmd) {
    case BINDER_WRITE_READ: {
        struct binder_write_read bwr;
        if (size != sizeof(struct binder_write_read)) {
            ret = -EINVAL;
            goto err;
        }
        if (copy_from_user(&bwr, ubuf, sizeof(bwr))) { //獲取用戶態的binder_write_read對象
            ret = -EFAULT;
            goto err;
        }
        if (bwr.write_size > 0) {//如果輸入緩沖區長度大於0則調用binder_thread_write方法
            ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed); 
            trace_binder_write_done(ret);
            if (ret < 0) {
                bwr.read_consumed = 0;
                if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
                    ret = -EFAULT;
                goto err;
            }
        }
        if (bwr.read_size > 0) {//如果輸出緩沖區長度大於0則調用binder_thread_read方法
            ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
            trace_binder_read_done(ret);
            if (!list_empty(&proc->todo))
                wake_up_interruptible(&proc->wait);
            if (ret < 0) {
                if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
                    ret = -EFAULT;
                goto err;
            }
        }
        if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
            ret = -EFAULT;
            goto err;
        }
        break;
    }
    case BINDER_SET_MAX_THREADS:
        if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {
            ret = -EINVAL;
            goto err;
        }
        break;
    case BINDER_SET_CONTEXT_MGR:
        if (binder_context_mgr_node != NULL) {
            printk(KERN_ERR "binder: BINDER_SET_CONTEXT_MGR already set\n");
            ret = -EBUSY;
            goto err;
        }
        ret = security_binder_set_context_mgr(proc->tsk);
        if (ret < 0)
            goto err;
        if (binder_context_mgr_uid != -1) {
            if (binder_context_mgr_uid != current->cred->euid) {
                printk(KERN_ERR "binder: BINDER_SET_"
                       "CONTEXT_MGR bad uid %d != %d\n",
                       current->cred->euid,
                       binder_context_mgr_uid);
                ret = -EPERM;
                goto err;
            }
        } else
            binder_context_mgr_uid = current->cred->euid;
        binder_context_mgr_node = binder_new_node(proc, NULL, NULL);
        if (binder_context_mgr_node == NULL) {
            ret = -ENOMEM;
            goto err;
        }
        binder_context_mgr_node->local_weak_refs++;
        binder_context_mgr_node->local_strong_refs++;
        binder_context_mgr_node->has_strong_ref = 1;
        binder_context_mgr_node->has_weak_ref = 1;
        break;
    case BINDER_THREAD_EXIT:
        binder_debug(BINDER_DEBUG_THREADS, "binder: %d:%d exit\n",
                 proc->pid, thread->pid);
        binder_free_thread(proc, thread);
        thread = NULL;
        break;
    case BINDER_VERSION:
        if (size != sizeof(struct binder_version)) {
            ret = -EINVAL;
            goto err;
        }
        if (put_user(BINDER_CURRENT_PROTOCOL_VERSION, &((struct binder_version *)ubuf)->protocol_version)) {
            ret = -EINVAL;
            goto err;
        }
        break;
    default:
        ret = -EINVAL;
        goto err;
    }
    ret = 0;
err:
    if (thread)
        thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
    binder_unlock(__func__);
    wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
    if (ret && ret != -ERESTARTSYS)
        printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
err_unlocked:
    trace_binder_ioctl_done(ret);
    return ret;
}

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved