Merge changes I6555c135,If5723ff4

* changes:
  logcat: test: also check "failed to clear" in blocking_clear
  logd: reader/writer element locks
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index e487a97..9c07472 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -1216,7 +1216,12 @@
     signal(SIGALRM, caught_blocking_clear);
     alarm(2);
     while (fgets(buffer, sizeof(buffer), fp)) {
-        if (!strncmp(buffer, "clearLog: ", 10)) {
+        if (!strncmp(buffer, "clearLog: ", strlen("clearLog: "))) {
+            fprintf(stderr, "WARNING: Test lacks permission to run :-(\n");
+            count = signals = 1;
+            break;
+        }
+        if (!strncmp(buffer, "failed to clear", strlen("failed to clear"))) {
             fprintf(stderr, "WARNING: Test lacks permission to run :-(\n");
             count = signals = 1;
             break;
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
index c67d2bf..a9edc3e 100644
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -44,14 +44,14 @@
 // LogTimeEntrys, and spawn a transitory per-client thread to
 // work at filing data to the  socket.
 //
-// global LogTimeEntry::lock() is used to protect access,
+// global LogTimeEntry::wrlock() is used to protect access,
 // reference counts are used to ensure that individual
 // LogTimeEntry lifetime is managed when not protected.
 void FlushCommand::runSocketCommand(SocketClient* client) {
     LogTimeEntry* entry = NULL;
     LastLogTimes& times = mReader.logbuf().mTimes;
 
-    LogTimeEntry::lock();
+    LogTimeEntry::wrlock();
     LastLogTimes::iterator it = times.begin();
     while (it != times.end()) {
         entry = (*it);
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 2d9024a..ee38d1c 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -277,7 +277,7 @@
             ++cp;
         }
         tid = pid;
-        logbuf->lock();
+        logbuf->wrlock();
         uid = logbuf->pidToUid(pid);
         logbuf->unlock();
         memmove(pidptr, cp, strlen(cp) + 1);
@@ -322,7 +322,7 @@
         pid = tid;
         comm = "auditd";
     } else {
-        logbuf->lock();
+        logbuf->wrlock();
         comm = commfree = logbuf->pidToName(pid);
         logbuf->unlock();
         if (!comm) {
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index ed46181..d9ec081 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -72,7 +72,7 @@
         // as the act of mounting /data would trigger persist.logd.timestamp to
         // be corrected. 1/30 corner case YMMV.
         //
-        pthread_mutex_lock(&mLogElementsLock);
+        rdlock();
         LogBufferElementCollection::iterator it = mLogElements.begin();
         while ((it != mLogElements.end())) {
             LogBufferElement* e = *it;
@@ -87,7 +87,7 @@
             }
             ++it;
         }
-        pthread_mutex_unlock(&mLogElementsLock);
+        unlock();
     }
 
     // We may have been triggered by a SIGHUP. Release any sleeping reader
@@ -95,7 +95,7 @@
     //
     // NB: this is _not_ performed in the context of a SIGHUP, it is
     // performed during startup, and in context of reinit administrative thread
-    LogTimeEntry::lock();
+    LogTimeEntry::wrlock();
 
     LastLogTimes::iterator times = mTimes.begin();
     while (times != mTimes.end()) {
@@ -111,7 +111,7 @@
 
 LogBuffer::LogBuffer(LastLogTimes* times)
     : monotonic(android_log_clockid() == CLOCK_MONOTONIC), mTimes(*times) {
-    pthread_mutex_init(&mLogElementsLock, nullptr);
+    pthread_rwlock_init(&mLogElementsLock, nullptr);
 
     log_id_for_each(i) {
         lastLoggedElements[i] = nullptr;
@@ -207,15 +207,15 @@
         }
         if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
             // Log traffic received to total
-            pthread_mutex_lock(&mLogElementsLock);
+            wrlock();
             stats.addTotal(elem);
-            pthread_mutex_unlock(&mLogElementsLock);
+            unlock();
             delete elem;
             return -EACCES;
         }
     }
 
-    pthread_mutex_lock(&mLogElementsLock);
+    wrlock();
     LogBufferElement* currentLast = lastLoggedElements[log_id];
     if (currentLast) {
         LogBufferElement* dropped = droppedElements[log_id];
@@ -316,14 +316,14 @@
                     // check for overflow
                     if (total >= UINT32_MAX) {
                         log(currentLast);
-                        pthread_mutex_unlock(&mLogElementsLock);
+                        unlock();
                         return len;
                     }
                     stats.addTotal(currentLast);
                     delete currentLast;
                     swab = total;
                     event->payload.data = htole32(swab);
-                    pthread_mutex_unlock(&mLogElementsLock);
+                    unlock();
                     return len;
                 }
                 if (count == USHRT_MAX) {
@@ -340,7 +340,7 @@
             }
             droppedElements[log_id] = currentLast;
             lastLoggedElements[log_id] = elem;
-            pthread_mutex_unlock(&mLogElementsLock);
+            unlock();
             return len;
         }
         if (dropped) {         // State 1 or 2
@@ -358,12 +358,12 @@
     lastLoggedElements[log_id] = new LogBufferElement(*elem);
 
     log(elem);
-    pthread_mutex_unlock(&mLogElementsLock);
+    unlock();
 
     return len;
 }
 
-// assumes mLogElementsLock held, owns elem, will look after garbage collection
+// assumes LogBuffer::wrlock() held, owns elem, look after garbage collection
 void LogBuffer::log(LogBufferElement* elem) {
     // cap on how far back we will sort in-place, otherwise append
     static uint32_t too_far_back = 5;  // five seconds
@@ -384,7 +384,7 @@
         bool end_set = false;
         bool end_always = false;
 
-        LogTimeEntry::lock();
+        LogTimeEntry::rdlock();
 
         LastLogTimes::iterator times = mTimes.begin();
         while (times != mTimes.end()) {
@@ -426,7 +426,7 @@
 
 // Prune at most 10% of the log entries or maxPrune, whichever is less.
 //
-// mLogElementsLock must be held when this function is called.
+// LogBuffer::wrlock() must be held when this function is called.
 void LogBuffer::maybePrune(log_id_t id) {
     size_t sizes = stats.sizes(id);
     unsigned long maxSize = log_buffer_size(id);
@@ -650,14 +650,14 @@
 // The third thread is optional, and only gets hit if there was a whitelist
 // and more needs to be pruned against the backstop of the region lock.
 //
-// mLogElementsLock must be held when this function is called.
+// LogBuffer::wrlock() must be held when this function is called.
 //
 bool LogBuffer::prune(log_id_t id, unsigned long pruneRows, uid_t caller_uid) {
     LogTimeEntry* oldest = nullptr;
     bool busy = false;
     bool clearAll = pruneRows == ULONG_MAX;
 
-    LogTimeEntry::lock();
+    LogTimeEntry::rdlock();
 
     // Region locked?
     LastLogTimes::iterator times = mTimes.begin();
@@ -1017,15 +1017,15 @@
             // 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.
-            pthread_mutex_lock(&mLogElementsLock);
+            wrlock();
             busy = prune(id, 1, uid);
-            pthread_mutex_unlock(&mLogElementsLock);
+            unlock();
             // 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) {
-                LogTimeEntry::lock();
+                LogTimeEntry::wrlock();
                 LastLogTimes::iterator times = mTimes.begin();
                 while (times != mTimes.end()) {
                     LogTimeEntry* entry = (*times);
@@ -1038,9 +1038,9 @@
                 LogTimeEntry::unlock();
             }
         }
-        pthread_mutex_lock(&mLogElementsLock);
+        wrlock();
         busy = prune(id, ULONG_MAX, uid);
-        pthread_mutex_unlock(&mLogElementsLock);
+        unlock();
         if (!busy || !--retry) {
             break;
         }
@@ -1051,9 +1051,9 @@
 
 // get the used space associated with "id".
 unsigned long LogBuffer::getSizeUsed(log_id_t id) {
-    pthread_mutex_lock(&mLogElementsLock);
+    rdlock();
     size_t retval = stats.sizes(id);
-    pthread_mutex_unlock(&mLogElementsLock);
+    unlock();
     return retval;
 }
 
@@ -1063,17 +1063,17 @@
     if (!__android_logger_valid_buffer_size(size)) {
         return -1;
     }
-    pthread_mutex_lock(&mLogElementsLock);
+    wrlock();
     log_buffer_size(id) = size;
-    pthread_mutex_unlock(&mLogElementsLock);
+    unlock();
     return 0;
 }
 
 // get the total space allocated to "id"
 unsigned long LogBuffer::getSize(log_id_t id) {
-    pthread_mutex_lock(&mLogElementsLock);
+    rdlock();
     size_t retval = log_buffer_size(id);
-    pthread_mutex_unlock(&mLogElementsLock);
+    unlock();
     return retval;
 }
 
@@ -1085,7 +1085,7 @@
     LogBufferElementCollection::iterator it;
     uid_t uid = reader->getUid();
 
-    pthread_mutex_lock(&mLogElementsLock);
+    rdlock();
 
     if (start == log_time::EPOCH) {
         // client wants to start from the beginning
@@ -1143,7 +1143,7 @@
             continue;
         }
 
-        // NB: calling out to another object with mLogElementsLock held (safe)
+        // NB: calling out to another object with wrlock() held (safe)
         if (filter) {
             int ret = (*filter)(element, arg);
             if (ret == false) {
@@ -1166,7 +1166,7 @@
                 (element->getDropped() && !sameTid) ? 0 : element->getTid();
         }
 
-        pthread_mutex_unlock(&mLogElementsLock);
+        unlock();
 
         // range locking in LastLogTimes looks after us
         max = element->flushTo(reader, this, privileged, sameTid);
@@ -1176,20 +1176,20 @@
         }
 
         skip = maxSkip;
-        pthread_mutex_lock(&mLogElementsLock);
+        rdlock();
     }
-    pthread_mutex_unlock(&mLogElementsLock);
+    unlock();
 
     return max;
 }
 
 std::string LogBuffer::formatStatistics(uid_t uid, pid_t pid,
                                         unsigned int logMask) {
-    pthread_mutex_lock(&mLogElementsLock);
+    wrlock();
 
     std::string ret = stats.format(uid, pid, logMask);
 
-    pthread_mutex_unlock(&mLogElementsLock);
+    unlock();
 
     return ret;
 }
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h
index 1272c20..51edd86 100644
--- a/logd/LogBuffer.h
+++ b/logd/LogBuffer.h
@@ -76,7 +76,7 @@
 
 class LogBuffer {
     LogBufferElementCollection mLogElements;
-    pthread_mutex_t mLogElementsLock;
+    pthread_rwlock_t mLogElementsLock;
 
     LogStatistics stats;
 
@@ -154,7 +154,7 @@
         return tags.tagToName(tag);
     }
 
-    // helper must be protected directly or implicitly by lock()/unlock()
+    // helper must be protected directly or implicitly by wrlock()/unlock()
     const char* pidToName(pid_t pid) {
         return stats.pidToName(pid);
     }
@@ -164,11 +164,14 @@
     const char* uidToName(uid_t uid) {
         return stats.uidToName(uid);
     }
-    void lock() {
-        pthread_mutex_lock(&mLogElementsLock);
+    void wrlock() {
+        pthread_rwlock_wrlock(&mLogElementsLock);
+    }
+    void rdlock() {
+        pthread_rwlock_rdlock(&mLogElementsLock);
     }
     void unlock() {
-        pthread_mutex_unlock(&mLogElementsLock);
+        pthread_rwlock_unlock(&mLogElementsLock);
     }
 
    private:
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 04a620c..381c974 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -121,7 +121,7 @@
     }
 
     static const char format_uid[] = "uid=%u%s%s %s %u line%s";
-    parent->lock();
+    parent->wrlock();
     const char* name = parent->uidToName(mUid);
     parent->unlock();
     const char* commName = android::tidToName(mTid);
@@ -129,7 +129,7 @@
         commName = android::tidToName(mPid);
     }
     if (!commName) {
-        parent->lock();
+        parent->wrlock();
         commName = parent->pidToName(mPid);
         parent->unlock();
     }
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index d23254d..a7e7208 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -579,7 +579,7 @@
     const pid_t tid = pid;
     uid_t uid = AID_ROOT;
     if (pid) {
-        logbuf->lock();
+        logbuf->wrlock();
         uid = logbuf->pidToUid(pid);
         logbuf->unlock();
     }
diff --git a/logd/LogReader.cpp b/logd/LogReader.cpp
index feb105f..6d69316 100644
--- a/logd/LogReader.cpp
+++ b/logd/LogReader.cpp
@@ -111,7 +111,7 @@
     if (!fastcmp<strncmp>(buffer, "dumpAndClose", 12)) {
         // Allow writer to get some cycles, and wait for pending notifications
         sched_yield();
-        LogTimeEntry::lock();
+        LogTimeEntry::wrlock();
         LogTimeEntry::unlock();
         sched_yield();
         nonBlock = true;
@@ -212,7 +212,7 @@
 
 void LogReader::doSocketDelete(SocketClient* cli) {
     LastLogTimes& times = mLogbuf.mTimes;
-    LogTimeEntry::lock();
+    LogTimeEntry::wrlock();
     LastLogTimes::iterator it = times.begin();
     while (it != times.end()) {
         LogTimeEntry* entry = (*it);
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 3f020b6..0b6b28c 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -228,6 +228,7 @@
 }
 
 // caller must own and free character string
+// Requires parent LogBuffer::wrlock() to be held
 const char* LogStatistics::uidToName(uid_t uid) const {
     // Local hard coded favourites
     if (uid == AID_LOGD) {
diff --git a/logd/LogTimes.cpp b/logd/LogTimes.cpp
index ccc550a..25c2ad2 100644
--- a/logd/LogTimes.cpp
+++ b/logd/LogTimes.cpp
@@ -78,7 +78,7 @@
 void LogTimeEntry::threadStop(void* obj) {
     LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
 
-    lock();
+    wrlock();
 
     if (me->mNonBlock) {
         me->error_Locked();
@@ -134,7 +134,7 @@
 
     me->leadingDropped = true;
 
-    lock();
+    wrlock();
 
     log_time start = me->mStart;
 
@@ -160,7 +160,7 @@
         start = logbuf.flushTo(client, start, me->mLastTid, privileged,
                                security, FilterSecondPass, me);
 
-        lock();
+        wrlock();
 
         if (start == LogBufferElement::FLUSH_ERROR) {
             me->error_Locked();
@@ -191,7 +191,7 @@
 int LogTimeEntry::FilterFirstPass(const LogBufferElement* element, void* obj) {
     LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
 
-    LogTimeEntry::lock();
+    LogTimeEntry::wrlock();
 
     if (me->leadingDropped) {
         if (element->getDropped()) {
@@ -219,7 +219,7 @@
 int LogTimeEntry::FilterSecondPass(const LogBufferElement* element, void* obj) {
     LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);
 
-    LogTimeEntry::lock();
+    LogTimeEntry::wrlock();
 
     me->mStart = element->getRealTime();
 
diff --git a/logd/LogTimes.h b/logd/LogTimes.h
index ec8252e..9ca2aea 100644
--- a/logd/LogTimes.h
+++ b/logd/LogTimes.h
@@ -61,7 +61,10 @@
     const log_time mEnd;  // only relevant if mNonBlock
 
     // Protect List manipulations
-    static void lock(void) {
+    static void wrlock(void) {
+        pthread_mutex_lock(&timesLock);
+    }
+    static void rdlock(void) {
         pthread_mutex_lock(&timesLock);
     }
     static void unlock(void) {
@@ -104,7 +107,7 @@
         mError = true;
     }
     void error(void) {
-        lock();
+        wrlock();
         error_Locked();
         unlock();
     }