Prevent overflow when caching sensor events

Ensure that the boundary of the SensorEventConnection's event cache is
not exceeded if more events need to be stored in the cache than there
is currently free capacity for.

Also resolves an issue where sensor events were not properly appended
to the end of the cache if events had to be dropped to fit the new
events.

Bug: 119501435
Test: Builds, forced events to be written to the cache and ensured the
      cache never exceeded its limits.
Change-Id: Ib3ed211dd42f47ea0e542687c07ed7106fcad1e7
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.