Merge changes from topic "no_logd"

* changes:
  Remove logd.microdroid and logcat.microdroid
  Default logger can be configured via sysprops

GitOrigin-RevId: 1a94375a953d64f10f051ac9de468b9883ac2a0c
Change-Id: Ide9b5515bacaaf30de697bfc7e3f4ae940d6963a
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index 9a9a126..a8d85db 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -52,6 +52,14 @@
 #include <windows.h>
 #endif
 
+// The preferred way to access system properties is using android::base::GetProperty in libbase.
+// However, adding dependency to libbase requires that if liblog was statically linked to a client,
+// that client now has additional dependency to libbase as well because static dependencies of
+// static library is not exported. (users of liblog.so however is fine).
+#ifdef __ANDROID__
+#include <sys/system_properties.h>
+#endif
+
 using android::base::ErrnoRestorer;
 
 #define LOG_BUF_SIZE 1024
@@ -157,11 +165,29 @@
 }
 
 #ifdef __ANDROID__
-static __android_logger_function logger_function = __android_log_logd_logger;
-#else
-static __android_logger_function logger_function = __android_log_stderr_logger;
+static 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
+}();
 #endif
 
+static void file_logger(const struct __android_log_message* log_message);
+
+static __android_logger_function logger_function = []() {
+#if __ANDROID__
+  if (file_logger_path != nullptr) {
+    return file_logger;
+  } else {
+    return __android_log_logd_logger;
+  }
+#else
+  return file_logger;
+#endif
+}();
+
 void __android_log_set_logger(__android_logger_function logger) {
   logger_function = logger;
 }
@@ -243,7 +269,7 @@
 #endif
 }
 
-void __android_log_stderr_logger(const struct __android_log_message* log_message) {
+static void filestream_logger(const struct __android_log_message* log_message, FILE* stream) {
   struct tm now;
   time_t t = time(nullptr);
 
@@ -265,16 +291,45 @@
   uint64_t tid = GetThreadId();
 
   if (log_message->file != nullptr) {
-    fprintf(stderr, "%s %c %s %5d %5" PRIu64 " %s:%u] %s\n",
+    fprintf(stream, "%s %c %s %5d %5" PRIu64 " %s:%u] %s\n",
             log_message->tag ? log_message->tag : "nullptr", priority_char, timestamp, getpid(),
             tid, log_message->file, log_message->line, log_message->message);
   } else {
-    fprintf(stderr, "%s %c %s %5d %5" PRIu64 "] %s\n",
+    fprintf(stream, "%s %c %s %5d %5" PRIu64 "] %s\n",
             log_message->tag ? log_message->tag : "nullptr", priority_char, timestamp, getpid(),
             tid, log_message->message);
   }
 }
 
+static void file_logger(const struct __android_log_message* log_message) {
+  static FILE* stream = []() {
+#ifdef __ANDROID__
+    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);
+    }
+#endif
+    // defaults to stderr if the sysprop is not set or the file is not available
+    return stderr;
+  }();
+  filestream_logger(log_message, stream);
+}
+
+void __android_log_stderr_logger(const struct __android_log_message* log_message) {
+  filestream_logger(log_message, stderr);
+}
+
 void __android_log_logd_logger(const struct __android_log_message* log_message) {
   int buffer_id = log_message->buffer_id == LOG_ID_DEFAULT ? LOG_ID_MAIN : log_message->buffer_id;