Merge "Make libbacktrace build with LLVM r275480"
diff --git a/adb/bugreport.cpp b/adb/bugreport.cpp
index 24be529..143c62a 100644
--- a/adb/bugreport.cpp
+++ b/adb/bugreport.cpp
@@ -240,8 +240,7 @@
         // Uses a default value until device provides the proper name
         dest_file = "bugreport.zip";
     } else {
-        if (!android::base::EndsWith(dest_file, ".zip")) {
-            // TODO: use a case-insensitive comparison (like EndsWithIgnoreCase
+        if (!android::base::EndsWithIgnoreCase(dest_file, ".zip")) {
             dest_file += ".zip";
         }
     }
diff --git a/base/include/android-base/strings.h b/base/include/android-base/strings.h
index 69781cd..b8a9289 100644
--- a/base/include/android-base/strings.h
+++ b/base/include/android-base/strings.h
@@ -58,9 +58,11 @@
 
 // Tests whether 's' starts with 'prefix'.
 bool StartsWith(const std::string& s, const char* prefix);
+bool StartsWithIgnoreCase(const std::string& s, const char* prefix);
 
 // Tests whether 's' ends with 'suffix'.
 bool EndsWith(const std::string& s, const char* suffix);
+bool EndsWithIgnoreCase(const std::string& s, const char* suffix);
 
 }  // namespace base
 }  // namespace android
diff --git a/base/strings.cpp b/base/strings.cpp
index b8775df..7a94ad7 100644
--- a/base/strings.cpp
+++ b/base/strings.cpp
@@ -87,17 +87,29 @@
 template std::string Join(const std::vector<const char*>&, const std::string&);
 
 bool StartsWith(const std::string& s, const char* prefix) {
-  return s.compare(0, strlen(prefix), prefix) == 0;
+  return strncmp(s.c_str(), prefix, strlen(prefix)) == 0;
 }
 
-bool EndsWith(const std::string& s, const char* suffix) {
+bool StartsWithIgnoreCase(const std::string& s, const char* prefix) {
+  return strncasecmp(s.c_str(), prefix, strlen(prefix)) == 0;
+}
+
+static bool EndsWith(const std::string& s, const char* suffix, bool case_sensitive) {
   size_t suffix_length = strlen(suffix);
   size_t string_length = s.size();
   if (suffix_length > string_length) {
     return false;
   }
   size_t offset = string_length - suffix_length;
-  return s.compare(offset, suffix_length, suffix) == 0;
+  return (case_sensitive ? strncmp : strncasecmp)(s.c_str() + offset, suffix, suffix_length) == 0;
+}
+
+bool EndsWith(const std::string& s, const char* suffix) {
+  return EndsWith(s, suffix, true);
+}
+
+bool EndsWithIgnoreCase(const std::string& s, const char* suffix) {
+  return EndsWith(s, suffix, false);
 }
 
 }  // namespace base
diff --git a/base/strings_test.cpp b/base/strings_test.cpp
index 30ae29e..5fb21dd 100644
--- a/base/strings_test.cpp
+++ b/base/strings_test.cpp
@@ -134,44 +134,113 @@
               "2,1" == android::base::Join(list, ','));
 }
 
