Merge "SnapshotManager::WaitForMerge gives more info"
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 83b9238..a6d7e31 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -1125,8 +1125,8 @@
         return false;
     }
 
+    fwrite(buf, 1, sizeof(buf) - bytes_left, stdout);
     fflush(stdout);
-    WriteFdExactly(STDOUT_FILENO, buf, sizeof(buf) - bytes_left);
     if (cur != buf && strstr(buf, "restarting") == nullptr) {
         return true;
     }
diff --git a/base/Android.bp b/base/Android.bp
index 8351461..b25d0df 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -56,6 +56,7 @@
         "chrono_utils.cpp",
         "cmsg.cpp",
         "file.cpp",
+        "liblog_symbols.cpp",
         "logging.cpp",
         "mapped_file.cpp",
         "parsebool.cpp",
@@ -68,6 +69,10 @@
         "test_utils.cpp",
     ],
 
+    static: {
+        cflags: ["-DNO_LIBLOG_DLSYM"],
+    },
+
     cppflags: ["-Wexit-time-destructors"],
     shared_libs: ["liblog"],
     target: {
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index 3a9186a..7fd0182 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -85,7 +85,7 @@
   INFO,
   WARNING,
   ERROR,
-  FATAL_WITHOUT_ABORT,
+  FATAL_WITHOUT_ABORT,  // For loggability tests, this is considered identical to FATAL.
   FATAL,
 };
 
@@ -93,6 +93,8 @@
   DEFAULT,
   MAIN,
   SYSTEM,
