Run the ivserver in its own process, independent of the launcher

Bug: 110532566
Test: run locally and on gce
Change-Id: I70dc3a00459b87337cb78d35d22b2b3a84803c2c
Merged-In: I70dc3a00459b87337cb78d35d22b2b3a84803c2c
(cherry picked from commit c114f963879f43914dbfd012976d8758685ec68a)
diff --git a/host/commands/Android.bp b/host/commands/Android.bp
index 1680f9b..30187b9 100644
--- a/host/commands/Android.bp
+++ b/host/commands/Android.bp
@@ -16,5 +16,6 @@
 subdirs = [
     "launch",
     "stop_cvd",
+    "ivserver",
     "record_audio",
 ]
diff --git a/host/commands/ivserver/Android.bp b/host/commands/ivserver/Android.bp
new file mode 100644
index 0000000..a537742
--- /dev/null
+++ b/host/commands/ivserver/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2018 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: "ivserver",
+    srcs: [
+        "main.cpp",
+    ],
+    header_libs: [
+        "cuttlefish_glog",
+    ],
+    shared_libs: [
+        "vsoc_lib",
+        "libbase",
+        "libcuttlefish_fs",
+        "libcuttlefish_utils",
+        "cuttlefish_auto_resources",
+        "liblog",
+    ],
+    static_libs: [
+        "libcuttlefish_host_config",
+        "libivserver",
+        "libgflags",
+        "libjsoncpp",
+    ],
+    defaults: ["cuttlefish_host_only"],
+}
diff --git a/host/commands/ivserver/main.cpp b/host/commands/ivserver/main.cpp
new file mode 100644
index 0000000..3ad5ed4
--- /dev/null
+++ b/host/commands/ivserver/main.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2017 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 <unistd.h>
+
+#include <thread>
+
+#include <gflags/gflags.h>
+#include <glog/logging.h>
+
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/ivserver/ivserver.h"
+#include "host/libs/ivserver/options.h"
+
+DEFINE_int32(
+    qemu_socket_fd, -1,
+    "A file descriptor to use as the server Qemu connects to. If not specified "
+    "a unix socket will be created in the default location.");
+DEFINE_int32(
+    client_socket_fd, -1,
+    "A file descriptor to use as the server clients connects to. If not "
+    "specified a unix socket will be created in the default location.");
+
+int main(int argc, char* argv[]) {
+  ::android::base::InitLogging(argv, android::base::StderrLogger);
+  google::ParseCommandLineFlags(&argc, &argv, true);
+
+  auto config = vsoc::CuttlefishConfig::Get();
+
+  ivserver::IVServer server(
+      ivserver::IVServerOptions(config->mempath(),
+                                config->ivshmem_qemu_socket_path(),
+                                vsoc::GetDomain()),
+      FLAGS_qemu_socket_fd, FLAGS_client_socket_fd);
+
+  // Close the file descriptors as they have been dupped by now.
+  if (FLAGS_qemu_socket_fd > 0) {
+    close(FLAGS_qemu_socket_fd);
+  }
+  if (FLAGS_client_socket_fd > 0) {
+    close(FLAGS_client_socket_fd);
+  }
+
+  server.Serve();
+
+  return 0;
+}
diff --git a/host/commands/launch/main.cc b/host/commands/launch/main.cc
index f449b22..35c73d4 100644
--- a/host/commands/launch/main.cc
+++ b/host/commands/launch/main.cc
@@ -45,8 +45,6 @@
 #include "host/commands/launch/pre_launch_initializers.h"
 #include "host/commands/launch/vsoc_shared_memory.h"
 #include "host/libs/config/cuttlefish_config.h"
-#include "host/libs/ivserver/ivserver.h"
-#include "host/libs/ivserver/options.h"
 #include "host/libs/monitor/kernel_log_server.h"
 #include "host/libs/usbip/server.h"
 #include "host/libs/vadb/virtual_adb_server.h"
@@ -118,6 +116,9 @@
 DEFINE_string(vnc_server_binary,
               vsoc::DefaultHostArtifactsPath("bin/vnc_server"),
               "Location of the vnc server binary.");
+DEFINE_string(ivserver_binary,
+              vsoc::DefaultHostArtifactsPath("bin/ivserver"),
+              "Location of the ivshmem server binary.");
 DEFINE_int32(vnc_server_port, GetPerInstanceDefault(6444),
              "The port on which the vnc server should listen");
 DEFINE_string(socket_forward_proxy_binary,
@@ -375,6 +376,11 @@
   return FLAGS_adb_mode == kAdbModeUsb;
 }
 
+int CreateIvServerUnixSocket(const std::string& path) {
+  return cvd::SharedFD::SocketLocalServer(path.c_str(), false, SOCK_STREAM,
+                                          0666)->UNMANAGED_Dup();
+}
+
 void LaunchIvServer() {
   auto config = vsoc::CuttlefishConfig::Get();
   // Resize gralloc region
@@ -391,15 +397,17 @@
       config->mempath(),
       {{vsoc::layout::screen::ScreenLayout::region_name, screen_buffers_size}});
 
