Merge "Prevent overflow when caching sensor events"
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 0fb4ac6..8dc80cc 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -315,32 +315,7 @@
     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 {
-            // Check if any new sensors have registered on this connection which may have increased
-            // the max cache size that is desired.
-            if (mCacheSize + count < computeMaxCacheSizeLocked()) {
-                reAllocateCacheLocked(scratch, count);
-                return status_t(NO_ERROR);
-            }
-            // 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));
-        }
+        appendEventsToCacheLocked(scratch, count);
         return status_t(NO_ERROR);
     }
 
@@ -376,8 +351,8 @@
             mEventCache = new sensors_event_t[mMaxCacheSize];
             mCacheSize = 0;
         }
-        memcpy(&mEventCache[mCacheSize], scratch, count * sizeof(sensors_event_t));
-        mCacheSize += count;
+        // Save the events so that they can be written later
+        appendEventsToCacheLocked(scratch, count);
 
         // Add this file descriptor to the looper to get a callback when this fd is available for
         // writing.
@@ -417,6 +392,51 @@
     mMaxCacheSize = new_cache_size;
 }
 
+void SensorService::SensorEventConnection::appendEventsToCacheLocked(sensors_event_t const* events,
+                                                                     int count) {
+    if (count <= 0) {
+        return;
+    } else if (mCacheSize + count <= mMaxCacheSize) {
+        // The events fit within the current cache: add them
+        memcpy(&mEventCache[mCacheSize], events, count * sizeof(sensors_event_t));
+        mCacheSize += count;
+    } else if (mCacheSize + count <= computeMaxCacheSizeLocked()) {
+        // The events fit within a resized cache: resize the cache and add the events
+        reAllocateCacheLocked(events, count);
+    } else {
+        // The events do not fit within the cache: drop the oldest events.
+        ALOGW("Dropping events from cache (%d / %d) to save %d newer events", mCacheSize,
+                mMaxCacheSize, count);
+
+        int freeSpace = mMaxCacheSize - mCacheSize;
+
+        // Drop up to the currently cached number of events to make room for new events
+        int cachedEventsToDrop = std::min(mCacheSize, count - freeSpace);
+
+        // New events need to be dropped if there are more new events than the size of the cache
+        int newEventsToDrop = std::max(0, count - mMaxCacheSize);
+
+        // Determine the number of new events to copy into the cache
+        int eventsToCopy = std::min(mMaxCacheSize, count);
+
+        // Check for any flush complete events in the events that will be dropped
+        countFlushCompleteEventsLocked(mEventCache, cachedEventsToDrop);
+        countFlushCompleteEventsLocked(events, newEventsToDrop);
+
+        // Only shift the events if they will not all be overwritten
+        if (eventsToCopy != mMaxCacheSize) {
+            memmove(mEventCache, &mEventCache[cachedEventsToDrop],
+                    (mCacheSize - cachedEventsToDrop) * sizeof(sensors_event_t));
+        }
+        mCacheSize -= cachedEventsToDrop;
+
+        // Copy the events into the cache
+        memcpy(&mEventCache[mCacheSize], &events[newEventsToDrop],
+                eventsToCopy * sizeof(sensors_event_t));
+        mCacheSize += eventsToCopy;
+    }
+}
+
 void SensorService::SensorEventConnection::sendPendingFlushEventsLocked() {
     ASensorEvent flushCompleteEvent;
     memset(&flushCompleteEvent, 0, sizeof(flushCompleteEvent));
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 40c21ff..eefd81a 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -108,6 +108,10 @@
     // size, reallocate memory and copy over events from the older cache.
     void reAllocateCacheLocked(sensors_event_t const* scratch, int count);
 
+    // Add the events to the cache. If the cache would be exceeded, drop events at the beginning of
+    // the cache.
+    void appendEventsToCacheLocked(sensors_event_t const* events, int count);
+
     // 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.