+  RADIO,
+  CRASH,
 };
 
 using LogFunction = std::function<void(LogId, LogSeverity, const char*, const char*,
@@ -209,8 +211,8 @@
 #define ABORT_AFTER_LOG_FATAL_EXPR(x) ABORT_AFTER_LOG_EXPR_IF(true, x)
 
 // Defines whether the given severity will be logged or silently swallowed.
-#define WOULD_LOG(severity) \
-  (UNLIKELY((SEVERITY_LAMBDA(severity)) >= ::android::base::GetMinimumLogSeverity()) || \
+#define WOULD_LOG(severity)                                                              \
+  (UNLIKELY(::android::base::ShouldLog(SEVERITY_LAMBDA(severity), _LOG_TAG_INTERNAL)) || \
    MUST_LOG_MESSAGE(severity))
 
 // Get an ostream that can be used for logging at the given severity and to the default
@@ -442,6 +444,9 @@
 // Set the minimum severity level for logging, returning the old severity.
 LogSeverity SetMinimumLogSeverity(LogSeverity new_severity);
 
+// Return whether or not a log message with the associated tag should be logged.
+bool ShouldLog(LogSeverity severity, const char* tag);
+
 // Allows to temporarily change the minimum severity level for logging.
 class ScopedLogSeverity {
  public:
@@ -460,9 +465,6 @@
 // Emit a warning of ostream<< with std::string*. The intention was most likely to print *string.
 //
 // Note: for this to work, we need to have this in a namespace.
-// Note: lots of ifdef magic to make this work with Clang (platform) vs GCC (windows tools)
-// Note: using diagnose_if(true) under Clang and nothing under GCC/mingw as there is no common
-//       attribute support.
 // Note: using a pragma because "-Wgcc-compat" (included in "-Weverything") complains about
 //       diagnose_if.
 // Note: to print the pointer, use "<< static_cast<const void*>(string_pointer)" instead.
@@ -472,8 +474,8 @@
 #pragma clang diagnostic ignored "-Wgcc-compat"
 #define OSTREAM_STRING_POINTER_USAGE_WARNING \
     __attribute__((diagnose_if(true, "Unexpected logging of string pointer", "warning")))
-inline std::ostream& operator<<(std::ostream& stream, const std::string* string_pointer)
-    OSTREAM_STRING_POINTER_USAGE_WARNING {
+inline OSTREAM_STRING_POINTER_USAGE_WARNING
+std::ostream& operator<<(std::ostream& stream, const std::string* string_pointer) {
   return stream << static_cast<const void*>(string_pointer);
 }
 #pragma clang diagnostic pop
diff --git a/base/liblog_symbols.cpp b/base/liblog_symbols.cpp
new file mode 100644
index 0000000..d0e2eaa
--- /dev/null
+++ b/base/liblog_symbols.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 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 "liblog_symbols.h"
+
+#if defined(__ANDROID__) && !defined(NO_LIBLOG_DLSYM)
+#include <dlfcn.h>
+#endif
+
+namespace android {
+namespace base {
+
+#if defined(__ANDROID__) && !defined(NO_LIBLOG_DLSYM)
+
+const std::optional<LibLogFunctions>& GetLibLogFunctions() {
+  static std::optional<LibLogFunctions> liblog_functions = []() -> std::optional<LibLogFunctions> {
+    void* liblog_handle = dlopen("liblog.so", RTLD_NOW);
+    if (liblog_handle == nullptr) {
+      return {};
+    }
+
+    LibLogFunctions real_liblog_functions = {};
+
+#define DLSYM(name)                                                                   \
+  real_liblog_functions.name =                                                        \
+      reinterpret_cast<decltype(LibLogFunctions::name)>(dlsym(liblog_handle, #name)); \
+  if (real_liblog_functions.name == nullptr) {                                        \
+    return {};                                                                        \
+  }
+
+    DLSYM(__android_log_set_logger)
+    DLSYM(__android_log_write_logger_data)
+    DLSYM(__android_log_logd_logger)
+    DLSYM(__android_log_stderr_logger)
+    DLSYM(__android_log_set_aborter)
+    DLSYM(__android_log_call_aborter)
+    DLSYM(__android_log_default_aborter)
+    DLSYM(__android_log_set_minimum_priority);
+    DLSYM(__android_log_get_minimum_priority);
+#undef DLSYM
+
+    return real_liblog_functions;
+  }();
+
+  return liblog_functions;
+}
+
+#else
+
+const std::optional<LibLogFunctions>& GetLibLogFunctions() {
+  static std::optional<LibLogFunctions> liblog_functions = []() -> std::optional<LibLogFunctions> {
+    return LibLogFunctions{
+        .__android_log_set_logger = __android_log_set_logger,
+        .__android_log_write_logger_data = __android_log_write_logger_data,
+        .__android_log_logd_logger = __android_log_logd_logger,
+        .__android_log_stderr_logger = __android_log_stderr_logger,
+        .__android_log_set_aborter = __android_log_set_aborter,
+        .__android_log_call_aborter = __android_log_call_aborter,
+        .__android_log_default_aborter = __android_log_default_aborter,
+        .__android_log_set_minimum_priority = __android_log_set_minimum_priority,
+        .__android_log_get_minimum_priority = __android_log_get_minimum_priority,
+    };
+  }();
+  return liblog_functions;
+}
+
+#endif
+
+}  // namespace base
+}  // namespace android
diff --git a/base/liblog_symbols.h b/base/liblog_symbols.h
new file mode 100644
index 0000000..c68fff6
--- /dev/null
+++ b/base/liblog_symbols.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <optional>
+
+#include <android/log.h>
+
+namespace android {
+namespace base {
+
+struct LibLogFunctions {
+  void (*__android_log_set_logger)(__android_logger_function logger);
+  void (*__android_log_write_logger_data)(struct __android_logger_data* logger_data,
+                                          const char* msg);
+
+  void (*__android_log_logd_logger)(const struct __android_logger_data* logger_data,
+                                    const char* msg);
+  void (*__android_log_stderr_logger)(const struct __android_logger_data* logger_data,
+                                      const char* message);
+
+  void (*__android_log_set_aborter)(__android_aborter_function aborter);
+  void (*__android_log_call_aborter)(const char* abort_message);
+  void (*__android_log_default_aborter)(const char* abort_message);
+  int (*__android_log_set_minimum_priority)(int priority);
+  int (*__android_log_get_minimum_priority)();
+};
+
+const std::optional<LibLogFunctions>& GetLibLogFunctions();
+
+}  // namespace base
+}  // namespace android
diff --git a/base/logging.cpp b/base/logging.cpp
index b46abbf..508871d 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -36,15 +36,16 @@
 #include <sys/uio.h>
 #endif
 
+#include <atomic>
 #include <iostream>
 #include <limits>
 #include <mutex>
+#include <optional>
 #include <sstream>
 #include <string>
 #include <utility>
 #include <vector>
 
-// Headers for LogMessage::LogLine.
 #include <android/log.h>
 #ifdef __ANDROID__
 #include <android/set_abort_message.h>
@@ -59,6 +60,8 @@
 #include <android-base/strings.h>
 #include <android-base/threads.h>
 
+#include "liblog_symbols.h"
+
 namespace android {
 namespace base {
 
@@ -115,11 +118,84 @@
 }
 #endif
 
+static LogId log_id_tToLogId(int buffer_id) {
+  switch (buffer_id) {
+    case LOG_ID_MAIN:
+      return MAIN;
+    case LOG_ID_SYSTEM:
+      return SYSTEM;
+    case LOG_ID_RADIO:
+      return RADIO;
+    case LOG_ID_CRASH:
+      return CRASH;
+    case LOG_ID_DEFAULT:
+    default:
+      return DEFAULT;
+  }
+}
+
+static int LogIdTolog_id_t(LogId log_id) {
+  switch (log_id) {
+    case MAIN:
+      return LOG_ID_MAIN;
+    case SYSTEM:
+      return LOG_ID_SYSTEM;
+    case RADIO:
+      return LOG_ID_RADIO;
+    case CRASH:
+      return LOG_ID_CRASH;
+    case DEFAULT:
+    default:
+      return LOG_ID_DEFAULT;
+  }
+}
+
+static LogSeverity PriorityToLogSeverity(int priority) {
+  switch (priority) {
+    case ANDROID_LOG_DEFAULT:
+      return INFO;
+    case ANDROID_LOG_VERBOSE:
+      return VERBOSE;
+    case ANDROID_LOG_DEBUG:
+      return DEBUG;
+    case ANDROID_LOG_INFO:
+      return INFO;
+    case ANDROID_LOG_WARN:
+      return WARNING;
+    case ANDROID_LOG_ERROR:
+      return ERROR;
+    case ANDROID_LOG_FATAL:
+      return FATAL;
+    default:
+      return FATAL;
+  }
+}
+
+static android_LogPriority LogSeverityToPriority(LogSeverity severity) {
+  switch (severity) {
+    case VERBOSE:
+      return ANDROID_LOG_VERBOSE;
+    case DEBUG:
+      return ANDROID_LOG_DEBUG;
+    case INFO:
+      return ANDROID_LOG_INFO;
+    case WARNING:
+      return ANDROID_LOG_WARN;
+    case ERROR:
+      return ANDROID_LOG_ERROR;
+    case FATAL_WITHOUT_ABORT:
+    case FATAL:
+    default:
+      return ANDROID_LOG_FATAL;
+  }
+}
+
 static std::mutex& LoggingLock() {
   static auto& logging_lock = *new std::mutex();
   return logging_lock;
 }
 
+// Only used for Q fallback.
 static LogFunction& Logger() {
 #ifdef __ANDROID__
   static auto& logger = *new LogFunction(LogdLogger());
@@ -129,6 +205,7 @@
   return logger;
 }
 
+// Only used for Q fallback.
 static AbortFunction& Aborter() {
   static auto& aborter = *new AbortFunction(DefaultAborter);
   return aborter;
@@ -158,6 +235,8 @@
 }
 
 static bool gInitialized = false;
+
+// Only used for Q fallback.
 static LogSeverity gMinimumLogSeverity = INFO;
 
 #if defined(__linux__)
@@ -218,8 +297,13 @@
   static_assert(arraysize(log_characters) - 1 == FATAL + 1,
                 "Mismatch in size of log_characters and values in LogSeverity");
   char severity_char = log_characters[severity];
-  fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s:%u] %s\n", tag ? tag : "nullptr", severity_char,
-          timestamp, getpid(), GetThreadId(), file, line, message);
+  if (file != nullptr) {
+    fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s:%u] %s\n", tag ? tag : "nullptr", severity_char,
+            timestamp, getpid(), GetThreadId(), file, line, message);
+  } else {
+    fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s\n", tag ? tag : "nullptr", severity_char,
+            timestamp, getpid(), GetThreadId(), message);
+  }
 }
 
 void StdioLogger(LogId, LogSeverity severity, const char* /*tag*/, const char* /*file*/,
@@ -248,29 +332,25 @@
 void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag,
                             const char* file, unsigned int line,
                             const char* message) {
-  static constexpr android_LogPriority kLogSeverityToAndroidLogPriority[] = {
-      ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO,
-      ANDROID_LOG_WARN,    ANDROID_LOG_ERROR, ANDROID_LOG_FATAL,
-      ANDROID_LOG_FATAL,
-  };
-  static_assert(arraysize(kLogSeverityToAndroidLogPriority) == FATAL + 1,
-                "Mismatch in size of kLogSeverityToAndroidLogPriority and values in LogSeverity");
-
-  int priority = kLogSeverityToAndroidLogPriority[severity];
+  android_LogPriority priority = LogSeverityToPriority(severity);
   if (id == DEFAULT) {
     id = default_log_id_;
   }
 
-  static constexpr log_id kLogIdToAndroidLogId[] = {
-    LOG_ID_MAX, LOG_ID_MAIN, LOG_ID_SYSTEM,
-  };
-  static_assert(arraysize(kLogIdToAndroidLogId) == SYSTEM + 1,
-                "Mismatch in size of kLogIdToAndroidLogId and values in LogId");
-  log_id lg_id = kLogIdToAndroidLogId[id];
+  int lg_id = LogIdTolog_id_t(id);
 
-  if (priority == ANDROID_LOG_FATAL) {
-    __android_log_buf_print(lg_id, priority, tag, "%s:%u] %s", file, line,
-                            message);
+  char log_message[1024];
+  if (priority == ANDROID_LOG_FATAL && file != nullptr) {
+    snprintf(log_message, sizeof(log_message), "%s:%u] %s", file, line, message);
+  } else {
+    snprintf(log_message, sizeof(log_message), "%s", message);
+  }
+
+  static auto& liblog_functions = GetLibLogFunctions();
+  if (liblog_functions) {
+    __android_logger_data logger_data = {sizeof(__android_logger_data),     lg_id, priority, tag,
+                                         static_cast<const char*>(nullptr), 0};
+    liblog_functions->__android_log_logd_logger(&logger_data, log_message);
   } else {
     __android_log_buf_print(lg_id, priority, tag, "%s", message);
   }
@@ -305,27 +385,27 @@
     if (spec.size() == 3 && StartsWith(spec, "*:")) {
       switch (spec[2]) {
         case 'v':
-          gMinimumLogSeverity = VERBOSE;
+          SetMinimumLogSeverity(VERBOSE);
           continue;
         case 'd':
-          gMinimumLogSeverity = DEBUG;
+          SetMinimumLogSeverity(DEBUG);
           continue;
         case 'i':
-          gMinimumLogSeverity = INFO;
+          SetMinimumLogSeverity(INFO);
           continue;
         case 'w':
-          gMinimumLogSeverity = WARNING;
+          SetMinimumLogSeverity(WARNING);
           continue;
         case 'e':
-          gMinimumLogSeverity = ERROR;
+          SetMinimumLogSeverity(ERROR);
           continue;
         case 'f':
-          gMinimumLogSeverity = FATAL_WITHOUT_ABORT;
+          SetMinimumLogSeverity(FATAL_WITHOUT_ABORT);
           continue;
         // liblog will even suppress FATAL if you say 's' for silent, but that's
         // crazy!
         case 's':
-          gMinimumLogSeverity = FATAL_WITHOUT_ABORT;
+          SetMinimumLogSeverity(FATAL_WITHOUT_ABORT);
           continue;
       }
     }
@@ -335,13 +415,46 @@
 }
 
 void SetLogger(LogFunction&& logger) {
-  std::lock_guard<std::mutex> lock(LoggingLock());
-  Logger() = std::move(logger);
+  static auto& liblog_functions = GetLibLogFunctions();
+  if (liblog_functions) {
+    // We need to atomically swap the old and new pointers since other threads may be logging.
+    // We know all threads will be using the new logger after __android_log_set_logger() returns,
+    // so we can delete it then.
+    // This leaks one std::function<> per instance of libbase if multiple copies of libbase within a
+    // single process call SetLogger().  That is the same cost as having a static
+    // std::function<>, which is the not-thread-safe alternative.
+    static std::atomic<LogFunction*> logger_function(nullptr);
+    auto* old_logger_function = logger_function.exchange(new LogFunction(logger));
+    liblog_functions->__android_log_set_logger([](const struct __android_logger_data* logger_data,
+                                                  const char* message) {
+      auto log_id = log_id_tToLogId(logger_data->buffer_id);
+      auto severity = PriorityToLogSeverity(logger_data->priority);
+
+      auto& function = *logger_function.load(std::memory_order_acquire);
+      function(log_id, severity, logger_data->tag, logger_data->file, logger_data->line, message);
+    });
+    delete old_logger_function;
+  } else {
+    std::lock_guard<std::mutex> lock(LoggingLock());
+    Logger() = std::move(logger);
+  }
 }
 
 void SetAborter(AbortFunction&& aborter) {
-  std::lock_guard<std::mutex> lock(LoggingLock());
-  Aborter() = std::move(aborter);
+  static auto& liblog_functions = GetLibLogFunctions();
+  if (liblog_functions) {
+    // See the comment in SetLogger().
+    static std::atomic<AbortFunction*> abort_function(nullptr);
+    auto* old_abort_function = abort_function.exchange(new AbortFunction(aborter));
+    __android_log_set_aborter([](const char* abort_message) {
+      auto& function = *abort_function.load(std::memory_order_acquire);
+      function(abort_message);
+    });
+    delete old_abort_function;
+  } else {
+    std::lock_guard<std::mutex> lock(LoggingLock());
+    Aborter() = std::move(aborter);
+  }
 }
 
 // This indirection greatly reduces the stack impact of having lots of
@@ -444,7 +557,12 @@
 
   // Abort if necessary.
   if (data_->GetSeverity() == FATAL) {
-    Aborter()(msg.c_str());
+    static auto& liblog_functions = GetLibLogFunctions();
+    if (liblog_functions) {
+      liblog_functions->__android_log_call_aborter(msg.c_str());
+    } else {
+      Aborter()(msg.c_str());
+    }
   }
 }
 
@@ -454,25 +572,65 @@
 
 void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity severity, const char* tag,
                          const char* message) {
+  static auto& liblog_functions = GetLibLogFunctions();
+  auto priority = LogSeverityToPriority(severity);
   if (tag == nullptr) {
     std::lock_guard<std::recursive_mutex> lock(TagLock());
     if (gDefaultTag == nullptr) {
       gDefaultTag = new std::string(getprogname());
     }
-    Logger()(DEFAULT, severity, gDefaultTag->c_str(), file, line, message);
+
+    if (liblog_functions) {
+      __android_logger_data logger_data = {sizeof(__android_logger_data), LOG_ID_DEFAULT, priority,
+                                           gDefaultTag->c_str(),          file,           line};
+      __android_log_write_logger_data(&logger_data, message);
+    } else {
+      Logger()(DEFAULT, severity, gDefaultTag->c_str(), file, line, message);
+    }
   } else {
-    Logger()(DEFAULT, severity, tag, file, line, message);
+    if (liblog_functions) {
+      __android_logger_data logger_data = {
+          sizeof(__android_logger_data), LOG_ID_DEFAULT, priority, tag, file, line};
+      __android_log_write_logger_data(&logger_data, message);
+    } else {
+      Logger()(DEFAULT, severity, tag, file, line, message);
+    }
   }
 }
 
 LogSeverity GetMinimumLogSeverity() {
+  static auto& liblog_functions = GetLibLogFunctions();
+  if (liblog_functions) {
+    return PriorityToLogSeverity(liblog_functions->__android_log_get_minimum_priority());
+  } else {
     return gMinimumLogSeverity;
+  }
+}
+
+bool ShouldLog(LogSeverity severity, const char* tag) {
+  static auto& liblog_functions = GetLibLogFunctions();
+  // Even though we're not using the R liblog functions in this function, if we're running on Q,
+  // we need to fall back to using gMinimumLogSeverity, since __android_log_is_loggable() will not
+  // take into consideration the value from SetMinimumLogSeverity().
+  if (liblog_functions) {
+    // TODO: It is safe to pass nullptr for tag, but it will be better to use the default log tag.
+    int priority = LogSeverityToPriority(severity);
+    return __android_log_is_loggable(priority, tag, ANDROID_LOG_INFO);
+  } else {
+    return severity >= gMinimumLogSeverity;
+  }
 }
 
 LogSeverity SetMinimumLogSeverity(LogSeverity new_severity) {
-  LogSeverity old_severity = gMinimumLogSeverity;
-  gMinimumLogSeverity = new_severity;
-  return old_severity;
+  static auto& liblog_functions = GetLibLogFunctions();
+  if (liblog_functions) {
+    auto priority = LogSeverityToPriority(new_severity);
+    return PriorityToLogSeverity(liblog_functions->__android_log_set_minimum_priority(priority));
+  } else {
+    LogSeverity old_severity = gMinimumLogSeverity;
+    gMinimumLogSeverity = new_severity;
+    return old_severity;
+  }
 }
 
 ScopedLogSeverity::ScopedLogSeverity(LogSeverity new_severity) {
diff --git a/base/logging_test.cpp b/base/logging_test.cpp
index 3113fb4..8f46196 100644
--- a/base/logging_test.cpp
+++ b/base/logging_test.cpp
@@ -140,10 +140,6 @@
   CHECK_WOULD_LOG_ENABLED(FATAL);
 }
 
