zoukankan      html  css  js  c++  java
  • Android : 跟我学Binder --- (3) C程序示例


    目录:

    一、Binder框架分析

      1、IPC、LPC和RPC的概念:

        IPC:  (Inter Process Communication )跨进程通信,泛指进程之间任何形式的通信行为,它不仅包括各种形式的消息传递,还可以指共享资源,以及同步对象;

        LPC: Local Procedure Call 本地过程调用,用在多任务操作系统中,使得同时运行的任务能互相会话。这些任务共享内存空间使任务同步和互相发送信息;(IPC的封装)

        RPC:(Reomote Procedure Call )远程过程调用,类似于LPC,只是在网上工作。RPC开始是出现在Sun微系统公司和HP公司的运行UNIX操作系统的计算机中;

      2、通信架构:

        Client/Server <---> service manager 交互流程:

          server ---------addservice-------> service manager

          client  ---------getservice--------> service manager

     注:ServiceManager首先向binder驱动注册为服务管理者,handle为0;

      3、简析示例代码(非完整流程)

    ①android_5.0.2_32frameworks ativecmdsservicemanagerservice_manager.c  //管理server注册的服务(进程)

        a. binder_open  //打开驱动
        b. binder_become_context_manager //告诉驱动注册为service manager
        c. binder_loop(bs, svcmgr_handler);
           c.1 res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);  //读数据
           c.2 binder_parse // 解析数据
        
              /*处理数据  : svcmgr_handler*/
                         SVC_MGR_GET_SERVICE/SVC_MGR_CHECK_SERVICE : 获取服务
                         SVC_MGR_ADD_SERVICE : 注册服务
              /*有必要则回复数据*/  
                 .......

    android_5.0.2_32frameworks ativecmdsservicemanagerctest.c  //client测试代码

       注册服务的过程:
        a. binder_open  //打开驱动
        b. svcmgr_publish  //构造数据   
        c. binder_call(bs, &msg, &reply, 0, SVC_MGR_ADD_SERVICE)
                           // 含有服务的名字
                                 // 它会含有servicemanager回复的数据
                                         // 0表示servicemanager
                                            // code: 表示要调用servicemanager中的"addservice函数"
    
      获取服务的过程:
        a. binder_open //打开驱动
        
    b. svcmgr_lookup //构造数据
        
    c. binder_call(bs,
    &msg, &reply, 0, SVC_MGR_CHECK_SERVICE)      // 含有服务的名字     // 它会含有servicemanager回复的数据, 表示提供服务的进程     // 0表示servicemanager      // code: 表示要调用servicemanager中的"getservice函数

     

    android_5.0.2_32frameworks ativecmdsservicemanagerinder.c  //封装好的C函数

    (1)构造参数:放在一个buffer用binder_io来描述;

       unsigned iodata[512/4]; //用binder_io来管理这个缓冲区
        struct binder_io msg, reply;
    ...
        bio_init(&msg, iodata, sizeof(iodata), 4); //初始化binder_io对象
    
      /*可以放入各类型参数,反之通过get方法获取*/
        bio_put_uint32(&msg, 0);  // strict mode header
        bio_put_string16_x(&msg, SVC_MGR_NAME); 
        bio_put_string16_x(&msg, name);
        bio_put_obj(&msg, ptr);
    ...
    
    /*调用binder_call(struct binder_state *bs,
              struct binder_io *msg/*提供参数*/, 
              struct binder_io *reply/*获得回复*/,
              uint32_t target/*发送对象*/,
              uint32_t code/*调用函数*/)*/
    
        if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE))
            return -1;

    (2)根据 binder_io、targetcode 构造writebuf:

        struct binder_write_read bwr;
        struct {
            uint32_t cmd;
            struct binder_transaction_data txn;
        } __attribute__((packed)) writebuf;
        unsigned readbuf[32];
    ....
    
        writebuf.cmd = BC_TRANSACTION;
        writebuf.txn.target.handle = target;
        writebuf.txn.code = code;
        writebuf.txn.flags = 0;
        writebuf.txn.data_size = msg->data - msg->data0;
        writebuf.txn.offsets_size = ((char*) msg->offs) - ((char*) msg->offs0);
        writebuf.txn.data.ptr.buffer = (uintptr_t)msg->data0;
        writebuf.txn.data.ptr.offsets = (uintptr_t)msg->offs0;
    
        bwr.write_size = sizeof(writebuf);
        bwr.write_consumed = 0;
        bwr.write_buffer = (uintptr_t) &writebuf;

      其中binder_write_read 结构体在内核代码中的定义:

    struct binder_write_read {
        signed long    write_size;    /* bytes to write */
        signed long    write_consumed;    /* bytes consumed by driver */
        unsigned long    write_buffer;
        signed long    read_size;    /* bytes to read */
        signed long    read_consumed;    /* bytes consumed by driver */
        unsigned long    read_buffer;
    };

      其中binder_transaction_data结构体在内核代码中的定义:

    struct binder_transaction_data {
        /* The first two are only used for bcTRANSACTION and brTRANSACTION,
         * identifying the target and contents of the transaction.
         */
        union {
            size_t    handle;    /* target descriptor of command transaction */
            void    *ptr;    /* target descriptor of return transaction */
        } target;
        void        *cookie;    /* target object cookie */
        unsigned int    code;        /* transaction command */
    
        /* General information about the transaction. */
        unsigned int    flags;
        pid_t        sender_pid;
        uid_t        sender_euid;
        size_t        data_size;    /* number of bytes of data */
        size_t        offsets_size;    /* number of bytes of offsets */
    
        /* If this transaction is inline, the data immediately
         * follows here; otherwise, it ends with a pointer to
         * the data buffer.
         */
        union {
            struct {
                /* transaction data */
                const void    *buffer;
                /* offsets from buffer to flat_binder_object structs */
                const void    *offsets;
            } ptr;
            uint8_t    buf[8];
        } data;
    };

    (3)通过ioctl发送数据:

        for (;;) {
            bwr.read_size = sizeof(readbuf);
            bwr.read_consumed = 0;
            bwr.read_buffer = (uintptr_t) readbuf;
    
            res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
    
            if (res < 0) {
                fprintf(stderr,"binder: ioctl failed (%s)
    ", strerror(errno));
                goto fail;
            }
    
            res = binder_parse(bs, reply, (uintptr_t) readbuf, bwr.read_consumed, 0); //解析返回的数据
            if (res == 0) return 0;
            if (res < 0) goto fail;
        }

    框架流程总结:

      client端: binder_open ---> 获得服务handle ---> 构造参数binder_io ---> 调用binder_call ---> 解析返回的binder_io;

      server端:binder_open ---> 注册服务 ---> ioctl读取数据(binder_write_read )---> 解析数据(binder_transaction_data ) ---> 获得binder_io并根据code调用对应函数 ---> 把返回值发送给client;

     

    二、编写程序

      1.参考service_manager.c编写test_server.c添加服务:

    /* Copyright 2008 The Android Open Source Project
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <linux/types.h>
    #include<stdbool.h>
    #include <string.h>
    
    #include <private/android_filesystem_config.h>
    
    #include "binder.h"
    #include "test_server.h"
    
    int svcmgr_publish(struct binder_state *bs, uint32_t target, const char *name, void *ptr)
    {
        int status;
        unsigned iodata[512/4];
        struct binder_io msg, reply;
    
        bio_init(&msg, iodata, sizeof(iodata), 4);
        bio_put_uint32(&msg, 0);  // strict mode header
        bio_put_string16_x(&msg, SVC_MGR_NAME);
        bio_put_string16_x(&msg, name);
        bio_put_obj(&msg, ptr);
    
        if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE))
            return -1;
    
        status = bio_get_uint32(&reply);
    
        binder_done(bs, &msg, &reply);
    
        return status;
    }
    
    void sayhello(void)
    {
        static int cnt = 0;
        fprintf(stderr, "say hello : %d
    ", ++cnt);
    }
    
    
    int sayhello_to(char *name)
    {
        static int cnt = 0;
        fprintf(stderr, "say hello to %s : %d
    ", name, ++cnt);
        return cnt;
    }
    
    void saygoodbye(void)
    {
        static int cnt = 0;
        fprintf(stderr, "say goodbye : %d
    ", ++cnt);
    }
    
    
    int saygoodbye_to(char *name)
    {
        static int cnt = 0;
        fprintf(stderr, "say goodbye to %s : %d
    ", name, ++cnt);
        return cnt;
    }
    
    
    int hello_service_handler(struct binder_state *bs,
                       struct binder_transaction_data *txn,
                       struct binder_io *msg,
                       struct binder_io *reply)
    {
        /* 根据txn->code知道要调用哪一个函数
         * 如果需要参数, 可以从msg取出
         * 如果要返回结果, 可以把结果放入reply
         */
    
        /* sayhello
         * sayhello_to
         */
        
        uint16_t *s;
        char name[512];
        size_t len;
        uint32_t handle;
        uint32_t strict_policy;
        int i;
    
    
        // Equivalent to Parcel::enforceInterface(), reading the RPC
        // header with the strict mode policy mask and the interface name.
        // Note that we ignore the strict_policy and don't propagate it
        // further (since we do no outbound RPCs anyway).
        strict_policy = bio_get_uint32(msg); // 取出0,后面才是传过来的所需数据
    
    
        switch(txn->code) {
        case HELLO_SVR_CMD_SAYHELLO:
            sayhello();
            bio_put_uint32(reply, 0); /* no exception */
            return 0;
    
        case HELLO_SVR_CMD_SAYHELLO_TO:
            /* 从msg里取出字符串(16位转8位) */
            s = bio_get_string16(msg, &len);  //"IHelloService"
            s = bio_get_string16(msg, &len);  // name
            if (s == NULL) {
                return -1;
            }
            for (i = 0; i < len; i++)
                name[i] = s[i];
            name[i] = '';
    
            /* 处理 */
            i = sayhello_to(name);
    
            /* 把结果放入reply */
            bio_put_uint32(reply, 0); /* no exception */
            bio_put_uint32(reply, i);
            
            break;
    
        default:
            fprintf(stderr, "unknown code %d
    ", txn->code);
            return -1;
        }
    
        return 0;
    }
    
    
    
    int goodbye_service_handler(struct binder_state *bs,
                       struct binder_transaction_data *txn,
                       struct binder_io *msg,
                       struct binder_io *reply)
    {
        /* 根据txn->code知道要调用哪一个函数
         * 如果需要参数, 可以从msg取出
         * 如果要返回结果, 可以把结果放入reply
         */
    
        /* sayhello
         * sayhello_to
         */
        
        uint16_t *s;
        char name[512];
        size_t len;
        uint32_t handle;
        uint32_t strict_policy;
        int i;
    
    
        // Equivalent to Parcel::enforceInterface(), reading the RPC
        // header with the strict mode policy mask and the interface name.
        // Note that we ignore the strict_policy and don't propagate it
        // further (since we do no outbound RPCs anyway).
        strict_policy = bio_get_uint32(msg);
    
    
        switch(txn->code) {
        case GOODBYE_SVR_CMD_SAYGOODBYE:
            saygoodbye();
            bio_put_uint32(reply, 0); /* no exception */
            return 0;
    
        case GOODBYE_SVR_CMD_SAYGOODBYE_TO:
            /* 从msg里取出字符串(16位转8位) */
            s = bio_get_string16(msg, &len);  //"IGoodbyeService"
            s = bio_get_string16(msg, &len);  // name
            if (s == NULL) {
                return -1;
            }
            for (i = 0; i < len; i++)
                name[i] = s[i];
            name[i] = '';
    
            /* 处理 */
            i = saygoodbye_to(name);
    
            /* 把结果放入reply */
            bio_put_uint32(reply, 0); /* no exception */
            bio_put_uint32(reply, i);
            
            break;
    
        default:
            fprintf(stderr, "unknown code %d
    ", txn->code);
            return -1;
        }
    
        return 0;
    }
    
    
    int test_server_handler(struct binder_state *bs,
                       struct binder_transaction_data *txn,
                       struct binder_io *msg,
                       struct binder_io *reply)
    {
        int (*handler)(struct binder_state *bs,
                       struct binder_transaction_data *txn,
                       struct binder_io *msg,
                       struct binder_io *reply);
    
        handler = (int (*)(struct binder_state *bs,
                       struct binder_transaction_data *txn,
                       struct binder_io *msg,
                       struct binder_io *reply))txn->target.ptr;
        
        return handler(bs, txn, msg, reply);
    }
    
    int main(int argc, char **argv)
    {
        int fd;
        struct binder_state *bs;
        uint32_t svcmgr = BINDER_SERVICE_MANAGER;
        uint32_t handle;
        int ret;
    
        bs = binder_open(128*1024);
        if (!bs) {
            fprintf(stderr, "failed to open binder driver
    ");
            return -1;
        }
    
        /* add service */
        ret = svcmgr_publish(bs, svcmgr, "hello", hello_service_handler); //第三个参数值需要唯一,obj->binder = (uintptr_t)ptr;
        if (ret) {
            fprintf(stderr, "failed to publish hello service
    ");
            return -1;
        }
        ret = svcmgr_publish(bs, svcmgr, "goodbye", goodbye_service_handler);
        if (ret) {
            fprintf(stderr, "failed to publish goodbye service
    ");
        }
    
        binder_set_maxthreads(bs, 10);
        
        /* //binder_loop已封装如下步骤:
        while (1)
        {
            /* read data */
            /* parse data, and process */
            /* reply */
        }
        */
        binder_loop(bs, test_server_handler); //通过函数test_server_handler处理消息
    
        return 0;
    }

    test_server.h :

    #ifndef _TEST_SERVER_H
    #define _TEST_SERVER_H
    
    #define HELLO_SVR_CMD_SAYHELLO     1
    #define HELLO_SVR_CMD_SAYHELLO_TO  2
    
    #define GOODBYE_SVR_CMD_SAYGOODBYE     1
    #define GOODBYE_SVR_CMD_SAYGOODBYE_TO  2
    
    #endif // _TEST_SERVER_H

        2.编写test_client.c获得/使用服务:

    /* Copyright 2008 The Android Open Source Project
     */
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <errno.h>
    #include <linux/types.h>
    #include<stdbool.h>
    #include <string.h>
    
    #include <private/android_filesystem_config.h>
    
    #include "binder.h"
    #include "test_server.h"
    
    
    
    uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name)
    {
        uint32_t handle;
        unsigned iodata[512/4];
        struct binder_io msg, reply;
    
        bio_init(&msg, iodata, sizeof(iodata), 4);
        bio_put_uint32(&msg, 0);  // strict mode header
        bio_put_string16_x(&msg, SVC_MGR_NAME);
        bio_put_string16_x(&msg, name);
    
        if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE))
            return 0;
    
        handle = bio_get_ref(&reply);
    
        if (handle)
            binder_acquire(bs, handle);
    
        binder_done(bs, &msg, &reply);
    
        return handle;
    }
    
    
    struct binder_state *g_bs;
    uint32_t g_hello_handle;
    uint32_t g_goodbye_handle;
    
    void sayhello(void)
    {
        unsigned iodata[512/4];
        struct binder_io msg, reply;
    
        /* 构造binder_io */
        bio_init(&msg, iodata, sizeof(iodata), 4);
        bio_put_uint32(&msg, 0);  // strict mode header ,传入0
        bio_put_string16_x(&msg, "IHelloService");
    
        /* 放入参数 */
    
        /* 调用binder_call */
        if (binder_call(g_bs, &msg, &reply, g_hello_handle, HELLO_SVR_CMD_SAYHELLO))
            return ;
        
        /* 从reply中解析出返回值 */
    
        binder_done(g_bs, &msg, &reply);
        
    }
    
    /*
    *带参数
    */
    int sayhello_to(char *name)
    {
        unsigned iodata[512/4];
        struct binder_io msg, reply;
        int ret;
        int exception;
    
        /* 构造binder_io */
        bio_init(&msg, iodata, sizeof(iodata), 4);
        bio_put_uint32(&msg, 0);  // strict mode header
        bio_put_string16_x(&msg, "IHelloService");
    
        /* 放入参数 */
        bio_put_string16_x(&msg, name);
    
        /* 调用binder_call */
        if (binder_call(g_bs, &msg, &reply, g_hello_handle, HELLO_SVR_CMD_SAYHELLO_TO))
            return 0;
        
        /* 从reply中解析出返回值 */
        exception = bio_get_uint32(&reply);
        if (exception)
            ret = -1;
        else
            ret = bio_get_uint32(&reply);
    
        binder_done(g_bs, &msg, &reply);
    
        return ret;
        
    }
    
    
    void saygoodbye(void)
    {
        unsigned iodata[512/4];
        struct binder_io msg, reply;
    
        /* 构造binder_io */
        bio_init(&msg, iodata, sizeof(iodata), 4);
        bio_put_uint32(&msg, 0);  // strict mode header
        bio_put_string16_x(&msg, "IGoodbyeService");
    
        /* 放入参数 */
    
        /* 调用binder_call */
        if (binder_call(g_bs, &msg, &reply, g_goodbye_handle, GOODBYE_SVR_CMD_SAYGOODBYE))
            return ;
        
        /* 从reply中解析出返回值 */
    
        binder_done(g_bs, &msg, &reply);
        
    }
    
    int saygoodbye_to(char *name)
    {
        unsigned iodata[512/4];
        struct binder_io msg, reply;
        int ret;
        int exception;
    
        /* 构造binder_io */
        bio_init(&msg, iodata, sizeof(iodata), 4);
        bio_put_uint32(&msg, 0);  // strict mode header
        bio_put_string16_x(&msg, "IGoodbyeService");
    
        /* 放入参数 */
        bio_put_string16_x(&msg, name);
    
        /* 调用binder_call */
        if (binder_call(g_bs, &msg, &reply, g_goodbye_handle, GOODBYE_SVR_CMD_SAYGOODBYE_TO))
            return 0;
        
        /* 从reply中解析出返回值 */
        exception = bio_get_uint32(&reply);
        if (exception)
            ret = -1;
        else
            ret = bio_get_uint32(&reply);
    
        binder_done(g_bs, &msg, &reply);
    
        return ret;
        
    }
    
    
    
    /* ./test_client hello
     * ./test_client hello <name>
     */
    
    int main(int argc, char **argv)
    {
        int fd;
        struct binder_state *bs;
        uint32_t svcmgr = BINDER_SERVICE_MANAGER;
        uint32_t handle;
        int ret;
    
        if (argc < 2){
            fprintf(stderr, "Usage:
    ");
            fprintf(stderr, "%s <hello|goodbye>
    ", argv[0]);
            fprintf(stderr, "%s <hello|goodbye> <name>
    ", argv[0]);
            return -1;
        }
    
        bs = binder_open(128*1024);
        if (!bs) {
            fprintf(stderr, "failed to open binder driver
    ");
            return -1;
        }
        g_bs = bs;
    
    
        /* get service */
        handle = svcmgr_lookup(bs, svcmgr, "goodbye");
        if (!handle) {
            fprintf(stderr, "failed to get goodbye service
    ");
            return -1;
        }
        g_goodbye_handle = handle;
        fprintf(stderr, "Handle for goodbye service = %d
    ", g_goodbye_handle);
    
        handle = svcmgr_lookup(bs, svcmgr, "hello");
        if (!handle) {
            fprintf(stderr, "failed to get hello service
    ");
            return -1;
        }
        g_hello_handle = handle;
        fprintf(stderr, "Handle for hello service = %d
    ", g_hello_handle);
    
        /* send data to server */
        if (!strcmp(argv[1], "hello"))
        {
            if (argc == 2) {
                sayhello();
            } else if (argc == 3) {
                ret = sayhello_to(argv[2]);
                fprintf(stderr, "get ret of sayhello_to = %d
    ", ret);        
            }
        } else if (!strcmp(argv[1], "goodbye"))
        {
            if (argc == 2) {
                saygoodbye();
            } else if (argc == 3) {
                ret = saygoodbye_to(argv[2]);
                fprintf(stderr, "get ret of sayhello_to = %d
    ", ret);        
            }
        }
    
        binder_release(bs, handle);
    
        return 0;
    }

      3.编译脚本:

      (1)Makefile

    APPS = service_manager test_client test_server
    
    all : $(APPS)
    
    service_manager : service_manager.o binder.o
        arm-linux-gcc -o $@ $^ -lpthread
    
    test_client : test_client.o binder.o
        arm-linux-gcc -o $@ $^ -lpthread
    
    test_server : test_server.o binder.o
        arm-linux-gcc -o $@ $^ -lpthread
    
    %.o : %.c 
        arm-linux-gcc -DBINDER_IPC_32BIT=1 -I include -c -o $@ $<
                
    clean:
        rm $(APPS) -f; rm -f *.o

      (2)Android.mk

    LOCAL_PATH:= $(call my-dir)
    
    include $(CLEAR_VARS)
    
    LOCAL_CFLAGS += -DBINDER_IPC_32BIT=1
     
    LOCAL_SRC_FILES:= service_manager.c binder.c
    
    LOCAL_C_INCLUDES += system/core/include/cutils
    
    LOCAL_MODULE:= service_manager_my
    
    include $(BUILD_EXECUTABLE)
    
    include $(CLEAR_VARS)
    
    LOCAL_CFLAGS += -DBINDER_IPC_32BIT=1
    
    LOCAL_SRC_FILES:= test_server.c binder.c
    
    LOCAL_C_INCLUDES += system/core/include/cutils
    
    LOCAL_MODULE:= test_server
    
    include $(BUILD_EXECUTABLE)
    
    include $(CLEAR_VARS)
    
    LOCAL_CFLAGS += -DBINDER_IPC_32BIT=1
    
    LOCAL_SRC_FILES:= test_client.c binder.c
    
    LOCAL_C_INCLUDES += system/core/include/cutils
    
    LOCAL_MODULE:= test_client
    
    include $(BUILD_EXECUTABLE)

    -end-

  • 相关阅读:
    java中给集合快速取值最大值和最小值
    Mybatis.xml文件中大于小于等于
    Validate表单验证
    更新了svn 后,某个文件多了几个副本如:xxx.r1 xxx.r3 xxx.mine等,正常文件名xxx
    Oracle监听出现的问题总结,以及解决办法
    oracle三个网络配置文件(listener.ora、tnsname.ora、sqlnet.ora)的作用
    Lucene提供的条件判断查询
    Lucene 单域多条件查询
    lucene自定义过滤器
    luke使用
  • 原文地址:https://www.cnblogs.com/blogs-of-lxl/p/10165045.html
Copyright © 2011-2022 走看看