Binder 程序示例之 C++ 篇

7/26/2023

本文基于 Android10 源码环境

Android 源码中提供了一系列的 C++ 类(libbinder 库)来简化 Binder 驱动的使用。使得开发者能快速在 Android 系统源码中添加 Binder 服务和使用 Binder 服务。接下来我们使用 Android 源码中提供的辅助类和 C++ 语言来编写一个 Binder C++ 示例程序。

可以在这里 (opens new window)下载到示例程序。

使用 C++ 实现一个 Binder 服务分为以下几步:

  • 定义协议
  • 实现服务端协议
  • 实现客户端协议
  • 服务端程序实现
  • 客户端程序实现

# 1. 定义通信协议

通信协议由三部分组成:

  • 通信协议接口
  • 通信协议服务端实现
  • 通信协议客户端实现

接下来我们来实现通信协议接口 IHelloService, 接口继承自 IInterface,描述了名为 Hello 的 Binder 服务对外提供的功能。

//IHelloService.h  类名的起始字母需要是大写的 I
class IHelloService: public IInterface {

public:
    //DECLARE_META_INTERFACE 是一个宏,声明了一些变量和函数
    DECLARE_META_INTERFACE(HelloService);
    //Binder 服务对外提供的功能
    virtual void sayHello() = 0;
    virtual int sayHelloTo(const char *name) = 0;

};
1
2
3
4
5
6
7
8
9
10
11

# 2. 通信协议服务端实现

通信协议服务端实现是一个继承自 BnInterface<IHelloService> 的类:

//声明
//IHelloService.h
class BnHelloService: public BnInterface<IHelloService> {

public:
    //服务端收到数据后的回调
    status_t onTransact(uint32_t code, const Parcefl& data, Parcel* reply, uint32_t lags = 0);
    void sayHello();
    int sayHelloTo(const char *name);
};


//实现
//BnHelloService.cpp
#define LOG_TAG "HelloService"
#include <log/log.h>
#include "IHelloService.h"


//服务端收到数据的回调
status_t BnHelloService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
    //code 表示客户端需要调用哪个函数
    switch(code) {
        //调用 sayhello
        case HELLO_SVR_CMD_SAYHELLO:  {
            //调用 sayhello 函数
            sayHello();
            //写入回复给客户端的数据
            reply->writeInt32(0);
            return NO_ERROR;
        } break;
        //调用 sayhelloto
        case HELLO_SVR_CMD_SAYHELLO_TO: {
            //取出客户端发送的参数
            int32_t policy =  data.readInt32();
			String16 name16_tmp = data.readString16(); 

			String16 name16 = data.readString16();
			String8 name8(name16);
            //调用 sayHelloTo 函数
			int cnt = sayHelloTo(name8.string());
            //写入回复给客户端的数据
			reply->writeInt32(0); 
			reply->writeInt32(cnt);

            return NO_ERROR;
        } break;
  
        default:
            return BBinder::onTransact(code, data, reply, flags);
  
    }
}

//服务端函数的具体实现
void BnHelloService::sayHello() {
    static int count = 0;
    ALOGI("say hello :%d\n ", ++count);
}