-  // Construct the server outside the thread so that the socket is guaranteed to
-  // be created when this function return. Use a shared pointer to avoid the
-  // destruction of the object.
-  std::shared_ptr<ivserver::IVServer> server(new ivserver::IVServer(ivserver::IVServerOptions(
-        config->mempath(), config->ivshmem_qemu_socket_path(),
-        vsoc::GetDomain())));
-  std::thread([server] {
-    server->Serve();
-  }).detach();
+  auto qemu_channel =
+      CreateIvServerUnixSocket(config->ivshmem_qemu_socket_path());
+  auto client_channel =
+      CreateIvServerUnixSocket(config->ivshmem_client_socket_path());
+  auto qemu_socket_arg = "-qemu_socket_fd=" + std::to_string(qemu_channel);
+  auto client_socket_arg =
+      "-client_socket_fd=" + std::to_string(client_channel);
+  cvd::subprocess({FLAGS_ivserver_binary, qemu_socket_arg, client_socket_arg,
+                   GetConfigFileArg()});
+  close(qemu_channel);
+  close(client_channel);
 }
 
 void LaunchSocketForwardProxyIfEnabled() {
diff --git a/host/libs/ivserver/ivserver.cc b/host/libs/ivserver/ivserver.cc
index eb377ec..e645501 100644
--- a/host/libs/ivserver/ivserver.cc
+++ b/host/libs/ivserver/ivserver.cc
@@ -26,21 +26,30 @@
 
 namespace ivserver {
 
-IVServer::IVServer(const IVServerOptions &options)
+IVServer::IVServer(const IVServerOptions &options, int qemu_channel_fd,
+                   int client_channel_fd)
     : vsoc_shmem_(VSoCSharedMemory::New(options.shm_file_path)) {
-  LOG_IF(WARNING, unlink(options.qemu_socket_path.c_str()) == 0)
-      << "Removed existing unix socket: " << options.qemu_socket_path
-      << ". We can't confirm yet whether another instance is running.";
-  qemu_channel_ = cvd::SharedFD::SocketLocalServer(
-      options.qemu_socket_path.c_str(), false, SOCK_STREAM, 0666);
+  if (qemu_channel_fd > 0) {
+    qemu_channel_ = cvd::SharedFD::Dup(qemu_channel_fd);
+  } else {
+    LOG_IF(WARNING, unlink(options.qemu_socket_path.c_str()) == 0)
+        << "Removed existing unix socket: " << options.qemu_socket_path
+        << ". We can't confirm yet whether another instance is running.";
+    qemu_channel_ = cvd::SharedFD::SocketLocalServer(
+        options.qemu_socket_path.c_str(), false, SOCK_STREAM, 0666);
+  }
   LOG_IF(FATAL, !qemu_channel_->IsOpen())
       << "Could not create QEmu channel: " << qemu_channel_->StrError();
 
-  LOG_IF(WARNING, unlink(options.client_socket_path.c_str()) == 0)
-      << "Removed existing unix socket: " << options.client_socket_path
-      << ". We can't confirm yet whether another instance is running.";
-  client_channel_ = cvd::SharedFD::SocketLocalServer(
-      options.client_socket_path.c_str(), false, SOCK_STREAM, 0666);
+  if (client_channel_fd > 0) {
+    client_channel_ = cvd::SharedFD::Dup(client_channel_fd);
+  } else {
+    LOG_IF(WARNING, unlink(options.client_socket_path.c_str()) == 0)
+        << "Removed existing unix socket: " << options.client_socket_path
+        << ". We can't confirm yet whether another instance is running.";
+    client_channel_ = cvd::SharedFD::SocketLocalServer(
+        options.client_socket_path.c_str(), false, SOCK_STREAM, 0666);
+  }
   LOG_IF(FATAL, !client_channel_->IsOpen())
       << "Could not create Client channel: " << client_channel_->StrError();
 }
diff --git a/host/libs/ivserver/ivserver.h b/host/libs/ivserver/ivserver.h
index 70fb39f..b8ee791 100644
--- a/host/libs/ivserver/ivserver.h
+++ b/host/libs/ivserver/ivserver.h
@@ -27,7 +27,11 @@
 // new connections.
 class IVServer final {
  public:
-  IVServer(const IVServerOptions &options);
+  // The qemu_channel_fd and client_channel_fd are the server sockets. If
+  // non-positive values are provided the server will create those sockets
+  // itself.
+  IVServer(const IVServerOptions &options, int qemu_channel_fd,
+           int client_channel_fd);
   IVServer(const IVServer &) = delete;
   IVServer& operator=(const IVServer&) = delete;