今天打开博客,才发现居然有一年多没有写博客了。。。
最近由于公司要分析android上的计步问题,顺便把计步器在android上的实现跟踪了一下。结果发现悲催的是,android的api19上,是用的硬件本身的计步实现了。
android源码中的流程追踪如下:
frameworks/base/core/java/android/hardware/Sensor.java 中定义了TYPE_STEP_DETECTOR和TYPE_STEP_COUNTER。 请注意,detector启动后,确认了,才启动counter.
然后在jni以下查到调用。
frameworks/base/core/jni/android_hardware_SensorManager.cpp
virtual int handleEvent(int fd, int events, void* data) { JNIEnv* env = AndroidRuntime::getJNIEnv(); sp<SensorEventQueue> q = reinterpret_cast<SensorEventQueue *>(data); ssize_t n; ASensorEvent buffer[16]; while ((n = q->read(buffer, 16)) > 0) { for (int i=0 ; i<n ; i++) { if (buffer[i].type == SENSOR_TYPE_STEP_COUNTER) { // step-counter returns a uint64, but the java API only deals with floats float value = float(buffer[i].u64.step_counter); env->SetFloatArrayRegion(mScratch, 0, 1, &value); } else { env->SetFloatArrayRegion(mScratch, 0, 16, buffer[i].data); }
可以看到,如果是计步器,直接从q里面读出的原生值。其中q被转化成了SensorEventQueue.查找转化方法:
frameworks/native/libs/gui/SensorEventQueue.cpp
ssize_t SensorEventQueue::read(ASensorEvent* events, size_t numEvents) { if (mAvailable == 0) { ssize_t err = BitTube::recvObjects(mSensorChannel, mRecBuffer, MAX_RECEIVE_BUFFER_EVENT_COUNT); if (err < 0) { return err; } mAvailable = err; mConsumed = 0; } size_t count = numEvents < mAvailable ? numEvents : mAvailable; memcpy(events, mRecBuffer + mConsumed, count*sizeof(ASensorEvent)); mAvailable -= count; mConsumed += count; return count; }
也就是说,SensorEvent是保存在ASensorEvent的结构中。查找原型。
frameworks/native/include/android/sensor.h
/* NOTE: Must match hardware/sensors.h */ typedef struct ASensorEvent { int32_t version; /* sizeof(struct ASensorEvent) */ int32_t sensor; int32_t type; int32_t reserved0; int64_t timestamp; union { union { float data[16]; ASensorVector vector; ASensorVector acceleration; ASensorVector magnetic; float temperature; float distance; float light; float pressure; float relative_humidity; AUncalibratedEvent uncalibrated_gyro; AUncalibratedEvent uncalibrated_magnetic; AMetaDataEvent meta_data; }; union { uint64_t data[8]; uint64_t step_counter; } u64; }; int32_t reserved1[4]; } ASensorEvent;
这时数据出来了。。。。直接调用硬件上的计步器实现。
hal层的相关文件。
./hardware/libhardware/include/hardware/sensors.h
#define SENSOR_TYPE_STEP_DETECTOR (18) ... #define SENSOR_TYPE_STEP_COUNTER (19)
OK。这时候查找hal层的使用方法。
invensense/65xx/libsensors_iio/sensors_mpl.cpp
202 int sensors_poll_context_t::pollEvents(sensors_event_t *data, int count) 203 { 204 VHANDLER_LOG; 205 206 int nbEvents = 0; 207 int nb, polltime = -1; 208 209 polltime = ((MPLSensor*) mSensor)->getStepCountPollTime(); 210 211 // look for new events 212 nb = poll(mPollFds, numFds, polltime); 213 LOGI_IF(0, "poll nb=%d, count=%d, pt=%d", nb, count, polltime); 214 if (nb > 0) { 215 for (int i = 0; count && i < numSensorDrivers; i++) { 216 if (mPollFds[i].revents & (POLLIN | POLLPRI)) { 217 LOGI_IF(0, "poll found=%d", i); 218 nb = 0; 219 if (i == mpl) { 220 ((MPLSensor*) mSensor)->buildMpuEvent(); 221 mPollFds[i].revents = 0; 222 } else if (i == compass) { 223 ((MPLSensor*) mSensor)->buildCompassEvent(); 224 mPollFds[i].revents = 0; .... 268 if(((MPLSensor*) mSensor)->hasStepCountPendingEvents() == true) { 269 nb = 0; 270 nb = ((MPLSensor*) mSensor)->readDmpPedometerEvents(data, count, ID_SC, SENSOR_TYPE_STEP_COUNTER, 0); 271 LOGI_IF(HANDLER_DATA, "sensors_mpl:readStepCount() - nb=%d, count=%d, nbEvents=%d, data->timestamp=%lld, data->data[0]=%f,", 272 nb, count, nbEvents, data->timestamp, data->data[0]); 273 if (nb > 0) { 274 count -= nb; 275 nbEvents += nb; 276 data += nb; 277 } 278 }
可以看出,270行把数据读出来了。。。
顺便查了一下android中的sensor的实现方法。
https://source.android.com/devices/sensors/sensor-stack.html 官方的介绍。sensor层次的介绍,不是很详细。
https://docs.google.com/file/d/0B2IJqxU5nzCyQWZ1TzhGd3FUWlNCQjhqV0psV1l3dw/edit 2012的文档,现在的实现有变化,大致可以参考一下。
http://processors.wiki.ti.com/index.php/Android_Sensor_PortingGuide 内核层的更改方法。
手上没有nexus5的内核源码,所以暂时没有跟n5中的step counter的内核中的驱动实现。不过这个跟踪过程比较简单了。