Move SetLogger and SetAborter from libbase to liblog

libbase is copied into each APEX module which requires it, meaning
that there may be multiple instances of libbase running within a
single process with their own copy of libbase's globals.  This means
that SetLogger() and SetAborter() will only impact logs from the
instance of libbase that calls it.  This change moves this state to
liblog, since it will only ever have one instance in a single
process.

One major side-effect here is that now both ALOGE style and LOG(...)
style logs will be handled through the same logger function.  For
example, a logger specified through libbase's SetLogger() will now see
logs sent to liblog through ALOGE().  This is intended behavior.

A second side-effect is that libbase's stderr logger is used for all
host logging now.  It's simply a better logging default than the
fake_log_device logger in liblog currently and makes ALOGE and
LOG(...) logs on host follow the same format.

Bug: 119867234
Test: libbase and liblog unit tests; logging works
Change-Id: Ib52cbfb4e43749e50910ed19a993dffae19ace86
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..26919fc 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -93,6 +93,8 @@
   DEFAULT,
   MAIN,
   SYSTEM,
+  RADIO,
+  CRASH,
 };
 
 using LogFunction = std::function<void(LogId, LogSeverity, const char*, const char*,
diff --git a/base/liblog_symbols.cpp b/base/liblog_symbols.cpp
new file mode 100644
index 0000000..9fd81b4
--- /dev/null
+++ b/base/liblog_symbols.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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)
+#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,
+    };
+  }();
+  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..4c0dc5c
--- /dev/null
+++ b/base/liblog_symbols.h
@@ -0,0 +1,44 @@
+/*
+ * 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);
+};
+
+const std::optional<LibLogFunctions>& GetLibLogFunctions();
+
+}  // namespace base
+}  // namespace android
diff --git a/base/logging.cpp b/base/logging.cpp
index b46abbf..880287b 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,82 @@
 }
 #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_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 +203,7 @@
   return logger;
 }
 
+// Only used for Q fallback.
 static AbortFunction& Aborter() {
   static auto& aborter = *new AbortFunction(DefaultAborter);
   return aborter;
@@ -218,8 +293,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 +328,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);
   }
@@ -335,13 +411,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 +553,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,14 +568,29 @@
 
 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);
+    }
   }
 }