-TEST(logging, WOULD_LOG_FATAL_WITHOUT_ABORT_disabled) {
-  CHECK_WOULD_LOG_DISABLED(FATAL_WITHOUT_ABORT);
-}
-
 TEST(logging, WOULD_LOG_FATAL_WITHOUT_ABORT_enabled) {
   CHECK_WOULD_LOG_ENABLED(FATAL_WITHOUT_ABORT);
 }
@@ -266,10 +262,6 @@
     CheckMessage(cap2, android::base::severity, "foobar"); \
   } \
 
-TEST(logging, LOG_STREAM_FATAL_WITHOUT_ABORT_disabled) {
-  CHECK_LOG_STREAM_DISABLED(FATAL_WITHOUT_ABORT);
-}
-
 TEST(logging, LOG_STREAM_FATAL_WITHOUT_ABORT_enabled) {
   ASSERT_NO_FATAL_FAILURE(CHECK_LOG_STREAM_ENABLED(FATAL_WITHOUT_ABORT));
 }
@@ -352,10 +344,6 @@
   ASSERT_DEATH({SuppressAbortUI(); LOG(::android::base::FATAL) << "foobar";}, "foobar");
 }
 
-TEST(logging, LOG_FATAL_WITHOUT_ABORT_disabled) {
-  CHECK_LOG_DISABLED(FATAL_WITHOUT_ABORT);
-}
-
 TEST(logging, LOG_FATAL_WITHOUT_ABORT_enabled) {
   ASSERT_NO_FATAL_FAILURE(CHECK_LOG_ENABLED(FATAL_WITHOUT_ABORT));
 }
