Binder学习一——Binder基础数据结构

在看Binder源码时,总是接触到很多这些莫名其妙的struct,故依据几本参考资料先把这些数据结构的意义即关系整理以下:

/** \kernel\goldfish\drivers\staging\android\binder.c*/

1、binder_work:

//表示binder驱动中进程所要处理的工作项

struct binder_work {

struct list_head entry;             //用于实现一个双向链表,存储所有binder_work的队列

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;                            //描述工作项的类型

};

2、binder_thread:

//存储Binder线程池中的每个线程的信息

struct binder_thread {

struct binder_proc *proc;               //宿主进程,即线程属于哪个Binder进程

struct rb_node rb_node;                 //红黑树中的一个节点,binder_proc使用红黑树来组织Binder线程池中的线程

int pid;                                //当期线程PID

int looper;                             //当前线程状态信息

struct binder_transaction *transaction_stack;//事务堆栈,将事务封装成binder_transaction,添加到事务堆栈中,定义了要接收和发送的进程和线程消息

struct list_head todo;                  //队列,当有来自Client的请求时,将会添加到to_do队列中

uint32_t return_error;                  //记录处理事务时出现异常错误情况信息

uint32_t return_error2;

wait_queue_head_t wait;                 /* 等待队列,当Binder处理T1事务依赖于其他Binder线程处理事务T2时, 
                                                                                                                                                                                                         则会sleep在wait所描述的等待队列中,直至T2事务处理完成再唤醒*/

struct binder_stats stats;              //Binder线程相关统计数据

};

//looper状态值

enum {

BINDER_LOOPER_STATE_REGISTERED  =
0x01, //Binder驱动请求创建该线程,通过BC_REGISTER_LOOPER协议通知Binder驱动,注册成功设为此状态

BINDER_LOOPER_STATE_ENTERED     =
0x02, //该线程是应用程序主动注册的,            BC_ENTER_LOOPER

BINDER_LOOPER_STATE_EXITED      =
0x04, //Binder线程退出,   BC_EXIT_LOOPER

BINDER_LOOPER_STATE_INVALID     =
0x08, //异常情况

BINDER_LOOPER_STATE_WAITING     =
0x10, //Binder线程处于空闲状态

BINDER_LOOPER_STATE_NEED_RETURN =
0x20  /*表示该线程需要马上返回到用户空间中,使用情形 :
                                                                                                                                                   一:线程注册成为Binder线程后,还没准备好去处理进程间通信,需要返回用户空间做其他初始化等准备 
                                                                                                                                               二:进程调用flush来刷新Binder线程池*/

};

3、binder_stats:

//Binder线程相关统计计数

struct binder_stats {

int br[_IOC_NR(BR_FAILED_REPLY)
+ 1];     // 用于存储BINDER_WRITE_READ读操作命令协议

int bc[_IOC_NR(BC_DEAD_BINDER_DONE)
+ 1]; // 用于存储BINDER_WRITE_READ写操作命令协议

int obj_created[BINDER_STAT_COUNT];       // 保存对象计数

int obj_deleted[BINDER_STAT_COUNT];

};

4、binder_proc:

/** 描述一个正在使用Binder进程通信的进程,binder_proc为管理其信息的记录体

*  当一个进程open
/dev/binder时,Binder驱动程序会为其创建一个binder_proc结构体,用以记录该进程的所有相关信息

*  并把该结构体保存到一个全局的hash表中*/

