Merge "SensorService performance improvements." into lmp-dev
diff --git a/include/gui/BitTube.h b/include/gui/BitTube.h
index d32df84..3ecac52 100644
--- a/include/gui/BitTube.h
+++ b/include/gui/BitTube.h
@@ -48,6 +48,9 @@
     // get receive file-descriptor
     int getFd() const;
 
+    // get the send file-descriptor.
+    int getSendFd() const;
+
     // send objects (sized blobs). All objects are guaranteed to be written or the call fails.
     template <typename T>
     static ssize_t sendObjects(const sp<BitTube>& tube,
diff --git a/include/gui/ISensorEventConnection.h b/include/gui/ISensorEventConnection.h
index b296797..f64c6b8 100644
--- a/include/gui/ISensorEventConnection.h
+++ b/include/gui/ISensorEventConnection.h
@@ -40,7 +40,6 @@
                                    nsecs_t maxBatchReportLatencyNs, int reservedFlags) = 0;
     virtual status_t setEventRate(int handle, nsecs_t ns) = 0;
     virtual status_t flush() = 0;
-    virtual void decreaseWakeLockRefCount() = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libs/gui/BitTube.cpp b/libs/gui/BitTube.cpp
index 0282834..3ed1f37 100644
--- a/libs/gui/BitTube.cpp
+++ b/libs/gui/BitTube.cpp
@@ -99,6 +99,11 @@
     return mReceiveFd;
 }
 
+int BitTube::getSendFd() const
+{
+    return mSendFd;
+}
+
 ssize_t BitTube::write(void const* vaddr, size_t size)
 {
     ssize_t err, len;
diff --git a/libs/gui/ISensorEventConnection.cpp b/libs/gui/ISensorEventConnection.cpp
index 8f88141..28fcb53 100644
--- a/libs/gui/ISensorEventConnection.cpp
+++ b/libs/gui/ISensorEventConnection.cpp
@@ -34,8 +34,7 @@
     GET_SENSOR_CHANNEL = IBinder::FIRST_CALL_TRANSACTION,
     ENABLE_DISABLE,
     SET_EVENT_RATE,
-    FLUSH_SENSOR,
-    DECREASE_WAKE_LOCK_REFCOUNT
+    FLUSH_SENSOR
 };
 
 class BpSensorEventConnection : public BpInterface<ISensorEventConnection>
@@ -84,13 +83,6 @@
         remote()->transact(FLUSH_SENSOR, data, &reply);
         return reply.readInt32();
     }
-
-    virtual void decreaseWakeLockRefCount() {
-        Parcel data, reply;
-        data.writeInterfaceToken(ISensorEventConnection::getInterfaceDescriptor());
-        remote()->transact(DECREASE_WAKE_LOCK_REFCOUNT, data, &reply, IBinder::FLAG_ONEWAY);
-        return;
-    }
 };
 
 IMPLEMENT_META_INTERFACE(SensorEventConnection, "android.gui.SensorEventConnection");
@@ -133,11 +125,6 @@
             reply->writeInt32(result);
             return NO_ERROR;
         } break;
-        case DECREASE_WAKE_LOCK_REFCOUNT: {
-            CHECK_INTERFACE(ISensorEventConnection, data, reply);
-            decreaseWakeLockRefCount();
-            return NO_ERROR;
-        } break;
     }
     return BBinder::onTransact(code, data, reply, flags);
 }
diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp
index c2eaf4e..842502d 100644
--- a/libs/gui/SensorEventQueue.cpp
+++ b/libs/gui/SensorEventQueue.cpp
@@ -18,6 +18,7 @@
 
 #include <stdint.h>
 #include <sys/types.h>