@@ -508,10 +496,6 @@
   ASSERT_DEATH({SuppressAbortUI(); PLOG(::android::base::FATAL) << "foobar";}, "foobar");
 }
 
-TEST(logging, PLOG_FATAL_WITHOUT_ABORT_disabled) {
-  CHECK_PLOG_DISABLED(FATAL_WITHOUT_ABORT);
-}
-
 TEST(logging, PLOG_FATAL_WITHOUT_ABORT_enabled) {
   ASSERT_NO_FATAL_FAILURE(CHECK_PLOG_ENABLED(FATAL_WITHOUT_ABORT));
 }
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 03c7943..ed82066 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -1092,7 +1092,9 @@
         return FS_MGR_MNTALL_FAIL;
     }
 
-    for (size_t i = 0; i < fstab->size(); i++) {
+    // Keep i int to prevent unsigned integer overflow from (i = top_idx - 1),
+    // where top_idx is 0. It will give SIGABRT
+    for (int i = 0; i < static_cast<int>(fstab->size()); i++) {
         auto& current_entry = (*fstab)[i];
 
         // If a filesystem should have been mounted in the first stage, we
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index bd575db..912087c 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -1249,15 +1249,45 @@
         return UpdateState::None;
     }
 
-    auto state = ReadUpdateState(lock.get());
-    if (progress) {
-        *progress = 0.0;
-        if (state == UpdateState::Merging) {
-            // :TODO: When merging is implemented, set progress_val.
-        } else if (state == UpdateState::MergeCompleted) {
-            *progress = 100.0;
-        }
+    SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock.get());
+    auto state = update_status.state();
+    if (progress == nullptr) {
+        return state;
     }
+
+    if (state == UpdateState::MergeCompleted) {
+        *progress = 100.0;
+        return state;
+    }
+
+    *progress = 0.0;
+    if (state != UpdateState::Merging) {
+        return state;
+    }
+
+    // Sum all the snapshot states as if the system consists of a single huge
+    // snapshots device, then compute the merge completion percentage of that
+    // device.
+    std::vector<std::string> snapshots;
+    if (!ListSnapshots(lock.get(), &snapshots)) {
+        LOG(ERROR) << "Could not list snapshots";
+        return state;
+    }
+
+    DmTargetSnapshot::Status fake_snapshots_status = {};
+    for (const auto& snapshot : snapshots) {
+        DmTargetSnapshot::Status current_status;
+
+        if (!QuerySnapshotStatus(snapshot, nullptr, &current_status)) continue;
+
+        fake_snapshots_status.sectors_allocated += current_status.sectors_allocated;
+        fake_snapshots_status.total_sectors += current_status.total_sectors;
+        fake_snapshots_status.metadata_sectors += current_status.metadata_sectors;
+    }
+
+    *progress = DmTargetSnapshot::MergePercent(fake_snapshots_status,
+                                               update_status.sectors_allocated());
+
     return state;
 }
 
@@ -2284,9 +2314,19 @@
         }
     }
 
+    unsigned int last_progress = 0;
+    auto callback = [&]() -> void {
+        double progress;
+        GetUpdateState(&progress);
+        if (last_progress < static_cast<unsigned int>(progress)) {
+            last_progress = progress;
+            LOG(INFO) << "Waiting for merge to complete: " << last_progress << "%.";
+        }
+    };
+
     LOG(INFO) << "Waiting for any previous merge request to complete. "
               << "This can take up to several minutes.";
-    auto state = ProcessUpdateState();
+    auto state = ProcessUpdateState(callback);
     if (state == UpdateState::None) {
         LOG(INFO) << "Can't find any snapshot to merge.";
         return state;
@@ -2298,7 +2338,8 @@
         }
         // All other states can be handled by ProcessUpdateState.
         LOG(INFO) << "Waiting for merge to complete. This can take up to several minutes.";
-        state = ProcessUpdateState();
+        last_progress = 0;
+        state = ProcessUpdateState(callback);
     }
 
     LOG(INFO) << "Merge finished with state \"" << state << "\".";
