Merge "Re-derive permissions after package changes."
diff --git a/adb/Android.mk b/adb/Android.mk
index c38cf93..fe3c9cc 100644
--- a/adb/Android.mk
+++ b/adb/Android.mk
@@ -160,6 +160,19 @@
 LOCAL_SHARED_LIBRARIES := libbase libcutils
 include $(BUILD_NATIVE_TEST)
 
+# libdiagnose_usb
+# =========================================================
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := libdiagnose_usb
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_CFLAGS := $(LIBADB_CFLAGS)
+LOCAL_SRC_FILES := diagnose_usb.cpp
+# Even though we're building a static library (and thus there's no link step for
+# this to take effect), this adds the includes to our path.
+LOCAL_STATIC_LIBRARIES := libbase
+include $(BUILD_HOST_STATIC_LIBRARY)
+
 # adb_test
 # =========================================================
 
@@ -185,6 +198,7 @@
     libadb \
     libcrypto_static \
     libcutils \
+    libdiagnose_usb \
 
 # Set entrypoint to wmain from sysdeps_win32.cpp instead of main
 LOCAL_LDFLAGS_windows := -municode
@@ -261,6 +275,7 @@
     libadb \
     libbase \
     libcrypto_static \
+    libdiagnose_usb \
     liblog \
 
 # Don't use libcutils on Windows.
diff --git a/adb/adb.h b/adb/adb.h
index 774215e..9020fc3 100644
--- a/adb/adb.h
+++ b/adb/adb.h
@@ -226,11 +226,6 @@
 int is_adb_interface(int vid, int pid, int usb_class, int usb_subclass, int usb_protocol);
 #endif
 
-// USB permission error help text. The short version will be one line, long may be multi-line.
-// Returns a string message to print, or an empty string if no problems could be found.
-std::string UsbNoPermissionsShortHelpText();
-std::string UsbNoPermissionsLongHelpText();
-
 int adb_commandline(int argc, const char **argv);
 
 ConnectionState connection_state(atransport *t);
diff --git a/adb/daemon/main.cpp b/adb/daemon/main.cpp
index 3e4fc92..240985f 100644
--- a/adb/daemon/main.cpp
+++ b/adb/daemon/main.cpp
@@ -53,12 +53,7 @@
             continue;
         }
 
-        int err = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
-
-        // Some kernels don't have file capabilities compiled in, and
-        // prctl(PR_CAPBSET_DROP) returns EINVAL. Don't automatically
-        // die when we see such misconfigured kernels.
-        if ((err < 0) && (errno != EINVAL)) {
+        if (prctl(PR_CAPBSET_DROP, i, 0, 0, 0) == -1) {
             PLOG(FATAL) << "Could not drop capabilities";
         }
     }
@@ -107,33 +102,7 @@
 #endif // ALLOW_ADBD_ROOT
 }
 
-int adbd_main(int server_port) {
-    umask(0);
-
-    signal(SIGPIPE, SIG_IGN);
-
-    init_transport_registration();
-
-    // We need to call this even if auth isn't enabled because the file
-    // descriptor will always be open.
-    adbd_cloexec_auth_socket();
-
-    if (ALLOW_ADBD_NO_AUTH && property_get_bool("ro.adb.secure", 0) == 0) {
-        auth_required = false;
-    }
-
-    adbd_auth_init();
-
-    // Our external storage path may be different than apps, since
-    // we aren't able to bind mount after dropping root.
-    const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE");
-    if (adb_external_storage != nullptr) {
-        setenv("EXTERNAL_STORAGE", adb_external_storage, 1);
-    } else {
-        D("Warning: ADB_EXTERNAL_STORAGE is not set.  Leaving EXTERNAL_STORAGE"
-          " unchanged.\n");
-    }
-
+static void drop_privileges(int server_port) {
     // Add extra groups:
     // AID_ADB to access the USB driver
     // AID_LOG to read system logs (adb logcat)
@@ -181,6 +150,36 @@
                 << error;
         }
     }
+}
+
+int adbd_main(int server_port) {
+    umask(0);
+
+    signal(SIGPIPE, SIG_IGN);
+
+    init_transport_registration();
+
+    // We need to call this even if auth isn't enabled because the file
+    // descriptor will always be open.
+    adbd_cloexec_auth_socket();
+
+    if (ALLOW_ADBD_NO_AUTH && property_get_bool("ro.adb.secure", 0) == 0) {
+        auth_required = false;
+    }
+
+    adbd_auth_init();
+
+    // Our external storage path may be different than apps, since
+    // we aren't able to bind mount after dropping root.
+    const char* adb_external_storage = getenv("ADB_EXTERNAL_STORAGE");
+    if (adb_external_storage != nullptr) {
+        setenv("EXTERNAL_STORAGE", adb_external_storage, 1);
+    } else {
+        D("Warning: ADB_EXTERNAL_STORAGE is not set.  Leaving EXTERNAL_STORAGE"
+          " unchanged.\n");
+    }
+
+    drop_privileges(server_port);
 
     bool is_usb = false;
     if (access(USB_ADB_PATH, F_OK) == 0 || access(USB_FFS_ADB_EP0, F_OK) == 0) {
diff --git a/adb/diagnose_usb.cpp b/adb/diagnose_usb.cpp
new file mode 100644
index 0000000..0f067b0
--- /dev/null
+++ b/adb/diagnose_usb.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "diagnose_usb.h"
+
+#include <errno.h>
+#include <unistd.h>
+
+#include <string>
+
+#include <android-base/stringprintf.h>
+
+#if defined(__linux__)
+#include <grp.h>
+#endif
+
+static const char kPermissionsHelpUrl[] = "http://developer.android.com/tools/device.html";
+
+// Returns a message describing any potential problems we find with udev, or nullptr if we can't
+// find plugdev information (i.e. udev is not installed).
+static const char* GetUdevProblem() {
+#if defined(__linux__)
+    errno = 0;
+    group* plugdev_group = getgrnam("plugdev");
+
+    if (plugdev_group == nullptr) {
+        if (errno != 0) {
+            perror("failed to read plugdev group info");
+        }
+        // We can't give any generally useful advice here, just let the caller print the help URL.
+        return nullptr;
+    }
+
+    // getgroups(2) indicates that the group_member() may not check the egid so we check it
+    // additionally just to be sure.
+    if (group_member(plugdev_group->gr_gid) || getegid() == plugdev_group->gr_gid) {
+        // The user is in plugdev so the problem is likely with the udev rules.
+        return "verify udev rules";
+    }
+    return "udev requires plugdev group membership";
+#else
+    return nullptr;
+#endif
+}
+
+// Short help text must be a single line, and will look something like:
+//   no permissions (reason); see <URL>
+std::string UsbNoPermissionsShortHelpText() {
+    std::string help_text = "no permissions";
+
+    const char* problem = GetUdevProblem();
+    if (problem != nullptr) {
+        help_text += android::base::StringPrintf(" (%s)", problem);
+    }
+
+    return android::base::StringPrintf("%s; see [%s]", help_text.c_str(), kPermissionsHelpUrl);
+}
+
+// Long help text can span multiple lines and should provide more detailed information.
+std::string UsbNoPermissionsLongHelpText() {
+    std::string header = "insufficient permissions for device";
+
+    const char* problem = GetUdevProblem();
+    if (problem != nullptr) {
+        header += android::base::StringPrintf(": %s", problem);
+    }
+
+    return android::base::StringPrintf("%s.\nSee [%s] for more information.",
+                                       header.c_str(), kPermissionsHelpUrl);
+}
diff --git a/adb/diagnose_usb.h b/adb/diagnose_usb.h
new file mode 100644
index 0000000..325b2e3
--- /dev/null
+++ b/adb/diagnose_usb.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DIAGNOSE_LINUX_USB_H
+#define __DIAGNOSE_LINUX_USB_H
+
+#include <string>
+
+// USB permission error help text. The short version will be one line, long may be multi-line.
+// Returns a string message to print, or an empty string if no problems could be found.
+std::string UsbNoPermissionsShortHelpText();
+std::string UsbNoPermissionsLongHelpText();
+
+#endif
diff --git a/adb/file_sync_client.cpp b/adb/file_sync_client.cpp
index 239aaf8..c68f28b 100644
--- a/adb/file_sync_client.cpp
+++ b/adb/file_sync_client.cpp
@@ -504,16 +504,6 @@
     });
 }
 
-struct copyinfo
-{
-    std::string lpath;
-    std::string rpath;
-    unsigned int time;
-    unsigned int mode;
-    uint64_t size;
-    bool skip;
-};
-
 static void ensure_trailing_separator(std::string& lpath, std::string& rpath) {
     if (!adb_is_separator(lpath.back())) {
         lpath.push_back(OS_PATH_SEPARATOR);
@@ -523,25 +513,26 @@
     }
 }
 
-static copyinfo mkcopyinfo(std::string lpath, std::string rpath,
-                           const std::string& name, unsigned int mode) {
-    copyinfo result;
-    result.lpath = std::move(lpath);
-    result.rpath = std::move(rpath);
-    ensure_trailing_separator(result.lpath, result.rpath);
-    result.lpath.append(name);
-    result.rpath.append(name);
+struct copyinfo {
+    std::string lpath;
+    std::string rpath;
+    unsigned int time = 0;
+    unsigned int mode;
+    uint64_t size = 0;
+    bool skip = false;
 
-    if (S_ISDIR(mode)) {
-        ensure_trailing_separator(result.lpath, result.rpath);
+    copyinfo(const std::string& lpath, const std::string& rpath, const std::string& name,
+             unsigned int mode)
+        : lpath(lpath), rpath(rpath), mode(mode) {
+        ensure_trailing_separator(this->lpath, this->rpath);
+        this->lpath.append(name);
+        this->rpath.append(name);
+
+        if (S_ISDIR(mode)) {
+            ensure_trailing_separator(this->lpath, this->rpath);
+        }
     }
-
-    result.time = 0;
-    result.mode = mode;
-    result.size = 0;
-    result.skip = false;
-    return result;
-}
+};
 
 static bool IsDotOrDotDot(const char* name) {
     return name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
@@ -574,7 +565,7 @@
             continue;
         }
 
-        copyinfo ci = mkcopyinfo(lpath, rpath, de->d_name, st.st_mode);
+        copyinfo ci(lpath, rpath, de->d_name, st.st_mode);
         if (S_ISDIR(st.st_mode)) {
             dirlist.push_back(ci);
         } else {
@@ -598,8 +589,7 @@
         // TODO(b/25566053): Make pushing empty directories work.
         // TODO(b/25457350): We don't preserve permissions on directories.
         sc.Warning("skipping empty directory '%s'", lpath.c_str());
-        copyinfo ci = mkcopyinfo(adb_dirname(lpath), adb_dirname(rpath),
-                                 adb_basename(lpath), S_IFDIR);
+        copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(lpath), S_IFDIR);
         ci.skip = true;
         filelist->push_back(ci);
         return true;
@@ -743,11 +733,23 @@
     return success;
 }
 
+static bool remote_symlink_isdir(SyncConnection& sc, const std::string& rpath) {
+    unsigned mode;
+    std::string dir_path = rpath;
+    dir_path.push_back('/');
+    if (!sync_stat(sc, dir_path.c_str(), nullptr, &mode, nullptr)) {
+        sc.Error("failed to stat remote symlink '%s'", dir_path.c_str());
+        return false;
+    }
+    return S_ISDIR(mode);
+}
+
 static bool remote_build_list(SyncConnection& sc,
                               std::vector<copyinfo>* filelist,
                               const std::string& rpath,
                               const std::string& lpath) {
     std::vector<copyinfo> dirlist;
+    std::vector<copyinfo> linklist;
     bool empty_dir = true;
 
     // Put the files/dirs in rpath on the lists.
@@ -759,20 +761,14 @@
         // We found a child that isn't '.' or '..'.
         empty_dir = false;
 
-        copyinfo ci = mkcopyinfo(lpath, rpath, name, mode);
+        copyinfo ci(lpath, rpath, name, mode);
         if (S_ISDIR(mode)) {
             dirlist.push_back(ci);
+        } else if (S_ISLNK(mode)) {
+            linklist.push_back(ci);
         } else {
-            if (S_ISREG(mode)) {
-                ci.time = time;
-                ci.size = size;
-            } else if (S_ISLNK(mode)) {
-                sc.Warning("skipping symlink '%s'", name);
-                ci.skip = true;
-            } else {
-                sc.Warning("skipping special file '%s'", name);
-                ci.skip = true;
-            }
+            ci.time = time;
+            ci.size = size;
             filelist->push_back(ci);
         }
     };
@@ -781,14 +777,22 @@
         return false;
     }
 
-    // Add the current directory to the list if it was empty, to ensure that
-    // it gets created.
+    // Add the current directory to the list if it was empty, to ensure that it gets created.
     if (empty_dir) {
-        filelist->push_back(mkcopyinfo(adb_dirname(lpath), adb_dirname(rpath),
-                                       adb_basename(rpath), S_IFDIR));
+        copyinfo ci(adb_dirname(lpath), adb_dirname(rpath), adb_basename(rpath), S_IFDIR);
+        filelist->push_back(ci);
         return true;
     }
 
+    // Check each symlink we found to see whether it's a file or directory.
+    for (copyinfo& link_ci : linklist) {
+        if (remote_symlink_isdir(sc, link_ci.rpath)) {
+            dirlist.emplace_back(std::move(link_ci));
+        } else {
+            filelist->emplace_back(std::move(link_ci));
+        }
+    }
+
     // Recurse into each directory we found.
     while (!dirlist.empty()) {
         copyinfo current = dirlist.back();
@@ -912,6 +916,7 @@
         const char* dst_path = dst;
         unsigned src_mode, src_time;
         if (!sync_stat(sc, src_path, &src_time, &src_mode, nullptr)) {
+            sc.Error("failed to stat remote object '%s'", src_path);
             return false;
         }
         if (src_mode == 0) {
@@ -920,28 +925,17 @@
             continue;
         }
 
-        if (S_ISREG(src_mode)) {
-            std::string path_holder;
-            if (dst_isdir) {
-                // If we're copying a remote file to a local directory, we
-                // really want to copy to local_dir + OS_PATH_SEPARATOR +
-                // basename(remote).
-                path_holder = android::base::StringPrintf(
-                    "%s%c%s", dst_path, OS_PATH_SEPARATOR,
-                    adb_basename(src_path).c_str());
-                dst_path = path_holder.c_str();
-            }
-            if (!sync_recv(sc, src_path, dst_path)) {
-                success = false;
-                continue;
-            } else {
-                if (copy_attrs &&
-                    set_time_and_mode(dst_path, src_time, src_mode) != 0) {
-                    success = false;
-                    continue;
-                }
-            }
-        } else if (S_ISDIR(src_mode)) {
+        bool src_isdir = S_ISDIR(src_mode);
+        if (S_ISLNK(src_mode)) {
+            src_isdir = remote_symlink_isdir(sc, src_path);
+        }
+
+        if ((src_mode & (S_IFREG | S_IFDIR | S_IFBLK | S_IFCHR)) == 0) {
+            sc.Error("skipping remote object '%s' (mode = 0o%o)", src_path, src_mode);
+            continue;
+        }
+
+        if (src_isdir) {
             std::string dst_dir = dst;
 
             // If the destination path existed originally, the source directory
@@ -957,13 +951,28 @@
                 dst_dir.append(adb_basename(src_path));
             }
 
-            success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(),
-                                             copy_attrs);
+            success &= copy_remote_dir_local(sc, src_path, dst_dir.c_str(), copy_attrs);
             continue;
         } else {
-            sc.Error("remote object '%s' not a file or directory", src_path);
-            success = false;
-            continue;
+            std::string path_holder;
+            if (dst_isdir) {
+                // If we're copying a remote file to a local directory, we
+                // really want to copy to local_dir + OS_PATH_SEPARATOR +
+                // basename(remote).
+                path_holder = android::base::StringPrintf("%s%c%s", dst_path, OS_PATH_SEPARATOR,
+                                                          adb_basename(src_path).c_str());
+                dst_path = path_holder.c_str();
+            }
+
+            if (!sync_recv(sc, src_path, dst_path)) {
+                success = false;
+                continue;
+            }
+
+            if (copy_attrs && set_time_and_mode(dst_path, src_time, src_mode) != 0) {
+                success = false;
+                continue;
+            }
         }
     }
 
diff --git a/adb/shell_service.cpp b/adb/shell_service.cpp
index 3fc70b0..366ed07 100644
--- a/adb/shell_service.cpp
+++ b/adb/shell_service.cpp
@@ -88,6 +88,9 @@
 #include <termios.h>
 
 #include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
 
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
@@ -237,13 +240,55 @@
     ScopedFd parent_error_sfd, child_error_sfd;
     char pts_name[PATH_MAX];
 
-    // Create a socketpair for the fork() child to report any errors back to
-    // the parent. Since we use threads, logging directly from the child could
-    // create a race condition.
+    // Create a socketpair for the fork() child to report any errors back to the parent. Since we
+    // use threads, logging directly from the child might deadlock due to locks held in another
+    // thread during the fork.
     if (!CreateSocketpair(&parent_error_sfd, &child_error_sfd)) {
         LOG(ERROR) << "failed to create pipe for subprocess error reporting";
     }
 
+    // Construct the environment for the child before we fork.
+    passwd* pw = getpwuid(getuid());
+    std::unordered_map<std::string, std::string> env;
+    if (environ) {
+        char** current = environ;
+        while (char* env_cstr = *current++) {
+            std::string env_string = env_cstr;
+            char* delimiter = strchr(env_string.c_str(), '=');
+
+            // Drop any values that don't contain '='.
+            if (delimiter) {
+                *delimiter++ = '\0';
+                env[env_string.c_str()] = delimiter;
+            }
+        }
+    }
+
+    if (pw != nullptr) {
+        // TODO: $HOSTNAME? Normally bash automatically sets that, but mksh doesn't.
+        env["HOME"] = pw->pw_dir;
+        env["LOGNAME"] = pw->pw_name;
+        env["USER"] = pw->pw_name;
+        env["SHELL"] = pw->pw_shell;
+    }
+
+    if (!terminal_type_.empty()) {
+        env["TERM"] = terminal_type_;
+    }
+
+    std::vector<std::string> joined_env;
+    for (auto it : env) {
+        const char* key = it.first.c_str();
+        const char* value = it.second.c_str();
+        joined_env.push_back(android::base::StringPrintf("%s=%s", key, value));
+    }
+
+    std::vector<const char*> cenv;
+    for (const std::string& str : joined_env) {
+        cenv.push_back(str.c_str());
+    }
+    cenv.push_back(nullptr);
+
     if (type_ == SubprocessType::kPty) {
         int fd;
         pid_ = forkpty(&fd, pts_name, nullptr, nullptr);
@@ -286,26 +331,14 @@
         parent_error_sfd.Reset();
         close_on_exec(child_error_sfd.fd());
 
-        // TODO: $HOSTNAME? Normally bash automatically sets that, but mksh doesn't.
-        passwd* pw = getpwuid(getuid());
-        if (pw != nullptr) {
-            setenv("HOME", pw->pw_dir, 1);
-            setenv("LOGNAME", pw->pw_name, 1);
-            setenv("SHELL", pw->pw_shell, 1);
-            setenv("USER", pw->pw_name, 1);
-        }
-        if (!terminal_type_.empty()) {
-            setenv("TERM", terminal_type_.c_str(), 1);
-        }
-
         if (is_interactive()) {
-            execl(_PATH_BSHELL, _PATH_BSHELL, "-", nullptr);
+            execle(_PATH_BSHELL, _PATH_BSHELL, "-", nullptr, cenv.data());
         } else {
-            execl(_PATH_BSHELL, _PATH_BSHELL, "-c", command_.c_str(), nullptr);
+            execle(_PATH_BSHELL, _PATH_BSHELL, "-c", command_.c_str(), nullptr, cenv.data());
         }
         WriteFdExactly(child_error_sfd.fd(), "exec '" _PATH_BSHELL "' failed");
         child_error_sfd.Reset();
-        exit(-1);
+        _Exit(1);
     }
 
     // Subprocess parent.
@@ -320,6 +353,7 @@
         return false;
     }
 
+    D("subprocess parent: exec completed");
     if (protocol_ == SubprocessProtocol::kNone) {
         // No protocol: all streams pass through the stdinout FD and hook
         // directly into the local socket for raw data transfer.
@@ -357,6 +391,7 @@
         return false;
     }
 
+    D("subprocess parent: completed");
     return true;
 }
 
diff --git a/adb/test_device.py b/adb/test_device.py
index 955b67a..afc061a 100644
--- a/adb/test_device.py
+++ b/adb/test_device.py
@@ -829,6 +829,40 @@
             if host_dir is not None:
                 shutil.rmtree(host_dir)
 
+    def test_pull_symlink_dir(self):
+        """Pull a symlink to a directory of symlinks to files."""
+        try:
+            host_dir = tempfile.mkdtemp()
+
+            remote_dir = posixpath.join(self.DEVICE_TEMP_DIR, 'contents')
+            remote_links = posixpath.join(self.DEVICE_TEMP_DIR, 'links')
+            remote_symlink = posixpath.join(self.DEVICE_TEMP_DIR, 'symlink')
+
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+            self.device.shell(['mkdir', '-p', remote_dir, remote_links])
+            self.device.shell(['ln', '-s', remote_links, remote_symlink])
+
+            # Populate device directory with random files.
+            temp_files = make_random_device_files(
+                self.device, in_dir=remote_dir, num_files=32)
+
+            for temp_file in temp_files:
+                self.device.shell(
+                    ['ln', '-s', '../contents/{}'.format(temp_file.base_name),
+                     posixpath.join(remote_links, temp_file.base_name)])
+
+            self.device.pull(remote=remote_symlink, local=host_dir)
+
+            for temp_file in temp_files:
+                host_path = os.path.join(
+                    host_dir, 'symlink', temp_file.base_name)
+                self._verify_local(temp_file.checksum, host_path)
+
+            self.device.shell(['rm', '-rf', self.DEVICE_TEMP_DIR])
+        finally:
+            if host_dir is not None:
+                shutil.rmtree(host_dir)
+
     def test_pull_empty(self):
         """Pull a directory containing an empty directory from the device."""
         try:
diff --git a/adb/transport.cpp b/adb/transport.cpp
index 988007d..f8c8c61 100644
--- a/adb/transport.cpp
+++ b/adb/transport.cpp
@@ -35,6 +35,7 @@
 
 #include "adb.h"
 #include "adb_utils.h"
+#include "diagnose_usb.h"
 
 static void transport_unref(atransport *t);
 
@@ -674,11 +675,9 @@
     adb_mutex_lock(&transport_lock);
     for (const auto& t : transport_list) {
         if (t->connection_state == kCsNoPerm) {
+#if ADB_HOST
             *error_out = UsbNoPermissionsLongHelpText();
-            // If we couldn't figure out a reasonable help message default to something generic.
-            if (error_out->empty()) {
-                *error_out = "insufficient permissions for device";
-            }
+#endif
             continue;
         }
 
@@ -759,10 +758,7 @@
         case kCsDevice: return "device";
         case kCsHost: return "host";
         case kCsRecovery: return "recovery";
-        case kCsNoPerm: {
-            std::string message = UsbNoPermissionsShortHelpText();
-            return message.empty() ? "no permissions" : message;
-        }
+        case kCsNoPerm: return UsbNoPermissionsShortHelpText();
         case kCsSideload: return "sideload";
         case kCsUnauthorized: return "unauthorized";
         default: return "unknown";
diff --git a/adb/usb_linux.cpp b/adb/usb_linux.cpp
index e887a94..ed5d2d67 100644
--- a/adb/usb_linux.cpp
+++ b/adb/usb_linux.cpp
@@ -22,7 +22,6 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <grp.h>
 #include <linux/usb/ch9.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/version.h>
@@ -596,54 +595,3 @@
         fatal_errno("cannot create device_poll thread");
     }
 }
-
-static const char kPermissionsHelpUrl[] = "developer.android.com/tools/device.html";
-
-// Returns a message describing any potential problems we find with udev, or nullptr if we can't
-// find plugdev information (i.e. udev is not installed).
-static const char* GetUdevProblem() {
-    errno = 0;
-    group* plugdev_group = getgrnam("plugdev");
-
-    if (plugdev_group == nullptr) {
-        if (errno != 0) {
-            D("failed to read plugdev group info: %s", strerror(errno));
-        }
-        // We can't give any generally useful advice here, just let the caller print the help URL.
-        return nullptr;
-    }
-
-    // getgroups(2) indicates that the group_member() may not check the egid so we check it
-    // additionally just to be sure.
-    if (group_member(plugdev_group->gr_gid) || getegid() == plugdev_group->gr_gid) {
-        // The user is in plugdev so the problem is likely with the udev rules.
-        return "verify udev rules";
-    }
-    return "udev requires plugdev group membership";
-}
-
-// Short help text must be a single line, and will look something like:
-//   no permissions (reason); see <URL>
-std::string UsbNoPermissionsShortHelpText() {
-    std::string help_text = "no permissions";
-
-    const char* problem = GetUdevProblem();
-    if (problem != nullptr) {
-        help_text += android::base::StringPrintf(" (%s)", problem);
-    }
-
-    return android::base::StringPrintf("%s; see [%s]", help_text.c_str(), kPermissionsHelpUrl);
-}
-
-// Long help text can span multiple lines and should provide more detailed information.
-std::string UsbNoPermissionsLongHelpText() {
-    std::string header = "USB permission failure";
-
-    const char* problem = GetUdevProblem();
-    if (problem != nullptr) {
-        header += android::base::StringPrintf(": %s", problem);
-    }
-
-    return android::base::StringPrintf("%s.\nSee [%s] for more information.",
-                                       header.c_str(), kPermissionsHelpUrl);
-}
diff --git a/adb/usb_linux_client.cpp b/adb/usb_linux_client.cpp
index c5e7452..ceed8fa 100644
--- a/adb/usb_linux_client.cpp
+++ b/adb/usb_linux_client.cpp
@@ -571,12 +571,3 @@
 {
     h->kick(h);
 }
-
-// kCsNoPerm is a host-side issue, we can just ignore it here.
-std::string UsbNoPermissionsShortHelpText() {
-    return "";
-}
-
-std::string UsbNoPermissionsLongHelpText() {
-    return "";
-}
diff --git a/adb/usb_osx.cpp b/adb/usb_osx.cpp
index f494795..148be1d 100644
--- a/adb/usb_osx.cpp
+++ b/adb/usb_osx.cpp
@@ -552,12 +552,3 @@
         handle->interface = 0;
     }
 }
-
-// kCsNoPerm is Linux-only.
-std::string UsbNoPermissionsShortHelpText() {
-    return "";
-}
-
-std::string UsbNoPermissionsLongHelpText() {
-    return "";
-}
diff --git a/adb/usb_windows.cpp b/adb/usb_windows.cpp
index 9124685..8d3501e 100644
--- a/adb/usb_windows.cpp
+++ b/adb/usb_windows.cpp
@@ -659,12 +659,3 @@
   }
   adb_mutex_unlock(&usb_lock);
 }
-
-// kCsNoPerm is Linux-only.
-std::string UsbNoPermissionsShortHelpText() {
-    return "";
-}
-
-std::string UsbNoPermissionsLongHelpText() {
-    return "";
-}
diff --git a/fastboot/Android.mk b/fastboot/Android.mk
index 5ca88cb..c293b57 100644
--- a/fastboot/Android.mk
+++ b/fastboot/Android.mk
@@ -18,9 +18,12 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_C_INCLUDES := $(LOCAL_PATH)/../mkbootimg \
+LOCAL_C_INCLUDES := \
+  $(LOCAL_PATH)/../adb \
+  $(LOCAL_PATH)/../mkbootimg \
   $(LOCAL_PATH)/../../extras/ext4_utils \
-  $(LOCAL_PATH)/../../extras/f2fs_utils
+  $(LOCAL_PATH)/../../extras/f2fs_utils \
+
 LOCAL_SRC_FILES := protocol.cpp engine.cpp bootimg_utils.cpp fastboot.cpp util.cpp fs.cpp
 LOCAL_MODULE := fastboot
 LOCAL_MODULE_TAGS := debug
@@ -31,8 +34,10 @@
 LOCAL_CFLAGS += -DFASTBOOT_REVISION='"$(fastboot_version)"'
 
 LOCAL_SRC_FILES_linux := usb_linux.cpp util_linux.cpp
+LOCAL_STATIC_LIBRARIES_linux := libselinux
 
 LOCAL_SRC_FILES_darwin := usb_osx.cpp util_osx.cpp
+LOCAL_STATIC_LIBRARIES_darwin := libselinux
 LOCAL_LDLIBS_darwin := -lpthread -framework CoreFoundation -framework IOKit -framework Carbon
 LOCAL_CFLAGS_darwin := -Wno-unused-parameter
 
@@ -49,11 +54,9 @@
     libutils \
     liblog \
     libz \
+    libdiagnose_usb \
     libbase \
 
-LOCAL_STATIC_LIBRARIES_darwin := libselinux
-LOCAL_STATIC_LIBRARIES_linux := libselinux
-
 # libf2fs_dlutils_host will dlopen("libf2fs_fmt_host_dyn")
 LOCAL_CFLAGS_linux := -DUSE_F2FS
 LOCAL_LDFLAGS_linux := -ldl -rdynamic -Wl,-rpath,.
diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp
index 0f1d22f..d653746 100644
--- a/fastboot/fastboot.cpp
+++ b/fastboot/fastboot.cpp
@@ -53,6 +53,7 @@
 #include <android-base/parseint.h>
 
 #include "bootimg_utils.h"
+#include "diagnose_usb.h"
 #include "fastboot.h"
 #include "fs.h"
 #include "transport.h"
@@ -206,21 +207,21 @@
 
 static int list_devices_callback(usb_ifc_info* info) {
     if (match_fastboot_with_serial(info, nullptr) == 0) {
-        const char* serial = info->serial_number;
+        std::string serial = info->serial_number;
         if (!info->writable) {
-            serial = "no permissions"; // like "adb devices"
+            serial = UsbNoPermissionsShortHelpText();
         }
         if (!serial[0]) {
             serial = "????????????";
         }
         // output compatible with "adb devices"
         if (!long_listing) {
-            printf("%s\tfastboot\n", serial);
-        } else if (strcmp("", info->device_path) == 0) {
-            printf("%-22s fastboot\n", serial);
+            printf("%s\tfastboot", serial.c_str());
         } else {
-            printf("%-22s fastboot %s\n", serial, info->device_path);
+            printf("%-22s fastboot", serial.c_str());
+            if (strlen(info->device_path) > 0) printf(" %s", info->device_path);
         }
+        putchar('\n');
     }
 
     return -1;
diff --git a/fastboot/genkey.sh b/fastboot/genkey.sh
deleted file mode 100755
index 011e902..0000000
--- a/fastboot/genkey.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/bin/bash
-
-if [ $# -ne 2 ]
-then
- echo "Usage: $0 alias \"pass phrase\""
- exit -1
-fi
-
-# Generate a 2048 bit RSA key with public exponent 3.
-# Encrypt private key with provided password.
-openssl genrsa -3 -out $1.pem -passout pass:"$2" 2048
-
-# Create a self-signed cert for this key.
-openssl req -new -x509 -key $1.pem -passin pass:"$2" \
-        -out $1-cert.pem \
-        -batch -days 10000
-
-# Create a PKCS12 store containing the generated private key.
-# Protect the keystore and the private key with the provided password.
-openssl pkcs12 -export -in $1-cert.pem -inkey $1.pem -passin pass:"$2" \
-        -out $1.p12 -name $1 -passout pass:"$2"
-
-rm $1.pem
-rm $1-cert.pem
-
diff --git a/include/cutils/trace.h b/include/cutils/trace.h
index 087a0c4..c9790ad 100644
--- a/include/cutils/trace.h
+++ b/include/cutils/trace.h
@@ -69,7 +69,8 @@
 #define ATRACE_TAG_POWER            (1<<17)
 #define ATRACE_TAG_PACKAGE_MANAGER  (1<<18)
 #define ATRACE_TAG_SYSTEM_SERVER    (1<<19)
-#define ATRACE_TAG_LAST             ATRACE_TAG_SYSTEM_SERVER
+#define ATRACE_TAG_DATABASE         (1<<20)
+#define ATRACE_TAG_LAST             ATRACE_TAG_DATABASE
 
 // Reserved for initialization.
 #define ATRACE_TAG_NOT_READY        (1ULL<<63)
diff --git a/include/log/log.h b/include/log/log.h
index 619bf23..3d9240d 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -604,7 +604,8 @@
     LOG_ID_EVENTS = 2,
     LOG_ID_SYSTEM = 3,
     LOG_ID_CRASH = 4,
-    LOG_ID_KERNEL = 5,
+    LOG_ID_SECURITY = 5,
+    LOG_ID_KERNEL = 6, /* place last, third-parties can not use it */
 #endif
 
     LOG_ID_MAX
diff --git a/include/log/logd.h b/include/log/logd.h
index 0fe515f..b7aedaf 100644
--- a/include/log/logd.h
+++ b/include/log/logd.h
@@ -44,6 +44,8 @@
     size_t len);
 int __android_log_bswrite(int32_t tag, const char *payload);
 
+int __android_log_security_bwrite(int32_t tag, const void *payload, size_t len);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/log/logger.h b/include/log/logger.h
index b3928a7..60d47a2 100644
--- a/include/log/logger.h
+++ b/include/log/logger.h
@@ -64,12 +64,24 @@
     char        msg[0];    /* the entry's payload */
 } __attribute__((__packed__));
 
+struct logger_entry_v4 {
+    uint16_t    len;       /* length of the payload */
+    uint16_t    hdr_size;  /* sizeof(struct logger_entry_v4) */
+    int32_t     pid;       /* generating process's pid */
+    uint32_t    tid;       /* generating process's tid */
+    uint32_t    sec;       /* seconds since Epoch */
+    uint32_t    nsec;      /* nanoseconds */
+    uint32_t    lid;       /* log id of the payload, bottom 4 bits currently */
+    uint32_t    uid;       /* generating process's uid */
+    char        msg[0];    /* the entry's payload */
+} __attribute__((__packed__));
+
 /*
  * The maximum size of the log entry payload that can be
  * written to the logger. An attempt to write more than
  * this amount will result in a truncated log entry.
  */
-#define LOGGER_ENTRY_MAX_PAYLOAD	4076
+#define LOGGER_ENTRY_MAX_PAYLOAD	4068
 
 /*
  * The maximum size of a log entry which can be read from the
@@ -83,7 +95,8 @@
 struct log_msg {
     union {
         unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
-        struct logger_entry_v3 entry;
+        struct logger_entry_v4 entry;
+        struct logger_entry_v4 entry_v4;
         struct logger_entry_v3 entry_v3;
         struct logger_entry_v2 entry_v2;
         struct logger_entry    entry_v1;
diff --git a/include/log/logprint.h b/include/log/logprint.h
index 204b3f2..539d1dc 100644
--- a/include/log/logprint.h
+++ b/include/log/logprint.h
@@ -44,6 +44,7 @@
     FORMAT_MODIFIER_ZONE,      /* Adds zone to date */
     FORMAT_MODIFIER_EPOCH,     /* Print time as seconds since Jan 1 1970 */
     FORMAT_MODIFIER_MONOTONIC, /* Print cpu time as seconds since start */
+    FORMAT_MODIFIER_UID,       /* Adds uid */
 } AndroidLogPrintFormat;
 
 typedef struct AndroidLogFormat_t AndroidLogFormat;
@@ -52,6 +53,7 @@
     time_t tv_sec;
     long tv_nsec;
     android_LogPriority priority;
+    int32_t uid;
     int32_t pid;
     int32_t tid;
     const char * tag;
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h
index a1d2539..d236938 100644
--- a/include/private/android_filesystem_config.h
+++ b/include/private/android_filesystem_config.h
@@ -82,6 +82,7 @@
 #define AID_DBUS          1038  /* dbus-daemon IPC broker process */
 #define AID_TLSDATE       1039  /* tlsdate unprivileged user */
 #define AID_MEDIA_EX      1040  /* mediaextractor process */
+#define AID_AUDIOSERVER   1041  /* audioserver process */
 
 #define AID_SHELL         2000  /* adb and debug shell user */
 #define AID_CACHE         2001  /* cache access */
@@ -181,6 +182,7 @@
     { "dbus",          AID_DBUS, },
     { "tlsdate",       AID_TLSDATE, },
     { "mediaex",       AID_MEDIA_EX, },
+    { "audioserver",   AID_AUDIOSERVER, },
 
     { "shell",         AID_SHELL, },
     { "cache",         AID_CACHE, },
diff --git a/init/readme.txt b/init/readme.txt
index bf440c2..bacd6bd 100644
--- a/init/readme.txt
+++ b/init/readme.txt
@@ -109,9 +109,16 @@
 user <username>
   Change to username before exec'ing this service.
   Currently defaults to root.  (??? probably should default to nobody)
-  Currently, if your process requires linux capabilities then you cannot use
-  this command. You must instead request the capabilities in-process while
-  still root, and then drop to your desired uid.
+  As of Android M, processes should use this option even if they
+  require linux capabilities.  Previously, to acquire linux
+  capabilities, a process would need to run as root, request the
+  capabilities, then drop to its desired uid.  There is a new
+  mechanism through fs_config that allows device manufacturers to add
+  linux capabilities to specific binaries on a file system that should
+  be used instead. This mechanism is described on
+  http://source.android.com/devices/tech/config/filesystem.html.  When
+  using this new mechanism, processes can use the user option to
+  select their desired uid without ever running as root.
 
 group <groupname> [ <groupname> ]*
   Change to groupname before exec'ing this service.  Additional
diff --git a/libcutils/ashmem-host.c b/libcutils/ashmem-host.c
index abc4f94..15dd43e 100644
--- a/libcutils/ashmem-host.c
+++ b/libcutils/ashmem-host.c
@@ -43,11 +43,16 @@
     char template[PATH_MAX];
     snprintf(template, sizeof(template), "/tmp/android-ashmem-%d-XXXXXXXXX", getpid());
     int fd = mkstemp(template);
-    if (fd != -1 && TEMP_FAILURE_RETRY(ftruncate(fd, size)) != -1 && unlink(template) != -1) {
-        return fd;
+    if (fd == -1) return -1;
+
+    unlink(template);
+
+    if (TEMP_FAILURE_RETRY(ftruncate(fd, size)) == -1) {
+      close(fd);
+      return -1;
     }
-    close(fd);
-    return -1;
+
+    return fd;
 }
 
 int ashmem_set_prot_region(int fd __unused, int prot __unused)
diff --git a/liblog/log_read.c b/liblog/log_read.c
index fb86757..8aa887b 100644
--- a/liblog/log_read.c
+++ b/liblog/log_read.c
@@ -208,6 +208,7 @@
     [LOG_ID_EVENTS] = "events",
     [LOG_ID_SYSTEM] = "system",
     [LOG_ID_CRASH] = "crash",
+    [LOG_ID_SECURITY] = "security",
     [LOG_ID_KERNEL] = "kernel",
 };
 
@@ -634,6 +635,7 @@
         android_log_header_t l;
     } buf;
     static uint8_t preread_count;
+    bool is_system;
 
     memset(log_msg, 0, sizeof(*log_msg));
 
@@ -690,12 +692,15 @@
             }
 
             uid = get_best_effective_uid();