int BnHelloService::sayHelloTo(const char *name) {
    static int cnt = 0;
	ALOGI("say hello to %s : %d\n", name, ++cnt);
	return cnt;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65

为叙述方便我们称 BnHelloService 以及同类型的类为 Binder 服务类

# 3. 通信协议客户端协议实现

客户端协议实现是一个继承自 BpInterface<IHelloService> 的类

//客户端
//IHelloService.h
class BpHelloService: public BpInterface<IHelloService> {
public:
    BpHelloService(const sp<IBinder>& impl);
    void sayHello();
    int sayHelloTo(const char *name);
};


//BpHelloService.cpp
#include "IHelloService.h"

//调用父类构造函数
BpHelloService::BpHelloService(const sp<IBinder>& impl):BpInterface<IHelloService>(impl) {

}

void BpHelloService::sayHello() {
    Parcel data, reply;
    data.writeInt32(0);
    data.writeString16(String16("IHelloService"));
    //发起远程调用
    remote()->transact(HELLO_SVR_CMD_SAYHELLO, data, &reply);
}

int BpHelloService::sayHelloTo(const char *name) {
    Parcel data, reply;
    int exception;

    data.writeInt32(0);
    data.writeString16(String16("IHelloService"));
    data.writeString16(String16(name));
    //发起远程调用
    remote()->transact(HELLO_SVR_CMD_SAYHELLO_TO, data, &reply);
    exception = reply.readInt32();
	if (exception)
		return -1;
	else
		return reply.readInt32();
}

    IMPLEMENT_META_INTERFACE(HelloService, "IHelloService");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

为叙述方便我们称 BpHelloService 以及同类型的类为 Binder 代理类

# 4. 服务端程序实现

int main(int argc, char const *argv[])
{
    //使用 ProcessState 类完成 binder 驱动的初始化
    sp<ProcessState> proc(ProcessState::self());
    //注册服务
    sp<IServiceManager> sm = defaultServiceManager();
    sm->addService(String16("hello"), new BnHelloService());

    //开启 binder 线程池
	ProcessState::self()->startThreadPool();
    //加入线程池
	IPCThreadState::self()->joinThreadPool();
  
    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 5. 客户端程序实现

int main(int argc, char const *argv[])
{
    //使用 ProcessState 类完成 binder 驱动的初始化
    sp<ProcessState> proc(ProcessState::self());
    //获取 hello 服务
    sp<IServiceManager> sm = defaultServiceManager();
    //返回的是 BpBinder 指针
    sp<IBinder> binder = sm->getService(String16("hello"));
    sp<IHelloService> service = interface_cast<IHelloService>(binder);

    if (binder == 0)
	{
		ALOGI("can't get hello service\n");
		return -1;
	}

    //发起远程调用
    service->sayHello();
    int cnt = service->sayHelloTo("nihao");
	ALOGI("client call sayhello_to, cnt = %d", cnt);

    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 6. 编译运行

项目根目录下添加 Android.bp

cc_binary {
    name: "MyCppBinderServer",
    srcs: ["BinderServer.cpp", "BnHelloService.cpp","BpHelloService.cpp"],
    shared_libs: [
        "liblog",
        "libcutils",
        "libutils",
        "libbinder",
    ],
}


cc_binary {
    name: "MyCppBinderClient",
    srcs: ["BinderClient.cpp", "BpHelloService.cpp"],
    shared_libs: [
        "liblog",
        "libcutils",
        "libutils",
        "libbinder",
    ],
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

将项目放到 aosp 任意目录下,然后执行以下命令:

source build/envsetup.sh
lunch aosp_x86_64-eng
#启动模拟器
emulator
1
2
3
4

进入到项目目录 device/jelly/rice14/BinderCppDemo,然后执行单编命令:

mm
1

编译完成后,将程序上传到模拟器并执行。

传输可执行文件到模拟器:

adb push out/target/product/generic_x86_64/symbols/system/bin/MyCppBinderServer /data/local/tmp

adb push out/target/product/generic_x86_64/symbols/system/bin/MyCppBinderClient /data/local/tmp

1
2
3
4

接下来 adb shell 进入模拟器 shell 环境:

adb shell
cd /data/local/tmp
./MyCppBinderServer
# 从新开一个终端进入 adb shell
cd /data/local/tmp
./MyCppBinderClient
1
2
3
4
5
6

最后通过 logcat 查看执行结果:

# 关于

我叫阿豪,2015 年本科毕业于国防科学技术大学指挥信息系统专业,毕业后从事信息化装备的研发工作,主要研究方向是 Android Framework 与 Linux Kernel。

如果你对 Android Framework 感兴趣或者正在学习 Android Framework,可以关注我的微信公众号和抖音,我会持续分享我的学习经验,帮助正在学习的你少走一些弯路。学习过程中如果你有疑问或者你的经验想要分享给大家可以添加我的微信,我拉你进技术交流群。