diff --git a/liblog/fake_log_device.cpp b/liblog/fake_log_device.cpp
index 2582cea..f1147dc 100644
--- a/liblog/fake_log_device.cpp
+++ b/liblog/fake_log_device.cpp
@@ -517,13 +517,16 @@
 }
 
 int __android_log_is_loggable(int prio, const char*, int def) {
-  int logLevel = def;
-  return logLevel >= 0 && prio >= logLevel;
+  int minimum_priority = __android_log_get_minimum_priority();
+  if (minimum_priority == ANDROID_LOG_DEFAULT) {
+    return prio >= def;
+  } else {
+    return prio >= minimum_priority;
+  }
 }
 
 int __android_log_is_loggable_len(int prio, const char*, size_t, int def) {
-  int logLevel = def;
-  return logLevel >= 0 && prio >= logLevel;
+  return __android_log_is_loggable(prio, nullptr, def);
 }
 
 int __android_log_is_debuggable() {
diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h
index 7290789..6530704 100644
--- a/liblog/include/android/log.h
+++ b/liblog/include/android/log.h
@@ -55,6 +55,7 @@
  */
 
 #include <stdarg.h>
+#include <stddef.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -152,6 +153,12 @@
 } log_id_t;
 
 /**
+ * Let the logging function choose the best log target.
+ * This is not part of the enum since adding either -1 or 0xFFFFFFFF forces the enum to be signed or
+ * unsigned, which breaks unfortunately common arithmetic against LOG_ID_MIN and LOG_ID_MAX. */
+#define LOG_ID_DEFAULT -1
+
+/**
  * Writes the constant string `text` to the log buffer `id`,
  * with priority `prio` and tag `tag`.
  *
@@ -170,6 +177,101 @@
 int __android_log_buf_print(int bufID, int prio, const char* tag, const char* fmt, ...)
     __attribute__((__format__(printf, 4, 5)));
 
+/**
+ * Logger data struct used for writing log messages to liblog via __android_log_write_logger_data()
+ * and sending log messages to user defined loggers specified in __android_log_set_logger().
+ */
+struct __android_logger_data {
+  size_t struct_size; /* Must be set to sizeof(__android_logger_data) and is used for versioning. */
+  int buffer_id;      /* log_id_t or -1 to represent 'default'. */
+  int priority;       /* android_LogPriority values. */
+  const char* tag;
+  const char* file;  /* Optional file name, may be set to nullptr. */
+  unsigned int line; /* Optional line number, ignore if file is nullptr. */
+};
+
+/**
+ * Writes the log message specified with logger_data and msg to the log.  logger_data includes
+ * additional file name and line number information that a logger may use.  logger_data is versioned
+ * for backwards compatibility.
+ */
+void __android_log_write_logger_data(struct __android_logger_data* logger_data, const char* msg);
+
+/**
+ * Prototype for the 'logger' function that is called for every log message.
+ */
+typedef void (*__android_logger_function)(const struct __android_logger_data* logger_data,
+                                          const char* message);
+
+/**
+ * Sets a user defined logger function.  All log messages sent to liblog will be set to the
+ * function pointer specified by logger for processing.
+ */
+void __android_log_set_logger(__android_logger_function logger);
+
+/**
+ * Writes the log message to logd.  This is an __android_logger_function and can be provided to
+ * __android_log_set_logger().  It is the default logger when running liblog on a device.
+ */
+void __android_log_logd_logger(const struct __android_logger_data* logger_data, const char* msg);
+
+/**
+ * Writes the log message to stderr.  This is an __android_logger_function and can be provided to
+ * __android_log_set_logger().  It is the default logger when running liblog on host.
+ */
+void __android_log_stderr_logger(const struct __android_logger_data* logger_data,
+                                 const char* message);
+
+/**
+ * Prototype for the 'abort' function that is called when liblog will abort due to
+ * __android_log_assert() failures.
+ */
+typedef void (*__android_aborter_function)(const char* abort_message);
+
+/**
+ * Sets a user defined aborter function that is called for __android_log_assert() failures.
+ */
+void __android_log_set_aborter(__android_aborter_function aborter);
+
+/**
+ * Calls the stored aborter function.  This allows for other logging libraries to use the same
+ * aborter function by calling this function in liblog.
+ */
+void __android_log_call_aborter(const char* abort_message);
+
+/**
+ * Sets android_set_abort_message() on device then aborts().  This is the default aborter.
+ */
+void __android_log_default_aborter(const char* abort_message);
+
+/**
+ * Use the per-tag properties "log.tag.<tagname>" along with the minimum priority from
+ * __android_log_set_minimum_priority() to determine if a log message with a given prio and tag will
+ * be printed.  A non-zero result indicates yes, zero indicates false.
+ *
+ * If both a priority for a tag and a minimum priority are set by
+ * __android_log_set_minimum_priority(), then the lowest of the two values are to determine the
+ * minimum priority needed to log.  If only one is set, then that value is used to determine the
+ * minimum priority needed.  If none are set, then default_priority is used.
+ *
+ * prio is ANDROID_LOG_VERBOSE to ANDROID_LOG_FATAL.
+ */
+int __android_log_is_loggable(int prio, const char* tag, int default_prio);
+int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio);
+
+/**
+ * Sets the minimum priority that will be logged for this process.
+ *
+ * This returns the previous set minimum priority, or ANDROID_LOG_DEFAULT if none was set.
+ */
+int __android_log_set_minimum_priority(int priority);
+
+/**
+ * Gets the minimum priority that will be logged for this process.  If none has been set by a
+ * previous __android_log_set_minimum_priority() call, this returns ANDROID_LOG_DEFAULT.
+ */
+int __android_log_get_minimum_priority();
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/liblog/liblog.map.txt b/liblog/liblog.map.txt
index 65194ce..62b9805 100644
--- a/liblog/liblog.map.txt
+++ b/liblog/liblog.map.txt
@@ -67,7 +67,16 @@
 
 LIGLOG_R { # introduced=30
   global:
+    __android_log_call_aborter;
+    __android_log_default_aborter;
+    __android_log_get_minimum_priority;
+    __android_log_logd_logger;
     __android_log_security_bswrite; # apex
+    __android_log_set_aborter;
+    __android_log_set_logger;
+    __android_log_set_minimum_priority;
+    __android_log_stderr_logger;
+    __android_log_write_logger_data;
 };
 
 LIBLOG_PRIVATE {
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index d6ef951..61b6fce 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <errno.h>
+#include <inttypes.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/time.h>
@@ -23,11 +24,15 @@
 #include <android/set_abort_message.h>
 #endif
 
+#include <shared_mutex>
+
 #include <android-base/macros.h>
 #include <private/android_filesystem_config.h>
 #include <private/android_logger.h>
 
+#include "android/log.h"
 #include "logger.h"
+#include "rwlock.h"
 #include "uio.h"
 
 #if (FAKE_LOG_DEVICE == 0)
@@ -37,6 +42,14 @@
 #include "fake_log_device.h"
 #endif
 
+#if defined(__APPLE__)
+#include <pthread.h>
+#elif defined(__linux__) && !defined(__ANDROID__)
+#include <syscall.h>
+#elif defined(_WIN32)
+#include <windows.h>
+#endif
+
 #define LOG_BUF_SIZE 1024
 
 #if defined(__ANDROID__)
@@ -93,6 +106,52 @@
 #endif
 }
 
+static int minimum_log_priority = ANDROID_LOG_DEFAULT;
+int __android_log_set_minimum_priority(int priority) {
+  int old_minimum_log_priority = minimum_log_priority;
+  minimum_log_priority = priority;
+  return old_minimum_log_priority;
+}
+
+int __android_log_get_minimum_priority() {
+  return minimum_log_priority;
+}
+
+#ifdef __ANDROID__
+static __android_logger_function logger_function = __android_log_logd_logger;
+#else
+static __android_logger_function logger_function = __android_log_stderr_logger;
+#endif
+static RwLock logger_function_lock;
+
+void __android_log_set_logger(__android_logger_function logger) {
+  auto lock = std::unique_lock{logger_function_lock};
+  logger_function = logger;
+}
+
+void __android_log_default_aborter(const char* abort_message) {
+#ifdef __ANDROID__
+  android_set_abort_message(abort_message);
+#else
+  UNUSED(abort_message);
+#endif
+  abort();
+}
+
+static __android_aborter_function aborter_function = __android_log_default_aborter;
+static RwLock aborter_function_lock;
+
+void __android_log_set_aborter(__android_aborter_function aborter) {
+  auto lock = std::unique_lock{aborter_function_lock};
+  aborter_function = aborter;
+}
+
+void __android_log_call_aborter(const char* abort_message) {
+  auto lock = std::shared_lock{aborter_function_lock};
+  aborter_function(abort_message);
+}
+
+#ifdef __ANDROID__
 static int write_to_log(log_id_t log_id, struct iovec* vec, size_t nr) {
   int ret, save_errno;
   struct timespec ts;
@@ -103,7 +162,6 @@
     return -EINVAL;
   }
 
