diff options
Diffstat (limited to 'base/logging.cpp')
-rw-r--r-- | base/logging.cpp | 234 |
1 files changed, 196 insertions, 38 deletions
diff --git a/base/logging.cpp b/base/logging.cpp index b46abbfe6..508871d8d 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 @@ 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]; - 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 @@ 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,13 +415,46 @@ void InitLogging(char* argv[], LogFunction&& logger, AbortFunction&& aborter) { } 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 @@ LogMessage::~LogMessage() { // 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 @@ 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()); } - 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) { |