android binder机制及其源码解析之第二节 重要函数讲解之常用数据结构(一)

 
struct binder_work {
    struct list_head entry;
    enum {
        BINDER_WORK_TRANSACTION = 1,
        BINDER_WORK_TRANSACTION_COMPLETE,
        BINDER_WORK_NODE,
        BINDER_WORK_DEAD_BINDER,
        BINDER_WORK_DEAD_BINDER_AND_CLEAR,
        BINDER_WORK_CLEAR_DEATH_NOTIFICATION,
    } type;
};

binder_work 结构体,entry 的定义:

struct list_head {

struct list_head *next, *prev;

};

双向链表,用来存储所有的binder_work队列。type当然是枚举类型的,本来枚举其实从0开始的,这里显示的赋值BINDER_WORK_TRANSACTION = 1。那就理所当然的从1开始。type其实是binder_work的工作类型。后面会对这些类型做详细分析,我更觉得它作为工作状态来理解更好一些。

work分两种,进程work和线程work,分别记录在binder_proc和binder_thread的todo列表里.entry是用来把work加入到相应todo里的。而type则是描述work的性质。TRANSACTION类型的work就是后面将要说的transaction,android里进程之间普通的请求就是这个东西。

NODE类型的work是用于引用计数的,当binder_node(后面会提到什么是binder_node)的引用计数发生某些变化时,驱动就会往进程或者线程的work里添加这个binder_node的work。

DEAD_BINDER,DEAD_BINDER_AND_CLEAR,CLEAR_DEATH_NOTIFICATION这三种类型是用于死亡通知的

驱动在处理各种work时,会考虑当前线程LOOPER状态(后面章节会解释),如果没有ENTERED或者REGISTERED的,便一定会把work添加到进程work里,否则很可能加到当前线程的work里,这个得看实际情况了。


binder 类型定义

#define B_PACK_CHARS(c1, c2, c3, c4) \
    ((((c1)<<24)) | (((c2)<<16)) | (((c3)<<8)) | (c4))
#define B_TYPE_LARGE 0x85

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

首先宏定义B_PACK_CHARS, c1 到c4 依次左移24,16,8,0位。不知道大家有没有发现规律,左移的间隔是8位,刚好一个字节。c1,c2,c3,c4 正好4个字节32位。继续宏定义B_TYPE_LARGE 为十六进制的0x85,占一个字节。然后枚举。在binder中枚举实在是太多啦,大家忍着看吧。枚举的5个类型正好是binder的5个不同类型。说白了就是五个宏定义,b应该是binder的缩写,代表本地类型,h是handle缩写,代表远端引用。看过对象和引用的应该了解的。w应该是WEAK_BINDER的代指,应该是指针强度的表示,那么s 指什么,强(strong)指针?大家想想。以上几个字母的含义是这是我猜的,不一定准确。fd就是很容易猜到的哦,就是文件。因此有:本地对象(BINDER_TYPE_BINDER,BINDER_TYPE_WEAK_BINDER),远程对象的引用(BINDER_TYPE_HANDLE,BINDER_TYPE_WEAK_HANDLE),文件(BINDER_TYPE_FD)。其实远程引用或者本地对象就是binder存在的两种方式,对于高层用户来说,他是不许要理清谁是本地谁是远程,因为提供了统一的接口。但是对于底层驱动来说,这是必须区分的了。这个类型定义就来干这件事情的。binder除了是个跨进程的指针之外,还能当做跨进程文件描述符用,FD类型就是干这个的


binder 对象


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;
};
我们把进程间传递的对象叫做binder对象,它的原型就是struct flat_binder_object。type是什么呢,你不知道?不可能。前面刚讲到额。五种就正好对应这里的type哦。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 */
};
又是enum 头大了吧,不过幸好不复杂。看我一一道来. TF_ONE_WAY 便是单向传递,异步的。TF_ROOT_OBJECT,contents are the component's root object。什么东东?表示内容是一个组建的根对象,就是对应类型位本地对象的binder。TF_STATUS_CODE,又是什么呢?它表示的内容是一个32位的状态码,更容易理解的说法是一个远程对象的引用(即为句柄handle),又提到本地对象和远程引用的概念了,各位同学不要偷懒,还是要去查查的哦。TF_ACCEPT_FDS便是接受的是一个文件描述符,对应的类型为文件。在继续解释flags的7~0bits是用来设置binder_node的线程优先级的,在binder的实际应用中,远程进程的对binder的操作请求会由binder本地进程的一个线程完成,而这个优先级就是用来设置该线程处理这个binder事物时的优先级。flags的第八位 bit是用来表示这个binder是否接受文件描述符的,不支持文件描述符的binder是没法用binder类型为BINDER_TYPE_FD的。cookie在xx_BINDER类型(binder的两种类型)时就是binder_node的cookie,在xx_HANDLE类型时是null。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值