Android系统开发入门-10.native服务回调

上一小节我们添加了一个 native server,也写了一个 client 来做测试。但只是单向的从 client 调用 server,实际项目中我们经常是需要双向调用的。某些事件发生的时候,server 端需要通知 client 来处理。这节我们就来学习一下如何从 server 端回调 client。
首先我们要明确的是无论是从 client 调用 server, 还是 server 回调 client,本质上都是跨进程通信,都是需要借助 binder 框架的。

1. client 端更改

为了简单省事,我们直接在上一小节的 demo 基础上作修改, HelloNatvieTest.cpp 修改如下:

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
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
#include <utils/Errors.h>
#include <stdio.h>

using namespace android;

enum {
CMD_SAY_HELLO = 1,
CMD_CAL_SUM = 2,
CMD_CONNECT = 3
};

class Callback :public BBinder {
public:
enum {
CALLBACK_SAY_HELLO = 1,
};
status_t onTransact(uint32_t code, const Parcel &request, Parcel *reply, uint32_t flag) {
printf("Callback onTransact\n");
switch (code) {
case CALLBACK_SAY_HELLO:
const char* str = request.readCString();
printf("msg from server:%s\n", str);
break;
}

return BBinder::onTransact(code, request, reply, flag);
}

};

static sp<IBinder> service;

static void test_sayHello() {
Parcel request, reply;
request.writeCString("qiushao");
service->transact(CMD_SAY_HELLO, request, &reply);
}

static void test_calSum() {
Parcel request, reply;
request.writeInt32(2);
request.writeInt32(3);
service->transact(CMD_CAL_SUM, request, &reply);
int sum = reply.readInt32();
printf("sum of 2 + 3 = %d\n", sum);
}

static void test_connect(sp<Callback> callback) {
Parcel request, reply;
request.writeStrongBinder(callback);
service->transact(CMD_CONNECT, request, &reply);
}

int main () {
service = defaultServiceManager()->getService(String16("HelloNativeService"));
sp<Callback> callback = new Callback();
test_connect(callback);
test_sayHello();
test_calSum();
sleep(10);
return 0;
}

增加了一个 Callback 类,并且增加了一个 CMD_CONNECT 命令。
main 函数中创建了一个 Callback 对象,然后通过 writeStrongBinder 把这个对象传给 server。

2. server 端更改

HelloNativeService.cpp 修改如下:

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
#include <android/log.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include "HelloNativeService.h"

#define LOG_TAG "HelloNativeService"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

enum {
CMD_SAY_HELLO = 1,
CMD_CAL_SUM = 2,
CMD_CONNECT = 3
};

enum {
CALLBACK_SAY_HELLO = 1,
};

static void sayHello(const char *name) {
LOGD("hello %s from HelloNativeService", name);
}

static void echo(sp<IBinder> client, const char *name) {
Parcel request, reply;
char buff[1024];
memset(buff, 0, sizeof(buff));
sprintf(buff, "hello %s from HelloNativeService", name);
request.writeCString(buff);
client->transact(CALLBACK_SAY_HELLO, request, &reply);
}

static int sum(int a, int b) {
return a + b;
}

HelloNativeService::HelloNativeService() {
LOGD("HelloNativeService created");
}

int HelloNativeService::instantiate() {
int r = defaultServiceManager()->addService(String16("HelloNativeService"),
new HelloNativeService());
LOGD("add HelloNativeService r = %d", r);
return r;
}

status_t
HelloNativeService::onTransact(uint32_t code, const Parcel &request, Parcel *reply, uint32_t flag) {
LOGD("service onTransact code = %d", code);
switch (code) {
case CMD_SAY_HELLO: {
const char *name = request.readCString();
sayHello(name);
echo(client, name);
return NO_ERROR;
}

case CMD_CAL_SUM: {
int a = request.readInt32();
int b = request.readInt32();
reply->writeInt32(sum(a, b));
return NO_ERROR;
}

case CMD_CONNECT: {
client = request.readStrongBinder();
return NO_ERROR;
}
}
return BBinder::onTransact(code, request, reply, flag);

}

增加了一个 CMD_CONNECT 命令,通过 readStrongBinder 把 client 传送过来的 callback 对象给读取保存下来。后面需要回调客户端的时候只需要通过 client 这个 binder 就可以。
client binder 与 server binder 的一个差异是 client binder 对象不需要添加到系统服务里面去,而是通过 writeStrongBinder 直接传送给 server。

3. 编译验证

1
2
3
4
5
6
7
8
9
10
11
12
pure:/ # HelloNativeTest                      
Callback onTransact
msg from server:hello qiushao from HelloNativeService
sum of 2 + 3 = 5
pure:/ # logcat -s HelloNativeService
--------- beginning of system
--------- beginning of main
01-12 17:07:34.250 1645 1660 D HelloNativeService: service onTransact code = 3
01-12 17:07:34.252 1645 1660 D HelloNativeService: service onTransact code = 1
01-12 17:07:34.252 1645 1660 D HelloNativeService: hello qiushao from HelloNativeService
01-12 17:07:34.252 1645 1660 D HelloNativeService: service onTransact code = 2
130|pure:/ #