码迷,mamicode.com
首页 > 其他好文 > 详细

Binder 驱动(三)

时间:2019-04-12 19:01:11      阅读:172      评论:0      收藏:0      [点我收藏+]

标签:priority   async   ide   ioctl   直接   发送   context   one   client   

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

 

Binder 驱动(三)

标签:priority   async   ide   ioctl   直接   发送   context   one   client   

原文地址:https://www.cnblogs.com/mingfeng002/p/10696059.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!