Android系统开发入门-12.hidl服务回调

上一小节我们已经完整的跑起来了一个 hidl 的 hello demo,这个 demo 虽然非常简单,但已经包含了 hidl 的大部分知识点了,我们只要在这个框架的基础上不断的扩展功能即可。
上一小节的demo 调用是单向的,即只能由 client 调用 service 的功能,但实际项目中我们是经常需要在 service 里面通知 client 某个事件发生了,需要 client 进行处理。也就是双向调用,或者称为 callback。下面我们在上一小节的基础上增加一个回调功能。

1. 增加回调 hal 接口

在 tvserver/1.0 目录下增加 ITVServerListener.hal 文件

1
2
3
4
5
package device.qiushao.pure.tvserver@1.0;

interface ITVServerListener {
oneway onMessage(string message);
};

2. ITVServer.hal 增加回调注册接口

1
2
3
4
5
6
7
package device.qiushao.pure.tvserver@1.0;
import ITVServerListener;
interface ITVServer {
hello(string name) generates (string result);
registerListener(uint32_t pid, ITVServerListener listener);
unregisterListener(uint32_t pid);
};

3. 更新 current.txt

current.txt 中增加 ITVServerListener 接口的 hash 值,先随便写一个,然后执行

1
./device/qiushao/pure/models/hidl/update-makefiles.sh

会提示 hash 值不对,更新 current.txt 即可,
两个 hal 接口的 hash 值都更新之后,再执行 update-makefiles.sh

4. 实现新增的 hal 接口

TVServer.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
...

#include <device/qiushao/pure/tvserver/1.0/ITVServerListener.h>
#include <map>
using namespace std;

...

class TVServer : public ITVServer {
public:
Return<void> hello(const hidl_string& name, hello_cb _hidl_cb) override;
Return<void> registerListener(const uint32_t pid, const sp<ITVServerListener>& listener) override;
Return<void> unregisterListener(const uint32_t pid) override;
private:
map<uint32_t, sp<ITVServerListener> > mListeners;
};

...

增加了 registerListener, unregisterListener 两个方法, 这两个方法的参数类型可以根据 hal 文件中声明的参数类型来推断。
hidl 与 c++ 的数据类型转换可以按下表来转换一下,给所有参数都加上 const
数据类型

hal 类型的参数,则使用 const sp& listener 这种智能指针的形式。
当然我们也可以使用 hidl-gen 来自动生成代码。参考上一小节的:根据 .hal 自动生成 cpp 实现。

TVServer.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
#include <android/log.h>
#define LOG_TAG "TVServer"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

...

Return<void> TVServer::hello(const hidl_string& name, hello_cb _hidl_cb) {
char buf[100];
::memset(buf, 0, 100);
::snprintf(buf, 100, "hello %s from TVServer", name.c_str());
hidl_string result(buf);
_hidl_cb(result);

LOGD("listener size = %d", mListeners.size());
map<uint32_t, sp<ITVServerListener> >::iterator it;
for (it = mListeners.begin(); it != mListeners.end(); ++it) {
sp<ITVServerListener> listener = it->second;
listener->onMessage("message from server");
}
return Void();
}

Return<void> TVServer::registerListener(const uint32_t pid, const sp<ITVServerListener>& listener) {
mListeners[pid] = listener;
LOGD("registerListener %d, %x", pid, listener.get());
return Void();
}

Return<void> TVServer::unregisterListener(const uint32_t pid) {
mListeners.erase(pid);
LOGD("unregisterListener %d", pid);
return Void();
}

5. 更新 manifest.xml

增加一个interface节点就行

1
2
3
4
5
6
7
8
9
10
11
12
13
<hal format="hidl">
<name>device.qiushao.pure.tvserver</name>
<transport>hwbinder</transport>
<version>1.0</version>
<interface>
<name>ITVServer</name>
<instance>default</instance>
</interface>
<interface>
<name>ITVServerListener</name>
<instance>default</instance>
</interface>
</hal>

6. 更新 client 

TVServerTest.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
#include <device/qiushao/pure/tvserver/1.0/ITVServer.h>
#include <device/qiushao/pure/tvserver/1.0/ITVServerListener.h>
#include <hidl/Status.h>
#include <utils/misc.h>
#include <hidl/HidlSupport.h>
#include <stdio.h>
#include <string>

using namespace std;

using ::android::hardware::hidl_string;
using ::android::sp;
using device::qiushao::pure::tvserver::V1_0::ITVServer;
using device::qiushao::pure::tvserver::V1_0::ITVServerListener;

class TVServerListener : public ITVServerListener {
public:
android::hardware::Return<void> onMessage(const hidl_string& message) override {
printf("onMessage:%s\n", message.c_str());
return android::hardware::Return<void>();
}
};

int main(){

sp<ITVServerListener> listener = new TVServerListener();

android::sp<ITVServer> service = ITVServer::getService();
if (service == nullptr){
printf("Failed to get service\n");
return -1;
}

service->registerListener(getpid(), listener);

service->hello("qiushao", [&](hidl_string result){
printf("%s\n", result.c_str());
});
sleep(1);

service->unregisterListener(getpid());
return 0;
}

7. 编译验证

整编系统,执行

1
2
3
4
5
6
7
8
9
10
11
pure:/ # TVServerTest                                                                                                                                                                                   
hello qiushao from TVServer
onMessage:message from server
pure:/ # logcat -s TVServer
--------- beginning of main
--------- beginning of system
01-18 13:21:27.414 1665 1903 D TVServer: registerListener 4466, b0443000
01-18 13:21:27.414 1665 1903 D TVServer: listener size = 1
01-18 13:21:28.415 1665 1903 D TVServer: unregisterListener 4466
^C
130|pure:/ #

可以看到收到了 onMessage 回调。