安卓9.0Sensor框架
前言
本來如果只是給傳感器寫個驅(qū)動并提供能讀取溫濕度數(shù)據(jù)的節(jié)點,是一件比較輕松的事情,但是最近上層應(yīng)用的同事要求我們按照安卓標準的流程來,這樣他們就能通過注冊一個服務(wù)直接讀取傳感器事件數(shù)據(jù)了。這樣做的好處就是第三方的應(yīng)用也能正常讀取溫濕度的數(shù)據(jù)并展示。
正文
網(wǎng)上分析安卓9.0 sensor相關(guān)的資料不多,下面找到了一位大神對安卓9.0整個sensor框架總結(jié)的流程圖:
雖然流程比較粗糙,但是也有助于我們跟蹤代碼。這里重點說一下,sensor架構(gòu)中的HAL層分為兩部分:
(1)安卓官方實現(xiàn)部分
hardware/libhardware/modules/sensors
(2)芯片產(chǎn)商實現(xiàn)部分(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();?/*?調(diào)用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?},};從上面可以發(fā)現(xiàn),最后調(diào)用到
android_server_SystemServer_startSensorService
函數(shù),里面會判斷屬性
system_init.startsensorservice
是否為1,然后才會真正去啟動
SensorService
服務(wù)。所以這里涉及到第一個改動,設(shè)置
system_init.startsensorservice
屬性,這里我是直接在
build/make/tools/buildinfo.sh
里面寫死為1。
用SensorService::instantiate()方式創(chuàng)建的sensorservice實例后,調(diào)用里面的SensorService::onFirstRef方法。
代碼路徑:
frameworks\native\services\sensorservice\SensorService.cpp
void?SensorService::onFirstRef()?{ALOGD("nuSensorService?starting...");SensorDevice&?dev(SensorDevice::getInstance());?/*?創(chuàng)建并獲取SensorDevice實例?*/...if?(dev.initCheck()?==?NO_ERROR)?{sensor_t?const*?list;ssize_t?count?=?dev.getSensorList(&list);?/*?通過SensorDevice,并調(diào)用到vendor層去獲取sensor的數(shù)目?*/if?(count?>?0)?{ssize_t?orientationIndex?=?-1;bool?hasGyro?=?false,?hasAccel?=?false,?hasMag?=?false;uint32_t?virtualSensorsNeeds?=(1<<SENSOR_TYPE_GRAVITY)?|(1<<SENSOR_TYPE_LINEAR_ACCELERATION)?|(1<<SENSOR_TYPE_ROTATION_VECTOR)?|(1<<SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR)?|(1<<SENSOR_TYPE_GAME_ROTATION_VECTOR);for?(ssize_t?i=0?;?i<count?;?i++)?{bool?useThisSensor=true;switch?(list[i].type)?{case?SENSOR_TYPE_ACCELEROMETER:hasAccel?=?true;break;case?SENSOR_TYPE_MAGNETIC_FIELD:hasMag?=?true;break;case?SENSOR_TYPE_ORIENTATION:orientationIndex?=?i;break;case?SENSOR_TYPE_GYROSCOPE:case?SENSOR_TYPE_GYROSCOPE_UNCALIBRATED:hasGyro?=?true;break;case?SENSOR_TYPE_GRAVITY:case?SENSOR_TYPE_LINEAR_ACCELERATION:case?SENSOR_TYPE_ROTATION_VECTOR:case?SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR:case?SENSOR_TYPE_GAME_ROTATION_VECTOR:if?(IGNORE_HARDWARE_FUSION)?{useThisSensor?=?false;}?else?{virtualSensorsNeeds?&=?~(1<<list[i].type);}break;}if?(useThisSensor)?{registerSensor(?new?HardwareSensor(list[i])?);}}//?it's?safe?to?instantiate?the?SensorFusion?object?here//?(it?wants?to?be?instantiated?after?h/w?sensors?have?been//?registered)SensorFusion::getInstance();if?(hasGyro?&&?hasAccel?&&?hasMag)?{...}if?(hasAccel?&&?hasGyro)?{...}if?(hasAccel?&&?hasMag)?{...}...}} }我這次主要是增加溫濕度傳感器的功能,上面的流程中沒有過多涉及溫濕度的,有興趣的可以參考大神的博客自行分析。不過這里重點關(guān)注一下SensorDevice這個類,它是連接上層應(yīng)用和HAL層的中間樞紐:
代碼路徑:
frameworks\native\services\sensorservice\SensorDevice.cpp
SensorDevice::SensorDevice():?mHidlTransportErrors(20),?mRestartWaiter(new?HidlServiceRegistrationWaiter())?{if?(!connectHidlService())?{return;}float?minPowerMa?=?0.001;?//?1?microAmpcheckReturn(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構(gòu)造函數(shù)中,通過調(diào)用connectHidlService()和安卓部分的HAL層服務(wù)建立連接。連接后,就可以調(diào)用已經(jīng)在HAL層注冊的sensor設(shè)備了,比如這里就調(diào)用getSensorsList()來獲取sensor設(shè)備列表,并放回sensor的數(shù)目。然后就是通過mSensors->activate()來“激活”sensor設(shè)備,而每個sensor具體的activate()函數(shù)由驅(qū)動工程師實現(xiàn)。
激活sensor設(shè)備后,就可以開始獲取sensor的數(shù)據(jù)了,在SensorService中會通過poll機制去查詢底層sensor的數(shù)據(jù):
代碼路徑:
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函數(shù)里面內(nèi)容挺多的,但是目前只關(guān)注讀取數(shù)據(jù)的poll部分。可以看到device就是SensorDevice的一個實例,前面我們講到上層都是通過SensorDevice和HAL層連接,這里也不例外,也是調(diào)用到了SensorDevice中的poll函數(shù),這里我給出這個調(diào)用的流程:
1、frameworks\native\services\sensorservice\SensorDevice.cpp SensorDevice::poll()2、vendor\mediatek\proprietary\hardware\sensor\sensors-1.0\sensors.cpppoll__poll()3、vendor\mediatek\proprietary\hardware\sensor\sensors-1.0\SensorManager.cppSensorManager::pollEvent()4、vendor\mediatek\proprietary\hardware\sensor\sensors-1.0\SensorContext.cppsensors_poll_context_t::pollEvent上面簡陋的流程展示了從framework層一路調(diào)用到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; }這里面我們重點關(guān)注三點 (1) mPollFds的定義如下:
struct?pollfd?mPollFds[numFds];其中,
struct?pollfd?{int?fd;????????/*?文件描述符?*/short?events;?/*?等待的事件?*/short?revents;?/*?實際發(fā)生了的事件?*/ };所以mPollFds就是用來監(jiān)聽代表每個sensor是否有數(shù)據(jù)上報的文件描述符
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類都繼承于它,比如我這次實現(xiàn)的濕度傳感器:
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();}; };從類的聲明來看,定義了很多函數(shù),比如readEvents、enable和batch等等,這些最終都會和底層驅(qū)動聯(lián)系起來,后面再細說。
(3)在sensors_poll_context_t的構(gòu)造函數(shù)中會對上面兩點講到的數(shù)組進行初始化:
sensors_poll_context_t::sensors_poll_context_t() {...mSensors[humidity]?=?new?HumiditySensor();?/*?分配一個Humidity傳感器的類?*/mPollFds[humidity].fd?=?mSensors[humidity]->getFd();?/*?獲取對應(yīng)sensor的字符描述符?*/mPollFds[humidity].events?=?POLLIN;?/*?等待POLLIN類型的事件?*/mPollFds[humidity].revents?=?0;... }再回到上面的
sensors_poll_context_t::pollEvent()
函數(shù),通過
mPollFds[i].revents
判斷到如果發(fā)生了POLLIN事件,證明可以獲取數(shù)據(jù)了,就調(diào)用對應(yīng)sensor的readEvents()
函數(shù)去獲取。接下來我們就進入到sensor設(shè)備對應(yīng)的HAL層里面了,現(xiàn)在以濕度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;}我們可以看到讀取數(shù)據(jù)實際又是統(tǒng)一通過
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; }構(gòu)造函數(shù)里面分配了Buffer來存儲接收的數(shù)據(jù)
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里面填充數(shù)據(jù),通過我們熟悉的read()函數(shù)來獲取數(shù)據(jù)。
ssize_t?SensorEventCircularReader::readEvent(struct?sensor_event?const**?events)?{*events?=?mCurr;ssize_t?available?=?(mBufferEnd?-?mBuffer)?-?mFreeSpace;return?available???1?:?0; }readEvent()
只是判斷buffer中是否有數(shù)據(jù),然后就是調(diào)用
mSensorReader.next()
獲取下一個buffer。再回到
HumiditySensor::readEvents()
在讀取到數(shù)據(jù)后會調(diào)用
processEvent()
去處理數(shù)據(jù):
void?HumiditySensor::processEvent(struct?sensor_event?const?*event)?{mPendingEvent.relative_humidity?=?(float)?event->word[0]?/?mDataDiv; }mPendingEvent.relative_humidity就是最終上報給上層應(yīng)用的值了。
結(jié)語
至此,framework層到vendor層的流程就分析完了,后面我們會分析kernel層的sensor框架。
參考鏈接
https://blog.csdn.net/goodnight1994/article/details/97503586
推薦閱讀:
專輯|Linux文章匯總
專輯|程序人生
專輯|C語言
嵌入式Linux
微信掃描二維碼,關(guān)注我的公眾號
總結(jié)
以上是生活随笔為你收集整理的安卓9.0Sensor框架的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python代码实现验证码识别
- 下一篇: UNUSED参数,这个宏,很秀