-            if (!uid_has_log_permission(uid) && (uid != buf.p.uid)) {
+            is_system = uid_has_log_permission(uid);
+            if (!is_system && (uid != buf.p.uid)) {
                 break;
             }
 
             ret = TEMP_FAILURE_RETRY(read(logger_list->sock,
-                                          log_msg->entry_v3.msg,
+                                          is_system ?
+                                              log_msg->entry_v4.msg :
+                                              log_msg->entry_v3.msg,
                                           buf.p.len - sizeof(buf)));
             if (ret < 0) {
                 return -errno;
@@ -704,13 +709,18 @@
                 return -EIO;
             }
 
-            log_msg->entry_v3.len = buf.p.len - sizeof(buf);
-            log_msg->entry_v3.hdr_size = sizeof(log_msg->entry_v3);
-            log_msg->entry_v3.pid = buf.p.pid;
-            log_msg->entry_v3.tid = buf.l.tid;
-            log_msg->entry_v3.sec = buf.l.realtime.tv_sec;
-            log_msg->entry_v3.nsec = buf.l.realtime.tv_nsec;
-            log_msg->entry_v3.lid = buf.l.id;
+            log_msg->entry_v4.len = buf.p.len - sizeof(buf);
+            log_msg->entry_v4.hdr_size = is_system ?
+                sizeof(log_msg->entry_v4) :
+                sizeof(log_msg->entry_v3);
+            log_msg->entry_v4.pid = buf.p.pid;
+            log_msg->entry_v4.tid = buf.l.tid;
+            log_msg->entry_v4.sec = buf.l.realtime.tv_sec;
+            log_msg->entry_v4.nsec = buf.l.realtime.tv_nsec;
+            log_msg->entry_v4.lid = buf.l.id;
+            if (is_system) {
+                log_msg->entry_v4.uid = buf.p.uid;
+            }
 
             return ret;
         }
diff --git a/liblog/logd_write.c b/liblog/logd_write.c
index 11c6d9c..c2b0ec2 100644
--- a/liblog/logd_write.c
+++ b/liblog/logd_write.c
@@ -84,7 +84,7 @@
 #endif  /* !defined(_WIN32) */
 
 #if FAKE_LOG_DEVICE
-static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1 };
+static int log_fds[(int)LOG_ID_MAX] = { -1, -1, -1, -1, -1, -1 };
 #else
 static int logd_fd = -1;
 static int pstore_fd = -1;
@@ -181,6 +181,7 @@
     static uid_t last_uid = AID_ROOT; /* logd *always* starts up as AID_ROOT */
     static pid_t last_pid = (pid_t) -1;
     static atomic_int_fast32_t dropped;
+    static atomic_int_fast32_t dropped_security;
 
     if (!nr) {
         return -EINVAL;
@@ -192,6 +193,23 @@
     if (last_pid == (pid_t) -1) {
         last_pid = getpid();
     }
+    if (log_id == LOG_ID_SECURITY) {
+        if ((last_uid != AID_SYSTEM) && (last_uid != AID_ROOT)) {
+            uid_t uid = geteuid();
+            if ((uid != AID_SYSTEM) && (uid != AID_ROOT)) {
+                gid_t gid = getgid();
+                if ((gid != AID_SYSTEM) && (gid != AID_ROOT)) {
+                    gid = getegid();
+                    if ((gid != AID_SYSTEM) && (gid != AID_ROOT)) {
+                        return -EPERM;
+                    }
+                }
+            }
+        }
+        if (!__android_log_security()) {
+            return -EPERM;
+        }
+    }
     /*
      *  struct {
      *      // what we provide to pstore
@@ -229,7 +247,26 @@
     newVec[1].iov_len    = sizeof(header);
 
     if (logd_fd > 0) {
-        int32_t snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
+        int32_t snapshot = atomic_exchange_explicit(&dropped_security, 0,
+                                                    memory_order_relaxed);
+        if (snapshot) {
+            android_log_event_int_t buffer;
+
+            header.id = LOG_ID_SECURITY;
+            buffer.header.tag = htole32(LIBLOG_LOG_TAG);
+            buffer.payload.type = EVENT_TYPE_INT;
+            buffer.payload.data = htole32(snapshot);
+
+            newVec[2].iov_base = &buffer;
+            newVec[2].iov_len  = sizeof(buffer);
+
+            ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, 2));
+            if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
+                atomic_fetch_add_explicit(&dropped_security, snapshot,
+                                          memory_order_relaxed);
+            }
+        }
+        snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed);
         if (snapshot) {
             android_log_event_int_t buffer;
 
@@ -243,7 +280,8 @@
 
             ret = TEMP_FAILURE_RETRY(writev(logd_fd, newVec + 1, 2));
             if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
-                atomic_fetch_add_explicit(&dropped, snapshot, memory_order_relaxed);
+                atomic_fetch_add_explicit(&dropped, snapshot,
+                                          memory_order_relaxed);
             }
         }
     }
@@ -315,6 +353,10 @@
         ret -= sizeof(header);
     } else if (ret == -EAGAIN) {
         atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
+        if (log_id == LOG_ID_SECURITY) {
+            atomic_fetch_add_explicit(&dropped_security, 1,
+                                      memory_order_relaxed);
+        }
     }
 #endif
 
@@ -328,6 +370,7 @@
     [LOG_ID_EVENTS] = "events",
     [LOG_ID_SYSTEM] = "system",
     [LOG_ID_CRASH] = "crash",
+    [LOG_ID_SECURITY] = "security",
     [LOG_ID_KERNEL] = "kernel",
 };
 
@@ -483,6 +526,18 @@
     return write_to_log(LOG_ID_EVENTS, vec, 2);
 }
 
+int __android_log_security_bwrite(int32_t tag, const void *payload, size_t len)
+{
+    struct iovec vec[2];
+
+    vec[0].iov_base = &tag;
+    vec[0].iov_len = sizeof(tag);
+    vec[1].iov_base = (void*)payload;
+    vec[1].iov_len = len;
+
+    return write_to_log(LOG_ID_SECURITY, vec, 2);
+}
+
 /*
  * Like __android_log_bwrite, but takes the type as well.  Doesn't work
  * for the general case where we're generating lists of stuff, but very
diff --git a/liblog/logprint.c b/liblog/logprint.c
index 40e13f4..bd36cdd 100644
--- a/liblog/logprint.c
+++ b/liblog/logprint.c
@@ -32,6 +32,7 @@
 #include <cutils/list.h>
 #include <log/logd.h>
 #include <log/logprint.h>
+#include <private/android_filesystem_config.h>
 
 #define MS_PER_NSEC 1000000
 #define US_PER_NSEC 1000
@@ -56,6 +57,7 @@
     bool zone_output;
     bool epoch_output;
     bool monotonic_output;
+    bool uid_output;
 };
 
 /*
@@ -204,6 +206,7 @@
     p_ret->zone_output = false;
     p_ret->epoch_output = false;
     p_ret->monotonic_output = android_log_clockid() == CLOCK_MONOTONIC;
+    p_ret->uid_output = false;
 
     return p_ret;
 }
@@ -258,6 +261,9 @@
     case FORMAT_MODIFIER_MONOTONIC:
         p_format->monotonic_output = true;
         return 0;
+    case FORMAT_MODIFIER_UID:
+        p_format->uid_output = true;
+        return 0;
     default:
         break;
     }
@@ -290,6 +296,7 @@
     else if (strcmp(formatString, "zone") == 0) format = FORMAT_MODIFIER_ZONE;
     else if (strcmp(formatString, "epoch") == 0) format = FORMAT_MODIFIER_EPOCH;
     else if (strcmp(formatString, "monotonic") == 0) format = FORMAT_MODIFIER_MONOTONIC;
+    else if (strcmp(formatString, "uid") == 0) format = FORMAT_MODIFIER_UID;
     else {
         extern char *tzname[2];
         static const char gmt[] = "GMT";
@@ -451,6 +458,7 @@
 {
     entry->tv_sec = buf->sec;
     entry->tv_nsec = buf->nsec;
+    entry->uid = -1;
     entry->pid = buf->pid;
     entry->tid = buf->tid;
 
@@ -482,6 +490,9 @@
     struct logger_entry_v2 *buf2 = (struct logger_entry_v2 *)buf;
     if (buf2->hdr_size) {
         msg = ((char *)buf2) + buf2->hdr_size;
+        if (buf2->hdr_size >= sizeof(struct logger_entry_v4)) {
+            entry->uid = ((struct logger_entry_v4 *)buf)->uid;
+        }
     }
     for (i = 1; i < buf->len; i++) {
         if (msg[i] == '\0') {
@@ -734,16 +745,25 @@
     entry->tv_sec = buf->sec;
     entry->tv_nsec = buf->nsec;
     entry->priority = ANDROID_LOG_INFO;
+    entry->uid = -1;
     entry->pid = buf->pid;
     entry->tid = buf->tid;
 
     /*
-     * Pull the tag out.
+     * Pull the tag out, fill in some additional details based on incoming
+     * buffer version (v3 adds lid, v4 adds uid).
      */
     eventData = (const unsigned char*) buf->msg;
     struct logger_entry_v2 *buf2 = (struct logger_entry_v2 *)buf;
     if (buf2->hdr_size) {
         eventData = ((unsigned char *)buf2) + buf2->hdr_size;
+        if ((buf2->hdr_size >= sizeof(struct logger_entry_v3)) &&
+                (((struct logger_entry_v3 *)buf)->lid == LOG_ID_SECURITY)) {
+            entry->priority = ANDROID_LOG_WARN;
+        }
+        if (buf2->hdr_size >= sizeof(struct logger_entry_v4)) {
+            entry->uid = ((struct logger_entry_v4 *)buf)->uid;
+        }
     }
     inCount = buf->len;
     if (inCount < 4)
@@ -1238,7 +1258,7 @@
     char prefixBuf[128], suffixBuf[128];
     char priChar;
     int prefixSuffixIsHeaderFooter = 0;
-    char *ret = NULL;
+    char *ret;
     time_t now;
     unsigned long nsec;
 
@@ -1310,6 +1330,30 @@
         suffixLen = MIN(suffixLen, sizeof(suffixBuf));
     }
 
+    char uid[16];
+    uid[0] = '\0';
+    if (p_format->uid_output) {
+        if (entry->uid >= 0) {
+            const struct android_id_info *info = android_ids;
+            size_t i;
+
+            for (i = 0; i < android_id_count; ++i) {
+                if (info->aid == (unsigned int)entry->uid) {
+                    break;
+                }
+                ++info;
+            }
+            if ((i < android_id_count) && (strlen(info->name) <= 5)) {
+                 snprintf(uid, sizeof(uid), "%5s:", info->name);
+            } else {
+                 // Not worth parsing package list, names all longer than 5
+                 snprintf(uid, sizeof(uid), "%5d:", entry->uid);
+            }
+        } else {
+            snprintf(uid, sizeof(uid), "      ");
+        }
+    }
+
     switch (p_format->format) {
         case FORMAT_TAG:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
@@ -1322,11 +1366,11 @@
                 "  (%s)\n", entry->tag);
             suffixLen += MIN(len, sizeof(suffixBuf) - suffixLen);
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%c(%5d) ", priChar, entry->pid);
+                "%c(%s%5d) ", priChar, uid, entry->pid);
             break;
         case FORMAT_THREAD:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%c(%5d:%5d) ", priChar, entry->pid, entry->tid);