struct binder_proc {

/** 进程相关参数*/

struct hlist_node proc_node;         // 上述全局hash表中的一个节点,用以标记该进程

int pid;                             // 进程组ID

struct task_struct *tsk;             // 任务控制模块

struct files_struct *files;          // 文件结构体数组

/**
Binder线程池——每一个Binder进程都有一个线程池,由Binder驱动程序来维护

*  Binder线程池中所有线程由一个红黑树来组织,RB树以线程ID为关键字;*/

struct rb_root threads;              // 上述红黑树根节点

/* 进程可以调用ioctl注册线程到Binder驱动程序中;当线程池中没有足够空闲线程来处理事务时,

*
Binder驱动程序可以主动要求进程注册更多的线程到Binder线程池中*/

int max_threads;                     //
Binder驱动程序最多可以请求进程注册的线程的数量

int requested_threads;               //
Binder驱动程序每主动请求进程添加注册一个线程时,requested_threads加1

int requested_threads_started;       // 进程响应Binder要求后,requested_threads_started
+ 1;requested_threads - 1

// 表示Binder已经主动请求注册的线程数目

int ready_threads;                   // 进程当前空闲Binder线程数目

long default_priority;               // 线程优先级,初始化为进程优先级

/** 一系列Binder实体对象(binder_node)和Binder引用对象(binder_ref)

老罗对此做的概念区分:

1. 在用户空间,运行在Server端的称为Binder本地对象,运行在Client端的称为Binder代理对象。

2. 在内核空间,Binder实体对象用来描述Binder本地对象,Binder引用对象用来描述Binder代理对象。*/

struct rb_root nodes;                //
Binder实体对象列表(RB树),关键字ptr

struct rb_root refs_by_desc;         //
Binder引用对象,关键字desc

struct rb_root refs_by_node;         //
Binder引用对象,关键字node

/**
mmap内核缓冲区*/

struct vm_area_struct *vma;          //
mmap——分配的内核缓冲区  用户空间地址(相较于buffer)

void *buffer;                        //
mmap——分配的内核缓冲区  内核空间地址(相较于vma)(两者都是虚拟地址)

ptrdiff_t user_buffer_offset;        //
mmap——buffer与vma之间的差值

/**
buffer指向的内核缓冲区,被划分成很多小块进行管理;这些小块保存在列表中,buffers就是列表头部*/

struct list_head buffers;            // 内核缓冲区列表

struct rb_root free_buffers;         // 空闲的内存缓冲区(红黑树)

struct rb_root allocated_buffers;    // 正在使用的内存缓冲区(红黑树)

size_t free_async_space;             // 当前可用来保存异步事务数据的内核缓冲区大小

struct page **pages;                 // 对应于vma、buffer虚拟地址,这里是它们对应的物理页面

size_t buffer_size;                  // 内核缓冲区大小

uint32_t buffer_free;                // 空闲内核缓冲区大小

/** 进程每接收到一个通信请求,Binder将其封装成一个工作项,保存在待处理队列to_do中*/

struct list_head todo;               // 待处理工作队列

wait_queue_head_t wait;              // 等待队列,存放一些睡眠的空闲Binder线程

struct hlist_node deferred_work_node;//
hash表,保存进程中可以延迟执行的工作项

int deferred_work;                   // 延迟工作项的具体类型

struct binder_stats stats;           // 统计进程相关数据,具体参见binder_stats结构

struct list_head delivered_death;    // 表示Binder驱动程序正在向进程发送的死亡通知

};

5、binder_node:

/** 描述一个Binder实体对象,每一个Service组件在Binder驱动程序中都对应一个Binder实体对象

*  Binder驱动程序通过强引用和弱引用计数来维护其生命周期*/

