Merge "init/service.cpp: fix access check for console"
diff --git a/fastboot/fastboot_protocol.txt b/fastboot/fastboot_protocol.txt
index 2801703..b12e420 100644
--- a/fastboot/fastboot_protocol.txt
+++ b/fastboot/fastboot_protocol.txt
@@ -78,7 +78,7 @@
 
 Host:    "getvar:nonexistant"    request some undefined variable
 
-Client:  "OKAY"                  return value ""
+Client:  "FAILUnknown variable"  getvar failure; see getvar details below
 
 Host:    "download:00001234"     request to send 0x1234 bytes of data
 
@@ -113,7 +113,14 @@
 
  "getvar:%s"           Read a config/version variable from the bootloader.
                        The variable contents will be returned after the
-                       OKAY response.
+                       OKAY response. If the variable is unknown, the bootloader
+                       should return a FAIL response, optionally with an error
+                       message.
+
+                       Previous versions of this document indicated that getvar
+                       should return an empty OKAY response for unknown
+                       variables, so older devices might exhibit this behavior,
+                       but new implementations should return FAIL instead.
 
  "download:%08x"       Write data to memory which will be later used
                        by "boot", "ramdisk", "flash", etc.  The client
@@ -215,7 +222,7 @@
 Host    [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x0E]getvar:version
 Device  [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x07]OKAY0.4
 Host    [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x0B]getvar:none
-Device  [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x04]OKAY
+Device  [0x00][0x00][0x00][0x00][0x00][0x00][0x00][0x14]FAILUnknown variable
 Host    <disconnect>
 
 
@@ -364,10 +371,10 @@
                                         0x03  0x00  0x00  0x01
 0x03  0x00  0x00  0x02
                                         0x03  0x00  0x00  0x02  OKAY0.4
-0x03  0x00  0x00  0x03  getvar:foo
+0x03  0x00  0x00  0x03  getvar:none
                                         0x03  0x00  0x00  0x03
 0x03  0x00  0x00  0x04
-                                        0x03  0x00  0x00  0x04  OKAY
+                                        0x03  0x00  0x00  0x04  FAILUnknown var
 
 ----------------------------------------------------------------------
 [fastboot "INFO" responses, S = 0x0000]
diff --git a/include/log/log.h b/include/log/log.h
index d6f0eb5..ece9ea6 100644
--- a/include/log/log.h
+++ b/include/log/log.h
@@ -24,7 +24,7 @@
 #include <stdint.h>  /* uint16_t, int32_t */
 #include <stdio.h>
 #include <sys/types.h>
-#include <time.h>    /* clock_gettime */
+#include <time.h>
 #include <unistd.h>
 
 #include <android/log.h>
@@ -812,6 +812,54 @@
 void __android_log_close();
 #endif
 
+#ifndef __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE
+#ifndef __ANDROID_API__
+#define __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE 1
+#elif __ANDROID_API__ > 25 /* > OC */
+#define __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE 1
+#else
+#define __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE 0
+#endif
+#endif
+
+#if __ANDROID_USE_LIBLOG_RATELIMIT_INTERFACE
+
+/*
+ * if last is NULL, caller _must_ provide a consistent value for seconds.
+ *
+ * Return -1 if we can not acquire a lock, which below will permit the logging,
+ * error on allowing a log message through.
+ */
+int __android_log_ratelimit(time_t seconds, time_t* last);
+
+/*
+ * Usage:
+ *
+ *   // Global default and state
+ *   IF_ALOG_RATELIMIT() {
+ *      ALOG*(...);
+ *   }
+ *
+ *   // local state, 10 seconds ratelimit
+ *   static time_t local_state;
+ *   IF_ALOG_RATELIMIT_LOCAL(10, &local_state) {
+ *     ALOG*(...);
+ *   }
+ */
+
+#define IF_ALOG_RATELIMIT() \
+      if (__android_log_ratelimit(0, NULL) > 0)
+#define IF_ALOG_RATELIMIT_LOCAL(seconds, state) \
+      if (__android_log_ratelimit(seconds, state) > 0)
+
+#else
+
+/* No ratelimiting as API unsupported */
+#define IF_ALOG_RATELIMIT() if (1)
+#define IF_ALOG_RATELIMIT_LOCAL(...) if (1)
+
+#endif
+
 #if defined(__clang__)
 #pragma clang diagnostic pop
 #endif
diff --git a/include/ziparchive/zip_archive.h b/include/ziparchive/zip_archive.h
index 54946fc..31fc2df 100644
--- a/include/ziparchive/zip_archive.h
+++ b/include/ziparchive/zip_archive.h
@@ -26,8 +26,6 @@
 #include <sys/types.h>
 #include <utils/Compat.h>
 
-__BEGIN_DECLS
-
 /* Zip compression methods we support */
 enum {
   kCompressStored     = 0,        // no compression
@@ -228,6 +226,4 @@
         ProcessZipEntryFunction func, void* cookie);
 #endif
 
-__END_DECLS
-
 #endif  // LIBZIPARCHIVE_ZIPARCHIVE_H_
diff --git a/init/Android.mk b/init/Android.mk
index ecdf5db..111fe89 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -54,7 +54,7 @@
     service.cpp \
     util.cpp \
 
-LOCAL_STATIC_LIBRARIES := libbase libselinux liblog libprocessgroup
+LOCAL_STATIC_LIBRARIES := libbase libselinux liblog libprocessgroup libnl
 LOCAL_WHOLE_STATIC_LIBRARIES := libcap
 LOCAL_MODULE := libinit
 LOCAL_SANITIZE := integer
@@ -103,7 +103,8 @@
     libdl \
     libsparse_static \
     libz \
