git clone https://aosp.tuna.tsinghua.edu.cn/kernel/goldfish.git
(清华镜像站)Binder
通信库,我们可以写一个简单的应用实例来熟悉它的使用方法。Binder
的例子里实现了一个 Service
组件,这个组件负责管理一个虚拟的硬件设备 freg
,这个虚拟的设备是作者在介绍 HAL
层时实现的。这里我们只需要用到这个设备的内核驱动部分,所以首先我们要实现这个虚拟设备。Binder
实例了。这个实例分为三个模块: common
: IFregService
。Binder
本地对象类 BnFregService
与 Binder
代理对象类 BpFregService
。server
: Server
进程,其中包含了一个 Service
组件 FregService
。client
: Client
进程,它通过一个 BpFregService
代理对象去访问运行在 Server
进程中的 Service
组件 FregService
所提供的服务。/kernel/goldfish/drivers
下新建一个文件夹 freg
: mkdir freg
freg
在设备文件系统中的名称。fake_reg_dev
描述虚拟设备 freg
: val
:描述一个虚拟寄存器。sem
:信号量,用于同步访问寄存器。dev
:标准 Linux 字符设备结构体变量,用于标志 freg
为字符设备类型。#ifndef _FAKE_REG_H_
#define _FAKE_REG_H_
#include
#include
#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
freg
的寄存器 val
的接口: proc
文件系统接口。devfs
文件系统接口。#include
#include
#include
#include
#include
#include
#include
#include "freg.h"
/* the major/minor device number */
static int freg_major = 0;
static int freg_minor = 0;
/* types and struct of the device */
static struct class* freg_class = NULL;
static struct fake_reg_dev* freg_dev = NULL;
/* traditional operations */
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);
/* traditional operations list */
static struct file_operations freg_fops = {
.owner = THIS_MODULE,
.open = freg_open,
.release = freg_release,
.read = freg_read,
.write = freg_write,
};
/* device properties operation of filesystem 'devfs' */
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);
/* devfs filesystem's device properties */
static DEVICE_ATTR(val,
S_IRUGO | S_IWUSR,
freg_val_show,
freg_val_store);
freg_open
/ freg_release
:打开 / 关闭设备。freg_read
/ freg_write
:读取 / 写入 val
。/* open this device */
static int freg_open(struct inode* inode,
struct file* filp)
{
struct fake_reg_dev* dev;
/* save our struct to the private_data of file pointer */
dev = container_of(inode->i_cdev, struct fake_reg_dev, dev);
filp->private_data = dev;
return 0;
}
/* release this device */
static int freg_release(struct inode* inode,
struct file* filp)
{
return 0;
}
/* read the value from the device */
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;
/* synchronize */
if (down_interruptible(&(dev->sem)))
{
return -ERESTARTSYS;
}
if (count < sizeof(dev->val))
{
goto out;
}
/* copy value to the buffer */
if (copy_to_user(buf, &(dev->val), sizeof(dev->val)))
{
err = -EFAULT;
goto out;
}
err = sizeof(dev->val);
out:
up(&(dev->sem));
return err;
}
/* write value to the device */
static ssize_t freg_write(struct file* filp,
const char __user *buf,
size_t count,
loff_t* f_pos)
{
ssize_t err = 0;
struct fake_reg_dev* dev = filp->private_data;
/* synchronize */
if (down_interruptible(&(dev->sem)))
{
return -ERESTARTSYS;
}
if (count != sizeof(dev->val))
{
goto out;
}
/* copy buffer to the value */
if (copy_from_user(&(dev->val), buf, count))
{
err = -EFAULT;
goto out;
}
err = sizeof(dev->val);
out:
up(&(dev->sem));
return err;
}
devfs
文件系统接口: val
当做设备的一个属性,通过读写熟悉达到访问目的。freg_val_show
:读取 val
。freg_val_store
:写入 val
。proc
文件系统接口,将一些共通的操作提取出来,写成两个内部函数 __freg_get_val
与 __freg_set_val
。/* read dev->val to buffer */
static ssize_t __freg_get_val(struct fake_reg_dev* dev,
const char* buf)
{
int val = 0;
if (down_interruptible(&(dev->sem)))
{
return -ERESTARTSYS;
}
val = dev->val;
up(&(dev->sem));
return snprintf(buf, PAGE_SIZE, "%d\n", val);
}
/* write buffer value to dev->val */
static ssize_t __freg_set_val(struct fake_reg_dev* dev,
const char* buf,
size_t count)
{
int val = 0;
/* str to int */
val = simple_strtol(buf, NULL, 10);
if (down_interruptible(&(dev->sem)))
{
return -ERESTARTSYS;
}
dev->val = val;
up(&(dev->sem));
return count;
}
/* read device properties value */
static ssize_t freg_val_show(struct device* dev,
struct device_attribute* attr,
char* buf)
{
struct fake_reg_dev* hdev = (struct fake_reg_dev*) dev_get_drvdata(dev);
return __freg_get_val(hdev, buf);
}
/* write value to device properties */
static ssize_t freg_val_store(struct device* dev,
struct device_attribute* attr,
const char* buf,
size_t count)
{
struct fake_reg_dev* hdev = (struct fake_reg_dev*) dev_get_drvdata(dev);
return __freg_set_val(hdev, buf, count);
}
proc
文件系统接口: freg_proc_read
/ freg_proc_write
:寄存器读写操作。freg_create_proc
/ freg_remove_proc
:创建 / 删除 /proc/freg
文件。creat
的时候,原本有一句 entry->owner = THIS_MODULE
的,但是在这个版本里不需要。/* read dev->val to page buffer */
static ssize_t freg_proc_read(char* page,
char** start,
off_t off,
int count,
int* eof,
void* data)
{
if (off > 0)
{
*eof = 1;
return 0;
}
return __freg_get_val(freg_dev, page);
}
/* save buffer value to dev->val */
static ssize_t freg_proc_write(struct file* filp,
const char __user *buff,
unsigned long len,
void* data)
{
int err = 0;
char* page = NULL;
if (len > PAGE_SIZE)
{
printk(KERN_ALERT"The buff is too large: %lu.\n", len);
return -EFAULT;
}
page = (char*) __get_free_page(GFP_KERNEL);
if (!page)
{
printk(KERN_ALERT"Failed to alloc page.\n");
return -ENOMEM;
}
/* copy user buffer to kernel buffer */
if (copy_from_user(page, buff, len))
{
printk(KERN_ALERT"Failed to copy buff from user.\n");
err = -EFAULT;
goto out;
}
err = __freg_set_val(freg_dev, page, len);
out:
free_page((unsigned long) page);
return err;
}
/* create file 'proc/freg' */
static void freg_create_proc(void)
{
struct proc_dir_entry* entry;
entry = create_proc_entry(FREG_DEVICE_PROC_NAME, 0, NULL);
if (entry)
{
entry->read_proc = freg_proc_read;
entry->write_proc = freg_proc_write;
}
}
/* remove file 'proc/freg' */
static void freg_remove_proc(void)
{
remove_proc_entry(FREG_DEVICE_PROC_NAME, NULL);
}
freg_init
:注册与初始化 freg
。freg_exit
:反注册与释放 freg
。setup
中,采用了 sema_init(&(dev->sem), 1)
来初始化信号量,而在源码分析的原文中,这里用的是 init_MUTEX(&(dev->sem))
,但目前这个操作已经被弃用了。/* init device */
static int __freg_setup_dev(struct fake_reg_dev* dev)
{
int err;
dev_t devno = MKDEV(freg_major, freg_minor);
memset(dev, 0, sizeof(struct fake_reg_dev));
/* init cdev */
cdev_init(&(dev->dev), &freg_fops);
dev->dev.owner = THIS_MODULE;
dev->dev.ops = &freg_fops;
/* register cdev */
err = cdev_add(&(dev->dev), devno, 1);
if (err)
{
return err;
}
/* init freg_dev */
sema_init(&(dev->sem), 1);
dev->val = 0;
return 0;
}
/* load module */
static int __init freg_init(void)
{
int err = -1;
dev_t dev = 0;
struct device* temp = NULL;
printk(KERN_ALERT"Initializing freg device.\n");
/* dynamic allocation of the major and minor number */
err = alloc_chrdev_region(&dev, 0, 1, FREG_DEVICE_NODE_NAME);
if (err < 0)
{
printk(KERN_ALERT"Failed to alloc char dev region.\n");
goto fail;
}
freg_major = MAJOR(dev);
freg_minor = MINOR(dev);
/* alloc struct freg */
freg_dev = kmalloc(sizeof(struct fake_reg_dev), GFP_KERNEL);
if (!freg_dev)
{
err = -ENOMEM;
printk(KERN_ALERT"Failed to alloc freg device.\n");
goto unregister;
}
/* init device */
err = __freg_setup_dev(freg_dev);
if (err)
{
printk(KERN_ALERT"Failed to setup freg device: %d.\n", err);
goto cleanup;
}
/* create freg_class dir 'freg' in '/sys/class' */
freg_class = class_create(THIS_MODULE, FREG_DEVICE_CLASS_NAME);
if (IS_ERR(freg_class))
{
err = PTR_ERR(freg_class);
printk(KERN_ALERT"Failed to create freg device class.\n");
goto destroy_cdev;
}
/* create dir 'freg' in '/dev/' and 'sys/class/freg' */
temp = device_create(freg_class, NULL, dev, NULL, "%s", FREG_DEVICE_FILE_NAME);
if (IS_ERR(freg_class))
{
err = PTR_ERR(temp);
printk(KERN_ALERT"Falied to create freg device.\n");
goto destroy_class;
}
/* create properties dir 'val' in 'sys/class/freg/freg' */
err = device_create_file(temp, &dev_attr_val);
if (err < 0)
{
printk(KERN_ALERT"Failed to create attribute val of freg device.\n");
goto destroy_device;
}
dev_set_drvdata(temp, freg_dev);
/* create 'proc/freg' */
freg_create_proc();
printk(KERN_ALERT"Succeeded to initialize freg device.\n");
return 0;
destroy_device:
device_destroy(freg_class, dev);
destroy_class:
class_destroy(freg_class);
destroy_cdev:
cdev_del(&(freg_dev->dev));
cleanup:
kfree(freg_dev);
unregister:
unregister_chrdev_region(MKDEV(freg_major, freg_minor), 1);
fail:
return err;
}
/* unload module */
static void __exit freg_exit(void)
{
dev_t devno = MKDEV(freg_major, freg_minor);
printk(KERN_ALERT"Destroy freg device.\n");
/* delete '/proc/freg' */
freg_remove_proc();
/* destroy device and its class */
if (freg_class)
{
device_destroy(freg_class, MKDEV(freg_major, freg_minor));
class_destroy(freg_class);
}
/* delete cdev and release mem */
if (freg_dev)
{
cdev_del(&(freg_dev->dev));
kfree(freg_dev);
}
/* release devno */
unregister_chrdev_region(devno, 1);
}
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Fake Register Driver");
module_init(freg_init);
module_exit(freg_exit);
config FREG
tristate "Fake Register Driver"
default n
help
This is the freg driver for android system.
freg
文件夹下写好这个文件后,还要去修改内核的 Kconfig
文件,否则无法编译我们加入的新内核驱动。kernel/goldfish/drivers/Kconfig
中,加入: source "drivers/freg/Kconfig"
obj-$(CONFIG_FREG) += freg.o
drivers/Makefile
obj-$(CONFIG_FREG) += freg/
make menuconfig
配置编译方式: Device Drivers
项,按下 Enter
。Fake Register Driver
项,按下 Y
。make
,成功后会有提示: Kernel: arch/arm/boot/zImage is ready
emulator
的时候,加上 -kernel kernel/goldfish/arch/arm/boot/zImage
,就能使用编译好的内核了。./external/binder
文件夹下创建 common
文件夹: mkdir common
cd common
FREG_SERVICE
描述了该 Service
组件注册到 Service Manager
的名称。IFregService
: getVal
:读取硬件设备 freg
中寄存器 val
的值。setVal
:写入 val
值。Binder
本地对象类 BnFregService
: onTransact
,用于处理收到的信息。DECLARE_META_INTERFACE
: IFregService
类的元接口。descriptor
,用于描述接口名。getInterfaceDescriptor
,用于获取接口名。asInterface
,用于将一个 IBinder
对象转换为 IFregService
接口。IFregService
的构造与析构函数。#ifndef IFREGSERVICE_H_
#define IFREGSERVICE_H_
#include
#include
#include
#define FREG_SERVICE "stone.FregService"
using namespace android;
class IFregService : public IInterface
{
public :
DECLARE_META_INTERFACE(FregService);
virtual int32_t getVal() = 0;
virtual void setVal(int32_t val) = 0;
};
class BnFregService : public BnInterface
{
public :
virtual status_t onTransact(uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
};
#endif
GET_VAL
:对应成员函数 getVal
。SET_VAL
:对应成员函数 setVal
。Binder
代理对象类 BpFregService
,它实现了 IFregService
接口: getVal
: Parcel
对象中。remote
函数获得一个 BpBinder
代理对象。transact
来请求运行在 Server
进程中的一个 Binder
本地对象执行一个 GET_VAL
操作。Parcel
对象中返回。setVal
: Parcel
对象中。BpBinder
代理对象。transact
请求 SET_VAL
操作。SET_VAL
操作将一个整数写入到设备 freg
的寄存器中。IMPLEMENT_META_INTERFACE
: IFregService
类的元接口。"stone.IFregService"
。IFregService
类的构造,析构函数(空实现)。getInterfaceDescriptor
。asInterface
: obj
应指向一个类型为 BnFregService
的 Binder
本地对象,或一个类型为 BpBinder
的 Binder
代理对象,否则其返回值为 NULL
。queryLocalInterface
直接返回一个 IFregService
接口。queryLocalInterface
返回 NULL
,随后将其封装成一个 BpFregService
对象,并将它的 IFregService
接口返回。BnFregService
类成员函数 onTransact
: GET_VAL
与 SET_VAL
请求分发给其子类的成员函数 getVal
与 setVal
处理。BnFregService
的子类为 FregService
,其具体实现了 getVal
与 setVal
。#define LOG_TAG "IFregService"
#include
#include "IFregService.h"
using namespace android;
enum
{
GET_VAL = IBinder::FIRST_CALL_TRANSACTION,
SET_VAL
};
class BpFregService : public BpInterface
{
public :
BpFregService(const sp& impl)
: BpInterface(impl)
{
}
int32_t getVal()
{
Parcel data;
data.writeInterfaceToken(IFregService::getInterfaceDescriptor());
Parcel reply;
remote()->transact(GET_VAL, data, &reply);
int32_t val = reply.readInt32();
return val;
}
void setVal(int32_t val)
{
Parcel data;
data.writeInterfaceToken(IFregService::getInterfaceDescriptor());
data.writeInt32(val);
Parcel reply;
remote()->transact(SET_VAL, data, &reply);
}
};
IMPLEMENT_META_INTERFACE(FregService, "stone.IFregService");
status_t BnFregService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code)
{
case GET_VAL:
{
CHECK_INTERFACE(IFregService, data, reply);
int32_t val = getVal();
reply->writeInt32(val);
return NO_ERROR;
}
case SET_VAL:
{
CHECK_INTERFACE(IFregService, data, reply);
int32_t val = data.readInt32();
setVal(val);
return NO_ERROR;
}
default:
{
return BBinder::onTransact(code, data, reply, flags);
}
}
}
./external/binder
文件夹下创建 common
文件夹: mkdir server
cd server
Service
组件类 FregService
: BnFregService
,并具体实现了 IFregService
接口。open
函数来打开设备文件 /dev/freg
,并将得到的文件描述符保存在成员变量 fd
中。getVal
与 setVal
都会通过打开的设备文件对其寄存器进行读写操作。instantiate
负责将 FregService
组件注册到 Service Manager
中,并将注册名设置为 "stone.FregService"
,如此一来,Client
进程就能通过该名称获取这个 FregService
组件的一个代理对象了。main
函数即是该 Server
进程的主函数: instantiate
注册组件。ProcessState
对象成员函数 startThreadPool
启动 Binder
线程池。IPCThreadState
对象的成员 joinThreadPool
将主线程添加到进程 Binder
线程池中,用于处理来自 Client
的通信请求。#define LOG_TAG "FregServer"
#include
#include
#include
#include
#include
#include "../common/IFregService.h"
#define FREG_DEVICE_NAME "/dev/freg"
class FregService : public BnFregService
{
public :
FregService()
{
fd = open(FREG_DEVICE_NAME, O_RDWR);
if (-1 == fd)
{
ALOGE("Failed to open device %s.\n", FREG_DEVICE_NAME);
}
}
virtual ~FregService()
{
if (fd != -1)
{
close(fd);
}
}
public :
static void instantiate()
{
defaultServiceManager()->addService(String16(FREG_SERVICE), new FregService());
}
int32_t getVal()
{
int32_t val = 0;
if (fd != -1)
{
read(fd, &val, sizeof(val));
}
return val;
}
void setVal(int32_t val)
{
if (fd != -1)
{
write(fd, &val, sizeof(val));
}
}
private :
int fd;
};
int main(int argc, char** argv)
{
FregService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
return 0;
}
server
模块的编译脚本。LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := ../common/IFregService.cpp \
FregServer.cpp
LOCAL_SHARED_LIBRARIES := libcutils libutils libbinder
LOCAL_MODULE := FregServer
include $(BUILD_EXECUTABLE)
./external/binder
文件夹下创建 common
文件夹: mkdir server
cd server
defaultServiceManager()
获取 Service Manager
的代理对象。getService
获取名为 "stone.FregService"
的 Service
组件的一个类型为 BpBinder
的代理对象。BpBinder
代理对象封装成 BpFregService
代理对象,获取其 IFregService
接口,保存在变量 service
中。service->getVal()
获取寄存器的当前值,并打印。service->setVal()
设置寄存器的值,这个值为当前值加一。service->getVal()
获取寄存器值并打印。FregClient
后屏幕上应有的输出应该是:n
与 n + 1
。0
,所以第一次运行 FregClient
时输出应为 0
和 1
。FregClient
时输出为 1
和 2
。#define LOG_TAG "FregClient"
#include
#include
#include "../common/IFregService.h"
int main()
{
sp binder = defaultServiceManager()->getService(String16(FREG_SERVICE));
if (binder == NULL)
{
ALOGE("Failed to get freg service: %s.\n", FREG_SERVICE);
return -1;
}
sp service = IFregService::asInterface(binder);
if (service == NULL)
{
ALOGE("Failed to get freg service interface.\n");
return -2;
}
printf("Read original value from FregService:\n");
int32_t val = service->getVal();
printf(" %d.\n", val);
printf("Add value 1 to FregService.\n");
val += 1;
service->setVal(val);
printf("Read the value from FregService again:\n");
val = service->getVal();
printf(" %d.\n", val);
return 0;
}
client
模块的编译脚本。LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := ../common/IFregService.cpp \
FregClient.cpp
LOCAL_SHARED_LIBRARIES := libcutils libutils libbinder
LOCAL_MODULE := FregClient
include $(BUILD_EXECUTABLE)
Android
根目录下: mmm ./external/binder/server/
mmm ./external/binder/client/
make snod
emulator -kernel kernel/goldfish/arch/arm/boot/zImage &
adb shell
FregServer
模块。FregClient
观察到两个值:0
和 1
。FregClient
观察到两个值:1
和 2
。generic:/ # FregServer &
[1] 1139
generic:/ # FregClient
Read original value from FregService:
0.
Add value 1 to FregService.
Read the value from FregService again:
1.
generic:/ # FregClient
Read original value from FregService:
1.
Add value 1 to FregService.
Read the value from FregService again:
2.