+                "%c(%s%5d:%5d) ", priChar, uid, entry->pid, entry->tid);
             strcpy(suffixBuf + suffixLen, "\n");
             ++suffixLen;
             break;
@@ -1338,21 +1382,26 @@
             break;
         case FORMAT_TIME:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%s %c/%-8s(%5d): ", timeBuf, priChar, entry->tag, entry->pid);
+                "%s %c/%-8s(%s%5d): ", timeBuf, priChar, entry->tag,
+                uid, entry->pid);
             strcpy(suffixBuf + suffixLen, "\n");
             ++suffixLen;
             break;
         case FORMAT_THREADTIME:
+            ret = strchr(uid, ':');
+            if (ret) {
+                *ret = ' ';
+            }
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%s %5d %5d %c %-8s: ", timeBuf,
-                entry->pid, entry->tid, priChar, entry->tag);
+                "%s %s%5d %5d %c %-8s: ", timeBuf,
+                uid, entry->pid, entry->tid, priChar, entry->tag);
             strcpy(suffixBuf + suffixLen, "\n");
             ++suffixLen;
             break;
         case FORMAT_LONG:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "[ %s %5d:%5d %c/%-8s ]\n",
-                timeBuf, entry->pid, entry->tid, priChar, entry->tag);
+                "[ %s %s%5d:%5d %c/%-8s ]\n",
+                timeBuf, uid, entry->pid, entry->tid, priChar, entry->tag);
             strcpy(suffixBuf + suffixLen, "\n\n");
             suffixLen += 2;
             prefixSuffixIsHeaderFooter = 1;
@@ -1360,7 +1409,7 @@
         case FORMAT_BRIEF:
         default:
             len = snprintf(prefixBuf + prefixLen, sizeof(prefixBuf) - prefixLen,
-                "%c/%-8s(%5d): ", priChar, entry->tag, entry->pid);
+                "%c/%-8s(%s%5d): ", priChar, entry->tag, uid, entry->pid);
             strcpy(suffixBuf + suffixLen, "\n");
             ++suffixLen;
             break;
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index 597d8f6..621101c 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -25,6 +25,7 @@
 #include <log/logger.h>
 #include <log/log_read.h>
 #include <log/logprint.h>
+#include <private/android_logger.h>
 
 // enhanced version of LOG_FAILURE_RETRY to add support for EAGAIN and
 // non-syscall libs. Since we are only using this in the emergency of
@@ -201,6 +202,96 @@
     property_set(persist_key, persist);
 }
 
+TEST(liblog, __security_buffer) {
+    struct logger_list *logger_list;
+    android_event_long_t buffer;
+
+    static const char persist_key[] = "persist.logd.security";
+    char persist[PROP_VALUE_MAX];
+    bool set_persist = false;
+    bool allow_security = false;
+
+    if (__android_log_security()) {
+        allow_security = true;
+    } else {
+        property_get(persist_key, persist, "");
+        if (strcasecmp(persist, "true")) {
+            property_set(persist_key, "TRUE");
+            if (__android_log_security()) {
+                allow_security = true;
+                set_persist = true;
+            } else {
+                property_set(persist_key, persist);
+            }
+        }
+    }
+
+    if (!allow_security) {
+        fprintf(stderr, "WARNING: "
+                "security buffer disabled, bypassing end-to-end test\n");
+
+        log_time ts(CLOCK_MONOTONIC);
+
+        buffer.type = EVENT_TYPE_LONG;
+        buffer.data = *(static_cast<uint64_t *>((void *)&ts));
+
+        // expect failure!
+        ASSERT_GE(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
+
+        return;
+    }
+
+    pid_t pid = getpid();
+
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        LOG_ID_SECURITY, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
+        1000, pid)));
+
+    log_time ts(CLOCK_MONOTONIC);
+
+    buffer.type = EVENT_TYPE_LONG;
+    buffer.data = *(static_cast<uint64_t *>((void *)&ts));
+
+    ASSERT_LT(0, __android_log_security_bwrite(0, &buffer, sizeof(buffer)));
+    usleep(1000000);
+
+    int count = 0;
+
+    for (;;) {
+        log_msg log_msg;
+        if (android_logger_list_read(logger_list, &log_msg) <= 0) {
+            break;
+        }
+
+        ASSERT_EQ(log_msg.entry.pid, pid);
+
+        if ((log_msg.entry.len != (4 + 1 + 8))
+         || (log_msg.id() != LOG_ID_SECURITY)) {
+            continue;
+        }
+
+        char *eventData = log_msg.msg();
+
+        if (eventData[4] != EVENT_TYPE_LONG) {
+            continue;
+        }
+
+        log_time tx(eventData + 4 + 1);
+        if (ts == tx) {
+            ++count;
+        }
+    }
+
+    if (set_persist) {
+        property_set(persist_key, persist);
+    }
+
+    android_logger_list_close(logger_list);
+
+    EXPECT_EQ(1, count);
+
+}
+
 static unsigned signaled;
 log_time signal_time;
 
@@ -342,8 +433,9 @@
 }
 
 static const char max_payload_tag[] = "TEST_max_payload_XXXX";
-static const char max_payload_buf[LOGGER_ENTRY_MAX_PAYLOAD
-    - sizeof(max_payload_tag) - 1] = "LEONATO\n\
+#define SIZEOF_MAX_PAYLOAD_BUF (LOGGER_ENTRY_MAX_PAYLOAD - \
+                                sizeof(max_payload_tag) - 1)
+static const char max_payload_buf[] = "LEONATO\n\
 I learn in this letter that Don Peter of Arragon\n\
 comes this night to Messina\n\
 MESSENGER\n\
@@ -469,7 +561,7 @@
 trouble: the fashion of the world is to avoid\n\
 cost, and you encounter it\n\
 LEONATO\n\
