1. 程式人生 > >Binder原始碼分析之ServiceManager(原)

Binder原始碼分析之ServiceManager(原)

        ServiceManager作為Native層Service的管理員,有著極其重要的作用,主要表現兩個方面:
        1、對於服務端來說,系統所有的服務提供者都需要向ServiceManager註冊。
        2、對於客戶端來說,所有客戶端如果想要獲得某個系統服務的代理,必須向ServiceManager申請相應的服務端代理。

        下面從原始碼分析ServiceManager的啟動流程和服務流程。

    @Service_manager.c(frameworks/base/cmds/servicemanager)
    int main(int argc, char **argv) {
        struct binder_state *bs;
        void *svcmgr = BINDER_SERVICE_MANAGER;
        //開啟binder裝置
        bs = binder_open
(128*1024); //成為Service manager if (binder_become_context_manager(bs)) { LOGE("cannot become context manager (%s)\n", strerror(errno)); return -1; } svcmgr_handle = svcmgr; //在binder_loop中迴圈檢測binder中是否有新的請求 binder_loop(bs, svcmgr_handler); return 0; }
        main函式主要有三個功能:
        1、開啟Binder裝置檔案;
        2、告訴Binder驅動程式自己是Binder上下文管理者;
        3、進入一個死迴圈,充當Service的角色,等待Client的請求。

        下面我們就分別介紹這三個步驟。

一、開啟Binder裝置

    @binder.c(\frameworks\base\cmds\servicemanager\)
    struct binder_state *binder_open(unsigned mapsize) {
        //建立binder_state結構體並分配記憶體
        struct binder_state *bs;
        bs = malloc(sizeof(*bs));
        //開啟binder裝置
        bs->fd = open("/dev/binder", O_RDWR);
        bs->mapsize = mapsize;
        //將binder物理空間對映為ServiceManager可用的虛擬空間
        bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
        //將結構體返回給servicemanager
        return bs;
    }
        上面開啟Binder裝置的過程其實就是構建一個binder_state結構體物件,然後對其各個成員初始化的過程。我們來看一下binder_state資料結構:
    struct binder_state {
        //檔案描述符,這裡指的是/dev/binder裝置檔案描述符
        int fd;
        //把裝置檔案/dev/binder對映到程序空間的起始地址,這裡就是128*1024
        void *mapped;
        //對映的空間大小
        unsigned mapsize;
    };
        這個結構體只有三個成員變數,其中fd是底層binder裝置的檔案描述符,mapped是ServiceManager得到的虛擬空間地址,這塊虛擬空間映射了底層binder的實體地址,而mapsize是這塊虛擬空間的大小,也就是128*1024。
        從上面可以看出,開啟Binder的過程的過程分為兩步:
        1、開啟Binder裝置;

        2、用Binder的實體地址對映為ServiceManager可用的虛擬地址;

二、ServiceManager成為服務管理員的過程

        在Android中,每個註冊的Service,Binder都會給他分配一個唯一的int型的控制代碼,Client可以用該控制代碼向ServiceManager請求相應的Service,而負責這個管理任務的正是ServiceManager。也就是說,Service需要先向ServiceManager註冊自己,並得到自己的服務控制代碼,然後Client需要拿這個int型的控制代碼向ServiceManager請求相應的Service,ServiceManager再把相應的Service代理物件傳送給Client使用
        同時我們注意到,ServiceManager本身也是一個Service,他需要先向Binder註冊自己,而且要把自己註冊為“管理員”,那麼這個註冊過程是怎樣的呢?我們來看原始碼:
    int binder_become_context_manager(struct binder_state *bs)
    {
        //向Binder驅動傳送BINDER_SET_CONTEXT_MGR的訊息
        return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
    }

    我們看到,當ServiceManager向Binder驅動傳送BINDER_SET_CONTEXT_MGR的訊息時,Binder就會把他註冊為“管理員”

三、Service_manager服務過程

3.1、Service_manager的執行流程

        經過前面兩步的操作,我們不僅打開了Binder,而且把當前的ServiceManager註冊成為了管理員,下面要做的就是去承擔管理員的職責,也就是接收各種請求
        這一步的入口是binder_loop():
    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,ServiceManager將要進入LOOPER狀態了
        binder_write(bs, readbuf, sizeof(unsigned));

        for (;;) {
            //準備要傳送的資料
            bwr.read_size = sizeof(readbuf);
            bwr.read_consumed = 0;
            bwr.read_buffer = (unsigned) readbuf;
            //與底層Binder通訊,得到客戶端的請求
            res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
            //用func解析請求並構建應答返回給客戶端
            res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);
        }
    }
        上面的過程表明了Service_manager進入迴圈的過程,主要分為三個步驟:
        1、先通過傳送BC_ENTER_LOOPER訊息告訴底層,ServiceManager將要進入迴圈了;
        2、在死迴圈中讀取客戶端的請求;
        3、處理請求;

        上面的第一步是通過向Binder傳送BC_ENTER_LOOPER訊息實現的,第二步通過BINDER_WRITE_READ可以讀取Binder中的資料(請求);第三步需要呼叫binder_parse去處理客戶端的請求,我們主要看一下這個過程。

