android中的计步问题及计步传感器分析

时间:2022-07-16 09:12:24

今天打开博客,才发现居然有一年多没有写博客了。。。


最近由于公司要分析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的内核中的驱动实现。不过这个跟踪过程比较简单了。