Android Binder 机制初步学习 笔记(四,完结)—— Binder 简单应用示例


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 实例了。这个实例分为三个模块:
    1. common
      • 实现硬件访问服务接口 IFregService
      • 实现 Binder 本地对象类 BnFregServiceBinder 代理对象类 BpFregService
    2. server
      • 实现了 Server 进程,其中包含了一个 Service 组件 FregService
    3. client
      • 实现了一个 Client 进程,它通过一个 BpFregService 代理对象去访问运行在 Server 进程中的 Service 组件 FregService 所提供的服务。

1. 为虚拟字符设备 Freg 编写驱动

  • /kernel/goldfish/drivers 下新建一个文件夹 freg
    • mkdir 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"

/* 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
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
千里马8年Android系统及应用开发经验,曾担任过美国unokiwi公司移动端技术总监兼架构师,对系统开发,性能优化,应用高级开发有深入的研究,Android开源定制ROM Lineage的贡献者之一,国内首家线下开辟培训Android Framework课程,拥有2年的Android系统培训经验。成为腾讯课堂专业负责android framework课程分享第一人,致力于提高国内android Framework水平Android Framework领域内是国内各大手机终端科技公司需要的人才,应用开发者都对Android系统充满着好奇,其中的binder是重中之重,都说无binderAndroidbinde是Android系统的任督二脉。课程水平循序渐进,由中级再到高级,满足各个层次水平的android开发者。1、灵活使用binder跨进程通信,在app端对它的任何api方法等使用自如2、可以单独分析android系统源码中任何binder部分,分析再也没有难度3、掌握binder驱动本质原理,及对应binder驱动怎么进行跨进程通信,及内存等拷贝方式数据等4、对binder从上层的java app端一直到最底层的内核binder驱动,都可以顺利理通5、针对系统开发过程中遇到的binder报错等分析方法,及binder bug案例学习6、针对面试官任何的binder问题都可以对答自如7、socket这种跨进程通信实战使用8、针对android源码使用的socket源码轻松掌握9、android系统源码中最常见的socketpair中双向跨进程通信10、使用socket实现一个可以让app执行shell命令的程序

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值