struct binder_node {

int debug_id;                      // 用以调试

struct binder_work work;           //

/** 每一个binder进程都由一个binder_proc来描述

*  binder进程内部所有Binder实体对象,由一个红黑树进行组织(struct
rb_root nodes)

*  rb_node则对应nodes其中的一个节点*/

union {

struct rb_node rb_node;        // 用于将本节点连接点红黑树中

struct hlist_node dead_node;   /* 如果Binder实体对象对应的进程死亡,销毁节点时需要将rb_node从红黑树中删除,

如果本节点还有引用没有切断,则用dead_node 将其隔离到另一个链表中,

直到通知所有进程切断与该节点的引用后,该节点才能销毁*/

};

/*  binder_proc 和 binder_node 关系:

*  可以将binder_proc理解为一个进程,而将binder_node理解为一个Service。

*  binder_proc里面有一个红黑树,用来保存所有在它所描述的进程里面创建的Service,

*  而每一个Service在Binder驱动程序里面都用一个binder_node来描述。

*
*/

struct binder_proc *proc;          // 指向该Binder实体对象对应的进程,进程由binder_proc描述

struct hlist_head refs;            /* 该Bidner实体对象可能同时被多个Client组件引用,所有指向本实体对象的引用都保存到这个hash队列中

refs表示队列头部;这些引用可能隶属不同进程,遍历该hash表能够得到哪些Client组件引用了该对象*/

/** 引用计数

*  1、当一个Bidner实体对象请求一个Service组件来执行Bidner操作时。会增加该Service组件的强/弱引用计数

*    同时,Binder实体对象会将has_strong_ref与has_weak_ref置为1

*  2、当一个Service组件完成一个Binder实体对象请求的操作后,Binder对象会请求减少该Service组件的强/弱引用计数

*  3、Binder实体对象在请求一个Service组件增加或减少强/弱引用计数的过程中,会将pending_strong_ref和pending_weak_ref置为1

*    当Service组件完成增加或减少计数时,Binder实体对象会将这两个变量置为0*/

int internal_strong_refs;          // 强引用计数

int local_weak_refs;               // 弱引用计数

int local_strong_refs;             // 强引用计数

unsigned has_strong_ref :
1;

unsigned pending_strong_ref :
1;

unsigned has_weak_ref :
1;

unsigned pending_weak_ref :
1;

/** 用来描述用户空间中的一个Service组件*/

void __user
*ptr;                  // 指向该Service组件内部的一个引用计数对象(weakref_impl)的地址??

void __user
*cookie;               // 指向该Service组件的地址

/** 异步事务处理,目的在于为同步交互让路,避免长时间阻塞发送端

*  异步事务的定义:(相对于同步事务)单向的进程间通信要求,即不需要等待应答的进程间通信请求

*  Binder驱动程序认为异步事务的优先级低于同步事务,则在同一时刻,一个Binder实体对象至多只有一个异步事务会得到处理;而同步事务则无此限制

*

*  Binder将事务保存在一个线程binder_thread的todo队列中,表示由该线程来处理该事务

*  每一个事务都关联Binder实体对象(union
target),表示该事务的目标处理对象,表示要求该Binder实体对象对应的Serice组件在指定线程中处理该事务

*  而如果Binder发现一个事务是异步事务,则会将其保存在目标Binder实体对象的async_todo的异步事务队列中等待处理*/

unsigned has_async_transaction :
1;// 描述该Binder实体对象是否正在处理一个异步事务,1 表示是

struct list_head async_todo;

/* 表示该Binder实体对象能否接收包含有该文件描述符的进程间通信数据。

* 当一个进程向另一个进程发送数据中包含文件描述符时,Binder会在目标进程中打开一个相同的文件

* 故设为accept_fds为0可以防止源进程在目标进程中打开文件*/

unsigned accept_fds :
1;

int min_priority :
8;              // 处理Binder请求的线程的最低优先级

};

6、binder_ref:

/** 用来描述一个Binder引用对象,每一个Client组件在Binder驱动程序中都有一个Binder引用对象,用来描述它在内核中的状态*/

struct binder_ref {

/*
Lookups needed: */

/*   node
+ proc => ref (transaction) */

/*   desc
+ proc => ref (transaction, inc/dec ref) */

/*   node
=> refs + procs (proc exit) */

int debug_id;                    // 用以调试

/**
binder_proc中使用红黑树(对应两个rb_root变量)来存储其内部所有的引用对象

*  下面rb_node则是红黑树中的节点*/

struct binder_proc *proc;        //
Binder引用对象的宿主进程

struct rb_node rb_node_desc;     // 对应refs_by_desc,以句柄desc索引

struct rb_node rb_node_node;     // 对应refs_by_node,以node索引

/**
Client通过Binder访问Service时,仅需指定一个句柄值,Binder通过该desc找到对应binder_ref,再根据该

*  binder_ref中的node变量得到binder_node(实体对象),进而找到对应的Service组件*/

struct hlist_nod
enode_entry;    // 对应Binder实体对象中(hlist_head)refs引用对象队列中的一个节点

struct binder_node *node;        // 引用对象所指向的Binder实体对象

uint32_t desc;                   // 句柄,用以描述该Binder引用对象

// 强弱引用计数

int strong;

int weak;

/* 表示Service组件接收到死亡通知;*/

struct binder_ref_death *death;

};

