binder-编写应用层 C 代码

之前分析了binder的整体框架,现在来手动编写 client 以及 server,这样可以更深入地理解binder系统,当然你也可以直接略过自己编写代码的步骤,直接查看流程就行

client:

  • 首先肯定是打开驱动
  • 然后需要获取服务(handle)
  • 获取到服务之后,想要调用server进程的函数,server函数肯定是需要参数的(当然你也可以不传参数),所以需要先构造参数(binder_io)
  • 调用binder_call
  • binder_call返回一个binder_io
  • 分析返回的binder_io取出返回值

server:

  • 打开驱动
  • 注册服务
  • 循环读取ioctl
    • 解析数据

按照流程以及参考bctest.c文件,自己动手写一个服务

服务名称我们取名为 hello

这个服务提供了两个功能

一个是 sayHello 功能 ,打印 日志
一个是 sayHelloTo 功能 , 根据传过来的值打印

下面开始讲代码

这里先给出一个结构图,后面的代码都是按照流程编写的

server

首先编写server端的 C 代码

肯定有个main方法 ,其实我们可以参考bctest.c里的代码编写最简单的代码

首先肯定是打开驱动

binder_open("/dev/binder", 128*1024);

然后是添加服务

svcmgr_publish(bs,svcmgr,"hello",1);

第三个参数是服务的指针,可以直接传整型,也可以传引用,作为测试,我们直接传1

之后就是循环读取client的数据,我们参考 service_manager.c 里的处理,因为他本身也是一个server

binder_loop(bs, hello_handler);

下面是main的所有代码

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
int main(int argc, char **argv)
{
struct binder_state *bs;
uint32_t svcmgr = BINDER_SERVICE_MANAGER;
uint32_t handle;

//打开驱动
bs = binder_open("/dev/binder", 128*1024);
if (!bs) {
fprintf(stderr, "failed to open binder driver\n");
return -1;
}

int ret ;

//一个函数 注册服务
ret = svcmgr_publish(bs,svcmgr,"hello",1);
if (!ret) {
fprintf(stderr, "failed to publish hello\n");
return -1;
}
//如果你这里的handle使用的也是 1 ,那么svrmgr会报错 death already set
ret = svcmgr_publish(bs,svcmgr,"world",2);
if (!ret) {
fprintf(stderr, "failed to publish world\n");
}

//一个函数 循环来获取client发送的数据
binder_loop(bs, hello_handler);

return 0;
}

然后开始完善这些代码

首先完善 svcmgr_publish 注册服务的代码

注册服务的流程前面讲过,主要是通过调用binder_call方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int svcmgr_publish(struct binder_state *bs, uint32_t target, const char *name, void *ptr)
{
int status;
unsigned iodata[512/4];
struct binder_io msg, reply;

bio_init(&msg, iodata, sizeof(iodata), 4);
bio_put_uint32(&msg, 0); // strict mode header
bio_put_string16_x(&msg, SVC_MGR_NAME);
bio_put_string16_x(&msg, name);
bio_put_obj(&msg, ptr);

if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE))
return -1;

status = bio_get_uint32(&reply);

binder_done(bs, &msg, &reply);

return status;
}

完善 binder_loop 方法

binder_loop是binder.c中的函数,有两个参数

void binder_loop(struct binder_state *bs, binder_handler func)

res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);

binder_handler是需要我们编写的数据处理的函数

可以直接从例子中复制过来进行修改,取名为 hello_handler

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
int hello_handler(struct binder_state *bs,
struct binder_transaction_data *txn,
struct binder_io *msg,
struct binder_io *reply)
{
/*
根据txn.code 知道要调用哪个函数,
如果需要参数,可以从msg取出来
如果要返回结果,可以吧结果放入reply
*/
uint16_t *s;
size_t len;
uint32_t handle;
uint32_t strict_policy;
char name[512];


strict_policy = bio_get_uint32(msg);
s = bio_get_string16(msg, &len);

//根据client传过来的code 决定调用本地的什么函数
switch(txn->code) {
case HELLO_SERVER_CMD:
sayHello();
return 0;

case HELLO_SERVER_CMD_TO:
s = bio_get_string16(msg, &len);
if (s == NULL) {
return -1;
}
for(i = 0;i<len;i++)
name[i] = s[i];
name[i] = "\0";
handle = sayHelloTo(name);
//将数据放入reply 返回给 client
bio_put_uint32(reply, handle);
break;
default:
ALOGE("unknown code %d\n", txn->code);
return -1;
}
return 0;
}

client

根据上面的client流程 编写 client 端的main方法

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
int main(int argc, char **argv)
{
struct binder_state *bs;
uint32_t svcmgr = BINDER_SERVICE_MANAGER;
uint32_t handle;
int ret = 0;

bs = binder_open("/dev/binder", 128 * 1024);
if (!bs)
{
fprintf(stderr, "failed to open binder driver\n");
return -1;
}

// get service 想要获得 名字为 hello 的服务
// HELLO_SERVER_CMD 和 HELLO_SERVER_CMD_TO 是服务中的哪个函数
handle = svcmgr_lookup(bs, svcmgr, "hello", HELLO_SERVER_CMD);
handle = svcmgr_lookup(bs, svcmgr, "hello", HELLO_SERVER_CMD_TO);

if (!handle){
fprintf(stderr, "failed to get service\n");
return -1;
}

// send data to server
if(argc == 2){
// 这里的函数里面的代码和 svcmgr_lookup 函数类似
// 构造binder_io
// 放入参数
// 调用binder_call
// 从reply中解析出返回值
sayHello();
}else if(argc == 3){
ret = sayHelloTo(argv[2]);
fprintf(stderr, "say hello result :%d\n",ret);
}

return 0;
}

