Android sensor 系统框架 (二)
连载上一篇http://www.cnblogs.com/hackfun/p/7327320.html
(D) 如何加载访问.so库
在前一篇博客http://www.cnblogs.com/hackfun/p/7327320.html中,知道如何生成了
一个HAL的.so库,在这里将分析如何加载这个HAL,如何再次封装以适合多客户端访问的情况。
实际上,系统是通过SENSORS_HARDWARE_MODULE_ID找到对应的.so库的。因为该库中的
struct sensors_module_t结构体包含了一个唯一的ID就是SENSORS_HARDWARE_MODULE_ID,
最终的目的也是要获得这个结构体。通过查找这个ID得知是在以下文件中加载设个so的。
文件路径是:
frameworks/native/services/sensorservice/SensorDevice.cpp
先看代码注释,最后再总结。
SensorDevice.cpp
SensorDevice::SensorDevice()
: mSensorDevice(),
mSensorModule()
{
/* 获取SENSORS_HARDWARE_MODULE_ID对应的模块(.so库) */
status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,
(hw_module_t const**)&mSensorModule);
......
/* 打开模块 */
err = sensors_open_1(&mSensorModule->common, &mSensorDevice);
......
/* 这个模块列表中有多少个sensor */
ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);
......
/* 设置容器大小 */
mActivationCount.setCapacity(count);
......
/* 激活/使能模块中所有sensors */
for (size_t i= ; i<size_t(count) ; i++) {
/* 添加sensor到容器 */
mActivationCount.add(list[i].handle, model);
/* 激活/使能sensors */
mSensorDevice->activate(
reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
list[i].handle, );
}
} ...... ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) {
......
do {
/* 轮询接收所有sensors上报的事件,填入sensors_event_t的buffer */
c = mSensorDevice->poll(reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice),
buffer, count);
} while (c == -EINTR);
return c;
} status_t SensorDevice::activate(void* ident, int handle, int enabled)
{
......
/* 初始化handle(sensor类型, 如ID_A)对应的info */
status_t SensorDevice::activate(void* ident, int handle, int enabled);
......
if (enabled) {
/* 如果ident客户端不存在 */
if (isClientDisabledLocked(ident)) {
return INVALID_OPERATION;
} /* 该客户端存在 */
if (info.batchParams.indexOfKey(ident) >= ) {
/* 只有一个客户端,第一个连接的 */
if (info.numActiveClients() == ) {
// This is the first connection, we need to activate the underlying h/w sensor.
actuateHardware = true;
}
}
} else {
/* ident移除成功(disable) */
if (info.removeBatchParamsForIdent(ident) >= ) {
/* 如果这是最后一个移除(disable)的客户端 */
if (info.numActiveClients() == ) {
// This is the last connection, we need to de-activate the underlying h/w sensor.
actuateHardware = true;
} else { }
}
/* 如果被disable,则直接返回 */
if (isClientDisabledLocked(ident)) {
return NO_ERROR;
}
} /* 如果是第一次激活(enable)或最后一个禁止(disable)sensor的
* 在这种情况下就根据handle(sensor类型)和enabled值,调用activate
* 来enable/disable对应的sensor
*/
if (actuateHardware) {
err = mSensorDevice->activate(
reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice), handle, enabled);
}
} status_t SensorDevice::batch(void* ident, int handle, int flags, int64_t samplingPeriodNs,
int64_t maxBatchReportLatencyNs) {
......
/* 初始化handle(sensor类型, 如ID_A)对应的info */
Info& info(mActivationCount.editValueFor(handle)); /* 如果这个ident(key)不存在 */
if (info.batchParams.indexOfKey(ident) < ) {
BatchParams params(flags, samplingPeriodNs, maxBatchReportLatencyNs);
/* 则添加添加这个(ident, params) (key-value)对 */
info.batchParams.add(ident, params);
} else {
/* 如果存在,则更新这个ident */
// A batch has already been called with this ident. Update the batch parameters.
info.setBatchParamsForIdent(ident, flags, samplingPeriodNs, maxBatchReportLatencyNs);
} BatchParams prevBestBatchParams = info.bestBatchParams;
/* 为这个sensor找到所有最小的采样频率和事件上报最大延迟 */
// Find the minimum of all timeouts and batch_rates for this sensor.
info.selectBatchParams(); /* 如果最小的采样频率和事件上报最大延迟相对于上一次发生了变化 */
// If the min period or min timeout has changed since the last batch call, call batch.
if (prevBestBatchParams != info.bestBatchParams) {
......
err = mSensorDevice->batch(mSensorDevice, handle, info.bestBatchParams.flags,
info.bestBatchParams.batchDelay,
info.bestBatchParams.batchTimeout); }
......
} /*
关于mSensorDevice->batch(SensorDevice::batch()基于它封装一层,相当于他的实例)的作用,
相关的说明是: Sets a sensor’s parameters, including sampling frequency and maximum
report latency. This function can be called while the sensor is
activated, in which case it must not cause any sensor measurements to
be lost: transitioning from one sampling rate to the other cannot cause
lost events, nor can transitioning from a high maximum report latency to
a low maximum report latency.
See the Batching sensor results page for details:
http://source.android.com/devices/sensors/batching.html 意思是这是一个设置每个sensor的一些参数,包括采样频率,最大事件上报延迟,这个
函数可以在sensor被激活/使能时被调用,在这种情况下不能造成任何的sensor的测量
据丢失,如从一个采样率转换到另一个采样率的时候不能造成事件丢失,或从一个最大
上报延迟转换到另一个较低的最大上报延迟都不能造成事件丢失。 也就是说每个传感器都应该有一个batch,这个batch是负责调整采样频率和最大上报事
件延迟的参数,例如,在sensor激活的时候,可以调整一次这些参数。
*/ status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodNs)
{
......
Info& info( mActivationCount.editValueFor(handle)); /* 如果存在的sensor不是工作在continuous模式,那么setDelay()应该返回一个错误
* 在batch模式下调用setDelay()是没用的
*/
// If the underlying sensor is NOT in continuous mode, setDelay() should return an error.
// Calling setDelay() in batch mode is an invalid operation.
if (info.bestBatchParams.batchTimeout != ) {
return INVALID_OPERATION;
} /* 到了这里,说明sensor工作的continuous模式 */
/* 获得这个客户端对应的index */
ssize_t index = info.batchParams.indexOfKey(ident);
/* 根据这个index找到对应的batchParams值 */
BatchParams& params = info.batchParams.editValueAt(index);
/* 设置这个batchParams对应的batchDelay采样频率 */
params.batchDelay = samplingPeriodNs;
/* 保存batchParams到bestBatchParams */
info.selectBatchParams();
/* 实际上是调用了sensors_poll_context_t::setDelay */
return mSensorDevice->setDelay(reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
handle, info.bestBatchParams.batchDelay);
} status_t SensorDevice::flush(void* ident, int handle) {
......
/* 刷数据 */
return mSensorDevice->flush(mSensorDevice, handle);
} bool SensorDevice::isClientDisabled(void* ident) {
/* 上锁 */
Mutex::Autolock _l(mLock);
/* 返回客户端状态 */
return isClientDisabledLocked(ident);
} bool SensorDevice::isClientDisabledLocked(void* ident) {
/* 获取ident (key-value对)对应的索引,索引存在(>=0),返回true,
* 否则,返回false。即用于判断该客户端是否disable
*/
return mDisabledClients.indexOf(ident) >= ;
} void SensorDevice::enableAllSensors() {
for (size_t i = ; i< mActivationCount.size(); ++i) {
Info& info = mActivationCount.editValueAt(i);
......
const int sensor_handle = mActivationCount.keyAt(i);
......
/* 激活sensor_handle sensor */
err = mSensorDevice->activate(
reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
sensor_handle, );
/* 设置相应的采样频率 */
err = mSensorDevice->setDelay(
reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
sensor_handle, info.bestBatchParams.batchDelay);
}
} void SensorDevice::disableAllSensors() {
......
/* 逐个sensor disable */
for (size_t i = ; i< mActivationCount.size(); ++i) {
/* 获得一个sensor对应的info */
const Info& info = mActivationCount.valueAt(i);
// Check if this sensor has been activated previously and disable it.
if (info.batchParams.size() > ) {
/* 获得sensor类型 */
const int sensor_handle = mActivationCount.keyAt(i);
......
/* 禁止该sensor */
mSensorDevice->activate(
reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice),
sensor_handle, );
// Add all the connections that were registered for this sensor to the disabled
// clients list.
/* 禁止所有注册了这个sensor的client */
for (size_t j = ; j < info.batchParams.size(); ++j) {
mDisabledClients.add(info.batchParams.keyAt(j));
}
}
}
} status_t SensorDevice::injectSensorData(const sensors_event_t *injected_sensor_event) {
......
/* 增加一个sensor到mSensorDevice */
return mSensorDevice->inject_sensor_data(mSensorDevice, injected_sensor_event);
} status_t SensorDevice::setMode(uint32_t mode) {
......
/* 操作模式设置 */
return mSensorModule->set_operation_mode(mode);
} int SensorDevice::Info::numActiveClients() {
SensorDevice& device(SensorDevice::getInstance()); /* 检查batchParams容器中所有ident是否被disable
* 返回未被disable(即active/enable)的个数
*/
for (size_t i = ; i < batchParams.size(); ++i) {
/* 该ident未被disable */
if (!device.isClientDisabledLocked(batchParams.keyAt(i))) {
++num;
}
} return num;
} status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int flags,
int64_t samplingPeriodNs,
int64_t maxBatchReportLatencyNs) {
{
/* 从容器中找到indent(key)对应的index */
ssize_t index = batchParams.indexOfKey(ident);
......
/* 从容器中找到index索引对应的BatchParams
* 修改该BatchParams的采样频率和事件上报
* 最大延迟
*/
BatchParams& params = batchParams.editValueAt(index);
params.flags = flags;
/* 设置采样频率 */
params.batchDelay = samplingPeriodNs;
/* 事件上报最大延迟 */
params.batchTimeout = maxBatchReportLatencyNs;
......
} void SensorDevice::Info::selectBatchParams() {
BatchParams bestParams(, -, -);
SensorDevice& device(SensorDevice::getInstance());
/* 设置容器中所有未被disable(active/enable)的元素(ident)的值 */
for (size_t i = ; i < batchParams.size(); ++i) {
/* 如果该元素(ident)被disable,则继续查找下一个元素(ident) */
if (device.isClientDisabledLocked(batchParams.keyAt(i))) continue;
/* 获得该索引对应的元素的value (batchParams)值 */
BatchParams params = batchParams.valueAt(i);
if (bestParams.batchDelay == - || params.batchDelay < bestParams.batchDelay) {
/* 如果最新设置采样频率的值小于上一次的,采用最新的值 */
bestParams.batchDelay = params.batchDelay;
}
if (bestParams.batchTimeout == - || params.batchTimeout < bestParams.batchTimeout) {
/* 如果最新事件上报最大延迟的值小于上一次的,采用最新的值 */
bestParams.batchTimeout = params.batchTimeout;
}
} /*
* 这些参数只能往小调
*/ /* 保存到bestBatchParams */
bestBatchParams = bestParams;
}
到这里,基本代码已经分析完了,简单总结一下这个文件主要做了什么工作:
1. 加载.so库,sensors_module_t结构体中获得相关参数
2. 在.so库的基础上,再一次封装activate,setDelay,pollEvents等方法,
目的是为了支持更多的客户端(client)访问。如:struct Info结构体,
每一个sensor都对应有这样一个结构体,该结构体中有两比较重要的成员
是BatchParams bestBatchParams 和
KeyedVector<void*, BatchParams> batchParams。每一个client对应着
一个batchParams,每个client对应的都会传入一个参数到void *,与
BatchParams关联,从BatchParams中选择合适的参数保存到bestBatchParams
中。
3. 这个模块中在.so库的基础上增加了一些方法,但这里是连载前一篇博客
http://www.cnblogs.com/hackfun/p/7327320.html, 在前一篇博客中没
有实现一些flush,batch,inject_sensor_data的方法,因为
struct sensors_poll_device_t结构体重没有提供这些方法,而
struct sensors_poll_device_1结构体才提供这些方法,因此在下一篇
关于sensor service的博客中暂且忽略这些方法是使用
Android sensor 系统框架 (二)的更多相关文章
- Android sensor 系统框架 (一)
这几天深入学习了Android sensor框架,以此博客记录和分享分析过程,其中难免会有错误的地方,欢迎指出! 这里主要分析KERNEL->HAL->JNI这3层的流程.主要从以下几方面 ...
- Android动画学习(一)——Android动画系统框架简介
2015-11-09补充:Drawable Animation极有可能是Frame Animation 这几天在找工作,面试的时候被问到了Android动画,之前完全没接触过这部分,直接给懵了,当然其 ...
- 11.1 Android显示系统框架_framebuffer原理及改进
1. Android显示系统框架Android Graphic UI with GPU Hardware Accelerationhttps://community.nxp.com/docs/DOC- ...
- Android的系统框架
Android的系统架构采用了分层架构的思想,如图1所示.从上层到底层共包括四层,分别是应用程序程序层.应用框架层.系统库和Android运行时和Linux内核. 图1:Android系统架构图 每 ...
- Android Http请求框架二:xUtils 框架网络请求
一:对Http不了解的请看 Android Http请求框架一:Get 和 Post 请求 二.正文 1.xUtils 下载地址 github 下载地址 : https://github.com/w ...
- Android的系统框架的深入认识
Android采用层次化系统架构,官方公布的标准架构如下图所示.Android由底层往上分为4个主要功能层,分别是linux内核层(Linux Kernel),系统运行时库层(Libraries和An ...
- [置顶] Android Sensor系统剖析(4.0)(下)
Author:Harish_hu@qq.com 由于现在电脑上只有4.0的代码,考虑到代码差别也不大,所以下部分,就基于4.0来分析. 3:SensorManager 上一部分说过,开机后,syst ...
- 11.5 Android显示系统框架_Vsync机制_黄油计划_三个方法改进显示系统
5. Vsync机制5.1 黄油计划_三个方法改进显示系统vsync, triple buffering, vsync虚拟化 参考文档:林学森 <深入理解Android内核设计思想>第2版 ...
- 11.2 Android显示系统框架_android源码禁用hwc和GPU
2. 修改tiny4412_Android源码禁用hwc和gpu(厂家不会提供hwc和gpu的源代码,没有源代码就没法分析了,因此在这里禁用该功能并用软件库实现)最终源码: git clone htt ...
随机推荐
- 公众号开发 jsp中<a>问题
在开发微信公众号时,使用了jQuery mobile这个框架,但是在jsp页面中使用<a>发现点击跳转不成功,这就很奇怪了,网上搜索发现大家基本上用js来代替<a>跳转功能: ...
- java 源码分析1 -String
1. String的本质是一个 char数组,实现了CharSequence 接口, /** The value is used for character storage. */ private f ...
- log4j.properties的简单配置和使用
log4j.properties // 日志文件名不能随便写, 是properties文件 log4j.rootLogger=INFO, Console //表示INFO级别 输出到控制台 #Con ...
- Spring Web Flow 入门demo(二)与业务结合 附源代码
第一部分demo仅仅介绍了简单的页面跳转,接下来我们要实现与业务逻辑相关的功能. 业务的逻辑涉及到数据的获取.传递.保存.相关的业务功能函数的调用等内容,这些功能的实现都可用Java 代码来完毕,但定 ...
- 自己定义控件:onDraw 方法实现仿 iOS 的开关效果
概述 本文主要解说怎样在 Android 下实现高仿 iOS 的开关按钮,并不是是在 Android 自带的 ToggleButton 上改动,而是使用 API 提供的 onDraw.onMeasur ...
- Android从源码看ListView的重用机制
不管是android还是iOS,列表视图应该是最复杂的控件了.android中的listview从命名能够看出是个一维数组,而iOS中的tableview则是二维数组.但事实上须要注意的地方是差点儿相 ...
- XCode 7 高速切换代码窗体和文档窗体
XCode 7 高速切换代码窗体和文档窗体 太阳火神的漂亮人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 ...
- Android studio 解决setText中文乱码问题
我在用Android Studio编译器的时候,总会遇到非常多乱码的问题.第一个乱码问题是在Layout文件中面定义了EditText.在代码中须要将获取到的内容填充到EditText里面,这时候假设 ...
- Wireshark 抓包遇到 you don’t have permission to capture on that device mac 错误的解决方案
Wireshark 抓包遇到 you don’t have permission to capture on that device mac 错误的解决方案 上次有篇博客讲了如何利用wireshark ...
- LeetCode 811. Subdomain Visit Count (子域名访问计数)
题目标签:HashMap 题目给了我们一组域名,让我们把每一个域名,包括它的子域名,计数. 遍历每一个域名,取得它的计数,然后把它的所有子域名和它自己,存入hashmap,域名作为key,计数作为va ...