7、binder_ref_death:

// 一个死亡通知结构体

/** 易知Client组件无法控制他所引用的Service组件的生命周期,由于Service组件所在进程可能意外崩溃

*  Client进程就需要能够在它所引用的Service组件死亡时获得通知,进而进行响应。

*  则Client进程就需要向Binder驱动程注册一个用来接收死亡通知的对象地址(这里的cookie)*/

struct binder_ref_death {

struct binder_work work;// 标志该通知具体的死亡类型

void __user
*cookie;    // 保存负责接收死亡通知的对象地址

};

/** Binder驱动向Client进程发送死亡通知的情形如下:

*  1、Binder驱动监测到Service组件死亡时,会找到对应Service实体对象(binder_node),再通过refs变量找到引用它的所有Client进程(binder_ref)

*    再通过death变量找到Client进程向Binder注册的死亡通知接收地址;

*    Binder将该死亡通知binder_ref_death封装成工作项,添加到Client进程的to_do队列中等待处理。

*    这种情况binder_work类型为BINDER_WORK_DEAD_BINDER

*  2、Client进程向Binder驱动程序注册一个死亡接收通知时

*    如果它所引用的Service组件已经死亡,Binder会立即发送通知给Client进程;

*    这种情况binder_work类型为BINDER_WORK_DEAD_BINDER

*

*  3、当Client进程向Binder驱动程序注销一个死亡通知时,也会发送通知,来响应注销结果

*    1)当Client注销时,Service组件还未死亡:Binder会找到之前Client注册的binder_ref_death,

*    将binder_work修改为BINDER_CLEAR_DEATH_NOTIFICATION,并将通知按上述步骤添加到Client的to_do对列中

*    2)当Client注销时,Service组件已经死亡,Binder同理将binder_work修改为WORK_DEAD_BINDER_AND_CLEAR,然后添加到todo中

*    */

8、binder_state:

struct binder_state

{

int fd;           //打开/dev/binder之后得到的文件描述符

void *mapped;     //mmap将设备文件映射到本进程的地址空间中,映射后得到的地址空间地址、及大小

size_t mapsize;

};

9、binder_buffer:

/** 内核缓冲区,用以在进程间传递数据

*  回顾binder_proc中的vma与buffers(内核缓冲区列表)*/

struct binder_buffer {

//
entry对应内核缓冲区列表buffers中的一个节点

struct list_head entry; /*
free and allocated entries by addesss */

/** 结合free,如果free=1,则rb_node对应free_buffers中一个节点(空闲内核缓冲区)

*          如果free!=1,则对应allocated_buffers中一个节点*/

struct rb_node rb_node; /*
free entry by size or allocated entry */

unsigned free :
1;

/**
Binder将事务数据保存到一个内核缓冲区中(binder_transaction.buffer),然后交由Binder实体对象(target_node)处理

*  而target_node会将缓冲区的内容交给对应的Service组件(proc)来处理

*  Service组件处理完事务后,若allow_user_free=1,则请求Binder释放该内核缓冲区*/

unsigned allow_user_free :
1;

struct binder_transaction *transaction;// 描述一个内核缓冲区正在交给哪个事务transaction,用以中转请求和返回结果

struct binder_node *target_node;       // 描述该缓冲区正在被哪个Binder实体对象使用

unsigned async_transaction :
1;        // 1表示事务是异步的;异步事务的内核缓冲区大小是受限的,这样可以保证同步事务可以优先得到缓冲区

unsigned debug_id :
29;                // 用以调试

/** 存储通信数据,通信数据中有两种类型数据:普通数据与Binder对象,

*  在数据缓冲区最后,有一个偏移数组,记录数据缓冲区中每一个Binder对象在缓冲区中的偏移地址*/

size_t data_size;                      // 数据缓冲区大小

size_t offsets_size;                   // 偏移数组的大小(其实也是偏移位置)

uint8_t data[0];                       // 用以保存通信数据,数据缓存区,大小可变

};

