本文共 10324 字,大约阅读时间需要 34 分钟。
前言
本来如果只是给传感器写个驱动并提供能读取温湿度数据的节点,是一件比较轻松的事情,但是最近上层应用的同事要求我们按照安卓标准的流程来,这样他们就能通过注册一个服务直接读取传感器事件数据了。这样做的好处就是第三方的应用也能正常读取温湿度的数据并展示。
正文
网上分析安卓9.0 sensor相关的资料不多,下面找到了一位大神对安卓9.0整个sensor框架总结的流程图:
虽然流程比较粗糙,但是也有助于我们跟踪代码。这里重点说一下,sensor架构中的HAL层分为两部分:
(1)安卓官方实现部分
hardware/libhardware/modules/sensors
(2)芯片产商实现部分(MTK平台)
vendor/mediatek/proprietary/hardware/sensor
一般来讲,在适配一款新的sensor,改动只会涉及vendor层到kernel层,再往上都是安卓标准的,但是为了了解整个流程怎么走的,参考这位大神的博客,在这里我也稍微介绍一下framework层的部分。
代码路径:
frameworks\base\services\java\com\android\server\SystemServer.java
private void startBootstrapServices() { ... mSensorServiceStart = SystemServerInitThreadPool.get().submit(() -> { TimingsTraceLog traceLog = new TimingsTraceLog( SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER); traceLog.traceBegin(START_SENSOR_SERVICE); startSensorService(); /* 调用JNI接口 */ traceLog.traceEnd(); }, START_SENSOR_SERVICE); ...}
system_server启动之后会通过JNI接口启动sensorService。
代码路径:
frameworks\base\services\core\jni\com_android_server_SystemServer.cpp
static void android_server_SystemServer_startSensorService(JNIEnv* /* env */, jobject /* clazz */) { char propBuf[PROPERTY_VALUE_MAX]; property_get("system_init.startsensorservice", propBuf, "1"); if (strcmp(propBuf, "1") == 0) { SensorService::instantiate(); }}/* * JNI registration. */ static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "startSensorService", "()V", (void*) android_server_SystemServer_startSensorService }, { "startHidlServices", "()V", (void*) android_server_SystemServer_startHidlServices }, };
从上面可以发现,最后调用到
android_server_SystemServer_startSensorService
函数,里面会判断属性
system_init.startsensorservice
是否为1,然后才会真正去启动
SensorService
服务。所以这里涉及到第一个改动,设置
system_init.startsensorservice
属性,这里我是直接在
build/make/tools/buildinfo.sh
里面写死为1。
用SensorService::instantiate()方式创建的sensorservice实例后,调用里面的SensorService::onFirstRef方法。
代码路径:
frameworks\native\services\sensorservice\SensorService.cpp
void SensorService::onFirstRef() { ALOGD("nuSensorService starting..."); SensorDevice& dev(SensorDevice::getInstance()); /* 创建并获取SensorDevice实例 */ ... if (dev.initCheck() == NO_ERROR) { sensor_t const* list; ssize_t count = dev.getSensorList(&list); /* 通过SensorDevice,并调用到vendor层去获取sensor的数目 */ if (count > 0) { ssize_t orientationIndex = -1; bool hasGyro = false, hasAccel = false, hasMag = false; uint32_t virtualSensorsNeeds = (1<< < < < <
我这次主要是增加温湿度传感器的功能,上面的流程中没有过多涉及温湿度的,有兴趣的可以参考大神的博客自行分析。不过这里重点关注一下SensorDevice这个类,它是连接上层应用和HAL层的中间枢纽:
代码路径:
frameworks\native\services\sensorservice\SensorDevice.cpp
SensorDevice::SensorDevice() : mHidlTransportErrors(20), mRestartWaiter(new HidlServiceRegistrationWaiter()) { if (!connectHidlService()) { return; } float minPowerMa = 0.001; // 1 microAmp checkReturn(mSensors->getSensorsList( [&](const auto &list "&") { const size_t count = list.size(); mActivationCount.setCapacity(count); Info model; for (size_t i=0 ; i < count; i++) { sensor_t sensor; convertToSensor(list[i], &sensor); // Sanity check and clamp power if it is 0 (or close) if (sensor.power < minPowerMa) { ALOGE("Reported power %f not deemed sane, clamping to %f", sensor.power, minPowerMa); sensor.power = minPowerMa; } mSensorList.push_back(sensor); mActivationCount.add(list[i].sensorHandle, model); checkReturn(mSensors->activate(list[i].sensorHandle, 0 /* enabled */)); } })); mIsDirectReportSupported = (checkReturn(mSensors->unregisterDirectChannel(-1)) != Result::INVALID_OPERATION);}
在SensorDevice构造函数中,通过调用connectHidlService()和安卓部分的HAL层服务建立连接。连接后,就可以调用已经在HAL层注册的sensor设备了,比如这里就调用getSensorsList()来获取sensor设备列表,并放回sensor的数目。然后就是通过mSensors->activate()来“激活”sensor设备,而每个sensor具体的activate()函数由驱动工程师实现。
激活sensor设备后,就可以开始获取sensor的数据了,在SensorService中会通过poll机制去查询底层sensor的数据:
代码路径:
frameworks\native\services\sensorservice\SensorService.cpp
bool SensorService::threadLoop() { ... SensorDevice& device(SensorDevice::getInstance()); const int halVersion = device.getHalDeviceVersion(); do { ssize_t count = device.poll(mSensorEventBuffer, numEventMax); if (count < 0) { ALOGE("sensor poll failed (%s)", strerror(-count)); break; } ... } while (!Thread::exitPending()); ALOGW("Exiting SensorService::threadLoop => aborting..."); abort(); return false;}
整个threadLoop函数里面内容挺多的,但是目前只关注读取数据的poll部分。可以看到device就是SensorDevice的一个实例,前面我们讲到上层都是通过SensorDevice和HAL层连接,这里也不例外,也是调用到了SensorDevice中的poll函数,这里我给出这个调用的流程:
1、frameworks\native\services\sensorservice\SensorDevice.cppSensorDevice::poll() 2、vendor\mediatek\proprietary\hardware\sensor\sensors-1.0\sensors.cpp poll__poll() 3、vendor\mediatek\proprietary\hardware\sensor\sensors-1.0\SensorManager.cpp SensorManager::pollEvent() 4、vendor\mediatek\proprietary\hardware\sensor\sensors-1.0\SensorContext.cpp sensors_poll_context_t::pollEvent
上面简陋的流程展示了从framework层一路调用到vendor层:
int sensors_poll_context_t::pollEvent(sensors_event_t* data, int count) { int nbEvents = 0; int n = 0; int averageCount = 0, loop = 0, loopcount = 0; int backupcount = count, backuploop = 0; do { loopcount++; computeCountForEachFd(count, &averageCount, &loop); backuploop = loop; for (int i = 0; count && loop && i < numFds; i++) { SensorBase* const sensor(mSensors[i]); if (mPollFds[i].revents & POLLIN || sensor->pendingEvent()) { int nb = sensor->readEvents(data, averageCount); ... } } // try to see if we can get some events immediately or just wait if // we don't have anything to return, important to update fd revents // which sensor data pending in buffer and aviod one sensor always // occupy poll bandwidth. n = TEMP_FAILURE_RETRY(poll(mPollFds, numFds, nbEvents ? 0 : -1)); if (n < 0) { ALOGE("poll() failed (%s)", strerror(errno)); return -errno; } } while (n && count); return nbEvents;}
这里面我们重点关注三点 (1) mPollFds的定义如下:
struct pollfd mPollFds[numFds];
其中,
struct pollfd { int fd; /* 文件描述符 */ short events; /* 等待的事件 */ short revents; /* 实际发生了的事件 */};
所以mPollFds就是用来监听代表每个sensor是否有数据上报的文件描述符
enum { accel, magnetic, gyro, light, proximity, pressure, humidity, temperature, stepcounter, pedometer, activity, situation, scpfusion, apfusion, bio, wakeupset, numFds,};
如果想自定义一种sensor就需要给这个枚举类型增加值。
(2) mSensors的定义如下:
SensorBase* mSensors[numFds];
SensorBase是一个基类,所有的sensor类都继承于它,比如我这次实现的湿度传感器:
class HumiditySensor : public SensorBase { private: int mEnabled; sensors_event_t mPendingEvent; SensorEventCircularReader mSensorReader; int64_t mEnabledTime; char input_sysfs_path[PATH_MAX]; int input_sysfs_path_len; int mDataDiv; int64_t m_hmdy_last_ts = 0; int64_t m_hmdy_delay = 0; void processEvent(struct sensor_event const *event); public: HumiditySensor(); virtual ~HumiditySensor(); virtual int readEvents(sensors_event_t* data, int count); virtual int setDelay(int32_t handle, int64_t ns); virtual int enable(int32_t handle, int enabled); virtual int batch(int handle, int flags, int64_t samplingPeriodNs, int64_t maxBatchReportLatencyNs); virtual int flush(int handle); virtual int getFd() { return mSensorReader.getReadFd(); };};
从类的声明来看,定义了很多函数,比如readEvents、enable和batch等等,这些最终都会和底层驱动联系起来,后面再细说。
(3)在sensors_poll_context_t的构造函数中会对上面两点讲到的数组进行初始化:
sensors_poll_context_t::sensors_poll_context_t(){ ... mSensors[humidity] = new HumiditySensor(); /* 分配一个Humidity传感器的类 */ mPollFds[humidity].fd = mSensors[humidity]->getFd(); /* 获取对应sensor的字符描述符 */ mPollFds[humidity].events = POLLIN; /* 等待POLLIN类型的事件 */ mPollFds[humidity].revents = 0; ...}
再回到上面的
sensors_poll_context_t::pollEvent()
函数,通过
mPollFds[i].revents
判断到如果发生了POLLIN事件,证明可以获取数据了,就调用对应sensor的readEvents()
函数去获取。接下来我们就进入到sensor设备对应的HAL层里面了,现在以湿度sensor为例:
代码路径:
vendor\mediatek\proprietary\hardware\sensor\sensors-1.0\Humidity.cpp
int HumiditySensor::readEvents(sensors_event_t* data, int count) { if (count < 1) return -EINVAL; ssize_t n = mSensorReader.fill(); if (n < 0) return n; int numEventReceived = 0; struct sensor_event const* event; while (count && mSensorReader.readEvent(&event)) { processEvent(event); if (event->flush_action <= FLUSH_ACTION) { ... } mSensorReader.next(); } return numEventReceived;}
我们可以看到读取数据实际又是统一通过
SensorEventCircularReader
这个类来操作:
代码路径:
vendor\mediatek\proprietary\hardware\sensor\sensors-1.0\SensorEventReader.cpp
SensorEventCircularReader::SensorEventCircularReader(size_t numEvents) : mBuffer(new struct sensor_event[numEvents * 2]), mBufferEnd(mBuffer + numEvents), mHead(mBuffer), mCurr(mBuffer), mFreeSpace(numEvents) { mReadFd = -1; mWriteFd = -1;}
构造函数里面分配了Buffer来存储接收的数据
ssize_t SensorEventCircularReader::fill() { size_t numEventsRead = 0; if (mFreeSpace) { const ssize_t nread = TEMP_FAILURE_RETRY(read(mReadFd, mHead, mFreeSpace * sizeof(struct sensor_event))); if (nread < 0 || nread % sizeof(struct sensor_event)) { return 0; } ... } return numEventsRead;}
fill顾名思义就是往分配的buffer里面填充数据,通过我们熟悉的read()函数来获取数据。
ssize_t SensorEventCircularReader::readEvent(struct sensor_event const** events) { *events = mCurr; ssize_t available = (mBufferEnd - mBuffer) - mFreeSpace; return available ? 1 : 0;}
readEvent()
只是判断buffer中是否有数据,然后就是调用
mSensorReader.next()
获取下一个buffer。再回到
HumiditySensor::readEvents()
在读取到数据后会调用
processEvent()
去处理数据:
void HumiditySensor::processEvent(struct sensor_event const *event) { mPendingEvent.relative_humidity = (float) event->word[0] / mDataDiv;}
mPendingEvent.relative_humidity就是最终上报给上层应用的值了。
结语
至此,framework层到vendor层的流程就分析完了,后面我们会分析kernel层的sensor框架。
参考链接
https://blog.csdn.net/goodnight1994/article/details/97503586
推荐阅读:
嵌入式Linux
微信扫描二维码,关注我的公众号
转载地址:https://linus.blog.csdn.net/article/details/107218292 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!