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 回调。