回顧一下
上一節我們學會了如何創建HIDL的server端和client端,對于那些沒玩過Android O或者以上的BSP開發者而言,可以吹上一陣子牛逼了,畢竟比人家多了一個技能,面試的時候也可以裝一下了_
OK,我們還知道了在Android O或者以上的Android版本上創建一個HAL模塊的一般流程是如何的,我們這一節來看一個比較簡單的東西,也是每個模塊基本必不可少的一個玩意兒,那就是回調函數。
注冊回調
怎么個回事呢,我們來舉一個栗子
我們把HAL獨立為一個單獨的進程,client也是一個單獨的進程,那么對于一般的模塊而言,都是需要從底層(HAL以及以下)獲取數據,比如sensor,需要獲取sensor數據,Camera,需要獲取camera的raw、yuv等數據流,那么對于軟件設計而言,如果是同步的話,很簡單,我們通過getXXX()函數來獲取即可,但是如果是異步的,比如底層的實現是中端的機制,你不知道他什么時候會出來數據,那么這個時候通常的,我們會通過callback來實現異步的回調。
看下面的圖就比較清楚了
我們這一節就來實現簡單的回調機制。
實戰演練
這個例子很簡單,寫一個簡單的HAL模塊,就跟之前的差不多,然后我們在.hal文件里面加入一個setCallback函數,傳入一個callback指針,當我們HAL的server端起來的時候會起一個線程,每隔5秒鐘時間調用一下傳入的這個回調函數,實現回調的機制,OK,廢話不多說,上代碼。
看一下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,可以定義自己喜歡的類型,這里是一個簡單的int成員變量
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,也不知道為什么指令會為我們創建出來,肯定是個bug。刪掉他們。
好了接下來就是寫代碼了,注意,要把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",
],
}
然后編譯一把,應該就能看到生產impl的庫和一個可執行程序用來起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",
],
}
現在可以手動運行測試程序了,還是跟上一節介紹的一樣,可以看到logcat有如下輸出:
OK,達到了我們的預期效果了。
這一節我們就簡單的介紹了在Android O/P里面使用HIDL的回調機制是如何實現的。