完善 svcmgr_lookup 函数

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
uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name,uint32_t code)
{
// 构造 binder_io
uint32_t handle;
unsigned iodata[512 / 4];
struct binder_io msg, reply;

//放入参数
bio_init(&msg, iodata, sizeof(iodata), 4);
bio_put_uint32(&msg, 0); // strict mode header
if (name) {
bio_put_string16_x(&msg, name);
}

//调用binder_call
if (binder_call(bs, &msg, &reply, target, code))
return 0;

//从reply中解析返回值
handle = bio_get_uint32(&reply);

if (handle)
binder_acquire(bs, handle);

binder_done(bs, &msg, &reply);

return handle;
}

下面是两个模块的所有代码

server

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/* Copyright 2008 The Android Open Source Project
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include "binder.h"

#define HELLO_SERVER_CMD 0
#define HELLO_SERVER_CMD_TO 1

uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name)
{
uint32_t handle;
unsigned iodata[512/4];
struct binder_io msg, reply;

bio_init(&msg, iodata, sizeof(iodata), 4);
bio_put_uint32(&msg, 0); // strict mode header
bio_put_string16_x(&msg, SVC_MGR_NAME);
bio_put_string16_x(&msg, name);

if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE))
return 0;

handle = bio_get_ref(&reply);

if (handle)
binder_acquire(bs, handle);

binder_done(bs, &msg, &reply);

return handle;
}

int svcmgr_publish(struct binder_state *bs, uint32_t target, const char *name, void *ptr)
{
int status;
unsigned iodata[512/4];
struct binder_io msg, reply;

bio_init(&msg, iodata, sizeof(iodata), 4);
bio_put_uint32(&msg, 0); // strict mode header
bio_put_string16_x(&msg, SVC_MGR_NAME);
bio_put_string16_x(&msg, name);
bio_put_obj(&msg, ptr);

if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE))
return -1;

status = bio_get_uint32(&reply);

binder_done(bs, &msg, &reply);

return status;
}

unsigned token;


int hello_handler(struct binder_state *bs,
struct binder_transaction_data *txn,
struct binder_io *msg,
struct binder_io *reply)
{
/*
根据txn.code 知道要调用哪个函数,
如果需要参数,可以从msg取出来
如果要返回结果,可以吧结果放入reply
*/
uint16_t *s;
size_t len;
uint32_t handle;
uint32_t strict_policy;
char name[512];


strict_policy = bio_get_uint32(msg);
s = bio_get_string16(msg, &len);

switch(txn->code) {
case HELLO_SERVER_CMD:
sayHello();
return 0;

case HELLO_SERVER_CMD_TO:
s = bio_get_string16(msg, &len);
if (s == NULL) {
return -1;
}
for(i = 0;i<len;i++)
name[i] = s[i];
name[i] = "\0";
handle = sayHelloTo(name);
bio_put_uint32(reply, handle);
break;
default:
ALOGE("unknown code %d\n", txn->code);
return -1;
}
return 0;
}

void sayHello(){
static int cnt =0;
fprintf(stderr, "say hello:%d\n",cnt++);
}

int sayHelloTo(char *name){
static int cnt =0;
fprintf(stderr, "say hello to: %s%d\n",name,cnt++);
return cnt;
}

int main(int argc, char **argv)
{
struct binder_state *bs;
uint32_t svcmgr = BINDER_SERVICE_MANAGER;
uint32_t handle;

bs = binder_open("/dev/binder", 128*1024);
if (!bs) {
fprintf(stderr, "failed to open binder driver\n");
return -1;
}

int ret ;

ret = svcmgr_publish(bs,svcmgr,"hello",1);
if (!ret) {
fprintf(stderr, "failed to publish hello\n");
return -1;
}
ret = svcmgr_publish(bs,svcmgr,"world",1);
if (!ret) {
fprintf(stderr, "failed to publish world\n");
}

binder_loop(bs, hello_handler);

return 0;
}

client

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
/* Copyright 2008 The Android Open Source Project
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include "binder.h"

#define HELLO_SERVER_CMD 0
#define HELLO_SERVER_CMD_TO 1

uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name,uint32_t code)
{
uint32_t handle;
unsigned iodata[512 / 4];
struct binder_io msg, reply;

bio_init(&msg, iodata, sizeof(iodata), 4);
bio_put_uint32(&msg, 0); // strict mode header
if (name) {
bio_put_string16_x(&msg, name);
}


if (binder_call(bs, &msg, &reply, target, code))
return 0;

handle = bio_get_uint32(&reply);

if (handle)
binder_acquire(bs, handle);

binder_done(bs, &msg, &reply);

return handle;
}



int main(int argc, char **argv)
{
struct binder_state *bs;
uint32_t svcmgr = BINDER_SERVICE_MANAGER;
uint32_t handle;
int ret = 0;

bs = binder_open("/dev/binder", 128 * 1024);
if (!bs)
{
fprintf(stderr, "failed to open binder driver\n");
return -1;
}

// get service

handle = svcmgr_lookup(bs, svcmgr, "hello", HELLO_SERVER_CMD);
handle = svcmgr_lookup(bs, svcmgr, "hello", HELLO_SERVER_CMD_TO);

if (!handle){
fprintf(stderr, "failed to get service\n");
return -1;
}

// send data to server
if(argc == 2){
sayHello();
}else if(argc == 3){
ret = sayHelloTo(argv[2]);
fprintf(stderr, "say hello result :%d\n",ret);
}

return 0;
}

void sayHello(){
//类似svcmgr_publish的代码
}

int sayHelloTo(char *name){
//类似svcmgr_publish的代码
}