ro.log.file_logger.path works even via libbase
Previously, even if ro.log.file_logger.path is set, logs written via
libbase APIs were not written to the file. This was because the sysprop
was ignored if a custom logger is set and libbase registers a custom
logger (LogdLogger).
This behavior was very confusing because it meant that depending on
which logging API you use, you get different results; `ALOGI("msg");`
goes to the file, whereas `LOG(INFO) << "msg";` goes to logd, or
silently ignored in a logd-less environment like Microdroid.
This change fixes the issue as follows:
* The sysprop doesn't change the global logger function. This was the
original behavior before the introduction of the sysprop.
* Instead, `__android_log_logd_logger` checks if the sysprop is set, and
if so writes the log to the file. If the sysprop is not set, the log
goes to logd as before.
* The check for sysprop and file descriptor for the file are cached as
before.
Bug: 270566364
Test: vm/vm_shell.sh start-microdroid -- --protected --console \
/data/local/tmp/console.txt --log /data/local/tmp/log.txt
Check that all logs (except for those from init and kernel) are in
log.txt.
Change-Id: I06ea1a6ee3732eb9eafe7794b9dfdcc34f5c1f83
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index 596b1af..bacdee1 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -165,42 +165,13 @@
}
#ifdef __ANDROID__
-static const char* get_file_logger_path() {
- static const char* file_logger_path = []() {
- static char path[PROP_VALUE_MAX] = {};
- if (__system_property_get("ro.log.file_logger.path", path) > 0) {
- return path;
- }
- return (char*)nullptr; // means file_logger should not be used
- }();
- return file_logger_path;
-}
-#endif
-
-static void file_logger(const struct __android_log_message* log_message);
-
-static __android_logger_function user_set_logger_function = nullptr;
-
-static __android_logger_function get_logger_function() {
- if (user_set_logger_function != nullptr) {
- return user_set_logger_function;
- }
- static __android_logger_function default_logger_function = []() {
-#if __ANDROID__
- if (get_file_logger_path() != nullptr) {
- return file_logger;
- } else {
- return __android_log_logd_logger;
- }
+static __android_logger_function logger_function = __android_log_logd_logger;
#else
- return file_logger;
+static __android_logger_function logger_function = __android_log_stderr_logger;
#endif
- }();
- return default_logger_function;
-}
void __android_log_set_logger(__android_logger_function logger) {
- user_set_logger_function = logger;
+ logger_function = logger;
}
void __android_log_default_aborter(const char* abort_message) {
@@ -312,30 +283,50 @@
}
}
-static void file_logger(const struct __android_log_message* log_message) {
- static FILE* stream = []() {
+static const char* get_file_logger_path() {
#ifdef __ANDROID__
- const char* file_logger_path = get_file_logger_path();
- if (file_logger_path != nullptr) {
- FILE* f = fopen(file_logger_path, "ae");
- if (f != nullptr) return f;
- using namespace std::string_literals;
- std::string err_msg = "Cannot open "s + file_logger_path + " for logging: (" + strerror(errno) +
- "). Falling back to stderr";
- __android_log_message m = {sizeof(__android_log_message),
- LOG_ID_DEFAULT,
- ANDROID_LOG_WARN,
- "liblog",
- __FILE__,
- __LINE__,
- err_msg.c_str()};
- filestream_logger(&m, stderr);
+ static const char* file_logger_path = []() {
+ static char path[PROP_VALUE_MAX] = {};
+ if (__system_property_get("ro.log.file_logger.path", path) > 0) {
+ return path;
}
+ return static_cast<char*>(nullptr); // means file_logger should not be used
+ }();
+ return file_logger_path;
+#else
+ return nullptr;
#endif
- // defaults to stderr if the sysprop is not set or the file is not available
+}
+
+/*
+ * If ro.log.file_logger.path is set to a file, send log_message to the file instead. This is for
+ * Android-like environments where logd is not available; e.g. Microdroid. If the file is not
+ * accessible (but ro.log.file_logger.path is set anyway), stderr is chosen as the fallback.
+ *
+ * Returns true if log was sent to file. false, if not.
+ */
+static bool log_to_file_if_overridden(const struct __android_log_message* log_message) {
+ const char* file_logger_path = get_file_logger_path();
+ if (file_logger_path == nullptr) return false;
+
+ static FILE* stream = [&file_logger_path]() {
+ FILE* f = fopen(file_logger_path, "ae");
+ if (f != nullptr) return f;
+ using namespace std::string_literals;
+ std::string err_msg = "Cannot open "s + file_logger_path + " for logging: (" + strerror(errno) +
+ "). Falling back to stderr";
+ __android_log_message m = {sizeof(__android_log_message),
+ LOG_ID_DEFAULT,
+ ANDROID_LOG_WARN,
+ "liblog",
+ __FILE__,
+ __LINE__,
+ err_msg.c_str()};
+ filestream_logger(&m, stderr);
return stderr;
}();
filestream_logger(log_message, stream);
+ return true;
}
void __android_log_stderr_logger(const struct __android_log_message* log_message) {
@@ -343,6 +334,8 @@
}
void __android_log_logd_logger(const struct __android_log_message* log_message) {
+ if (log_to_file_if_overridden(log_message)) return;
+
int buffer_id = log_message->buffer_id == LOG_ID_DEFAULT ? LOG_ID_MAIN : log_message->buffer_id;
struct iovec vec[3];
@@ -380,7 +373,7 @@
}
#endif
- get_logger_function()(log_message);
+ logger_function(log_message);
}
int __android_log_buf_write(int bufID, int prio, const char* tag, const char* msg) {