diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h index 7fd018227..cc162cd53 100644 --- a/base/include/android-base/logging.h +++ b/base/include/android-base/logging.h @@ -115,7 +115,6 @@ void StdioLogger(LogId, LogSeverity, const char*, const char*, unsigned int, con void DefaultAborter(const char* abort_message); -std::string GetDefaultTag(); void SetDefaultTag(const std::string& tag); // We expose this even though it is the default because a user that wants to diff --git a/base/liblog_symbols.cpp b/base/liblog_symbols.cpp index d0e2eaa77..d5dfcd28b 100644 --- a/base/liblog_symbols.cpp +++ b/base/liblog_symbols.cpp @@ -50,6 +50,7 @@ const std::optional& GetLibLogFunctions() { DLSYM(__android_log_default_aborter) DLSYM(__android_log_set_minimum_priority); DLSYM(__android_log_get_minimum_priority); + DLSYM(__android_log_set_default_tag); #undef DLSYM return real_liblog_functions; @@ -72,6 +73,7 @@ const std::optional& GetLibLogFunctions() { .__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, + .__android_log_set_default_tag = __android_log_set_default_tag, }; }(); return liblog_functions; diff --git a/base/liblog_symbols.h b/base/liblog_symbols.h index c68fff680..d3134e9c5 100644 --- a/base/liblog_symbols.h +++ b/base/liblog_symbols.h @@ -38,6 +38,7 @@ struct LibLogFunctions { void (*__android_log_default_aborter)(const char* abort_message); int (*__android_log_set_minimum_priority)(int priority); int (*__android_log_get_minimum_priority)(); + void (*__android_log_set_default_tag)(const char* tag); }; const std::optional& GetLibLogFunctions(); diff --git a/base/logging.cpp b/base/logging.cpp index 508871d8d..1d8ef573d 100644 --- a/base/logging.cpp +++ b/base/logging.cpp @@ -211,26 +211,27 @@ static AbortFunction& Aborter() { return aborter; } +// Only used for Q fallback. static std::recursive_mutex& TagLock() { static auto& tag_lock = *new std::recursive_mutex(); return tag_lock; } +// Only used for Q fallback. static std::string* gDefaultTag; -std::string GetDefaultTag() { - std::lock_guard lock(TagLock()); - if (gDefaultTag == nullptr) { - return ""; - } - return *gDefaultTag; -} + void SetDefaultTag(const std::string& tag) { - std::lock_guard lock(TagLock()); - if (gDefaultTag != nullptr) { - delete gDefaultTag; - gDefaultTag = nullptr; - } - if (!tag.empty()) { - gDefaultTag = new std::string(tag); + static auto& liblog_functions = GetLibLogFunctions(); + if (liblog_functions) { + liblog_functions->__android_log_set_default_tag(tag.c_str()); + } else { + std::lock_guard lock(TagLock()); + if (gDefaultTag != nullptr) { + delete gDefaultTag; + gDefaultTag = nullptr; + } + if (!tag.empty()) { + gDefaultTag = new std::string(tag); + } } } @@ -574,24 +575,18 @@ void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity severi const char* message) { static auto& liblog_functions = GetLibLogFunctions(); auto priority = LogSeverityToPriority(severity); - if (tag == nullptr) { - std::lock_guard 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); - } + 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 { - 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); + if (tag == nullptr) { + std::lock_guard lock(TagLock()); + if (gDefaultTag == nullptr) { + gDefaultTag = new std::string(getprogname()); + } + + Logger()(DEFAULT, severity, gDefaultTag->c_str(), file, line, message); } else { Logger()(DEFAULT, severity, tag, file, line, message); } diff --git a/base/logging_test.cpp b/base/logging_test.cpp index 8f4619639..3a453e66c 100644 --- a/base/logging_test.cpp +++ b/base/logging_test.cpp @@ -603,21 +603,6 @@ __attribute__((constructor)) void TestLoggingInConstructor() { LOG(ERROR) << "foobar"; } -TEST(logging, SetDefaultTag) { - constexpr const char* expected_tag = "test_tag"; - constexpr const char* expected_msg = "foobar"; - CapturedStderr cap; - { - std::string old_default_tag = android::base::GetDefaultTag(); - android::base::SetDefaultTag(expected_tag); - android::base::ScopedLogSeverity sls(android::base::LogSeverity::INFO); - LOG(INFO) << expected_msg; - android::base::SetDefaultTag(old_default_tag); - } - ASSERT_NO_FATAL_FAILURE( - CheckMessage(cap, android::base::LogSeverity::INFO, expected_msg, expected_tag)); -} - TEST(logging, StdioLogger) { CapturedStderr cap_err; CapturedStdout cap_out; diff --git a/liblog/include/android/log.h b/liblog/include/android/log.h index 00aafaa60..c84ddf7ad 100644 --- a/liblog/include/android/log.h +++ b/liblog/include/android/log.h @@ -276,6 +276,13 @@ int __android_log_set_minimum_priority(int priority); */ int __android_log_get_minimum_priority(); +/** + * Sets the default tag if no tag is provided when writing a log message. Defaults to + * getprogname(). This truncates tag to the maximum log message size, though appropriate tags + * should be much smaller. + */ +void __android_log_set_default_tag(const char* tag); + #ifdef __cplusplus } #endif diff --git a/liblog/liblog.map.txt b/liblog/liblog.map.txt index 62b9805fc..198cdae21 100644 --- a/liblog/liblog.map.txt +++ b/liblog/liblog.map.txt @@ -73,6 +73,7 @@ LIGLOG_R { # introduced=30 __android_log_logd_logger; __android_log_security_bswrite; # apex __android_log_set_aborter; + __android_log_set_default_tag; __android_log_set_logger; __android_log_set_minimum_priority; __android_log_stderr_logger; diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp index 1783854ee..e86d9ec13 100644 --- a/liblog/logger_write.cpp +++ b/liblog/logger_write.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -31,6 +32,7 @@ #include #include "android/log.h" +#include "log/log_read.h" #include "logger.h" #include "rwlock.h" #include "uio.h" @@ -106,6 +108,45 @@ void __android_log_close() { #endif } +#if defined(__GLIBC__) || defined(_WIN32) +static const char* getprogname() { +#if defined(__GLIBC__) + return program_invocation_short_name; +#elif defined(_WIN32) + static bool first = true; + static char progname[MAX_PATH] = {}; + + if (first) { + char path[PATH_MAX + 1]; + DWORD result = GetModuleFileName(nullptr, path, sizeof(path) - 1); + if (result == 0 || result == sizeof(path) - 1) return ""; + path[PATH_MAX - 1] = 0; + + char* path_basename = basename(path); + + snprintf(progname, sizeof(progname), "%s", path_basename); + first = false; + } + + return progname; +#endif +} +#endif + +// It's possible for logging to happen during static initialization before our globals are +// initialized, so we place this std::string in a function such that it is initialized on the first +// call. +static std::string& GetDefaultTag() { + static std::string default_tag = getprogname(); + return default_tag; +} +static RwLock default_tag_lock; + +void __android_log_set_default_tag(const char* tag) { + auto lock = std::unique_lock{default_tag_lock}; + GetDefaultTag().assign(tag, 0, LOGGER_ENTRY_MAX_PAYLOAD); +} + static int minimum_log_priority = ANDROID_LOG_DEFAULT; int __android_log_set_minimum_priority(int priority) { int old_minimum_log_priority = minimum_log_priority; @@ -270,7 +311,11 @@ int __android_log_write(int prio, const char* tag, const char* msg) { } void __android_log_write_logger_data(__android_logger_data* logger_data, const char* msg) { - if (logger_data->tag == nullptr) logger_data->tag = ""; + auto tag_lock = std::shared_lock{default_tag_lock, std::defer_lock}; + if (logger_data->tag == nullptr) { + tag_lock.lock(); + logger_data->tag = GetDefaultTag().c_str(); + } #if __BIONIC__ if (logger_data->priority == ANDROID_LOG_FATAL) { diff --git a/liblog/tests/Android.bp b/liblog/tests/Android.bp index 328895476..b3364f9ea 100644 --- a/liblog/tests/Android.bp +++ b/liblog/tests/Android.bp @@ -54,6 +54,7 @@ cc_defaults { ], srcs: [ "libc_test.cpp", + "liblog_default_tag.cpp", "liblog_global_state.cpp", "liblog_test.cpp", "log_id_test.cpp", diff --git a/liblog/tests/liblog_default_tag.cpp b/liblog/tests/liblog_default_tag.cpp new file mode 100644 index 000000000..a5baa9ff9 --- /dev/null +++ b/liblog/tests/liblog_default_tag.cpp @@ -0,0 +1,99 @@ +/* + * 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. + */ + +// LOG_TAG must be unset for android-base's logging to use a default tag. +#undef LOG_TAG + +#include + +#include +#include +#include +#include + +#include + +TEST(liblog_default_tag, no_default_tag_libbase_write_first) { + using namespace android::base; + bool message_seen = false; + std::string expected_tag = ""; + SetLogger([&](LogId, LogSeverity, const char* tag, const char*, unsigned int, const char*) { + message_seen = true; + EXPECT_EQ(expected_tag, tag); + }); + + expected_tag = getprogname(); + LOG(WARNING) << "message"; + EXPECT_TRUE(message_seen); + message_seen = false; + + __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_WARN, nullptr, "message"); + EXPECT_TRUE(message_seen); +} + +TEST(liblog_default_tag, no_default_tag_liblog_write_first) { + using namespace android::base; + bool message_seen = false; + std::string expected_tag = ""; + SetLogger([&](LogId, LogSeverity, const char* tag, const char*, unsigned int, const char*) { + message_seen = true; + EXPECT_EQ(expected_tag, tag); + }); + + expected_tag = getprogname(); + __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_WARN, nullptr, "message"); + EXPECT_TRUE(message_seen); + message_seen = false; + + LOG(WARNING) << "message"; + EXPECT_TRUE(message_seen); +} + +TEST(liblog_default_tag, libbase_sets_default_tag) { + using namespace android::base; + bool message_seen = false; + std::string expected_tag = "libbase_test_tag"; + SetLogger([&](LogId, LogSeverity, const char* tag, const char*, unsigned int, const char*) { + message_seen = true; + EXPECT_EQ(expected_tag, tag); + }); + SetDefaultTag(expected_tag); + + __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_WARN, nullptr, "message"); + EXPECT_TRUE(message_seen); + message_seen = false; + + LOG(WARNING) << "message"; + EXPECT_TRUE(message_seen); +} + +TEST(liblog_default_tag, liblog_sets_default_tag) { + using namespace android::base; + bool message_seen = false; + std::string expected_tag = "liblog_test_tag"; + SetLogger([&](LogId, LogSeverity, const char* tag, const char*, unsigned int, const char*) { + message_seen = true; + EXPECT_EQ(expected_tag, tag); + }); + __android_log_set_default_tag(expected_tag.c_str()); + + __android_log_buf_write(LOG_ID_MAIN, ANDROID_LOG_WARN, nullptr, "message"); + EXPECT_TRUE(message_seen); + message_seen = false; + + LOG(WARNING) << "message"; + EXPECT_TRUE(message_seen); +} \ No newline at end of file