三、回调函数
我们把HAL 独立为一个单独的进程,Client 也是一个单独的进程,那么对于一般的模块而言,都是需要从底层(HAL 及 以下)获取数据,比如sensor需要获取sensor 数据,Camera需要获取 Camera的raw/yuv 等数据流。
那么对于软件设计而言,如果是同步的话,我们通过getXXX()函数来获取即可。
但如果是异步的话,比如底层实现的中断机制,你不知道他什么时候会来数据,那么这个时候,我们就会通过callback 来实现异步的回调。
看下图就比较清楚了
3.1 实战演练
写个简单的HAL 模块,我们在.hal 文件中加入一个setCallback函数,传入一个callback 指针,
当我们HAL 的server 端起来的时候会起一个线程,每隔5s钟的时间调用下传入的这个回调函数,实现回调的机制。
看下 HIDL 接口 IHello.hal
package vendor.sample.hello@1.0;
import IHelloCallback;
interface IHello {
init();
release();
setCallback(IHelloCallback callback);
};
定义了三个接口:
init: 做一些初始化的动作
release: 做一些释放的动作
setCallback:让client 端设置一个 callback 方法到 server 端
下面来看看这个callback里面都定义了些啥,我们要为这个 callback 写一个接口 IHelloCallback.hal
package vendor.sample.hello@1.0;
interface IHelloCallback {
oneway onNotify(HalEvent event);
};
回调函数里面有一个回调函数,可以让server 传入一个 HalEvent 的结构体到 Client 端,
这个结构体也是自定义的,在 types.hal,可以定义自已喜欢的类型,这里是一个简单的 init 成员变量。
package vendor.sample.hello@1.0;
struct HalEvent {
int32_t value;
};
ok,HIDL 的接口定义好后,我们来使用指令来为我们生产代码框架:
hidl-gen -o vendor/honeywell/common/sample/hidl-impl/sample/
-Lc++-impl -rvendor.sample:vendor/honeywell/common/sample/interfaces
-randroid.hidl:system/libhidl/transport vendor.sample.hello@1.0
此时会成生成一堆代码:
├── Android.mk
├── hidl-impl
│ ├── Android.mk
│ └── sample │
├── Android.bp ***
│ ├── HelloCallback.cpp*** ***
│ ├── HelloCallback.h*** ***
│ ├── Hello.cpp*** ***
│ └── Hello.h***
└── interfaces
├── Android.bp
└── hello
└── 1.0
├── Android.bp
├── IHelloCallback.hal
├── IHello.hal
└── types.hal
其中有一个代码是用不到的,HelloCallback.h 和 HelloCallback.cpp ,也不知道为啥会生成,
我们可以把它删了。
注意,要把hidl-impl/sample/Android.bp里面的HelloCallback.cpp也要删掉
cc_library_shared {
proprietary: true,
srcs: [
"Hello.cpp",
],
shared_libs: [
"libhidlbase",
"libhidltransport",
"libutils",
"vendor.sample.hello@1.0",
],
}
在Vendor 分区中,要起一个 service 来 handle 这个HIDL 接口,
#include <vendor/sample/hello/1.0/IHello.h>
#include <hidl/LegacySupport.h>
using vendor::sample::hello::V1_0::IHello;
using android::hardware::defaultPassthroughServiceImplementation;
int main()
{
return defaultPassthroughServiceImplementation<IHello>();
}
然后是 makefile:
cc_binary {
name: "vendor.sample.hello@1.0-service",
relative_install_path: "hw",
defaults: ["hidl_defaults"],
vendor: true,
init_rc: ["vendor.sample.hello@1.0-service.rc"],
srcs: [
"service.cpp",
],
shared_libs: [
"liblog",
"libutils",
"libhidlbase",
"libhidltransport",
"libutils",
"vendor.sample.hello@1.0",
],
}
编译后应该能看到 impk 的库 和 一个可执行程序用来起server 的。
看一下下面的代码,是主体实现端的代码:
#define LOG_TAG "Sample"
#include "Hello.h"
#include <log/log.h>
namespace vendor {
namespace sample {
namespace hello {
namespace V1_0 {
namespace implementation {
sp<IHelloCallback> Hello::mCallback = nullptr;
// Methods from ::vendor::sample::hello::V1_0::IHello follow.
Return<void> Hello::init() {
mExit = false;
run("sample");
return Void();
}
Return<void> Hello::release() {
mExit = true;
return Void();
}
Return<void> Hello::setCallback(const sp<::vendor::sample::hello::V1_0::IHelloCallback>& callback) {
mCallback = callback;
if(mCallback != nullptr) {
ALOGD("setCallback: done");
}
return Void();
}
bool Hello::threadLoop()
{
static int32_t count = 0;
HalEvent event;
while(!mExit) {
::sleep(1);
event.value = count ++;
if(mCallback != nullptr) {
mCallback->onNotify(event);
}
}
ALOGD("threadLoop: exit");
return false;
}
// Methods from ::android::hidl::base::V1_0::IBase follow.
IHello* HIDL_FETCH_IHello(const char* /* name */) {
return new Hello();
}
//
} // namespace implementation
} // namespace V1_0
} // namespace hello
} // namespace sample
} // namespace vendor
在init 函数中调用 run 方法去启动线程,线程的主体是 threadloop 函数,
可以看到在线程里面,是一个死揗环,会每隔 1 秒去 callback 一次方法,这是很简单。
下面是 client 的实现:
#define LOG_TAG "TestHello"
#include <log/log.h>
#include <vendor/sample/hello/1.0/types.h>
#include <vendor/sample/hello/1.0/IHello.h>
#include <vendor/sample/hello/1.0/IHelloCallback.h>
#include <hidl/Status.h>
#include <hidl/HidlSupport.h>
using android::sp;
using android::hardware::Return;
using android::hardware::Void;
using vendor::sample::hello::V1_0::HalEvent;
using vendor::sample::hello::V1_0::IHello;
using vendor::sample::hello::V1_0::IHelloCallback;
class HelloCallback: public IHelloCallback {
public:
HelloCallback() {
}
~HelloCallback() {
}
Return<void> onNotify(const HalEvent& event) {
ALOGD("onNotify: value = %d", event.value);
return Void();
}
};
int main(void)
{
sp<IHello> service = IHello::getService();
if(service == nullptr) {
ALOGE("main: failed to get hello service");
return -1;
}
sp<HelloCallback> callback = new HelloCallback();
service->setCallback(callback);
service->init();
::sleep(10);
service->release();
return 0;
}
ok ,在 client 端就是简单的打印了 callback 回来的event 里面的数据。
下面是makefile 的代码:
cc_binary {
name: "test_hello",
srcs: [
"test_hello.cpp",
],
shared_libs: [
"liblog",
"libutils",
"libhidlbase",
"libhidltransport",
"libutils",
"vendor.sample.hello@1.0",
],
}
手动运行,结果如下: