Merge "sdcard: Fix compilation with FUSE_TRACE == 1."
diff --git a/include/utils/LruCache.h b/include/utils/LruCache.h
index ed96fe4..f4e225a 100644
--- a/include/utils/LruCache.h
+++ b/include/utils/LruCache.h
@@ -56,36 +56,55 @@
 private:
     LruCache(const LruCache& that);  // disallow copy constructor
 
-    struct Entry {
+    // Super class so that we can have entries having only a key reference, for searches.
+    class KeyedEntry {
+    public:
+        virtual const TKey& getKey() const = 0;
+        // Make sure the right destructor is executed so that keys and values are deleted.
+        virtual ~KeyedEntry() {}
+    };
+
+    class Entry final : public KeyedEntry {
+    public:
         TKey key;
         TValue value;
         Entry* parent;
         Entry* child;
 
-        Entry(TKey key_, TValue value_) : key(key_), value(value_), parent(NULL), child(NULL) {
+        Entry(TKey _key, TValue _value) : key(_key), value(_value), parent(NULL), child(NULL) {
         }
-        const TKey& getKey() const { return key; }
+        const TKey& getKey() const final { return key; }
     };
 
-    struct HashForEntry : public std::unary_function<Entry*, hash_t> {
-        size_t operator() (const Entry* entry) const {
-            return hash_type(entry->key);
+    class EntryForSearch : public KeyedEntry {
+    public:
+        const TKey& key;
+        EntryForSearch(const TKey& key_) : key(key_) {
+        }
+        const TKey& getKey() const final { return key; }
+    };
+
+    struct HashForEntry : public std::unary_function<KeyedEntry*, hash_t> {
+        size_t operator() (const KeyedEntry* entry) const {
+            return hash_type(entry->getKey());
         };
     };
 
-    struct EqualityForHashedEntries : public std::unary_function<Entry*, hash_t> {
-        bool operator() (const Entry* lhs, const Entry* rhs) const {
-            return lhs->key == rhs->key;
+    struct EqualityForHashedEntries : public std::unary_function<KeyedEntry*, hash_t> {
+        bool operator() (const KeyedEntry* lhs, const KeyedEntry* rhs) const {
+            return lhs->getKey() == rhs->getKey();
         };
     };
 
-    typedef std::unordered_set<Entry*, HashForEntry, EqualityForHashedEntries> LruCacheSet;
+    // All entries in the set will be Entry*. Using the weaker KeyedEntry as to allow entries
+    // that have only a key reference, for searching.
+    typedef std::unordered_set<KeyedEntry*, HashForEntry, EqualityForHashedEntries> LruCacheSet;
 
     void attachToCache(Entry& entry);
     void detachFromCache(Entry& entry);
 
     typename LruCacheSet::iterator findByKey(const TKey& key) {
-        Entry entryForSearch(key, mNullValue);
+        EntryForSearch entryForSearch(key);
         typename LruCacheSet::iterator result = mSet->find(&entryForSearch);
         return result;
     }
@@ -124,11 +143,13 @@
         }
 
         const TValue& value() const {
-            return (*mIterator)->value;
+            // All the elements in the set are of type Entry. See comment in the definition
+            // of LruCacheSet above.
+            return reinterpret_cast<Entry *>(*mIterator)->value;
         }
 
         const TKey& key() const {
-            return (*mIterator)->key;
+            return (*mIterator)->getKey();
         }
     private:
         const LruCache<TKey, TValue>& mCache;
@@ -171,7 +192,9 @@
     if (find_result == mSet->end()) {
         return mNullValue;
     }
-    Entry *entry = *find_result;
+    // All the elements in the set are of type Entry. See comment in the definition
+    // of LruCacheSet above.
+    Entry *entry = reinterpret_cast<Entry*>(*find_result);
     detachFromCache(*entry);
     attachToCache(*entry);
     return entry->value;
@@ -199,7 +222,9 @@
     if (find_result == mSet->end()) {
         return false;
     }
-    Entry* entry = *find_result;
+    // All the elements in the set are of type Entry. See comment in the definition
+    // of LruCacheSet above.
+    Entry* entry = reinterpret_cast<Entry*>(*find_result);
     mSet->erase(entry);
     if (mListener) {
         (*mListener)(entry->key, entry->value);
diff --git a/libcutils/iosched_policy.c b/libcutils/iosched_policy.c
index 71bc94b..13c2ceb 100644
--- a/libcutils/iosched_policy.c
+++ b/libcutils/iosched_policy.c
@@ -24,7 +24,8 @@
 #include <cutils/iosched_policy.h>
 
 #if defined(__ANDROID__)
-#include <linux/ioprio.h>
+#define IOPRIO_WHO_PROCESS (1)
+#define IOPRIO_CLASS_SHIFT (13)
 #include <sys/syscall.h>
 #define __android_unused
 #else
diff --git a/libpackagelistparser/Android.bp b/libpackagelistparser/Android.bp
new file mode 100644
index 0000000..70ff528
--- /dev/null
+++ b/libpackagelistparser/Android.bp
@@ -0,0 +1,13 @@
+cc_library {
+
+    name: "libpackagelistparser",
+    srcs: ["packagelistparser.c"],
+    shared_libs: ["liblog"],
+    local_include_dirs: ["include"],
+    export_include_dirs: ["include"],
+
+    clang: true,
+    sanitize: {
+        misc_undefined: ["integer"],
+    },
+}
diff --git a/libpackagelistparser/Android.mk b/libpackagelistparser/Android.mk
deleted file mode 100644
index c8be050..0000000
--- a/libpackagelistparser/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-#########################
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libpackagelistparser
-LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := packagelistparser.c
-LOCAL_SHARED_LIBRARIES := liblog
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-
-LOCAL_CLANG := true
-LOCAL_SANITIZE := integer
-
-include $(BUILD_SHARED_LIBRARY)
-
-#########################
-include $(CLEAR_VARS)
-
-
-LOCAL_MODULE := libpackagelistparser
-LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := packagelistparser.c
-LOCAL_STATIC_LIBRARIES := liblog
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-
-LOCAL_CLANG := true
-LOCAL_SANITIZE := integer
-
-include $(BUILD_STATIC_LIBRARY)
diff --git a/libutils/tests/LruCache_test.cpp b/libutils/tests/LruCache_test.cpp
index dd95c57..de440fd 100644
--- a/libutils/tests/LruCache_test.cpp
+++ b/libutils/tests/LruCache_test.cpp
@@ -80,6 +80,14 @@
     }
 };
 
+struct KeyFailsOnCopy : public ComplexKey {
+    public:
+    KeyFailsOnCopy(const KeyFailsOnCopy& key) : ComplexKey(key) {
+        ADD_FAILURE();
+    }
+    KeyFailsOnCopy(int key) : ComplexKey(key) { }
+};
+
 } // namespace
 
 
@@ -95,6 +103,10 @@
     return hash_type(*value.ptr);
 }
 
+template<> inline android::hash_t hash_type(const KeyFailsOnCopy& value) {
+    return hash_type<ComplexKey>(value);
+}
+
 class EntryRemovedCallback : public OnEntryRemoved<SimpleKey, StringValue> {
 public:
     EntryRemovedCallback() : callbackCount(0), lastKey(-1), lastValue(NULL) { }
@@ -437,4 +449,10 @@
     EXPECT_EQ(std::unordered_set<int>({ 4, 5, 6 }), returnedValues);
 }
 
+TEST_F(LruCacheTest, DontCopyKeyInGet) {
+    LruCache<KeyFailsOnCopy, KeyFailsOnCopy> cache(1);
+    // Check that get doesn't copy the key
+    cache.get(KeyFailsOnCopy(0));
+}
+
 }
diff --git a/logcat/logpersist b/logcat/logpersist
index e9982e2..f0e7d42 100755
--- a/logcat/logpersist
+++ b/logcat/logpersist
@@ -17,6 +17,7 @@
    ;;
 esac
 
+log_tag_property=persist.log.tag
 data=/data/misc/logd
 service=logcatd
 size_default=256
@@ -65,6 +66,9 @@
   exit 1
 fi
 
+log_tag="`getprop ${log_tag_property}`"
+logd_logpersistd="`getprop ${property}`"
+
 case ${progname} in
 *.cat)
   if [ -n "${size}${buffer}" -o "true" = "${clear}" ]; then
