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),
};
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[];
} 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[];
} data;
};
Binder 驱动(三)的更多相关文章
- Android - Binder驱动
以下资料摘录整理自老罗的Android之旅博客,是对老罗的博客关于Android底层原理的一个抽象的知识概括总结(如有错误欢迎指出)(侵删): http://blog.csdn.net/luosh ...
- Binder机制,从Java到C (10. Binder驱动)
Binder驱动的代码都在kernel里面,这里就简单讲一下里面涉及到的几个东西: 1.MemoryBinder其实本质上就是一中数据传输方式,这种方式是通过binder driver实现的. 我们知 ...
- Android系统--Binder系统具体框架分析(二)Binder驱动情景分析
Android系统--Binder系统具体框架分析(二)Binder驱动情景分析 1. Binder驱动情景分析 1.1 进程间通信三要素 源 目的:handle表示"服务",即向 ...
- Android Binder实现浅析-Binder驱动
简介 Android是如何实现跨进程通信的,大家熟悉的Binder是什么,怎么设计的,进程间的数据如何发送接收的.本文将以及解析,并对Binder驱动实现.Native层实现.Java层实现三块做一个 ...
- [Binder深入学习一]Binder驱动——基础数据结构
具体代码路径: kernel/drivers/staging/android/binder.c kernel/drivers/staging/android/binder.h /* * binder_ ...
- Android面试官:说说你对 Binder 驱动的了解?
面试官提了一个问题:说说你对 binder 驱动的了解.这个问题虽有些 "面试造火箭" 的无奈,可难点就是亮点.价值所在,是筛选面试者的有效手段.如果让你回答,你能说出多少呢?我们 ...
- android binder 机制三(匿名Service)
什么是匿名Service?凡是没有到ServiceManager上注冊的Service,都是匿名Service. 还是拿上一篇的样例来举例,看代码: status_t MediaPlayer::set ...
- 【iCore4 双核心板_ARM】例程一:ARM驱动三色LED
实验原理: 通过STM32的三个GPIO驱动一个三色LED,引脚PB2接红色LED(ARM_LEDR), 引脚PA9接蓝色LED(ARM_LEDB),引脚PA10接绿色LED(ARM_LEDG), ...
- 【iCore1S 双核心板_ARM】例程一:ARM驱动三色LED
实验原理: 通过STM32的三个GPIO驱动一个三色LED,引脚PF3接蓝色LED(ARM_LEDB), 引脚PF4接绿色LED(ARM_LEDG),引脚PF5接红色LED(ARM_LEDR), G ...
随机推荐
- mybatis 存储过程调用
接口 UserInfoMapper.java xml UserInfoMapper.xml 如何关联 <?xml version="1.0" encoding=" ...
- 编写高质量代码改善C#程序的157个建议——建议130:以复数命名枚举类型,以单数命名枚举元素
建议130:以复数命名枚举类型,以单数命名枚举元素 枚举类型应该具有负数形式,它表达的是将一组相关元素组合起来的语义.比如: enum Week { Monday, Tuesday, Wednesda ...
- NSArray去除重复元素
直接上代码吧! 1.可以创建一个新的数组,对需要去除重复的数组进行遍历,如果新数组不包含就数组,那么添加元素,如果包含就不添加. NSMutableArray *array = [NSMutableA ...
- Java50道经典习题-程序4 分解质因数
题目:将一个正整数分解质因数.例如:输入90,打印出90=2*3*3*5.分析:对n进行分解质因数,应先找到一个最小的质数k,然后按下述步骤完成:(1)如果这个质数恰等于n,则说明分解质因数的过程已经 ...
- solr的schema.xml配置属性解释
schema.xml做什么? SOLR加载数据,创建索引和数据时,核心数据结构的配置文件是schema.xml,该配置文件主要用于配置数据源,字段类型定义,搜索类型定义等.schema.xml的配置直 ...
- Python 单元测试 增强系统健壮性
问题背景交代 注意,JulyNovel只爬取免费小说,所有vip章节全部导航至起点网站,遵循robots协议,所有数据仅供学习用途,侵删 通过编写单元测试,提高JulyNovel系统可靠性 首先我们知 ...
- C# 设置textedit只能输入英文数字下划线,并且只能以英文开头(正则表达式)
this.textEdit1.Properties.Mask.EditMask = @"[a-zA-z][a-zA-Z0-9_]*";
- MVC ASP.NET MVC5使用Area区域
MVC ASP.NET MVC5使用Area区域 一.为什么要使用area? 在大型的ASP.NET mvc5项目中一般都有许多个功能模块,这些功能模块可以用Area(中文翻译为区域)把它们分离开来 ...
- 陌上花开(三维偏序)(cdq分治)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3262 其实就是三位偏序的模板,cdq分治入门题. 学习cdq分治请看__stdcall大 ...
- Android应用-底部导航栏的使用
目录 1. 设计底部导航栏页面 1.1. 创建必须的文件夹 1.2. 设计主页面 2. 设计逻辑函数 3. 项目展示 底部导航栏是基于Bottom Navigation Bar 插件使用的 这个插件包 ...