分享

android sensor 框架分析

 jiffes 2019-02-14

5,sensor数据流分析

前面几章做了很多准备和铺垫,这章终于可以分析sensor数据的传输流程了。主要步骤如下,

1,服务端通过HAL从驱动文件节点中获取sensor数据。

2,服务端通过管道发送数据。

3,客户端通过管道读取数据。

4,客户端吐出数据。

5.1服务端获取数据

启动sensor服务之后,就会调用SensorService.cpp的threadLoop方法,该方法首先不断调用SensorDevice.cpp的poll方法获取sensor数据,

  1. do {
  2. ssize_t count = device.poll(mSensorEventBuffer, numEventMax);

然后遍历activeConnections变量,向每一个客户端发送一份sensor数据。

  1. for (size_t i=0 ; i < numConnections; ++i) {
  2. if (activeConnections[i] != 0) {
  3. activeConnections[i]->sendEvents(mSensorEventBuffer, count, mSensorEventScratch,
  4. mMapFlushEventsToConnections);

poll方法调用流程图如下,


这些方法都很简单,没什么可论述的。加速度sensor的readEvents调用流程图如下,


1,fill方法

Accelerometer.cpp 的readEvents中调用fill方法如下,

ssize_t n = mInputReader.fill(data_fd);

传入的data_fd是NativeSensorManager.h的SensorContext结构体的变量。见第二章2.1.2 小节。

fill方法如下,

  1. ssize_t InputEventCircularReader::fill(int fd)
  2. {
  3. size_t numEventsRead = 0;
  4. if (mFreeSpace) {
  5. const ssize_t nread = read(fd, mHead, mFreeSpace * sizeof(input_event));
  6. if (nread<0 || nread % sizeof(input_event)) {
  7. // we got a partial event!!
  8. return nread<0 ? -errno : -EINVAL;
  9. }
  10. numEventsRead = nread / sizeof(input_event);
  11. if (numEventsRead) {
  12. mHead += numEventsRead;
  13. mFreeSpace -= numEventsRead;
  14. if (mHead > mBufferEnd) {
  15. size_t s = mHead - mBufferEnd;
  16. memcpy(mBuffer, mBufferEnd, s * sizeof(input_event));
  17. mHead = mBuffer + s;
  18. }
  19. }
  20. }
  21. return numEventsRead;
  22. }

  1. struct input_event* const mBuffer;
  2. struct input_event* const mBufferEnd;
  3. struct input_event* mHead;
  4. struct input_event* mCurr;
  5. ssize_t mFreeSpace;

mBuffer表示未读事件;

mHead表示未读事件的第一个,初始为缓冲区首部.

mBufferEnd表示未读事件的最后一个,初始为缓冲区尾部.

mCurr表示当前未读事件

struct input_event结构体定义在kernel/include/uapi/linux/input.h中,

  1. struct input_event {
  2. struct timeval time;
  3. __u16 type;//类型,比如sensor,按键事件等
  4. __u16 code;
  5. __s32 value;//具体的数值
  6. };

2,获取sensor值,

  1. while (count && mInputReader.readEvent(&event)) {
  2. int type = event->type;
  3. if (type == EV_ABS) {
  4. float value = event->value;
  5. if (event->code == EVENT_TYPE_ACCEL_X) {
  6. mPendingEvent.data[0] = value * CONVERT_ACCEL_X;
  7. } else if (event->code == EVENT_TYPE_ACCEL_Y) {
  8. mPendingEvent.data[1] = value * CONVERT_ACCEL_Y;
  9. } else if (event->code == EVENT_TYPE_ACCEL_Z) {
  10. mPendingEvent.data[2] = value * CONVERT_ACCEL_Z;
  11. }
  12. } else if (type == EV_SYN) {
  13. switch (event->code){
  14. case SYN_TIME_SEC:
  15. {
  16. mUseAbsTimeStamp = true;
  17. report_time = event->value*1000000000LL;
  18. }
  19. break;
  20. case SYN_TIME_NSEC:
  21. {
  22. mUseAbsTimeStamp = true;
  23. mPendingEvent.timestamp = report_time+event->value;
  24. }
  25. break;
  26. ···
  27. mInputReader.next();

首先获取加速度sensor三个方向上的值,然后获取对应的时间。

当然,时间有2部分组成,最后转化为ns相加。

InputEventReader.cpp的readEvent方法如下,

  1. ssize_t InputEventCircularReader::readEvent(input_event const** events)
  2. {
  3. *events = mCurr;
  4. ssize_t available = (mBufferEnd - mBuffer) - mFreeSpace;
  5. return available ? 1 : 0;
  6. }

3,读取下一个sensor的值

InputEventReader.cpp的next方法如下,

  1. void InputEventCircularReader::next()
  2. {
  3. mCurr++;
  4. mFreeSpace++;
  5. if (mCurr >= mBufferEnd) {
  6. mCurr = mBuffer;
  7. }
  8. }

这样,通过InputEventReader.cpp读取sensor设备节点的值。

5.2服务端发送数据

Sensor服务端每次读取数据之后,当然,一次读取一组sensor数据,这一组sensor数据可能有几个sensor值,也可能一个都没有。

  1. for (size_t i=0 ; i < numConnections; ++i) {
  2. if (activeConnections[i] != 0) {
  3. activeConnections[i]->sendEvents(mSensorEventBuffer, count, mSensorEventScratch,
  4. mMapFlushEventsToConnections);

调用SensorEventConnection对象的sendEvents方法将数据发送给客户端。发送流程图如下,


最后的write方法如下,

  1. ssize_t BitTube::write(void const* vaddr, size_t size)
  2. {
  3. ssize_t err, len;
  4. do {
  5. len = ::send(mSendFd, vaddr, size, MSG_DONTWAIT | MSG_NOSIGNAL);
  6. // cannot return less than size, since we're using SOCK_SEQPACKET
  7. err = len < 0 ? errno : 0;
  8. } while (err == EINTR);
  9. return err == 0 ? len : -err;
  10. }

利用mSendFd将数据写入管道。

注意, mSensorChannel就是指BitTube.cpp对象,在服务端和客户端共用一个。

5.3客服端读取数据

android_hardware_SensorManager.cpp内部类Receiver的handleEvent首先会读取服务端写入管道的数据,然后发送给Java上层。

读取代码如下,

while ((n = q->read(buffer, 16)) > 0) {

read方法的调用流程图如下,


BitTube.cpp的read方法如下,

  1. ssize_t BitTube::read(void* vaddr, size_t size)
  2. {
  3. ssize_t err, len;
  4. do {
  5. len = ::recv(mReceiveFd, vaddr, size, MSG_DONTWAIT);
  6. err = len < 0 ? errno : 0;
  7. } while (err == EINTR);
  8. if (err == EAGAIN || err == EWOULDBLOCK) {
  9. // EAGAIN means that we have non-blocking I/O but there was
  10. // no data to be read. Nothing the client should care about.
  11. return 0;
  12. }
  13. return err == 0 ? len : -err;
  14. }

使用mReceiveFd从管道中读取服务端发送过来的数据。

5.4客户端发送数据

handleEvent方法获取数据之后, 回调Java层SystemSensorManager的内部类SensorEventQueue的dispatchSensorEvent方法。

  1. env->CallVoidMethod(receiverObj.get(),gBaseEventQueueClassInfo.dispatchSensorEvent,
  2. buffer[i].sensor, mScratch, status, buffer[i].timestamp);

最后调用注册的onSensorChanged吐出数据。

小结:

经过了前面那么多的铺垫,终于论述了数据从服务端到客户端客户端的过程。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多