-#if defined(__ANDROID__)
   clock_gettime(android_log_clockid(), &ts);
 
   if (log_id == LOG_ID_SECURITY) {
@@ -137,51 +195,106 @@
       return -EPERM;
     }
   }
-#else
-  /* simulate clock_gettime(CLOCK_REALTIME, &ts); */
-  {
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    ts.tv_sec = tv.tv_sec;
-    ts.tv_nsec = tv.tv_usec * 1000;
-  }
-#endif
 
-  ret = 0;
-
-#if (FAKE_LOG_DEVICE == 0)
   ret = LogdWrite(log_id, &ts, vec, nr);
   PmsgWrite(log_id, &ts, vec, nr);
-#else
-  ret = FakeWrite(log_id, &ts, vec, nr);
-#endif
 
   errno = save_errno;
   return ret;
 }
+#else
+static int write_to_log(log_id_t, struct iovec*, size_t) {
+  // Non-Android text logs should go to __android_log_stderr_logger, not here.
+  // Non-Android binary logs are always dropped.
+  return 1;
+}
+#endif
+
+// Copied from base/threads.cpp
+static uint64_t GetThreadId() {
+#if defined(__BIONIC__)
+  return gettid();
+#elif defined(__APPLE__)
+  uint64_t tid;
+  pthread_threadid_np(NULL, &tid);
+  return tid;
+#elif defined(__linux__)
+  return syscall(__NR_gettid);
+#elif defined(_WIN32)
+  return GetCurrentThreadId();
+#endif
+}
+
+void __android_log_stderr_logger(const struct __android_logger_data* logger_data,
+                                 const char* message) {
+  struct tm now;
+  time_t t = time(nullptr);
+
+#if defined(_WIN32)
+  localtime_s(&now, &t);
+#else
+  localtime_r(&t, &now);
+#endif
+
+  char timestamp[32];
+  strftime(timestamp, sizeof(timestamp), "%m-%d %H:%M:%S", &now);
+
+  static const char log_characters[] = "XXVDIWEF";
+  static_assert(arraysize(log_characters) - 1 == ANDROID_LOG_SILENT,
+                "Mismatch in size of log_characters and values in android_LogPriority");
+  int priority =
+      logger_data->priority > ANDROID_LOG_SILENT ? ANDROID_LOG_FATAL : logger_data->priority;
+  char priority_char = log_characters[priority];
+  uint64_t tid = GetThreadId();
+
+  if (logger_data->file != nullptr) {
+    fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s:%u] %s\n",
+            logger_data->tag ? logger_data->tag : "nullptr", priority_char, timestamp, getpid(),
+            tid, logger_data->file, logger_data->line, message);
+  } else {
+    fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s\n",
+            logger_data->tag ? logger_data->tag : "nullptr", priority_char, timestamp, getpid(),
+            tid, message);
+  }
+}
+
+void __android_log_logd_logger(const struct __android_logger_data* logger_data,
+                               const char* message) {
+  int buffer_id = logger_data->buffer_id == LOG_ID_DEFAULT ? LOG_ID_MAIN : logger_data->buffer_id;
+
+  struct iovec vec[3];
+  vec[0].iov_base =
+      const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(&logger_data->priority));
+  vec[0].iov_len = 1;
+  vec[1].iov_base = const_cast<void*>(static_cast<const void*>(logger_data->tag));
+  vec[1].iov_len = strlen(logger_data->tag) + 1;
+  vec[2].iov_base = const_cast<void*>(static_cast<const void*>(message));
+  vec[2].iov_len = strlen(message) + 1;
+
+  write_to_log(static_cast<log_id_t>(buffer_id), vec, 3);
+}
 
 int __android_log_write(int prio, const char* tag, const char* msg) {
   return __android_log_buf_write(LOG_ID_MAIN, prio, tag, msg);
 }
 
