• Binder 驱动(三)


    Binder 驱动是 Binder 的最终实现, ServiceManager 和 Client/Service 进程间通信最终都是由 Binder 驱动投递的。

    Binder 驱动的代码位于 kernel 代码的 drivers/staging/android 目录下。主文件是 binder.h 和 binder.c

    Binder 驱动的逻辑图

    进程间传输的数据被称为 Binder 对象,它是一个 flat_binder_object,结构如下

    struct flat_binder_object {
        /* 8 bytes for large_flat_header. */
        unsigned long       type;
        unsigned long       flags;
    
        /* 8 bytes of data. */
        union {
            void        *binder;    /* local object */
            signed long handle;     /* remote object */
        };
    
        /* extra data associated with local object */
        void            *cookie;
    };

    其中 类型 type 描述了 Binder 对象的类型,包含 BINDER(本地对象)、HANDLE(远程对象)、 FD 三大类(五种)

    enum {
        BINDER_TYPE_BINDER  = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
        BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),
        BINDER_TYPE_HANDLE  = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),
        BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),
        BINDER_TYPE_FD      = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),
    };

    flags 则表述了传输方式,如异步、无返回等

    enum transaction_flags {
        TF_ONE_WAY  = 0x01, /* this is a one-way call: async, no return */
        TF_ROOT_OBJECT  = 0x04, /* contents are the component's root object */
        TF_STATUS_CODE  = 0x08, /* contents are a 32-bit status code */
        TF_ACCEPT_FDS   = 0x10, /* allow replies with file descriptors */
    };

    而 flat_binder_object 中的 union 联合体 就是要传输的数据,当类型为 BINDER 时, 数据就是一个本地对象 *binder,而类型为 HANDLE 时,数据则是一个远程对象 handle

    当 flat_binder_object 在进程间传递时, Binder 驱动会修改它的类型和数据,交换的代码参考 binder_transaction 的实现。

    该如何理解本地 BINDER 对象和远程 HANDLE 对象呢?其实它们都代表同一个对象,不过是从不同的角度来看。举例来说,假如进程 RemoteService 有个对象 mBinder,对于 RemoteService 来说,mBinder 就是一个本地的 BINDER 对象;如果进程 app 通过 Binder 驱动访问 RemoteService 的 mBinder 对象,对于 app 来说, mBinder 就是一个 HANDLE。因此,从根本上来说 handle 和 binder 都指向 RemoteService 的 mBinder。本地对象还可以带有额外的数据,保存在 cookie 中。

    Binder 驱动直接操作的最外层数据结构是 binder_transaction_data, Binder 对象 flat_binder_object 被封装在 binder_transaction_data 结构体中。

    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;
    };

    flat_binder_object 就被封装在 *buffer中,其中的 unsigned int code; 则是传输命令,描述了 Binder 对象执行的操作。

    1. binder 设备的创建

    device_initcall() 函数是内核加载驱动的入口函数,我们先来看这个函数的调用过程。

    static struct miscdevice binder_miscdev = {
        .minor = MISC_DYNAMIC_MINOR,
        .name = "binder",
        .fops = &binder_fops
    };
    
    static int __init binder_init(void)
    {
        int ret;
        ...
        ret = misc_register(&binder_miscdev);
        ...
        return ret;
    }
    
    device_initcall(binder_init);

    可以看出 binder_init() 使用 misc_register() 函数创建了 binder 设备。从 misc_register(&binder_miscdev); 及 .name = "binder" 可以看出, binder 向 kernel 注册了一个 /dev/binder 的字符设备,而文件操作都在 binder_fops 结构体中定义。

    static const struct file_operations binder_fops = {
        .owner = THIS_MODULE,
        .poll = binder_poll,
        .unlocked_ioctl = binder_ioctl,
        .mmap = binder_mmap,
        .open = binder_open,
        .flush = binder_flush,
        .release = binder_release,
    };

    从上面 binder_fops 结构体可以看出,主要的操作是 binder_ioctl() binder_mmap() binder_open() 等函数实现的。

    2. ServiceManager 服务的注册

    binder协议和数据结构

    binder.h 文件中定义了 binder 协议和重要的数据结构。

    首先在 enum 中定义了 binder 处理的类型,引用或是句柄

    enum {
        BINDER_TYPE_BINDER  = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE),
        BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE),
        BINDER_TYPE_HANDLE  = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE),
        BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE),
        BINDER_TYPE_FD      = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE),
    };

    下面这段宏定义则是在 ioctl 函数调用时可用的具体命令。

    #define BINDER_WRITE_READ       _IOWR('b', 1, struct binder_write_read)
    #define BINDER_SET_IDLE_TIMEOUT     _IOW('b', 3, int64_t)
    #define BINDER_SET_MAX_THREADS      _IOW('b', 5, size_t)
    #define BINDER_SET_IDLE_PRIORITY    _IOW('b', 6, int)
    #define BINDER_SET_CONTEXT_MGR      _IOW('b', 7, int)
    #define BINDER_THREAD_EXIT      _IOW('b', 8, int)
    #define BINDER_VERSION          _IOWR('b', 9, struct binder_version)

    在 BinderDriverReturnProtocol 和 BinderDriverCommandProtocol 中 则分别定义了 客户端调用 和 服务端 返回的命令。

    binder_ioctl() 函数

    用户态程序调用 ioctl 系统函数向 /dev/binder 设备发送数据时,会触发 binder_ioctl 函数响应。

    binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 函数用来处理

    Binder 在头文件中只要定义了两个数据类型, 一个是 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;
    };
  • 相关阅读:
    DrawSVG
    Cool!15个创意的 CSS3 文本效果【下篇】
    分享最新15个加速 Web 开发的框架和工具
    Unsplash.it
    Cool!15个超炫的 CSS3 文本特效【上篇】
    Codrops 实验:使用 Vibrant.js 提取图像颜色
    Javscript调用iframe框架页面中函数的方法
    竞争的残酷性暂时只体现在产业竞争上(老美有发达的制药、农业、军工、金融、航空、航天、石油、化工等产业,还有以芯片为代表的高端服务业)
    Qt元对象(Meta-Object)系统与反射
    安晓辉:程序员在公司没事干时候,做什么好?(产品上想多一点,设计上想多一点,技术上做深一点、做宽一点,思维框架上学多一点)
  • 原文地址:https://www.cnblogs.com/mingfeng002/p/10696059.html
Copyright © 2020-2023  润新知