10、binder_transaction:

//描述进程间通信,这个过程称为一个transaction(事务),用以中转请求和返回结果,并保存接收和要发送的进程信息

struct binder_transaction {

int debug_id;

struct binder_work work;                // 用来描述待处理的工作项,这里会将其type设置为BINDER_WORK_TRANSACTION,具体结构见binder_work

/** 源线程*/

struct binder_thread *from;             // 源线程,即发起事务的线程

long    priority;                       // 源线程的优先级

uid_t   sender_euid;                    // 源线程的用户ID

/** 目标线程*/

struct binder_proc *to_proc;            // 目标进程,处理该事务的进程(process)

struct binder_thread *to_thread;        // 目标线程:处理该事务的线程

/** 《源代码分析》中的例子:线程A发起事务T1,需要由B线程处理;B处理T1时,需要C先处理T2;C处理T2时,又需要A处理T1;

*  则T1依赖于T2,T2依赖于T3;
A 要处理T1,T3,但要先处理T3

*  故:  T2->from_parent
= T1

*     T3->from_parent
= T2

*     T3->to_parent
= T1*/

struct binder_transaction *from_parent; // 表示另一个事务需要依赖该事务(不一定在同一线程中)

struct binder_transaction *to_parent;   // 目标线程下一个需要处理的事务

unsigned need_reply :
1;                // 标志事务是同步/异步;设为1——表示同步事务,需要等待对方回复;设为0——异步

/*unsigned
is_dead : 1;*//* not used at the moment
*/

/** 参照binder_buffer中解释,指向Binder为该事务分配的内核缓冲区

*  code与flags参见binder_transaction_data
*/

struct binder_buffer *buffer;

unsigned int    code;

unsigned int    flags;

/** 目标线程处理事务前,Binder需要修改其priority;修改前需要将线程原来的priority保存到saved_priority中,用以处理完事务恢复到原来优先级

*  优先级的设置:目标线程处理事务时,优先级应不低于目标Service组件要求的线程优先级,也不低于源线程的优先级;故设为两者的较大值*/

long    saved_priority;

};

11、binder_transaction_data:

/* 描述进程间通信所传输的数据:

* Binder对象的传递是通过binder_transaction_data来实现的,

* 即Binder对象实际是封装在binder_transaction_data结构体中。*/