3.2、ServiceManager處理請求並回應客戶端的過程

        ServiceManager是通過binder_parse()的函式來處理請求的:
    int binder_parse(struct binder_state *bs,struct binder_io *bio,uint32_t *ptr,uint32_t size,binder_handler func){
        while (ptr < end) {
            uint32_t cmd = *ptr++;
            switch(cmd) {
                case BR_NOOP:
                case BR_TRANSACTION_COMPLETE:
                case BR_INCREFS:
                case BR_ACQUIRE:
                case BR_RELEASE:
                case BR_DECREFS:
                    break;
                case BR_TRANSACTION: {
                    struct binder_txn *txn = (void *) ptr;
                    binder_dump_txn(txn);
                    if (func) {
                        unsigned rdata[256/4];
                        struct binder_io msg;
                        struct binder_io reply;
                        bio_init(&reply, rdata, sizeof(rdata), 4);
                        bio_init_from_txn(&msg, txn);
                        //呼叫service_manager.c中的svcmgr_handler去處理資料
                        res = func(bs, txn, &msg, &reply);
                        //將Service_manager對客戶端的迴應資料(reply)返回給Binder驅動
                        binder_send_reply(bs, &reply, txn->data, res);
                    }
                    ptr += sizeof(*txn) / sizeof(uint32_t);
                    break;
                }
                case BR_REPLY: 
                case BR_DEAD_BINDER: 
                case BR_FAILED_REPLY:
                case BR_DEAD_REPLY:
                default:
            }
        }
        return r;
    }
        這個函式中我們只關心BR_TRANSACTION分支,通過呼叫func去解析拿到的請求,然後把返回值作為迴應通過binder_send_reply()函式返回給客戶端。

3.2.1、處理請求過程

        我們先來看一下請求的處理過程,也就是func()的流程,這裡的func來自於呼叫binder_loop()時的引數:
    binder_loop(bs, svcmgr_handler);
        因此func()就是svcmgr_handler():
    int svcmgr_handler(struct binder_state *bs,struct binder_txn *txn,struct binder_io *msg,struct binder_io *reply){
        switch(txn->code) {
            case SVC_MGR_GET_SERVICE:
            case SVC_MGR_CHECK_SERVICE:
                //得到一個Service
                s = bio_get_string16(msg, &len);
                ptr = do_find_service(bs, s, len, txn->sender_euid);
                bio_put_ref(reply, ptr);
                return 0;

            case SVC_MGR_ADD_SERVICE:
                //新增一個Service
                s = bio_get_string16(msg, &len);
                ptr = bio_get_ref(msg);
                allow_isolated = bio_get_uint32(msg) ? 1 : 0;
                if (do_add_service(bs, s, len, ptr, txn->sender_euid, allow_isolated))
                    return -1;
                break;

            case SVC_MGR_LIST_SERVICES: {
                //得到當前所有的Service
                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;
            }
        }
        return 0;
    }
        從svcmgr_handler的case分支我們可以看出,作為Service_manager主要完成三個功能:
        1、得到一個Service;
        2、新增一個Service;
        3、列出所有的Service;

        下面我們分別看一下這三個功能的實現方式,我們先從add一個Service開始:
    int do_add_service(struct binder_state *bs,uint16_t *s,unsigned len,void *ptr,unsigned uid,int allow_isolated) {
        struct svcinfo *si;
        //檢查當前註冊的Service的uid和註冊的服務名稱是否有許可權
        if (!svc_can_register(uid, s)) {
            return -1;
        }
        //檢視是否已經add過了
        si = find_svc(s, len);
        if (si) {
            if (si->ptr) {
                svcinfo_death(bs, si);
            }
            si->ptr = ptr;
        } else {
            si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
            si->ptr = ptr;
            si->len = len;
            memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
            si->name[len] = '\0';
            si->death.func = svcinfo_death;
            si->death.ptr = si;
            si->allow_isolated = allow_isolated;
            si->next = svclist;
            //把當前需要註冊的Service新增到svclist中,完成註冊過程
            svclist = si;
        }
    }
        從add的過程可以看出,所謂向ServiceManager註冊一個服務,其實就是為當前的Service建立svcinfo的結構體,並把該結構體新增到svclist中
        那麼我們可以推測,find的過程無非就是去svclist中查詢svcinfo的過程:
    void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len, unsigned uid) {
        struct svcinfo *si;
        //從svclist連結串列中得到當前請求的Service資訊
        si = find_svc(s, len);
        if (si && si->ptr) {
            //得到一個Service需要這個Service的許可
            if (!si->allow_isolated) {
                //還要檢查申請者的uid是否匹配
                unsigned appid = uid % AID_USER;
                if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
                    return 0;
                }
            }
            return si->ptr;
        } else {
            return 0;
        }
    }
        這個過程確實如我們所料,需要通過find_svc()在svclist中尋找需要的Service並把該Service節點發送給請求的Client。
        那麼list Service的請求只需要把svclist返回給Client即可:
    case SVC_MGR_LIST_SERVICES: {
        unsigned n = bio_get_uint32(msg);

        si = svclist;
        while ((n-- > 0) && si)
            si = si->next;
        if (si) {
            //把svclist返回給請求者
            bio_put_string16(reply, si->name);
            return 0;
        }
        return -1;
    }
        經過這些過程,ServiceManager就完成了解析資料的過程,下面就需要把相應的資料返回給客戶端。

