Use a FIFO instead of a socket for kernel logs

Once created, FIFOs are opened just like any other file, which will
allow crosvm to use it directly with a --serial option.

Bug: 134435388
Test: local
Change-Id: Ia837eedfb2e0f7a600b85a36f921b808df8bc97e
diff --git a/host/commands/kernel_log_monitor/kernel_log_server.cc b/host/commands/kernel_log_monitor/kernel_log_server.cc
index 84b2694..f8ceb94 100644
--- a/host/commands/kernel_log_monitor/kernel_log_server.cc
+++ b/host/commands/kernel_log_monitor/kernel_log_server.cc
@@ -66,25 +66,20 @@
 }  // namespace
 
 namespace monitor {
-KernelLogServer::KernelLogServer(cvd::SharedFD server_socket,
+KernelLogServer::KernelLogServer(cvd::SharedFD pipe_fd,
                                  const std::string& log_name,
                                  bool deprecated_boot_completed)
-    : server_fd_(server_socket),
+    : pipe_fd_(pipe_fd),
       log_fd_(cvd::SharedFD::Open(log_name.c_str(), O_CREAT | O_RDWR, 0666)),
       deprecated_boot_completed_(deprecated_boot_completed) {}
 
 void KernelLogServer::BeforeSelect(cvd::SharedFDSet* fd_read) const {
-  if (!client_fd_->IsOpen()) fd_read->Set(server_fd_);
-  if (client_fd_->IsOpen()) fd_read->Set(client_fd_);
+  fd_read->Set(pipe_fd_);
 }
 
 void KernelLogServer::AfterSelect(const cvd::SharedFDSet& fd_read) {
-  if (fd_read.IsSet(server_fd_)) HandleIncomingConnection();
-
-  if (client_fd_->IsOpen() && fd_read.IsSet(client_fd_)) {
-    if (!HandleIncomingMessage()) {
-      client_fd_->Close();
-    }
+  if (fd_read.IsSet(pipe_fd_)) {
+    HandleIncomingMessage();
   }
 }
 
@@ -93,29 +88,12 @@
   subscribers_.push_back(callback);
 }
 
-// Accept new kernel log connection.
-void KernelLogServer::HandleIncomingConnection() {
-  if (client_fd_->IsOpen()) {
-    LOG(ERROR) << "Client already connected. No longer accepting connection.";
-    return;
-  }
-
-  client_fd_ = SharedFD::Accept(*server_fd_, nullptr, nullptr);
-  if (!client_fd_->IsOpen()) {
-    LOG(ERROR) << "Client connection failed: " << client_fd_->StrError();
-    return;
-  }
-  if (client_fd_->Fcntl(F_SETFL, O_NONBLOCK) == -1) {
-    LOG(ERROR) << "Client connection refused O_NONBLOCK: " << client_fd_->StrError();
-  }
-}
-
 bool KernelLogServer::HandleIncomingMessage() {
   const size_t buf_len = 256;
   char buf[buf_len];
-  ssize_t ret = client_fd_->Read(buf, buf_len);
+  ssize_t ret = pipe_fd_->Read(buf, buf_len);
   if (ret < 0) {
-    LOG(ERROR) << "Could not read from QEmu serial port: " << client_fd_->StrError();
+    LOG(ERROR) << "Could not read kernel logs: " << pipe_fd_->StrError();
     return false;
   }
   if (ret == 0) return false;
diff --git a/host/commands/kernel_log_monitor/kernel_log_server.h b/host/commands/kernel_log_monitor/kernel_log_server.h
index f71ebb7..f5709ee 100644
--- a/host/commands/kernel_log_monitor/kernel_log_server.h
+++ b/host/commands/kernel_log_monitor/kernel_log_server.h
@@ -46,7 +46,7 @@
 // one connection.
 class KernelLogServer {
  public:
-  KernelLogServer(cvd::SharedFD server_socket,
+  KernelLogServer(cvd::SharedFD pipe_fd,
                   const std::string& log_name,
                   bool deprecated_boot_completed);
 
@@ -62,15 +62,11 @@
 
   void SubscribeToBootEvents(BootEventCallback callback);
  private:
-  // Handle new client connection. Only accept one connection.
-  void HandleIncomingConnection();
-
   // Respond to message from remote client.
   // Returns false, if client disconnected.
   bool HandleIncomingMessage();
 
-  cvd::SharedFD server_fd_;
-  cvd::SharedFD client_fd_;
+  cvd::SharedFD pipe_fd_;
   cvd::SharedFD log_fd_;
   std::string line_;
   bool deprecated_boot_completed_;
diff --git a/host/commands/kernel_log_monitor/main.cc b/host/commands/kernel_log_monitor/main.cc
index a17b1b8..1f0ead3 100644
--- a/host/commands/kernel_log_monitor/main.cc
+++ b/host/commands/kernel_log_monitor/main.cc
@@ -29,7 +29,7 @@
 #include <host/libs/config/cuttlefish_config.h>
 #include "host/commands/kernel_log_monitor/kernel_log_server.h"
 
-DEFINE_int32(log_server_fd, -1,
+DEFINE_int32(log_pipe_fd, -1,
              "A file descriptor representing a (UNIX) socket from which to "
              "read the logs. If -1 is given the socket is created according to "
              "the instance configuration");
@@ -77,22 +77,21 @@
     return 1;
   }
 
-  cvd::SharedFD server;
-  if (FLAGS_log_server_fd < 0) {
-    auto log_name = config->kernel_log_socket_name();
-    server = cvd::SharedFD::SocketLocalServer(log_name.c_str(), false,
-                                              SOCK_STREAM, 0666);
+  cvd::SharedFD pipe;
+  if (FLAGS_log_pipe_fd < 0) {
+    auto log_name = config->kernel_log_pipe_name();
+    pipe = cvd::SharedFD::Open(log_name.c_str(), O_RDONLY);
   } else {
-    server = cvd::SharedFD::Dup(FLAGS_log_server_fd);
-    close(FLAGS_log_server_fd);
+    pipe = cvd::SharedFD::Dup(FLAGS_log_pipe_fd);
+    close(FLAGS_log_pipe_fd);
   }
 
-  if (!server->IsOpen()) {
-    LOG(ERROR) << "Error opening log server: " << server->StrError();
+  if (!pipe->IsOpen()) {
+    LOG(ERROR) << "Error opening log pipe: " << pipe->StrError();
     return 2;
   }
 
-  monitor::KernelLogServer klog{server, config->PerInstancePath("kernel.log"),
+  monitor::KernelLogServer klog{pipe, config->PerInstancePath("kernel.log"),
                                 config->deprecated_boot_completed()};
 
   for (auto subscriber_fd: subscriber_fds) {
diff --git a/host/commands/launch/flags.cc b/host/commands/launch/flags.cc
index 105741b..d16eb0e 100644
--- a/host/commands/launch/flags.cc
+++ b/host/commands/launch/flags.cc
@@ -452,7 +452,7 @@
     tmp_config_obj.set_usb_ip_socket_name(tmp_config_obj.PerInstancePath("usb-ip"));
   }
 
-  tmp_config_obj.set_kernel_log_socket_name(tmp_config_obj.PerInstancePath("kernel-log"));
+  tmp_config_obj.set_kernel_log_pipe_name(tmp_config_obj.PerInstancePath("kernel-log"));
   tmp_config_obj.set_deprecated_boot_completed(FLAGS_deprecated_boot_completed);
   tmp_config_obj.set_console_path(tmp_config_obj.PerInstancePath("console"));
   tmp_config_obj.set_logcat_path(tmp_config_obj.PerInstancePath("logcat"));
diff --git a/host/commands/launch/launch.cc b/host/commands/launch/launch.cc
index e8367b3..75387f0 100644
--- a/host/commands/launch/launch.cc
+++ b/host/commands/launch/launch.cc
@@ -1,5 +1,8 @@
 #include "host/commands/launch/launch.h"
 
+#include <sys/types.h>
+#include <sys/stat.h>
+
 #include <glog/logging.h>
 
 #include "common/libs/fs/shared_fd.h"
@@ -130,11 +133,20 @@
     const vsoc::CuttlefishConfig& config,
     cvd::ProcessMonitor* process_monitor,
     unsigned int number_of_event_pipes) {
-  auto log_name = config.kernel_log_socket_name();
-  auto server = cvd::SharedFD::SocketLocalServer(log_name.c_str(), false,
-                                                 SOCK_STREAM, 0666);
+  auto log_name = config.kernel_log_pipe_name();
+  if (mkfifo(log_name.c_str(), 0600) != 0) {
+    LOG(ERROR) << "Unable to create named pipe at " << log_name << ": "
+               << strerror(errno);
+    return {};
+  }
+
+  cvd::SharedFD pipe;
+  // Open the pipe here (from the launcher) to ensure the pipe is not deleted
+  // due to the usage counters in the kernel reaching zero. If this is not done
+  // and the kernel_log_monitor crashes for some reason the VMM may get SIGPIPE.
+  pipe = cvd::SharedFD::Open(log_name.c_str(), O_RDWR);
   cvd::Command command(config.kernel_log_monitor_binary());
-  command.AddParameter("-log_server_fd=", server);
+  command.AddParameter("-log_pipe_fd=", pipe);
 
   std::vector<cvd::SharedFD> ret;
 
diff --git a/host/libs/config/cuttlefish_config.cpp b/host/libs/config/cuttlefish_config.cpp
index 34df60e..bfd8633 100644
--- a/host/libs/config/cuttlefish_config.cpp
+++ b/host/libs/config/cuttlefish_config.cpp
@@ -102,7 +102,7 @@
 const char* kUsbV1SocketName = "usb_v1_socket_name";
 const char* kVhciPort = "vhci_port";
 const char* kUsbIpSocketName = "usb_ip_socket_name";
-const char* kKernelLogSocketName = "kernel_log_socket_name";
+const char* kKernelLogPipeName = "kernel_log_pipe_name";
 const char* kDeprecatedBootCompleted = "deprecated_boot_completed";
 const char* kConsolePath = "console_path";
 const char* kLogcatPath = "logcat_path";
@@ -495,12 +495,12 @@
   (*dictionary_)[kUsbIpSocketName] = usb_ip_socket_name;
 }
 
-std::string CuttlefishConfig::kernel_log_socket_name() const {
-  return (*dictionary_)[kKernelLogSocketName].asString();
+std::string CuttlefishConfig::kernel_log_pipe_name() const {
+  return (*dictionary_)[kKernelLogPipeName].asString();
 }
-void CuttlefishConfig::set_kernel_log_socket_name(
-    const std::string& kernel_log_socket_name) {
-  (*dictionary_)[kKernelLogSocketName] = kernel_log_socket_name;
+void CuttlefishConfig::set_kernel_log_pipe_name(
+    const std::string& kernel_log_pipe_name) {
+  (*dictionary_)[kKernelLogPipeName] = kernel_log_pipe_name;
 }
 
 bool CuttlefishConfig::deprecated_boot_completed() const {
diff --git a/host/libs/config/cuttlefish_config.h b/host/libs/config/cuttlefish_config.h
index 74118b1..9d591ac 100644
--- a/host/libs/config/cuttlefish_config.h
+++ b/host/libs/config/cuttlefish_config.h
@@ -193,8 +193,8 @@
   std::string usb_ip_socket_name() const;
   void set_usb_ip_socket_name(const std::string& usb_ip_socket_name);
 
-  std::string kernel_log_socket_name() const;
-  void set_kernel_log_socket_name(const std::string& kernel_log_socket_name);
+  std::string kernel_log_pipe_name() const;
+  void set_kernel_log_pipe_name(const std::string& kernel_log_pipe_name);
 
   bool deprecated_boot_completed() const;
   void set_deprecated_boot_completed(bool deprecated_boot_completed);
diff --git a/host/libs/vm_manager/cf_qemu.sh b/host/libs/vm_manager/cf_qemu.sh
index 3556303..e81e1de 100755
--- a/host/libs/vm_manager/cf_qemu.sh
+++ b/host/libs/vm_manager/cf_qemu.sh
@@ -212,7 +212,7 @@
 args+=(
     -chardev "socket,id=charmonitor,path=${monitor_path:-${default_dir}/qemu_monitor.sock},server,nowait"
     -mon "chardev=charmonitor,id=monitor,mode=control"
-    -chardev "socket,id=charserial0,path=${kernel_log_socket_name:-${default_dir}/kernel-log}"
+    -chardev "file,id=charserial0,path=${kernel_log_pipe_name:-${default_dir}/kernel-log},append=on"
     -device "${kernel_console_serial},chardev=charserial0,id=serial0"
     -chardev "socket,id=charserial1,path=${console_path:-${default_dir}/console},server,nowait"
     -device "pci-serial,chardev=charserial1,id=serial1"
diff --git a/host/libs/vm_manager/crosvm_manager.cpp b/host/libs/vm_manager/crosvm_manager.cpp
index ef0645f..6aa13af 100644
--- a/host/libs/vm_manager/crosvm_manager.cpp
+++ b/host/libs/vm_manager/crosvm_manager.cpp
@@ -36,8 +36,7 @@
 }
 
 cvd::SharedFD ConnectToLogMonitor(const std::string& log_monitor_name) {
-  return cvd::SharedFD::SocketLocalClient(log_monitor_name.c_str(), false,
-                                          SOCK_STREAM);
+  return cvd::SharedFD::Open(log_monitor_name.c_str(), O_WRONLY);
 }
 
 void AddTapFdParameter(cvd::Command* crosvm_cmd, const std::string& tap_name) {
@@ -146,7 +145,7 @@
   }
 
   auto kernel_log_connection =
-      ConnectToLogMonitor(config_->kernel_log_socket_name());
+      ConnectToLogMonitor(config_->kernel_log_pipe_name());
   if (!kernel_log_connection->IsOpen()) {
     LOG(WARNING) << "Unable to connect to log monitor: "
                  << kernel_log_connection->StrError();
diff --git a/host/libs/vm_manager/qemu_manager.cpp b/host/libs/vm_manager/qemu_manager.cpp
index 36deff1..09ec4a2 100644
--- a/host/libs/vm_manager/qemu_manager.cpp
+++ b/host/libs/vm_manager/qemu_manager.cpp
@@ -109,14 +109,14 @@
   LogAndSetEnv("composite_disk_path", config_->composite_disk_path());
   LogAndSetEnv("wifi_tap_name", config_->wifi_tap_name());
   LogAndSetEnv("mobile_tap_name", config_->mobile_tap_name());
-  LogAndSetEnv("kernel_log_socket_name",
-                      config_->kernel_log_socket_name());
+  LogAndSetEnv("kernel_log_pipe_name",
+               config_->kernel_log_pipe_name());
   LogAndSetEnv("console_path", config_->console_path());
   LogAndSetEnv("logcat_path", config_->logcat_path());
   LogAndSetEnv("ivshmem_qemu_socket_path",
-                      config_->ivshmem_qemu_socket_path());
+               config_->ivshmem_qemu_socket_path());
   LogAndSetEnv("ivshmem_vector_count",
-                      std::to_string(config_->ivshmem_vector_count()));
+               std::to_string(config_->ivshmem_vector_count()));
   LogAndSetEnv("usb_v1_socket_name", config_->usb_v1_socket_name());
   LogAndSetEnv("vsock_guest_cid", std::to_string(config_->vsock_guest_cid()));
   LogAndSetEnv("logcat_mode", config_->logcat_mode());