#星光计划1.0# OpenHarmony 源码解析之Sensor子系统(上) 原创 精华
作者:李祥志
1 简介
人类获取外界信息必须借助于感觉器官,而在研究自然现象和规律以及生产活动仅靠感官已经远远不够了,为了适应这种情况,出现了传感器。随着物联网,移动互联网的快速发展,在数字时代,传感器在智能交通,智能工业,智能穿戴等领域有着广阔的应用空间。
1.1 OpenHarmony架构图
2 基础知识
2.1 传感器概述
传感器是检测到被测量信息,将非电量信息转换成电信号的检测装置。就像眼睛是人类心灵的窗户,传感器则是计算机感知世界万物的眼睛。
传感器用于侦测环境中所发生事件或变化,并将此消息发送至其他电子设备(如中央处理器)的设备,通常由敏感组件和转换组件组成。
根据用途可分为以下六大类:
-
运动类:加速度、陀螺仪、重力、线性加速度传感器等;
-
姿态类:旋转矢量、方向传感器等;
-
环境类:磁力计、气压、湿度传感器等;
-
光线类:环境光、接近光、色温传感器等;
-
健康类:心率、心跳传感器等;
-
其它:霍尔传感器、手握传感器等;
2.2 传感器架构图
应用层 :各种需要sensor
的应用,例如运动健康,计步器,指南针等等。
框架层 :
-
SDK :给应用提供标准接口,包括
JS接口
和C++接口
。 -
Framework:向应用层提供稳定的基础能力,包括
Sensor
列表查询、Sensor
启停、Sensor
订阅及去订阅,Sensor
参数配置,创建数据传递通道,sensor数据上传等功能。 -
Service:提供
Sensor
设备管理,Sensor
通用配置能力,Sensor
通用数据解析能力,权限管理能力。
HDF层 :HDF驱动框架
,Sensor设备驱动
的开发是基于该框架的基础上,结合操作系统适配层(OSAL
)和平台驱动接口(比如I2C/SPI/UART总线
等平台资源)能力,屏蔽不同操作系统和平台总线资源差异,实现Sensor驱动
“一次开发,多系统部署”的目标。
Hardware层 :各种传感器器件,例如加速度计,陀螺仪,温度,湿度等等。
2.3 Sensor子系统代码目录
/base/sensors/sensor
├── frameworks # 框架代码
│ └── native # sensor客户端代码
├── interfaces # 对外接口存放目录
│ ├── native # sensor native实现
│ └── plugin # Js API
├── sa_profile # 服务名称和服务的动态库的配置文件
├── services # 服务的代码目录
│ └── sensor # 传感器服务,包括加速度、陀螺仪等,上报传感器数据
└── utils # 公共代码,包括权限、通信等能力
3 源码分析
本文先讲解框架层的代码,HDF
的部分放在下一篇文章讲解。
框架层主要包含两部分:
-
JS
应用订阅、启动sensor
。 -
JS
应用收到订阅sensor
的数据信息。
3.1 JS应用订阅、启动Sensor
我们从JS API
开放的能力开始看源码,绿色部分看作client
,黄色部分看作service
。
JS API的主要接口:
接口名 | 描述 |
---|---|
on(type: SensorType, callback: AsyncCallback<Response>, options?: Options) | 监听传感器数据变化。SensorType为支持订阅的传感器类型,callback表示订阅传感器的回调函数,options为设置传感器数据上报的时间间隔。 |
once(type: SensorType, callback: AsyncCallback<Response>) | 监听传感器数据变化一次。SensorType为支持订阅的传感器类型,callback表示订阅传感器的回调函数。 |
off(type: SensorType, callback: AsyncCallback<void>) | 取消订阅传感器数据。SensorType为支持的取消订阅的传感器类型,callback表示取消订阅传感器是否成功。 |
给JS应用提供接口的实现文件是sensor_js.cpp
,我们从init
开始看接口的实现:
static napi_value Init(napi_env env, napi_value exports)
{
// 这里定义了三个接口,on、once、off。
napi_property_descriptor desc[] = {
DECLARE_NAPI_FUNCTION("on", On),
DECLARE_NAPI_FUNCTION("once", Once),
DECLARE_NAPI_FUNCTION("off", Off)
};
NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(napi_property_descriptor), desc));
return exports;
}
static napi_value On(napi_env env, napi_callback_info info)
{
......
// 获取JS应用传递的sensorTypeId,例如加速度计,陀螺仪等等
int32_t sensorTypeId = GetCppInt32(args[0], env);
......
AsyncCallbackInfo *asyncCallbackInfo = new AsyncCallbackInfo {
.env = env,
.asyncWork = nullptr,
.deferred = nullptr,
};
napi_create_reference(env, args[1], 1, &asyncCallbackInfo->callback[0]);
g_onCallbackInfos[sensorTypeId] = asyncCallbackInfo;
// 调用SubscribeSensor函数订阅该sensor,指定sensor类型,上报频率,数据返回通过DataCallbackImpl。
int32_t ret = SubscribeSensor(sensorTypeId, interval, DataCallbackImpl);
......
HiLog::Info(LABEL, "%{public}s out", __func__);
return nullptr;
}
static int32_t SubscribeSensor(int32_t sensorTypeId, int64_t interval, RecordSensorCallback callback)
{
HiLog::Info(LABEL, "%{public}s in, sensorTypeId: %{public}d", __func__, sensorTypeId);
// 注一:订阅指定sensorId的传感器数据,通过user,系统将向应用上报获得的传感器数据,user实际就是callback。
int32_t ret = SubscribeSensor(sensorTypeId, &user);
if (ret < 0) {
HiLog::Error(LABEL, "%{public}s subscribeSensor failed", __func__);
return ret;
}
// 设置采样频率和上报频率
ret = SetBatch(sensorTypeId, &user, interval, 0);
if (ret < 0) {
HiLog::Error(LABEL, "%{public}s set batch failed", __func__);
return ret;
}
//注二: 启用已订阅的传感器。只有在启用传感器后,应用才能获取传感器数据。
ret = ActivateSensor(sensorTypeId, &user);
if (ret < 0) {
HiLog::Error(LABEL, "%{public}s activateSensor failed", __func__);
return ret;
}
return 0;
}
注一:SubscribeSensor
,订阅sensor
,建立sensor
数据传递频道。
int32_t SensorAgentProxy::SubscribeSensor(int32_t sensorId, const SensorUser *user) const
{
HiLog::Info(LABEL, "%{public}s in, sensorId: %{public}d", __func__, sensorId);
if (user == nullptr || sensorId < 0 || user->callback == nullptr) {
HiLog::Error(LABEL, "%{public}s user is null or sensorId is invalid", __func__);
return OHOS::Sensors::ERROR;
}
if (!g_isChannelCreated) {
HiLog::Info(LABEL, "%{public}s channel created", __func__);
g_isChannelCreated = true;
// 创建sensor数据频道,通过此channel实现client和service的数据传递。
CreateSensorDataChannel(user);
}
// 指定sensorId对应的callback
g_subscribeMap[sensorId] = user;
return OHOS::Sensors::SUCCESS;
}
int32_t SensorAgentProxy::CreateSensorDataChannel(const SensorUser *user) const
{
HiLog::Debug(LABEL, "%{public}s", __func__);
if (dataChannel_ == nullptr) {
HiLog::Error(LABEL, "%{public}s data channel cannot be null", __func__);
return INVALID_POINTER;
}
// 注1 ,创建sensor数据传递频道,sendFd和recvFd
auto ret = dataChannel_->CreateSensorDataChannel(HandleSensorData, nullptr);
if (ret != ERR_OK) {
HiLog::Error(LABEL, "%{public}s create data channel failed, ret : %{public}d", __func__, ret);
return ret;
}
auto &client = SensorServiceClient::GetInstance();
// 注2 , 将client创建的数据频道,sendFd转移到service,使得service和client可以通讯。
ret = client.TransferDataChannel(dataChannel_);
if (ret != ERR_OK) {
auto destoryRet = dataChannel_->DestroySensorDataChannel();
HiLog::Error(LABEL, "%{public}s transfer data channel failed,
ret : %{public}d, destoryRet : %{public}d",__func__, ret, destoryRet);
return ret;
}
return ERR_OK;
}
先看注1,创建sensor
数据传递频道,sendFd
和receiveFd
,由调用关系找到,调用SensorDataChannel::InnerSensorDataChannel()
,我们来看下这个函数。
int32_t SensorDataChannel::InnerSensorDataChannel()
{
std::lock_guard<std::mutex> threadLock(treadMutex_);
// create basic data channel,通过socketpair()函数用于创建一对套接字sendFd_和receiveFd_
int32_t ret = CreateSensorBasicChannel(SENSOR_READ_DATA_SIZE,SENSOR_READ_DATA_SIZE);
if (ret != ERR_OK) {
HiLog::Error(LABEL, "%{public}s create basic channel failed, ret : %{public}d", __func__, ret);
return ret;
}
auto listener = std::make_shared<MyFileDescriptorListener>();
listener->SetChannel(this);
auto myRunner = AppExecFwk::EventRunner::Create(true);
if (myRunner == nullptr) {
HiLog::Error(LABEL, "%{public}s myRunner is null", __func__);
return -1;
}
auto handler = std::make_shared<MyEventHandler>(myRunner);
if (handler == nullptr) {
HiLog::Error(LABEL, "%{public}s handler is null", __func__);
return -1;
}
// receiveFd_绑定到MyFileDescriptorListener,MyFileDescriptorListener用于接收sensor数据
receiveFd_ = GetReceiveDataFd();
auto inResult = handler->AddFileDescriptorListener(receiveFd_, AppExecFwk::FILE_DESCRIPTOR_INPUT_EVENT, listener);
……
}
再看注2,如何将sendFd_
转移给service
,作为sensor
数据的发送端?
ErrCode SensorServiceProxy::TransferDataChannel(const sptr<SensorBasicDataChannel> &sensorBasicDataChannel,
const sptr<IRemoteObject> &sensorClient)
{
HiLog::Debug(LABEL, "%{public}s sendFd: %{public}d", __func__, sensorBasicDataChannel->GetSendDataFd());
if (sensorBasicDataChannel == nullptr || sensorClient == nullptr) {
HiLog::Error(LABEL, "%{public}s sensorBasicDataChannel or sensorClient cannot be null", __func__);
return OBJECT_NULL;
}
MessageParcel data;
MessageParcel reply;
MessageOption option;
if (!data.WriteInterfaceToken(SensorServiceProxy::GetDescriptor())) {
HiLog::Error(LABEL, "%{public}s write descriptor failed", __func__);
return WRITE_MSG_ERR;
}
// 将sendFd_写入parcel,会通过SendRequest,传递给service
sensorBasicDataChannel->SendToBinder(data);
if (!data.WriteRemoteObject(sensorClient)) {
HiLog::Error(LABEL, "%{public}s write sensorClient failed", __func__);
return WRITE_MSG_ERR;
}
// IPC通讯机制,执行此处会调用service的CreateDataChannelInner
int32_t ret = Remote()->SendRequest(ISensorService::TRANSFER_DATA_CHANNEL, data, reply, option);
if (ret != NO_ERROR) {
DmdReport::ReportException(SENSOR_SERVICE_IPC_EXCEPTION, "TransferDataChannel", ret);
HiLog::Error(LABEL, "%{public}s failed, ret : %{public}d", __func__, ret);
}
sensorBasicDataChannel->CloseSendFd();
return static_cast<ErrCode>(ret);
}
由SendRequest
,指定ISensorService::TRANSFER_DATA_CHANNEL
会调用到CreateDataChannelInner
,这个函数主要的作用是CreateSensorBasicChannel
,service
端获取到sendFd_
。
ErrCode SensorServiceStub::CreateDataChannelInner(MessageParcel &data, MessageParcel &reply)
{
(void)reply;
sptr<SensorBasicDataChannel> sensorChannel = new (std::nothrow)SensorBasicDataChannel();
if (sensorChannel == nullptr) {
HiLog::Error(LABEL, "%{public}s sensorChannel cannot be null", __func__);
return OBJECT_NULL;
}
auto ret = sensorChannel->CreateSensorBasicChannel(data);
if (ret != ERR_OK) {
HiLog::Error(LABEL, "%{public}s CreateSensorBasicChannel ret : %{public}d",__func__, ret);
return OBJECT_NULL;
}
sptr<IRemoteObject> sensorClient = data.ReadRemoteObject();
if (sensorClient == nullptr) {
HiLog::Error(LABEL, "%{public}s sensorClient cannot be null", __func__);
return OBJECT_NULL;
}
return TransferDataChannel(sensorChannel, sensorClient);
}
int32_t SensorBasicDataChannel::CreateSensorBasicChannel(MessageParcel &data)
{
HiLog::Debug(LABEL, "%{public}s begin", __func__);
if ((sendFd_ != INVALID_FD) || (receiveFd_ != INVALID_FD)) {
HiLog::Debug(LABEL, "%{public}s already create socketpair", __func__);
return ERR_OK;
}
int32_t tmpFd = data.ReadFileDescriptor();
if (tmpFd < 0) {
HiLog::Error(LABEL, "%{public}s ReadFileDescriptor failed", __func__);
sendFd_ = INVALID_FD;
return SENSOR_CHANNEL_DUP_ERR;
}
// service的sendFd,和前面的receiveFd对应,用于传递sensor数据。
sendFd_ = dup(tmpFd);
HiLog::Error(LABEL, "%{public}s sendFd: %{public}d", __func__, sendFd_);
if (sendFd_ < 0) {
HiLog::Error(LABEL, "%{public}s dup FileDescriptor failed", __func__);
sendFd_ = INVALID_FD;
return SENSOR_CHANNEL_DUP_ERR;
}
return ERR_OK;
}
至此client
和service
跨进程传递Sensor
数据的通道建立完成了。
注二: 启用已订阅的传感器。
int32_t ActivateSensor(int32_t sensorId, const SensorUser *user)
{
HiLog::Info(LABEL, "%{public}s begin", __func__);
const SensorAgentProxy *proxy = GetInstance();
if (proxy == NULL) {
HiLog::Error(LABEL, "%s proxy is null", __func__);
return OHOS::Sensors::ERROR;
}
// 调用SensorAgentProxy的ActivateSensor函数,指定sendorId和user,开启sensor
return proxy->ActivateSensor(sensorId, user);
}
int32_t SensorAgentProxy::ActivateSensor(int32_t sensorId, const SensorUser *user) const
{
if (user == NULL || sensorId < 0) {
HiLog::Error(LABEL, "%{public}s user is null or sensorId is invalid",__func__);
return OHOS::Sensors::ERROR;
}
if (g_samplingInterval < 0 || g_reportInterval < 0) {
HiLog::Error(LABEL, "%{public}s samplingPeroid or g_reportInterval is invalid", __func__);
return OHOS::Sensors::ERROR;
}
if ((g_subscribeMap.find(sensorId) == g_subscribeMap.end()) || (g_subscribeMap.at(sensorId) != user)) {
HiLog::Error(LABEL, "%{public}s subscribe sensorId first", __func__);
return OHOS::Sensors::ERROR;
}
SensorServiceClient &client = SensorServiceClient::GetInstance();
// 调用SensorServiceClient的 EnableSensor,指定sensorId,采样频率设上报频率。
int32_t ret = client.EnableSensor(sensorId, g_samplingInterval, g_reportInterval);
g_samplingInterval = -1;
g_reportInterval = -1;
if (ret != 0) {
HiLog::Error(LABEL, "%{public}s enable sensor failed, ret: %{public}d",__func__, ret);
return OHOS::Sensors::ERROR;
}
return OHOS::Sensors::SUCCESS;
}
最终会调用到SensorServiceImpl::EnableSensor
,这里主要是调用HDF
提供的标准接口,打开sensor
,下一篇文章会讲述HDF
的内容。
ErrCode SensorServiceImpl::EnableSensor(uint32_t sensorId) const
{
HiLog::Info(LABEL, "%{public}s begin", __func__);
int32_t ret = sensorInterface_->Enable(sensorId);
if (ret < 0) {
HiLog::Error(LABEL, "%{public}s is failed", __func__);
return -1;
}
HiLog::Info(LABEL, "%{public}s end", __func__);
return ERR_OK;
}
3.2 JS应用接收订阅的sensor数据
Sensor打开之后,就会有sensor数据按照上报频率上报给应用。我们下面看下,数据是如何上报的?
前面看到传递的数据通道在订阅时已经创建好了,SensorService::EnableSensor
时,在其内部还调用了SaveSubscriber
。
ErrCode SensorService::EnableSensor(uint32_t sensorId, int64_t samplingPeriodNs, int64_t maxReportDelayNs)
{
......
auto ret = SaveSubscriber(sensorId, samplingPeriodNs, maxReportDelayNs);
if (ret != ERR_OK) {
HiLog::Error(LABEL, "%{public}s SaveSubscriber failed", __func__);
return ret;
}
ret = sensorServiceImpl_.EnableSensor(sensorId);
if (ret != ERR_OK) {
HiLog::Error(LABEL, "%{public}s EnableSensor failed", __func__);
clientInfo_.RemoveSubscriber(sensorId, this->GetCallingPid());
return ENABLE_SENSOR_ERR;
}
return ret;
}
SaveSubscriber 做了两件事情:
1、调用SensorManager::SaveSubscriber
管理sensor
订阅信息。
2、开启sensor
数据上报的线程。
ErrCode SensorService::SaveSubscriber(uint32_t sensorId, int64_t samplingPeriodNs, int64_t maxReportDelayNs)
{
auto ret = sensorManager_.SaveSubscriber(sensorId, this->GetCallingPid(), samplingPeriodNs, maxReportDelayNs);
if (ret != ERR_OK) {
HiLog::Error(LABEL, "%{public}s SaveSubscriber failed", __func__);
return ret;
}
sensorManager_.StartDataReportThread();
if (!sensorManager_.SetBestSensorParams(sensorId, samplingPeriodNs, maxReportDelayNs)) {
HiLog::Error(LABEL, "%{public}s SetBestSensorParams failed", __func__);
clientInfo_.RemoveSubscriber(sensorId, this->GetCallingPid());
return ENABLE_SENSOR_ERR;
}
return ret;
}
void SensorManager::StartDataReportThread()
{
HiLog::Debug(LABEL, "%{public}s begin", __func__);
if (!dataThread_.joinable()) {
HiLog::Warn(LABEL, "%{public}s dataThread_ started", __func__);
std::thread senocdDataThread(SensorDataProcesser::DataThread, sensorDataProcesser_, reportDataCallback_);
dataThread_ = std::move(senocdDataThread);
}
HiLog::Debug(LABEL, "%{public}s end", __func__);
}
int32_t SensorDataProcesser::DataThread(sptr<SensorDataProcesser>dataProcesser, sptr<ReportDataCallback> dataCallback)
{
HiLog::Debug(LABEL, "%{public}s begin", __func__);
do {
if (dataProcesser->ProcessEvents(dataCallback) == INVALID_POINTER) {
HiLog::Error(LABEL, "%{public}s callback cannot be null", __func__);
return INVALID_POINTER;
}
} while (1);
}
int32_t SensorDataProcesser::ProcessEvents(sptr<ReportDataCallback>dataCallback)
{
if (dataCallback == nullptr) {
HiLog::Error(LABEL, "%{public}s dataCallback cannot be null", __func__);
return INVALID_POINTER;
}
std::unique_lock<std::mutex> lk(SensorServiceImpl::dataMutex_);
// 使用std::condition_variable::wait(),处于阻塞状态,
// 当其它线程调用notify_one()或者notify_all()函数,wait()会结束阻塞。
SensorServiceImpl::dataCondition_.wait(lk);
......
return SUCCESS;
}
看到这里,我们发现SaveSubscriber
创建了sensor
数据处理的线程,并使用SensorServiceImpl::dataCondition_.wait(lk)
进入阻塞状态,我们看下何时使用notify_one()
来激活该线程上报数据的?
系统开机启动时,hsensors
进程启动,也就是SensorService
启动。
on post-fs-data
start hsensors
service hsensors /system/bin/sa_main /system/profile/hsensors.xml
class hsensors
user system
group system shell
seclabel u:r:foundation:s0
SensorService
启动后,会将ZReportDataCallback
注册到HDF
,看下面的代码:
void SensorService::OnStart()
{
if (state_ == SensorServiceState::STATE_RUNNING) {
HiLog::Warn(LABEL, "%{public}s SensorService has already started", __func__);
return;
}
// 调用HDF标准接口,初始化
if (!InitInterface()) {
HiLog::Error(LABEL, "%{public}s Init interface error", __func__);
return;
}
// 注册数据返回的callback,初始化
if (!InitDataCallback()) {
HiLog::Error(LABEL, "%{public}s Init data callback error", __func__);
return;
}
......
}
bool SensorService::InitDataCallback()
{
reportDataCallback_ = new (std::nothrow) ReportDataCallback();
if (reportDataCallback_ == nullptr) {
HiLog::Error(LABEL, "%{public}s failed, reportDataCallback_ cannot be null",__func__);
return false;
}
// 将ZReportDataCallback通过RegisteDataReport赋值给reportDataCb_,sensor数据上报会触发ZReportDataCallback
// new ReportDataCallback传递到sensorServiceImpl_,为了调用reportDataCb_
ZReportDataCb cb = &ReportDataCallback::ZReportDataCallback;
auto ret = sensorServiceImpl_.RegisteDataReport(cb, reportDataCallback_);
if (ret != ERR_OK) {
HiLog::Error(LABEL, "%{public}s RegisterDataReport failed", __func__);
return false;
}
return true;
}
ErrCode SensorServiceImpl::RegisteDataReport(ZReportDataCb cb, sptr<ReportDataCallback> reportDataCallback)
{
HiLog::Info(LABEL, "%{public}s begin", __func__);
if (reportDataCallback == nullptr) {
HiLog::Error(LABEL, "%{public}s failed, reportDataCallback cannot be null",__func__);
return ERR_NO_INIT;
}
// 注册callback到HDF
Register(SensorDataCallback);
reportDataCb_ = cb;
reportDataCallback_ = reportDataCallback;
HiLog::Info(LABEL, "%{public}s end", __func__);
return ERR_OK;
}
ErrCode SensorServiceImpl::Register(RecordDataCallback cb) const
{
HiLog::Info(LABEL, "%{public}s begin", __func__);
if (sensorInterface_ == nullptr) {
HiLog::Error(LABEL, " %{public}s,", "test sensorHdi get Module instance failed\n\r");
return ERR_INVALID_VALUE;
}
// 通过HDF提供的标准接口,注册到HDF
int32_t ret = sensorInterface_->Register(cb);
if (ret < 0) {
HiLog::Error(LABEL, "%{public}s failed", __func__);
return ERR_INVALID_VALUE;
}
HiLog::Info(LABEL, "%{public}s end", __func__);
return ERR_OK;
}
当JS应用订阅了传感器,并且启用了传感器,传感器数据就从SensorServiceImpl::SensorDataCallback
向上传递,我们看下这函数的实现,主要做了两件事情:
1、调用ReportDataCallback::ZreportDataCallback
将sensor
数据写入cb->eventsBuf\_
。
2、调用dataCondition_.notify_one()
激活数据上报的线程。
int32_t SensorServiceImpl::SensorDataCallback(const struct SensorEvents *event)
{
HiLog::Debug(LABEL, "%{public}s begin", __func__);
const int32_t SENSOR_AXISZ = 2;
if ((event == nullptr) || (event->dataLen == 0)) {
HiLog::Error(LABEL, "%{public}s event is NULL", __func__);
return ERR_INVALID_VALUE;
}
float *data = (float*)event->data;
if (reportDataCb_ == nullptr) {
HiLog::Error(LABEL, "%{public}s reportDataCb_ cannot be null", __func__);
return ERR_INVALID_VALUE;
}
// 调用ReportDataCallback::ZReportDataCallback方法,存入eventsBuf_
(void)(reportDataCallback_->*reportDataCb_)(reinterpret_cast<const structSensorEvent*>(event), reportDataCallback_);
// 激活sensor数据上报线程
dataCondition_.notify_one();
return ERR_OK;
}
int32_t ReportDataCallback::ZReportDataCallback(const struct SensorEvent *event, sptr<ReportDataCallback> cb)
{
float *data = (float*)event->data;
if (cb == nullptr || cb->eventsBuf_.circularBuf == nullptr || event == nullptr) {
HiLog::Error(LABEL, "%{public}s callback or circularBuf or event cannot be null", __func__);
return ERROR;
}
struct SensorEvent eventCopy = {
.sensorTypeId = event->sensorTypeId,
.version = event->version,
.timestamp = event->timestamp,
.option = event->option,
.mode = event->mode,
.dataLen = event->dataLen
};
eventCopy.data = new uint8_t[SENSOR_DATA_LENGHT];
if (memcpy_s(eventCopy.data, event->dataLen, event->data, event->dataLen) != EOK) {
HiLog::Error(LABEL, "%{public}s copy data failed", __func__);
return COPY_ERR;
}
// 将SensorEvent的数据存入到ReportDataCallback的变量eventsBuf_里面
int32_t leftSize = CIRCULAR_BUF_LEN - cb->eventsBuf_.eventNum;
int32_t toEndLen = CIRCULAR_BUF_LEN - cb->eventsBuf_.writePosition;
if (toEndLen == 0) {
cb->eventsBuf_.circularBuf[0] = eventCopy;
cb->eventsBuf_.writePosition = 1 - toEndLen;
} else {
cb->eventsBuf_.circularBuf[cb->eventsBuf_.writePosition] = eventCopy;
cb->eventsBuf_.writePosition += 1;
}
……
}
至此,回过头来再看SensorDataProcesser::ProcessEvents
,lock
锁激活后,获取到eventsBuf\_
。
int32_t SensorDataProcesser::ProcessEvents(sptr<ReportDataCallback>dataCallback)
{
if (dataCallback == nullptr) {
HiLog::Error(LABEL, "%{public}s dataCallback cannot be null", __func__);
return INVALID_POINTER;
}
std::unique_lock<std::mutex> lk(SensorServiceImpl::dataMutex_);
SensorServiceImpl::dataCondition_.wait(lk);
auto &eventsBuf = dataCallback->GetEventData();
if (eventsBuf.eventNum <= 0) {
HiLog::Error(LABEL, "%{public}s data cannot be empty", __func__);
return NO_EVENT;
}
int32_t eventNum = eventsBuf.eventNum;
for (int32_t i = 0; i < eventNum; i++) {
// 通过EventFilter report eventsBuf数据
EventFilter(eventsBuf);
delete eventsBuf.circularBuf[eventsBuf.readPosition].data;
eventsBuf.circularBuf[eventsBuf.readPosition].data = nullptr;
eventsBuf.readPosition++;
if (eventsBuf.readPosition == CIRCULAR_BUF_LEN) {
eventsBuf.readPosition = 0;
}
eventsBuf.eventNum--;
}
return SUCCESS;
}
EventFilter
最终会调用SendRawData
,通过该函数的channel-\>SendData
,调用Socket send
函数发送sensor
数据。这里的sendFd_
就是前面创建的。(中间的调用过程请看前面的时序图)
int32_t SensorBasicDataChannel::SendData(const void *vaddr, size_t size)
{
if (vaddr == nullptr || sendFd_ < 0) {
HiLog::Error(LABEL, "%{public}s failed, param is invalid", __func__);
return SENSOR_CHANNEL_SEND_ADDR_ERR;
}
ssize_t length;
do {
length = send(sendFd_, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (errno == EINTR);
if (length < 0) {
HiLog::Error(LABEL, "%{public}s send fail : %{public}d, length = %{public}d", __func__, errno, (int32_t)length);
return SENSOR_CHANNEL_SEND_DATA_ERR;
}
return ERR_OK;
}
void MyFileDescriptorListener::OnReadable(int32_t fileDescriptor)
{
if (fileDescriptor < 0) {
HiLog::Error(LABEL, "%{public}s fileDescriptor: %{public}d", __func__, fileDescriptor);
return;
}
FileDescriptorListener::OnReadable(fileDescriptor);
struct TransferSensorEvents *receiveDataBuff_
= new (std::nothrow) TransferSensorEvents[sizeof(struct TransferSensorEvents) * RECEIVE_DATA_SIZE];
// 接收sensor数据,这里的fileDescriptor就是receiveFd_
int32_t len = recv(fileDescriptor, receiveDataBuff_, sizeof(struct TransferSensorEvents) * RECEIVE_DATA_SIZE, NULL);
while (len > 0) {
int32_t eventSize = sizeof(struct TransferSensorEvents);
int32_t num = len / eventSize;
for (int i = 0; i < num; i++) {
SensorEvent event = {
.sensorTypeId = receiveDataBuff_[i].sensorTypeId,
.version = receiveDataBuff_[i].version,
.timestamp = receiveDataBuff_[i].timestamp,
.option = receiveDataBuff_[i].option,
.mode = receiveDataBuff_[i].mode,
.dataLen = receiveDataBuff_[i].dataLen,
.data = receiveDataBuff_[i].data
};
float *data = (float *)(event.data);
// 通过dataCB_将数据再往上层传递,dataCB_即SensorAgentProxy::HandleSensorData
channel_->dataCB_(&event, 1, channel_->privateData_);
}
len = recv(fileDescriptor, receiveDataBuff_, sizeof(struct TransferSensorEvents) * RECEIVE_DATA_SIZE, NULL);
}
}
void SensorAgentProxy::HandleSensorData(struct SensorEvent *events, int32_t num, void *data)
{
if (events == nullptr || num <= 0) {
HiLog::Error(LABEL, "%{public}s events is null or num is invalid", __func__);
return;
}
struct SensorEvent eventStream;
for (int32_t i = 0; i < num; ++i) {
eventStream = events[i];
if (eventStream.data == nullptr || g_subscribeMap[eventStream.sensorTypeId] == nullptr) {
HiLog::Error(LABEL, "%{public}s data or sensorUser is nullptr", __func__);
return;
}
if (g_subscribeMap.find(eventStream.sensorTypeId) == g_subscribeMap.end()) {
HiLog::Error(LABEL, "%{public}s sensorTypeId not in g_subscribeMap", __func__);
return;
}
// 这里的callback调用的是sensor_js.cpp DataCallbackImpl函数
g_subscribeMap[eventStream.sensorTypeId]->callback(&eventStream);
}
}
通过DataCallbackImpl
将数据上报给JS
应用。以加速度计为例,会出现下面的log
打印。
sensor.on(sensor.SensorType.SENSOR_TYPE_ID_ACCELEROMETER, (error, data) => {
if (error) {
console.error("Failed to subscribe to acceleration data. Error code: " +
error.code + "; message: " + error.message);
return;
}
console.info("Acceleration data obtained. x: " + data.x + "; y: " + data.y + ";z: " + data.z);
}, {'interval':200000000});
总结
本文主要和大家分享传感器应用到框架层的实现,重点分析了传感器订阅、启动以及接收订阅传感器数据,做了较为详细的代码说明,希望通过本文您能初步掌握JS应用开发到框架层开发的步骤与流程。关于传感器HDF框架和驱动的分析,请关注后续文章。
更多原创内容请关注:开鸿 HarmonyOS 学院
入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,共建鸿蒙生态,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。
OpenHarmony源码解析系列更新啦,后续还有一大波更新
膜拜大佬~学习了~
原来对sensor完全小白的我,看完这篇文章之后豁然开朗。
太棒了,让我对sensor有了全新的认识