@@ -123,6 +127,12 @@
   while [ "clear" = "`getprop ${property#persist.}`" ]; do
     continue
   done
+  # Tell Settings that we are back on again if we turned logging off
+  tag="${log_tag#Settings}"
+  if [ X"${log_tag}" != X"${tag}" ]; then
+    echo "WARNING: enabling logd service" >&2
+    setprop ${log_tag_property} "${tag#,}"
+  fi
   # ${service}.rc does the heavy lifting with the following trigger
   setprop ${property} ${service}
   # 20ms done, to permit process feedback check
@@ -158,3 +168,9 @@
   echo "ERROR: Unexpected command ${0##*/} ${args}" >&2
   exit 1
 esac
+
+if [ X"${log_tag}" != X"`getprop ${log_tag_property}`" ] ||
+   [ X"${logd_logpersistd}" != X"`getprop ${property}`" ]; then
+  echo "WARNING: killing Settings" >&2
+  am force-stop com.android.settings
+fi
diff --git a/logd/Android.mk b/logd/Android.mk
index 84ea7a2..3348890 100644
--- a/logd/Android.mk
+++ b/logd/Android.mk
@@ -28,7 +28,8 @@
     liblog \
     libcutils \
     libbase \
-    libpackagelistparser
+    libpackagelistparser \
+    libminijail
 
 # This is what we want to do:
 #  event_logtags = $(shell \
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 4eb5e83..8859d55 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -181,16 +181,72 @@
         struct iovec iov[3];
         static const char log_info[] = { KMSG_PRIORITY(LOG_INFO) };
         static const char log_warning[] = { KMSG_PRIORITY(LOG_WARNING) };
