Starts a host process to receive logcat output over vsock
The host process is started conditionally on the logcat_mode launcher
flag (when set to 'vsock'). The process accepts connections (one at a
time) on a vsock socket and forwards everything to the logcat file in
the instance directory.
Bug: 124535805
Test: run locally
Change-Id: I2dbff42735a9dc16079e8adb5862ead3c7581de4
diff --git a/host/commands/launch/flags.cc b/host/commands/launch/flags.cc
index 797c1ea..4548588 100644
--- a/host/commands/launch/flags.cc
+++ b/host/commands/launch/flags.cc
@@ -172,7 +172,13 @@
DEFINE_string(e2e_test_binary,
vsoc::DefaultHostArtifactsPath("bin/host_region_e2e_test"),
"Location of the region end to end test binary");
-
+DEFINE_string(logcat_receiver_binary,
+ vsoc::DefaultHostArtifactsPath("bin/logcat_receiver"),
+ "Binary for the logcat server");
+DEFINE_string(logcat_mode, "", "How to send android's log messages from "
+ "guest to host. One of [serial, vsock]");
+DEFINE_int32(logcat_vsock_port, vsoc::GetPerInstanceDefault(5620),
+ "The port for logcat over vsock");
namespace {
template<typename S, typename T>
@@ -297,6 +303,10 @@
tmp_config_obj.add_kernel_cmdline(
concat("androidboot.hardware=", FLAGS_hardware_name));
}
+ if (FLAGS_logcat_mode == cvd::kLogcatVsockMode) {
+ tmp_config_obj.add_kernel_cmdline(concat("androidboot.vsock_logcat_port=",
+ FLAGS_logcat_vsock_port));
+ }
tmp_config_obj.set_hardware_name(FLAGS_hardware_name);
if (!FLAGS_guest_security.empty()) {
tmp_config_obj.add_kernel_cmdline(concat("security=", FLAGS_guest_security));
@@ -344,6 +354,7 @@
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"));
+ tmp_config_obj.set_logcat_receiver_binary(FLAGS_logcat_receiver_binary);
tmp_config_obj.set_launcher_log_path(tmp_config_obj.PerInstancePath("launcher.log"));
tmp_config_obj.set_launcher_monitor_socket_path(
tmp_config_obj.PerInstancePath("launcher_monitor.sock"));
@@ -396,6 +407,9 @@
tmp_config_obj.disable_usb_adb();
}
+ tmp_config_obj.set_logcat_mode(FLAGS_logcat_mode);
+ tmp_config_obj.set_logcat_vsock_port(FLAGS_logcat_vsock_port);
+
tmp_config_obj.set_cuttlefish_env_path(GetCuttlefishEnvPath());
auto config_file = GetConfigFilePath(tmp_config_obj);
@@ -444,6 +458,8 @@
google::FlagSettingMode::SET_FLAGS_DEFAULT);
SetCommandLineOptionWithMode("decompress_kernel", "false",
google::FlagSettingMode::SET_FLAGS_DEFAULT);
+ SetCommandLineOptionWithMode("logcat_mode", cvd::kLogcatSerialMode,
+ google::FlagSettingMode::SET_FLAGS_DEFAULT);
}
void SetDefaultFlagsForCrosvm() {
@@ -481,6 +497,8 @@
google::FlagSettingMode::SET_FLAGS_DEFAULT);
SetCommandLineOptionWithMode("start_stream_audio", "false",
google::FlagSettingMode::SET_FLAGS_DEFAULT);
+ SetCommandLineOptionWithMode("logcat_mode", cvd::kLogcatVsockMode,
+ google::FlagSettingMode::SET_FLAGS_DEFAULT);
}
bool ParseCommandLineFlags(int* argc, char*** argv) {
diff --git a/host/commands/launch/launch.cc b/host/commands/launch/launch.cc
index 4bf3db9..497b6c4 100644
--- a/host/commands/launch/launch.cc
+++ b/host/commands/launch/launch.cc
@@ -83,6 +83,10 @@
return vsoc::GetPerInstanceDefault(kFirstHostPort);
}
+bool LogcatReceiverEnabled(const vsoc::CuttlefishConfig& config) {
+ return config.logcat_mode() == cvd::kLogcatVsockMode;
+}
+
bool AdbUsbEnabled(const vsoc::CuttlefishConfig& config) {
return AdbModeEnabled(config, kAdbModeUsb);
}
@@ -141,6 +145,24 @@
return kernel_log_monitor;
}
+void LaunchLogcatReceiverIfEnabled(const vsoc::CuttlefishConfig& config,
+ cvd::ProcessMonitor* process_monitor) {
+ if (!LogcatReceiverEnabled(config)) {
+ return;
+ }
+ auto port = config.logcat_vsock_port();
+ auto socket = cvd::SharedFD::VsockServer(port, SOCK_STREAM);
+ if (!socket->IsOpen()) {
+ LOG(ERROR) << "Unable to create logcat server socket: "
+ << socket->StrError();
+ std::exit(LauncherExitCodes::kLogcatServerError);
+ }
+ cvd::Command cmd(config.logcat_receiver_binary());
+ cmd.AddParameter("-server_fd=", socket);
+ process_monitor->StartSubprocess(std::move(cmd),
+ GetOnSubprocessExitCallback(config));
+}
+
void LaunchUsbServerIfEnabled(const vsoc::CuttlefishConfig& config,
cvd::ProcessMonitor* process_monitor) {
if (!AdbUsbEnabled(config)) {
diff --git a/host/commands/launch/launch.h b/host/commands/launch/launch.h
index 02f3a38..550ce02 100644
--- a/host/commands/launch/launch.h
+++ b/host/commands/launch/launch.h
@@ -13,6 +13,8 @@
cvd::Command GetIvServerCommand(const vsoc::CuttlefishConfig& config);
cvd::Command GetKernelLogMonitorCommand(const vsoc::CuttlefishConfig& config,
cvd::SharedFD* boot_events_pipe);
+void LaunchLogcatReceiverIfEnabled(const vsoc::CuttlefishConfig& config,
+ cvd::ProcessMonitor* process_monitor);
void LaunchUsbServerIfEnabled(const vsoc::CuttlefishConfig& config,
cvd::ProcessMonitor* process_monitor);
void LaunchVNCServerIfEnabled(const vsoc::CuttlefishConfig& config,
diff --git a/host/commands/launch/launcher_defs.h b/host/commands/launch/launcher_defs.h
index ccf859c..9a78a4e 100644
--- a/host/commands/launch/launcher_defs.h
+++ b/host/commands/launch/launcher_defs.h
@@ -17,6 +17,9 @@
namespace cvd {
+constexpr char kLogcatSerialMode[] = "serial";
+constexpr char kLogcatVsockMode[] = "vsock";
+
enum LauncherExitCodes : int {
kSuccess = 0,
kArgumentParsingError = 1,
@@ -36,6 +39,7 @@
kUsbV1SocketError = 15,
kE2eTestFailed = 16,
kKernelDecompressError = 17,
+ kLogcatServerError = 18,
};
// Actions supported by the launcher server
diff --git a/host/commands/launch/main.cc b/host/commands/launch/main.cc
index 639a364..ff2c7dd 100644
--- a/host/commands/launch/main.cc
+++ b/host/commands/launch/main.cc
@@ -424,6 +424,8 @@
SetUpHandlingOfBootEvents(&process_monitor, boot_events_pipe,
boot_state_machine);
+ LaunchLogcatReceiverIfEnabled(*config, &process_monitor);
+
LaunchUsbServerIfEnabled(*config, &process_monitor);
LaunchIvServerIfEnabled(&process_monitor, *config);
diff --git a/host/commands/logcat_receiver/Android.bp b/host/commands/logcat_receiver/Android.bp
new file mode 100644
index 0000000..16f3bf9
--- /dev/null
+++ b/host/commands/logcat_receiver/Android.bp
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2019 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.
+
+cc_binary_host {
+ name: "logcat_receiver",
+ srcs: [
+ "main.cpp",
+ ],
+ header_libs: [
+ "cuttlefish_glog",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcuttlefish_fs",
+ "liblog",
+ "libcuttlefish_utils",
+ "cuttlefish_auto_resources",
+ ],
+ static_libs: [
+ "libcuttlefish_host_config",
+ "libgflags",
+ "libjsoncpp",
+ ],
+ defaults: ["cuttlefish_host_only"],
+}
diff --git a/host/commands/logcat_receiver/main.cpp b/host/commands/logcat_receiver/main.cpp
new file mode 100644
index 0000000..e9cbad2
--- /dev/null
+++ b/host/commands/logcat_receiver/main.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include <gflags/gflags.h>
+#include <glog/logging.h>
+
+#include "common/libs/fs/shared_fd.h"
+#include "host/libs/config/cuttlefish_config.h"
+
+DEFINE_int32(
+ server_fd, -1,
+ "File descriptor to an already created vsock server. If negative a new "
+ "server will be created at the port specified on the config file");
+
+int main(int argc, char** argv) {
+ ::android::base::InitLogging(argv, android::base::StderrLogger);
+ google::ParseCommandLineFlags(&argc, &argv, true);
+
+ auto config = vsoc::CuttlefishConfig::Get();
+
+ auto path = config->logcat_path();
+ auto logcat_file =
+ cvd::SharedFD::Open(path.c_str(), O_CREAT | O_APPEND | O_WRONLY, 0666);
+ CHECK(logcat_file->IsOpen())
+ << "Unable to open logcat file: " << logcat_file->StrError();
+
+ cvd::SharedFD server_fd;
+ if (FLAGS_server_fd < 0) {
+ unsigned int port = config->logcat_vsock_port();
+ server_fd = cvd::SharedFD::VsockServer(port, SOCK_STREAM);
+ } else {
+ server_fd = cvd::SharedFD::Dup(FLAGS_server_fd);
+ close(FLAGS_server_fd);
+ }
+
+ CHECK(server_fd->IsOpen()) << "Error creating or inheriting logcat server: "
+ << server_fd->StrError();
+
+ // Server loop
+ while (true) {
+ auto conn = cvd::SharedFD::Accept(*server_fd);
+
+ while (true) {
+ char buff[1024];
+ auto read = conn->Read(buff, sizeof(buff));
+ if (read <= 0) {
+ // Close here to ensure the other side gets reset if it's still
+ // connected
+ conn->Close();
+ LOG(WARNING) << "Detected close from the other side";
+ break;
+ }
+ auto written = logcat_file->Write(buff, read);
+ CHECK(written == read)
+ << "Error writing to log file: " << logcat_file->StrError()
+ << ". This is unrecoverable.";
+ }
+ }
+ return 0;
+}
\ No newline at end of file
diff --git a/host/libs/config/cuttlefish_config.cpp b/host/libs/config/cuttlefish_config.cpp
index b77e03d..3940739 100644
--- a/host/libs/config/cuttlefish_config.cpp
+++ b/host/libs/config/cuttlefish_config.cpp
@@ -152,6 +152,10 @@
const char* kDataPolicy = "data_policy";
const char* kBlankDataImageMb = "blank_data_image_mb";
const char* kBlankDataImageFmt = "blank_data_image_fmt";
+
+const char* kLogcatMode = "logcat_mode";
+const char* kLogcatVsockPort = "logcat_vsock_mode";
+const char* kLogcatReceiverBinary = "logcat_receiver_binary";
} // namespace
namespace vsoc {
@@ -760,6 +764,31 @@
}
+void CuttlefishConfig::set_logcat_mode(const std::string& mode) {
+ (*dictionary_)[kLogcatMode] = mode;
+}
+
+std::string CuttlefishConfig::logcat_mode() const {
+ return (*dictionary_)[kLogcatMode].asString();
+}
+
+void CuttlefishConfig::set_logcat_vsock_port(int port) {
+ (*dictionary_)[kLogcatVsockPort] = port;
+}
+
+int CuttlefishConfig::logcat_vsock_port() const {
+ return (*dictionary_)[kLogcatVsockPort].asInt();
+}
+
+void CuttlefishConfig::set_logcat_receiver_binary(const std::string& binary) {
+ SetPath(kLogcatReceiverBinary, binary);
+}
+
+std::string CuttlefishConfig::logcat_receiver_binary() const {
+ return (*dictionary_)[kLogcatReceiverBinary].asString();
+}
+
+
bool CuttlefishConfig::enable_ivserver() const {
return hardware_name() == "vsoc";
}
diff --git a/host/libs/config/cuttlefish_config.h b/host/libs/config/cuttlefish_config.h
index 451f4a3..933cdca 100644
--- a/host/libs/config/cuttlefish_config.h
+++ b/host/libs/config/cuttlefish_config.h
@@ -175,6 +175,9 @@
std::string logcat_path() const;
void set_logcat_path(const std::string& logcat_path);
+ std::string logcat_receiver_binary() const;
+ void set_logcat_receiver_binary(const std::string& binary);
+
std::string launcher_log_path() const;
void set_launcher_log_path(const std::string& launcher_log_path);
@@ -293,6 +296,12 @@
void set_blank_data_image_fmt(const std::string& blank_data_image_fmt);
std::string blank_data_image_fmt() const;
+ void set_logcat_mode(const std::string& mode);
+ std::string logcat_mode() const;
+
+ void set_logcat_vsock_port(int port);
+ int logcat_vsock_port() const;
+
bool enable_ivserver() const;
private:
diff --git a/host/libs/vm_manager/cf_qemu.sh b/host/libs/vm_manager/cf_qemu.sh
index 166c4e7..45224cf 100755
--- a/host/libs/vm_manager/cf_qemu.sh
+++ b/host/libs/vm_manager/cf_qemu.sh
@@ -184,12 +184,17 @@
-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"
- -chardev "file,id=charchannel0,path=${logcat_path:-${default_dir}/logcat},append=on"
- -device "virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=cf-logcat"
-chardev "socket,path=${ivshmem_qemu_socket_path:-${default_dir}/ivshmem_socket_qemu},id=ivsocket"
-device "ivshmem-doorbell,chardev=ivsocket,vectors=${ivshmem_vector_count}"
)
+if [[ "${logcat_mode}" == "serial" ]]; then
+ args+=(
+ -chardev "file,id=charchannel0,path=${logcat_path:-${default_dir}/logcat},append=on"
+ -device "virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=cf-logcat"
+ )
+fi
+
if [[ -n "${gdb_flag}" ]]; then
args+=(-gdb "${gdb_flag}")
fi
diff --git a/host/libs/vm_manager/qemu_manager.cpp b/host/libs/vm_manager/qemu_manager.cpp
index 751c68c..33d9d44 100644
--- a/host/libs/vm_manager/qemu_manager.cpp
+++ b/host/libs/vm_manager/qemu_manager.cpp
@@ -87,6 +87,7 @@
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());
cvd::Command qemu_cmd(vsoc::DefaultHostArtifactsPath("bin/cf_qemu.sh"));
return qemu_cmd;