+#include <sys/socket.h>
 
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
@@ -147,7 +148,14 @@
 void SensorEventQueue::sendAck(const ASensorEvent* events, int count) {
     for (int i = 0; i < count; ++i) {
         if (events[i].flags & WAKE_UP_SENSOR_EVENT_NEEDS_ACK) {
-            mSensorEventConnection->decreaseWakeLockRefCount();
+            // Send just a byte of data to acknowledge for the wake up sensor events
+            // received
+            char buf = '1';
+            ssize_t size = ::send(mSensorChannel->getFd(), &buf, sizeof(buf),
+                                             MSG_DONTWAIT | MSG_NOSIGNAL);
+            if (size < 0) {
+                ALOGE("sendAck failure %d", size);
+            }
         }
     }
     return;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 6468017..8fe79d0 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -18,6 +18,7 @@
 #include <math.h>
 #include <stdint.h>
 #include <sys/types.h>
+#include <sys/socket.h>
 
 #include <cutils/properties.h>
 
@@ -165,6 +166,7 @@
 
             mWakeLockAcquired = false;
             run("SensorService", PRIORITY_URGENT_DISPLAY);
+            mLooper = new Looper(false);
             mInitCheck = NO_ERROR;
         }
     }
@@ -340,6 +342,8 @@
     SensorDevice& device(SensorDevice::getInstance());
     const size_t vcount = mVirtualSensorList.size();
 
+    SensorEventAckReceiver sender(this);
+    sender.run("SensorEventAckReceiver", PRIORITY_URGENT_DISPLAY);
     ssize_t count;
     const int halVersion = device.getHalDeviceVersion();
     do {
@@ -348,6 +352,11 @@
             ALOGE("sensor poll failed (%s)", strerror(-count));
             break;
         }
+
+        // Reset sensors_event_t.flags to zero for all events in the buffer.
+        for (int i = 0; i < count; i++) {
+             buffer[i].flags = 0;
+        }
         Mutex::Autolock _l(mLock);
         // Poll has returned. Hold a wakelock if one of the events is from a wake up sensor. The
         // rest of this loop is under a critical section protected by mLock. Acquiring a wakeLock,
@@ -443,6 +452,19 @@
     return false;
 }
 
+sp<Looper> SensorService::getLooper() const {
+    return mLooper;
+}
+
+bool SensorService::SensorEventAckReceiver::threadLoop() {
+    ALOGD("new thread SensorEventAckReceiver");
+    do {
+        sp<Looper> looper = mService->getLooper();
+        looper->pollOnce(-1);
+    } while(!Thread::exitPending());
+    return false;
+}
+
 void SensorService::recordLastValueLocked(
         const sensors_event_t* buffer, size_t count) {
     const sensors_event_t* last = NULL;
@@ -656,6 +678,12 @@
         err = sensor->activate(connection.get(), true);
     }
 
+    if (err == NO_ERROR && sensor->getSensor().isWakeUpSensor()) {
+        // Add the file descriptor to the Looper for receiving acknowledgments;
+        int ret = mLooper->addFd(connection->getSensorChannel()->getSendFd(), 0,
+                                        ALOOPER_EVENT_INPUT, connection.get(), NULL);
+    }
+
     if (err != NO_ERROR) {
         // batch/activate has failed, reset our state.
         cleanupWithoutDisableLocked(connection, handle);
@@ -752,9 +780,8 @@
 
 
 bool SensorService::canAccessSensor(const Sensor& sensor) {
-    String16 permissionString(sensor.getRequiredPermission());
-    return permissionString.size() == 0 ||
-            PermissionCache::checkCallingPermission(permissionString);
+    return (sensor.getRequiredPermission().isEmpty()) ||
+            PermissionCache::checkCallingPermission(String16(sensor.getRequiredPermission()));
 }
 
 bool SensorService::verifyCanAccessSensor(const Sensor& sensor, const char* operation) {
@@ -797,7 +824,6 @@
     }
 }
 // ---------------------------------------------------------------------------
-
 SensorService::SensorRecord::SensorRecord(
         const sp<SensorEventConnection>& connection)
 {
@@ -828,25 +854,30 @@
 
 SensorService::SensorEventConnection::SensorEventConnection(
         const sp<SensorService>& service, uid_t uid)
-    : mService(service), mUid(uid), mWakeLockRefCount(0)
-{
+    : mService(service), mUid(uid), mWakeLockRefCount(0), mEventCache(NULL), mCacheSize(0),
+      mMaxCacheSize(0) {
     const SensorDevice& device(SensorDevice::getInstance());
     if (device.getHalDeviceVersion() >= SENSORS_DEVICE_API_VERSION_1_1) {
-        // Increase socket buffer size to 1MB for batching capabilities.
-        mChannel = new BitTube(service->mSocketBufferSize);
+        // Increase socket buffer size to a max of 100 KB for batching capabilities.
+        mChannel = new BitTube(mService->mSocketBufferSize);
     } else {
         mChannel = new BitTube(SOCKET_BUFFER_SIZE_NON_BATCHED);
     }
+#if DEBUG_CONNECTIONS
+    mEventsReceived = mEventsSentFromCache = mEventsSent = 0;
+#endif
 }
 
-SensorService::SensorEventConnection::~SensorEventConnection()
-{
+SensorService::SensorEventConnection::~SensorEventConnection() {
     ALOGD_IF(DEBUG_CONNECTIONS, "~SensorEventConnection(%p)", this);
+    if (mEventCache != NULL) {
+        delete mEventCache;
+    }
     mService->cleanupConnection(this);
 }
 
-void SensorService::SensorEventConnection::onFirstRef()
-{
+void SensorService::SensorEventConnection::onFirstRef() {
+    LooperCallback::onFirstRef();
 }
 
 bool SensorService::SensorEventConnection::needsWakeLock() {
@@ -856,15 +887,28 @@
 
 void SensorService::SensorEventConnection::dump(String8& result) {
     Mutex::Autolock _l(mConnectionLock);
-    result.appendFormat("%d WakeLockRefCount\n", mWakeLockRefCount);
+    result.appendFormat("\t %d WakeLockRefCount \n", mWakeLockRefCount);
     for (size_t i = 0; i < mSensorInfo.size(); ++i) {
         const FlushInfo& flushInfo = mSensorInfo.valueAt(i);
-        result.appendFormat("\t %s | status: %s | pending flush events %d | uid %d\n",
+        result.appendFormat("\t %s | status: %s | pending flush events %d | flush calls %d| uid %d|"
+                            "cache size: %d max cache size %d\n",
                             mService->getSensorName(mSensorInfo.keyAt(i)).string(),
                             flushInfo.mFirstFlushPending ? "First flush pending" :
                                                            "active",
                             flushInfo.mPendingFlushEventsToSend,
-                            mUid);
+                            flushInfo.mNumFlushCalls,
+                            mUid,
+                            mCacheSize,
+                            mMaxCacheSize);
+#if DEBUG_CONNECTIONS
+        result.appendFormat("\t events recvd: %d | sent %d | cache %d | dropped %d\n",
+                                        mEventsReceived,
+                                        mEventsSent,
+                                        mEventsSentFromCache,
+                                        mEventsReceived - (mEventsSentFromCache +
+                                                           mEventsSent + mCacheSize));
+#endif
+
     }
 }
 
@@ -910,8 +954,7 @@
 
 status_t SensorService::SensorEventConnection::sendEvents(
         sensors_event_t const* buffer, size_t numEvents,
-        sensors_event_t* scratch)
-{
+        sensors_event_t* scratch) {
     // filter out events not for this connection
     size_t count = 0;
     Mutex::Autolock _l(mConnectionLock);
@@ -927,30 +970,127 @@
                 curr = buffer[i].meta_data.sensor;
             }
             ssize_t index = mSensorInfo.indexOfKey(curr);
-            if (index >= 0 && mSensorInfo[index].mFirstFlushPending == true &&
-                buffer[i].type == SENSOR_TYPE_META_DATA) {
-                // This is the first flush before activate is called. Events can now be sent for
-                // this sensor on this connection.
-                ALOGD_IF(DEBUG_CONNECTIONS, "First flush event for sensor==%d ",
-                         buffer[i].meta_data.sensor);
-                mSensorInfo.editValueAt(index).mFirstFlushPending = false;
+            // Check if this connection has registered for this sensor. If not continue to the
+            // next sensor_event.
+            if (index < 0) {
+                ++i;
+                continue;
             }
-            if (index >= 0 && mSensorInfo[index].mFirstFlushPending == false)  {
-                do {
+
+            // Check if there is a pending flush_complete event for this sensor on this connection.
+            FlushInfo& flushInfo = mSensorInfo.editValueAt(index);
+            if (buffer[i].type == SENSOR_TYPE_META_DATA) {
+                if (flushInfo.mFirstFlushPending == true) {
+                    // This is the first flush before activate is called. Events can now be sent for
+                    // this sensor on this connection.
+                    ALOGD_IF(DEBUG_CONNECTIONS, "First flush event for sensor==%d ",
+                                                    buffer[i].meta_data.sensor);
+                    flushInfo.mFirstFlushPending = false;
+                    ++i;
+                    continue;
+                }
+            }
+
+            // If there is a pending flush complete event for this sensor on this connection,
+            // ignore the event and proceed to the next.
+            if (flushInfo.mFirstFlushPending) {
+                ++i;
+                continue;
+            }
+
+            do {
+                if (buffer[i].type == SENSOR_TYPE_META_DATA) {
+                    // Send flush complete event only if flush() has been explicitly called by
+                    // this app else ignore.
+                    if (flushInfo.mNumFlushCalls > 0) {
+                        scratch[count++] = buffer[i];
+                        flushInfo.mNumFlushCalls--;
+                    }
+                    ++i;
+                } else {
+                    // Regular sensor event, just copy it to the scratch buffer.
                     scratch[count++] = buffer[i++];
-                } while ((i<numEvents) && ((buffer[i].sensor == curr) ||
-                         (buffer[i].type == SENSOR_TYPE_META_DATA  &&
-                          buffer[i].meta_data.sensor == curr)));
-            } else {
-                i++;
-            }
+                }
+            } while ((i<numEvents) && ((buffer[i].sensor == curr) ||
+                                       (buffer[i].type == SENSOR_TYPE_META_DATA  &&
+                                        buffer[i].meta_data.sensor == curr)));
         }
     } else {
         scratch = const_cast<sensors_event_t *>(buffer);
         count = numEvents;
     }
 
-    // Send pending flush events (if any) before sending events from the cache.
+    // Early return if there are no events for this connection.
+    if (count == 0) {
+        return status_t(NO_ERROR);
+    }
+
+#if DEBUG_CONNECTIONS
+     mEventsReceived += count;
+#endif
+    if (mCacheSize != 0) {
+        // There are some events in the cache which need to be sent first. Copy this buffer to
+        // the end of cache.
+        if (mCacheSize + count <= mMaxCacheSize) {
+            memcpy(&mEventCache[mCacheSize], scratch, count * sizeof(sensors_event_t));
+            mCacheSize += count;
+        } else {
+            // Some events need to be dropped.
+            int remaningCacheSize = mMaxCacheSize - mCacheSize;
+            if (remaningCacheSize != 0) {
+                memcpy(&mEventCache[mCacheSize], scratch,
+                                                remaningCacheSize * sizeof(sensors_event_t));
+            }
+            int numEventsDropped = count - remaningCacheSize;
+            countFlushCompleteEventsLocked(mEventCache, numEventsDropped);
+            // Drop the first "numEventsDropped" in the cache.
+            memmove(mEventCache, &mEventCache[numEventsDropped],
+                    (mCacheSize - numEventsDropped) * sizeof(sensors_event_t));
+
+            // Copy the remainingEvents in scratch buffer to the end of cache.
+            memcpy(&mEventCache[mCacheSize - numEventsDropped], scratch + remaningCacheSize,
+                                            numEventsDropped * sizeof(sensors_event_t));
+        }
+        return status_t(NO_ERROR);
+    }
+
+    int numWakeUpSensorEvents = countWakeUpSensorEventsLocked(scratch, count);
+    mWakeLockRefCount += numWakeUpSensorEvents;
+
+    // NOTE: ASensorEvent and sensors_event_t are the same type.
+    ssize_t size = SensorEventQueue::write(mChannel,
+                                    reinterpret_cast<ASensorEvent const*>(scratch), count);
+    if (size < 0) {
+        // Write error, copy events to local cache.
+        mWakeLockRefCount -= numWakeUpSensorEvents;
+        if (mEventCache == NULL) {
+            mMaxCacheSize = computeMaxCacheSizeLocked();
+            mEventCache = new sensors_event_t[mMaxCacheSize];
+            mCacheSize = 0;
+        }
+        memcpy(&mEventCache[mCacheSize], scratch, count * sizeof(sensors_event_t));
+        mCacheSize += count;
+
+        // Add this file descriptor to the looper to get a callback when this fd is available for
+        // writing.
+        mService->getLooper()->addFd(mChannel->getSendFd(), 0,
+                ALOOPER_EVENT_OUTPUT | ALOOPER_EVENT_INPUT, this, NULL);
+        return size;
+    }
+
+#if DEBUG_CONNECTIONS
+    if (size > 0) {
+        mEventsSent += count;
+    }
+#endif
+
+    return size < 0 ? status_t(size) : status_t(NO_ERROR);
+}
+
+void SensorService::SensorEventConnection::writeToSocketFromCacheLocked() {
+    // At a time write at most half the size of the receiver buffer in SensorEventQueue.
+    const int maxWriteSize = SensorEventQueue::MAX_RECEIVE_BUFFER_EVENT_COUNT/2;
+    // Send pending flush events (if any) before sending events from the buffer.
     {
         ASensorEvent flushCompleteEvent;
         flushCompleteEvent.type = SENSOR_TYPE_META_DATA;
@@ -963,35 +1103,44 @@
                 flushCompleteEvent.meta_data.sensor = mSensorInfo.keyAt(i);
                 ssize_t size = SensorEventQueue::write(mChannel, &flushCompleteEvent, 1);
                 if (size < 0) {
-                    // ALOGW("dropping %d events on the floor", count);
-                    countFlushCompleteEventsLocked(scratch, count);
-                    return size;
+                    return;
                 }
                 ALOGD_IF(DEBUG_CONNECTIONS, "sent dropped flush complete event==%d ",
-                         flushCompleteEvent.meta_data.sensor);
+                                                flushCompleteEvent.meta_data.sensor);
                 flushInfo.mPendingFlushEventsToSend--;
             }
         }
     }
+    // Write "count" events at a time.
+    for (int numEventsSent = 0; numEventsSent < mCacheSize;) {
+        const int count = (mCacheSize - numEventsSent) < maxWriteSize ?
+                                        mCacheSize - numEventsSent : maxWriteSize;
+        int numWakeUpSensorEvents =
+                  countWakeUpSensorEventsLocked(mEventCache + numEventsSent, count);
+        mWakeLockRefCount += numWakeUpSensorEvents;
 
-    // Early return if there are no events for this connection.
-    if (count == 0) {
-        return status_t(NO_ERROR);
+        ssize_t size = SensorEventQueue::write(mChannel,
+                          reinterpret_cast<ASensorEvent const*>(mEventCache + numEventsSent),
+                          count);
+        if (size < 0) {
+            memmove(mEventCache, &mEventCache[numEventsSent],
+                                 (mCacheSize - numEventsSent) * sizeof(sensors_event_t));
+            ALOGD_IF(DEBUG_CONNECTIONS, "wrote %d events from cache size==%d ",
+                                            numEventsSent, mCacheSize);
+            mCacheSize -= numEventsSent;
+            mWakeLockRefCount -= numWakeUpSensorEvents;
+            return;
+        }
+        numEventsSent += count;
+#if DEBUG_CONNECTIONS
+        mEventsSentFromCache += count;
+#endif
     }
-
-    int numWakeUpSensorEvents = countWakeUpSensorEventsLocked(scratch, count);
-    // NOTE: ASensorEvent and sensors_event_t are the same type
-    ssize_t size = SensorEventQueue::write(mChannel,
-            reinterpret_cast<ASensorEvent const*>(scratch), count);
-    if (size == -EAGAIN) {
-        // the destination doesn't accept events anymore, it's probably
-        // full. For now, we just drop the events on the floor.
-        // ALOGW("dropping %d events on the floor", count);
-        countFlushCompleteEventsLocked(scratch, count);
-        mWakeLockRefCount -= numWakeUpSensorEvents;
-        return size;
-    }
-    return size < 0 ? status_t(size) : status_t(NO_ERROR);
+    ALOGD_IF(DEBUG_CONNECTIONS, "wrote all events from cache size=%d ", mCacheSize);
+    // All events from the cache have been sent. Reset cache size to zero.
+    mCacheSize = 0;
+    // Poll only for ALOOPER_EVENT_INPUT(read) on the file descriptor.
+    mService->getLooper()->addFd(mChannel->getSendFd(), 0, ALOOPER_EVENT_INPUT, this, NULL);
 }
 
 void SensorService::SensorEventConnection::countFlushCompleteEventsLocked(
@@ -1015,7 +1164,6 @@
     for (int i = 0; i < count; ++i) {
         if (mService->isWakeUpSensorEvent(scratch[i])) {
             scratch[i].flags |= WAKE_UP_SENSOR_EVENT_NEEDS_ACK;
-            ++mWakeLockRefCount;
             return 1;
         }
     }
@@ -1035,6 +1183,7 @@
     if (enabled) {
         err = mService->enable(this, handle, samplingPeriodNs, maxBatchReportLatencyNs,
                                reservedFlags);
+
     } else {
         err = mService->disable(this, handle);
     }
@@ -1055,14 +1204,16 @@
     // Loop through all sensors for this connection and call flush on each of them.
     for (size_t i = 0; i < mSensorInfo.size(); ++i) {
         const int handle = mSensorInfo.keyAt(i);
+        FlushInfo& flushInfo = mSensorInfo.editValueFor(handle);
         if (halVersion < SENSORS_DEVICE_API_VERSION_1_1 || mService->isVirtualSensor(handle)) {
             // For older devices just increment pending flush count which will send a trivial
             // flush complete event.
-            FlushInfo& flushInfo = mSensorInfo.editValueFor(handle);
             flushInfo.mPendingFlushEventsToSend++;
         } else {
             status_t err_flush = mService->flushSensor(this, handle);
-            if (err_flush != NO_ERROR) {
+            if (err_flush == NO_ERROR) {
+                flushInfo.mNumFlushCalls++;
+            } else {
                 ALOGE("Flush error handle=%d %s", handle, strerror(-err_flush));
             }
             err = (err_flush != NO_ERROR) ? err_flush : err;
@@ -1071,15 +1222,69 @@
     return err;
 }
 
-void SensorService::SensorEventConnection::decreaseWakeLockRefCount() {
-    {
+int SensorService::SensorEventConnection::handleEvent(int fd, int events, void* data) {
+    if (events & ALOOPER_EVENT_HANGUP || events & ALOOPER_EVENT_ERROR) {
+        return 0;
+    }
+
+    if (events & ALOOPER_EVENT_INPUT) {
+        char buf;
+        ssize_t ret = ::recv(fd, &buf, sizeof(buf), MSG_DONTWAIT);
+
+        {
+           Mutex::Autolock _l(mConnectionLock);
+           --mWakeLockRefCount;
+        }
+        // Check if wakelock can be released by sensorservice. mConnectionLock needs to be released
+        // here as checkWakeLockState() will need it.
+        if (mWakeLockRefCount == 0) {
+            mService->checkWakeLockState();
+        }
+        // continue getting callbacks.
+        return 1;
+    }
+
+    if (events & ALOOPER_EVENT_OUTPUT) {
+        // send sensor data that is stored in mEventCache.
         Mutex::Autolock _l(mConnectionLock);
-        --mWakeLockRefCount;
+        writeToSocketFromCacheLocked();
     }
-    // Release the lock before calling checkWakeLockState which also needs the same connectionLock.
-    if (mWakeLockRefCount == 0) {
-        mService->checkWakeLockState();
-    }
+    return 1;
+}
+
+int SensorService::SensorEventConnection::computeMaxCacheSizeLocked() const {
+    int fifoWakeUpSensors = 0;
+    int fifoNonWakeUpSensors = 0;
+    for (size_t i = 0; i < mSensorInfo.size(); ++i) {
+        const Sensor& sensor = mService->getSensorFromHandle(mSensorInfo.keyAt(i));
+        if (sensor.getFifoReservedEventCount() == sensor.getFifoMaxEventCount()) {
+            // Each sensor has a reserved fifo. Sum up the fifo sizes for all wake up sensors and
+            // non wake_up sensors.
+            if (sensor.isWakeUpSensor()) {
+                fifoWakeUpSensors += sensor.getFifoReservedEventCount();
+            } else {
+                fifoNonWakeUpSensors += sensor.getFifoReservedEventCount();
+            }
+        } else {
+            // Shared fifo. Compute the max of the fifo sizes for wake_up and non_wake up sensors.
+            if (sensor.isWakeUpSensor()) {
+                fifoWakeUpSensors = fifoWakeUpSensors > sensor.getFifoMaxEventCount() ?
+                                          fifoWakeUpSensors : sensor.getFifoMaxEventCount();
+
+            } else {
+                fifoNonWakeUpSensors = fifoNonWakeUpSensors > sensor.getFifoMaxEventCount() ?
+                                          fifoNonWakeUpSensors : sensor.getFifoMaxEventCount();
+
+            }
+        }
+   }
+   if (fifoWakeUpSensors + fifoNonWakeUpSensors == 0) {
+       // It is extremely unlikely that there is a write failure in non batch mode. Return a cache
+       // size of 100.
+       ALOGI("Write failure in non-batch mode");
+       return 100;
+   }
+   return fifoWakeUpSensors + fifoNonWakeUpSensors;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 5fd56b8..3cdc825 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -24,7 +24,9 @@
 #include <utils/SortedVector.h>
 #include <utils/KeyedVector.h>
 #include <utils/threads.h>
+#include <utils/AndroidThreads.h>
 #include <utils/RefBase.h>
+#include <utils/Looper.h>
 
 #include <binder/BinderService.h>
 
@@ -38,10 +40,11 @@
 // ---------------------------------------------------------------------------
 
 #define DEBUG_CONNECTIONS   false
-// Max size is 1 MB which is enough to accept a batch of about 10k events.
-#define MAX_SOCKET_BUFFER_SIZE_BATCHED 1024 * 1024
+// Max size is 100 KB which is enough to accept a batch of about 1000 events.
+#define MAX_SOCKET_BUFFER_SIZE_BATCHED 100 * 1024
+// For older HALs which don't support batching, use a smaller socket buffer size.
 #define SOCKET_BUFFER_SIZE_NON_BATCHED 4 * 1024
-#define WAKE_UP_SENSOR_EVENT_NEEDS_ACK (1 << 31)
+#define WAKE_UP_SENSOR_EVENT_NEEDS_ACK (1U << 31)
 
 struct sensors_poll_device_t;
 struct sensors_module_t;
@@ -72,7 +75,8 @@
     virtual sp<ISensorEventConnection> createSensorEventConnection();
     virtual status_t dump(int fd, const Vector<String16>& args);
 
-    class SensorEventConnection : public BnSensorEventConnection {
+    class SensorEventConnection : public BnSensorEventConnection, public LooperCallback {
+        friend class SensorService;
         virtual ~SensorEventConnection();
         virtual void onFirstRef();
         virtual sp<BitTube> getSensorChannel() const;
@@ -80,7 +84,6 @@
                                        nsecs_t maxBatchReportLatencyNs, int reservedFlags);
         virtual status_t setEventRate(int handle, nsecs_t samplingPeriodNs);
         virtual status_t flush();
-        void decreaseWakeLockRefCount();
         // Count the number of flush complete events which are about to be dropped in the buffer.
         // Increment mPendingFlushEventsToSend in mSensorInfo. These flush complete events will be
         // sent separately before the next batch of events.
@@ -90,7 +93,20 @@
         // Increment it by exactly one unit for each packet sent on the socket. SOCK_SEQPACKET for
         // the socket ensures that either the entire packet is read or dropped.
         // Return 1 if mWakeLockRefCount has been incremented, zero if not.
-        int countWakeUpSensorEventsLocked(sensors_event_t* scratch, const int count);
+        int countWakeUpSensorEventsLocked(sensors_event_t* scratch, int count);
+
+        // Writes events from mEventCache to the socket.
+        void writeToSocketFromCacheLocked();
+
+        // Compute the approximate cache size from the FIFO sizes of various sensors registered for
+        // this connection. Wake up and non-wake up sensors have separate FIFOs but FIFO may be
+        // shared amongst wake-up sensors and non-wake up sensors.
+        int computeMaxCacheSizeLocked() const;
+
+        // LooperCallback method. If there is data to read on this fd, it is an ack from the
+        // app that it has read events from a wake up sensor, decrement mWakeLockRefCount.
+        // If this fd is available for writing send the data from the cache.
+        virtual int handleEvent(int fd, int events, void* data);
 
         sp<SensorService> const mService;
         sp<BitTube> mChannel;
@@ -108,10 +124,20 @@
             // Every activate is preceded by a flush. Only after the first flush complete is
             // received, the events for the sensor are sent on that *connection*.
             bool mFirstFlushPending;
-            FlushInfo() : mPendingFlushEventsToSend(0), mFirstFlushPending(false) {}
+            // Number of time flush() was called on this connection. This is incremented every time
+            // flush() is called and decremented when flush_complete_event is received.
+            int mNumFlushCalls;
+            FlushInfo() : mPendingFlushEventsToSend(0), mFirstFlushPending(false),
+                                            mNumFlushCalls(0) {}
         };
         // protected by SensorService::mLock. Key for this vector is the sensor handle.
         KeyedVector<int, FlushInfo> mSensorInfo;
+        sensors_event_t *mEventCache;
+        int mCacheSize, mMaxCacheSize;
+
+#if DEBUG_CONNECTIONS
+        int mEventsReceived, mEventsSent, mEventsSentFromCache;
+#endif
 
     public:
         SensorEventConnection(const sp<SensorService>& service, uid_t uid);
@@ -138,6 +164,13 @@
         size_t getNumConnections() const { return mConnections.size(); }
     };
 
+    class SensorEventAckReceiver : public Thread {
+        sp<SensorService> const mService;
+    public:
+        virtual bool threadLoop();
+        SensorEventAckReceiver(const sp<SensorService>& service): mService(service) {}
+    };
+
     String8 getSensorName(int handle) const;
     bool isVirtualSensor(int handle) const;
     Sensor getSensorFromHandle(int handle) const;
@@ -160,6 +193,9 @@
     void checkWakeLockState();
     void checkWakeLockStateLocked();
     bool isWakeUpSensorEvent(const sensors_event_t& event) const;
+
+    sp<Looper> getLooper() const;
+
     // constants
     Vector<Sensor> mSensorList;
     Vector<Sensor> mUserSensorListDebug;
@@ -168,6 +204,7 @@
     Vector<SensorInterface *> mVirtualSensorList;
     status_t mInitCheck;
     size_t mSocketBufferSize;
+    sp<Looper> mLooper;
 
     // protected by mLock
     mutable Mutex mLock;