From 724d91d778e71c8186399f4955de14b54812b3ed Mon Sep 17 00:00:00 2001 From: Aravind Akella Date: Thu, 27 Jun 2013 12:04:23 -0700 Subject: [PATCH] Sensor batching. Changes to the native code. Bug: 10109508 Change-Id: I7333f3aac76125a8226a4c99c901fb904588df04 --- include/android/sensor.h | 29 ++- include/gui/ISensorEventConnection.h | 4 +- include/gui/Sensor.h | 6 +- include/gui/SensorEventQueue.h | 4 +- libs/gui/ISensorEventConnection.cpp | 30 ++- libs/gui/Sensor.cpp | 29 ++- libs/gui/SensorEventQueue.cpp | 20 +- services/sensorservice/SensorDevice.cpp | 274 ++++++++++++++++----- services/sensorservice/SensorDevice.h | 52 +++- services/sensorservice/SensorFusion.cpp | 9 + services/sensorservice/SensorFusion.h | 1 + services/sensorservice/SensorInterface.cpp | 12 +- services/sensorservice/SensorInterface.h | 17 ++ services/sensorservice/SensorService.cpp | 72 ++++-- services/sensorservice/SensorService.h | 11 +- 15 files changed, 451 insertions(+), 119 deletions(-) diff --git a/include/android/sensor.h b/include/android/sensor.h index 32c5c0a1f..129ea3ebd 100644 --- a/include/android/sensor.h +++ b/include/android/sensor.h @@ -106,6 +106,30 @@ typedef struct ASensorVector { uint8_t reserved[3]; } ASensorVector; +typedef struct AMetaDataEvent { + int32_t what; + int32_t sensor; +} AMetaDataEvent; + +typedef struct AUncalibratedEvent { + union { + float uncalib[3]; + struct { + float x_uncalib; + float y_uncalib; + float z_uncalib; + }; + }; + union { + float bias[3]; + struct { + float x_bias; + float y_bias; + float z_bias; + }; + }; +} AUncalibratedEvent; + /* NOTE: Must match hardware/sensors.h */ typedef struct ASensorEvent { int32_t version; /* sizeof(struct ASensorEvent) */ @@ -123,6 +147,10 @@ typedef struct ASensorEvent { float distance; float light; float pressure; + float relative_humidity; + AUncalibratedEvent uncalibrated_gyro; + AUncalibratedEvent uncalibrated_magnetic; + AMetaDataEvent meta_data; }; union { uint64_t data[8]; @@ -132,7 +160,6 @@ typedef struct ASensorEvent { int32_t reserved1[4]; } ASensorEvent; - struct ASensorManager; typedef struct ASensorManager ASensorManager; diff --git a/include/gui/ISensorEventConnection.h b/include/gui/ISensorEventConnection.h index 749065e84..00eecc479 100644 --- a/include/gui/ISensorEventConnection.h +++ b/include/gui/ISensorEventConnection.h @@ -36,8 +36,10 @@ public: DECLARE_META_INTERFACE(SensorEventConnection); virtual sp getSensorChannel() const = 0; - virtual status_t enableDisable(int handle, bool enabled) = 0; + virtual status_t enableDisable(int handle, bool enabled, nsecs_t samplingPeriodNs, + nsecs_t maxBatchReportLatencyNs, int reservedFlags) = 0; virtual status_t setEventRate(int handle, nsecs_t ns) = 0; + virtual status_t flushSensor(int handle) = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/gui/Sensor.h b/include/gui/Sensor.h index 91973723e..0c8142681 100644 --- a/include/gui/Sensor.h +++ b/include/gui/Sensor.h @@ -53,7 +53,7 @@ public: }; Sensor(); - Sensor(struct sensor_t const* hwSensor); + Sensor(struct sensor_t const* hwSensor, int halVersion = 0); ~Sensor(); const String8& getName() const; @@ -67,6 +67,8 @@ public: int32_t getMinDelay() const; nsecs_t getMinDelayNs() const; int32_t getVersion() const; + int32_t getFifoReservedEventCount() const; + int32_t getFifoMaxEventCount() const; // LightFlattenable protocol inline bool isFixedSize() const { return false; } @@ -85,6 +87,8 @@ private: float mPower; int32_t mMinDelay; int32_t mVersion; + int32_t mFifoReservedEventCount; + int32_t mFifoMaxEventCount; }; // ---------------------------------------------------------------------------- diff --git a/include/gui/SensorEventQueue.h b/include/gui/SensorEventQueue.h index 759b5cb94..8d8493b48 100644 --- a/include/gui/SensorEventQueue.h +++ b/include/gui/SensorEventQueue.h @@ -68,8 +68,10 @@ public: status_t setEventRate(Sensor const* sensor, nsecs_t ns) const; // these are here only to support SensorManager.java - status_t enableSensor(int32_t handle, int32_t us) const; + status_t enableSensor(int32_t handle, int32_t samplingPeriodUs, int maxBatchReportLatencyUs, + int reservedFlags) const; status_t disableSensor(int32_t handle) const; + status_t flushSensor(int32_t handle) const; private: sp getLooper() const; diff --git a/libs/gui/ISensorEventConnection.cpp b/libs/gui/ISensorEventConnection.cpp index 0e51e8ef0..a80c661cb 100644 --- a/libs/gui/ISensorEventConnection.cpp +++ b/libs/gui/ISensorEventConnection.cpp @@ -33,7 +33,8 @@ namespace android { enum { GET_SENSOR_CHANNEL = IBinder::FIRST_CALL_TRANSACTION, ENABLE_DISABLE, - SET_EVENT_RATE + SET_EVENT_RATE, + FLUSH_SENSOR }; class BpSensorEventConnection : public BpInterface @@ -52,12 +53,16 @@ public: return new BitTube(reply); } - virtual status_t enableDisable(int handle, bool enabled) + virtual status_t enableDisable(int handle, bool enabled, nsecs_t samplingPeriodNs, + nsecs_t maxBatchReportLatencyNs, int reservedFlags) { Parcel data, reply; data.writeInterfaceToken(ISensorEventConnection::getInterfaceDescriptor()); data.writeInt32(handle); data.writeInt32(enabled); + data.writeInt64(samplingPeriodNs); + data.writeInt64(maxBatchReportLatencyNs); + data.writeInt32(reservedFlags); remote()->transact(ENABLE_DISABLE, data, &reply); return reply.readInt32(); } @@ -71,6 +76,14 @@ public: remote()->transact(SET_EVENT_RATE, data, &reply); return reply.readInt32(); } + + virtual status_t flushSensor(int handle) { + Parcel data, reply; + data.writeInterfaceToken(ISensorEventConnection::getInterfaceDescriptor()); + data.writeInt32(handle); + remote()->transact(FLUSH_SENSOR, data, &reply); + return reply.readInt32(); + } }; IMPLEMENT_META_INTERFACE(SensorEventConnection, "android.gui.SensorEventConnection"); @@ -91,7 +104,11 @@ status_t BnSensorEventConnection::onTransact( CHECK_INTERFACE(ISensorEventConnection, data, reply); int handle = data.readInt32(); int enabled = data.readInt32(); - status_t result = enableDisable(handle, enabled); + nsecs_t samplingPeriodNs = data.readInt64(); + nsecs_t maxBatchReportLatencyNs = data.readInt64(); + int reservedFlags = data.readInt32(); + status_t result = enableDisable(handle, enabled, samplingPeriodNs, + maxBatchReportLatencyNs, reservedFlags); reply->writeInt32(result); return NO_ERROR; } break; @@ -103,6 +120,13 @@ status_t BnSensorEventConnection::onTransact( reply->writeInt32(result); return NO_ERROR; } break; + case FLUSH_SENSOR: { + CHECK_INTERFACE(ISensorEventConnection, data, reply); + int handle = data.readInt32(); + status_t result = flushSensor(handle); + reply->writeInt32(result); + return NO_ERROR; + } break; } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp index d84c370a1..da6b0f97f 100644 --- a/libs/gui/Sensor.cpp +++ b/libs/gui/Sensor.cpp @@ -32,11 +32,11 @@ namespace android { Sensor::Sensor() : mHandle(0), mType(0), mMinValue(0), mMaxValue(0), mResolution(0), - mPower(0), mMinDelay(0) + mPower(0), mMinDelay(0), mFifoReservedEventCount(0), mFifoMaxEventCount(0) { } -Sensor::Sensor(struct sensor_t const* hwSensor) +Sensor::Sensor(struct sensor_t const* hwSensor, int halVersion) { mName = hwSensor->name; mVendor = hwSensor->vendor; @@ -48,6 +48,15 @@ Sensor::Sensor(struct sensor_t const* hwSensor) mResolution = hwSensor->resolution; mPower = hwSensor->power; mMinDelay = hwSensor->minDelay; + // Set fifo event count zero for older devices which do not support batching. Fused + // sensors also have their fifo counts set to zero. + if (halVersion >= SENSORS_DEVICE_API_VERSION_1_1) { + mFifoReservedEventCount = hwSensor->fifoReservedEventCount; + mFifoMaxEventCount = hwSensor->fifoMaxEventCount; + } else { + mFifoReservedEventCount = 0; + mFifoMaxEventCount = 0; + } } Sensor::~Sensor() @@ -98,12 +107,20 @@ int32_t Sensor::getVersion() const { return mVersion; } +int32_t Sensor::getFifoReservedEventCount() const { + return mFifoReservedEventCount; +} + +int32_t Sensor::getFifoMaxEventCount() const { + return mFifoMaxEventCount; +} + size_t Sensor::getFlattenedSize() const { size_t fixedSize = sizeof(int32_t) * 3 + sizeof(float) * 4 + - sizeof(int32_t); + sizeof(int32_t) * 3; size_t variableSize = sizeof(int32_t) + FlattenableUtils::align<4>(mName.length()) + @@ -133,6 +150,8 @@ status_t Sensor::flatten(void* buffer, size_t size) const { FlattenableUtils::write(buffer, size, mResolution); FlattenableUtils::write(buffer, size, mPower); FlattenableUtils::write(buffer, size, mMinDelay); + FlattenableUtils::write(buffer, size, mFifoReservedEventCount); + FlattenableUtils::write(buffer, size, mFifoMaxEventCount); return NO_ERROR; } @@ -163,7 +182,7 @@ status_t Sensor::unflatten(void const* buffer, size_t size) { size_t fixedSize = sizeof(int32_t) * 3 + sizeof(float) * 4 + - sizeof(int32_t); + sizeof(int32_t) * 3; if (size < fixedSize) { return NO_MEMORY; @@ -177,6 +196,8 @@ status_t Sensor::unflatten(void const* buffer, size_t size) { FlattenableUtils::read(buffer, size, mResolution); FlattenableUtils::read(buffer, size, mPower); FlattenableUtils::read(buffer, size, mMinDelay); + FlattenableUtils::read(buffer, size, mFifoReservedEventCount); + FlattenableUtils::read(buffer, size, mFifoMaxEventCount); return NO_ERROR; } diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp index 8a1bf4182..08b8ac89e 100644 --- a/libs/gui/SensorEventQueue.cpp +++ b/libs/gui/SensorEventQueue.cpp @@ -107,23 +107,25 @@ status_t SensorEventQueue::wake() const } status_t SensorEventQueue::enableSensor(Sensor const* sensor) const { - return mSensorEventConnection->enableDisable(sensor->getHandle(), true); + return mSensorEventConnection->enableDisable(sensor->getHandle(), true, 0, 0, false); } status_t SensorEventQueue::disableSensor(Sensor const* sensor) const { - return mSensorEventConnection->enableDisable(sensor->getHandle(), false); + return mSensorEventConnection->enableDisable(sensor->getHandle(), false, 0, 0, false); } -status_t SensorEventQueue::enableSensor(int32_t handle, int32_t us) const { - status_t err = mSensorEventConnection->enableDisable(handle, true); - if (err == NO_ERROR) { - mSensorEventConnection->setEventRate(handle, us2ns(us)); - } - return err; +status_t SensorEventQueue::enableSensor(int32_t handle, int32_t samplingPeriodUs, + int maxBatchReportLatencyUs, int reservedFlags) const { + return mSensorEventConnection->enableDisable(handle, true, us2ns(samplingPeriodUs), + us2ns(maxBatchReportLatencyUs), reservedFlags); +} + +status_t SensorEventQueue::flushSensor(int32_t handle) const { + return mSensorEventConnection->flushSensor(handle); } status_t SensorEventQueue::disableSensor(int32_t handle) const { - return mSensorEventConnection->enableDisable(handle, false); + return mSensorEventConnection->enableDisable(handle, false, 0, 0, false); } status_t SensorEventQueue::setEventRate(Sensor const* sensor, nsecs_t ns) const { diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp index 2fa5dbd58..19caa5c95 100644 --- a/services/sensorservice/SensorDevice.cpp +++ b/services/sensorservice/SensorDevice.cpp @@ -47,7 +47,7 @@ SensorDevice::SensorDevice() SENSORS_HARDWARE_MODULE_ID, strerror(-err)); if (mSensorModule) { - err = sensors_open(&mSensorModule->common, &mSensorDevice); + err = sensors_open_1(&mSensorModule->common, &mSensorDevice); ALOGE_IF(err, "couldn't open device for module %s (%s)", SENSORS_HARDWARE_MODULE_ID, strerror(-err)); @@ -59,7 +59,9 @@ SensorDevice::SensorDevice() Info model; for (size_t i=0 ; iactivate(mSensorDevice, list[i].handle, 0); + mSensorDevice->activate( + reinterpret_cast(mSensorDevice), + list[i].handle, 0); } } } @@ -76,15 +78,23 @@ void SensorDevice::dump(String8& result) Mutex::Autolock _l(mLock); for (size_t i=0 ; ipoll(mSensorDevice, buffer, count); + c = mSensorDevice->poll(reinterpret_cast (mSensorDevice), + buffer, count); } while (c == -EINTR); return c; } @@ -110,7 +121,7 @@ ssize_t SensorDevice::poll(sensors_event_t* buffer, size_t count) { void SensorDevice::autoDisable(void *ident, int handle) { Info& info( mActivationCount.editValueFor(handle) ); Mutex::Autolock _l(mLock); - info.rates.removeItem(ident); + info.removeBatchParamsForIdent(ident); } status_t SensorDevice::activate(void* ident, int handle, int enabled) @@ -119,35 +130,46 @@ status_t SensorDevice::activate(void* ident, int handle, int enabled) status_t err(NO_ERROR); bool actuateHardware = false; + Mutex::Autolock _l(mLock); Info& info( mActivationCount.editValueFor(handle) ); - ALOGD_IF(DEBUG_CONNECTIONS, - "SensorDevice::activate: ident=%p, handle=0x%08x, enabled=%d, count=%d", - ident, handle, enabled, info.rates.size()); + "SensorDevice::activate: ident=%p, handle=0x%08x, enabled=%d, count=%d", + ident, handle, enabled, info.batchParams.size()); if (enabled) { - Mutex::Autolock _l(mLock); - ALOGD_IF(DEBUG_CONNECTIONS, "... index=%ld", - info.rates.indexOfKey(ident)); + ALOGD_IF(DEBUG_CONNECTIONS, "enable index=%d", info.batchParams.indexOfKey(ident)); - if (info.rates.indexOfKey(ident) < 0) { - info.rates.add(ident, DEFAULT_EVENTS_PERIOD); - if (info.rates.size() == 1) { - actuateHardware = true; - } + if (info.batchParams.indexOfKey(ident) >= 0) { + if (info.batchParams.size() == 1) { + // This is the first connection, we need to activate the underlying h/w sensor. + actuateHardware = true; + } } else { - // sensor was already activated for this ident + // Log error. Every activate call should be preceded by a batch() call. + ALOGE("\t >>>ERROR: activate called without batch"); } } else { - Mutex::Autolock _l(mLock); - ALOGD_IF(DEBUG_CONNECTIONS, "... index=%ld", - info.rates.indexOfKey(ident)); + ALOGD_IF(DEBUG_CONNECTIONS, "disable index=%d", info.batchParams.indexOfKey(ident)); - ssize_t idx = info.rates.removeItem(ident); - if (idx >= 0) { - if (info.rates.size() == 0) { + if (info.removeBatchParamsForIdent(ident) >= 0) { + if (info.batchParams.size() == 0) { + // This is the last connection, we need to de-activate the underlying h/w sensor. actuateHardware = true; + } else { + const int halVersion = getHalDeviceVersion(); + if (halVersion >= SENSORS_DEVICE_API_VERSION_1_1) { + // Call batch for this sensor with the previously calculated best effort + // batch_rate and timeout. One of the apps has unregistered for sensor + // events, and the best effort batch parameters might have changed. + ALOGD_IF(DEBUG_CONNECTIONS, + "\t>>> actuating h/w batch %d %d %lld %lld ", handle, + info.bestBatchParams.flags, info.bestBatchParams.batchDelay, + info.bestBatchParams.batchTimeout); + mSensorDevice->batch(mSensorDevice, handle,info.bestBatchParams.flags, + info.bestBatchParams.batchDelay, + info.bestBatchParams.batchTimeout); + } } } else { // sensor wasn't enabled for this ident @@ -155,41 +177,130 @@ status_t SensorDevice::activate(void* ident, int handle, int enabled) } if (actuateHardware) { - ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w"); + ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle, enabled); + err = mSensorDevice->activate( + reinterpret_cast (mSensorDevice), handle, enabled); + ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" : "disabling", handle, + strerror(-err)); - err = mSensorDevice->activate(mSensorDevice, handle, enabled); - ALOGE_IF(err, "Error %s sensor %d (%s)", - enabled ? "activating" : "disabling", - handle, strerror(-err)); - - if (err != NO_ERROR) { - // clean-up on failure - if (enabled) { - // failure when enabling the sensor - Mutex::Autolock _l(mLock); - info.rates.removeItem(ident); - } + if (err != NO_ERROR && enabled) { + // Failure when enabling the sensor. Clean up on failure. + info.removeBatchParamsForIdent(ident); } } - { // scope for the lock - Mutex::Autolock _l(mLock); - nsecs_t ns = info.selectDelay(); - mSensorDevice->setDelay(mSensorDevice, handle, ns); + // On older devices which do not support batch, call setDelay(). + if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1 && info.batchParams.size() > 0) { + ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w setDelay %d %lld ", handle, + info.bestBatchParams.batchDelay); + mSensorDevice->setDelay( + reinterpret_cast(mSensorDevice), + handle, info.bestBatchParams.batchDelay); } - return err; } -status_t SensorDevice::setDelay(void* ident, int handle, int64_t ns) +status_t SensorDevice::batch(void* ident, int handle, int flags, int64_t samplingPeriodNs, + int64_t maxBatchReportLatencyNs) { + if (!mSensorDevice) return NO_INIT; + + if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) { + samplingPeriodNs = MINIMUM_EVENTS_PERIOD; + } + + const int halVersion = getHalDeviceVersion(); + if (halVersion >= SENSORS_DEVICE_API_VERSION_1_1) { + if (flags & SENSORS_BATCH_DRY_RUN) { + return mSensorDevice->batch(mSensorDevice, handle, flags, samplingPeriodNs, + maxBatchReportLatencyNs); + } else { + // Call h/w with dry run to see if the given parameters are feasible or not. Return if + // there is an error. + status_t errDryRun(NO_ERROR); + errDryRun = mSensorDevice->batch(mSensorDevice, handle, flags | SENSORS_BATCH_DRY_RUN, + samplingPeriodNs, maxBatchReportLatencyNs); + if (errDryRun != NO_ERROR) { + ALOGD_IF(DEBUG_CONNECTIONS, "SensorDevice::batch dry run error %s", + strerror(-errDryRun)); + return errDryRun; + } + } + } else if (maxBatchReportLatencyNs != 0) { + // Batch is not supported on older devices. + return INVALID_OPERATION; + } + + ALOGD_IF(DEBUG_CONNECTIONS, + "SensorDevice::batch: ident=%p, handle=0x%08x, flags=%d, period_ns=%lld timeout=%lld", + ident, handle, flags, samplingPeriodNs, maxBatchReportLatencyNs); + + Mutex::Autolock _l(mLock); + Info& info(mActivationCount.editValueFor(handle)); + + if (info.batchParams.indexOfKey(ident) < 0) { + BatchParams params(flags, samplingPeriodNs, maxBatchReportLatencyNs); + info.batchParams.add(ident, params); + } else { + // A batch has already been called with this ident. Update the batch parameters. + info.setBatchParamsForIdent(ident, flags, samplingPeriodNs, maxBatchReportLatencyNs); + } + + BatchParams prevBestBatchParams = info.bestBatchParams; + // Find the minimum of all timeouts and batch_rates for this sensor. + info.selectBatchParams(); + + ALOGD_IF(DEBUG_CONNECTIONS, + "\t>>> curr_period=%lld min_period=%lld curr_timeout=%lld min_timeout=%lld", + prevBestBatchParams.batchDelay, info.bestBatchParams.batchDelay, + prevBestBatchParams.batchTimeout, info.bestBatchParams.batchTimeout); + + status_t err(NO_ERROR); + // If the min period or min timeout has changed since the last batch call, call batch. + if (prevBestBatchParams != info.bestBatchParams) { + if (halVersion >= SENSORS_DEVICE_API_VERSION_1_1) { + ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w BATCH %d %d %lld %lld ", handle, + info.bestBatchParams.flags, info.bestBatchParams.batchDelay, + info.bestBatchParams.batchTimeout); + err = mSensorDevice->batch(mSensorDevice, handle, info.bestBatchParams.flags, + info.bestBatchParams.batchDelay, + info.bestBatchParams.batchTimeout); + } else { + // For older devices which do not support batch, call setDelay() after activate() is + // called. Some older devices may not support calling setDelay before activate(), so + // call setDelay in SensorDevice::activate() method. + } + if (err != NO_ERROR) { + ALOGE("sensor batch failed %p %d %d %lld %lld err=%s", mSensorDevice, handle, + info.bestBatchParams.flags, info.bestBatchParams.batchDelay, + info.bestBatchParams.batchTimeout, strerror(-err)); + info.removeBatchParamsForIdent(ident); + } + } + return err; +} + +status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodNs) { if (!mSensorDevice) return NO_INIT; + if (samplingPeriodNs < MINIMUM_EVENTS_PERIOD) { + samplingPeriodNs = MINIMUM_EVENTS_PERIOD; + } Mutex::Autolock _l(mLock); Info& info( mActivationCount.editValueFor(handle) ); - status_t err = info.setDelayForIdent(ident, ns); - if (err < 0) return err; - ns = info.selectDelay(); - return mSensorDevice->setDelay(mSensorDevice, handle, ns); + // 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 != 0) { + return INVALID_OPERATION; + } + ssize_t index = info.batchParams.indexOfKey(ident); + if (index < 0) { + return BAD_INDEX; + } + BatchParams& params = info.batchParams.editValueAt(index); + params.batchDelay = samplingPeriodNs; + info.selectBatchParams(); + return mSensorDevice->setDelay(reinterpret_cast(mSensorDevice), + handle, info.bestBatchParams.batchDelay); } int SensorDevice::getHalDeviceVersion() const { @@ -198,31 +309,58 @@ int SensorDevice::getHalDeviceVersion() const { return mSensorDevice->common.version; } +status_t SensorDevice::flush(void* ident, int handle) { + if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1) { + return INVALID_OPERATION; + } + ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle); + return mSensorDevice->flush(mSensorDevice, handle); +} + // --------------------------------------------------------------------------- -status_t SensorDevice::Info::setDelayForIdent(void* ident, int64_t ns) -{ - ssize_t index = rates.indexOfKey(ident); +status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int flags, + int64_t samplingPeriodNs, + int64_t maxBatchReportLatencyNs) { + ssize_t index = batchParams.indexOfKey(ident); if (index < 0) { - ALOGE("Info::setDelayForIdent(ident=%p, ns=%lld) failed (%s)", - ident, ns, strerror(-index)); + ALOGE("Info::setBatchParamsForIdent(ident=%p, period_ns=%lld timeout=%lld) failed (%s)", + ident, samplingPeriodNs, maxBatchReportLatencyNs, strerror(-index)); return BAD_INDEX; } - rates.editValueAt(index) = ns; + BatchParams& params = batchParams.editValueAt(index); + params.flags = flags; + params.batchDelay = samplingPeriodNs; + params.batchTimeout = maxBatchReportLatencyNs; return NO_ERROR; } -nsecs_t SensorDevice::Info::selectDelay() -{ - nsecs_t ns = rates.valueAt(0); - for (size_t i=1 ; i 0) { + BatchParams params = batchParams.valueAt(0); + bestParams = params; + } + + for (size_t i = 1; i < batchParams.size(); ++i) { + BatchParams params = batchParams.valueAt(i); + if (params.batchDelay < bestParams.batchDelay) { + bestParams.batchDelay = params.batchDelay; + } + if (params.batchTimeout < bestParams.batchTimeout) { + bestParams.batchTimeout = params.batchTimeout; } } - delay = ns; - return ns; + bestBatchParams = bestParams; +} + +ssize_t SensorDevice::Info::removeBatchParamsForIdent(void* ident) { + ssize_t idx = batchParams.removeItem(ident); + if (idx >= 0) { + selectBatchParams(); + } + return idx; } // --------------------------------------------------------------------------- diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h index b50e20582..761b48cf5 100644 --- a/services/sensorservice/SensorDevice.h +++ b/services/sensorservice/SensorDevice.h @@ -31,20 +31,50 @@ namespace android { // --------------------------------------------------------------------------- -static const nsecs_t DEFAULT_EVENTS_PERIOD = 200000000; // 5 Hz - class SensorDevice : public Singleton { friend class Singleton; - struct sensors_poll_device_t* mSensorDevice; + sensors_poll_device_1_t* mSensorDevice; struct sensors_module_t* mSensorModule; - mutable Mutex mLock; // protect mActivationCount[].rates + static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz + mutable Mutex mLock; // protect mActivationCount[].batchParams // fixed-size array after construction + + // Struct to store all the parameters(samplingPeriod, maxBatchReportLatency and flags) from + // batch call. For continous mode clients, maxBatchReportLatency is set to zero. + struct BatchParams { + int flags; + nsecs_t batchDelay, batchTimeout; + BatchParams() : flags(0), batchDelay(0), batchTimeout(0) {} + BatchParams(int flag, nsecs_t delay, nsecs_t timeout): flags(flag), batchDelay(delay), + batchTimeout(timeout) { } + bool operator != (const BatchParams& other) { + return other.batchDelay != batchDelay || other.batchTimeout != batchTimeout || + other.flags != flags; + } + }; + + // Store batch parameters in the KeyedVector and the optimal batch_rate and timeout in + // bestBatchParams. For every batch() call corresponding params are stored in batchParams + // vector. A continuous mode request is batch(... timeout=0 ..) followed by activate(). A batch + // mode request is batch(... timeout > 0 ...) followed by activate(). + // Info is a per-sensor data structure which contains the batch parameters for each client that + // has registered for this sensor. struct Info { - Info() : delay(0) { } - KeyedVector rates; - nsecs_t delay; - status_t setDelayForIdent(void* ident, int64_t ns); - nsecs_t selectDelay(); + BatchParams bestBatchParams; + // Key is the unique identifier(ident) for each client, value is the batch parameters + // requested by the client. + KeyedVector batchParams; + + Info() : bestBatchParams(-1, -1, -1) {} + // Sets batch parameters for this ident. Returns error if this ident is not already present + // in the KeyedVector above. + status_t setBatchParamsForIdent(void* ident, int flags, int64_t samplingPeriodNs, + int64_t maxBatchReportLatencyNs); + // Finds the optimal parameters for batching and stores them in bestBatchParams variable. + void selectBatchParams(); + // Removes batchParams for an ident and re-computes bestBatchParams. Returns the index of + // the removed ident. If index >=0, ident is present and successfully removed. + ssize_t removeBatchParamsForIdent(void* ident); }; DefaultKeyedVector mActivationCount; @@ -55,7 +85,11 @@ public: int getHalDeviceVersion() const; ssize_t poll(sensors_event_t* buffer, size_t count); status_t activate(void* ident, int handle, int enabled); + status_t batch(void* ident, int handle, int flags, int64_t samplingPeriodNs, + int64_t maxBatchReportLatencyNs); + // Call batch with timeout zero instead of calling setDelay() for newer devices. status_t setDelay(void* ident, int handle, int64_t ns); + status_t flush(void* ident, int handle); void autoDisable(void *ident, int handle); void dump(String8& result); }; diff --git a/services/sensorservice/SensorFusion.cpp b/services/sensorservice/SensorFusion.cpp index 401447788..27967dc76 100644 --- a/services/sensorservice/SensorFusion.cpp +++ b/services/sensorservice/SensorFusion.cpp @@ -102,6 +102,15 @@ status_t SensorFusion::activate(void* ident, bool enabled) { } } + if (enabled) { + ALOGD("SensorFusion calling batch ident=%p ", ident); + // Activating a sensor in continuous mode is equivalent to calling batch with the default + // period and timeout equal to ZERO, followed by a call to activate. + mSensorDevice.batch(ident, mAcc.getHandle(), 0, DEFAULT_EVENTS_PERIOD, 0); + mSensorDevice.batch(ident, mMag.getHandle(), 0, DEFAULT_EVENTS_PERIOD, 0); + mSensorDevice.batch(ident, mGyro.getHandle(), 0, DEFAULT_EVENTS_PERIOD, 0); + } + mSensorDevice.activate(ident, mAcc.getHandle(), enabled); mSensorDevice.activate(ident, mMag.getHandle(), enabled); mSensorDevice.activate(ident, mGyro.getHandle(), enabled); diff --git a/services/sensorservice/SensorFusion.h b/services/sensorservice/SensorFusion.h index 432adbcfd..b8f360f52 100644 --- a/services/sensorservice/SensorFusion.h +++ b/services/sensorservice/SensorFusion.h @@ -37,6 +37,7 @@ class SensorDevice; class SensorFusion : public Singleton { friend class Singleton; + static const nsecs_t DEFAULT_EVENTS_PERIOD = 200000000; // 5 Hz SensorDevice& mSensorDevice; Sensor mAcc; diff --git a/services/sensorservice/SensorInterface.cpp b/services/sensorservice/SensorInterface.cpp index b483b7514..f1d16634b 100644 --- a/services/sensorservice/SensorInterface.cpp +++ b/services/sensorservice/SensorInterface.cpp @@ -32,7 +32,7 @@ SensorInterface::~SensorInterface() HardwareSensor::HardwareSensor(const sensor_t& sensor) : mSensorDevice(SensorDevice::getInstance()), - mSensor(&sensor) + mSensor(&sensor, mSensorDevice.getHalDeviceVersion()) { ALOGI("%s", sensor.name); } @@ -50,6 +50,16 @@ status_t HardwareSensor::activate(void* ident, bool enabled) { return mSensorDevice.activate(ident, mSensor.getHandle(), enabled); } +status_t HardwareSensor::batch(void* ident, int handle, int flags, + int64_t samplingPeriodNs, int64_t maxBatchReportLatencyNs) { + return mSensorDevice.batch(ident, mSensor.getHandle(), flags, samplingPeriodNs, + maxBatchReportLatencyNs); +} + +status_t HardwareSensor::flush(void* ident, int handle) { + return mSensorDevice.flush(ident, handle); +} + status_t HardwareSensor::setDelay(void* ident, int handle, int64_t ns) { return mSensorDevice.setDelay(ident, handle, ns); } diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h index 2e14e5782..c295e22dc 100644 --- a/services/sensorservice/SensorInterface.h +++ b/services/sensorservice/SensorInterface.h @@ -38,6 +38,20 @@ public: virtual status_t activate(void* ident, bool enabled) = 0; virtual status_t setDelay(void* ident, int handle, int64_t ns) = 0; + + // Not all sensors need to support batching. + virtual status_t batch(void* ident, int handle, int flags, int64_t samplingPeriodNs, + int64_t maxBatchReportLatencyNs) { + if (maxBatchReportLatencyNs == 0) { + return setDelay(ident, handle, samplingPeriodNs); + } + return -EINVAL; + } + + virtual status_t flush(void* ident, int handle) { + return -EINVAL; + } + virtual Sensor getSensor() const = 0; virtual bool isVirtual() const = 0; virtual void autoDisable(void *ident, int handle) { } @@ -59,7 +73,10 @@ public: const sensors_event_t& event); virtual status_t activate(void* ident, bool enabled); + virtual status_t batch(void* ident, int handle, int flags, int64_t samplingPeriodNs, + int64_t maxBatchReportLatencyNs); virtual status_t setDelay(void* ident, int handle, int64_t ns); + virtual status_t flush(void* ident, int handle); virtual Sensor getSensor() const; virtual bool isVirtual() const { return false; } virtual void autoDisable(void *ident, int handle); diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index e3d2a60bd..7bb6e8649 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -213,6 +213,11 @@ status_t SensorService::dump(int fd, const Vector& args) ? "on-demand | " : "one-shot | "); } + if (s.getFifoMaxEventCount() > 0) { + result.appendFormat("getFifoMaxEventCount=%d events | ", s.getFifoMaxEventCount()); + } else { + result.append("no batching support | "); + } switch (s.getType()) { case SENSOR_TYPE_ROTATION_VECTOR: @@ -384,7 +389,6 @@ bool SensorService::threadLoop() // We have read the data, upper layers should hold the wakelock. if (wakeLockAcquired) release_wake_lock(WAKE_LOCK_NAME); - } while (count >= 0 || Thread::exitPending()); ALOGW("Exiting SensorService::threadLoop => aborting..."); @@ -502,7 +506,7 @@ void SensorService::cleanupConnection(SensorEventConnection* c) } status_t SensorService::enable(const sp& connection, - int handle) + int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags) { if (mInitCheck != NO_ERROR) return mInitCheck; @@ -511,7 +515,6 @@ status_t SensorService::enable(const sp& connection, if (sensor == NULL) { return BAD_VALUE; } - Mutex::Autolock _l(mLock); SensorRecord* rec = mActiveSensors.valueFor(handle); if (rec == 0) { @@ -548,10 +551,24 @@ status_t SensorService::enable(const sp& connection, handle, connection.get()); } - // we are setup, now enable the sensor. - status_t err = sensor->activate(connection.get(), true); + nsecs_t minDelayNs = sensor->getSensor().getMinDelayNs(); + if (samplingPeriodNs < minDelayNs) { + samplingPeriodNs = minDelayNs; + } + + ALOGD_IF(DEBUG_CONNECTIONS, "Calling batch handle==%d flags=%d rate=%lld timeout== %lld", + handle, reservedFlags, samplingPeriodNs, maxBatchReportLatencyNs); + + status_t err = sensor->batch(connection.get(), handle, reservedFlags, samplingPeriodNs, + maxBatchReportLatencyNs); + + if (err == NO_ERROR) { + ALOGD_IF(DEBUG_CONNECTIONS, "Calling activate on %d", handle); + err = sensor->activate(connection.get(), true); + } + if (err != NO_ERROR) { - // enable has failed, reset our state. + // batch/activate has failed, reset our state. cleanupWithoutDisableLocked(connection, handle); } return err; @@ -618,12 +635,18 @@ status_t SensorService::setEventRate(const sp& connection ns = minDelayNs; } - if (ns < MINIMUM_EVENTS_PERIOD) - ns = MINIMUM_EVENTS_PERIOD; - return sensor->setDelay(connection.get(), handle, ns); } +status_t SensorService::flushSensor(const sp& connection, + int handle) { + if (mInitCheck != NO_ERROR) return mInitCheck; + SensorInterface* sensor = mSensorMap.valueFor(handle); + if (sensor == NULL) { + return BAD_VALUE; + } + return sensor->flush(connection.get(), handle); +} // --------------------------------------------------------------------------- SensorService::SensorRecord::SensorRecord( @@ -707,11 +730,21 @@ status_t SensorService::SensorEventConnection::sendEvents( Mutex::Autolock _l(mConnectionLock); size_t i=0; while (i= 0) { + int32_t curr = buffer[i].sensor; + if (buffer[i].type == SENSOR_TYPE_META_DATA) { + ALOGD_IF(DEBUG_CONNECTIONS, "flush complete event sensor==%d ", + buffer[i].meta_data.sensor); + // Setting curr to the correct sensor to ensure the sensor events per connection are + // filtered correctly. buffer[i].sensor is zero for meta_data events. + curr = buffer[i].meta_data.sensor; + } + if (mSensorInfo.indexOf(curr) >= 0) { do { - scratch[count++] = buffer[i++]; - } while ((i SensorService::SensorEventConnection::getSensorChannel() const } status_t SensorService::SensorEventConnection::enableDisable( - int handle, bool enabled) + int handle, bool enabled, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, + int reservedFlags) { status_t err; if (enabled) { - err = mService->enable(this, handle); + err = mService->enable(this, handle, samplingPeriodNs, maxBatchReportLatencyNs, + reservedFlags); } else { err = mService->disable(this, handle); } @@ -752,11 +787,14 @@ status_t SensorService::SensorEventConnection::enableDisable( } status_t SensorService::SensorEventConnection::setEventRate( - int handle, nsecs_t ns) + int handle, nsecs_t samplingPeriodNs) { - return mService->setEventRate(this, handle, ns); + return mService->setEventRate(this, handle, samplingPeriodNs); } +status_t SensorService::SensorEventConnection::flushSensor(int handle) { + return mService->flushSensor(this, handle); +} // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h index 69e5dbb1d..6267dd1a6 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -52,7 +52,6 @@ class SensorService : { friend class BinderService; - static const nsecs_t MINIMUM_EVENTS_PERIOD = 1000000; // 1000 Hz static const char* WAKE_LOCK_NAME; static char const* getServiceName() ANDROID_API { return "sensorservice"; } @@ -74,8 +73,10 @@ class SensorService : virtual ~SensorEventConnection(); virtual void onFirstRef(); virtual sp getSensorChannel() const; - virtual status_t enableDisable(int handle, bool enabled); - virtual status_t setEventRate(int handle, nsecs_t ns); + virtual status_t enableDisable(int handle, bool enabled, nsecs_t samplingPeriodNs, + nsecs_t maxBatchReportLatencyNs, int reservedFlags); + virtual status_t setEventRate(int handle, nsecs_t samplingPeriodNs); + virtual status_t flushSensor(int handle); sp const mService; sp const mChannel; @@ -141,9 +142,11 @@ class SensorService : public: void cleanupConnection(SensorEventConnection* connection); - status_t enable(const sp& connection, int handle); + status_t enable(const sp& connection, int handle, + nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags); status_t disable(const sp& connection, int handle); status_t setEventRate(const sp& connection, int handle, nsecs_t ns); + status_t flushSensor(const sp& connection, int handle); }; // ---------------------------------------------------------------------------