-int __android_log_buf_write(int bufID, int prio, const char* tag, const char* msg) {
-  if (!tag) tag = "";
+void __android_log_write_logger_data(__android_logger_data* logger_data, const char* msg) {
+  if (logger_data->tag == nullptr) logger_data->tag = "";
 
 #if __BIONIC__
-  if (prio == ANDROID_LOG_FATAL) {
+  if (logger_data->priority == ANDROID_LOG_FATAL) {
     android_set_abort_message(msg);
   }
 #endif
 
-  struct iovec vec[3];
-  vec[0].iov_base = (unsigned char*)&prio;
-  vec[0].iov_len = 1;
-  vec[1].iov_base = (void*)tag;
-  vec[1].iov_len = strlen(tag) + 1;
-  vec[2].iov_base = (void*)msg;
-  vec[2].iov_len = strlen(msg) + 1;
+  auto lock = std::shared_lock{logger_function_lock};
+  logger_function(logger_data, msg);
+}
 
-  return write_to_log(static_cast<log_id_t>(bufID), vec, 3);
+int __android_log_buf_write(int bufID, int prio, const char* tag, const char* msg) {
+  __android_logger_data logger_data = {sizeof(__android_logger_data), bufID, prio, tag, nullptr, 0};
+  __android_log_write_logger_data(&logger_data, msg);
+  return 1;
 }
 
 int __android_log_vprint(int prio, const char* tag, const char* fmt, va_list ap) {
@@ -239,8 +352,8 @@
   TEMP_FAILURE_RETRY(write(2, "\n", 1));
 
   __android_log_write(ANDROID_LOG_FATAL, tag, buf);
-  abort(); /* abort so we have a chance to debug the situation */
-           /* NOTREACHED */
+  __android_log_call_aborter(buf);
+  abort();
 }
 
 int __android_log_bwrite(int32_t tag, const void* payload, size_t len) {
diff --git a/liblog/properties.cpp b/liblog/properties.cpp
index 2b2327c..a53c92b 100644
--- a/liblog/properties.cpp
+++ b/liblog/properties.cpp
@@ -24,6 +24,8 @@
 #include <sys/_system_properties.h>
 #include <unistd.h>
 
+#include <algorithm>
+
 #include <private/android_logger.h>
 
 static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER;
@@ -87,7 +89,7 @@
   }
 }
 
-static int __android_log_level(const char* tag, size_t len, int default_prio) {
+static int __android_log_level(const char* tag, size_t len) {
   /* sizeof() is used on this array below */
   static const char log_namespace[] = "persist.log.tag.";
   static const size_t base_offset = 8; /* skip "persist." */
@@ -256,20 +258,30 @@
     case 'F': /* FALLTHRU */ /* Not officially supported */
     case 'A': return ANDROID_LOG_FATAL;
     case BOOLEAN_FALSE: /* FALLTHRU */ /* Not Officially supported */
-    case 'S': return -1; /* ANDROID_LOG_SUPPRESS */
+    case 'S': return ANDROID_LOG_SILENT;
       /* clang-format on */
   }
-  return default_prio;
+  return -1;
 }
 
 int __android_log_is_loggable_len(int prio, const char* tag, size_t len, int default_prio) {
-  int logLevel = __android_log_level(tag, len, default_prio);
-  return logLevel >= 0 && prio >= logLevel;
+  int minimum_log_priority = __android_log_get_minimum_priority();
+  int property_log_level = __android_log_level(tag, len);
+
+  if (property_log_level >= 0 && minimum_log_priority != ANDROID_LOG_DEFAULT) {
+    return prio >= std::min(property_log_level, minimum_log_priority);
+  } else if (property_log_level >= 0) {
+    return prio >= property_log_level;
+  } else if (minimum_log_priority != ANDROID_LOG_DEFAULT) {
+    return prio >= minimum_log_priority;
+  } else {
+    return prio >= default_prio;
+  }
 }
 
 int __android_log_is_loggable(int prio, const char* tag, int default_prio) {
-  int logLevel = __android_log_level(tag, (tag && *tag) ? strlen(tag) : 0, default_prio);
-  return logLevel >= 0 && prio >= logLevel;
+  auto len = tag ? strlen(tag) : 0;
+  return __android_log_is_loggable_len(prio, tag, len, default_prio);
 }
 
 int __android_log_is_debuggable() {
diff --git a/liblog/tests/Android.bp b/liblog/tests/Android.bp
index f58c524..3288954 100644
--- a/liblog/tests/Android.bp
+++ b/liblog/tests/Android.bp
@@ -54,6 +54,7 @@
     ],
     srcs: [
         "libc_test.cpp",
+        "liblog_global_state.cpp",
         "liblog_test.cpp",
         "log_id_test.cpp",
         "log_radio_test.cpp",
diff --git a/liblog/tests/liblog_global_state.cpp b/liblog/tests/liblog_global_state.cpp
new file mode 100644
index 0000000..8d73bb8
--- /dev/null
+++ b/liblog/tests/liblog_global_state.cpp
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#define LOG_TAG "global_state_test_tag"
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android/log.h>
+
+#include <gtest/gtest.h>
+
+TEST(liblog_global_state, libbase_logs_with_libbase_SetLogger) {
+  using namespace android::base;
+  bool message_seen = false;
+  LogSeverity expected_severity = WARNING;
+  std::string expected_file = Basename(__FILE__);
+  unsigned int expected_line;
+  std::string expected_message = "libbase test message";
+
+  auto LoggerFunction = [&](LogId log_id, LogSeverity severity, const char* tag, const char* file,
+                            unsigned int line, const char* message) {
+    message_seen = true;
+    EXPECT_EQ(DEFAULT, log_id);
+    EXPECT_EQ(expected_severity, severity);
+    EXPECT_STREQ(LOG_TAG, tag);
+    EXPECT_EQ(expected_file, file);
+    EXPECT_EQ(expected_line, line);
+    EXPECT_EQ(expected_message, message);
+  };
+
+  SetLogger(LoggerFunction);
+
+  expected_line = __LINE__ + 1;
+  LOG(expected_severity) << expected_message;
+  EXPECT_TRUE(message_seen);
+}
+
+TEST(liblog_global_state, libbase_logs_with_liblog_set_logger) {
+  using namespace android::base;
+  // These must be static since they're used by the liblog logger function, which only accepts
+  // lambdas without captures.  The items used by the libbase logger are explicitly not static, to
+  // ensure that lambdas with captures do work there.
+  static bool message_seen = false;
+  static std::string expected_file = Basename(__FILE__);
+  static unsigned int expected_line;
+  static std::string expected_message = "libbase test message";
+
+  auto liblog_logger_function = [](const struct __android_logger_data* logger_data,
+                                   const char* message) {
+    message_seen = true;
+    EXPECT_EQ(sizeof(__android_logger_data), logger_data->struct_size);
+    EXPECT_EQ(LOG_ID_DEFAULT, logger_data->buffer_id);
+    EXPECT_EQ(ANDROID_LOG_WARN, logger_data->priority);
+    EXPECT_STREQ(LOG_TAG, logger_data->tag);
+    EXPECT_EQ(expected_file, logger_data->file);
+    EXPECT_EQ(expected_line, logger_data->line);
+    EXPECT_EQ(expected_message, message);
+  };
+
+  __android_log_set_logger(liblog_logger_function);
+
+  expected_line = __LINE__ + 1;
+  LOG(WARNING) << expected_message;
+  EXPECT_TRUE(message_seen);
+}
+
+TEST(liblog_global_state, liblog_logs_with_libbase_SetLogger) {
+  using namespace android::base;
+  bool message_seen = false;
+  std::string expected_message = "libbase test message";
+
+  auto LoggerFunction = [&](LogId log_id, LogSeverity severity, const char* tag, const char* file,
+                            unsigned int line, const char* message) {
+    message_seen = true;
+    EXPECT_EQ(MAIN, log_id);
+    EXPECT_EQ(WARNING, severity);
+    EXPECT_STREQ(LOG_TAG, tag);
+    EXPECT_EQ(nullptr, file);
+    EXPECT_EQ(0U, line);
+    EXPECT_EQ(expected_message, message);
+  };
+
+  SetLogger(LoggerFunction);
+
+  __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_WARN, LOG_TAG, expected_message.c_str());
+  EXPECT_TRUE(message_seen);
+  message_seen = false;
+}
+
+TEST(liblog_global_state, liblog_logs_with_liblog_set_logger) {
+  using namespace android::base;
+  // These must be static since they're used by the liblog logger function, which only accepts
+  // lambdas without captures.  The items used by the libbase logger are explicitly not static, to
+  // ensure that lambdas with captures do work there.
+  static bool message_seen = false;
+  static int expected_buffer_id = LOG_ID_MAIN;
+  static int expected_priority = ANDROID_LOG_WARN;
+  static std::string expected_message = "libbase test message";
+
+  auto liblog_logger_function = [](const struct __android_logger_data* logger_data,
+                                   const char* message) {
+    message_seen = true;
+    EXPECT_EQ(sizeof(__android_logger_data), logger_data->struct_size);
+    EXPECT_EQ(expected_buffer_id, logger_data->buffer_id);
+    EXPECT_EQ(expected_priority, logger_data->priority);
+    EXPECT_STREQ(LOG_TAG, logger_data->tag);
+    EXPECT_STREQ(nullptr, logger_data->file);
+    EXPECT_EQ(0U, logger_data->line);
+    EXPECT_EQ(expected_message, message);
+  };
+
+  __android_log_set_logger(liblog_logger_function);
+
+  __android_log_buf_write(expected_buffer_id, expected_priority, LOG_TAG, expected_message.c_str());
+  EXPECT_TRUE(message_seen);
+}
+
+TEST(liblog_global_state, SetAborter_with_liblog) {
+  using namespace android::base;
+
+  std::string expected_message = "libbase test message";
+  static bool message_seen = false;
+  auto aborter_function = [&](const char* message) {
+    message_seen = true;
+    EXPECT_EQ(expected_message, message);
+  };
+
+  SetAborter(aborter_function);
+  LOG(FATAL) << expected_message;
+  EXPECT_TRUE(message_seen);
+  message_seen = false;
+
+  static std::string expected_message_static = "libbase test message";
+  auto liblog_aborter_function = [](const char* message) {
+    message_seen = true;
+    EXPECT_EQ(expected_message_static, message);
+  };
+  __android_log_set_aborter(liblog_aborter_function);
+  LOG(FATAL) << expected_message_static;
+  EXPECT_TRUE(message_seen);
+  message_seen = false;
+}
+
+TEST(liblog_global_state, is_loggable_both_default) {
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+}
+
+TEST(liblog_global_state, is_loggable_minimum_log_priority_only) {
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  EXPECT_EQ(ANDROID_LOG_DEFAULT, __android_log_set_minimum_priority(ANDROID_LOG_DEBUG));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  EXPECT_EQ(ANDROID_LOG_DEBUG, __android_log_set_minimum_priority(ANDROID_LOG_WARN));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  EXPECT_EQ(android::base::WARNING, android::base::SetMinimumLogSeverity(android::base::DEBUG));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  EXPECT_EQ(android::base::DEBUG, android::base::SetMinimumLogSeverity(android::base::WARNING));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+}
+
+TEST(liblog_global_state, is_loggable_tag_log_priority_only) {
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  auto log_tag_property = std::string("log.tag.") + LOG_TAG;
+  android::base::SetProperty(log_tag_property, "d");
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  android::base::SetProperty(log_tag_property, "w");
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  android::base::SetProperty(log_tag_property, "");
+}
+
+TEST(liblog_global_state, is_loggable_both_set) {
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  // When both a tag and a minimum priority are set, we use the lower value of the two.
+
+  // tag = warning, minimum_priority = debug, expect 'debug'
+  auto log_tag_property = std::string("log.tag.") + LOG_TAG;
+  android::base::SetProperty(log_tag_property, "w");
+  EXPECT_EQ(ANDROID_LOG_DEFAULT, __android_log_set_minimum_priority(ANDROID_LOG_DEBUG));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  // tag = warning, minimum_priority = warning, expect 'warning'
+  EXPECT_EQ(ANDROID_LOG_DEBUG, __android_log_set_minimum_priority(ANDROID_LOG_WARN));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  // tag = debug, minimum_priority = warning, expect 'debug'
+  android::base::SetProperty(log_tag_property, "d");
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  // tag = debug, minimum_priority = debug, expect 'debug'
+  EXPECT_EQ(ANDROID_LOG_WARN, __android_log_set_minimum_priority(ANDROID_LOG_DEBUG));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO));
+  EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO));
+
+  android::base::SetProperty(log_tag_property, "");
+}
diff --git a/liblog/tests/liblog_test.cpp b/liblog/tests/liblog_test.cpp
index c402e20..75a26bf 100644
--- a/liblog/tests/liblog_test.cpp
+++ b/liblog/tests/liblog_test.cpp
@@ -1074,7 +1074,6 @@
 
     // Once we've found our expected entry, break.
     if (len == LOGGER_ENTRY_MAX_PAYLOAD - sizeof(big_payload_tag)) {
-      EXPECT_EQ(ret, len + static_cast<ssize_t>(sizeof(big_payload_tag)));
       *found = true;
     }
   };
