Merge "Try to recover corrupted ext4 /data with backup superblock"
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 82f5b8c..612854d 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -711,8 +711,8 @@
                 if (it == properties->end()) {
                     (*properties)[key] = value;
                 } else if (it->second != value) {
-                    LOG(WARNING) << "Overriding previous 'ro.' property '" << key << "':'"
-                                 << it->second << "' with new value '" << value << "'";
+                    LOG(WARNING) << "Overriding previous property '" << key << "':'" << it->second
+                                 << "' with new value '" << value << "'";
                     it->second = value;
                 }
             } else {
diff --git a/logd/ChattyLogBuffer.cpp b/logd/ChattyLogBuffer.cpp
index f92fe65..c213448 100644
--- a/logd/ChattyLogBuffer.cpp
+++ b/logd/ChattyLogBuffer.cpp
@@ -327,7 +327,6 @@
 //
 bool ChattyLogBuffer::Prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
     LogReaderThread* oldest = nullptr;
-    bool busy = false;
     bool clearAll = pruneRows == ULONG_MAX;
 
     auto reader_threads_lock = std::lock_guard{reader_list()->reader_threads_lock()};
@@ -359,17 +358,16 @@
             }
 
             if (oldest && oldest->start() <= element.sequence()) {
-                busy = true;
                 KickReader(oldest, id, pruneRows);
-                break;
+                return false;
             }
 
             it = Erase(it);
             if (--pruneRows == 0) {
-                break;
+                return true;
             }
         }
-        return busy;
+        return true;
     }
 
     // prune by worst offenders; by blacklist, UID, and by PID of system UID
@@ -440,7 +438,6 @@
             LogBufferElement& element = *it;
 
             if (oldest && oldest->start() <= element.sequence()) {
-                busy = true;
                 // Do not let chatty eliding trigger any reader mitigation
                 break;
             }
@@ -577,7 +574,6 @@
         }
 
         if (oldest && oldest->start() <= element.sequence()) {
-            busy = true;
             if (!whitelist) KickReader(oldest, id, pruneRows);
             break;
         }
@@ -605,7 +601,6 @@
             }
 
             if (oldest && oldest->start() <= element.sequence()) {
-                busy = true;
                 KickReader(oldest, id, pruneRows);
                 break;
             }
@@ -615,5 +610,5 @@
         }
     }
 
-    return (pruneRows > 0) && busy;
+    return pruneRows == 0 || it == logs().end();
 }
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index 9764c44..39c5490 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -82,7 +82,7 @@
         return 0;
     }
 
-    cli->sendMsg(buf()->Clear((log_id_t)id, uid) ? "busy" : "success");
+    cli->sendMsg(buf()->Clear((log_id_t)id, uid) ? "success" : "busy");
     return 0;
 }
 
diff --git a/logd/LogBufferTest.cpp b/logd/LogBufferTest.cpp
index e651b4f..412b6f1 100644
--- a/logd/LogBufferTest.cpp
+++ b/logd/LogBufferTest.cpp
@@ -26,6 +26,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 
+#include "LogBuffer.h"
 #include "LogReaderThread.h"
 #include "LogWriter.h"
 
@@ -240,7 +241,7 @@
         std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
         std::unique_ptr<LogReaderThread> log_reader(
                 new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true,
-                                    0, ~0, 0, {}, 1, {}));
+                                    0, kLogMaskAll, 0, {}, 1, {}));
         reader_list_.reader_threads().emplace_back(std::move(log_reader));
     }
 
@@ -314,7 +315,7 @@
         std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
         std::unique_ptr<LogReaderThread> log_reader(
                 new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true,
-                                    0, ~0, 0, {}, 1, {}));
+                                    0, kLogMaskAll, 0, {}, 1, {}));
         reader_list_.reader_threads().emplace_back(std::move(log_reader));
     }
 
@@ -348,7 +349,7 @@
         std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
         std::unique_ptr<LogReaderThread> log_reader(
                 new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), true,
