Sensor batching. Changes to the native code.

Bug: 10109508
Change-Id: I7333f3aac76125a8226a4c99c901fb904588df04
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 32c5c0a..129ea3e 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -106,6 +106,30 @@
     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 @@
             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 @@
     int32_t reserved1[4];
 } ASensorEvent;
 
-
 struct ASensorManager;
 typedef struct ASensorManager ASensorManager;
 
diff --git a/include/gui/ISensorEventConnection.h b/include/gui/ISensorEventConnection.h
index 749065e..00eecc4 100644
--- a/include/gui/ISensorEventConnection.h
+++ b/include/gui/ISensorEventConnection.h
@@ -36,8 +36,10 @@
     DECLARE_META_INTERFACE(SensorEventConnection);
 
     virtual sp<BitTube> 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 9197372..0c81426 100644
--- a/include/gui/Sensor.h
+++ b/include/gui/Sensor.h
@@ -53,7 +53,7 @@
     };
 
             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 @@
     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 @@
     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 759b5cb..8d8493b 100644
--- a/include/gui/SensorEventQueue.h
+++ b/include/gui/SensorEventQueue.h
@@ -68,8 +68,10 @@
     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<Looper> getLooper() const;
diff --git a/libs/gui/ISensorEventConnection.cpp b/libs/gui/ISensorEventConnection.cpp
index 0e51e8e..a80c661 100644
--- a/libs/gui/ISensorEventConnection.cpp
+++ b/libs/gui/ISensorEventConnection.cpp
@@ -33,7 +33,8 @@
 enum {
     GET_SENSOR_CHANNEL = IBinder::FIRST_CALL_TRANSACTION,
     ENABLE_DISABLE,
-    SET_EVENT_RATE
+    SET_EVENT_RATE,
+    FLUSH_SENSOR
 };
 
 class BpSensorEventConnection : public BpInterface<ISensorEventConnection>
@@ -52,12 +53,16 @@
         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 @@
         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 @@
             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 @@
             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 d84c370..da6b0f9 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -32,11 +32,11 @@
 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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 8a1bf41..08b8ac8 100644
--- a/libs/gui/SensorEventQueue.cpp
+++ b/libs/gui/SensorEventQueue.cpp
@@ -107,23 +107,25 @@
 }
 
 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 2fa5dbd..19caa5c 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -47,7 +47,7 @@
             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 @@
             Info model;
             for (size_t i=0 ; i<size_t(count) ; i++) {
                 mActivationCount.add(list[i].handle, model);
-                mSensorDevice->activate(mSensorDevice, list[i].handle, 0);
+                mSensorDevice->activate(
+                        reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
+                        list[i].handle, 0);
             }
         }
     }
@@ -76,15 +78,23 @@
     Mutex::Autolock _l(mLock);
     for (size_t i=0 ; i<size_t(count) ; i++) {
         const Info& info = mActivationCount.valueFor(list[i].handle);
-        result.appendFormat("handle=0x%08x, active-count=%d, rates(ms)={ ",
-                list[i].handle,
-                info.rates.size());
-        for (size_t j=0 ; j<info.rates.size() ; j++) {
-            result.appendFormat("%4.1f%s",
-                    info.rates.valueAt(j) / 1e6f,
-                    j<info.rates.size()-1 ? ", " : "");
+        result.appendFormat("handle=0x%08x, active-count=%d, batch_period(ms)={ ", list[i].handle,
+                            info.batchParams.size());
+        for (size_t j = 0; j < info.batchParams.size(); j++) {
+            BatchParams params = info.batchParams.valueAt(j);
+            result.appendFormat("%4.1f%s", params.batchDelay / 1e6f,
+                                j < info.batchParams.size() - 1 ? ", " : "");
         }
-        result.appendFormat(" }, selected=%4.1f ms\n",  info.delay / 1e6f);
+        result.appendFormat(" }, selected=%4.1f ms\n", info.bestBatchParams.batchDelay / 1e6f);
+
+        result.appendFormat("handle=0x%08x, active-count=%d, batch_timeout(ms)={ ", list[i].handle,
+                            info.batchParams.size());
+        for (size_t j = 0; j < info.batchParams.size(); j++) {
+            BatchParams params = info.batchParams.valueAt(j);
+            result.appendFormat("%4.1f%s", params.batchTimeout / 1e6f,
+                                j < info.batchParams.size() - 1 ? ", " : "");
+        }
+        result.appendFormat(" }, selected=%4.1f ms\n", info.bestBatchParams.batchTimeout / 1e6f);
     }
 }
 
@@ -102,7 +112,8 @@
     if (!mSensorDevice) return NO_INIT;
     ssize_t c;
     do {
-        c = mSensorDevice->poll(mSensorDevice, buffer, count);
+        c = mSensorDevice->poll(reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice),
+                                buffer, count);
     } while (c == -EINTR);
     return c;
 }