structbinder_transaction_data {

/** 有一个联合体target,当这个BINDER_WRITE_READ命令的目标对象是本地Binder实体时,

就使用ptr来表示这个对象在本进程中的地址,否则就使用handle来表示这个Binder实体的引用。

只有目标对象是Binder实体时,cookie成员变量才有意义,表示一些附加数据;

详细的解释为:传输的数据是一个复用数据联合体,对于BINDER类型,数据就是一个binder本地对象,

如果是HANDLE类型,这数据就是一个远程的handle对象。该如何理解本地binder对象和远程handle对象呢?

其实它们都指向同一个对象,不过是从不同的角度来说。举例来说,假如A有个对象X,对于A来说,

X就是一个本地的binder对象;如果B想访问A的X对象,这对于B来说,X就是一个handle。

因此,从根本上来说handle和binder都指向X。本地对象还可以带有额外的数据,保存在cookie中。 */

union {

size_t  handle;/*
target descriptor of command transaction */

void    *ptr;   /*
target descriptor of return transaction */

} target;

//Binder实体带有的附加数据

void        *cookie;    /*
target object cookie */

//code是一个命令,描述了请求Binder对象执行的操作,表示要对目标对象请求的命令代码

unsignedint    code;       /*
transaction command */

/*
transaction的基本信息*/

//事务标志,见transaction_flags

unsignedint    flags;

pid_t       sender_pid;     // 发起请求的进程PID

uid_t       sender_euid;    // 发起请求的进程UID

size_t      data_size;      //data.buffer缓冲区的大小,data见最下面定义;命令的真正要传输的数据就保存在data.buffer缓冲区中

size_t      offsets_size;   //data.offsets缓冲区的大小

union {

struct {

/*
transaction data */

constvoid  *buffer;

/*
offsets from buffer to flat_binder_object structs */

constvoid  *offsets;

} ptr;

uint8_t buf[8];

} data;

/**   命令的真正要传输的数据就保存在data.buffer缓冲区中,前面的一成员变量都是一些用来描述数据的特征的。

data.buffer所表示的缓冲区数据分为两类,一类是普通数据,Binder驱动程序不关心,

一类是Binder实体或者Binder引用,这需要Binder驱动程序介入处理。为什么呢?

想想,如果一个进程A传递了一个Binder实体或Binder引用给进程B,那么,

Binder驱动程序就需要介入维护这个Binder实体或者引用的引用计数,防止B进程还在使用这个Binder实体时,

A却销毁这个实体,这样的话,B进程就会crash了。所以在传输数据时,如果数据中含有Binder实体和Binder引和,

就需要告诉Binder驱动程序它们的具体位置,以便Binder驱动程序能够去维护它们。

data.offsets的作用就在这里了,它指定在data.buffer缓冲区中,所有Binder实体或者引用的偏移位置。

注::

进程间传输的数据被称为Binder对象(Binder
Object),

它是一个flat_binder_object。Binder对象的传递是通过binder_transaction_data来实现的,

即Binder对象实际是封装在binder_transaction_data结构体中。*/

};

12、transaction_flags:

/* transaction_flags描述了传输方式,比如同步、异步等*/

enum transaction_flags
{

TF_ONE_WAY  =
0x01,    /* 当前事务异步,不需要等待*/

TF_ROOT_OBJECT  =
0x04,/* 包含内容是根对象(暂未使用)*/

TF_STATUS_CODE  =
0x08,/* 表示data所描述的数据缓冲区内同是一个4bit状态吗*/

TF_ACCEPT_FDS   =
0x10,/* 允许数据中包含文件描述符*/

};

13、flat_binder_object:

struct flat_binder_object {

/*
8 bytes for large_flat_header. */

unsigned long       type;  //Binder对象的类型

unsigned long       flags; //Binder对象的标志

/*
8 bytes of data. */

union {

void        *binder;    /*
local object */

signed long handle;     /*
remote object */

};

/*
extra data associated with local object */

void            *cookie;

};

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-05 04:59:24

Binder学习一——Binder基础数据结构的相关文章

Android Binder驱动中的基础数据结构整理

最近突然看到一个博客,是讲Binder原理的,以前看深入理解Android I的时候看过,那时候就看不懂.感觉这个还有点意思,就看了好几天,发现越看越不懂,然后看老罗的博客,发现也不是太懂,现在想根据书上的东西好好梳理下Binder. 感觉里面应该重点掌握的应是bind_node是注册的服务在内核中的代表,bind_ref是客户端连接在驱动的代表.bind_buffer内核缓冲区,通过mmap之后可以在用户空间操作,然后在内核也可以访问,bind_proc是进程的代表,客户端和服务端都有,对上面

Android Binder实现浅析-Binder驱动

简介 Android是如何实现跨进程通信的,大家熟悉的Binder是什么,怎么设计的,进程间的数据如何发送接收的.本文将以及解析,并对Binder驱动实现.Native层实现.Java层实现三块做一个总结分析. Binder学习思路 Binder与传统IPC的区别 Binder驱动的内部设计.数据结构 Binder驱动与应用程序进程(C/S)之间的通信过程 Android应用程序通过Binder驱动进行通信的流程 Android开发人员如何使用Binder通信(AIDL.Java层架构) 基础知

Binder学习笔记(五)—— Parcel是怎么打包数据的?