+        static const char newline[] = "\n";
 
-        iov[0].iov_base = info ? const_cast<char *>(log_info)
-                               : const_cast<char *>(log_warning);
-        iov[0].iov_len = info ? sizeof(log_info) : sizeof(log_warning);
-        iov[1].iov_base = str;
-        iov[1].iov_len = strlen(str);
-        iov[2].iov_base = const_cast<char *>("\n");
-        iov[2].iov_len = 1;
+        // Dedupe messages, checking for identical messages starting with avc:
+        static unsigned count;
+        static char *last_str;
+        static bool last_info;
 
-        writev(fdDmesg, iov, sizeof(iov) / sizeof(iov[0]));
+        if (last_str != NULL) {
+            static const char avc[] = "): avc: ";
+            char *avcl = strstr(last_str, avc);
+            bool skip = false;
+
+            if (avcl) {
+                char *avcr = strstr(str, avc);
+
+                skip = avcr && !strcmp(avcl + strlen(avc), avcr + strlen(avc));
+                if (skip) {
+                    ++count;
+                    free(last_str);
+                    last_str = strdup(str);
+                    last_info = info;
+                }
+            }
+            if (!skip) {
+                static const char resume[] = " duplicate messages suppressed\n";
+
+                iov[0].iov_base = last_info ?
+                    const_cast<char *>(log_info) :
+                    const_cast<char *>(log_warning);
+                iov[0].iov_len = last_info ?
+                    sizeof(log_info) :
+                    sizeof(log_warning);
+                iov[1].iov_base = last_str;
+                iov[1].iov_len = strlen(last_str);
+                if (count > 1) {
+                    iov[2].iov_base = const_cast<char *>(resume);
+                    iov[2].iov_len = strlen(resume);
+                } else {
+                    iov[2].iov_base = const_cast<char *>(newline);
+                    iov[2].iov_len = strlen(newline);
+                }
+
+                writev(fdDmesg, iov, sizeof(iov) / sizeof(iov[0]));
+                free(last_str);
+                last_str = NULL;
+            }
+        }
+        if (last_str == NULL) {
+            count = 0;
+            last_str = strdup(str);
+            last_info = info;
+        }
+        if (count == 0) {
+            iov[0].iov_base = info ?
+                const_cast<char *>(log_info) :
+                const_cast<char *>(log_warning);
+            iov[0].iov_len = info ?
+                sizeof(log_info) :
+                sizeof(log_warning);
+            iov[1].iov_base = str;
+            iov[1].iov_len = strlen(str);
+            iov[2].iov_base = const_cast<char *>(newline);
+            iov[2].iov_len = strlen(newline);
+
+            writev(fdDmesg, iov, sizeof(iov) / sizeof(iov[0]));
+        }
     }
 
     pid_t pid = getpid();
