Merge "logd: refactor mLast setting into a GetOldest function"
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 1f8ad05..36273de 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -46,9 +46,6 @@
 
 void LogBuffer::init() {
     log_id_for_each(i) {
-        mLastSet[i] = false;
-        mLast[i] = mLogElements.begin();
-
         if (setSize(i, __android_logger_get_buffer_size(i))) {
             setSize(i, LOG_BUFFER_MIN_SIZE);
         }
@@ -131,6 +128,20 @@
     }
 }
 
+LogBufferElementCollection::iterator LogBuffer::GetOldest(log_id_t log_id) {
+    auto it = mLogElements.begin();
+    if (mOldest[log_id]) {
+        it = *mOldest[log_id];
+    }
+    while (it != mLogElements.end() && (*it)->getLogId() != log_id) {
+        it++;
+    }
+    if (it != mLogElements.end()) {
+        mOldest[log_id] = it;
+    }
+    return it;
+}
+
 enum match_type { DIFFERENT, SAME, SAME_LIBLOG };
 
 static enum match_type identical(LogBufferElement* elem,
@@ -450,9 +461,7 @@
 
     bool setLast[LOG_ID_MAX];
     bool doSetLast = false;
-    log_id_for_each(i) {
-        doSetLast |= setLast[i] = mLastSet[i] && (it == mLast[i]);
-    }
+    log_id_for_each(i) { doSetLast |= setLast[i] = mOldest[i] && it == *mOldest[i]; }
 #ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
     LogBufferElementCollection::iterator bad = it;
     int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY))
@@ -463,11 +472,11 @@
     if (doSetLast) {
         log_id_for_each(i) {
             if (setLast[i]) {
-                if (__predict_false(it == mLogElements.end())) {  // impossible
-                    mLastSet[i] = false;
-                    mLast[i] = mLogElements.begin();
+                if (__predict_false(it == mLogElements.end())) {
+                    mOldest[i] = std::nullopt;
                 } else {
-                    mLast[i] = it;  // push down the road as next-best-watermark
+                    mOldest[i] = it;  // Store the next iterator even if it does not correspond to
+                                      // the same log_id, as a starting point for GetOldest().
                 }
             }
         }
@@ -486,11 +495,6 @@
                                  b.first);
             }
         }
-        if (mLastSet[i] && (bad == mLast[i])) {
-            android::prdebug("stale mLast[%d]\n", i);
-            mLastSet[i] = false;
-            mLast[i] = mLogElements.begin();
-        }
     }
 #endif
     if (coalesce) {
@@ -668,7 +672,7 @@
     if (__predict_false(caller_uid != AID_ROOT)) {  // unlikely
         // Only here if clear all request from non system source, so chatty
         // filter logistics is not required.
-        it = mLastSet[id] ? mLast[id] : mLogElements.begin();
+        it = GetOldest(id);
         while (it != mLogElements.end()) {
             LogBufferElement* element = *it;
 
@@ -678,11 +682,6 @@
                 continue;
             }
 
-            if (!mLastSet[id] || ((*mLast[id])->getLogId() != id)) {
-                mLast[id] = it;
-                mLastSet[id] = true;
-            }
-
             if (oldest && oldest->mStart <= element->getSequence()) {
                 busy = true;
                 kickMe(oldest, id, pruneRows);
@@ -734,8 +733,8 @@
         }
 
         bool kick = false;
-        bool leading = true;
-        it = mLastSet[id] ? mLast[id] : mLogElements.begin();
+        bool leading = true;  // true if starting from the oldest log entry, false if starting from
+                              // a specific chatty entry.
         // Perform at least one mandatory garbage collection cycle in following
         // - clear leading chatty tags
         // - coalesce chatty tags
@@ -763,6 +762,9 @@
                 }
             }
         }
+        if (leading) {
+            it = GetOldest(id);
+        }
         static const timespec too_old = { EXPIRE_HOUR_THRESHOLD * 60 * 60, 0 };
         LogBufferElementCollection::iterator lastt;
         lastt = mLogElements.end();
@@ -783,11 +785,6 @@
             }
             // below this point element->getLogId() == id
 
-            if (leading && (!mLastSet[id] || ((*mLast[id])->getLogId() != id))) {
-                mLast[id] = it;
-                mLastSet[id] = true;
-            }
-
             uint16_t dropped = element->getDropped();
 
             // remove any leading drops
@@ -909,7 +906,7 @@
 
     bool whitelist = false;
     bool hasWhitelist = (id != LOG_ID_SECURITY) && mPrune.nice() && !clearAll;
-    it = mLastSet[id] ? mLast[id] : mLogElements.begin();
+    it = GetOldest(id);
     while ((pruneRows > 0) && (it != mLogElements.end())) {
         LogBufferElement* element = *it;
 
@@ -918,11 +915,6 @@
             continue;
         }
 
-        if (!mLastSet[id] || ((*mLast[id])->getLogId() != id)) {
-            mLast[id] = it;
-            mLastSet[id] = true;
-        }
-
         if (oldest && oldest->mStart <= element->getSequence()) {
             busy = true;
             if (!whitelist) kickMe(oldest, id, pruneRows);
@@ -942,7 +934,7 @@
 
     // Do not save the whitelist if we are reader range limited
     if (whitelist && (pruneRows > 0)) {
-        it = mLastSet[id] ? mLast[id] : mLogElements.begin();
+        it = GetOldest(id);
         while ((it != mLogElements.end()) && (pruneRows > 0)) {
             LogBufferElement* element = *it;
 
@@ -951,11 +943,6 @@
                 continue;
             }
 
-            if (!mLastSet[id] || ((*mLast[id])->getLogId() != id)) {
-                mLast[id] = it;
-                mLastSet[id] = true;
-            }
-
             if (oldest && oldest->mStart <= element->getSequence()) {
                 busy = true;
                 kickMe(oldest, id, pruneRows);
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 16225a5..458fbbb 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -20,6 +20,7 @@
 #include <sys/types.h>
 
 #include <list>
+#include <optional>
 #include <string>
 
 #include <android/log.h>
@@ -81,9 +82,9 @@
     LogStatistics stats;
 
     PruneList mPrune;
-    // watermark for last per log id
-    LogBufferElementCollection::iterator mLast[LOG_ID_MAX];
-    bool mLastSet[LOG_ID_MAX];
+    // Keeps track of the iterator to the oldest log message of a given log type, as an
+    // optimization when pruning logs.  Use GetOldest() to retrieve.
+    std::optional<LogBufferElementCollection::iterator> mOldest[LOG_ID_MAX];
     // watermark of any worst/chatty uid processing
     typedef std::unordered_map<uid_t, LogBufferElementCollection::iterator>
         LogBufferIteratorMap;
@@ -181,6 +182,10 @@
     bool prune(log_id_t id, unsigned long pruneRows, uid_t uid = AID_ROOT);
     LogBufferElementCollection::iterator erase(
         LogBufferElementCollection::iterator it, bool coalesce = false);
+
+    // Returns an iterator to the oldest element for a given log type, or mLogElements.end() if
+    // there are no logs for the given log type. Requires mLogElementsLock to be held.
+    LogBufferElementCollection::iterator GetOldest(log_id_t log_id);
 };
 
 #endif  // _LOGD_LOG_BUFFER_H__