3.2.2、迴應客戶端的過程

        在3.2.1中的三個請求處理過程中,特別是get和list Service的請求,最終都需要給客戶端相應迴應的,我們看到在這兩個請求的處理最後,都將相應的迴應資料放入了reply的指標中,當從svcmgr_handler()返回後,就把資料帶到了binder_parse()中,我們再來回顧一下這裡的程式碼:
    int binder_parse(struct binder_state *bs,struct binder_io *bio,uint32_t *ptr,uint32_t size,binder_handler func){
        while (ptr < end) {
            switch(cmd) {
                case BR_TRANSACTION: {
                    struct binder_txn *txn = (void *) ptr;
                    binder_dump_txn(txn);
                    if (func) {
                        //reply就是svcmgr_handler()中得到的迴應
                        res = func(bs, txn, &msg, &reply);
                        //將回應資料(reply)返回給Binder驅動
                        binder_send_reply(bs, &reply, txn->data, res);
                    }
                    ptr += sizeof(*txn) / sizeof(uint32_t);
                    break;
                }
            }
        }
        return r;
    }
        在binder_parse()中又呼叫binder_send_reply()函式完成迴應的操作:
    void binder_send_reply(struct binder_state *bs, struct binder_io *reply, void *buffer_to_free, int status) {
        struct {
            uint32_t cmd_free;
            void *buffer;
            uint32_t cmd_reply;
            struct binder_txn txn;
        } __attribute__((packed)) data;

        data.cmd_free = BC_FREE_BUFFER;
        data.buffer = buffer_to_free;
        data.cmd_reply = BC_REPLY;
        data.txn.target = 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.offs_size = 0;
            data.txn.data = &status;
            data.txn.offs = 0;
        } else {
            data.txn.flags = 0;
            data.txn.data_size = reply->data - reply->data0;
            data.txn.offs_size = ((char*) reply->offs) - ((char*) reply->offs0);
            data.txn.data = reply->data0;
            data.txn.offs = reply->offs0;
        }
        //向Binder寫回應的資料
        binder_write(bs, &data, sizeof(data));
    }
        在給Binder傳送返回值時,構建了data的資料,並把reply放入其中,並標記了資料的大小,最後通過binder_write()函式將資料寫到Binder中,而且寫的方法仍然是呼叫ioctl()。
    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;
        //向Binder寫資料
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
        if (res < 0) {
            fprintf(stderr,"binder_write: ioctl failed (%s)\n", strerror(errno));
        }
        return res;
    }

        經過以上步驟,就完成了一次完整的請求呼叫過程。

四、總結

        我們用兩張圖來總結ServiceManager提供服務的過程。

4.1、ServiceManager初始化流程

4.2、ServiceManager處理事務的流程