NOTE
- 源码版本:Android 7.1.2。
- 内核版本:android-goldfish-3.4
- 内核下载:
git clone https://aosp.tuna.tsinghua.edu.cn/kernel/goldfish.git
(清华镜像站)
- 以下分析思路均来自老罗的《Android 系统源代码情景分析(修订版)》。
Binder 通信实践
- 基于之前介绍过的
Binder
通信库,我们可以写一个简单的应用实例来熟悉它的使用方法。
- 在参考书中,这个关于
Binder
的例子里实现了一个 Service
组件,这个组件负责管理一个虚拟的硬件设备 freg
,这个虚拟的设备是作者在介绍 HAL
层时实现的。这里我们只需要用到这个设备的内核驱动部分,所以首先我们要实现这个虚拟设备。
- 完成设备的驱动程序后,就要开始写我们的
Binder
实例了。这个实例分为三个模块:
common
:
- 实现硬件访问服务接口
IFregService
。
- 实现
Binder
本地对象类 BnFregService
与 Binder
代理对象类 BpFregService
。
server
:
- 实现了
Server
进程,其中包含了一个 Service
组件 FregService
。
client
:
- 实现了一个
Client
进程,它通过一个 BpFregService
代理对象去访问运行在 Server
进程中的 Service
组件 FregService
所提供的服务。
1. 为虚拟字符设备 Freg 编写驱动
- 在
/kernel/goldfish/drivers
下新建一个文件夹 freg
:
1.1 freg.h
- 定义四个字符串常量,分别描述
freg
在设备文件系统中的名称。
- 定义结构体
fake_reg_dev
描述虚拟设备 freg
:
val
:描述一个虚拟寄存器。
sem
:信号量,用于同步访问寄存器。
dev
:标准 Linux 字符设备结构体变量,用于标志 freg
为字符设备类型。
#ifndef _FAKE_REG_H_
#define _FAKE_REG_H_
#include <linux/cdev.h>
#include <linux/semaphore.h>
#define FREG_DEVICE_NODE_NAME "freg"
#define FREG_DEVICE_FILE_NAME "freg"
#define FREG_DEVICE_PROC_NAME "freg"
#define FREG_DEVICE_CLASS_NAME "freg"
struct fake_reg_dev {
int val;
struct semaphore sem;
struct cdev dev;
};
#endif
1.2 freg.c
- 向用户空间提供三个访问设备
freg
的寄存器 val
的接口:
proc
文件系统接口。
- 传统设备文件系统接口。
devfs
文件系统接口。
- 首先定义一些相关变量以及函数原型:
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include "freg.h"
static int freg_major = 0;
static int freg_minor = 0;
static struct class* freg_class = NULL;
static struct fake_reg_dev* freg_dev = NULL;
static int freg_open(struct inode* inode,
struct file* filp);
static int freg_release(struct inode* inode,
struct file* filp);
static ssize_t freg_read(struct file* filp,
char __user *buf,
size_t count,
loff_t* f_pos);
static ssize_t freg_write(struct file* filp,
const char __user *buf,
size_t count,
loff_t* f_pos);
static struct file_operations freg_fops = {
.owner = THIS_MODULE,
.open = freg_open,
.release = freg_release,
.read = freg_read,
.write = freg_write,
};
static ssize_t freg_val_show(struct device* dev,
struct device_attribute* attr,
char* buf);
static ssize_t freg_val_store(struct device* dev,
struct device_attribute* attr,
const char* buf,
size_t count);
static DEVICE_ATTR(val,
S_IRUGO | S_IWUSR,
freg_val_show,
freg_val_store);
- 实现传统设备文件操作:
freg_open
/ freg_release
:打开 / 关闭设备。
freg_read
/ freg_write
:读取 / 写入 val
。
static int freg_open(struct inode* inode,
struct file* filp)
{
struct fake_reg_dev* dev;
dev = container_of(inode->i_cdev, struct fake_reg_dev, dev);
filp->private_data = dev;
return 0;
}
static int freg_release(struct inode* inode,
struct file* filp)
{
return 0;
}
static ssize_t freg_read(struct file* filp,
char __user *buf,
size_t count,
loff_t* f_pos)
{
ssize_t err = 0;
struct fake_reg_dev* dev = filp->private_data;
if (down_interruptible(&(dev->sem)))
{
return -ERESTARTSYS;
}
if (count < sizeof(dev->val))
{
goto out;
}
if (copy