diff --git a/logd/main.cpp b/logd/main.cpp
index 69ba896..b69927d 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -36,12 +36,15 @@
 #include <cstdbool>
 #include <memory>
 
+#include <android-base/macros.h>
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
 #include <cutils/sockets.h>
+#include <libminijail.h>
 #include <log/event_tag_map.h>
 #include <packagelistparser/packagelistparser.h>
 #include <private/android_filesystem_config.h>
+#include <scoped_minijail.h>
 #include <utils/threads.h>
 
 #include "CommandListener.h"
@@ -58,14 +61,14 @@
     '>'
 
 //
-//  The service is designed to be run by init, it does not respond well
+// The service is designed to be run by init, it does not respond well
 // to starting up manually. When starting up manually the sockets will
 // fail to open typically for one of the following reasons:
 //     EADDRINUSE if logger is running.
 //     EACCESS if started without precautions (below)
 //
 // Here is a cookbook procedure for starting up logd manually assuming
-// init is out of the way, pedantically all permissions and selinux
+// init is out of the way, pedantically all permissions and SELinux
 // security is put back in place:
 //
 //    setenforce 0
@@ -102,43 +105,13 @@
         return -1;
     }
 
-    if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
-        return -1;
-    }
-
     gid_t groups[] = { AID_READPROC };
-
-    if (setgroups(sizeof(groups) / sizeof(groups[0]), groups) == -1) {
-        return -1;
-    }
-
-    if (setgid(AID_LOGD) != 0) {
-        return -1;
-    }
-
-    if (setuid(AID_LOGD) != 0) {
-        return -1;
-    }
-
-    struct __user_cap_header_struct capheader;
-    struct __user_cap_data_struct capdata[2];
-    memset(&capheader, 0, sizeof(capheader));
-    memset(&capdata, 0, sizeof(capdata));
-    capheader.version = _LINUX_CAPABILITY_VERSION_3;
-    capheader.pid = 0;
-
-    capdata[CAP_TO_INDEX(CAP_SYSLOG)].permitted = CAP_TO_MASK(CAP_SYSLOG);
-    capdata[CAP_TO_INDEX(CAP_AUDIT_CONTROL)].permitted |= CAP_TO_MASK(CAP_AUDIT_CONTROL);
-
-    capdata[0].effective = capdata[0].permitted;
-    capdata[1].effective = capdata[1].permitted;
-    capdata[0].inheritable = 0;
-    capdata[1].inheritable = 0;
-
-    if (capset(&capheader, &capdata[0]) < 0) {
-        return -1;
-    }
-
+    ScopedMinijail j(minijail_new());
+    minijail_set_supplementary_gids(j.get(), arraysize(groups), groups);
+    minijail_change_uid(j.get(), AID_LOGD);
+    minijail_change_gid(j.get(), AID_LOGD);
+    minijail_use_caps(j.get(), CAP_TO_MASK(CAP_SYSLOG) | CAP_TO_MASK(CAP_AUDIT_CONTROL));
+    minijail_enter(j.get());
     return 0;
 }