Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 81c8385a authored by Tom Cherry's avatar Tom Cherry Committed by Gerrit Code Review
Browse files

Merge changes Icb49b30b,Ib52cbfb4

* changes:
  Move minimum log priority from libbase to liblog
  Move SetLogger and SetAborter from libbase to liblog
parents 2353510b 0391a879
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -56,6 +56,7 @@ cc_defaults {
        "chrono_utils.cpp",
        "cmsg.cpp",
        "file.cpp",
        "liblog_symbols.cpp",
        "logging.cpp",
        "mapped_file.cpp",
        "parsebool.cpp",
@@ -68,6 +69,10 @@ cc_defaults {
        "test_utils.cpp",
    ],

    static: {
        cflags: ["-DNO_LIBLOG_DLSYM"],
    },

    cppflags: ["-Wexit-time-destructors"],
    shared_libs: ["liblog"],
    target: {
+8 −3
Original line number Diff line number Diff line
@@ -85,7 +85,7 @@ enum LogSeverity {
  INFO,
  WARNING,
  ERROR,
  FATAL_WITHOUT_ABORT,
  FATAL_WITHOUT_ABORT,  // For loggability tests, this is considered identical to FATAL.
  FATAL,
};

@@ -93,6 +93,8 @@ enum LogId {
  DEFAULT,
  MAIN,
  SYSTEM,
  RADIO,
  CRASH,
};

using LogFunction = std::function<void(LogId, LogSeverity, const char*, const char*,
@@ -210,7 +212,7 @@ struct LogAbortAfterFullExpr {

// Defines whether the given severity will be logged or silently swallowed.
#define WOULD_LOG(severity)                                                              \
  (UNLIKELY((SEVERITY_LAMBDA(severity)) >= ::android::base::GetMinimumLogSeverity()) || \
  (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 @@ LogSeverity GetMinimumLogSeverity();
// 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:
+83 −0
Original line number Diff line number Diff line
/*
 * 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

base/liblog_symbols.h

0 → 100644
+46 −0
Original line number Diff line number Diff line
/*
 * 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
+196 −38
Original line number Diff line number Diff line
@@ -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 @@ static int OpenKmsg() {
}
#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 @@ static LogFunction& Logger() {
  return logger;
}

// Only used for Q fallback.
static AbortFunction& Aborter() {
  static auto& aborter = *new AbortFunction(DefaultAborter);
  return aborter;
@@ -158,6 +235,8 @@ void SetDefaultTag(const std::string& tag) {
}

static bool gInitialized = false;

// Only used for Q fallback.
static LogSeverity gMinimumLogSeverity = INFO;

#if defined(__linux__)
@@ -218,8 +297,13 @@ void StderrLogger(LogId, LogSeverity severity, const char* tag, const char* file
  static_assert(arraysize(log_characters) - 1 == FATAL + 1,
                "Mismatch in size of log_characters and values in LogSeverity");
  char severity_char = log_characters[severity];
  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 @@ LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) {
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);

  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);
  }

  if (priority == ANDROID_LOG_FATAL) {
    __android_log_buf_print(lg_id, priority, tag, "%s:%u] %s", file, line,
                            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 @@ void InitLogging(char* argv[], LogFunction&& logger, AbortFunction&& aborter) {
    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,14 +415,47 @@ void InitLogging(char* argv[], LogFunction&& logger, AbortFunction&& aborter) {
}

void SetLogger(LogFunction&& 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) {
  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
// checks/logging in a function.
@@ -444,9 +557,14 @@ LogMessage::~LogMessage() {

  // Abort if necessary.
  if (data_->GetSeverity() == FATAL) {
    static auto& liblog_functions = GetLibLogFunctions();
    if (liblog_functions) {
      liblog_functions->__android_log_call_aborter(msg.c_str());
    } else {
      Aborter()(msg.c_str());
    }
  }
}

std::ostream& LogMessage::stream() {
  return data_->GetBuffer();
@@ -454,26 +572,66 @@ std::ostream& LogMessage::stream() {

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());
    }

    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 {
    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) {
  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) {
  old_ = SetMinimumLogSeverity(new_severity);
Loading