-Never came trouble to my house in the likeness";
+Never came trouble to my house in the likeness of your grace";
 
 TEST(liblog, max_payload) {
     pid_t pid = getpid();
@@ -528,7 +620,7 @@
 
     EXPECT_EQ(true, matches);
 
-    EXPECT_LE(sizeof(max_payload_buf), static_cast<size_t>(max_len));
+    EXPECT_LE(SIZEOF_MAX_PAYLOAD_BUF, static_cast<size_t>(max_len));
 }
 
 TEST(liblog, too_big_payload) {
@@ -650,7 +742,8 @@
         EXPECT_EQ(id, android_logger_get_id(logger));
         EXPECT_LT(0, android_logger_get_log_size(logger));
         /* crash buffer is allowed to be empty, that is actually healthy! */
-        if (android_logger_get_log_readable_size(logger) || strcmp("crash", name)) {
+        if (android_logger_get_log_readable_size(logger) ||
+                (strcmp("crash", name) && strcmp("security", name))) {
             EXPECT_LT(0, android_logger_get_log_readable_size(logger));
         }
         EXPECT_LT(0, android_logger_get_log_version(logger));
@@ -1005,7 +1098,7 @@
     const int TAG = 123456782;
     const char SUBTAG[] = "test-subtag";
     const int UID = -1;
-    const int DATA_LEN = sizeof(max_payload_buf);
+    const int DATA_LEN = SIZEOF_MAX_PAYLOAD_BUF;
     struct logger_list *logger_list;
 
     pid_t pid = getpid();
@@ -1076,8 +1169,8 @@
         }
         eventData += dataLen;
 
-        // 4 bytes for the tag, and 512 bytes for the log since the max_payload_buf should be
-        // truncated.
+        // 4 bytes for the tag, and 512 bytes for the log since the
+        // max_payload_buf should be truncated.
         ASSERT_EQ(4 + 512, eventData - original);
 
         ++count;
diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp
index cef2d75..17b7742 100644
--- a/libnativeloader/native_loader.cpp
+++ b/libnativeloader/native_loader.cpp
@@ -132,7 +132,7 @@
                         jobject class_loader, jstring java_library_path,
                         jstring java_permitted_path) {
 #if defined(__ANDROID__)
-  if (target_sdk_version == 0 || class_loader == nullptr) {
+  if (target_sdk_version <= INT_MAX || class_loader == nullptr) {
     return dlopen(path, RTLD_NOW);
   }
 
diff --git a/libpixelflinger/codeflinger/MIPS64Assembler.cpp b/libpixelflinger/codeflinger/MIPS64Assembler.cpp
index a5305cc..672040b 100644
--- a/libpixelflinger/codeflinger/MIPS64Assembler.cpp
+++ b/libpixelflinger/codeflinger/MIPS64Assembler.cpp
@@ -1304,9 +1304,8 @@
 
 MIPS64Assembler::MIPS64Assembler(void* assembly, ArmToMips64Assembler *parent)
     : mParent(parent),
-    MIPSAssembler::MIPSAssembler(NULL, NULL)
+    MIPSAssembler::MIPSAssembler(assembly)
 {
-    mBase = mPC = (uint32_t *)assembly;
 }
 
 MIPS64Assembler::~MIPS64Assembler()
diff --git a/libpixelflinger/codeflinger/MIPSAssembler.cpp b/libpixelflinger/codeflinger/MIPSAssembler.cpp
index daa231f..5497fae 100644
--- a/libpixelflinger/codeflinger/MIPSAssembler.cpp
+++ b/libpixelflinger/codeflinger/MIPSAssembler.cpp
@@ -1256,6 +1256,12 @@
     mDuration = ggl_system_time();
 }
 
+MIPSAssembler::MIPSAssembler(void* assembly)
+    : mParent(NULL), mAssembly(NULL)
+{
+    mBase = mPC = (uint32_t *)assembly;
+}
+
 MIPSAssembler::~MIPSAssembler()
 {
 }
diff --git a/libpixelflinger/codeflinger/MIPSAssembler.h b/libpixelflinger/codeflinger/MIPSAssembler.h
index 06cb0d0..b53fefb 100644
--- a/libpixelflinger/codeflinger/MIPSAssembler.h
+++ b/libpixelflinger/codeflinger/MIPSAssembler.h
@@ -242,6 +242,7 @@
 {
 public:
                 MIPSAssembler(const sp<Assembly>& assembly, ArmToMipsAssembler *parent);
+                MIPSAssembler(void* assembly);
     virtual     ~MIPSAssembler();
 
     virtual uint32_t*   base() const;
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index 059916e..ddc91ca 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -265,7 +265,7 @@
                     "  -v <format>     Sets the log print format, where <format> is:\n"
                     "  --format=<format>\n"
                     "                      brief color epoch long monotonic printable process raw\n"
-                    "                      tag thread threadtime time usec UTC year zone\n\n"
+                    "                      tag thread threadtime time uid usec UTC year zone\n\n"
                     "  -D              print dividers between each log buffer\n"
                     "  --dividers\n"
                     "  -c              clear (flush) the entire log and exit\n"
@@ -283,10 +283,12 @@
                     "  --buffer_size=<size>\n"
                     "  -L              dump logs from prior to last reboot\n"
                     "  --last\n"
+                    // Leave security (Device Owner only installations) and
+                    // kernel (userdebug and eng) buffers undocumented.
                     "  -b <buffer>     Request alternate ring buffer, 'main', 'system', 'radio',\n"
-                    "  --buffer=<buffer> 'events', 'crash' or 'all'. Multiple -b parameters are\n"
-                    "                  allowed and results are interleaved. The default is\n"
-                    "                  -b main -b system -b crash.\n"
+                    "  --buffer=<buffer> 'events', 'crash', 'default' or 'all'. Multiple -b\n"
+                    "                  parameters are allowed and results are interleaved. The\n"
+                    "                  default is -b main -b system -b crash.\n"
                     "  -B              output the log in binary.\n"
                     "  --binary\n"
                     "  -S              output statistics.\n"
@@ -696,16 +698,20 @@
             break;
 
             case 'b': {
-                if (strcmp(optarg, "all") == 0) {
-                    while (devices) {
-                        dev = devices;
-                        devices = dev->next;
-                        delete dev;
-                    }
+                if (strcmp(optarg, "default") == 0) {
+                    for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
+                        switch (i) {
+                        case LOG_ID_SECURITY:
+                        case LOG_ID_EVENTS:
+                            continue;
+                        case LOG_ID_MAIN:
+                        case LOG_ID_SYSTEM:
+                        case LOG_ID_CRASH:
+                            break;
+                        default:
+                            continue;
+                        }
 
-                    devices = dev = NULL;
-                    g_devCount = 0;
-                    for(int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
                         const char *name = android_log_id_to_name((log_id_t)i);
                         log_id_t log_id = android_name_to_log_id(name);
 
@@ -713,7 +719,58 @@
                             continue;
                         }
 
-                        bool binary = strcmp(name, "events") == 0;
+                        bool found = false;
+                        for (dev = devices; dev; dev = dev->next) {
+                            if (!strcmp(optarg, dev->device)) {
+                                found = true;
+                                break;
+                            }
+                            if (!dev->next) {
+                                break;
+                            }
+                        }
+                        if (found) {
+                            break;
+                        }
+
+                        log_device_t* d = new log_device_t(name, false);
+
+                        if (dev) {
+                            dev->next = d;
+                            dev = d;
+                        } else {
+                            devices = dev = d;
+                        }
+                        g_devCount++;
+                    }
+                    break;
+                }
+
+                if (strcmp(optarg, "all") == 0) {
+                    for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
+                        const char *name = android_log_id_to_name((log_id_t)i);
+                        log_id_t log_id = android_name_to_log_id(name);
+
+                        if (log_id != (log_id_t)i) {
+                            continue;
+                        }
+
+                        bool found = false;
+                        for (dev = devices; dev; dev = dev->next) {
+                            if (!strcmp(optarg, dev->device)) {
+                                found = true;
+                                break;
+                            }
+                            if (!dev->next) {
+                                break;
+                            }
+                        }
+                        if (found) {
+                            break;
+                        }
+
+                        bool binary = !strcmp(name, "events") ||
+                                      !strcmp(name, "security");
                         log_device_t* d = new log_device_t(name, binary);
 
                         if (dev) {
@@ -727,14 +784,21 @@
                     break;
                 }
 
-                bool binary = strcmp(optarg, "events") == 0;
+                bool binary = !(strcmp(optarg, "events") &&
+                                strcmp(optarg, "security"));
 
                 if (devices) {
                     dev = devices;
                     while (dev->next) {
+                        if (!strcmp(optarg, dev->device)) {
+                            dev = NULL;
+                            break;
+                        }
                         dev = dev->next;
                     }
-                    dev->next = new log_device_t(optarg, binary);
+                    if (dev) {
+                        dev->next = new log_device_t(optarg, binary);
+                    }
                 } else {
                     devices = new log_device_t(optarg, binary);
                 }
@@ -1004,7 +1068,7 @@
         size_t len = 8192;
         char *buf;
 
-        for(int retry = 32;
+        for (int retry = 32;
                 (retry >= 0) && ((buf = new char [len]));
                 delete [] buf, buf = NULL, --retry) {
             if (getPruneList) {
@@ -1094,7 +1158,7 @@
             logcat_panic(false, "logcat read failure");
         }
 
-        for(d = devices; d; d = d->next) {
+        for (d = devices; d; d = d->next) {
             if (android_name_to_log_id(d->device) == log_msg.id()) {
                 break;
             }
diff --git a/logd/CommandListener.cpp b/logd/CommandListener.cpp
index c45111a..e103359 100644
--- a/logd/CommandListener.cpp
+++ b/logd/CommandListener.cpp
@@ -34,6 +34,7 @@
 
 #include "CommandListener.h"
 #include "LogCommand.h"
+#include "LogUtils.h"
 
 CommandListener::CommandListener(LogBuffer *buf, LogReader * /*reader*/,
                                  LogListener * /*swl*/) :
diff --git a/logd/FlushCommand.cpp b/logd/FlushCommand.cpp
index bf650cd..cb3d1c2 100644
--- a/logd/FlushCommand.cpp
+++ b/logd/FlushCommand.cpp
@@ -21,6 +21,7 @@
 #include "LogCommand.h"
 #include "LogReader.h"
 #include "LogTimes.h"
+#include "LogUtils.h"
 
 FlushCommand::FlushCommand(LogReader &reader,
                            bool nonBlock,
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index 6770bb7..1e4f3b0 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -199,22 +199,24 @@
 
     LogBufferElement *elem = new LogBufferElement(log_id, realtime,
                                                   uid, pid, tid, msg, len);
-    int prio = ANDROID_LOG_INFO;
-    const char *tag = NULL;
-    if (log_id == LOG_ID_EVENTS) {
-        tag = android::tagToName(elem->getTag());
-    } else {
-        prio = *msg;
-        tag = msg + 1;
-    }
-    if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
-        // Log traffic received to total
-        pthread_mutex_lock(&mLogElementsLock);
-        stats.add(elem);
-        stats.subtract(elem);
-        pthread_mutex_unlock(&mLogElementsLock);
-        delete elem;
-        return -EACCES;
+    if (log_id != LOG_ID_SECURITY) {
+        int prio = ANDROID_LOG_INFO;
+        const char *tag = NULL;
+        if (log_id == LOG_ID_EVENTS) {
+            tag = android::tagToName(elem->getTag());
+        } else {
+            prio = *msg;
+            tag = msg + 1;
+        }
+        if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
+            // Log traffic received to total
+            pthread_mutex_lock(&mLogElementsLock);
+            stats.add(elem);
+            stats.subtract(elem);
+            pthread_mutex_unlock(&mLogElementsLock);
+            delete elem;
+            return -EACCES;
+        }
     }
 
     pthread_mutex_lock(&mLogElementsLock);
@@ -484,7 +486,7 @@
     }
 
     // prune by worst offender by uid
-    bool hasBlacklist = mPrune.naughty();
+    bool hasBlacklist = (id != LOG_ID_SECURITY) && mPrune.naughty();
     while (!clearAll && (pruneRows > 0)) {
         // recalculate the worst offender on every batched pass
         uid_t worst = (uid_t) -1;
@@ -654,7 +656,7 @@
     }
 
     bool whitelist = false;
-    bool hasWhitelist = mPrune.nice() && !clearAll;
+    bool hasWhitelist = (id != LOG_ID_SECURITY) && mPrune.nice() && !clearAll;
     it = mLogElements.begin();
     while((pruneRows > 0) && (it != mLogElements.end())) {
         LogBufferElement *e = *it;
@@ -846,7 +848,7 @@
         pthread_mutex_unlock(&mLogElementsLock);
 
         // range locking in LastLogTimes looks after us
-        max = element->flushTo(reader, this);
+        max = element->flushTo(reader, this, privileged);
 
         if (max == element->FLUSH_ERROR) {
             return max;
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index c4c302b..fde9ad7 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -51,7 +51,8 @@
 }
 
 uint32_t LogBufferElement::getTag() const {
-    if ((mLogId != LOG_ID_EVENTS) || !mMsg || (mMsgLen < sizeof(uint32_t))) {
+    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);
@@ -158,7 +159,9 @@
                           mDropped, (mDropped > 1) ? "s" : "");
 
     size_t hdrLen;
-    if (mLogId == LOG_ID_EVENTS) {
+    // LOG_ID_SECURITY not strictly needed since spam filter not activated,
+    // but required for accuracy.
+    if ((mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY)) {
         hdrLen = sizeof(android_log_event_string_t);
     } else {
         hdrLen = 1 + sizeof(tag);
@@ -172,7 +175,7 @@
     }
 
     size_t retval = hdrLen + len;
-    if (mLogId == LOG_ID_EVENTS) {
+    if ((mLogId == LOG_ID_EVENTS) || (mLogId == LOG_ID_SECURITY)) {
         android_log_event_string_t *event =
             reinterpret_cast<android_log_event_string_t *>(buffer);
 
@@ -194,21 +197,25 @@
     return retval;
 }
 
-uint64_t LogBufferElement::flushTo(SocketClient *reader, LogBuffer *parent) {
-    struct logger_entry_v3 entry;
+uint64_t LogBufferElement::flushTo(SocketClient *reader, LogBuffer *parent,
+                                   bool privileged) {
+    struct logger_entry_v4 entry;
 
-    memset(&entry, 0, sizeof(struct logger_entry_v3));
+    memset(&entry, 0, sizeof(struct logger_entry_v4));
 
-    entry.hdr_size = sizeof(struct logger_entry_v3);
+    entry.hdr_size = privileged ?
+                         sizeof(struct logger_entry_v4) :
+                         sizeof(struct logger_entry_v3);
     entry.lid = mLogId;
     entry.pid = mPid;
     entry.tid = mTid;
+    entry.uid = mUid;
     entry.sec = mRealTime.tv_sec;
     entry.nsec = mRealTime.tv_nsec;
 
     struct iovec iovec[2];
     iovec[0].iov_base = &entry;
-    iovec[0].iov_len = sizeof(struct logger_entry_v3);
+    iovec[0].iov_len = entry.hdr_size;
 
     char *buffer = NULL;
 
diff --git a/logd/LogBufferElement.h b/logd/LogBufferElement.h
index 09987ea..e7f88b9 100644
--- a/logd/LogBufferElement.h
+++ b/logd/LogBufferElement.h
@@ -80,7 +80,7 @@
     uint32_t getTag(void) const;
 
     static const uint64_t FLUSH_ERROR;
-    uint64_t flushTo(SocketClient *writer, LogBuffer *parent);
+    uint64_t flushTo(SocketClient *writer, LogBuffer *parent, bool privileged);
 };
 
 #endif
diff --git a/logd/LogCommand.cpp b/logd/LogCommand.cpp
index 6d0e92e..3b17576 100644
--- a/logd/LogCommand.cpp
+++ b/logd/LogCommand.cpp
@@ -22,6 +22,7 @@
 #include <private/android_filesystem_config.h>
 
 #include "LogCommand.h"
+#include "LogUtils.h"
 
 LogCommand::LogCommand(const char *cmd) : FrameworkCommand(cmd) {
 }
@@ -56,20 +57,18 @@
     return false;
 }
 
-bool clientHasLogCredentials(SocketClient * cli) {
-    uid_t uid = cli->getUid();
-    if (uid == AID_ROOT) {
+bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid) {
+    if ((uid == AID_ROOT) || (uid == AID_SYSTEM) || (uid == AID_LOG)) {
         return true;
     }
 
-    gid_t gid = cli->getGid();
     if ((gid == AID_ROOT) || (gid == AID_SYSTEM) || (gid == AID_LOG)) {
         return true;
     }
 
     // FYI We will typically be here for 'adb logcat'
     char filename[256];
-    snprintf(filename, sizeof(filename), "/proc/%u/status", cli->getPid());
+    snprintf(filename, sizeof(filename), "/proc/%u/status", pid);
 
     bool ret;
     bool foundLog = false;
@@ -145,3 +144,7 @@
 
     return ret;
 }
+
+bool clientHasLogCredentials(SocketClient *cli) {
+    return clientHasLogCredentials(cli->getUid(), cli->getGid(), cli->getPid());
+}
diff --git a/logd/LogCommand.h b/logd/LogCommand.h
index e3b96a2..c944478 100644
--- a/logd/LogCommand.h
+++ b/logd/LogCommand.h
@@ -26,6 +26,4 @@
     virtual ~LogCommand() {}
 };
 
-bool clientHasLogCredentials(SocketClient * cli);
-
 #endif
diff --git a/logd/LogListener.cpp b/logd/LogListener.cpp
index b29f5ab..5348a2d 100644
--- a/logd/LogListener.cpp
+++ b/logd/LogListener.cpp
@@ -27,6 +27,7 @@
 #include <private/android_logger.h>
 
 #include "LogListener.h"
+#include "LogUtils.h"
 
 LogListener::LogListener(LogBuffer *buf, LogReader *reader) :
         SocketListener(getLogSocket(), false),
@@ -44,7 +45,6 @@
     char buffer[sizeof_log_id_t + sizeof(uint16_t) + sizeof(log_time)
         + LOGGER_ENTRY_MAX_PAYLOAD];
     struct iovec iov = { buffer, sizeof(buffer) };
-    memset(buffer, 0, sizeof(buffer));
 
     char control[CMSG_SPACE(sizeof(struct ucred))];
     struct msghdr hdr = {
@@ -59,6 +59,9 @@
 
     int socket = cli->getSocket();
 
+    // To clear the entire buffer is secure/safe, but this contributes to 1.68%
+    // overhead under logging load. We are safe because we check counts.
+    // memset(buffer, 0, sizeof(buffer));
     ssize_t n = recvmsg(socket, &hdr, 0);
     if (n <= (ssize_t)(sizeof(android_log_header_t))) {
         return false;
@@ -92,6 +95,12 @@
         return false;
     }
 
+    if ((header->id == LOG_ID_SECURITY) &&
+            (!__android_log_security() ||
+             !clientHasLogCredentials(cred->uid, cred->gid, cred->pid))) {
+        return false;
+    }
+
     char *msg = ((char *)buffer) + sizeof(android_log_header_t);
     n -= sizeof(android_log_header_t);
 
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp
index 416edd8..bf0e30b 100644
--- a/logd/LogStatistics.cpp
+++ b/logd/LogStatistics.cpp
@@ -85,7 +85,11 @@
 
     uint32_t tag = element->getTag();
     if (tag) {
-        tagTable.add(tag, element);
+        if (log_id == LOG_ID_SECURITY) {
+            securityTagTable.add(tag, element);
+        } else {
+            tagTable.add(tag, element);
+        }
     }
 }
 
@@ -113,7 +117,11 @@
 
     uint32_t tag = element->getTag();
     if (tag) {
-        tagTable.subtract(tag, element);
+        if (log_id == LOG_ID_SECURITY) {
+            securityTagTable.subtract(tag, element);
+        } else {
+            tagTable.subtract(tag, element);
+        }
     }
 }
 
@@ -468,6 +476,11 @@
         output += tagTable.format(*this, uid, name, LOG_ID_EVENTS);
     }
 
+    if (enable && (logMask & (1 << LOG_ID_SECURITY))) {
+        name = "Chattiest security log buffer TAGs:";
+        output += securityTagTable.format(*this, uid, name, LOG_ID_SECURITY);
+    }
+
     return output;
 }
 
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h
index 28810d9..8558b06 100644
--- a/logd/LogStatistics.h
+++ b/logd/LogStatistics.h
@@ -397,6 +397,9 @@
     typedef LogHashtable<uint32_t, TagEntry> tagTable_t;
     tagTable_t tagTable;
 
+    // security tag list
+    tagTable_t securityTagTable;
+
 public:
     LogStatistics();
 
diff --git a/logd/LogUtils.h b/logd/LogUtils.h
index 533eb1c..b591f28 100644
--- a/logd/LogUtils.h
+++ b/logd/LogUtils.h
@@ -20,6 +20,7 @@
 #include <sys/types.h>
 
 #include <log/log.h>
+#include <sysutils/SocketClient.h>
 
 // Hijack this header as a common include file used by most all sources
 // to report some utilities defined here and there.
@@ -38,8 +39,12 @@
 
 }
 
+// Furnished in LogCommand.cpp
+bool clientHasLogCredentials(uid_t uid, gid_t gid, pid_t pid);
+bool clientHasLogCredentials(SocketClient *cli);
+
 static inline bool worstUidEnabledForLogid(log_id_t id) {
-    return (id != LOG_ID_CRASH) && (id != LOG_ID_KERNEL) && (id != LOG_ID_EVENTS);
+    return (id == LOG_ID_MAIN) || (id == LOG_ID_SYSTEM) || (id == LOG_ID_RADIO);
 }
 
 template <int (*cmp)(const char *l, const char *r, const size_t s)>
diff --git a/rootdir/init.rc b/rootdir/init.rc
index a902536..ab6afa2 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -605,13 +605,3 @@
 service flash_recovery /system/bin/install-recovery.sh
     class main
     oneshot
-
-# bugreportplus is an enhanced version of bugreport that provides a better
-# user interface (like displaying progress and allowing user to enter details).
-# It's typically triggered by the power button or developer settings.
-# TODO: remove the -p option when screenshot is taken by Shell
-service bugreportplus /system/bin/dumpstate -d -p -B -P -z \
-        -o /data/data/com.android.shell/files/bugreports/bugreport
-    class main
-    disabled
-    oneshot
diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc
index 0ca38b9..53cfcc2 100644
--- a/rootdir/init.zygote32.rc
+++ b/rootdir/init.zygote32.rc
@@ -3,6 +3,7 @@
     socket zygote stream 660 root system
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
+    onrestart restart audioserver
     onrestart restart media
     onrestart restart netd
     writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc
index 1646c0f..a9a94d7 100644
--- a/rootdir/init.zygote32_64.rc
+++ b/rootdir/init.zygote32_64.rc
@@ -3,6 +3,7 @@
     socket zygote stream 660 root system
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
+    onrestart restart audioserver
     onrestart restart media
     onrestart restart netd
     writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc
index b477c8e..8f47174 100644
--- a/rootdir/init.zygote64.rc
+++ b/rootdir/init.zygote64.rc
@@ -3,6 +3,7 @@
     socket zygote stream 660 root system
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
+    onrestart restart audioserver
     onrestart restart media
     onrestart restart netd
     writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks
diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc
index 633a981..70a9678 100644
--- a/rootdir/init.zygote64_32.rc
+++ b/rootdir/init.zygote64_32.rc
@@ -3,6 +3,7 @@
     socket zygote stream 660 root system
     onrestart write /sys/android_power/request_state wake
     onrestart write /sys/power/state on
+    onrestart restart audioserver
     onrestart restart media
     onrestart restart netd
     writepid /dev/cpuset/foreground/tasks /sys/fs/cgroup/stune/foreground/tasks