Android HIDL學習(3) ---- 注冊回調

回顧一下

上一節我們學會了如何創建HIDL的server端和client端,對于那些沒玩過Android O或者以上的BSP開發者而言,可以吹上一陣子牛逼了,畢竟比人家多了一個技能,面試的時候也可以裝一下了_

OK,我們還知道了在Android O或者以上的Android版本上創建一個HAL模塊的一般流程是如何的,我們這一節來看一個比較簡單的東西,也是每個模塊基本必不可少的一個玩意兒,那就是回調函數。

注冊回調

怎么個回事呢,我們來舉一個栗子

2bb314c97dde411a864933d3a2043b5f_th.gif

我們把HAL獨立為一個單獨的進程,client也是一個單獨的進程,那么對于一般的模塊而言,都是需要從底層(HAL以及以下)獲取數據,比如sensor,需要獲取sensor數據,Camera,需要獲取camera的raw、yuv等數據流,那么對于軟件設計而言,如果是同步的話,很簡單,我們通過getXXX()函數來獲取即可,但是如果是異步的,比如底層的實現是中端的機制,你不知道他什么時候會出來數據,那么這個時候通常的,我們會通過callback來實現異步的回調

看下面的圖就比較清楚了

HAL-CALLBACK.jpg

我們這一節就來實現簡單的回調機制。

實戰演練

這個例子很簡單,寫一個簡單的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有如下輸出:

1543998428670.png

OK,達到了我們的預期效果了。

這一節我們就簡單的介紹了在Android O/P里面使用HIDL的回調機制是如何實現的。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,908評論 2 372

推薦閱讀更多精彩內容