-                                    0, ~0, 0, {}, 3, {}));
+                                    0, kLogMaskAll, 0, {}, 3, {}));
         reader_list_.reader_threads().emplace_back(std::move(log_reader));
     }
 
@@ -363,4 +364,95 @@
     CompareLogMessages(expected_log_messages, read_log_messages);
 }
 
+TEST_P(LogBufferTest, clear_logs) {
+    // Log 3 initial logs.
+    std::vector<LogMessage> log_messages = {
+            {{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20001, .lid = LOG_ID_MAIN, .uid = 0},
+             "first"},
+            {{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20002, .lid = LOG_ID_MAIN, .uid = 0},
+             "second"},
+            {{.pid = 100, .tid = 2, .sec = 10000, .nsec = 20003, .lid = LOG_ID_MAIN, .uid = 0},
+             "third"},
+    };
+    FixupMessages(&log_messages);
+    LogMessages(log_messages);
+
+    std::vector<LogMessage> read_log_messages;
+    bool released = false;
+
+    // Connect a blocking reader.
+    {
+        auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
+        std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages, &released));
+        std::unique_ptr<LogReaderThread> log_reader(
+                new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(test_writer), false,
+                                    0, kLogMaskAll, 0, {}, 1, {}));
+        reader_list_.reader_threads().emplace_back(std::move(log_reader));
+    }
+
+    // Wait up to 250ms for the reader to read the first 3 logs.
+    constexpr int kMaxRetryCount = 50;
+    int count = 0;
+    for (; count < kMaxRetryCount; ++count) {
+        usleep(5000);
+        auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
+        if (reader_list_.reader_threads().back()->start() == 4) {
+            break;
+        }
+    }
+    ASSERT_LT(count, kMaxRetryCount);
+
+    // Clear the log buffer.
+    log_buffer_->Clear(LOG_ID_MAIN, 0);
+
+    // Log 3 more logs.
+    std::vector<LogMessage> after_clear_messages = {
+            {{.pid = 1, .tid = 2, .sec = 10000, .nsec = 20001, .lid = LOG_ID_MAIN, .uid = 0},
+             "4th"},
+            {{.pid = 10, .tid = 2, .sec = 10000, .nsec = 20002, .lid = LOG_ID_MAIN, .uid = 0},
+             "5th"},
+            {{.pid = 100, .tid = 2, .sec = 10000, .nsec = 20003, .lid = LOG_ID_MAIN, .uid = 0},
+             "6th"},
+    };
+    FixupMessages(&after_clear_messages);
+    LogMessages(after_clear_messages);
+
+    // Wait up to 250ms for the reader to read the 3 additional logs.
+    for (count = 0; count < kMaxRetryCount; ++count) {
+        usleep(5000);
+        auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
+        if (reader_list_.reader_threads().back()->start() == 7) {
+            break;
+        }
+    }
+    ASSERT_LT(count, kMaxRetryCount);
+
+    // Release the reader, wait for it to get the signal then check that it has been deleted.
+    {
+        auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
+        reader_list_.reader_threads().back()->release_Locked();
+    }
+    while (!released) {
+        usleep(5000);
+    }
+    {
+        auto lock = std::unique_lock{reader_list_.reader_threads_lock()};
+        EXPECT_EQ(0U, reader_list_.reader_threads().size());
+    }
+
+    // Check that we have read all 6 messages.
+    std::vector<LogMessage> expected_log_messages = log_messages;
+    expected_log_messages.insert(expected_log_messages.end(), after_clear_messages.begin(),
+                                 after_clear_messages.end());
+    CompareLogMessages(expected_log_messages, read_log_messages);
+
+    // Finally, call FlushTo and ensure that only the 3 logs after the clear remain in the buffer.
+    std::vector<LogMessage> read_log_messages_after_clear;
+    std::unique_ptr<LogWriter> test_writer(new TestWriter(&read_log_messages_after_clear, nullptr));
+    std::unique_ptr<FlushToState> flush_to_state = log_buffer_->CreateFlushToState(1, kLogMaskAll);
+    EXPECT_TRUE(log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr));
+    EXPECT_EQ(7ULL, flush_to_state->start());
+    CompareLogMessages(after_clear_messages, read_log_messages_after_clear);
+}
+
 INSTANTIATE_TEST_CASE_P(LogBufferTests, LogBufferTest, testing::Values("chatty", "simple"));