-    libprocessgroup
+    libprocessgroup \
+    libnl \
 
 # Create symlinks.
 LOCAL_POST_INSTALL_CMD := $(hide) mkdir -p $(TARGET_ROOT_OUT)/sbin; \
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 812ac3c..1186e9d 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -38,6 +38,7 @@
 #include <linux/loop.h>
 #include <linux/module.h>
 
+#include <string>
 #include <thread>
 
 #include <selinux/android.h>
@@ -67,6 +68,8 @@
 #include "signal_handler.h"
 #include "util.h"
 
+using namespace std::literals::string_literals;
+
 #define chmod DO_NOT_USE_CHMOD_USE_FCHMODAT_SYMLINK_NOFOLLOW
 #define UNMOUNT_CHECK_TIMES 10
 
@@ -139,8 +142,7 @@
     }
 }
 
-static int wipe_data_via_recovery(const std::string& reason) {
-    const std::vector<std::string> options = {"--wipe_data", std::string() + "--reason=" + reason};
+static int reboot_into_recovery(const std::vector<std::string>& options) {
     std::string err;
     if (!write_bootloader_message(options, &err)) {
         LOG(ERROR) << "failed to set bootloader message: " << err;
@@ -247,7 +249,7 @@
 }
 
 static int do_domainname(const std::vector<std::string>& args) {
-    return write_file("/proc/sys/kernel/domainname", args[1].c_str());
+    return write_file("/proc/sys/kernel/domainname", args[1].c_str()) ? 0 : 1;
 }
 
 static int do_enable(const std::vector<std::string>& args) {
@@ -275,7 +277,7 @@
 }
 
 static int do_hostname(const std::vector<std::string>& args) {
-    return write_file("/proc/sys/kernel/hostname", args[1].c_str());
+    return write_file("/proc/sys/kernel/hostname", args[1].c_str()) ? 0 : 1;
 }
 
 static int do_ifup(const std::vector<std::string>& args) {
@@ -338,7 +340,10 @@
 
     if (e4crypt_is_native()) {
         if (e4crypt_set_directory_policy(args[1].c_str())) {
-            wipe_data_via_recovery(std::string() + "set_policy_failed:" + args[1]);
+            const std::vector<std::string> options = {
+                "--prompt_and_wipe_data",
+                "--reason=set_policy_failed:"s + args[1]};
+            reboot_into_recovery(options);
             return -1;
         }
     }
@@ -559,7 +564,8 @@
     } else if (code == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
         /* Setup a wipe via recovery, and reboot into recovery */
         PLOG(ERROR) << "fs_mgr_mount_all suggested recovery, so wiping data via recovery.";
-        ret = wipe_data_via_recovery("fs_mgr_mount_all");
+        const std::vector<std::string> options = {"--wipe_data", "--reason=fs_mgr_mount_all" };
+        ret = reboot_into_recovery(options);
         /* If reboot worked, there is no return. */
     } else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
         if (e4crypt_install_keyring()) {
@@ -808,7 +814,7 @@
 static int do_write(const std::vector<std::string>& args) {
     const char* path = args[1].c_str();
     const char* value = args[2].c_str();
-    return write_file(path, value);
+    return write_file(path, value) ? 0 : 1;
 }
 
 static int do_copy(const std::vector<std::string>& args) {
diff --git a/init/init.cpp b/init/init.cpp
index 60eac48..ee5add8 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -542,7 +542,7 @@
             }
         }
 
-        if (write_file("/sys/fs/selinux/checkreqprot", "0") == -1) {
+        if (!write_file("/sys/fs/selinux/checkreqprot", "0")) {
             security_failure();
         }
 
diff --git a/init/log.cpp b/init/log.cpp
index 8618340..6b32526 100644
--- a/init/log.cpp
+++ b/init/log.cpp
@@ -19,6 +19,8 @@
 #include <fcntl.h>
 #include <string.h>
 
+#include <linux/audit.h>
+#include <netlink/netlink.h>
 #include <selinux/selinux.h>
 
 void InitKernelLogging(char* argv[]) {
@@ -38,6 +40,24 @@
     android::base::InitLogging(argv, &android::base::KernelLogger);
 }
 
+static void selinux_avc_log(char* buf, size_t buf_len) {
+    size_t str_len = strnlen(buf, buf_len);
+
+    // trim newline at end of string
+    buf[str_len - 1] = '\0';
+
+    struct nl_sock* sk = nl_socket_alloc();
+    if (sk == NULL) {
+        return;
+    }
+    nl_connect(sk, NETLINK_AUDIT);
+    int result;
+    do {
+        result = nl_send_simple(sk, AUDIT_USER_AVC, 0, buf, str_len);
+    } while (result == -NLE_INTR);
+    nl_socket_free(sk);
+}
+
 int selinux_klog_callback(int type, const char *fmt, ...) {
     android::base::LogSeverity severity = android::base::ERROR;
     if (type == SELINUX_WARNING) {
@@ -48,8 +68,15 @@
     char buf[1024];
     va_list ap;
     va_start(ap, fmt);
-    vsnprintf(buf, sizeof(buf), fmt, ap);
+    int res = vsnprintf(buf, sizeof(buf), fmt, ap);
     va_end(ap);
-    android::base::KernelLogger(android::base::MAIN, severity, "selinux", nullptr, 0, buf);
+    if (res <= 0) {
+        return 0;
+    }
+    if (type == SELINUX_AVC) {
+        selinux_avc_log(buf, sizeof(buf));
+    } else {
+        android::base::KernelLogger(android::base::MAIN, severity, "selinux", nullptr, 0, buf);
+    }
     return 0;
 }
diff --git a/init/util.cpp b/init/util.cpp
index a79a419..888a366 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -185,18 +185,18 @@
     return okay;
 }
 
-int write_file(const char* path, const char* content) {
+bool write_file(const char* path, const char* content) {
     int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY|O_CREAT|O_NOFOLLOW|O_CLOEXEC, 0600));
     if (fd == -1) {
         PLOG(ERROR) << "write_file: Unable to open '" << path << "'";
-        return -1;
+        return false;
     }
-    int result = android::base::WriteStringToFd(content, fd) ? 0 : -1;
-    if (result == -1) {
+    bool success = android::base::WriteStringToFd(content, fd);
+    if (!success) {
         PLOG(ERROR) << "write_file: Unable to write to '" << path << "'";
     }
     close(fd);
-    return result;
+    return success;
 }
 
 boot_clock::time_point boot_clock::now() {
diff --git a/init/util.h b/init/util.h
index e63c469..009413d 100644
--- a/init/util.h
+++ b/init/util.h
@@ -33,7 +33,7 @@
                   uid_t uid, gid_t gid, const char *socketcon);
 
 bool read_file(const char* path, std::string* content);
-int write_file(const char* path, const char* content);
+bool write_file(const char* path, const char* content);
 
 // A std::chrono clock based on CLOCK_BOOTTIME.
 class boot_clock {
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index 684e611..5b31ecb 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -27,22 +27,8 @@
 
     include_dirs: ["external/libunwind/include/tdep"],
 
-    // TODO: LLVM_DEVICE_BUILD_MK
-    // TODO: LLVM_HOST_BUILD_MK
 
     target: {
-        host: {
-            // -fno-omit-frame-pointer should be set for host build. Because currently
-            // libunwind can't recognize .debug_frame using dwarf version 4, and it relies
-            // on stack frame pointer to do unwinding on x86.
-            // $(LLVM_HOST_BUILD_MK) overwrites -fno-omit-frame-pointer. so the below line
-            // must be after the include.
-            cflags: [
-                "-Wno-extern-c-compat",
-                "-fno-omit-frame-pointer",
-            ],
-        },
-
         darwin: {
             enabled: false,
         },
diff --git a/libcutils/properties.c b/libcutils/properties.c
index 5aa6371..740c7a9 100644
--- a/libcutils/properties.c
+++ b/libcutils/properties.c
@@ -36,7 +36,7 @@
     }
 
     int8_t result = default_value;
-    char buf[PROPERTY_VALUE_MAX] = {'\0',};
+    char buf[PROPERTY_VALUE_MAX] = {'\0'};
 
     int len = property_get(key, buf, "");
     if (len == 1) {
@@ -47,7 +47,7 @@
             result = true;
         }
     } else if (len > 1) {
-         if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
+        if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {
             result = false;
         } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {
             result = true;
@@ -59,13 +59,13 @@
 
 // Convert string property to int (default if fails); return default value if out of bounds
 static intmax_t property_get_imax(const char *key, intmax_t lower_bound, intmax_t upper_bound,
-        intmax_t default_value) {
+                                  intmax_t default_value) {
     if (!key) {
         return default_value;
     }
 
     intmax_t result = default_value;
-    char buf[PROPERTY_VALUE_MAX] = {'\0',};
+    char buf[PROPERTY_VALUE_MAX] = {'\0'};
     char *end = NULL;
 
     int len = property_get(key, buf, "");
@@ -74,7 +74,7 @@
         errno = 0;
 
         // Infer base automatically
-        result = strtoimax(buf, &end, /*base*/0);
+        result = strtoimax(buf, &end, /*base*/ 0);
         if ((result == INTMAX_MIN || result == INTMAX_MAX) && errno == ERANGE) {
             // Over or underflow
             result = default_value;
@@ -86,8 +86,8 @@
         } else if (end == buf) {
             // Numeric conversion failed
             result = default_value;
-            ALOGV("%s(%s,%" PRIdMAX ") - numeric conversion failed",
-                    __FUNCTION__, key, default_value);
+            ALOGV("%s(%s,%" PRIdMAX ") - numeric conversion failed", __FUNCTION__, key,
+                  default_value);
         }
 
         errno = tmp;
@@ -107,38 +107,31 @@
 #define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
 #include <sys/_system_properties.h>
 
-int property_set(const char *key, const char *value)
-{
+int property_set(const char *key, const char *value) {
     return __system_property_set(key, value);
 }
 
-int property_get(const char *key, char *value, const char *default_value)
-{
+int property_get(const char *key, char *value, const char *default_value) {
     int len;
 
     len = __system_property_get(key, value);
-    if(len > 0) {
+    if (len > 0) {
         return len;
     }
-    if(default_value) {
-        len = strlen(default_value);
-        if (len >= PROPERTY_VALUE_MAX) {
-            len = PROPERTY_VALUE_MAX - 1;
-        }
+    if (default_value) {
+        len = strnlen(default_value, PROPERTY_VALUE_MAX - 1);
         memcpy(value, default_value, len);
         value[len] = '\0';
     }
     return len;
 }
 
-struct property_list_callback_data
-{
+struct property_list_callback_data {
     void (*propfn)(const char *key, const char *value, void *cookie);
     void *cookie;
 };
 
-static void property_list_callback(const prop_info *pi, void *cookie)
-{
+static void property_list_callback(const prop_info *pi, void *cookie) {
     char name[PROP_NAME_MAX];
     char value[PROP_VALUE_MAX];
     struct property_list_callback_data *data = cookie;
@@ -147,10 +140,7 @@
     data->propfn(name, value, data->cookie);
 }
 
-int property_list(
-        void (*propfn)(const char *key, const char *value, void *cookie),
-        void *cookie)
-{
-    struct property_list_callback_data data = { propfn, cookie };
+int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie) {
+    struct property_list_callback_data data = {propfn, cookie};
     return __system_property_foreach(property_list_callback, &data);
 }
diff --git a/libcutils/tests/PropertiesTest.cpp b/libcutils/tests/PropertiesTest.cpp
index f0cdffd..7921972 100644
--- a/libcutils/tests/PropertiesTest.cpp
+++ b/libcutils/tests/PropertiesTest.cpp
@@ -159,19 +159,68 @@
 
 TEST_F(PropertiesTest, GetString) {
 
-    // Try to use a default value that's too long => set fails
+    // Try to use a default value that's too long => get truncates the value
     {
         ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
 
-        std::string maxLengthString = std::string(PROPERTY_VALUE_MAX-1, 'a');
+        std::string maxLengthString = std::string(PROPERTY_VALUE_MAX - 1, 'a');
         std::string oneLongerString = std::string(PROPERTY_VALUE_MAX, 'a');
 
         // Expect that the value is truncated since it's too long (by 1)
         int len = property_get(PROPERTY_TEST_KEY, mValue, oneLongerString.c_str());
-        EXPECT_EQ(PROPERTY_VALUE_MAX-1, len);
+        EXPECT_EQ(PROPERTY_VALUE_MAX - 1, len);
         EXPECT_STREQ(maxLengthString.c_str(), mValue);
         ResetValue();
     }
+
+    // Try to use a default value that's the max length => get succeeds
+    {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
+
+        std::string maxLengthString = std::string(PROPERTY_VALUE_MAX - 1, 'b');
+
+        // Expect that the value matches maxLengthString
+        int len = property_get(PROPERTY_TEST_KEY, mValue, maxLengthString.c_str());
+        EXPECT_EQ(PROPERTY_VALUE_MAX - 1, len);
+        EXPECT_STREQ(maxLengthString.c_str(), mValue);
+        ResetValue();
+    }
+
+    // Try to use a default value of length one => get succeeds
+    {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
+
+        std::string oneCharString = std::string(1, 'c');
+
+        // Expect that the value matches oneCharString
+        int len = property_get(PROPERTY_TEST_KEY, mValue, oneCharString.c_str());
+        EXPECT_EQ(1, len);
+        EXPECT_STREQ(oneCharString.c_str(), mValue);
+        ResetValue();
+    }
+
+    // Try to use a default value of length zero => get succeeds
+    {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
+
+        std::string zeroCharString = std::string(0, 'd');
+
+        // Expect that the value matches oneCharString
+        int len = property_get(PROPERTY_TEST_KEY, mValue, zeroCharString.c_str());
+        EXPECT_EQ(0, len);
+        EXPECT_STREQ(zeroCharString.c_str(), mValue);
+        ResetValue();
+    }
+
+    // Try to use a NULL default value => get returns 0
+    {
+        ASSERT_OK(property_set(PROPERTY_TEST_KEY, ""));
+
+        // Expect a return value of 0
+        int len = property_get(PROPERTY_TEST_KEY, mValue, NULL);
+        EXPECT_EQ(0, len);
+        ResetValue();
+    }
 }
 
 TEST_F(PropertiesTest, GetBool) {
diff --git a/liblog/Android.bp b/liblog/Android.bp
index 2424dba..be47fc3 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -21,6 +21,7 @@
     "config_write.c",
     "logger_name.c",
     "logger_lock.c",
+    "log_ratelimit.cpp",
 ]
 liblog_host_sources = [
     "fake_log_device.c",
diff --git a/liblog/log_ratelimit.cpp b/liblog/log_ratelimit.cpp
new file mode 100644
index 0000000..dfd4b8f
--- /dev/null
+++ b/liblog/log_ratelimit.cpp
@@ -0,0 +1,86 @@
+/*
+** Copyright 2016, 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 <errno.h>
+#include <pthread.h>
+#include <time.h>
+
+#include <log/log.h>
+
+#include "log_portability.h"
+
+// Global default if 'last' argument in __android_log_ratelimit is NULL
+static time_t g_last_clock;
+// Global above can not deal well with callers playing games with the
+// seconds argument, so we will also hold on to the maximum value
+// ever provided and use that to gain consistency.  If the caller
+// provides their own 'last' argument, then they can play such games
+// of varying the 'seconds' argument to their pleasure.
+static time_t g_last_seconds;
+static const time_t last_seconds_default = 10;
+static const time_t last_seconds_max = 24 * 60 * 60; // maximum of a day
+static const time_t last_seconds_min = 2; // granularity
+// Lock to protect last_clock and last_seconds, but also 'last'
+// argument (not NULL) as supplied to __android_log_ratelimit.
+static pthread_mutex_t lock_ratelimit = PTHREAD_MUTEX_INITIALIZER;
+
+// if last is NULL, caller _must_ provide a consistent value for
+// seconds, otherwise we will take the maximum ever issued and hold
+// on to that.  Preserves value of non-zero errno.  Return -1 if we
+// can not acquire a lock, 0 if we are not to log a message, and 1
+// if we are ok to log a message.  Caller should check > 0 for true.
+LIBLOG_ABI_PUBLIC int __android_log_ratelimit(time_t seconds, time_t* last) {
+    int save_errno = errno;
+
+    // Two reasons for trylock failure:
+    //   1. In a signal handler. Must prevent deadlock
+    //   2. Too many threads calling __android_log_ratelimit.
+    //      Bonus to not print if they race here because that
+    //      dovetails the goal of ratelimiting. One may print
+    //      and the others will wait their turn ...
+    if (pthread_mutex_trylock(&lock_ratelimit)) {
+        if (save_errno) errno = save_errno;
+        return -1;
+    }
+
+    if (seconds == 0) {
+        seconds = last_seconds_default;
+    } else if (seconds < last_seconds_min) {
+        seconds = last_seconds_min;
+    } else if (seconds > last_seconds_max) {
+        seconds = last_seconds_max;
+    }
+
+    if (!last) {
+        if (g_last_seconds > seconds) {
+            seconds = g_last_seconds;
+        } else if (g_last_seconds < seconds) {
+            g_last_seconds = seconds;
+        }
+        last = &g_last_clock;
+    }
+
+    time_t now = time(NULL);
+    if ((now == (time_t)-1) || ((*last + seconds) > now)) {
+        pthread_mutex_unlock(&lock_ratelimit);
+        if (save_errno) errno = save_errno;
+        return 0;
+    }
+    *last = now;
+    pthread_mutex_unlock(&lock_ratelimit);
+    if (save_errno) errno = save_errno;
+    return 1;
+}
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index d07d774..371e6ca 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -214,6 +214,8 @@
     }
     return false;
 }
+
+bool tested__android_log_close;
 #endif
 
 TEST(liblog, __android_log_btwrite__android_logger_list_read) {
@@ -228,22 +230,33 @@
     // Check that we can close and reopen the logger
     log_time ts(CLOCK_MONOTONIC);
     ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts)));
-    bool pmsgActiveAfter__android_log_btwrite = isPmsgActive();
-    bool logdwActiveAfter__android_log_btwrite = isLogdwActive();
-    EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
-    EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
+    bool pmsgActiveAfter__android_log_btwrite;
+    bool logdwActiveAfter__android_log_btwrite;
+    if (getuid() == AID_ROOT) {
+        tested__android_log_close = true;
+        pmsgActiveAfter__android_log_btwrite = isPmsgActive();
+        logdwActiveAfter__android_log_btwrite = isLogdwActive();
+        EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
+        EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
+    } else if (!tested__android_log_close) {
+        fprintf(stderr, "WARNING: can not test __android_log_close()\n");
+    }
     __android_log_close();
-    bool pmsgActiveAfter__android_log_close = isPmsgActive();
-    bool logdwActiveAfter__android_log_close = isLogdwActive();
-    EXPECT_FALSE(pmsgActiveAfter__android_log_close);
-    EXPECT_FALSE(logdwActiveAfter__android_log_close);
+    if (getuid() == AID_ROOT) {
+        bool pmsgActiveAfter__android_log_close = isPmsgActive();
+        bool logdwActiveAfter__android_log_close = isLogdwActive();
+        EXPECT_FALSE(pmsgActiveAfter__android_log_close);
+        EXPECT_FALSE(logdwActiveAfter__android_log_close);
+    }
 
     log_time ts1(CLOCK_MONOTONIC);
     ASSERT_LT(0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1)));
-    pmsgActiveAfter__android_log_btwrite = isPmsgActive();
-    logdwActiveAfter__android_log_btwrite = isLogdwActive();
-    EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
-    EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
+    if (getuid() == AID_ROOT) {
+        pmsgActiveAfter__android_log_btwrite = isPmsgActive();
+        logdwActiveAfter__android_log_btwrite = isLogdwActive();
+        EXPECT_TRUE(pmsgActiveAfter__android_log_btwrite);
+        EXPECT_TRUE(logdwActiveAfter__android_log_btwrite);
+    }
     usleep(1000000);
 
     int count = 0;
@@ -539,7 +552,6 @@
     bool set_persist = false;
     bool allow_security = false;
 
-    setuid(AID_SYSTEM); // only one that can read security buffer
     if (__android_log_security()) {
         allow_security = true;
     } else {
@@ -612,6 +624,8 @@
         return;
     }
 
+    setuid(AID_SYSTEM); // only one that can read security buffer
+
     pid_t pid = getpid();
 
     ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
@@ -2662,10 +2676,15 @@
 TEST(liblog, __android_log_pmsg_file_write) {
 #ifdef __ANDROID__
     __android_log_close();
-    bool pmsgActiveAfter__android_log_close = isPmsgActive();
-    bool logdwActiveAfter__android_log_close = isLogdwActive();
-    EXPECT_FALSE(pmsgActiveAfter__android_log_close);
-    EXPECT_FALSE(logdwActiveAfter__android_log_close);
+    if (getuid() == AID_ROOT) {
+        tested__android_log_close = true;
+        bool pmsgActiveAfter__android_log_close = isPmsgActive();
+        bool logdwActiveAfter__android_log_close = isLogdwActive();
+        EXPECT_FALSE(pmsgActiveAfter__android_log_close);
+        EXPECT_FALSE(logdwActiveAfter__android_log_close);
+    } else if (!tested__android_log_close) {
+        fprintf(stderr, "WARNING: can not test __android_log_close()\n");
+    }
     int return__android_log_pmsg_file_write = __android_log_pmsg_file_write(
             LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
             __pmsg_file, max_payload_buf, sizeof(max_payload_buf));
@@ -2679,24 +2698,32 @@
                         "with liblog.__android_log_msg_file_read test\n",
                         __pmsg_file);
     }
-    bool pmsgActiveAfter__android_pmsg_file_write = isPmsgActive();
-    bool logdwActiveAfter__android_pmsg_file_write = isLogdwActive();
-    EXPECT_FALSE(pmsgActiveAfter__android_pmsg_file_write);
-    EXPECT_FALSE(logdwActiveAfter__android_pmsg_file_write);
+    bool pmsgActiveAfter__android_pmsg_file_write;
+    bool logdwActiveAfter__android_pmsg_file_write;
+    if (getuid() == AID_ROOT) {
+        pmsgActiveAfter__android_pmsg_file_write = isPmsgActive();
+        logdwActiveAfter__android_pmsg_file_write = isLogdwActive();
+        EXPECT_FALSE(pmsgActiveAfter__android_pmsg_file_write);
+        EXPECT_FALSE(logdwActiveAfter__android_pmsg_file_write);
+    }
     EXPECT_LT(0, __android_log_buf_print(LOG_ID_MAIN, ANDROID_LOG_INFO,
                                          "TEST__android_log_pmsg_file_write",
                                          "main"));
-    bool pmsgActiveAfter__android_log_buf_print = isPmsgActive();
-    bool logdwActiveAfter__android_log_buf_print = isLogdwActive();
-    EXPECT_TRUE(pmsgActiveAfter__android_log_buf_print);
-    EXPECT_TRUE(logdwActiveAfter__android_log_buf_print);
+    if (getuid() == AID_ROOT) {
+        bool pmsgActiveAfter__android_log_buf_print = isPmsgActive();
+        bool logdwActiveAfter__android_log_buf_print = isLogdwActive();
+        EXPECT_TRUE(pmsgActiveAfter__android_log_buf_print);
+        EXPECT_TRUE(logdwActiveAfter__android_log_buf_print);
+    }
     EXPECT_LT(0, __android_log_pmsg_file_write(
             LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
             __pmsg_file, max_payload_buf, sizeof(max_payload_buf)));
-    pmsgActiveAfter__android_pmsg_file_write = isPmsgActive();
-    logdwActiveAfter__android_pmsg_file_write = isLogdwActive();
-    EXPECT_TRUE(pmsgActiveAfter__android_pmsg_file_write);
-    EXPECT_TRUE(logdwActiveAfter__android_pmsg_file_write);
+    if (getuid() == AID_ROOT) {
+        pmsgActiveAfter__android_pmsg_file_write = isPmsgActive();
+        logdwActiveAfter__android_pmsg_file_write = isLogdwActive();
+        EXPECT_TRUE(pmsgActiveAfter__android_pmsg_file_write);
+        EXPECT_TRUE(logdwActiveAfter__android_pmsg_file_write);
+    }
 #else
     GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
@@ -2731,19 +2758,26 @@
     signaled = 0;
 
     __android_log_close();
-    bool pmsgActiveAfter__android_log_close = isPmsgActive();
-    bool logdwActiveAfter__android_log_close = isLogdwActive();
-    EXPECT_FALSE(pmsgActiveAfter__android_log_close);
-    EXPECT_FALSE(logdwActiveAfter__android_log_close);
+    if (getuid() == AID_ROOT) {
+        tested__android_log_close = true;
+        bool pmsgActiveAfter__android_log_close = isPmsgActive();
+        bool logdwActiveAfter__android_log_close = isLogdwActive();
+        EXPECT_FALSE(pmsgActiveAfter__android_log_close);
+        EXPECT_FALSE(logdwActiveAfter__android_log_close);
+    } else if (!tested__android_log_close) {
+        fprintf(stderr, "WARNING: can not test __android_log_close()\n");
+    }
 
     ssize_t ret = __android_log_pmsg_file_read(
             LOG_ID_CRASH, ANDROID_LOG_VERBOSE,
             __pmsg_file, __pmsg_fn, NULL);
 
-    bool pmsgActiveAfter__android_log_pmsg_file_read = isPmsgActive();
-    bool logdwActiveAfter__android_log_pmsg_file_read = isLogdwActive();
-    EXPECT_FALSE(pmsgActiveAfter__android_log_pmsg_file_read);
-    EXPECT_FALSE(logdwActiveAfter__android_log_pmsg_file_read);
+    if (getuid() == AID_ROOT) {
+        bool pmsgActiveAfter__android_log_pmsg_file_read = isPmsgActive();
+        bool logdwActiveAfter__android_log_pmsg_file_read = isLogdwActive();
+        EXPECT_FALSE(pmsgActiveAfter__android_log_pmsg_file_read);
+        EXPECT_FALSE(logdwActiveAfter__android_log_pmsg_file_read);
+    }
 
     if (ret == -ENOENT) {
         fprintf(stderr,
@@ -2870,3 +2904,35 @@
     GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
 }
+
+TEST(liblog, __android_log_ratelimit) {
+    time_t state = 0;
+
+    errno = 42;
+    // Prime
+    __android_log_ratelimit(3, &state);
+    EXPECT_EQ(errno, 42);
+    // Check
+    EXPECT_FALSE(__android_log_ratelimit(3, &state));
+    sleep(1);
+    EXPECT_FALSE(__android_log_ratelimit(3, &state));
+    sleep(4);
+    EXPECT_TRUE(__android_log_ratelimit(3, &state));
+    sleep(5);
+    EXPECT_TRUE(__android_log_ratelimit(3, &state));
+
+    // API checks
+    IF_ALOG_RATELIMIT_LOCAL(3, &state) {
+        EXPECT_FALSE(0 != "IF_ALOG_RATELIMIT_LOCAL(3, &state)");
+    }
+
+    IF_ALOG_RATELIMIT() {
+        ;
+    } else {
+        EXPECT_TRUE(0 == "IF_ALOG_RATELIMIT()");
+    }
+    IF_ALOG_RATELIMIT() {
+        EXPECT_FALSE(0 != "IF_ALOG_RATELIMIT()");
+    }
+    // Do not test default seconds, to allow liblog to tune freely
+}
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index fce1378..1495f39 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -20,6 +20,7 @@
         "-DZLIB_CONST",
         "-Werror",
         "-Wall",
+        "-D_FILE_OFFSET_BITS=64",
     ],
     cppflags: [
         "-Wold-style-cast",
diff --git a/logcat/tests/logcat_test.cpp b/logcat/tests/logcat_test.cpp
index 11cffe6..725d76e 100644
--- a/logcat/tests/logcat_test.cpp
+++ b/logcat/tests/logcat_test.cpp
@@ -451,11 +451,12 @@
       "logcat -v brief -b radio,events,bogo,system,main -g 2>/dev/null"));
 }
 
-static void caught_blocking(int /*signum*/)
+static void caught_blocking(int signum)
 {
     unsigned long long v = 0xDEADBEEFA55A0000ULL;
 
     v += getpid() & 0xFFFF;
+    if (signum == 0) ++v;
 
     LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
 }
@@ -520,11 +521,12 @@
     EXPECT_EQ(1, signals);
 }
 
-static void caught_blocking_tail(int /*signum*/)
+static void caught_blocking_tail(int signum)
 {
     unsigned long long v = 0xA55ADEADBEEF0000ULL;
 
     v += getpid() & 0xFFFF;
+    if (signum == 0) ++v;
 
     LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
 }
@@ -955,10 +957,11 @@
                      " -n 256 -r 1024"));
 }
 
-static void caught_blocking_clear(int /*signum*/) {
+static void caught_blocking_clear(int signum) {
     unsigned long long v = 0xDEADBEEFA55C0000ULL;
 
     v += getpid() & 0xFFFF;
+    if (signum == 0) ++v;
 
     LOG_FAILURE_RETRY(__android_log_btwrite(0, EVENT_TYPE_LONG, &v, sizeof(v)));
 }
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index aa05932..11ffcb7 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -47,6 +47,10 @@
         logbuf(buf),
         reader(reader),
         fdDmesg(fdDmesg),
+        main(__android_logger_property_get_bool("ro.logd.auditd.main",
+                                                BOOL_DEFAULT_TRUE)),
+        events(__android_logger_property_get_bool("ro.logd.auditd.events",
+                                                  BOOL_DEFAULT_TRUE)),
         initialized(false) {
     static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO),
         'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':',
@@ -94,6 +98,13 @@
     }
 
     char *cp;
+    // Work around kernels missing
+    // https://github.com/torvalds/linux/commit/b8f89caafeb55fba75b74bea25adc4e4cd91be67
+    // Such kernels improperly add newlines inside audit messages.
+    while ((cp = strchr(str, '\n'))) {
+        *cp = ' ';
+    }
+
     while ((cp = strstr(str, "  "))) {
         memmove(cp, cp + 1, strlen(cp + 1) + 1);
     }
@@ -172,6 +183,11 @@
         }
     }
 
+    if (!main && !events) {
+        free(str);
+        return 0;
+    }
+
     pid_t pid = getpid();
     pid_t tid = gettid();
     uid_t uid = AID_LOGD;
@@ -222,7 +238,7 @@
 
     bool notify = false;
 
-    {   // begin scope for event buffer
+    if (events) {   // begin scope for event buffer
         uint32_t buffer[(n + sizeof(uint32_t) - 1) / sizeof(uint32_t)];
 
         android_log_event_string_t *event
@@ -277,7 +293,7 @@
     size_t e = strnlen(ecomm, LOGGER_ENTRY_MAX_PAYLOAD - b);
     n = b + e + l + 2;
 
-    {   // begin scope for main buffer
+    if (main) {   // begin scope for main buffer
         char newstr[n];
 
         *newstr = info ? ANDROID_LOG_INFO : ANDROID_LOG_WARN;
diff --git a/logd/LogAudit.h b/logd/LogAudit.h
index ab30e28..844951d 100644
--- a/logd/LogAudit.h
+++ b/logd/LogAudit.h
@@ -26,7 +26,9 @@
 class LogAudit : public SocketListener {
     LogBuffer *logbuf;
     LogReader *reader;
-    int fdDmesg;
+    int fdDmesg; // fdDmesg >= 0 is functionally bool dmesg
+    bool main;
+    bool events;
     bool initialized;
 
 public:
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp
index a5d435f..cc65d47 100644
--- a/logd/LogBuffer.cpp
+++ b/logd/LogBuffer.cpp
@@ -534,10 +534,9 @@
 class LogBufferElementKey {
     const union {
         struct {
-            uint16_t uid;
+            uint32_t uid;
             uint16_t pid;
             uint16_t tid;
-            uint16_t padding;
         } __packed;
         uint64_t value;
     } __packed;
@@ -546,8 +545,8 @@
     LogBufferElementKey(uid_t uid, pid_t pid, pid_t tid):
             uid(uid),
             pid(pid),
-            tid(tid),
-            padding(0) {
+            tid(tid)
+    {
     }
     explicit LogBufferElementKey(uint64_t key):value(key) { }
 
diff --git a/logd/README.property b/logd/README.property
index 791b1d5..de6767a 100644
--- a/logd/README.property
+++ b/logd/README.property
@@ -2,8 +2,9 @@
 
 name                       type default  description
 ro.logd.auditd             bool   true   Enable selinux audit daemon
-ro.logd.auditd.dmesg       bool   true   selinux audit messages duplicated and
-                                         sent on to dmesg log
+ro.logd.auditd.dmesg       bool   true   selinux audit messages sent to dmesg.
+ro.logd.auditd.main        bool   true   selinux audit messages sent to main.
+ro.logd.auditd.events      bool   true   selinux audit messages sent to events.
 persist.logd.security      bool   false  Enable security buffer.
 ro.device_owner            bool   false  Override persist.logd.security to false
 ro.logd.kernel             bool+ svelte+ Enable klogd daemon
diff --git a/logd/main.cpp b/logd/main.cpp
index c3343d7..5878f15 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -451,9 +451,8 @@
         pthread_attr_destroy(&attr);
     }
 
-    bool auditd = __android_logger_property_get_bool("logd.auditd",
-                                                     BOOL_DEFAULT_TRUE |
-                                                     BOOL_DEFAULT_FLAG_PERSIST);
+    bool auditd = __android_logger_property_get_bool("ro.logd.auditd",
+                                                     BOOL_DEFAULT_TRUE);
     if (drop_privs(klogd, auditd) != 0) {
         return -1;
     }
@@ -513,8 +512,8 @@
     if (auditd) {
         al = new LogAudit(logBuf, reader,
                           __android_logger_property_get_bool(
-                              "logd.auditd.dmesg",
-                              BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST)
+                              "ro.logd.auditd.dmesg",
+                              BOOL_DEFAULT_TRUE)
                                   ? fdDmesg
                                   : -1);
     }
diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp
index 4e621e3..5cd9fc8 100644
--- a/logd/tests/logd_test.cpp
+++ b/logd/tests/logd_test.cpp
@@ -415,7 +415,13 @@
 
     // Introduce some extreme spam for the worst UID filter
     ASSERT_TRUE(NULL != (fp = popen(
-        "/data/nativetest/liblog-benchmarks/liblog-benchmarks",
+        "/data/nativetest/liblog-benchmarks/liblog-benchmarks"
+            " BM_log_maximum_retry"
+            " BM_log_maximum"
+            " BM_clock_overhead"
+            " BM_log_overhead"
+            " BM_log_latency"
+            " BM_log_delay",
         "r")));
 
     char buffer[5120];
@@ -581,10 +587,12 @@
             continue;
         }
 
+        // alarm triggers at 50% of the --wrap time out
         content_wrap = recv(fd, msg_wrap.buf, sizeof(msg_wrap), 0) > 0;
 
         alarm_wrap = alarm(5);
 
+        // alarm triggers at 133% of the --wrap time out
         content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
         if (!content_timeout) { // make sure we hit dumpAndClose
             content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
@@ -629,11 +637,24 @@
 
 // b/26447386 refined behavior
 TEST(logd, timeout) {
+    // b/33962045 This test interferes with other log reader tests that
+    // follow because of file descriptor socket persistence in the same
+    // process.  So let's fork it to isolate it from giving us pain.
+
+    pid_t pid = fork();
+
+    if (pid) {
+        siginfo_t info = {};
+        ASSERT_EQ(0, TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED)));
+        ASSERT_EQ(0, info.si_status);
+        return;
+    }
+
     log_msg msg_wrap, msg_timeout;
     bool content_wrap = false, content_timeout = false, written = false;
     unsigned int alarm_wrap = 0, alarm_timeout = 0;
     // A few tries to get it right just in case wrap kicks in due to
-    // content providers being active during the test
+    // content providers being active during the test.
     int i = 5;
     log_time now(android_log_clockid());
     now.tv_sec -= 30; // reach back a moderate period of time
@@ -642,7 +663,8 @@
         int fd = socket_local_client("logdr",
                                      ANDROID_SOCKET_NAMESPACE_RESERVED,
                                      SOCK_SEQPACKET);
-        ASSERT_LT(0, fd);
+        EXPECT_LT(0, fd);
+        if (fd < 0) _exit(fd);
 
         std::string ask = android::base::StringPrintf(
             "dumpAndClose lids=0,1,2,3,4,5 timeout=6 start=%"
@@ -665,10 +687,12 @@
             continue;
         }
 
+        // alarm triggers at 50% of the --wrap time out
         content_wrap = recv(fd, msg_wrap.buf, sizeof(msg_wrap), 0) > 0;
 
         alarm_wrap = alarm(5);
 
+        // alarm triggers at 133% of the --wrap time out
         content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
         if (!content_timeout) { // make sure we hit dumpAndClose
             content_timeout = recv(fd, msg_timeout.buf, sizeof(msg_timeout), 0) > 0;
@@ -692,6 +716,7 @@
         if (content_timeout) {
             log_time msg(msg_timeout.entry.sec, msg_timeout.entry.nsec);
             EXPECT_FALSE(msg < now);
+            if (msg < now) _exit(-1);
             if (msg > now) {
                 now = msg;
                 now.tv_sec += 30;
@@ -724,6 +749,8 @@
     EXPECT_EQ(0U, alarm_wrap);
     EXPECT_TRUE(content_timeout);
     EXPECT_NE(0U, alarm_timeout);
+
+    _exit(!written + content_wrap + alarm_wrap + !content_timeout + !alarm_timeout);
 }
 
 // b/27242723 confirmed fixed
@@ -787,12 +814,11 @@
 void __android_log_btwrite_multiple__helper(int count) {
     log_time ts(CLOCK_MONOTONIC);
 
-    struct logger_list *logger_list;
-    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
-        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 1000, 0)));
-
     log_time ts1(CLOCK_MONOTONIC);
 
+    // We fork to create a unique pid for the submitted log messages
+    // so that we do not collide with the other _multiple_ tests.
+
     pid_t pid = fork();
 
     if (pid == 0) {
@@ -807,8 +833,13 @@
         _exit(0);
     }
 
-    siginfo_t info{};
+    siginfo_t info = {};
     ASSERT_EQ(0, TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED)));
+    ASSERT_EQ(0, info.si_status);
+
+    struct logger_list *logger_list;
+    ASSERT_TRUE(NULL != (logger_list = android_logger_list_open(
+        LOG_ID_EVENTS, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, pid)));
 
     int expected_count = (count < 2) ? count : 2;
     int expected_chatty_count = (count <= 2) ? 0 : 1;
@@ -854,12 +885,12 @@
         }
     }
 
+    android_logger_list_close(logger_list);
+
     EXPECT_EQ(expected_count, count);
     EXPECT_EQ(1, second_count);
     EXPECT_EQ(expected_chatty_count, chatty_count);
     EXPECT_EQ(expected_expire_count, expire_count);
-
-    android_logger_list_close(logger_list);
 }
 
 TEST(logd, multiple_test_1) {