@@ -1259,14 +1258,10 @@
     int level;
     char type;
   } levels[] = {
-    { ANDROID_LOG_VERBOSE, 'v' },
-    { ANDROID_LOG_DEBUG, 'd' },
-    { ANDROID_LOG_INFO, 'i' },
-    { ANDROID_LOG_WARN, 'w' },
-    { ANDROID_LOG_ERROR, 'e' },
-    { ANDROID_LOG_FATAL, 'a' },
-    { -1, 's' },
-    { -2, 'g' },  // Illegal value, resort to default
+      {ANDROID_LOG_VERBOSE, 'v'}, {ANDROID_LOG_DEBUG, 'd'},
+      {ANDROID_LOG_INFO, 'i'},    {ANDROID_LOG_WARN, 'w'},
+      {ANDROID_LOG_ERROR, 'e'},   {ANDROID_LOG_FATAL, 'a'},
+      {ANDROID_LOG_SILENT, 's'},  {-2, 'g'},  // Illegal value, resort to default
   };
 
   // Set up initial test condition
diff --git a/shell_and_utilities/README.md b/shell_and_utilities/README.md
index d391cc1..3bee875 100644
--- a/shell_and_utilities/README.md
+++ b/shell_and_utilities/README.md
@@ -218,25 +218,28 @@
 
 bzip2: bzcat bzip2 bunzip2
 
+gavinhoward/bc: bc
+
 one-true-awk: awk
 
 toolbox: getevent getprop setprop start stop
 
-toybox: acpi base64 basename bc blkid blockdev cal cat chattr chcon chgrp
-chmod chown chroot chrt cksum clear cmp comm cp cpio cut date dd df
-diff dirname dmesg dos2unix du echo egrep env expand expr fallocate
-false fgrep file find flock fmt free freeramdisk fsfreeze getconf
-getenforce getfattr grep groups gunzip gzip head help hostname hwclock
-i2cdetect i2cdump i2cget i2cset iconv id ifconfig inotifyd insmod
-install ionice iorenice iotop kill killall ln load\_policy log logname
-losetup ls lsattr lsmod lsof lspci lsusb makedevs md5sum microcom
+toybox: acpi base64 basename blkid blockdev cal cat chattr chcon chgrp chmod
+chown chroot chrt cksum clear cmp comm cp cpio cut date dd devmem
+df diff dirname dmesg dos2unix du echo egrep env expand expr fallocate
+false fgrep file find flock fmt free freeramdisk fsfreeze fsync getconf
+getenforce getfattr getopt grep groups gunzip gzip head help hostname
+hwclock i2cdetect i2cdump i2cget i2cset iconv id ifconfig inotifyd
+insmod install ionice iorenice iotop kill killall ln load\_policy log
+logname losetup ls lsattr lsmod lsof lspci lsusb makedevs md5sum microcom
 mkdir mkfifo mknod mkswap mktemp modinfo modprobe more mount mountpoint
 mv nbd-client nc netcat netstat nice nl nohup nproc nsenter od partprobe
 paste patch pgrep pidof ping ping6 pivot\_root pkill pmap printenv
-printf prlimit ps pwd pwdx readlink realpath renice restorecon rev
-rfkill rm rmdir rmmod runcon sed sendevent seq setenforce setfattr
-setsid sha1sum sha224sum sha256sum sha384sum sha512sum sleep sort split
-stat strings stty swapoff swapon sync sysctl tac tail tar taskset tee
-time timeout top touch tr traceroute traceroute6 true truncate tty tunctl
-ulimit umount uname uniq unix2dos unlink unshare uptime usleep uudecode
-uuencode uuidgen vconfig vmstat watch wc which whoami xargs xxd yes zcat
+printf prlimit ps pwd pwdx readelf readlink realpath renice restorecon
+rev rfkill rm rmdir rmmod runcon sed sendevent seq setenforce setfattr
+setsid sha1sum sha224sum sha256sum sha384sum sha512sum sleep sort
+split stat strings stty swapoff swapon sync sysctl tac tail tar taskset
+tee time timeout top touch tr traceroute traceroute6 true truncate
+tty tunctl ulimit umount uname uniq unix2dos unlink unshare uptime
+usleep uudecode uuencode uuidgen vconfig vi vmstat watch wc which
+whoami xargs xxd yes zcat