Android Sensor流程
2016-03-22 22:55
597 查看
一.首先看一下sensor的整体架构:
第一层是应用层:代表上层使用frameworks的接口注册或使用一个sensor:
Sensor sensor = sensorManager.getDefaultSensor(sensortype); sensorManager.registerListener(mListener, sensor, SensorManager.SENSOR_DELAY_FASTEST);
第二层Frameworks层: 包含SensorService, 接收HAl层传上来的 sensor event 数据,并让应用层做出相应的动作,如陀螺仪转动,横竖屏切换等
第三层HAL层: kernel层的硬件驱动等, 有SensorDevice 的poll函数读取数据
二.分析SensorServier 的启动流程:
在android系统中每一个功能点都是由Service来调度, 如熟知的ActivityManagerService, PackageManagerService等等, 这些我会在以后的博客中逐个分析先看调用时序图
SystemServer中唯一的一个JNI调用启动SensorService
SystemServer.java :
/** * Start the sensor service. */ private static native void startSensorService();
com_android_server_SystemServer.cpp:
void* sensorInit(void *arg) { ALOGI("System server: starting sensor init.\n"); // Start the sensor service SensorService::instantiate(); ALOGI("System server: sensor init done.\n"); return NULL; }
使用Binder机制将SensorService启动。
SensorService的初始化:
Service的初始在SensorService::onFirstRef函数中
SensorDevice& dev(SensorDevice::getInstance()); // 实例化SensorDevice if (dev.initCheck() == NO_ERROR) { sensor_t const* list; ssize_t count = dev.getSensorList(&list); // 获取sensor list if (count > 0) { ssize_t orientationIndex = -1; bool hasGyro = false, hasAccel = false, hasMag = false; ... ... mLastEventSeen.setCapacity(count); for (ssize_t i=0 ; i<count ; i++) { registerSensor( new HardwareSensor(list[i]) ); // 向HAL层注册触感器 ... ... mNextSensorRegIndex = 0; for (int i = 0; i < SENSOR_REGISTRATIONS_BUF_SIZE; ++i) { mLastNSensorRegistrations.push(); } mInitCheck = NO_ERROR; mAckReceiver = new SensorEventAckReceiver(this); mAckReceiver->run("SensorEventAckReceiver", PRIORITY_URGENT_DISPLAY); run("SensorService", PRIORITY_URGENT_DISPLAY); } }
SensorService的初始化主要有:
1. 创建SensorDevice实例,获取Sensor列表
2. 调用SensorDevice.getSensorList(),获取Sensor模块所有传感器列表并为为每个传感器注册监听器
SensorDevice的初始化:
SensorDevice::SensorDevice() : mSensorDevice(0), mSensorModule(0) { status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID, (hw_module_t const**)&mSensorModule); if (mSensorModule) { err = sensors_open_1(&mSensorModule->common, &mSensorDevice); ... ... if (mSensorDevice) { if (mSensorDevice->common.version == SENSORS_DEVICE_API_VERSION_1_1 || mSensorDevice->common.version == SENSORS_DEVICE_API_VERSION_1_2) { } sensor_t const* list; ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list); mActivationCount.setCapacity(count); Info model; for (size_t i=0 ; i<size_t(count) ; i++) { mActivationCount.add(list[i].handle, model); mSensorDevice->activate( reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),list[i].handle, 0); ... ... }
SensorService 及SensorDevice的启动主要实现一下几件事:
1. 调用HAL层的hw_get_modele()方法,加载Sensor模块so文件
2. 调用sensor.h的sensors_open方法打开设备
3. 调用sensors_poll_device_t->activate()对Sensor模块使能
启动一个线程,获取HAL层的数据:
SensorService::threadLoop():
bool SensorService::threadLoop() { SensorDevice& device(SensorDevice::getInstance()); const size_t vcount = mVirtualSensorList.size(); const int halVersion = device.getHalDeviceVersion(); do { ssize_t count = device.poll(mSensorEventBuffer, numEventMax); // 从HAL层读取数据 // Reset sensors_event_t.flags to zero for all events in the buffer. for (int i = 0; i < count; i++) { mSensorEventBuffer[i].flags = 0; } SortedVector< sp<SensorEventConnection> > activeConnections; populateActiveConnections(&activeConnections); ... ... // Send our events to clients. Check the state of wake lock for each client and release the // lock if none of the clients need it. bool needsWakeLock = false; size_t numConnections = activeConnections.size(); for (size_t i=0 ; i < numConnections; ++i) { if (activeConnections[i] != 0) { activeConnections[i]->sendEvents(mSensorEventBuffer, count, mSensorEventScratch, mMapFlushEventsToConnections); // 向客户端发数据 needsWakeLock |= activeConnections[i]->needsWakeLock(); // If the connection has one-shot sensors, it may be cleaned up after first trigger. // Early check for one-shot sensors. if (activeConnections[i]->hasOneShotSensors()) { cleanupAutoDisabledSensorLocked(activeConnections[i], mSensorEventBuffer, count); } } } ... ... abort(); return false; }
进入while循环, 不停的从底层poll数据, 并sendEvent到上层
三. 客户端与服务端之间Sensor数据传递
先看服务器与客户端状态图:1. 上图涉及两个线程:
橘黄色服务端: SensorService::threadLoop 它通过SensorDevice::poll 不停的从HAL获取数据
蓝色客户端:android_hardware_SensorManager::Receiver 从EventQueue中读数据
2. 传递数据是的一个关键宏:sensors_event_t
int32_t version; // sensor 的version int32_t sensor; //sensor 标识每个sensor都唯一 int32_t type; // sensor 的类型一个sensor可有多个类型 如: 陀螺仪有校准后与校准前类型 int32_t reserved0; int64_t timestamp; // sensor产生时间戳 union { union { float data[16]; sensors_vec_t acceleration; //加速sensor sensors_vec_t magnetic; // 磁场感应sensor sensors_vec_t orientation; // 横竖屏sensor sensors_vec_t gyro; // 陀螺仪sensor float temperature; //温度sensor float distance; // 距离sensor float light; // 光感sensor float pressure; //压力sensor float relative_humidity; // 相对湿度sensor uncalibrated_event_t uncalibrated_gyro; // 无定向的陀螺仪sensor uncalibrated_event_t uncalibrated_magnetic; // 无定向的磁场sensor heart_rate_event_t heart_rate; // 心率检测sensor meta_data_event_t meta_data; }; union { uint64_t data[8]; uint64_t step_counter; // 步数检测sensor } u64; }; uint32_t flags; uint32_t reserved1[3]; } sensors_event_t;
4. 使用管道传递数据的原因是由于sensor数据量较大, Binder不能胜任此任务, 所以需要BitTube管道来传递这些数据
5. 数据时序图:
根据图示可以看出客户端与服务端通过Binder建立链接, 通过BitTube管道进行数据传递。
BitTube init函数:
void BitTube::init(size_t rcvbuf, size_t sndbuf) { int sockets[2]; if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets) == 0) { size_t size = DEFAULT_SOCKET_BUFFER_SIZE; setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)); setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf)); // sine we don't use the "return channel", we keep it small... setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &size, sizeof(size)); setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &size, sizeof(size)); fcntl(sockets[0], F_SETFL, O_NONBLOCK); fcntl(sockets[1], F_SETFL, O_NONBLOCK); mReceiveFd = sockets[0]; //socket[0]接受数据 mSendFd = sockets[1]; // socket[1]发送数据 } else { mReceiveFd = -errno; ALOGE("BitTube: pipe creation failed (%s)", strerror(-mReceiveFd)); } }
1. 使用socket[0] 来接收数据
2. 使用socket[1] 来发送数据
3.通过pipe(fds)创建管道,通过fcntl来设置操作管道的方式,设置通道两端的操作方式为O_NONBLOCK ,非阻塞IO方式,read或write调用返回-1和EAGAIN错误。
相关文章推荐
- Android ListView同一个item显示2列的实现方法(仿2列商品列表)
- [android] 显示意图激活另外一个activity
- Android单选对话框的创建
- Android PullToRefresh (ListView GridView 下拉刷新) 使用详解
- Android Studio依赖包aar使用全攻略!
- android 双击事件的实现
- Android Material Design之Toolbar与Palette实践
- Android 仿 窗帘效果 和 登录界面拖动效果 (Scroller类的应用) 附 2个DEMO及源码
- android颜色指列表
- android中RecyclerView使用自定义的列表布局
- Android——加载模式
- Android百度地图点聚合功能
- Android MediaServer初始化流程
- android颜色color.xml设置
- Android中实现在手机屏幕上拖动View(如拖动图片)
- 零成本实现Android/iOS自动化测试:基于Appium和Test Perfect
- Android开发艺术探索读书笔记(二)
- Android获取手机本地图片缩略图
- Android Studio 使用Lambda表达式
- 管理服务的生命周期 Android Service