@@ -110,7 +121,7 @@
 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 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 @@
     }
 
     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<struct sensors_poll_device_t *> (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<struct sensors_poll_device_t *>(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<struct sensors_poll_device_t *>(mSensorDevice),
+                                   handle, info.bestBatchParams.batchDelay);
 }
 
 int SensorDevice::getHalDeviceVersion() const {
@@ -198,31 +309,58 @@
     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<rates.size() ; i++) {
-        nsecs_t cur = rates.valueAt(i);
-        if (cur < ns) {
-            ns = cur;
+void SensorDevice::Info::selectBatchParams() {
+    BatchParams bestParams(-1, -1, -1);
+
+    if (batchParams.size() > 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 b50e205..761b48c 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<SensorDevice> {
     friend class Singleton<SensorDevice>;
-    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<void*, nsecs_t> 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<void*, BatchParams> 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<int, Info> mActivationCount;
 
@@ -55,7 +85,11 @@
     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 4014477..27967dc 100644
--- a/services/sensorservice/SensorFusion.cpp
+++ b/services/sensorservice/SensorFusion.cpp
@@ -102,6 +102,15 @@
         }
     }
 
+    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 432adbc..b8f360f 100644
--- a/services/sensorservice/SensorFusion.h
+++ b/services/sensorservice/SensorFusion.h
@@ -37,6 +37,7 @@
 
 class SensorFusion : public Singleton<SensorFusion> {
     friend class Singleton<SensorFusion>;
+    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 b483b75..f1d1663 100644
--- a/services/sensorservice/SensorInterface.cpp
+++ b/services/sensorservice/SensorInterface.cpp
@@ -32,7 +32,7 @@
 
 HardwareSensor::HardwareSensor(const sensor_t& sensor)
     : mSensorDevice(SensorDevice::getInstance()),
-      mSensor(&sensor)
+      mSensor(&sensor, mSensorDevice.getHalDeviceVersion())
 {
     ALOGI("%s", sensor.name);
 }
@@ -50,6 +50,16 @@
     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 2e14e57..c295e22 100644
--- a/services/sensorservice/SensorInterface.h
+++ b/services/sensorservice/SensorInterface.h
@@ -38,6 +38,20 @@
 
     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 @@
             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 e3d2a60..7bb6e86 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -213,6 +213,11 @@
                         ? "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 @@
 
         // 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 @@
 }
 
 status_t SensorService::enable(const sp<SensorEventConnection>& connection,
-        int handle)
+        int handle, nsecs_t samplingPeriodNs,  nsecs_t maxBatchReportLatencyNs, int reservedFlags)
 {
     if (mInitCheck != NO_ERROR)
         return mInitCheck;
@@ -511,7 +515,6 @@
     if (sensor == NULL) {
         return BAD_VALUE;
     }
-
     Mutex::Autolock _l(mLock);
     SensorRecord* rec = mActiveSensors.valueFor(handle);
     if (rec == 0) {
@@ -548,10 +551,24 @@
             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 @@
         ns = minDelayNs;
     }
 
-    if (ns < MINIMUM_EVENTS_PERIOD)
-        ns = MINIMUM_EVENTS_PERIOD;
-
     return sensor->setDelay(connection.get(), handle, ns);
 }
 
+status_t SensorService::flushSensor(const sp<SensorEventConnection>& 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 @@
         Mutex::Autolock _l(mConnectionLock);
         size_t i=0;
         while (i<numEvents) {
-            const int32_t curr = buffer[i].sensor;
-            if (mSensorInfo.indexOf(curr) >= 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<numEvents) && (buffer[i].sensor == curr));
+                    scratch[count] = buffer[i];
+                    ++count; ++i;
+                } while ((i<numEvents) && ((buffer[i].sensor == curr) ||
+                         (buffer[i].type == SENSOR_TYPE_META_DATA  &&
+                          buffer[i].meta_data.sensor == curr)));
             } else {
                 i++;
             }
@@ -740,11 +773,13 @@
 }
 
 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::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 69e5dbb..6267dd1 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -52,7 +52,6 @@
 {
     friend class BinderService<SensorService>;
 
-    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 @@
         virtual ~SensorEventConnection();
         virtual void onFirstRef();
         virtual sp<BitTube> 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<SensorService> const mService;
         sp<BitTube> const mChannel;
@@ -141,9 +142,11 @@
 
 public:
     void cleanupConnection(SensorEventConnection* connection);
-    status_t enable(const sp<SensorEventConnection>& connection, int handle);
+    status_t enable(const sp<SensorEventConnection>& connection, int handle,
+                    nsecs_t samplingPeriodNs,  nsecs_t maxBatchReportLatencyNs, int reservedFlags);
     status_t disable(const sp<SensorEventConnection>& connection, int handle);
     status_t setEventRate(const sp<SensorEventConnection>& connection, int handle, nsecs_t ns);
+    status_t flushSensor(const sp<SensorEventConnection>& connection, int handle);
 };
 
 // ---------------------------------------------------------------------------