Android HIDL学习(3) --- 注册回调

本文介绍了回调函数在异步通信中的应用,特别是在硬件抽象层(HAL)中如何通过HIDL接口实现。通过一个简单的HAL模块示例,展示了如何定义HIDL接口,设置回调函数,并在服务端定时触发回调,客户端接收到数据并进行处理的过程。此外,还给出了服务端和客户端的代码实现以及编译构建步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

三、回调函数
我们把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",
 ],
}


手动运行,结果如下:

在这里插入图片描述

### Android硬件传感器多HAL服务文档与实现细节 在Android操作系统中,硬件抽象层(Hardware Abstraction Layer, HAL)用于提供一种标准化的方式,使上层应用能够通过统一接口访问底层硬件资源。对于传感器子系统而言,`android.hardware.sensors`模块负责管理设备上的各种物理传感器[^1]。 #### 多HAL服务的设计目标 为了支持不同厂商的多种传感器芯片以及复杂的传感器组合方案,Android引入了多HAL机制。这种设计允许单个设备加载多个独立的HAL实例来处理不同的传感器组。具体来说: - **动态加载能力**:每个HAL可以被单独编译并作为共享库部署到文件系统中,在运行时由框架按需加载[^2]。 - **隔离性增强**:即使某个特定供应商提供的HAL出现问题也不会影响其他部分的功能正常运作[^3]。 #### 实现架构概述 以下是关于如何构建一个多HAL环境的关键组件及其作用说明: ##### 1. `sensors.h` 定义了一套标准API供所有类型的sensor driver遵循。它规定了诸如初始化、数据采集周期设置等功能原型声明。 ##### 2. Vendor-specific implementations 各个OEM可以根据自己采用的具体IC型号定制相应的C++类继承自通用基类,并重写虚函数完成实际操作逻辑编码工作。例如: ```cpp class MySensorHal : public ISensor { public: virtual int initialize() override; }; ``` ##### 3. Service registration & discovery mechanism HIDL(Hardware Interface Definition Language)或者AIDL(Android Interface Definition Language),依据版本差异选用其中之一描述远程过程调用接口;随后利用Binder IPC技术建立连接通道让client端获取server端暴露出来的服务能力对象句柄。 ##### 4. Event dispatching pipeline 当检测到来自真实世界的变化信号之后,经过一系列预处理步骤最终封装成事件包形式传递给监听者列表中的每一个注册成员执行回调方法通知它们状态更新情况。 #### 示例代码片段展示 下面给出一段简化版伪代码用来演示上述提到的部分概念的实际运用场景: ```java // Java side pseudo-code example showing interaction with native layer via JNI bridge. private void registerListener(SensorEventListener listener){ if(mNativeInstance != null && !mListeners.contains(listener)){ mListeners.add(listener); // Call into native method which will eventually invoke appropriate sensor hal function. nativeRegisterCallback(new NativeEventDispatcher()); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值