前文中曾经遇到过Parcel,从命名上知道他负责数据打包.在checkService的请求/响应体系中,Parcel只打包了基本数据类型,如Int32.String16……后面还要用于打包抽象数据类型flat_binder_object,这会稍微复杂一些,因此有必要拿出来单独研究.我们从Parcel::writeInterfaceToken(…)追起,它的层层调用关系如下,这些函数都在frameworks/native/libs/binder/Parcel.cpp文件中,行数和函数名为: 582

Binder学习指南

毫不夸张地说,Binder是Android系统中最重要的特性之一:正如其名“粘合剂”所喻,它是系统间各个组件的桥梁,Android系统的开放式设计也很大程度上得益于这种及其方便的跨进程通信机制. 理解Binder对于理解整个Android系统有着非常重要的作用,Android系统的四大组件,AMS,PMS等系统服务无一不与 Binder挂钩:如果对Binder不甚了解,那么就很难了解这些系统机制,从而仅仅浮游与表面,不懂Binder你都不好意思说自己会Android 开发:要深入Android,

Android binder学习一:主要概念

要看得懂android代码,首先要了解binder机制.binder机制也是android里面比較难以理解的一块,这里记录一下binder的重要概念以及实现.作为备忘. 部分内容来源于网上,如有侵权.请及时告知. 1.binder通信机制概述 binder通信是一种client-server的通信结构, 1.从表面上来看.是client通过获得一个server的代理接口,对server进行直接调用: 2.实际上,代理接口中定义的方法与server中定义的方法是一一相应的. 3.client调用某

从零开始系列-R语言基础学习笔记之二 数据结构(一)

在上一篇中我们一起学习了R语言的环境搭建,这次我们开始学习R语言的数据结构第一部分:向量.数组和矩阵. 一.向量 向量是一维数组,其内容可以是数值.字符或布尔值,但所有数据的类型必须一致.创建向量使用的关键字是c,访问向量中的元素使用[],具体如下: 创建数值向量a<-c(1,2,3,4,5,6) 创建字符向量b<-c("a","b","c") 创建布尔向量c<-c(TRUE,FALSE) 访问向量: a[3] 得到的值是3,注

Binder学习笔记(一)

网上看了很多关于binder的文章,但我还是想把自己的心路历程记录下来,有些是跟着别人的脚步领略险峻风景,有些则是自己只身探入代码深处打捞出的收获.我不确定是否全部融会贯通,更担心一两个月后会完全不记得来时的路.最好的验证和留存的方法是把他们写成博文,几个月后回头再来读,看是否还能读得明白.如果可以,说明我两个担心已不复存在:如果又回到云里雾里,刚好可以带着新问题继续探索.文章很多地方会引用Android源码,我的源码版本是6.0.1_r11. 当静态代码走查遭遇多态.依赖外部数据时,常常会陷入

Java基础学习(一)数据结构

基础问题  1. 几类数据结构的定义和区别是什么? 2. 容器的数据结构底层是怎么实现的?怎么进行扩容? 3. 容器的线程安全怎么实现?   一.List容器 数据有序,允许重复数据,线程不安全. 1. linkedList  底层用双向链表实现,操作速度快,可以在头.尾.[n]操作数据. 2. ArrayList 底层用数组实现,查询速度快,默认数组大小是10.可以通过new ArrayList<Object>(n)设置n的值来指定数组的size,这样可以节省空间并避免数组扩容引起的效率下降

Android Binder机制(1):Binder架构分析

从这篇博客开始,将进入Binder机制的分析系列,顺序是先讲解Binder机制的框架,理解了整体思想后,再深入分析各层的细节实现,最后会实现一个自己的本地服务. 1.Binder的历史 BeOS是Be公司在1991年开发的运行在BeBOX硬件上的一款操作系统,与同期的其他操作系统不同,它是一款基于GUI设计的操作系统. George Hoffman(在LinkedIn上可以找到这哥们,简直是活着的传奇)当时任Be公司的工程师,他启动了一个名为OpenBinder的项目,该项目的宗旨是研究一个高效