-TEST(strings, startswith_empty) {
+TEST(strings, StartsWith_empty) {
   ASSERT_FALSE(android::base::StartsWith("", "foo"));
   ASSERT_TRUE(android::base::StartsWith("", ""));
 }
 
-TEST(strings, startswith_simple) {
+TEST(strings, StartsWithIgnoreCase_empty) {
+  ASSERT_FALSE(android::base::StartsWithIgnoreCase("", "foo"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("", ""));
+}
+
+TEST(strings, StartsWith_simple) {
   ASSERT_TRUE(android::base::StartsWith("foo", ""));
   ASSERT_TRUE(android::base::StartsWith("foo", "f"));
   ASSERT_TRUE(android::base::StartsWith("foo", "fo"));
   ASSERT_TRUE(android::base::StartsWith("foo", "foo"));
 }
 
-TEST(strings, startswith_prefix_too_long) {
+TEST(strings, StartsWithIgnoreCase_simple) {
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", ""));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "f"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "F"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fo"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fO"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "Fo"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FO"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "foo"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "foO"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fOo"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "fOO"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "Foo"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FoO"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FOo"));
+  ASSERT_TRUE(android::base::StartsWithIgnoreCase("foo", "FOO"));
+}
+
+TEST(strings, StartsWith_prefix_too_long) {
   ASSERT_FALSE(android::base::StartsWith("foo", "foobar"));
 }
 
-TEST(strings, startswith_contains_prefix) {
+TEST(strings, StartsWithIgnoreCase_prefix_too_long) {
+  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foo", "foobar"));
+  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foo", "FOOBAR"));
+}
+
+TEST(strings, StartsWith_contains_prefix) {
   ASSERT_FALSE(android::base::StartsWith("foobar", "oba"));
   ASSERT_FALSE(android::base::StartsWith("foobar", "bar"));
 }
 
-TEST(strings, endswith_empty) {
+TEST(strings, StartsWithIgnoreCase_contains_prefix) {
+  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "oba"));
+  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "OBA"));
+  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "bar"));
+  ASSERT_FALSE(android::base::StartsWithIgnoreCase("foobar", "BAR"));
+}
+
+TEST(strings, EndsWith_empty) {
   ASSERT_FALSE(android::base::EndsWith("", "foo"));
   ASSERT_TRUE(android::base::EndsWith("", ""));
 }
 
