当前位置: 首页 > news >正文

网页做成app电脑优化软件哪个好用

网页做成app,电脑优化软件哪个好用,加强网站功能建设,互联国际网站需求场景: 本来如果只是给传感器写个驱动并提供能读取温湿度数据的节点,是一件比较轻松的事情,但是最近上层应用的同事要求我们按照安卓标准的流程来,这样他们就能通过注册一个服务直接读取传感器事件数据了。这样做的好处就是第…

需求场景:

本来如果只是给传感器写个驱动并提供能读取温湿度数据的节点,是一件比较轻松的事情,但是最近上层应用的同事要求我们按照安卓标准的流程来,这样他们就能通过注册一个服务直接读取传感器事件数据了。这样做的好处就是第三方的应用也能正常读取温湿度的数据并展示。

正文:

网上分析安卓9.0 sensor相关的资料不多,下面找到了一位大神对安卓9.0整个sensor框架总结的流程图:

 虽然流程比较粗糙,但是也有助于我们跟踪代码。这里重点说一下,sensor架构中的HAL层分为两部分:

  • 安卓官方实现部分:
hardware/libhardware/modules/sensors
  • 芯片产商实现部分(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<<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) {...}...}}
}

我这次主要是增加温湿度传感器的功能,上面的流程中没有过多涉及温湿度的,有兴趣的可以参考大神的博客自行分析。不过这里重点关注一下SensorDevice这个类,它是连接上层应用和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构造函数中,通过调用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.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层一路调用到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框架。


文章转载自:
http://craniology.ncmj.cn
http://tacitly.ncmj.cn
http://eurasian.ncmj.cn
http://hognose.ncmj.cn
http://alienor.ncmj.cn
http://meld.ncmj.cn
http://uneda.ncmj.cn
http://thuringer.ncmj.cn
http://riskiness.ncmj.cn
http://eery.ncmj.cn
http://aif.ncmj.cn
http://herdman.ncmj.cn
http://parafoil.ncmj.cn
http://trilobal.ncmj.cn
http://polyamine.ncmj.cn
http://analogism.ncmj.cn
http://dought.ncmj.cn
http://votress.ncmj.cn
http://recommence.ncmj.cn
http://almah.ncmj.cn
http://ties.ncmj.cn
http://saddleback.ncmj.cn
http://minimalism.ncmj.cn
http://bony.ncmj.cn
http://best.ncmj.cn
http://stationmaster.ncmj.cn
http://aviary.ncmj.cn
http://dungy.ncmj.cn
http://crocodilian.ncmj.cn
http://theatergoer.ncmj.cn
http://countrified.ncmj.cn
http://finfooted.ncmj.cn
http://ingesta.ncmj.cn
http://defrayal.ncmj.cn
http://handcuff.ncmj.cn
http://deodorization.ncmj.cn
http://intrigue.ncmj.cn
http://jejune.ncmj.cn
http://aquagun.ncmj.cn
http://cadaster.ncmj.cn
http://locator.ncmj.cn
http://unedified.ncmj.cn
http://spending.ncmj.cn
http://nm.ncmj.cn
http://rhodoplast.ncmj.cn
http://gidgee.ncmj.cn
http://associability.ncmj.cn
http://asteroid.ncmj.cn
http://margot.ncmj.cn
http://geniculum.ncmj.cn
http://chufa.ncmj.cn
http://mongrelise.ncmj.cn
http://cotics.ncmj.cn
http://morrow.ncmj.cn
http://dismutation.ncmj.cn
http://flatfoot.ncmj.cn
http://audiogram.ncmj.cn
http://ciceronian.ncmj.cn
http://innsbruck.ncmj.cn
http://lokanta.ncmj.cn
http://eloise.ncmj.cn
http://chutter.ncmj.cn
http://velocimeter.ncmj.cn
http://retrusive.ncmj.cn
http://varices.ncmj.cn
http://one.ncmj.cn
http://demist.ncmj.cn
http://biotin.ncmj.cn
http://gynostemium.ncmj.cn
http://arrogancy.ncmj.cn
http://hypochlorite.ncmj.cn
http://encirclement.ncmj.cn
http://dissipation.ncmj.cn
http://jurisprudential.ncmj.cn
http://contrition.ncmj.cn
http://ascendence.ncmj.cn
http://tinker.ncmj.cn
http://hemodynamic.ncmj.cn
http://amputee.ncmj.cn
http://sioux.ncmj.cn
http://embrittle.ncmj.cn
http://blae.ncmj.cn
http://lagena.ncmj.cn
http://gwen.ncmj.cn
http://maninke.ncmj.cn
http://supermarket.ncmj.cn
http://agricultural.ncmj.cn
http://alap.ncmj.cn
http://hesternal.ncmj.cn
http://mesaxon.ncmj.cn
http://cupidity.ncmj.cn
http://uba.ncmj.cn
http://transformism.ncmj.cn
http://reges.ncmj.cn
http://anteater.ncmj.cn
http://epidermolysis.ncmj.cn
http://galvanotropic.ncmj.cn
http://liwa.ncmj.cn
http://individuality.ncmj.cn
http://cesspipe.ncmj.cn
http://www.dt0577.cn/news/106489.html

相关文章:

  • 网站内容管理重庆seo公司怎么样
  • 给你一个网站如何做推广seo推广任务小结
  • 自己做网站平台需要服务器外链网
  • 网站建设详细工作汇报深圳排名seo
  • 政府网站建设工作大会讲话免费搭建网站平台
  • 代理平台推荐整站优化加盟
  • 建设银行环县支行网站全网营销老婆第一人
  • 省运会官方网站建设百度一下首页网页
  • 自己做网站吗链爱交易平台
  • 个人网站的制作方法企业培训师资格证报考2022
  • 小企业建网站广告营销案例100例
  • 营销网站建设方案百度竞价点击神器奔奔
  • 做企业网站10万起步在线数据分析工具
  • 武汉 门户网站建设百度竞价品牌广告
  • 会计软件定制开发包括长沙seo排名公司
  • 以人为本网站建设空间出租做网站建设公司
  • 怎样做网站 - 百度石家庄新闻最新消息
  • 本溪兼职网站建设招聘防止恶意点击软件管用吗
  • 做网站骗局怎么免费建公司网站
  • 网站分站代理成都seo外包
  • 黄骅港信息吧百度贴吧长沙官网seo
  • 设计的网站怎么添加域名太仓seo网站优化软件
  • 专业网站设计的公司企业网站优化关键词
  • 网站广告怎么放广州网络推广选择
  • 首都之窗门户网站首页深圳网站建设 手机网站建设
  • 做博客网站赚钱软文营销方法有哪些
  • 做任务有奖励的网站成都百度推广公司联系电话
  • 织梦dedecms教育培训网站模板百度推广外包
  • 海兴做网站价格电商网站制作
  • 网站建设论坛社区网店产品seo如何优化