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

  • NOTE
  • Binder 通信实践
    • 为虚拟字符设备 Freg 编写驱动
      • 1 fregh
      • 2 fregc
      • 3 Kconfig
      • 4 Makefile
      • 5 编译内核驱动模块
    • Binder 实例 Common 模块
      • 1 IFregServiceh
      • 2 IFregServicecpp
    • Binder 实例 Server 模块
      • 1 FregServercpp
      • 2 Androidmk
    • Binder 实例 Client 模块
      • 1 FregClientcpp
      • 2 Androidmk
    • 测试结果


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 
#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

1.2 freg.c

  • 向用户空间提供三个访问设备 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);

1.3 Kconfig

  • 驱动程序写完后,需要继续编写一些编译配置文件。
  • 这个文件定义了驱动的编译选项。
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"

1.4 Makefile

  • 这个驱动的编译脚本很简单,只有一行:
    • obj-$(CONFIG_FREG) += freg.o
  • 相应地,我们也需要修改内核的 Makefile 文件:
    • drivers/Makefile
    • 添加语句:obj-$(CONFIG_FREG) += freg/

1.5 编译内核驱动模块

  • 指令 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,就能使用编译好的内核了。

2. Binder 实例 —— Common 模块

  • ./external/binder 文件夹下创建 common 文件夹:
    • mkdir common
    • 进入 cd common

2.1 IFregService.h

  • 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

2.2 IFregService.cpp

  • 定义枚举变量,表示进程间通信代码:
    • 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 应指向一个类型为 BnFregServiceBinder 本地对象,或一个类型为 BpBinderBinder 代理对象,否则其返回值为 NULL
      • 若指向本地对象,则调用成员函数 queryLocalInterface 直接返回一个 IFregService 接口。
      • 若指向代理对象,则成员函数 queryLocalInterface 返回 NULL,随后将其封装成一个 BpFregService 对象,并将它的 IFregService 接口返回。
  • 实现了 BnFregService 类成员函数 onTransact
    • 负责将 GET_VALSET_VAL 请求分发给其子类的成员函数 getValsetVal 处理。
    • BnFregService 的子类为 FregService,其具体实现了 getValsetVal
#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);
                }
        }
}

3. Binder 实例 —— Server 模块

  • ./external/binder 文件夹下创建 common 文件夹:
    • mkdir server
    • 进入 cd server

3.1 FregServer.cpp

  • 首先实现了一个 Service 组件类 FregService
    • 继承了 BnFregService,并具体实现了 IFregService 接口。
    • 构造函数中,调用 open 函数来打开设备文件 /dev/freg,并将得到的文件描述符保存在成员变量 fd 中。
    • 相应地,析构函数中则会关闭设备文件。
    • getValsetVal 都会通过打开的设备文件对其寄存器进行读写操作。
    • 静态成员函数 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;
}

3.2 Android.mk

  • 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)

4. Binder 实例 —— Client 模块

  • ./external/binder 文件夹下创建 common 文件夹:
    • mkdir server
    • 进入 cd server

4.1 FregClient.cpp

  • 首先调用 defaultServiceManager() 获取 Service Manager 的代理对象。
  • 调用代理对象成员函数 getService 获取名为 "stone.FregService"Service 组件的一个类型为 BpBinder 的代理对象。
  • BpBinder 代理对象封装成 BpFregService 代理对象,获取其 IFregService 接口,保存在变量 service 中。
  • 通过 service->getVal() 获取寄存器的当前值,并打印。
  • 通过 service->setVal() 设置寄存器的值,这个值为当前值加一。
  • 再次通过 service->getVal() 获取寄存器值并打印。
  • 可以预见到的结果是,运行 FregClient 后屏幕上应有的输出应该是:nn + 1
  • 由于寄存器值初始化为 0,所以第一次运行 FregClient 时输出应为 01
  • 可以预见到的是,第二次运行 FregClient 时输出为 12
#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;
}

4.2 Android.mk

  • 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)

5. 测试结果

  • 回到 Android 根目录下:
    • mmm ./external/binder/server/
    • mmm ./external/binder/client/
    • make snod
  • 编译成功后:
    • emulator -kernel kernel/goldfish/arch/arm/boot/zImage &
    • adb shell
  • 接下来的操作与输出如下:
    • 启动 FregServer 模块。
    • 启用一次 FregClient 观察到两个值:01
    • 启用第二次 FregClient 观察到两个值:12
  • 实测结果与 4.1 中的分析一致,说明这个实例已经成功运作了。

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.

你可能感兴趣的:(Android-源码分析)