-TEST(strings, endswith_simple) {
+TEST(strings, EndsWithIgnoreCase_empty) {
+  ASSERT_FALSE(android::base::EndsWithIgnoreCase("", "foo"));
+  ASSERT_FALSE(android::base::EndsWithIgnoreCase("", "FOO"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("", ""));
+}
+
+TEST(strings, EndsWith_simple) {
   ASSERT_TRUE(android::base::EndsWith("foo", ""));
   ASSERT_TRUE(android::base::EndsWith("foo", "o"));
   ASSERT_TRUE(android::base::EndsWith("foo", "oo"));
   ASSERT_TRUE(android::base::EndsWith("foo", "foo"));
 }
 
-TEST(strings, endswith_prefix_too_long) {
+TEST(strings, EndsWithIgnoreCase_simple) {
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", ""));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "o"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "O"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "oo"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "oO"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "Oo"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "OO"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "foo"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "foO"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "fOo"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "fOO"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "Foo"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "FoO"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "FOo"));
+  ASSERT_TRUE(android::base::EndsWithIgnoreCase("foo", "FOO"));
+}
+
+TEST(strings, EndsWith_prefix_too_long) {
   ASSERT_FALSE(android::base::EndsWith("foo", "foobar"));
 }
 
-TEST(strings, endswith_contains_prefix) {
+TEST(strings, EndsWithIgnoreCase_prefix_too_long) {
+  ASSERT_FALSE(android::base::EndsWithIgnoreCase("foo", "foobar"));
+  ASSERT_FALSE(android::base::EndsWithIgnoreCase("foo", "FOOBAR"));
+}
+
+TEST(strings, EndsWith_contains_prefix) {
   ASSERT_FALSE(android::base::EndsWith("foobar", "oba"));
   ASSERT_FALSE(android::base::EndsWith("foobar", "foo"));
 }
+
+TEST(strings, EndsWithIgnoreCase_contains_prefix) {
+  ASSERT_FALSE(android::base::EndsWithIgnoreCase("foobar", "OBA"));
+  ASSERT_FALSE(android::base::EndsWithIgnoreCase("foobar", "FOO"));
+}
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 1e569af..e7176c6 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -141,23 +141,24 @@
     }
 }
 
-static bool is_legal_property_name(const char* name, size_t namelen)
+bool is_legal_property_name(const std::string &name)
 {
-    size_t i;
+    size_t namelen = name.size();
+
     if (namelen >= PROP_NAME_MAX) return false;
     if (namelen < 1) return false;
     if (name[0] == '.') return false;
     if (name[namelen - 1] == '.') return false;
 
-    /* Only allow alphanumeric, plus '.', '-', or '_' */
+    /* Only allow alphanumeric, plus '.', '-', '@', or '_' */
     /* Don't allow ".." to appear in a property name */
-    for (i = 0; i < namelen; i++) {
+    for (size_t i = 0; i < namelen; i++) {
         if (name[i] == '.') {
             // i=0 is guaranteed to never have a dot. See above.
             if (name[i-1] == '.') return false;
             continue;
         }
-        if (name[i] == '_' || name[i] == '-') continue;
+        if (name[i] == '_' || name[i] == '-' || name[i] == '@') continue;
         if (name[i] >= 'a' && name[i] <= 'z') continue;
         if (name[i] >= 'A' && name[i] <= 'Z') continue;
         if (name[i] >= '0' && name[i] <= '9') continue;
@@ -168,10 +169,9 @@
 }
 
 static int property_set_impl(const char* name, const char* value) {
-    size_t namelen = strlen(name);
     size_t valuelen = strlen(value);
 
-    if (!is_legal_property_name(name, namelen)) return -1;
+    if (!is_legal_property_name(name)) return -1;
     if (valuelen >= PROP_VALUE_MAX) return -1;
 
     if (strcmp("selinux.restorecon_recursive", name) == 0 && valuelen > 0) {
@@ -188,7 +188,7 @@
 
         __system_property_update(pi, value, valuelen);
     } else {
-        int rc = __system_property_add(name, namelen, value, valuelen);
+        int rc = __system_property_add(name, strlen(name), value, valuelen);
         if (rc < 0) {
             return rc;
         }
@@ -272,7 +272,7 @@
         msg.name[PROP_NAME_MAX-1] = 0;
         msg.value[PROP_VALUE_MAX-1] = 0;
 
-        if (!is_legal_property_name(msg.name, strlen(msg.name))) {
+        if (!is_legal_property_name(msg.name)) {
             LOG(ERROR) << "sys_prop: illegal property name \"" << msg.name << "\"";
             close(s);
             return;
diff --git a/init/property_service.h b/init/property_service.h
index dbaed34..e3a2acb 100644
--- a/init/property_service.h
+++ b/init/property_service.h
@@ -34,6 +34,7 @@
 extern void start_property_service(void);
 std::string property_get(const char* name);
 extern int property_set(const char *name, const char *value);
+extern bool is_legal_property_name(const std::string &name);
 
 
 #endif  /* _INIT_PROPERTY_H */
diff --git a/init/service.cpp b/init/service.cpp
index 685befd..6460e71 100644
--- a/init/service.cpp
+++ b/init/service.cpp
@@ -996,13 +996,5 @@
 }
 
 bool ServiceParser::IsValidName(const std::string& name) const {
-    if (name.size() > PROP_NAME_MAX - sizeof("init.svc.")) {
-        return false;
-    }
-    for (const auto& c : name) {
-        if (!isalnum(c) && (c != '_') && (c != '-')) {
-            return false;
-        }
-    }
-    return true;
+    return is_legal_property_name("init.svc." + name);
 }
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 5cab7a8..a009433 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -13,6 +13,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+// for manual checking of stale entries during LogBuffer::erase()
+//#define DEBUG_CHECK_FOR_STALE_ENTRIES
 
 #include <ctype.h>
 #include <errno.h>
@@ -256,6 +258,11 @@
     log_id_for_each(i) {
         doSetLast |= setLast[i] = mLastSet[i] && (it == mLast[i]);
     }
+#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
+    LogBufferElementCollection::iterator bad = it;
+    int key = ((id == LOG_ID_EVENTS) || (id == LOG_ID_SECURITY)) ?
+            element->getTag() : element->getUid();
+#endif
     it = mLogElements.erase(it);
     if (doSetLast) {
         log_id_for_each(i) {
@@ -269,6 +276,27 @@
             }
         }
     }
+#ifdef DEBUG_CHECK_FOR_STALE_ENTRIES
+    log_id_for_each(i) {
+        for(auto b : mLastWorst[i]) {
+            if (bad == b.second) {
+                android::prdebug("stale mLastWorst[%d] key=%d mykey=%d\n",
+                                 i, b.first, key);
+            }
+        }
+        for(auto b : mLastWorstPidOfSystem[i]) {
+            if (bad == b.second) {
+                android::prdebug("stale mLastWorstPidOfSystem[%d] pid=%d\n",
+                                 i, 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) {
         stats.erase(element);
     } else {
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index a939002..f5c60c7 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -36,29 +36,24 @@
 LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime,
                                    uid_t uid, pid_t pid, pid_t tid,
                                    const char *msg, unsigned short len) :
-        mLogId(log_id),
         mUid(uid),
         mPid(pid),
         mTid(tid),
-        mMsgLen(len),
         mSequence(sequence.fetch_add(1, memory_order_relaxed)),
-        mRealTime(realtime) {
+        mRealTime(realtime),
+        mMsgLen(len),
+        mLogId(log_id) {
     mMsg = new char[len];
     memcpy(mMsg, msg, len);
+    mTag = (isBinary() && (mMsgLen >= sizeof(uint32_t))) ?
+        le32toh(reinterpret_cast<android_event_header_t *>(mMsg)->tag) :
+        0;
 }
 
 LogBufferElement::~LogBufferElement() {
     delete [] mMsg;
 }
 
-uint32_t LogBufferElement::getTag() const {
-    if (((mLogId != LOG_ID_EVENTS) && (mLogId != LOG_ID_SECURITY)) ||
-            !mMsg || (mMsgLen < sizeof(uint32_t))) {
-        return 0;
-    }
-    return le32toh(reinterpret_cast<android_event_header_t *>(mMsg)->tag);
-}
-
 // caller must own and free character string
 char *android::tidToName(pid_t tid) {
     char *retval = NULL;
@@ -164,7 +159,7 @@
     size_t hdrLen;
     // LOG_ID_SECURITY not strictly needed since spam filter not activated,
     // but required for accuracy.
-    if ((mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY)) {
+    if (isBinary()) {
         hdrLen = sizeof(android_log_event_string_t);
     } else {
         hdrLen = 1 + sizeof(tag);
@@ -178,7 +173,7 @@
     }
 
     size_t retval = hdrLen + len;
-    if ((mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY)) {
+    if (isBinary()) {
         android_log_event_string_t *event =
             reinterpret_cast<android_log_event_string_t *>(buffer);
 
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index 2c7fd44..fb7fbed 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -36,33 +36,40 @@
 
     friend LogBuffer;
 
-    const log_id_t mLogId;
-    const uid_t mUid;
-    const pid_t mPid;
-    const pid_t mTid;
-    char *mMsg;
-    union {
-        const unsigned short mMsgLen; // mMSg != NULL
-        unsigned short mDropped;      // mMsg == NULL
-    };
+    // sized to match reality of incoming log packets
+    uint32_t mTag; // only valid for isBinary()
+    const uint32_t mUid;
+    const uint32_t mPid;
+    const uint32_t mTid;
     const uint64_t mSequence;
     log_time mRealTime;
+    char *mMsg;
+    union {
+        const uint16_t mMsgLen; // mMSg != NULL
+        uint16_t mDropped;      // mMsg == NULL
+    };
+    const uint8_t mLogId;
+
     static atomic_int_fast64_t sequence;
 
     // assumption: mMsg == NULL
     size_t populateDroppedMessage(char *&buffer,
                                   LogBuffer *parent);
-
 public:
     LogBufferElement(log_id_t log_id, log_time realtime,
                      uid_t uid, pid_t pid, pid_t tid,
                      const char *msg, unsigned short len);
     virtual ~LogBufferElement();
 
-    log_id_t getLogId() const { return mLogId; }
+    bool isBinary(void) const {
+        return (mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY);
+    }
+
+    log_id_t getLogId() const { return static_cast<log_id_t>(mLogId); }
     uid_t getUid(void) const { return mUid; }
     pid_t getPid(void) const { return mPid; }
     pid_t getTid(void) const { return mTid; }
+    uint32_t getTag() const { return mTag; }
     unsigned short getDropped(void) const { return mMsg ? 0 : mDropped; }
     unsigned short setDropped(unsigned short value) {
         if (mMsg) {
@@ -76,8 +83,6 @@
     static uint64_t getCurrentSequence(void) { return sequence.load(memory_order_relaxed); }
     log_time getRealTime(void) const { return mRealTime; }
 
-    uint32_t getTag(void) const;
-
     static const uint64_t FLUSH_ERROR;
     uint64_t flushTo(SocketClient *writer, LogBuffer *parent, bool privileged);
 };