diff --git a/logd/SimpleLogBuffer.cpp b/logd/SimpleLogBuffer.cpp
index 292a7e4..ec08d54 100644
--- a/logd/SimpleLogBuffer.cpp
+++ b/logd/SimpleLogBuffer.cpp
@@ -212,46 +212,38 @@
     return true;
 }
 
-// clear all rows of type "id" from the buffer.
 bool SimpleLogBuffer::Clear(log_id_t id, uid_t uid) {
-    bool busy = true;
-    // If it takes more than 4 tries (seconds) to clear, then kill reader(s)
-    for (int retry = 4;;) {
-        if (retry == 1) {  // last pass
-            // Check if it is still busy after the sleep, we say prune
-            // one entry, not another clear run, so we are looking for
-            // the quick side effect of the return value to tell us if
-            // we have a _blocked_ reader.
-            {
-                auto lock = std::lock_guard{lock_};
-                busy = Prune(id, 1, uid);
-            }
-            // It is still busy, blocked reader(s), lets kill them all!
-            // otherwise, lets be a good citizen and preserve the slow
-            // readers and let the clear run (below) deal with determining
-            // if we are still blocked and return an error code to caller.
-            if (busy) {
-                auto reader_threads_lock = std::lock_guard{reader_list_->reader_threads_lock()};
-                for (const auto& reader_thread : reader_list_->reader_threads()) {
-                    if (reader_thread->IsWatching(id)) {
-                        LOG(WARNING) << "Kicking blocked reader, " << reader_thread->name()
-                                     << ", from LogBuffer::clear()";
-                        reader_thread->release_Locked();
-                    }
-                }
-            }
-        }
+    // Try three times to clear, then disconnect the readers and try one final time.
+    for (int retry = 0; retry < 3; ++retry) {
         {
             auto lock = std::lock_guard{lock_};
-            busy = Prune(id, ULONG_MAX, uid);
+            if (Prune(id, ULONG_MAX, uid)) {
+                return true;
+            }
         }
-
-        if (!busy || !--retry) {
-            break;
-        }
-        sleep(1);  // Let reader(s) catch up after notification
+        sleep(1);
     }
-    return busy;
+    // Check if it is still busy after the sleep, we try to prune one entry, not another clear run,
+    // so we are looking for the quick side effect of the return value to tell us if we have a
+    // _blocked_ reader.
+    bool busy = false;
+    {
+        auto lock = std::lock_guard{lock_};
+        busy = !Prune(id, 1, uid);
+    }
+    // It is still busy, disconnect all readers.
+    if (busy) {
+        auto reader_threads_lock = std::lock_guard{reader_list_->reader_threads_lock()};
+        for (const auto& reader_thread : reader_list_->reader_threads()) {
+            if (reader_thread->IsWatching(id)) {
+                LOG(WARNING) << "Kicking blocked reader, " << reader_thread->name()
+                             << ", from LogBuffer::clear()";
+                reader_thread->release_Locked();
+            }
+        }
+    }
+    auto lock = std::lock_guard{lock_};
+    return Prune(id, ULONG_MAX, uid);
 }
 
 // get the total space allocated to "id"
@@ -313,16 +305,16 @@
 
         if (oldest && oldest->start() <= element.sequence()) {
             KickReader(oldest, id, prune_rows);
-            return true;
+            return false;
         }
 
         stats_->Subtract(element.ToLogStatisticsElement());
         it = Erase(it);
         if (--prune_rows == 0) {
-            return false;
+            return true;
         }
     }
-    return false;
+    return true;
 }
 
 std::list<LogBufferElement>::iterator SimpleLogBuffer::Erase(