Merge "Move Euler rotation state to CF webrtc backend" into main
diff --git a/Android.bp b/Android.bp
index 3109bf3..ee916a9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -68,6 +68,9 @@
         host: {
             cflags: ["-DCUTTLEFISH_HOST"],
             compile_multilib: "64",
+            strip: {
+                keep_symbols_and_debug_frame: true,
+            },
         },
         linux: {
             host_ldlibs: ["-lrt"],
@@ -141,42 +144,6 @@
     defaults: ["cuttlefish_base"],
 }
 
-cc_defaults {
-  name: "cuttlefish_recovery_available",
-  recovery_available : true
-}
-
-cc_defaults {
-  name: "enabled_on_p_and_later",
-  enabled: true
-}
-
-cc_defaults {
-  name: "enabled_on_q_and_later",
-  enabled: true
-}
-
-cc_defaults {
-  name: "enabled_on_q_internal_and_later",
-  enabled: true
-}
-
-cc_defaults {
-    name: "cuttlefish_libicuuc",
-    target: {
-        host: {
-            shared_libs: [
-                "libicuuc",
-            ],
-        },
-    },
-}
-
-cc_defaults {
-    name: "cuttlefish_health_storage",
-    defaults: ["enabled_on_q_and_later"],
-}
-
 java_test_host {
     name: "tombstone_transmit_tests",
 
@@ -188,8 +155,3 @@
 
     test_suites: ["general-tests"],
 }
-
-filegroup {
-    name: "cf_dtb",
-    srcs: ["dtb.img"],
-}
diff --git a/AndroidProducts.mk b/AndroidProducts.mk
index 1857e3a..55b23bb 100644
--- a/AndroidProducts.mk
+++ b/AndroidProducts.mk
@@ -18,6 +18,7 @@
 	aosp_cf_arm_minidroid:$(LOCAL_DIR)/vsoc_arm_minidroid/aosp_cf.mk \
 	aosp_cf_arm64_auto:$(LOCAL_DIR)/vsoc_arm64_only/auto/aosp_cf.mk \
 	aosp_cf_arm64_phone:$(LOCAL_DIR)/vsoc_arm64/phone/aosp_cf.mk \
+	aosp_cf_arm64_phone_pgagnostic:$(LOCAL_DIR)/vsoc_arm64_only/phone/aosp_cf_pgagnostic.mk \
 	aosp_cf_arm64_phone_fullmte:$(LOCAL_DIR)/vsoc_arm64_only/phone/aosp_cf_fullmte.mk \
 	aosp_cf_arm64_phone_hwasan:$(LOCAL_DIR)/vsoc_arm64/phone/aosp_cf_hwasan.mk \
 	aosp_cf_arm64_only_phone:$(LOCAL_DIR)/vsoc_arm64_only/phone/aosp_cf.mk \
diff --git a/build/Android.bp b/build/Android.bp
index d517ac4..d45d501 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -134,6 +134,12 @@
     "vulkan.pastel",
 ]
 
+cvd_host_tools_aarch64 = [
+    "aarch64_linux_gnu_crosvm",
+    "aarch64_linux_gnu_libgfxstream_backend.so_for_crosvm",
+    "aarch64_linux_gnu_libminijail.so_for_crosvm",
+]
+
 cvd_openwrt_images = [
     "openwrt_kernel_x86_64",
     "openwrt_rootfs_x86_64",
@@ -341,6 +347,7 @@
             },
         },
         arm64: {
+            deps: cvd_host_tools_aarch64,
             multilib: {
                 common: {
                     deps: cvd_host_seccomp_policy_aarch64,
diff --git a/common/frontend/socket_vsock_proxy/client.cpp b/common/frontend/socket_vsock_proxy/client.cpp
index 90aee5a..44161fc 100644
--- a/common/frontend/socket_vsock_proxy/client.cpp
+++ b/common/frontend/socket_vsock_proxy/client.cpp
@@ -26,11 +26,11 @@
   return address.find(':') != std::string::npos;
 }
 
-SharedFD StartIpv4(const std::string& host, int port) {
-  return SharedFD::SocketClient(host, port, SOCK_STREAM);
+SharedFD StartIpv4(const std::string& host, int port, std::chrono::seconds timeout) {
+  return SharedFD::SocketClient(host, port, SOCK_STREAM, timeout);
 }
 
-SharedFD StartIpv6(const std::string& host, int port) {
+SharedFD StartIpv6(const std::string& host, int port, std::chrono::seconds timeout) {
   const auto host_parsed = android::base::Tokenize(host, "%");
   const auto host_interface_tokens_count = host_parsed.size();
 
@@ -46,20 +46,23 @@
     host_name = host;
   }
 
-  return SharedFD::Socket6Client(host_name, interface_name, port, SOCK_STREAM);
+  return SharedFD::Socket6Client(host_name, interface_name, port, SOCK_STREAM, timeout);
 }
 
 }
 
-TcpClient::TcpClient(std::string host, int port) : host_(std::move(host)), port_(port) {}
+TcpClient::TcpClient(std::string host, int port, std::chrono::seconds timeout)
+    : host_(std::move(host)),
+      port_(port),
+      timeout_(timeout) {}
 
 SharedFD TcpClient::Start() {
   SharedFD client;
 
   if (IsIpv6(host_)) {
-    client = StartIpv6(host_, port_);
+    client = StartIpv6(host_, port_, timeout_);
   } else {
-    client = StartIpv4(host_, port_);
+    client = StartIpv4(host_, port_, timeout_);
   }
 
   if (client->IsOpen()) {
diff --git a/common/frontend/socket_vsock_proxy/client.h b/common/frontend/socket_vsock_proxy/client.h
index ca21005..e45c974 100644
--- a/common/frontend/socket_vsock_proxy/client.h
+++ b/common/frontend/socket_vsock_proxy/client.h
@@ -15,6 +15,8 @@
 
 #pragma once
 
+#include <chrono>
+
 #include "common/libs/fs/shared_fd.h"
 
 namespace cuttlefish {
@@ -29,13 +31,14 @@
 
 class TcpClient : public Client {
  public:
-  TcpClient(std::string host, int port);
+  TcpClient(std::string host, int port, std::chrono::seconds timeout = std::chrono::seconds(0));
   SharedFD Start() override;
   std::string Describe() const override;
 
  private:
   std::string host_;
   int port_;
+  std::chrono::seconds timeout_;
   int last_failure_reason_ = 0;
 };
 
diff --git a/common/frontend/socket_vsock_proxy/server.cpp b/common/frontend/socket_vsock_proxy/server.cpp
index 2264442..fcd46f4 100644
--- a/common/frontend/socket_vsock_proxy/server.cpp
+++ b/common/frontend/socket_vsock_proxy/server.cpp
@@ -13,7 +13,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <chrono>
 #include <set>
+#include <thread>
 
 #include "common/frontend/socket_vsock_proxy/server.h"
 #include "common/libs/utils/contains.h"
@@ -23,7 +25,7 @@
 namespace {
 
 bool socketErrorIsRecoverable(int error) {
-  std::set<int> unrecoverable{EACCES, EAFNOSUPPORT, EINVAL, EPROTONOSUPPORT};
+  std::set<int> unrecoverable{EACCES, EAFNOSUPPORT, EINVAL, EPROTONOSUPPORT, EADDRINUSE};
   return !Contains(unrecoverable, error);
 }
 
@@ -35,15 +37,31 @@
 
 }
 
-TcpServer::TcpServer(int port) : port_(port) {}
+TcpServer::TcpServer(int port, int retries_count, std::chrono::milliseconds retries_delay)
+    : port_(port),
+      retries_count_(retries_count),
+      retries_delay_(retries_delay) {};
 
-SharedFD TcpServer::Start() {
+Result<SharedFD> TcpServer::Start() {
   SharedFD server;
+  int last_error = 0;
 
-  server = SharedFD::SocketLocalServer(port_, SOCK_STREAM);
-  CHECK(server->IsOpen()) << "Could not start server on " << port_;
+  for (int i = 0; i < retries_count_; i++) {
+    server = SharedFD::SocketLocalServer(port_, SOCK_STREAM);
+    if (server->IsOpen()) {
+      return server;
+    }
+    last_error = server->GetErrno();
 
-  return server;
+    LOG(INFO) << "Failed to start TCP server on port: " << port_
+              << " after " << i + 1 << "th attempt (going to have "
+              << retries_count_ << " total attempts" << "). Error: " << last_error;
+
+    std::this_thread::sleep_for(retries_delay_);
+  }
+
+  return CF_ERR("Could not start TCP server on port: " << port_
+                << "after " << retries_count_ << " attempts. Last error: " << last_error);
 }
 
 std::string TcpServer::Describe() const {
@@ -53,7 +71,7 @@
 VsockServer::VsockServer(int port) : port_(port) {}
 
 // Intended to run in the guest
-SharedFD VsockServer::Start() {
+Result<SharedFD> VsockServer::Start() {
   SharedFD server;
 
   do {
@@ -78,8 +96,8 @@
   close(fd);
 }
 
-SharedFD DupServer::Start() {
-  CHECK(sfd_->IsOpen()) << "Could not start duplicate server for passed fd";
+Result<SharedFD> DupServer::Start() {
+  CF_EXPECT(sfd_->IsOpen(), "Could not start duplicate server for passed fd");
   return sfd_;
 }
 
diff --git a/common/frontend/socket_vsock_proxy/server.h b/common/frontend/socket_vsock_proxy/server.h
index 66aaeef..7535852 100644
--- a/common/frontend/socket_vsock_proxy/server.h
+++ b/common/frontend/socket_vsock_proxy/server.h
@@ -15,32 +15,38 @@
 
 #pragma once
 
+#include <chrono>
+
 #include "common/libs/fs/shared_fd.h"
+#include "common/libs/utils/result.h"
 
 namespace cuttlefish {
 namespace socket_proxy {
 
 class Server {
  public:
-  virtual SharedFD Start() = 0;
+  virtual Result<SharedFD> Start() = 0;
   virtual std::string Describe() const = 0;
   virtual ~Server() = default;
 };
 
 class TcpServer : public Server {
  public:
-  TcpServer(int port);
-  SharedFD Start() override;
+  TcpServer(int port, int retries_count = 1,
+            std::chrono::milliseconds retries_delay = std::chrono::milliseconds(0));
+  Result<SharedFD> Start() override;
   std::string Describe() const override;
 
  private:
   int port_;
+  int retries_count_;
+  std::chrono::milliseconds retries_delay_;
 };
 
 class VsockServer : public Server {
  public:
   VsockServer(int port);
-  SharedFD Start() override;
+  Result<SharedFD> Start() override;
   std::string Describe() const override;
 
  private:
@@ -50,7 +56,7 @@
 class DupServer : public Server {
  public:
   DupServer(int fd);
-  SharedFD Start() override;
+  Result<SharedFD> Start() override;
   std::string Describe() const override;
 
  private:
diff --git a/common/frontend/socket_vsock_proxy/socket_vsock_proxy.cpp b/common/frontend/socket_vsock_proxy/socket_vsock_proxy.cpp
index 1851368..43173c3 100644
--- a/common/frontend/socket_vsock_proxy/socket_vsock_proxy.cpp
+++ b/common/frontend/socket_vsock_proxy/socket_vsock_proxy.cpp
@@ -18,12 +18,14 @@
 #include <android-base/logging.h>
 #include <gflags/gflags.h>
 
+#include <chrono>
 #include <memory>
 #include <sstream>
 
 #include "common/frontend/socket_vsock_proxy/client.h"
 #include "common/frontend/socket_vsock_proxy/server.h"
 #include "common/libs/fs/shared_fd.h"
+#include "common/libs/utils/result.h"
 #include "common/libs/utils/socket2socket_proxy.h"
 #include "common/libs/utils/tee_logging.h"
 #include "host/commands/kernel_log_monitor/utils.h"
@@ -32,8 +34,12 @@
 #include "host/libs/config/logging.h"
 #endif // CUTTLEFISH_HOST
 
-constexpr const char TRANSPORT_TCP[] = "tcp";
-constexpr const char TRANSPORT_VSOCK[] = "vsock";
+constexpr int TCP_SERVER_START_RETRIES_COUNT = 10;
+constexpr std::chrono::milliseconds TCP_SERVER_RETRIES_DELAY(1250);
+constexpr std::chrono::seconds TCP_CLIENT_TIMEOUT(1);
+
+constexpr char TRANSPORT_TCP[] = "tcp";
+constexpr char TRANSPORT_VSOCK[] = "vsock";
 
 DEFINE_string(label, "socket_vsock_proxy", "Label which is used only for logging. "
                                            "Log messages will look like [label] message");
@@ -55,12 +61,14 @@
                                   "kernel_log_server.h) that we will listen to start proxy");
 DEFINE_uint32(stop_event_id, -1, "Kernel event id (cuttlefish::monitor::Event from "
                                   "kernel_log_server.h) that we will listen to stop proxy");
+DEFINE_bool(start_immediately, false, "A flag to start proxying without waiting for "
+                                      "initial start event");
 
 namespace cuttlefish {
 namespace socket_proxy {
 namespace {
 
-std::unique_ptr<Server> BuildServer() {
+static std::unique_ptr<Server> BuildServer() {
   if (FLAGS_server_fd >= 0) {
     return std::make_unique<DupServer>(FLAGS_server_fd);
   }
@@ -80,7 +88,8 @@
   std::unique_ptr<Server> server = nullptr;
 
   if (FLAGS_server_type == TRANSPORT_TCP) {
-    server = std::make_unique<TcpServer>(FLAGS_server_tcp_port);
+    server = std::make_unique<TcpServer>(FLAGS_server_tcp_port, TCP_SERVER_START_RETRIES_COUNT,
+                                         TCP_SERVER_RETRIES_DELAY);
   } else if (FLAGS_server_type == TRANSPORT_VSOCK) {
     server = std::make_unique<VsockServer>(FLAGS_server_vsock_port);
   } else {
@@ -90,7 +99,7 @@
   return server;
 }
 
-std::unique_ptr<Client> BuildClient() {
+static std::unique_ptr<Client> BuildClient() {
   CHECK(FLAGS_client_type == TRANSPORT_TCP || FLAGS_client_type == TRANSPORT_VSOCK)
       << "Must specify -client_type with tcp or vsock values";
 
@@ -106,7 +115,8 @@
   std::unique_ptr<Client> client = nullptr;
 
   if (FLAGS_client_type == TRANSPORT_TCP) {
-    client = std::make_unique<TcpClient>(FLAGS_client_tcp_host, FLAGS_client_tcp_port);
+    client = std::make_unique<TcpClient>(FLAGS_client_tcp_host, FLAGS_client_tcp_port,
+                                         TCP_CLIENT_TIMEOUT);
   } else if (FLAGS_client_type == TRANSPORT_VSOCK) {
     client = std::make_unique<VsockClient>(FLAGS_client_vsock_id, FLAGS_client_vsock_port);
   } else {
@@ -116,14 +126,26 @@
   return client;
 }
 
-void ListenEventsAndProxy(int events_fd, const monitor::Event start, const monitor::Event stop,
-                          Server& server, Client& client) {
+static Result<std::unique_ptr<ProxyServer>> StartProxyAsync(Server& server, Client& client) {
+  LOG(INFO) << "From: " << server.Describe();
+  LOG(INFO) << "To: " << client.Describe();
+  return ProxyAsync(CF_EXPECT(server.Start()), [&client] { return client.Start(); });
+}
+
+static Result<void> ListenEventsAndProxy(int events_fd,
+                                         const monitor::Event start, const monitor::Event stop,
+                                         Server& server, Client& client) {
   auto events = SharedFD::Dup(events_fd);
   close(events_fd);
 
-  std::unique_ptr<cuttlefish::ProxyServer> proxy;
+  std::unique_ptr<ProxyServer> proxy;
 
-  LOG(DEBUG) << "Start reading ";
+  if (FLAGS_start_immediately) {
+    LOG(INFO) << "start_immediately was set to true, so starting proxying";
+    proxy = std::move(CF_EXPECT(StartProxyAsync(server, client)));
+  }
+
+  LOG(DEBUG) << "Start reading evets to start/stop proxying";
   while (events->IsOpen()) {
     std::optional<monitor::ReadEventResult> received_event = monitor::ReadEvent(events);
 
@@ -135,12 +157,7 @@
     if (start != -1 && received_event->event == start) {
       if (!proxy) {
         LOG(INFO) << "Start event (" << start << ") received. Starting proxy";
-        LOG(INFO) << "From: " << server.Describe();
-        LOG(INFO) << "To: " << client.Describe();
-        auto started_proxy = cuttlefish::ProxyAsync(server.Start(), [&client] {
-          return client.Start();
-        });
-        proxy = std::move(started_proxy);
+        proxy = std::move(CF_EXPECT(StartProxyAsync(server, client)));
       }
       continue;
     }
@@ -151,6 +168,28 @@
       continue;
     }
   }
+
+  return {};
+}
+
+Result<void> Main() {
+  auto server = BuildServer();
+  auto client = BuildClient();
+
+  if (FLAGS_events_fd != -1) {
+    CF_EXPECT(FLAGS_start_event_id != -1, "start_event_id is required if events_fd is provided");
+
+    const monitor::Event start_event = static_cast<monitor::Event>(FLAGS_start_event_id);
+    const monitor::Event stop_event = static_cast<monitor::Event>(FLAGS_stop_event_id);
+
+    CF_EXPECT(ListenEventsAndProxy(FLAGS_events_fd, start_event, stop_event,
+                                   *server, *client));
+  } else {
+    LOG(DEBUG) << "Starting proxy";
+    Proxy(CF_EXPECT(server->Start()), [&client] { return client->Start(); });
+  }
+
+  return {};
 }
 
 }
@@ -171,20 +210,10 @@
     android::base::SetDefaultTag("proxy_" + FLAGS_label);
   }
 
-  auto server = cuttlefish::socket_proxy::BuildServer();
-  auto client = cuttlefish::socket_proxy::BuildClient();
-
-  if (FLAGS_events_fd != -1) {
-    CHECK(FLAGS_start_event_id != -1)
-        << "start_event_id is required if events_fd is provided";
-
-    const monitor::Event start_event = static_cast<monitor::Event>(FLAGS_start_event_id);
-    const monitor::Event stop_event = static_cast<monitor::Event>(FLAGS_stop_event_id);
-
-    cuttlefish::socket_proxy::ListenEventsAndProxy(FLAGS_events_fd, start_event, stop_event,
-                                                   *server, *client);
-  } else {
-    LOG(DEBUG) << "Starting proxy";
-    cuttlefish::Proxy(server->Start(), [&client] { return client->Start(); });
+  auto result = cuttlefish::socket_proxy::Main();
+  if (!result.ok()) {
+    LOG(FATAL) << "Failed to proxy: " << result.error().Message();
   }
+
+  return 0;
 }
diff --git a/common/libs/confui/Android.bp b/common/libs/confui/Android.bp
index ca6348a..fca008b 100644
--- a/common/libs/confui/Android.bp
+++ b/common/libs/confui/Android.bp
@@ -17,7 +17,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_confui",
     srcs: [
         "packet_types.cpp",
@@ -25,15 +25,14 @@
         "protocol_types.cpp",
         "protocol.cpp",
     ],
-    static: {
-        static_libs: [
-            "libbase",
-            "libcuttlefish_fs",
-	    "libteeui",
-        ],
-        shared_libs: [
-          "libcrypto", // libcrypto_static is not accessible from all targets
-        ],
-    },
+    static_libs: [
+        "libteeui",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcrypto", // libcrypto_static is not accessible from all targets
+        "libcuttlefish_fs",
+        "liblog",
+    ],
     defaults: ["cuttlefish_host"],
 }
diff --git a/common/libs/fs/Android.bp b/common/libs/fs/Android.bp
index 56cb96e..7285f84 100644
--- a/common/libs/fs/Android.bp
+++ b/common/libs/fs/Android.bp
@@ -24,50 +24,42 @@
         "shared_fd.cpp",
         "shared_fd_stream.cpp",
     ],
-    shared: {
-        shared_libs: [
-            "libbase",
-            "liblog",
-        ],
-    },
-    static: {
-        static_libs: [
-            "libbase",
-            "liblog",
-        ],
-    },
+    shared_libs: [
+        "libbase",
+        "liblog",
+    ],
     target: {
+        android: {
+            shared_libs: [
+                "libbase",
+                "liblog",
+            ],
+        },
         darwin: {
             enabled: true,
         },
+        host: {
+            shared: {
+                shared_libs: [
+                    "libbase",
+                    "liblog",
+                ],
+            },
+            static: {
+                static_libs: [
+                    "libbase",
+                    "liblog",
+                ],
+            },
+        },
         linux: {
             srcs: [
                 "epoll.cpp",
             ],
         },
-        vendor: {
-            // Liblog does not have a vendor-static variant.
-            shared_libs: ["liblog"],
-            exclude_static_libs: ["liblog"],
-        },
     },
     defaults: ["cuttlefish_host"],
-}
-
-cc_library_static {
-    name: "libcuttlefish_fs_product",
-    srcs: [
-        "epoll.cpp",
-        "shared_buf.cc",
-        "shared_fd.cpp",
-        "shared_fd_stream.cpp",
-    ],
-    shared_libs: [
-        "libbase",
-        "liblog",
-    ],
-    stl: "libc++_static",
-    defaults: ["cuttlefish_guest_product_only"],
+    product_available: true,
 }
 
 cc_test {
diff --git a/common/libs/fs/shared_fd.cpp b/common/libs/fs/shared_fd.cpp
index cfdb3c2..51039cf 100644
--- a/common/libs/fs/shared_fd.cpp
+++ b/common/libs/fs/shared_fd.cpp
@@ -525,7 +525,8 @@
   return rval;
 }
 
-SharedFD SharedFD::SocketClient(const std::string& host, int port, int type) {
+SharedFD SharedFD::SocketClient(const std::string& host, int port, int type,
+                                std::chrono::seconds timeout) {
   sockaddr_in addr{};
   addr.sin_family = AF_INET;
   addr.sin_port = htons(port);
@@ -534,14 +535,16 @@
   if (!rval->IsOpen()) {
     return rval;
   }
-  if (rval->Connect(reinterpret_cast<const sockaddr*>(&addr), sizeof addr) < 0) {
+  struct timeval timeout_timeval = {static_cast<time_t>(timeout.count()), 0};
+  if (rval->ConnectWithTimeout(reinterpret_cast<const sockaddr*>(&addr),
+                               sizeof addr, &timeout_timeval) < 0) {
     return SharedFD::ErrorFD(rval->GetErrno());
   }
   return rval;
 }
 
 SharedFD SharedFD::Socket6Client(const std::string& host, const std::string& interface,
-                                 int port, int type) {
+                                 int port, int type, std::chrono::seconds timeout) {
   sockaddr_in6 addr{};
   addr.sin6_family = AF_INET6;
   addr.sin6_port = htons(port);
@@ -569,7 +572,9 @@
 #endif
   }
 
-  if (rval->Connect(reinterpret_cast<const sockaddr*>(&addr), sizeof addr) < 0) {
+  struct timeval timeout_timeval = {static_cast<time_t>(timeout.count()), 0};
+  if (rval->ConnectWithTimeout(reinterpret_cast<const sockaddr*>(&addr),
+                               sizeof addr, &timeout_timeval) < 0) {
     return SharedFD::ErrorFD(rval->GetErrno());
   }
   return rval;
diff --git a/common/libs/fs/shared_fd.h b/common/libs/fs/shared_fd.h
index 583db7a..4672ade 100644
--- a/common/libs/fs/shared_fd.h
+++ b/common/libs/fs/shared_fd.h
@@ -33,6 +33,7 @@
 #include <sys/uio.h>
 #include <sys/un.h>
 
+#include <chrono>
 #include <memory>
 #include <sstream>
 #include <string>
@@ -156,9 +157,10 @@
   static SharedFD SocketLocalClient(const std::string& name, bool is_abstract,
                                     int in_type, int timeout_seconds);
   static SharedFD SocketLocalClient(int port, int type);
-  static SharedFD SocketClient(const std::string& host, int port, int type);
-  static SharedFD Socket6Client(const std::string& host, const std::string& interface,
-                                int port, int type);
+  static SharedFD SocketClient(const std::string& host, int port,
+                               int type, std::chrono::seconds timeout = std::chrono::seconds(0));
+  static SharedFD Socket6Client(const std::string& host, const std::string& interface, int port,
+                                int type, std::chrono::seconds timeout = std::chrono::seconds(0));
   static SharedFD SocketLocalServer(const std::string& name, bool is_abstract,
                                     int in_type, mode_t mode);
   static SharedFD SocketLocalServer(int port, int type);
diff --git a/common/libs/utils/Android.bp b/common/libs/utils/Android.bp
index 6fb8e34..14ff196 100644
--- a/common/libs/utils/Android.bp
+++ b/common/libs/utils/Android.bp
@@ -67,19 +67,7 @@
         }
     },
     defaults: ["cuttlefish_host"],
-}
-
-cc_library_static {
-    name: "libcuttlefish_utils_product",
-    srcs: [
-        "inotify.cpp",
-    ],
-    shared_libs: [
-        "libbase",
-        "liblog",
-    ],
-    stl: "libc++_static",
-    defaults: ["cuttlefish_guest_product_only"],
+    product_available: true,
 }
 
 cc_test_host {
diff --git a/common/libs/utils/flag_parser.cpp b/common/libs/utils/flag_parser.cpp
index 6cb65c9..aba5236 100644
--- a/common/libs/utils/flag_parser.cpp
+++ b/common/libs/utils/flag_parser.cpp
@@ -123,27 +123,6 @@
   return *this;
 }
 
-Flag& Flag::Setter(std::function<bool(const FlagMatch&)> fn) & {
-  setter_ = [fn = std::move(fn)](const FlagMatch& match) -> Result<void> {
-    if (fn(match)) {
-      return {};
-    } else {
-      return CF_ERR("Flag setter failed");
-    }
-  };
-  return *this;
-}
-Flag Flag::Setter(std::function<bool(const FlagMatch&)> fn) && {
-  setter_ = [fn = std::move(fn)](const FlagMatch& match) -> Result<void> {
-    if (fn(match)) {
-      return {};
-    } else {
-      return CF_ERR("Flag setter failed");
-    }
-  };
-  return *this;
-}
-
 Flag& Flag::Setter(std::function<Result<void>(const FlagMatch&)> setter) & {
   setter_ = std::move(setter);
   return *this;
@@ -439,15 +418,15 @@
       .Help("Used to set the verbosity level for logging.");
 }
 
-Flag HelpFlag(const std::vector<Flag>& flags, const std::string& text) {
-  auto setter = [&](FlagMatch) {
+Flag HelpFlag(const std::vector<Flag>& flags, std::string text) {
+  auto setter = [&flags, text](FlagMatch) -> Result<void> {
     if (text.size() > 0) {
       LOG(INFO) << text;
     }
     for (const auto& flag : flags) {
       LOG(INFO) << flag;
     }
-    return false;
+    return CF_ERR("user requested early exit");
   };
   return Flag()
       .Alias({FlagAliasMode::kFlagExact, "-help"})
@@ -491,9 +470,9 @@
 }
 
 Flag HelpXmlFlag(const std::vector<Flag>& flags, std::ostream& out, bool& value,
-                 const std::string& text) {
+                 std::string text) {
   const std::string name = "helpxml";
-  auto setter = [name, &out, &value, &text,
+  auto setter = [name, &out, &value, text,
                  &flags](const FlagMatch& match) -> Result<void> {
     bool print_xml = false;
     CF_EXPECT(GflagsCompatBoolFlagSetter(name, print_xml, match));
@@ -518,9 +497,8 @@
       .Help(
           "This executable only supports the flags in `-help`. Positional "
           "arguments may be supported.")
-      .Setter([](const FlagMatch& match) {
-        LOG(ERROR) << "Unknown flag " << match.value;
-        return false;
+      .Setter([](const FlagMatch& match) -> Result<void> {
+        return CF_ERRF("Unknown flag \"{}\"", match.value);
       });
 }
 
@@ -530,9 +508,8 @@
       .Help(
           "This executable only supports the flags in `-help`. Positional "
           "arguments are not supported.")
-      .Setter([](const FlagMatch& match) {
-        LOG(ERROR) << "Unexpected argument \"" << match.value << "\"";
-        return false;
+      .Setter([](const FlagMatch& match) -> Result<void> {
+        return CF_ERRF("Unexpected argument \"{}\"", match.value);
       });
 }
 
@@ -547,9 +524,9 @@
 Flag GflagsCompatFlag(const std::string& name, std::string& value) {
   return GflagsCompatFlag(name)
       .Getter([&value]() { return value; })
-      .Setter([&value](const FlagMatch& match) {
+      .Setter([&value](const FlagMatch& match) -> Result<void> {
         value = match.value;
-        return true;
+        return {};
       });
 }
 
@@ -598,9 +575,11 @@
                       std::vector<std::string>& value) {
   return GflagsCompatFlag(name)
       .Getter([&value]() { return android::base::Join(value, ','); })
-      .Setter([&name, &value](const FlagMatch& match) -> Result<void> {
-        CF_EXPECTF(!match.value.empty(), "No values given for flag \"{}\"",
-                   name);
+      .Setter([&value](const FlagMatch& match) -> Result<void> {
+        if (match.value.empty()) {
+          value.clear();
+          return {};
+        }
         std::vector<std::string> str_vals =
             android::base::Split(match.value, ",");
         value = std::move(str_vals);
@@ -613,8 +592,10 @@
   return GflagsCompatFlag(name)
       .Getter([&value]() { return fmt::format("{}", fmt::join(value, ",")); })
       .Setter([&name, &value, def_val](const FlagMatch& match) -> Result<void> {
-        CF_EXPECTF(!match.value.empty(), "No values given for flag \"{}\"",
-                   name);
+        if (match.value.empty()) {
+          value.clear();
+          return {};
+        }
         std::vector<std::string> str_vals =
             android::base::Split(match.value, ",");
         value.clear();
diff --git a/common/libs/utils/flag_parser.h b/common/libs/utils/flag_parser.h
index e8b045b..3304311 100644
--- a/common/libs/utils/flag_parser.h
+++ b/common/libs/utils/flag_parser.h
@@ -81,9 +81,8 @@
   /* Set a loader that displays the current value in help text. Optional. */
   Flag& Getter(std::function<std::string()>) &;
   Flag Getter(std::function<std::string()>) &&;
-  /* Set the callback for matches. The callback be invoked multiple times. */
-  Flag& Setter(std::function<bool(const FlagMatch&)>) &;
-  Flag Setter(std::function<bool(const FlagMatch&)>) &&;
+  /* Set the callback for matches. The callback may be invoked multiple times.
+   */
   Flag& Setter(std::function<Result<void>(const FlagMatch&)>) &;
   Flag Setter(std::function<Result<void>(const FlagMatch&)>) &&;
 
@@ -154,11 +153,11 @@
  * unexpected arguments). */
 
 /* If a "-help" or "--help" flag is present, prints all the flags and fails. */
-Flag HelpFlag(const std::vector<Flag>& flags, const std::string& text = "");
+Flag HelpFlag(const std::vector<Flag>& flags, std::string text = "");
 
 /* If a "-helpxml" is present, prints all the flags in XML and fails. */
 Flag HelpXmlFlag(const std::vector<Flag>& flags, std::ostream&, bool& value,
-                 const std::string& text = "");
+                 std::string text = "");
 
 /* Catches unrecognized arguments that begin with `-`, and errors out. This
  * effectively denies unknown flags. */
diff --git a/common/libs/utils/flag_parser_test.cpp b/common/libs/utils/flag_parser_test.cpp
index 74422e5..26503f7 100644
--- a/common/libs/utils/flag_parser_test.cpp
+++ b/common/libs/utils/flag_parser_test.cpp
@@ -117,9 +117,9 @@
 TEST(FlagParser, RepeatedListFlag) {
   std::vector<std::string> elems;
   auto flag = GflagsCompatFlag("myflag");
-  flag.Setter([&elems](const FlagMatch& match) {
+  flag.Setter([&elems](const FlagMatch& match) -> Result<void> {
     elems.push_back(match.value);
-    return true;
+    return {};
   });
   ASSERT_THAT(flag.Parse({"-myflag=a", "--myflag", "b"}), IsOk());
   ASSERT_EQ(elems, (std::vector<std::string>{"a", "b"}));
@@ -238,7 +238,7 @@
   std::vector<std::string> value;
   auto flag = GflagsCompatFlag("myflag", value);
 
-  ASSERT_THAT(flag.Parse({"--myflag="}), IsError());
+  ASSERT_THAT(flag.Parse({"--myflag="}), IsOk());
   ASSERT_TRUE(value.empty());
 
   ASSERT_THAT(flag.Parse({"--myflag=foo"}), IsOk());
@@ -262,7 +262,7 @@
   bool default_value = true;
   auto flag = GflagsCompatFlag("myflag", value, default_value);
 
-  ASSERT_THAT(flag.Parse({"--myflag="}), IsError());
+  ASSERT_THAT(flag.Parse({"--myflag="}), IsOk());
   ASSERT_TRUE(value.empty());
 
   ASSERT_THAT(flag.Parse({"--myflag=foo"}), IsError());
@@ -391,9 +391,9 @@
     elems_.clear();
     flag_ = Flag()
                 .Alias({FlagAliasMode::kFlagConsumesArbitrary, "--flag"})
-                .Setter([this](const FlagMatch& match) {
+                .Setter([this](const FlagMatch& match) -> Result<void> {
                   elems_.push_back(match.value);
-                  return true;
+                  return {};
                 });
   }
   Flag flag_;
diff --git a/common/libs/utils/json.h b/common/libs/utils/json.h
index db9581c..89517d85 100644
--- a/common/libs/utils/json.h
+++ b/common/libs/utils/json.h
@@ -15,7 +15,9 @@
 
 #pragma once
 
+#include <string>
 #include <string_view>
+#include <vector>
 
 #include <json/json.h>
 
@@ -25,4 +27,26 @@
 
 Result<Json::Value> ParseJson(std::string_view input);
 
+template <typename T>
+Result<T> GetValue(const Json::Value& root,
+                   const std::vector<std::string>& selectors) {
+  const Json::Value* traversal = &root;
+  for (const auto& selector : selectors) {
+    CF_EXPECTF(traversal->isMember(selector),
+               "JSON selector \"{}\" does not exist", selector);
+    traversal = &(*traversal)[selector];
+  }
+  return traversal->as<T>();
+}
+
+template <typename T>
+Result<std::vector<T>> GetArrayValues(
+    const Json::Value& array, const std::vector<std::string>& selectors) {
+  std::vector<T> result;
+  for (const auto& element : array) {
+    result.emplace_back(CF_EXPECT(GetValue<T>(element, selectors)));
+  }
+  return result;
+}
+
 }  // namespace cuttlefish
diff --git a/common/libs/utils/rust/vsock_connection/Android.bp b/common/libs/utils/rust/vsock_connection/Android.bp
index 43a51a0..66f8b79 100644
--- a/common/libs/utils/rust/vsock_connection/Android.bp
+++ b/common/libs/utils/rust/vsock_connection/Android.bp
@@ -2,7 +2,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "libvsock_utils_wrapper",
     srcs: [
         "wrapper.cpp",
@@ -14,9 +14,9 @@
       "libbase_headers",
     ],
     shared_libs: [
+        "libcuttlefish_fs",
+        "libjsoncpp", // needed since libjsoncpp_headers isn't available from the vendor partition
         "libvsock_utils",
-        // needed since libjsoncpp_headers isn't available from the vendor partition
-        "libjsoncpp",
     ],
     defaults: ["cuttlefish_guest_only"],
 }
diff --git a/common/libs/utils/rust/vsock_connection/lib.rs b/common/libs/utils/rust/vsock_connection/lib.rs
index b6c88e4..59bd099 100644
--- a/common/libs/utils/rust/vsock_connection/lib.rs
+++ b/common/libs/utils/rust/vsock_connection/lib.rs
@@ -14,7 +14,7 @@
 
 //! Rust wrapper for VSockServerConnection.
 
-use cxx::SharedPtr;
+use cxx::UniquePtr;
 
 /// This module exposes the VsockServerConnection C++ class to Rust.
 #[allow(unsafe_op_in_unsafe_fn)]
@@ -24,25 +24,37 @@
         include!("wrapper.h");
 
         type VsockServerConnection;
-        fn create_shared_vsock_server_connection() -> SharedPtr<VsockServerConnection>;
-        fn IsConnected(self: &VsockServerConnection) -> bool;
+        fn create_vsock_server_connection() -> UniquePtr<VsockServerConnection>;
+        fn IsConnected(self: Pin<&mut VsockServerConnection>) -> bool;
+        fn Connect(self: Pin<&mut VsockServerConnection>, port: u32, cid: u32) -> bool;
+        fn ServerShutdown(self: Pin<&mut VsockServerConnection>);
     }
 }
 
 /// Rust wrapper for a VsockServerConnection.
 pub struct VsockServerConnection {
-    instance: SharedPtr<ffi::VsockServerConnection>,
+    instance: UniquePtr<ffi::VsockServerConnection>,
 }
 
 impl VsockServerConnection {
     /// Creates a VsockServerConnection.
     pub fn new() -> Self {
-        Self { instance: ffi::create_shared_vsock_server_connection() }
+        Self { instance: ffi::create_vsock_server_connection() }
     }
 
     /// Returns if the vsock server has an active connection or not.
-    pub fn is_connected(&self) -> bool {
-        self.instance.IsConnected()
+    pub fn is_connected(&mut self) -> bool {
+        self.instance.pin_mut().IsConnected()
+    }
+
+    /// Start connection using the provided port and cid.
+    pub fn connect(&mut self, port: u32, cid: u32) -> bool {
+        self.instance.pin_mut().Connect(port, cid)
+    }
+
+    /// Shutdown connection.
+    pub fn server_shutdown(&mut self) {
+        self.instance.pin_mut().ServerShutdown();
     }
 }
 
@@ -51,3 +63,7 @@
         Self::new()
     }
 }
+
+// SAFETY: VsockServerConnection is a pointer to an `ffi::VsockServerConnection`, which in turn only
+// contains a file descriptor and so is safe to pass between threads.
+unsafe impl Send for VsockServerConnection {}
diff --git a/common/libs/utils/rust/vsock_connection/wrapper.cpp b/common/libs/utils/rust/vsock_connection/wrapper.cpp
index 2b519c7..3dd4d63 100644
--- a/common/libs/utils/rust/vsock_connection/wrapper.cpp
+++ b/common/libs/utils/rust/vsock_connection/wrapper.cpp
@@ -17,8 +17,8 @@
 
 namespace cuttlefish {
 
-std::shared_ptr<VsockServerConnection> create_shared_vsock_server_connection() {
-  return std::make_shared<VsockServerConnection>();
+std::unique_ptr<VsockServerConnection> create_vsock_server_connection() {
+  return std::make_unique<VsockServerConnection>();
 }
 
 } // namespace cuttlefish
diff --git a/common/libs/utils/rust/vsock_connection/wrapper.h b/common/libs/utils/rust/vsock_connection/wrapper.h
index 90addca..81fa145 100644
--- a/common/libs/utils/rust/vsock_connection/wrapper.h
+++ b/common/libs/utils/rust/vsock_connection/wrapper.h
@@ -21,6 +21,6 @@
 
 namespace cuttlefish {
 
-std::shared_ptr<VsockServerConnection> create_shared_vsock_server_connection();
+std::unique_ptr<VsockServerConnection> create_vsock_server_connection();
 
 } // namespace cuttlefish
diff --git a/common/libs/utils/shared_fd_flag.cpp b/common/libs/utils/shared_fd_flag.cpp
index b894147..e50d6d1 100644
--- a/common/libs/utils/shared_fd_flag.cpp
+++ b/common/libs/utils/shared_fd_flag.cpp
@@ -31,18 +31,16 @@
 
 namespace cuttlefish {
 
-static bool Set(const FlagMatch& match, SharedFD& out) {
+static Result<void> Set(const FlagMatch& match, SharedFD& out) {
   int raw_fd;
-  if (!android::base::ParseInt(match.value.c_str(), &raw_fd)) {
-    LOG(ERROR) << "Failed to parse value \"" << match.value
-               << "\" for fd flag \"" << match.key << "\"";
-    return false;
-  }
+  CF_EXPECTF(android::base::ParseInt(match.value.c_str(), &raw_fd),
+             "Failed to parse value \"{}\" for fd flag \"{}\"", match.value,
+             match.key);
   out = SharedFD::Dup(raw_fd);
   if (out->IsOpen()) {
     close(raw_fd);
   }
-  return true;
+  return {};
 }
 
 Flag SharedFDFlag(SharedFD& out) {
diff --git a/common/libs/utils/vsock_connection.cpp b/common/libs/utils/vsock_connection.cpp
index 9151cf1..161e988 100644
--- a/common/libs/utils/vsock_connection.cpp
+++ b/common/libs/utils/vsock_connection.cpp
@@ -47,6 +47,10 @@
 }
 
 void VsockConnection::Disconnect() {
+  // We need to serialize all accesses to the SharedFD.
+  std::lock_guard<std::recursive_mutex> read_lock(read_mutex_);
+  std::lock_guard<std::recursive_mutex> write_lock(write_mutex_);
+
   LOG(INFO) << "Disconnecting with fd status:" << fd_->StrError();
   fd_->Shutdown(SHUT_RDWR);
   if (disconnect_callback_) {
@@ -59,10 +63,21 @@
   disconnect_callback_ = callback;
 }
 
-bool VsockConnection::IsConnected() const { return fd_->IsOpen(); }
+bool VsockConnection::IsConnected() {
+  // We need to serialize all accesses to the SharedFD.
+  std::lock_guard<std::recursive_mutex> read_lock(read_mutex_);
+  std::lock_guard<std::recursive_mutex> write_lock(write_mutex_);
 
-bool VsockConnection::DataAvailable() const {
+  return fd_->IsOpen();
+}
+
+bool VsockConnection::DataAvailable() {
   SharedFDSet read_set;
+
+  // We need to serialize all accesses to the SharedFD.
+  std::lock_guard<std::recursive_mutex> read_lock(read_mutex_);
+  std::lock_guard<std::recursive_mutex> write_lock(write_mutex_);
+
   read_set.Set(fd_);
   struct timeval timeout = {0, 0};
   return Select(&read_set, nullptr, nullptr, &timeout) > 0;
diff --git a/common/libs/utils/vsock_connection.h b/common/libs/utils/vsock_connection.h
index c7a796a..0042eb5 100644
--- a/common/libs/utils/vsock_connection.h
+++ b/common/libs/utils/vsock_connection.h
@@ -37,9 +37,8 @@
   std::future<bool> ConnectAsync(unsigned int port, unsigned int cid);
   void SetDisconnectCallback(std::function<void()> callback);
 
-  bool IsConnected() const;
-  bool DataAvailable() const;
-
+  bool IsConnected();
+  bool DataAvailable();
   int32_t Read();
   bool Read(std::vector<char>& data);
   std::vector<char> Read(size_t size);
diff --git a/guest/hals/health/Android.bp b/guest/hals/health/Android.bp
index a452c1e..e43d605 100644
--- a/guest/hals/health/Android.bp
+++ b/guest/hals/health/Android.bp
@@ -47,8 +47,6 @@
         "libutils",
         "android.hardware.health-V2-ndk",
     ],
-
-    defaults: ["enabled_on_p_and_later"],
 }
 
 cc_binary {
@@ -101,6 +99,4 @@
         "android.hardware.health@2.0",
         "android.hardware.health@2.1",
     ],
-
-    defaults: ["enabled_on_p_and_later"],
 }
diff --git a/guest/hals/health/storage/Android.bp b/guest/hals/health/storage/Android.bp
index 1ca807d1..6f26661 100644
--- a/guest/hals/health/storage/Android.bp
+++ b/guest/hals/health/storage/Android.bp
@@ -21,7 +21,7 @@
 cc_binary {
     name: "android.hardware.health.storage-service.cuttlefish",
     vendor: true,
-    defaults: ["hidl_defaults", "cuttlefish_health_storage"],
+    defaults: ["hidl_defaults"],
     relative_install_path: "hw",
     init_rc: ["android.hardware.health.storage-service.cuttlefish.rc"],
     vintf_fragments: [
diff --git a/guest/hals/keymint/rust/Android.bp b/guest/hals/keymint/rust/Android.bp
index c073d0a..780d10c 100644
--- a/guest/hals/keymint/rust/Android.bp
+++ b/guest/hals/keymint/rust/Android.bp
@@ -20,12 +20,6 @@
 rust_binary {
     name: "android.hardware.security.keymint-service.rust",
     relative_install_path: "hw",
-    init_rc: ["android.hardware.security.keymint-service.rust.rc"],
-    vintf_fragments: [
-        "android.hardware.security.keymint-service.rust.xml",
-        "android.hardware.security.secureclock-service.rust.xml",
-        "android.hardware.security.sharedsecret-service.rust.xml",
-    ],
     vendor: true,
     srcs: ["src/keymint_hal_main.rs"],
     rustlibs: [
@@ -37,14 +31,65 @@
         "liblibc",
         "liblog_rust",
     ],
-    required: [
-        "android.hardware.hardware_keystore.rust-keymint.xml",
-    ],
+    prefer_rlib: true,
 }
 
+// init_rc
+prebuilt_etc {
+    name: "android.hardware.security.keymint-service.rust.rc",
+    vendor: true,
+    src: "android.hardware.security.keymint-service.rust.rc",
+}
+
+// vintf_fragments
+prebuilt_etc {
+    name: "android.hardware.security.keymint-service.rust.xml",
+    sub_dir: "vintf",
+    vendor: true,
+    src: "android.hardware.security.keymint-service.rust.xml",
+}
+
+prebuilt_etc {
+    name: "android.hardware.security.sharedsecret-service.rust.xml",
+    sub_dir: "vintf",
+    vendor: true,
+    src: "android.hardware.security.sharedsecret-service.rust.xml",
+}
+
+prebuilt_etc {
+    name: "android.hardware.security.secureclock-service.rust.xml",
+    sub_dir: "vintf",
+    vendor: true,
+    src: "android.hardware.security.secureclock-service.rust.xml",
+}
+
+// permissions
 prebuilt_etc {
     name: "android.hardware.hardware_keystore.rust-keymint.xml",
     sub_dir: "permissions",
     vendor: true,
     src: "android.hardware.hardware_keystore.rust-keymint.xml",
 }
+
+apex {
+    name: "com.google.cf.keymint.rust",
+    manifest: "manifest.json",
+    file_contexts: "file_contexts",
+    key: "com.google.cf.apex.key",
+    certificate: ":com.google.cf.apex.certificate",
+    soc_specific: true,
+    updatable: false,
+    binaries: [
+        "android.hardware.security.keymint-service.rust",
+    ],
+    prebuilts: [
+        // init_rc
+        "android.hardware.security.keymint-service.rust.rc",
+        // vintf_fragments
+        "android.hardware.security.keymint-service.rust.xml",
+        "android.hardware.security.secureclock-service.rust.xml",
+        "android.hardware.security.sharedsecret-service.rust.xml",
+        // permissions
+        "android.hardware.hardware_keystore.rust-keymint.xml",
+    ],
+}
diff --git a/guest/hals/keymint/rust/android.hardware.security.keymint-service.rust.rc b/guest/hals/keymint/rust/android.hardware.security.keymint-service.rust.rc
index 5c6d1f8..b53859b 100644
--- a/guest/hals/keymint/rust/android.hardware.security.keymint-service.rust.rc
+++ b/guest/hals/keymint/rust/android.hardware.security.keymint-service.rust.rc
@@ -1,4 +1,4 @@
-service vendor.keymint-rust /vendor/bin/hw/android.hardware.security.keymint-service.rust
+service vendor.keymint-rust /apex/com.google.cf.keymint.rust/bin/hw/android.hardware.security.keymint-service.rust
     class early_hal
     user nobody
     # The keymint service is not allowed to restart.
diff --git a/guest/hals/keymint/rust/file_contexts b/guest/hals/keymint/rust/file_contexts
new file mode 100644
index 0000000..b396d14
--- /dev/null
+++ b/guest/hals/keymint/rust/file_contexts
@@ -0,0 +1,3 @@
+(/.*)?                                                      u:object_r:vendor_file:s0
+/etc(/.*)?                                                  u:object_r:vendor_configs_file:s0
+/bin/hw/android\.hardware\.security\.keymint-service\.rust  u:object_r:hal_keymint_rust_exec:s0
\ No newline at end of file
diff --git a/guest/hals/keymint/rust/manifest.json b/guest/hals/keymint/rust/manifest.json
new file mode 100644
index 0000000..c68870a
--- /dev/null
+++ b/guest/hals/keymint/rust/manifest.json
@@ -0,0 +1,5 @@
+{
+  "name": "com.google.cf.keymint.rust",
+  "version": 1,
+  "vendorBootstrap": true
+}
diff --git a/guest/hals/light/Android.bp b/guest/hals/light/Android.bp
index 13e2607..27f8ed6 100644
--- a/guest/hals/light/Android.bp
+++ b/guest/hals/light/Android.bp
@@ -13,6 +13,8 @@
         "liblog_rust",
         "libbinder_rs",
         "android.hardware.light-V2-rust",
+        "libvsock_utils_rust",
+        "librustutils",
     ],
     srcs: [ "main.rs" ],
 }
diff --git a/guest/hals/light/lights-cuttlefish.rc b/guest/hals/light/lights-cuttlefish.rc
index ae68e83..2c73861 100644
--- a/guest/hals/light/lights-cuttlefish.rc
+++ b/guest/hals/light/lights-cuttlefish.rc
@@ -1,4 +1,4 @@
-service vendor.light-default /vendor/bin/hw/android.hardware.lights-service.cuttlefish
+service vendor.light-cuttlefish /vendor/bin/hw/android.hardware.lights-service.cuttlefish
     class hal
     user nobody
     group nobody
diff --git a/guest/hals/light/lights.rs b/guest/hals/light/lights.rs
index 6c8aa3f..944d495 100644
--- a/guest/hals/light/lights.rs
+++ b/guest/hals/light/lights.rs
@@ -15,6 +15,7 @@
  */
 //! This module implements the ILights AIDL interface.
 
+use rustutils::system_properties;
 use std::collections::HashMap;
 use std::sync::Mutex;
 
@@ -26,6 +27,9 @@
 
 use binder::{ExceptionCode, Interface, Status};
 
+mod lights_vsock_server;
+use lights_vsock_server::VsockServer;
+
 struct Light {
     hw_light: HwLight,
     state: HwLightState,
@@ -36,6 +40,8 @@
 /// Defined so we can implement the ILights AIDL interface.
 pub struct LightsService {
     lights: Mutex<HashMap<i32, Light>>,
+    // TODO(b/295543722): Move to a virtio_console transport instead.
+    vsock_server: VsockServer,
 }
 
 impl Interface for LightsService {}
@@ -48,7 +54,22 @@
             lights_map.insert(hw_light.id, Light { hw_light, state: Default::default() });
         }
 
-        Self { lights: Mutex::new(lights_map) }
+        let mut service = Self { lights: Mutex::new(lights_map), vsock_server: VsockServer::new() };
+
+        let lights_server_port: u32 = system_properties::read("ro.boot.vsock_lights_port")
+            .unwrap_or(None)
+            .unwrap_or("0".to_string())
+            .parse()
+            .unwrap();
+        let guest_cid: u32 = system_properties::read("ro.boot.vsock_lights_cid")
+            .unwrap_or(None)
+            .unwrap_or("0".to_string())
+            .parse()
+            .unwrap();
+
+        service.vsock_server.start(lights_server_port, guest_cid);
+
+        service
     }
 }
 
diff --git a/guest/hals/light/lights/lights_vsock_server.rs b/guest/hals/light/lights/lights_vsock_server.rs
new file mode 100644
index 0000000..5a3525e
--- /dev/null
+++ b/guest/hals/light/lights/lights_vsock_server.rs
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+//! This module provides a Vsock Server helper.
+
+use log::info;
+use std::sync::atomic::{AtomicBool, Ordering};
+use std::sync::{Arc, Mutex};
+use std::thread;
+use vsock_utils::VsockServerConnection;
+
+/// Vsock server helper.
+pub struct VsockServer {
+    vsock_connection: Arc<Mutex<VsockServerConnection>>,
+    is_server_running: Arc<AtomicBool>,
+    thread_handle: Option<thread::JoinHandle<()>>,
+}
+
+impl VsockServer {
+    pub fn new() -> Self {
+        Self {
+            vsock_connection: Arc::new(Mutex::new(VsockServerConnection::new())),
+            is_server_running: Arc::new(AtomicBool::new(false)),
+            thread_handle: None,
+        }
+    }
+
+    /// Spawns a thread to start accepting connections from clients.
+    pub fn start(&mut self, port: u32, cid: u32) {
+        self.stop();
+        info!("Starting vsocks server for Lights service on port {} cid {}", port, cid);
+
+        self.is_server_running.store(true, Ordering::SeqCst);
+
+        let vsock_connection = self.vsock_connection.clone();
+        let is_running = self.is_server_running.clone();
+        self.thread_handle = Some(thread::spawn(move || {
+            while is_running.load(Ordering::SeqCst) {
+                if vsock_connection.lock().unwrap().connect(port, cid) {
+                    info!("Lights service Vsock server connection established.");
+                    // TODO: finish this once we know the protocol
+                }
+            }
+        }));
+    }
+
+    /// Stops the server thread.
+    pub fn stop(&mut self) {
+        info!("Stopping vsocks server for Lights service");
+
+        self.vsock_connection.lock().unwrap().server_shutdown();
+        self.is_server_running.store(false, Ordering::SeqCst);
+
+        if self.thread_handle.is_some() {
+            let handle = self.thread_handle.take().expect("Thread handle should be valid");
+            if handle.is_finished() {
+                handle.join().expect("Could not join thread");
+            }
+        }
+    }
+}
+
+impl Default for VsockServer {
+    fn default() -> Self {
+        Self::new()
+    }
+}
diff --git a/guest/hals/ril/reference-libril/ril_service.cpp b/guest/hals/ril/reference-libril/ril_service.cpp
index 96b00fe..f934852 100644
--- a/guest/hals/ril/reference-libril/ril_service.cpp
+++ b/guest/hals/ril/reference-libril/ril_service.cpp
@@ -11061,15 +11061,17 @@
     dcResult.ifname = convertCharPtrToHidlString(dcResponse->ifname);
 
     std::vector<::android::hardware::radio::V1_5::LinkAddress> linkAddresses;
-    std::stringstream ss(static_cast<std::string>(dcResponse->addresses));
-    std::string tok;
-    while(getline(ss, tok, ' ')) {
-        ::android::hardware::radio::V1_5::LinkAddress la;
-        la.address = hidl_string(tok);
-        la.properties = 0;
-        la.deprecationTime = INT64_MAX;  // LinkAddress.java LIFETIME_PERMANENT = Long.MAX_VALUE
-        la.expirationTime = INT64_MAX;  // --"--
-        linkAddresses.push_back(la);
+    if (dcResponse->addresses != NULL) {
+        std::stringstream ss(static_cast<std::string>(dcResponse->addresses));
+        std::string tok;
+        while (getline(ss, tok, ' ')) {
+            ::android::hardware::radio::V1_5::LinkAddress la;
+            la.address = hidl_string(tok);
+            la.properties = 0;
+            la.deprecationTime = INT64_MAX;  // LinkAddress.java LIFETIME_PERMANENT = Long.MAX_VALUE
+            la.expirationTime = INT64_MAX;   // --"--
+            linkAddresses.push_back(la);
+        }
     }
 
     dcResult.addresses = linkAddresses;
diff --git a/guest/hals/uwb/uwb-service.rc b/guest/hals/uwb/uwb-service.rc
deleted file mode 100644
index eb9d205..0000000
--- a/guest/hals/uwb/uwb-service.rc
+++ /dev/null
@@ -1,3 +0,0 @@
-service vendor.uwb_hal /vendor/bin/hw/android.hardware.uwb-service /dev/hvc9
-    class hal
-    user uwb
diff --git a/guest/monitoring/tombstone_transmit/Android.bp b/guest/monitoring/tombstone_transmit/Android.bp
index 86daf8b..add2ace 100644
--- a/guest/monitoring/tombstone_transmit/Android.bp
+++ b/guest/monitoring/tombstone_transmit/Android.bp
@@ -36,8 +36,8 @@
         "tombstone_transmit.cpp",
     ],
     static_libs: [
-        "libcuttlefish_fs_product",
-        "libcuttlefish_utils_product",
+        "libcuttlefish_fs",
+        "libcuttlefish_utils",
     ],
     defaults: [
         "tombstone_transmit_defaults",
diff --git a/host/commands/assemble_cvd/Android.bp b/host/commands/assemble_cvd/Android.bp
index 42fbc0e..f6b1294 100644
--- a/host/commands/assemble_cvd/Android.bp
+++ b/host/commands/assemble_cvd/Android.bp
@@ -22,6 +22,7 @@
     srcs: [
         "alloc.cc",
         "assemble_cvd.cc",
+        "bootconfig_args.cpp",
         "boot_config.cc",
         "boot_image_utils.cc",
         "clean.cc",
@@ -103,5 +104,5 @@
             ],
         },
     },
-    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
+    defaults: ["cuttlefish_host"],
 }
diff --git a/host/commands/assemble_cvd/assemble_cvd.cc b/host/commands/assemble_cvd/assemble_cvd.cc
index ed7b0d3..0266c51 100644
--- a/host/commands/assemble_cvd/assemble_cvd.cc
+++ b/host/commands/assemble_cvd/assemble_cvd.cc
@@ -14,6 +14,7 @@
 // limitations under the License.
 
 #include <iostream>
+#include <string_view>
 
 #include <android-base/logging.h>
 #include <android-base/parsebool.h>
@@ -47,19 +48,23 @@
 DEFINE_string(instance_dir, CF_DEFAULTS_INSTANCE_DIR,
               "This is a directory that will hold the cuttlefish generated"
               "files, including both instance-specific and common files");
+DEFINE_string(snapshot_path, "",
+              "Path to snapshot. Must not be empty if the device is to be "
+              "restored from a snapshot");
 DEFINE_bool(resume, CF_DEFAULTS_RESUME,
             "Resume using the disk from the last session, if "
             "possible. i.e., if --noresume is passed, the disk "
             "will be reset to the state it was initially launched "
             "in. This flag is ignored if the underlying partition "
-            "images have been updated since the first launch.");
+            "images have been updated since the first launch."
+            "If the device starts from a snapshot, this will be always true.");
 
 DECLARE_bool(use_overlay);
 
 namespace cuttlefish {
 namespace {
 
-std::string kFetcherConfigFile = "fetcher_config.json";
+static constexpr std::string_view kFetcherConfigFile = "fetcher_config.json";
 
 FetcherConfig FindFetcherConfig(const std::vector<std::string>& files) {
   FetcherConfig fetcher_config;
@@ -433,7 +438,7 @@
   CF_EXPECT(FlagFeature::ProcessFlags(flag_features, args),
             "Failed to parse flags.");
 
-  if (help || help_str != "") {
+  if (help || !help_str.empty()) {
     LOG(WARNING) << "TODO(schuffelen): Implement `--help` for assemble_cvd.";
     LOG(WARNING) << "In the meantime, call `launch_cvd --help`";
     return 1;
@@ -443,6 +448,12 @@
     }
     return 1;  // For parity with gflags
   }
+
+  // set --resume=true if --snapshot_path is not empty
+  const std::string snapshot_path(FLAGS_snapshot_path);
+  CF_EXPECT(snapshot_path.empty() || FLAGS_resume,
+            "--resume must be true when restoring from snapshot.");
+
   // TODO(schuffelen): Put in "unknown flag" guards after gflags is removed.
   // gflags either consumes all arguments that start with - or leaves all of
   // them in place, and either errors out on unknown flags or accepts any flags.
diff --git a/host/commands/assemble_cvd/boot_config.cc b/host/commands/assemble_cvd/boot_config.cc
index f46ae6b..4c34deb 100644
--- a/host/commands/assemble_cvd/boot_config.cc
+++ b/host/commands/assemble_cvd/boot_config.cc
@@ -31,7 +31,7 @@
 #include "common/libs/utils/result.h"
 #include "common/libs/utils/size_utils.h"
 #include "common/libs/utils/subprocess.h"
-#include "host/libs/config/bootconfig_args.h"
+#include "host/commands/assemble_cvd/bootconfig_args.h"
 #include "host/libs/config/cuttlefish_config.h"
 #include "host/libs/config/kernel_args.h"
 #include "host/libs/vm_manager/crosvm_manager.h"
diff --git a/host/libs/config/bootconfig_args.cpp b/host/commands/assemble_cvd/bootconfig_args.cpp
similarity index 94%
rename from host/libs/config/bootconfig_args.cpp
rename to host/commands/assemble_cvd/bootconfig_args.cpp
index 77cc621..4e24f74 100644
--- a/host/libs/config/bootconfig_args.cpp
+++ b/host/commands/assemble_cvd/bootconfig_args.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "host/libs/config/bootconfig_args.h"
+#include "host/commands/assemble_cvd/bootconfig_args.h"
 
 #include <array>
 #include <sstream>
@@ -60,7 +60,7 @@
     // need to mux, and would prefer to retain the kernel dmesg logging, so we
     // must work around init falling back to the check for /dev/console (which
     // we'll always have).
-    //bootconfig_args["androidboot.console"] = "invalid";
+    // bootconfig_args["androidboot.console"] = "invalid";
     // The bug above has been fixed in Android 14 and later so we can just
     // specify androidboot.serialconsole=0 instead.
     bootconfig_args["androidboot.serialconsole"] = "0";
@@ -81,9 +81,7 @@
   auto vmm =
       vm_manager::GetVmManager(config.vm_manager(), instance.target_arch());
   AppendMapWithReplacement(&bootconfig_args,
-                           CF_EXPECT(vmm->ConfigureBootDevices(
-                               instance.virtual_disk_paths().size(),
-                               instance.hwcomposer() != kHwComposerNone)));
+                           CF_EXPECT(vmm->ConfigureBootDevices(instance)));
 
   AppendMapWithReplacement(&bootconfig_args,
                            CF_EXPECT(vmm->ConfigureGraphics(instance)));
@@ -152,6 +150,13 @@
         std::to_string(instance.vsock_guest_cid());
   }
 
+  if (instance.lights_server_port()) {
+    bootconfig_args["androidboot.vsock_lights_port"] =
+        std::to_string(instance.lights_server_port());
+    bootconfig_args["androidboot.vsock_lights_cid"] =
+        std::to_string(instance.vsock_guest_cid());
+  }
+
   if (instance.enable_modem_simulator() &&
       instance.modem_simulator_ports() != "") {
     bootconfig_args["androidboot.modem_simulator_ports"] =
diff --git a/host/libs/config/bootconfig_args.h b/host/commands/assemble_cvd/bootconfig_args.h
similarity index 100%
rename from host/libs/config/bootconfig_args.h
rename to host/commands/assemble_cvd/bootconfig_args.h
diff --git a/host/commands/assemble_cvd/disk/generate_persistent_bootconfig.cpp b/host/commands/assemble_cvd/disk/generate_persistent_bootconfig.cpp
index 4624ed4..5682205 100644
--- a/host/commands/assemble_cvd/disk/generate_persistent_bootconfig.cpp
+++ b/host/commands/assemble_cvd/disk/generate_persistent_bootconfig.cpp
@@ -26,7 +26,7 @@
 #include "common/libs/utils/files.h"
 #include "common/libs/utils/result.h"
 #include "common/libs/utils/size_utils.h"
-#include "host/libs/config/bootconfig_args.h"
+#include "host/commands/assemble_cvd/bootconfig_args.h"
 #include "host/libs/config/cuttlefish_config.h"
 #include "host/libs/config/data_image.h"
 #include "host/libs/config/feature.h"
diff --git a/host/commands/assemble_cvd/disk_flags.cc b/host/commands/assemble_cvd/disk_flags.cc
index c180550..38f438b 100644
--- a/host/commands/assemble_cvd/disk_flags.cc
+++ b/host/commands/assemble_cvd/disk_flags.cc
@@ -33,12 +33,12 @@
 #include "common/libs/utils/subprocess.h"
 #include "host/commands/assemble_cvd/boot_config.h"
 #include "host/commands/assemble_cvd/boot_image_utils.h"
-#include "host/commands/assemble_cvd/disk_builder.h"
+#include "host/commands/assemble_cvd/bootconfig_args.h"
 #include "host/commands/assemble_cvd/disk/disk.h"
+#include "host/commands/assemble_cvd/disk_builder.h"
 #include "host/commands/assemble_cvd/flags_defaults.h"
 #include "host/commands/assemble_cvd/super_image_mixer.h"
 #include "host/commands/assemble_cvd/vendor_dlkm_utils.h"
-#include "host/libs/config/bootconfig_args.h"
 #include "host/libs/config/cuttlefish_config.h"
 #include "host/libs/config/data_image.h"
 #include "host/libs/config/inject.h"
diff --git a/host/commands/assemble_cvd/flags.cc b/host/commands/assemble_cvd/flags.cc
index 7c89813..21ee4e5 100644
--- a/host/commands/assemble_cvd/flags.cc
+++ b/host/commands/assemble_cvd/flags.cc
@@ -141,6 +141,9 @@
 DEFINE_vec(enable_gpu_udmabuf,
            fmt::format("{}", CF_DEFAULTS_ENABLE_GPU_UDMABUF),
            "Use the udmabuf driver for zero-copy virtio-gpu");
+DEFINE_vec(enable_gpu_vhost_user,
+           fmt::format("{}", CF_DEFAULTS_ENABLE_GPU_VHOST_USER),
+           "Run the Virtio GPU worker in a separate process.");
 
 DEFINE_vec(use_allocd, CF_DEFAULTS_USE_ALLOCD?"true":"false",
             "Acquire static resources from the resource allocator daemon.");
@@ -174,6 +177,8 @@
 
 DEFINE_bool(netsim_bt, CF_DEFAULTS_NETSIM_BT,
             "[Experimental] Connect Bluetooth radio to netsim.");
+DEFINE_string(netsim_args, CF_DEFAULTS_NETSIM_ARGS,
+              "Space-separated list of netsim args.");
 
 /**
  * crosvm sandbox feature requires /var/empty and seccomp directory
@@ -423,8 +428,16 @@
 DEFINE_vec(use_pmem, "true",
            "Make this flag false to disable pmem with crosvm");
 
-DEFINE_bool(enable_wifi, true,
-            "Enables the guest WIFI. Disable this only for Minidroid.");
+/* TODO(kwstephenkim): replace this flag with "--start-from-snapshot" or so.
+ *
+ * This flag only makes sense to be "false" if cuttlefish device starts from
+ * the saved snapshot.
+ */
+DEFINE_vec(sock_vsock_proxy_wait_adbd_start, "true",
+           "Make this flag false for sock_vsock_proxy not to wait for adbd"
+           "This is needed when the device is restored from a snapshot.");
+
+DEFINE_bool(enable_wifi, true, "Enables the guest WIFI. Mainly for Minidroid");
 
 DEFINE_vec(device_external_network, CF_DEFAULTS_DEVICE_EXTERNAL_NETWORK,
            "The mechanism to connect to the public internet.");
@@ -432,6 +445,7 @@
 DECLARE_string(assembly_dir);
 DECLARE_string(boot_image);
 DECLARE_string(system_image_dir);
+DECLARE_string(snapshot_path);
 
 namespace cuttlefish {
 using vm_manager::QemuManager;
@@ -832,8 +846,8 @@
 #endif
 
 Result<std::string> InitializeGpuMode(
-    const std::string& gpu_mode_arg, const std::string& vm_manager,
-    const GuestConfig& guest_config,
+    const std::string& gpu_mode_arg, const bool gpu_vhost_user_arg,
+    const std::string& vm_manager, const GuestConfig& guest_config,
     CuttlefishConfig::MutableInstanceSpecific* instance) {
 #ifdef __APPLE__
   (void)vm_manager;
@@ -860,8 +874,22 @@
       angle_features.angle_feature_overrides_enabled);
   instance->set_gpu_angle_feature_overrides_disabled(
       angle_features.angle_feature_overrides_disabled);
+
+  if (gpu_vhost_user_arg) {
+    const auto gpu_vhost_user_features =
+        CF_EXPECT(GetNeededVhostUserGpuHostRendererFeatures(
+            CF_EXPECT(GetRenderingMode(gpu_mode)), graphics_availability));
+    instance->set_enable_gpu_external_blob(
+        gpu_vhost_user_features.external_blob);
+    instance->set_enable_gpu_system_blob(gpu_vhost_user_features.system_blob);
+  } else {
+    instance->set_enable_gpu_external_blob(false);
+    instance->set_enable_gpu_system_blob(false);
+  }
+
 #endif
   instance->set_gpu_mode(gpu_mode);
+  instance->set_enable_gpu_vhost_user(gpu_vhost_user_arg);
   return gpu_mode;
 }
 
@@ -913,6 +941,9 @@
 
   tmp_config_obj.set_gem5_debug_flags(FLAGS_gem5_debug_flags);
 
+  // setting snapshot path
+  tmp_config_obj.set_snapshot_path(FLAGS_snapshot_path);
+
   // streaming, webrtc setup
   tmp_config_obj.set_webrtc_certs_dir(FLAGS_webrtc_certs_dir);
   tmp_config_obj.set_sig_server_secure(FLAGS_webrtc_sig_server_secure);
@@ -1058,6 +1089,8 @@
       CF_EXPECT(GET_FLAG_STR_VALUE(hwcomposer));
   std::vector<bool> enable_gpu_udmabuf_vec =
       CF_EXPECT(GET_FLAG_BOOL_VALUE(enable_gpu_udmabuf));
+  std::vector<bool> enable_gpu_vhost_user_vec =
+      CF_EXPECT(GET_FLAG_BOOL_VALUE(enable_gpu_vhost_user));
   std::vector<bool> smt_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(smt));
   std::vector<std::string> crosvm_binary_vec =
       CF_EXPECT(GET_FLAG_STR_VALUE(crosvm_binary));
@@ -1085,7 +1118,8 @@
   std::vector<bool> use_rng_vec =
       CF_EXPECT(GET_FLAG_BOOL_VALUE(crosvm_use_rng));
   std::vector<bool> use_pmem_vec = CF_EXPECT(GET_FLAG_BOOL_VALUE(use_pmem));
-
+  std::vector<bool> sock_vsock_proxy_wait_adbd_vec =
+      CF_EXPECT(GET_FLAG_BOOL_VALUE(sock_vsock_proxy_wait_adbd_start));
   std::vector<std::string> device_external_network_vec =
       CF_EXPECT(GET_FLAG_STR_VALUE(device_external_network));
 
@@ -1110,6 +1144,7 @@
   int netsim_instance_num = *instance_nums.begin() - 1;
   tmp_config_obj.set_netsim_instance_num(netsim_instance_num);
   LOG(DEBUG) << "netsim_instance_num: " << netsim_instance_num;
+  tmp_config_obj.set_netsim_args(FLAGS_netsim_args);
 
   // crosvm should create fifos for UWB
   auto pica_instance_num = *instance_nums.begin() - 1;
@@ -1147,6 +1182,8 @@
     instance.set_crosvm_use_balloon(use_balloon_vec[instance_index]);
     instance.set_crosvm_use_rng(use_rng_vec[instance_index]);
     instance.set_use_pmem(use_pmem_vec[instance_index]);
+    instance.set_sock_vsock_proxy_wait_adbd_start(
+        sock_vsock_proxy_wait_adbd_vec[instance_index]);
     instance.set_bootconfig_supported(guest_configs[instance_index].bootconfig_supported);
     instance.set_filename_encryption_mode(
       guest_configs[instance_index].hctr2_supported ? "hctr2" : "cts");
@@ -1289,8 +1326,7 @@
     instance.set_qemu_vnc_server_port(544 + num - 1);
     instance.set_adb_host_port(6520 + num - 1);
     instance.set_adb_ip_and_port("0.0.0.0:" + std::to_string(6520 + num - 1));
-
-    instance.set_fastboot_host_port(7520 + num - 1);
+    instance.set_fastboot_host_port(const_instance.adb_host_port());
 
     std::uint8_t ethernet_mac[6] = {};
     std::uint8_t mobile_mac[6] = {};
@@ -1310,11 +1346,13 @@
     instance.set_vehicle_hal_server_port(9300 + num - 1);
     instance.set_audiocontrol_server_port(9410);  /* OK to use the same port number across instances */
     instance.set_config_server_port(calc_vsock_port(6800));
+    instance.set_lights_server_port(calc_vsock_port(6900));
 
     // gpu related settings
     const std::string gpu_mode = CF_EXPECT(InitializeGpuMode(
-        gpu_mode_vec[instance_index], vm_manager_vec[instance_index],
-        guest_configs[instance_index], &instance));
+        gpu_mode_vec[instance_index], enable_gpu_vhost_user_vec[instance_index],
+        vm_manager_vec[instance_index], guest_configs[instance_index],
+        &instance));
 
     instance.set_restart_subprocesses(restart_subprocesses_vec[instance_index]);
     instance.set_gpu_capture_binary(gpu_capture_binary_vec[instance_index]);
@@ -1489,7 +1527,7 @@
     instance.set_start_rootcanal(is_first_instance && !is_bt_netsim &&
                                  (FLAGS_rootcanal_instance_num <= 0));
 
-    instance.set_start_pica(is_first_instance);
+    instance.set_start_pica(is_first_instance && FLAGS_pica_instance_num <= 0);
 
     if (!FLAGS_ap_rootfs_image.empty() && !FLAGS_ap_kernel_image.empty() && start_wmediumd) {
       // TODO(264537774): Ubuntu grub modules / grub monoliths cannot be used to boot
diff --git a/host/commands/assemble_cvd/flags_defaults.h b/host/commands/assemble_cvd/flags_defaults.h
index dcc7078..89eaa3e 100644
--- a/host/commands/assemble_cvd/flags_defaults.h
+++ b/host/commands/assemble_cvd/flags_defaults.h
@@ -133,6 +133,7 @@
 #define CF_DEFAULTS_RECORD_SCREEN false
 #define CF_DEFAULTS_GPU_CAPTURE_BINARY CF_DEFAULTS_DYNAMIC_STRING
 #define CF_DEFAULTS_ENABLE_GPU_UDMABUF false
+#define CF_DEFAULTS_ENABLE_GPU_VHOST_USER false
 #define CF_DEFAULTS_DISPLAY0 CF_DEFAULTS_DYNAMIC_STRING
 #define CF_DEFAULTS_DISPLAY1 CF_DEFAULTS_DYNAMIC_STRING
 #define CF_DEFAULTS_DISPLAY2 CF_DEFAULTS_DYNAMIC_STRING
@@ -147,6 +148,9 @@
 #define CF_DEFAULTS_NETSIM false
 #define CF_DEFAULTS_NETSIM_BT true
 
+// Netsim default parameters
+#define CF_DEFAULTS_NETSIM_ARGS ""
+
 // Wifi default parameters
 #define CF_DEFAULTS_AP_KERNEL_IMAGE CF_DEFAULTS_DYNAMIC_STRING
 #define CF_DEFAULTS_AP_ROOTFS_IMAGE CF_DEFAULTS_DYNAMIC_STRING
diff --git a/host/commands/assemble_cvd/proto/Android.bp b/host/commands/assemble_cvd/proto/Android.bp
index 767f728..6b32c5f 100644
--- a/host/commands/assemble_cvd/proto/Android.bp
+++ b/host/commands/assemble_cvd/proto/Android.bp
@@ -18,7 +18,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_launch_cvd_proto",
     host_supported: true,
     proto: {
@@ -31,5 +31,5 @@
             enabled: true,
         },
     },
-    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
+    defaults: ["cuttlefish_host"],
 }
diff --git a/host/commands/assemble_cvd/ramdisk_modules.h b/host/commands/assemble_cvd/ramdisk_modules.h
deleted file mode 100644
index 7f23e4a..0000000
--- a/host/commands/assemble_cvd/ramdisk_modules.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2023 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.
- */
-
-#pragma once
-#include <set>
-
-static constexpr auto RAMDISK_MODULES = {
-    "failover.ko",   "nd_virtio.ko",      "net_failover.ko",
-    "virtio_blk.ko", "virtio_console.ko", "virtio_dma_buf.ko",
-    "virtio-gpu.ko", "virtio_input.ko",   "virtio_net.ko",
-    "virtio_pci.ko", "virtio-rng.ko",     "vmw_vsock_virtio_transport.ko",
-};
\ No newline at end of file
diff --git a/host/commands/assemble_cvd/super_image_mixer.cc b/host/commands/assemble_cvd/super_image_mixer.cc
index 2eb937b..7336fa1 100644
--- a/host/commands/assemble_cvd/super_image_mixer.cc
+++ b/host/commands/assemble_cvd/super_image_mixer.cc
@@ -13,14 +13,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "super_image_mixer.h"
+#include "host/commands/assemble_cvd/super_image_mixer.h"
 
-#include <errno.h>
 #include <sys/stat.h>
 
 #include <algorithm>
-#include <cstdio>
-#include <functional>
+#include <array>
 #include <memory>
 
 #include <android-base/strings.h>
@@ -28,6 +26,7 @@
 
 #include "common/libs/fs/shared_buf.h"
 #include "common/libs/utils/archive.h"
+#include "common/libs/utils/contains.h"
 #include "common/libs/utils/files.h"
 #include "common/libs/utils/subprocess.h"
 #include "host/commands/assemble_cvd/misc_info.h"
@@ -88,20 +87,24 @@
   return "";
 }
 
-const std::string kMiscInfoPath = "META/misc_info.txt";
-const std::set<std::string> kDefaultTargetImages = {
-    "IMAGES/boot.img",        "IMAGES/init_boot.img",
-    "IMAGES/odm.img",         "IMAGES/odm_dlkm.img",
-    "IMAGES/recovery.img",    "IMAGES/userdata.img",
-    "IMAGES/vbmeta.img",      "IMAGES/vendor.img",
-    "IMAGES/vendor_dlkm.img", "IMAGES/vbmeta_vendor_dlkm.img",
+constexpr char kMiscInfoPath[] = "META/misc_info.txt";
+constexpr std::array kDefaultTargetImages = {
+    "IMAGES/boot.img",
+    "IMAGES/odm.img",
+    "IMAGES/odm_dlkm.img",
+    "IMAGES/recovery.img",
+    "IMAGES/userdata.img",
+    "IMAGES/vbmeta.img",
+    "IMAGES/vendor.img",
+    "IMAGES/vendor_dlkm.img",
+    "IMAGES/vbmeta_vendor_dlkm.img",
     "IMAGES/system_dlkm.img",
 };
-const std::set<std::string> kDefaultTargetBuildProp = {
-  "ODM/build.prop",
-  "ODM/etc/build.prop",
-  "VENDOR/build.prop",
-  "VENDOR/etc/build.prop",
+constexpr std::array kDefaultTargetBuildProp = {
+    "ODM/build.prop",
+    "ODM/etc/build.prop",
+    "VENDOR/build.prop",
+    "VENDOR/etc/build.prop",
 };
 
 void FindImports(Archive* archive, const std::string& build_prop_file) {
@@ -185,7 +188,7 @@
       continue;
     } else if (!android::base::EndsWith(name, ".img")) {
       continue;
-    } else if (kDefaultTargetImages.count(name) == 0) {
+    } else if (!Contains(kDefaultTargetImages, name)) {
       continue;
     }
     LOG(INFO) << "Writing " << name;
@@ -195,7 +198,7 @@
   for (const auto& name : default_target_contents) {
     if (!android::base::EndsWith(name, "build.prop")) {
       continue;
-    } else if (kDefaultTargetBuildProp.count(name) == 0) {
+    } else if (!Contains(kDefaultTargetBuildProp, name)) {
       continue;
     }
     FindImports(&default_target_archive, name);
@@ -209,7 +212,7 @@
       continue;
     } else if (!android::base::EndsWith(name, ".img")) {
       continue;
-    } else if (kDefaultTargetImages.count(name) > 0) {
+    } else if (Contains(kDefaultTargetImages, name)) {
       continue;
     }
     LOG(INFO) << "Writing " << name;
@@ -219,7 +222,7 @@
   for (const auto& name : system_target_contents) {
     if (!android::base::EndsWith(name, "build.prop")) {
       continue;
-    } else if (kDefaultTargetBuildProp.count(name) > 0) {
+    } else if (Contains(kDefaultTargetBuildProp, name)) {
       continue;
     }
     FindImports(&system_target_archive, name);
diff --git a/host/commands/assemble_cvd/vendor_dlkm_utils.cc b/host/commands/assemble_cvd/vendor_dlkm_utils.cc
index ed6f7b2..4681da7 100644
--- a/host/commands/assemble_cvd/vendor_dlkm_utils.cc
+++ b/host/commands/assemble_cvd/vendor_dlkm_utils.cc
@@ -13,31 +13,26 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-
 #include <fcntl.h>
 
-#include <fcntl.h>
 #include <algorithm>
-#include <iterator>
 #include <map>
-#include <queue>
 #include <set>
 #include <sstream>
 #include <string>
 #include <vector>
 
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 #include <fmt/format.h>
 
+#include "common/libs/utils/contains.h"
 #include "common/libs/utils/files.h"
 #include "common/libs/utils/subprocess.h"
-#include "fmt/core.h"
 #include "host/commands/assemble_cvd/boot_image_utils.h"
 #include "host/commands/assemble_cvd/kernel_module_parser.h"
-#include "host/commands/assemble_cvd/ramdisk_modules.h"
 #include "host/libs/config/cuttlefish_config.h"
 
 namespace cuttlefish {
@@ -108,15 +103,34 @@
 
 std::vector<std::string> GetRamdiskModules(
     const std::vector<std::string>& all_modules) {
-  static const auto ramdisk_modules_allow_list =
-      std::set<std::string>(RAMDISK_MODULES.begin(), RAMDISK_MODULES.end());
+  static constexpr auto kRamdiskModules = {
+      "failover.ko",
+      "nd_virtio.ko",
+      "net_failover.ko",
+      "virtio_blk.ko",
+      "virtio_console.ko",
+      "virtio_dma_buf.ko",
+      "virtio-gpu.ko",
+      "virtio_input.ko",
+      "virtio_net.ko",
+      "virtio_pci.ko",
+      "virtio_pci_legacy_dev.ko",
+      "virtio_pci_modern_dev.ko",
+      "virtio-rng.ko",
+      "vmw_vsock_virtio_transport.ko",
+      "vmw_vsock_virtio_transport_common.ko",
+      "vsock.ko",
+      // TODO(b/176860479) once virt_wifi is deprecated fully,
+      // these following modules can be loaded in second stage init
+      "libarc4.ko",
+      "rfkill.ko",
+      "cfg80211.ko",
+      "mac80211.ko",
+      "mac80211_hwsim.ko",
+  };
   std::vector<std::string> ramdisk_modules;
   for (const auto& mod_path : all_modules) {
-    if (mod_path.empty()) {
-      continue;
-    }
-    const auto mod_name = cpp_basename(mod_path);
-    if (ramdisk_modules_allow_list.count(mod_name) != 0) {
+    if (Contains(kRamdiskModules, android::base::Basename(mod_path))) {
       ramdisk_modules.emplace_back(mod_path);
     }
   }
@@ -513,6 +527,17 @@
             << vendor_dlkm_modules.size() << " vendor_dlkm modules, "
             << system_dlkm_modules.size() << " system_dlkm modules.";
 
+  // transfer blocklist in whole to the vendor dlkm partition. It currently
+  // only contains one module that is loaded during second stage init.
+  // We can split the blocklist at a later date IF it contains modules in
+  // different partitions.
+  const auto initramfs_blocklist_path = module_base_dir + "/modules.blocklist";
+  if (FileExists(initramfs_blocklist_path)) {
+    const auto vendor_dlkm_blocklist_path =
+        fmt::format("{}/{}", vendor_modules_dir, "modules.blocklist");
+    RenameFile(initramfs_blocklist_path, vendor_dlkm_blocklist_path);
+  }
+
   // Write updated modules.dep and modules.load files
   CHECK(WriteDepsToFile(FilterDependencies(deps, ramdisk_modules),
                         module_base_dir + "/modules.dep"));
diff --git a/host/commands/control_env_proxy_server/Android.bp b/host/commands/control_env_proxy_server/Android.bp
index de6cf54..2923fac 100644
--- a/host/commands/control_env_proxy_server/Android.bp
+++ b/host/commands/control_env_proxy_server/Android.bp
@@ -16,7 +16,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_host_static {
+cc_library {
     name: "libcontrol_env_proxy_server",
     shared_libs: [
         "libprotobuf-cpp-full",
@@ -51,6 +51,7 @@
         "libcuttlefish_utils",
         "libprotobuf-cpp-full",
         "libgrpc++",
+        "libjsoncpp",
     ],
     static_libs: [
         "grpc_cli_libs",
diff --git a/host/commands/control_env_proxy_server/control_env_proxy.proto b/host/commands/control_env_proxy_server/control_env_proxy.proto
index 68bf46a..b6c85dc 100644
--- a/host/commands/control_env_proxy_server/control_env_proxy.proto
+++ b/host/commands/control_env_proxy_server/control_env_proxy.proto
@@ -16,8 +16,14 @@
 
 package controlenvproxyserver;
 
+import "google/protobuf/empty.proto";
+
 service ControlEnvProxyService {
   rpc CallUnaryMethod (CallUnaryMethodRequest) returns (CallUnaryMethodReply) {}
+  rpc ListServices (google.protobuf.Empty) returns (ListServicesReply) {}
+  rpc ListMethods (ListMethodsRequest) returns (ListMethodsReply) {}
+  rpc ListReqResType (ListReqResTypeRequest) returns (ListReqResTypeReply) {}
+  rpc TypeInformation (TypeInformationRequest) returns (TypeInformationReply) {}
 }
 
 message CallUnaryMethodRequest {
@@ -29,3 +35,34 @@
 message CallUnaryMethodReply {
   string json_formatted_proto = 1;
 }
+
+message ListServicesReply {
+  repeated string services = 1;
+}
+
+message ListMethodsRequest {
+  string service_name = 1;
+}
+
+message ListMethodsReply {
+  repeated string methods = 1;
+}
+
+message ListReqResTypeRequest {
+  string service_name = 1;
+  string method_name = 2;
+}
+
+message ListReqResTypeReply {
+  string request_type_name = 1;
+  string response_type_name = 2;
+}
+
+message TypeInformationRequest {
+  string service_name = 1;
+  string type_name = 2;
+}
+
+message TypeInformationReply {
+  string text_formatted_type_info = 1;
+}
diff --git a/host/commands/control_env_proxy_server/main.cpp b/host/commands/control_env_proxy_server/main.cpp
index ab8455a..2434ce2 100644
--- a/host/commands/control_env_proxy_server/main.cpp
+++ b/host/commands/control_env_proxy_server/main.cpp
@@ -1,7 +1,6 @@
 /*
  *
- * Copyright 2015 gRPC authors.
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 2023 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.
@@ -25,6 +24,7 @@
 #include <grpcpp/ext/proto_server_reflection_plugin.h>
 #include <grpcpp/grpcpp.h>
 #include <grpcpp/health_check_service_interface.h>
+#include <json/json.h>
 
 #include "common/libs/utils/files.h"
 #include "common/libs/utils/result.h"
@@ -34,6 +34,14 @@
 using controlenvproxyserver::CallUnaryMethodReply;
 using controlenvproxyserver::CallUnaryMethodRequest;
 using controlenvproxyserver::ControlEnvProxyService;
+using controlenvproxyserver::ListMethodsReply;
+using controlenvproxyserver::ListMethodsRequest;
+using controlenvproxyserver::ListReqResTypeReply;
+using controlenvproxyserver::ListReqResTypeRequest;
+using controlenvproxyserver::ListServicesReply;
+using controlenvproxyserver::TypeInformationReply;
+using controlenvproxyserver::TypeInformationRequest;
+using google::protobuf::Empty;
 using google::protobuf::RepeatedPtrField;
 using grpc::Server;
 using grpc::ServerBuilder;
@@ -53,16 +61,104 @@
     std::vector<std::string> args{request->service_name(),
                                   request->method_name(),
                                   request->json_formatted_proto()};
-    std::vector<std::string> options;
-
-    auto result =
-        cuttlefish::HandleCmds(FLAGS_grpc_socket_path, "call", args, options);
-
+    auto result = cuttlefish::HandleCmds(FLAGS_grpc_socket_path, "call", args);
     if (!TypeIsSuccess(result)) {
-      return Status(StatusCode::FAILED_PRECONDITION, "Call gRPC method failed");
+      return Status(StatusCode::FAILED_PRECONDITION,
+                    "Calling gRPC method failed");
+    }
+    reply->set_json_formatted_proto(*result);
+
+    return Status::OK;
+  }
+
+  Status ListServices(ServerContext* context, const Empty* request,
+                      ListServicesReply* reply) override {
+    std::vector<std::string> args;
+    auto result = cuttlefish::HandleCmds(FLAGS_grpc_socket_path, "ls", args);
+    if (!TypeIsSuccess(result)) {
+      return Status(StatusCode::FAILED_PRECONDITION,
+                    "Listing gRPC services failed");
     }
 
-    reply->set_json_formatted_proto(*result);
+    Json::Value value;
+    if (!reader.parse(*result, value)) {
+      return parsing_json_failure_status;
+    }
+    if (!value["services"].isArray()) {
+      return parsing_json_failure_status;
+    }
+    for (auto& service : value["services"]) {
+      if (!service.isString()) {
+        return parsing_json_failure_status;
+      }
+      reply->add_services(service.asString());
+    }
+
+    return Status::OK;
+  }
+
+  Status ListMethods(ServerContext* context, const ListMethodsRequest* request,
+                     ListMethodsReply* reply) override {
+    std::vector<std::string> args{request->service_name()};
+    auto result = cuttlefish::HandleCmds(FLAGS_grpc_socket_path, "ls", args);
+    if (!TypeIsSuccess(result)) {
+      return Status(StatusCode::FAILED_PRECONDITION,
+                    "Listing gRPC methods failed");
+    }
+
+    Json::Value value;
+    if (!reader.parse(*result, value)) {
+      return parsing_json_failure_status;
+    }
+    if (!value["methods"].isArray()) {
+      return parsing_json_failure_status;
+    }
+    for (auto& method : value["methods"]) {
+      if (!method.isString()) {
+        return parsing_json_failure_status;
+      }
+      reply->add_methods(method.asString());
+    }
+
+    return Status::OK;
+  }
+
+  Status ListReqResType(ServerContext* context,
+                        const ListReqResTypeRequest* request,
+                        ListReqResTypeReply* reply) override {
+    std::vector<std::string> args{request->service_name(),
+                                  request->method_name()};
+    auto result = cuttlefish::HandleCmds(FLAGS_grpc_socket_path, "ls", args);
+    if (!TypeIsSuccess(result)) {
+      return Status(StatusCode::FAILED_PRECONDITION,
+                    "Listing gRPC request and response message type failed");
+    }
+
+    Json::Value value;
+    if (!reader.parse(*result, value)) {
+      return parsing_json_failure_status;
+    }
+    if (!value["request_type"].isString() ||
+        !value["response_type"].isString()) {
+      return parsing_json_failure_status;
+    }
+    reply->set_request_type_name(value["request_type"].asString());
+    reply->set_response_type_name(value["response_type"].asString());
+
+    return Status::OK;
+  }
+
+  Status TypeInformation(ServerContext* context,
+                         const TypeInformationRequest* request,
+                         TypeInformationReply* reply) override {
+    std::vector<std::string> args{request->service_name(),
+                                  request->type_name()};
+    auto result = cuttlefish::HandleCmds(FLAGS_grpc_socket_path, "type", args);
+    if (!TypeIsSuccess(result)) {
+      return Status(StatusCode::FAILED_PRECONDITION,
+                    "Calling gRPC method failed");
+    }
+    reply->set_text_formatted_type_info(*result);
 
     return Status::OK;
   }
@@ -76,6 +172,10 @@
     }
     return vec;
   }
+
+  Json::Reader reader;
+  Status parsing_json_failure_status = Status(
+      StatusCode::FAILED_PRECONDITION, "Parsing result into json failed");
 };
 
 void RunServer() {
diff --git a/host/commands/cvd/acloud/converter.cpp b/host/commands/cvd/acloud/converter.cpp
index 6c90b6e..b3638d5 100644
--- a/host/commands/cvd/acloud/converter.cpp
+++ b/host/commands/cvd/acloud/converter.cpp
@@ -182,36 +182,36 @@
       Flag()
           .Alias({FlagAliasMode::kFlagConsumesFollowing, "--boot-build-id"})
           .Alias({FlagAliasMode::kFlagConsumesFollowing, "--boot_build_id"})
-          .Setter([&boot_build_id](const FlagMatch& m) {
+          .Setter([&boot_build_id](const FlagMatch& m) -> Result<void> {
             boot_build_id = m.value;
-            return true;
+            return {};
           }));
   std::optional<std::string> boot_build_target;
   flags.emplace_back(
       Flag()
           .Alias({FlagAliasMode::kFlagConsumesFollowing, "--boot-build-target"})
           .Alias({FlagAliasMode::kFlagConsumesFollowing, "--boot_build_target"})
-          .Setter([&boot_build_target](const FlagMatch& m) {
+          .Setter([&boot_build_target](const FlagMatch& m) -> Result<void> {
             boot_build_target = m.value;
-            return true;
+            return {};
           }));
   std::optional<std::string> boot_branch;
   flags.emplace_back(
       Flag()
           .Alias({FlagAliasMode::kFlagConsumesFollowing, "--boot-branch"})
           .Alias({FlagAliasMode::kFlagConsumesFollowing, "--boot_branch"})
-          .Setter([&boot_branch](const FlagMatch& m) {
+          .Setter([&boot_branch](const FlagMatch& m) -> Result<void> {
             boot_branch = m.value;
-            return true;
+            return {};
           }));
   std::optional<std::string> boot_artifact;
   flags.emplace_back(
       Flag()
           .Alias({FlagAliasMode::kFlagConsumesFollowing, "--boot-artifact"})
           .Alias({FlagAliasMode::kFlagConsumesFollowing, "--boot_artifact"})
-          .Setter([&boot_artifact](const FlagMatch& m) {
+          .Setter([&boot_artifact](const FlagMatch& m) -> Result<void> {
             boot_artifact = m.value;
-            return true;
+            return {};
           }));
 
   std::optional<std::string> ota_build_id;
@@ -219,90 +219,92 @@
       Flag()
           .Alias({FlagAliasMode::kFlagConsumesFollowing, "--ota-build-id"})
           .Alias({FlagAliasMode::kFlagConsumesFollowing, "--ota_build_id"})
-          .Setter([&ota_build_id](const FlagMatch& m) {
+          .Setter([&ota_build_id](const FlagMatch& m) -> Result<void> {
             ota_build_id = m.value;
-            return true;
+            return {};
           }));
   std::optional<std::string> ota_build_target;
   flags.emplace_back(
       Flag()
           .Alias({FlagAliasMode::kFlagConsumesFollowing, "--ota-build-target"})
           .Alias({FlagAliasMode::kFlagConsumesFollowing, "--ota_build_target"})
-          .Setter([&ota_build_target](const FlagMatch& m) {
+          .Setter([&ota_build_target](const FlagMatch& m) -> Result<void> {
             ota_build_target = m.value;
-            return true;
+            return {};
           }));
   std::optional<std::string> ota_branch;
   flags.emplace_back(
       Flag()
           .Alias({FlagAliasMode::kFlagConsumesFollowing, "--ota-branch"})
           .Alias({FlagAliasMode::kFlagConsumesFollowing, "--ota_branch"})
-          .Setter([&ota_branch](const FlagMatch& m) {
+          .Setter([&ota_branch](const FlagMatch& m) -> Result<void> {
             ota_branch = m.value;
-            return true;
+            return {};
           }));
 
   std::optional<std::string> launch_args;
   flags.emplace_back(
       Flag()
           .Alias({FlagAliasMode::kFlagConsumesFollowing, "--launch-args"})
-          .Setter([&launch_args](const FlagMatch& m) {
+          .Setter([&launch_args](const FlagMatch& m) -> Result<void> {
             launch_args = m.value;
-            return true;
+            return {};
           }));
 
   std::optional<std::string> system_branch;
   flags.emplace_back(
       Flag()
           .Alias({FlagAliasMode::kFlagConsumesFollowing, "--system-branch"})
-          .Setter([&system_branch](const FlagMatch& m) {
+          .Setter([&system_branch](const FlagMatch& m) -> Result<void> {
             system_branch = m.value;
-            return true;
+            return {};
           }));
 
   std::optional<std::string> system_build_target;
-  flags.emplace_back(Flag()
-                         .Alias({FlagAliasMode::kFlagConsumesFollowing,
-                                 "--system-build-target"})
-                         .Setter([&system_build_target](const FlagMatch& m) {
-                           system_build_target = m.value;
-                           return true;
-                         }));
+  flags.emplace_back(
+      Flag()
+          .Alias(
+              {FlagAliasMode::kFlagConsumesFollowing, "--system-build-target"})
+          .Setter([&system_build_target](const FlagMatch& m) -> Result<void> {
+            system_build_target = m.value;
+            return {};
+          }));
 
   std::optional<std::string> system_build_id;
   flags.emplace_back(
       Flag()
           .Alias({FlagAliasMode::kFlagConsumesFollowing, "--system-build-id"})
-          .Setter([&system_build_id](const FlagMatch& m) {
+          .Setter([&system_build_id](const FlagMatch& m) -> Result<void> {
             system_build_id = m.value;
-            return true;
+            return {};
           }));
 
   std::optional<std::string> kernel_branch;
   flags.emplace_back(
       Flag()
           .Alias({FlagAliasMode::kFlagConsumesFollowing, "--kernel-branch"})
-          .Setter([&kernel_branch](const FlagMatch& m) {
+          .Setter([&kernel_branch](const FlagMatch& m) -> Result<void> {
             kernel_branch = m.value;
-            return true;
+            return {};
           }));
 
   std::optional<std::string> kernel_build_target;
-  flags.emplace_back(Flag()
-                         .Alias({FlagAliasMode::kFlagConsumesFollowing,
-                                 "--kernel-build-target"})
-                         .Setter([&kernel_build_target](const FlagMatch& m) {
-                           kernel_build_target = m.value;
-                           return true;
-                         }));
+  flags.emplace_back(
+      Flag()
+          .Alias(
+              {FlagAliasMode::kFlagConsumesFollowing, "--kernel-build-target"})
+          .Setter([&kernel_build_target](const FlagMatch& m) -> Result<void> {
+            kernel_build_target = m.value;
+            return {};
+          }));
 
   std::optional<std::string> kernel_build_id;
   flags.emplace_back(
       Flag()
           .Alias({FlagAliasMode::kFlagConsumesFollowing, "--kernel-build-id"})
-          .Setter([&kernel_build_id](const FlagMatch& m) {
+          .Setter([&kernel_build_id](const FlagMatch& m) -> Result<void> {
             kernel_build_id = m.value;
-            return true;
+            return {};
           }));
   bool use_16k = false;
   flags.emplace_back(Flag()
@@ -310,9 +312,9 @@
                          .Alias({FlagAliasMode::kFlagExact, "--16K"})
                          .Alias({FlagAliasMode::kFlagExact, "--use-16k"})
                          .Alias({FlagAliasMode::kFlagExact, "--use-16K"})
-                         .Setter([&use_16k](const FlagMatch&) {
+                         .Setter([&use_16k](const FlagMatch&) -> Result<void> {
                            use_16k = true;
-                           return true;
+                           return {};
                          }));
 
   std::optional<std::string> pet_name;
@@ -320,9 +322,9 @@
   flags.emplace_back(
       GflagsCompatFlag("pet-name")
           .Getter([&pet_name]() { return (pet_name ? *pet_name : ""); })
-          .Setter([&pet_name](const FlagMatch& match) {
+          .Setter([&pet_name](const FlagMatch& match) -> Result<void> {
             pet_name = match.value;
-            return true;
+            return {};
           }));
 
   CF_EXPECT(ParseFlags(flags, arguments));
diff --git a/host/commands/cvd/acloud/converter_parser_common.h b/host/commands/cvd/acloud/converter_parser_common.h
index 8274145..f3422d5 100644
--- a/host/commands/cvd/acloud/converter_parser_common.h
+++ b/host/commands/cvd/acloud/converter_parser_common.h
@@ -42,9 +42,9 @@
   for (const auto& alias_name : alias_names) {
     new_flag.Alias({FlagAliasMode::kFlagConsumesFollowing, "--" + alias_name});
   }
-  new_flag.Setter([&opt](const FlagMatch& m) {
+  new_flag.Setter([&opt](const FlagMatch& m) -> Result<void> {
     opt = m.value;
-    return true;
+    return {};
   });
   return new_flag;
 }
diff --git a/host/commands/cvd/acloud/create_converter_parser.cpp b/host/commands/cvd/acloud/create_converter_parser.cpp
index 816e58d..ba9a527 100644
--- a/host/commands/cvd/acloud/create_converter_parser.cpp
+++ b/host/commands/cvd/acloud/create_converter_parser.cpp
@@ -32,22 +32,21 @@
   auto local_instance_flag = Flag();
   local_instance_flag.Alias(
       {FlagAliasMode::kFlagConsumesArbitrary, "--local-instance"});
-  local_instance_flag.Setter(
-      [&local_instance_set, &local_instance](const FlagMatch& m) {
-        local_instance_set = true;
-        if (m.value != "" && local_instance) {
-          LOG(ERROR) << "Instance number already set, was \"" << *local_instance
-                     << "\", now set to \"" << m.value << "\"";
-          return false;
-        } else if (m.value != "" && !local_instance) {
-          int value = -1;
-          if (!android::base::ParseInt(m.value, &value)) {
-            return false;
-          }
-          local_instance = value;
-        }
-        return true;
-      });
+  local_instance_flag.Setter([&local_instance_set, &local_instance](
+                                 const FlagMatch& m) -> Result<void> {
+    local_instance_set = true;
+    if (m.value != "" && local_instance) {
+      return CF_ERRF(
+          "Instance number already set, was \"{}\", now set to \"{}\"",
+          *local_instance, m.value);
+    } else if (m.value != "" && !local_instance) {
+      int value = -1;
+      CF_EXPECTF(android::base::ParseInt(m.value, &value),
+                 "Failed to parse \"{}\"", m.value);
+      local_instance = value;
+    }
+    return {};
+  });
   return local_instance_flag;
 }
 
@@ -56,9 +55,9 @@
                           .Alias({FlagAliasMode::kFlagExact, "-v"})
                           .Alias({FlagAliasMode::kFlagExact, "-vv"})
                           .Alias({FlagAliasMode::kFlagExact, "--verbose"})
-                          .Setter([&verbose](const FlagMatch&) {
+                          .Setter([&verbose](const FlagMatch&) -> Result<void> {
                             verbose = true;
-                            return true;
+                            return {};
                           });
   return verbose_flag;
 }
@@ -67,12 +66,13 @@
                            std::optional<std::string>& local_image_path) {
   return Flag()
       .Alias({FlagAliasMode::kFlagConsumesArbitrary, "--local-image"})
-      .Setter([&local_image_given, &local_image_path](const FlagMatch& m) {
+      .Setter([&local_image_given,
+               &local_image_path](const FlagMatch& m) -> Result<void> {
         local_image_given = true;
         if (m.value != "") {
           local_image_path = m.value;
         }
-        return true;
+        return {};
       });
 }
 
diff --git a/host/commands/cvd/client.cpp b/host/commands/cvd/client.cpp
index 5b1ef51..3ad4288 100644
--- a/host/commands/cvd/client.cpp
+++ b/host/commands/cvd/client.cpp
@@ -28,13 +28,32 @@
 #include "common/libs/fs/shared_buf.h"
 #include "common/libs/fs/shared_fd.h"
 #include "common/libs/utils/environment.h"
+#include "common/libs/utils/result.h"
 #include "common/libs/utils/subprocess.h"
 #include "host/commands/cvd/common_utils.h"
+#include "host/commands/cvd/flag.h"
+#include "host/commands/cvd/frontline_parser.h"
+#include "host/commands/cvd/handle_reset.h"
 #include "host/libs/config/host_tools_version.h"
 
 namespace cuttlefish {
 namespace {
 
+Result<FlagCollection> CvdFlags() {
+  FlagCollection cvd_flags;
+  cvd_flags.EnrollFlag(CvdFlag<bool>("clean", false));
+  cvd_flags.EnrollFlag(CvdFlag<bool>("help", false));
+  cvd_flags.EnrollFlag(CvdFlag<std::string>("verbosity"));
+  return cvd_flags;
+}
+
+Result<bool> FilterDriverHelpOptions(const FlagCollection& cvd_flags,
+                                     cvd_common::Args& cvd_args) {
+  auto help_flag = CF_EXPECT(cvd_flags.GetFlag("help"));
+  bool is_help = CF_EXPECT(help_flag.CalculateFlag<bool>(cvd_args));
+  return is_help;
+}
+
 [[noreturn]] void CallPythonAcloud(std::vector<std::string>& args) {
   auto android_top = StringFromEnv("ANDROID_BUILD_TOP", "");
   if (android_top == "") {
@@ -55,6 +74,102 @@
   abort();
 }
 
+cvd_common::Args AllArgs(const std::string& prog_path,
+                         const cvd_common::Args& cvd_args,
+                         const std::optional<std::string>& subcmd,
+                         const cvd_common::Args& subcmd_args) {
+  std::vector<std::string> all_args;
+  all_args.push_back(prog_path);
+  all_args.insert(all_args.end(), cvd_args.begin(), cvd_args.end());
+  if (subcmd) {
+    all_args.push_back(*subcmd);
+  }
+  all_args.insert(all_args.end(), subcmd_args.begin(), subcmd_args.end());
+  return all_args;
+}
+
+enum class VersionCommandReport : std::uint32_t {
+  kNonVersion,
+  kVersion,
+};
+Result<VersionCommandReport> HandleVersionCommand(
+    CvdClient& client, const cvd_common::Args& all_args) {
+  std::vector<std::string> version_command{"version"};
+  FlagCollection cvd_flags = CF_EXPECT(CvdFlags());
+  FrontlineParser::ParserParam version_param{
+      .server_supported_subcmds = std::vector<std::string>{},
+      .internal_cmds = version_command,
+      .all_args = all_args,
+      .cvd_flags = cvd_flags};
+  auto version_parser_result = FrontlineParser::Parse(version_param);
+  if (!version_parser_result.ok()) {
+    return VersionCommandReport::kNonVersion;
+  }
+
+  auto version_parser = std::move(*version_parser_result);
+  CF_EXPECT(version_parser != nullptr);
+  const auto subcmd = version_parser->SubCmd().value_or("");
+  auto cvd_args = version_parser->CvdArgs();
+  CF_EXPECT(subcmd == "version" || subcmd.empty(),
+            "subcmd is expected to be \"version\" or empty but is " << subcmd);
+
+  if (subcmd == "version") {
+    auto version_msg = CF_EXPECT(client.HandleVersion());
+    std::cout << version_msg;
+    return VersionCommandReport::kVersion;
+  }
+  return VersionCommandReport::kNonVersion;
+}
+
+struct ClientCommandCheckResult {
+  bool was_client_command_;
+  cvd_common::Args new_all_args;
+};
+Result<ClientCommandCheckResult> HandleClientCommands(
+    CvdClient& client, const cvd_common::Args& all_args) {
+  ClientCommandCheckResult output;
+  std::vector<std::string> client_internal_commands{"kill-server",
+                                                    "server-kill", "reset"};
+  FlagCollection cvd_flags = CF_EXPECT(CvdFlags());
+  FrontlineParser::ParserParam client_param{
+      .server_supported_subcmds = std::vector<std::string>{},
+      .internal_cmds = client_internal_commands,
+      .all_args = all_args,
+      .cvd_flags = cvd_flags};
+  auto client_parser_result = FrontlineParser::Parse(client_param);
+  if (!client_parser_result.ok()) {
+    return ClientCommandCheckResult{.was_client_command_ = false,
+                                    .new_all_args = all_args};
+  }
+
+  auto client_parser = std::move(*client_parser_result);
+  CF_EXPECT(client_parser != nullptr);
+  auto cvd_args = client_parser->CvdArgs();
+  auto is_help = CF_EXPECT(FilterDriverHelpOptions(cvd_flags, cvd_args));
+
+  output.new_all_args =
+      AllArgs(client_parser->ProgPath(), cvd_args, client_parser->SubCmd(),
+              client_parser->SubCmdArgs());
+  output.was_client_command_ = (!is_help && client_parser->SubCmd());
+  if (!output.was_client_command_) {
+    // could be simply "cvd"
+    output.new_all_args = cvd_common::Args{"cvd", "help"};
+    return output;
+  }
+
+  // Special case for `cvd kill-server`, handled by directly
+  // stopping the cvd_server.
+  std::vector<std::string> kill_server_cmds{"kill-server", "server-kill"};
+  std::string subcmd = client_parser->SubCmd().value_or("");
+  if (Contains(kill_server_cmds, subcmd)) {
+    CF_EXPECT(client.StopCvdServer(/*clear=*/true));
+    return output;
+  }
+  CF_EXPECT_EQ(subcmd, "reset", "unsupported subcmd: " << subcmd);
+  CF_EXPECT(HandleReset(client, client_parser->SubCmdArgs()));
+  return output;
+}
+
 }  // end of namespace
 
 Result<SharedFD> CvdClient::ConnectToServer() {
@@ -319,6 +434,30 @@
   return {};
 }
 
+Result<void> CvdClient::HandleCvdCommand(
+    const std::vector<std::string>& all_args,
+    const std::unordered_map<std::string, std::string>& env) {
+  auto [was_client_command, new_all_args] =
+      CF_EXPECT(HandleClientCommands(*this, all_args));
+  if (was_client_command) {
+    return {};
+  }
+
+  auto version_command_handle_report =
+      CF_EXPECT(HandleVersionCommand(*this, new_all_args));
+  if (version_command_handle_report == VersionCommandReport::kVersion) {
+    return {};
+  }
+
+  const cvd_common::Args new_cmd_args{"cvd", "process"};
+  CF_EXPECT(!new_all_args.empty());
+  const cvd_common::Args new_selector_args{new_all_args.begin(),
+                                           new_all_args.end()};
+  // TODO(schuffelen): Deduplicate when calls to setenv are removed.
+  CF_EXPECT(HandleCommand(new_cmd_args, env, new_selector_args));
+  return {};
+}
+
 Result<std::string> CvdClient::HandleVersion() {
   using google::protobuf::TextFormat;
   std::stringstream result;
diff --git a/host/commands/cvd/client.h b/host/commands/cvd/client.h
index 71ee03a..52564e7 100644
--- a/host/commands/cvd/client.h
+++ b/host/commands/cvd/client.h
@@ -50,6 +50,9 @@
   Result<void> HandleAcloud(
       const std::vector<std::string>& args,
       const std::unordered_map<std::string, std::string>& env);
+  Result<void> HandleCvdCommand(
+      const std::vector<std::string>& args,
+      const std::unordered_map<std::string, std::string>& env);
   Result<cvd::Response> HandleCommand(
       const std::vector<std::string>& args,
       const std::unordered_map<std::string, std::string>& env,
diff --git a/host/commands/cvd/fetch/fetch_cvd.cc b/host/commands/cvd/fetch/fetch_cvd.cc
index c76be71..fd7d8cf 100644
--- a/host/commands/cvd/fetch/fetch_cvd.cc
+++ b/host/commands/cvd/fetch/fetch_cvd.cc
@@ -30,6 +30,7 @@
 #include <vector>
 
 #include <android-base/logging.h>
+#include <android-base/parseint.h>
 #include <android-base/strings.h>
 #include <curl/curl.h>
 #include <gflags/gflags.h>
@@ -57,7 +58,6 @@
 const std::string OTA_TOOLS_DIR = "/otatools/";
 const std::string DEFAULT_DIR = "/default";
 const std::string SYSTEM_DIR = "/system";
-const int DEFAULT_RETRY_PERIOD = 20;
 const std::string USAGE_MESSAGE =
     "<flags>\n"
     "\n"
@@ -70,21 +70,13 @@
     "\"build_id\" - build \"build_id\" for \"aosp_cf_x86_phone-userdebug\"\n";
 const mode_t RWX_ALL_MODE = S_IRWXU | S_IRWXG | S_IRWXO;
 const bool OVERRIDE_ENTRIES = true;
-const bool DOWNLOAD_IMG_ZIP_DEFAULT = true;
-const bool DOWNLOAD_TARGET_FILES_ZIP_DEFAULT = false;
 const std::string LOG_FILENAME = "fetch.log";
 
 struct BuildApiFlags {
-  std::string api_key = "";
-  std::string credential_source = "";
-  std::chrono::seconds wait_retry_period =
-      std::chrono::seconds(DEFAULT_RETRY_PERIOD);
-  bool external_dns_resolver =
-#ifdef __BIONIC__
-      true;
-#else
-      false;
-#endif
+  std::string api_key = kDefaultApiKey;
+  std::string credential_source = kDefaultCredentialSource;
+  std::chrono::seconds wait_retry_period = kDefaultWaitRetryPeriod;
+  bool external_dns_resolver = kDefaultExternalDnsResolver;
 };
 
 struct VectorFlags {
@@ -117,9 +109,9 @@
 };
 
 struct FetchFlags {
-  std::string target_directory = "";
+  std::string target_directory = kDefaultTargetDirectory;
   std::vector<std::string> target_subdirectory;
-  bool keep_downloaded_archives = false;
+  bool keep_downloaded_archives = kDefaultKeepDownloadedArchives;
   android::base::LogSeverity verbosity = android::base::INFO;
   bool helpxml = false;
   BuildApiFlags build_api_flags;
@@ -144,9 +136,22 @@
   std::string system_target_files;
 };
 
+Flag GflagsCompatFlagSeconds(const std::string& name,
+                             std::chrono::seconds& value) {
+  return GflagsCompatFlag(name)
+      .Getter([&value]() { return std::to_string(value.count()); })
+      .Setter([&value](const FlagMatch& match) -> Result<void> {
+        int parsed_int;
+        CF_EXPECTF(android::base::ParseInt(match.value, &parsed_int),
+                   "Failed to parse \"{}\" as an integer", match.value);
+        value = std::chrono::seconds(parsed_int);
+        return {};
+      });
+}
+
 std::vector<Flag> GetFlagsVector(FetchFlags& fetch_flags,
                                  BuildApiFlags& build_api_flags,
-                                 VectorFlags& vector_flags, int& retry_period,
+                                 VectorFlags& vector_flags,
                                  std::string& directory) {
   std::vector<Flag> flags;
   flags.emplace_back(
@@ -172,7 +177,8 @@
   flags.emplace_back(
       GflagsCompatFlag("credential_source", build_api_flags.credential_source)
           .Help("Build API credential source"));
-  flags.emplace_back(GflagsCompatFlag("wait_retry_period", retry_period)
+  flags.emplace_back(GflagsCompatFlagSeconds("wait_retry_period",
+                                             build_api_flags.wait_retry_period)
                          .Help("Retry period for pending builds given in "
                                "seconds. Set to 0 to not wait."));
   flags.emplace_back(
@@ -204,12 +210,12 @@
           .Help("name of the boot image in boot_build"));
   flags.emplace_back(GflagsCompatFlag("download_img_zip",
                                       vector_flags.download_img_zip,
-                                      DOWNLOAD_IMG_ZIP_DEFAULT)
+                                      kDefaultDownloadImgZip)
                          .Help("Whether to fetch the -img-*.zip file."));
   flags.emplace_back(
       GflagsCompatFlag("download_target_files_zip",
                        vector_flags.download_target_files_zip,
-                       DOWNLOAD_TARGET_FILES_ZIP_DEFAULT)
+                       kDefaultDownloadTargetFilesZip)
           .Help("Whether to fetch the -target_files-*.zip file."));
 
   flags.emplace_back(HelpFlag(flags, USAGE_MESSAGE));
@@ -264,26 +270,28 @@
       num_builds);
   for (int i = 0; i < result.size(); ++i) {
     auto build_source = BuildSourceFlags{
-        .default_build =
-            AccessOrDefault<std::string>(flags.default_build, i, ""),
-        .system_build = AccessOrDefault<std::string>(flags.system_build, i, ""),
-        .kernel_build = AccessOrDefault<std::string>(flags.kernel_build, i, ""),
-        .boot_build = AccessOrDefault<std::string>(flags.boot_build, i, ""),
-        .bootloader_build =
-            AccessOrDefault<std::string>(flags.bootloader_build, i, ""),
-        .otatools_build =
-            AccessOrDefault<std::string>(flags.otatools_build, i, ""),
-        .host_package_build =
-            AccessOrDefault<std::string>(flags.host_package_build, i, ""),
+        .default_build = AccessOrDefault<std::string>(flags.default_build, i,
+                                                      kDefaultBuildString),
+        .system_build = AccessOrDefault<std::string>(flags.system_build, i,
+                                                     kDefaultBuildString),
+        .kernel_build = AccessOrDefault<std::string>(flags.kernel_build, i,
+                                                     kDefaultBuildString),
+        .boot_build = AccessOrDefault<std::string>(flags.boot_build, i,
+                                                   kDefaultBuildString),
+        .bootloader_build = AccessOrDefault<std::string>(
+            flags.bootloader_build, i, kDefaultBuildString),
+        .otatools_build = AccessOrDefault<std::string>(flags.otatools_build, i,
+                                                       kDefaultBuildString),
+        .host_package_build = AccessOrDefault<std::string>(
+            flags.host_package_build, i, kDefaultBuildString),
     };
     auto download = DownloadFlags{
         .boot_artifact =
             AccessOrDefault<std::string>(flags.boot_artifact, i, ""),
         .download_img_zip = AccessOrDefault<bool>(flags.download_img_zip, i,
-                                                  DOWNLOAD_IMG_ZIP_DEFAULT),
-        .download_target_files_zip =
-            AccessOrDefault<bool>(flags.download_target_files_zip, i,
-                                  DOWNLOAD_TARGET_FILES_ZIP_DEFAULT),
+                                                  kDefaultDownloadImgZip),
+        .download_target_files_zip = AccessOrDefault<bool>(
+            flags.download_target_files_zip, i, kDefaultDownloadTargetFilesZip),
     };
     result[i] = {build_source, download, i};
   }
@@ -294,22 +302,20 @@
   FetchFlags fetch_flags;
   BuildApiFlags build_api_flags;
   VectorFlags vector_flags;
-  int retry_period = DEFAULT_RETRY_PERIOD;
-  std::string directory = "";
+  std::string directory;
 
-  std::vector<Flag> flags = GetFlagsVector(
-      fetch_flags, build_api_flags, vector_flags, retry_period, directory);
+  std::vector<Flag> flags =
+      GetFlagsVector(fetch_flags, build_api_flags, vector_flags, directory);
   std::vector<std::string> args = ArgsToVec(argc - 1, argv + 1);
   CF_EXPECT(ParseFlags(flags, args), "Could not process command line flags.");
 
-  build_api_flags.wait_retry_period = std::chrono::seconds(retry_period);
-  if (directory != "") {
+  if (!directory.empty()) {
     LOG(ERROR) << "Please use --target_directory instead of --directory";
-    if (fetch_flags.target_directory == "") {
+    if (fetch_flags.target_directory.empty()) {
       fetch_flags.target_directory = directory;
     }
   } else {
-    if (fetch_flags.target_directory == "") {
+    if (fetch_flags.target_directory.empty()) {
       fetch_flags.target_directory = CurrentDirectory();
     }
   }
@@ -713,17 +719,8 @@
   return {};
 }
 
-}  // namespace
-
-Result<void> FetchCvdMain(int argc, char** argv) {
-  android::base::InitLogging(argv, android::base::StderrLogger);
-  const FetchFlags flags = CF_EXPECT(GetFlagValues(argc, argv));
-  const std::string fetch_root_directory = AbsolutePath(flags.target_directory);
-  CF_EXPECT(EnsureDirectoryExists(fetch_root_directory, RWX_ALL_MODE));
-  android::base::SetLogger(
-      LogToStderrAndFiles({fetch_root_directory + "/" + LOG_FILENAME}));
-  android::base::SetMinimumLogSeverity(flags.verbosity);
-
+Result<void> InnerMain(const FetchFlags& flags,
+                       const std::string& fetch_root_directory) {
 #ifdef __BIONIC__
   // TODO(schuffelen): Find a better way to deal with tzdata
   setenv("ANDROID_TZDATA_ROOT", "/", /* overwrite */ 0);
@@ -763,4 +760,22 @@
   return {};
 }
 
+}  // namespace
+
+Result<void> FetchCvdMain(int argc, char** argv) {
+  android::base::InitLogging(argv, android::base::StderrLogger);
+  const FetchFlags flags = CF_EXPECT(GetFlagValues(argc, argv));
+  const std::string fetch_root_directory = AbsolutePath(flags.target_directory);
+  CF_EXPECT(EnsureDirectoryExists(fetch_root_directory, RWX_ALL_MODE));
+  android::base::SetLogger(
+      LogToStderrAndFiles({fetch_root_directory + "/" + LOG_FILENAME}));
+  android::base::SetMinimumLogSeverity(flags.verbosity);
+
+  auto result = InnerMain(flags, fetch_root_directory);
+  if (!result.ok()) {
+    LOG(ERROR) << result.error().Trace();
+  }
+  return result;
+}
+
 }  // namespace cuttlefish
diff --git a/host/commands/cvd/fetch/fetch_cvd.h b/host/commands/cvd/fetch/fetch_cvd.h
index e99395f..9ff6c91 100644
--- a/host/commands/cvd/fetch/fetch_cvd.h
+++ b/host/commands/cvd/fetch/fetch_cvd.h
@@ -13,9 +13,29 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#pragma once
+
+#include <chrono>
+
 #include "common/libs/utils/result.h"
 
 namespace cuttlefish {
 
+inline constexpr char kDefaultApiKey[] = "";
+inline constexpr char kDefaultCredentialSource[] = "";
+inline constexpr std::chrono::seconds kDefaultWaitRetryPeriod =
+    std::chrono::seconds(20);
+inline constexpr bool kDefaultExternalDnsResolver =
+#ifdef __BIONIC__
+    true;
+#else
+    false;
+#endif
+inline constexpr char kDefaultBuildString[] = "";
+inline constexpr bool kDefaultDownloadImgZip = true;
+inline constexpr bool kDefaultDownloadTargetFilesZip = false;
+inline constexpr char kDefaultTargetDirectory[] = "";
+inline constexpr bool kDefaultKeepDownloadedArchives = false;
+
 Result<void> FetchCvdMain(int argc, char** argv);
 }
diff --git a/host/commands/cvd/handle_reset.cpp b/host/commands/cvd/handle_reset.cpp
index 2c11a81..73b653b 100644
--- a/host/commands/cvd/handle_reset.cpp
+++ b/host/commands/cvd/handle_reset.cpp
@@ -58,19 +58,20 @@
   bool is_confirmed_by_flag = false;
   std::string verbosity_flag_value;
 
-  Flag y_flag = Flag()
-                    .Alias({FlagAliasMode::kFlagExact, "-y"})
-                    .Alias({FlagAliasMode::kFlagExact, "--yes"})
-                    .Setter([&is_confirmed_by_flag](const FlagMatch&) {
-                      is_confirmed_by_flag = true;
-                      return true;
-                    });
+  Flag y_flag =
+      Flag()
+          .Alias({FlagAliasMode::kFlagExact, "-y"})
+          .Alias({FlagAliasMode::kFlagExact, "--yes"})
+          .Setter([&is_confirmed_by_flag](const FlagMatch&) -> Result<void> {
+            is_confirmed_by_flag = true;
+            return {};
+          });
   Flag help_flag = Flag()
                        .Alias({FlagAliasMode::kFlagExact, "-h"})
                        .Alias({FlagAliasMode::kFlagExact, "--help"})
-                       .Setter([&is_help](const FlagMatch&) {
+                       .Setter([&is_help](const FlagMatch&) -> Result<void> {
                          is_help = true;
-                         return true;
+                         return {};
                        });
   std::vector<Flag> flags{
       GflagsCompatFlag("device-by-cvd-only", device_by_cvd_only),
diff --git a/host/commands/cvd/instance_manager.cpp b/host/commands/cvd/instance_manager.cpp
index a87e87e..6a18c12 100644
--- a/host/commands/cvd/instance_manager.cpp
+++ b/host/commands/cvd/instance_manager.cpp
@@ -23,7 +23,9 @@
 #include <sstream>
 
 #include <android-base/file.h>
+#include "fmt/format.h"
 #include <fruit/fruit.h>
+#include "json/value.h"
 
 #include "common/libs/fs/shared_buf.h"
 #include "common/libs/fs/shared_fd.h"
@@ -224,7 +226,7 @@
   return command_result;
 }
 
-Result<InstanceManager::StatusCommandOutput>
+Result<Json::Value>
 InstanceManager::IssueStatusCommand(const selector::LocalInstanceGroup& group,
                                     const SharedFD& err) {
   std::string not_supported_version_msg = " does not comply with cvd fleet.\n";
@@ -234,38 +236,44 @@
       .op = "status",
   }));
   const auto prog_path = host_android_out + "/bin/" + status_bin;
-  Command with_args = GetCommand(prog_path, "--all_instances", "--print");
-  with_args.SetEnvironment({ConcatToString("HOME=", group.HomeDir())});
-  auto command_result = ExecCommand(std::move(with_args));
-  if (command_result.ok()) {
-    StatusCommandOutput output;
-    if (command_result->stdout_buf.empty()) {
-      WriteAll(err, ConcatToString(group.GroupName(), "-*",
-                                   not_supported_version_msg));
-      Json::Reader().parse("{}", output.stdout_json);
-      return output;
-    }
-    output.stdout_json = CF_EXPECT(ParseJson(command_result->stdout_buf));
-    return output;
-  }
-  StatusCommandOutput output;
-  int index = 0;
+
+  Json::Value output(Json::arrayValue);
   for (const auto& instance_ref : CF_EXPECT(group.FindAllInstances())) {
     const auto id = instance_ref.Get().InstanceId();
-    Command without_args = GetCommand(prog_path);
+    Command status_cmd = GetCommand(prog_path, "-print");
     std::vector<std::string> new_envs{
         ConcatToString("HOME=", group.HomeDir()),
         ConcatToString(kCuttlefishInstanceEnvVarName, "=", std::to_string(id))};
-    without_args.SetEnvironment(new_envs);
-    auto second_command_result =
-        CF_EXPECT(ExecCommand(std::move(without_args)));
-    if (second_command_result.stdout_buf.empty()) {
+    status_cmd.SetEnvironment(new_envs);
+    auto cmd_result = CF_EXPECT(ExecCommand(std::move(status_cmd)));
+    if (cmd_result.stdout_buf.empty()) {
       WriteAll(err,
                instance_ref.Get().DeviceName() + not_supported_version_msg);
-      second_command_result.stdout_buf.append("{}");
+      cmd_result.stdout_buf.append("{}");
     }
-    output.stdout_json[index] =
-        CF_EXPECT(ParseJson(second_command_result.stdout_buf));
+    auto status = CF_EXPECT(ParseJson(cmd_result.stdout_buf));
+    if (status.isArray()) {
+      // cvd_internal_status returns an array even when limited to a single
+      // instance.
+      CF_EXPECT(status.size() == 1,
+                status_bin << " returned unexpected number of instances: "
+                           << status.size());
+      status = status[0];
+    }
+    static constexpr auto kWebrtcProp = "webrtc_device_id";
+    static constexpr auto kNameProp = "instance_name";
+    // Check for isObject first, calling isMember on anything else causes a
+    // runtime error
+    if (status.isObject() && !status.isMember(kWebrtcProp) &&
+        status.isMember(kNameProp)) {
+      // b/296644913 some cuttlefish versions printed the webrtc device id as
+      // the instance name.
+      status[kWebrtcProp] = status[kNameProp];
+    }
+    // The instance doesn't know the name under which it was created on the
+    // server.
+    status[kNameProp] = instance_ref.Get().PerInstanceName();
+    output.append(status);
   }
   return output;
 }
@@ -275,33 +283,34 @@
                                                   const SharedFD& err) {
   std::lock_guard assemblies_lock(instance_db_mutex_);
   auto& instance_db = GetInstanceDB(uid);
-  const char _GroupDeviceInfoStart[] = "[\n";
-  const char _GroupDeviceInfoSeparate[] = ",\n";
-  const char _GroupDeviceInfoEnd[] = "]\n";
-  WriteAll(out, _GroupDeviceInfoStart);
   auto&& instance_groups = instance_db.InstanceGroups();
-
-  for (const auto& group : instance_groups) {
-    CF_EXPECT(group != nullptr);
-    auto result = IssueStatusCommand(*group, err);
-    if (!result.ok()) {
-      WriteAll(err, "      (unknown instance status error)");
-    } else {
-      const auto [stderr_msg, stdout_json] = *result;
-      WriteAll(err, stderr_msg);
-      // TODO(kwstephenkim): build a data structure that also includes
-      // selector-related information, etc.
-      WriteAll(out, stdout_json.toStyledString());
-    }
-    // move on
-    if (group == *instance_groups.crbegin()) {
-      continue;
-    }
-    WriteAll(out, _GroupDeviceInfoSeparate);
-  }
-  WriteAll(out, _GroupDeviceInfoEnd);
   cvd::Status status;
   status.set_code(cvd::Status::OK);
+
+  Json::Value groups_json(Json::arrayValue);
+  for (const auto& group : instance_groups) {
+    CF_EXPECT(group != nullptr);
+    Json::Value group_json(Json::objectValue);
+    group_json["group_name"] = group->GroupName();
+    auto result = IssueStatusCommand(*group, err);
+    if (!result.ok()) {
+      WriteAll(err, fmt::format("Group '{}' status error: '{}'",
+                                group->GroupName(), result.error().Message()));
+      status.set_code(cvd::Status::INTERNAL);
+      continue;
+    }
+    group_json["instances"] = *result;
+    groups_json.append(group_json);
+  }
+  Json::Value output(Json::objectValue);
+  output["groups"] = groups_json;
+  // Calling toStyledString here puts the string representation of all instance
+  // groups into a single string in memory. That sounds large, but the host's
+  // RAM should be able to handle it if it can handle that many instances
+  // running simultaneously.
+  // The alternative is probably to create an std::ostream from
+  // cuttlefish::SharedFD and use Json::Value's operator<< to print it.
+  WriteAll(out, output.toStyledString());
   return status;
 }
 
diff --git a/host/commands/cvd/instance_manager.h b/host/commands/cvd/instance_manager.h
index a7bc7e9..41c7ac6 100644
--- a/host/commands/cvd/instance_manager.h
+++ b/host/commands/cvd/instance_manager.h
@@ -114,11 +114,7 @@
  private:
   Result<cvd::Status> CvdFleetImpl(const uid_t uid, const SharedFD& out,
                                    const SharedFD& err);
-  struct StatusCommandOutput {
-    std::string stderr_msg;
-    Json::Value stdout_json;
-  };
-  Result<StatusCommandOutput> IssueStatusCommand(
+  Result<Json::Value> IssueStatusCommand(
       const selector::LocalInstanceGroup& group, const SharedFD& err);
   Result<void> IssueStopCommand(const SharedFD& out, const SharedFD& err,
                                 const std::string& config_file_path,
diff --git a/host/commands/cvd/main.cc b/host/commands/cvd/main.cc
index 0e1f1ed..28c735d 100644
--- a/host/commands/cvd/main.cc
+++ b/host/commands/cvd/main.cc
@@ -38,21 +38,6 @@
 namespace cuttlefish {
 namespace {
 
-Result<FlagCollection> CvdFlags() {
-  FlagCollection cvd_flags;
-  cvd_flags.EnrollFlag(CvdFlag<bool>("clean", false));
-  cvd_flags.EnrollFlag(CvdFlag<bool>("help", false));
-  cvd_flags.EnrollFlag(CvdFlag<std::string>("verbosity"));
-  return cvd_flags;
-}
-
-Result<bool> FilterDriverHelpOptions(const FlagCollection& cvd_flags,
-                                     cvd_common::Args& cvd_args) {
-  auto help_flag = CF_EXPECT(cvd_flags.GetFlag("help"));
-  bool is_help = CF_EXPECT(help_flag.CalculateFlag<bool>(cvd_args));
-  return is_help;
-}
-
 /**
  * Returns --verbosity value if ever exist in the entire commandline args
  *
@@ -84,102 +69,6 @@
   return (encoded_verbosity.ok() ? *encoded_verbosity : GetMinimumVerbosity());
 }
 
-cvd_common::Args AllArgs(const std::string& prog_path,
-                         const cvd_common::Args& cvd_args,
-                         const std::optional<std::string>& subcmd,
-                         const cvd_common::Args& subcmd_args) {
-  std::vector<std::string> all_args;
-  all_args.push_back(prog_path);
-  all_args.insert(all_args.end(), cvd_args.begin(), cvd_args.end());
-  if (subcmd) {
-    all_args.push_back(*subcmd);
-  }
-  all_args.insert(all_args.end(), subcmd_args.begin(), subcmd_args.end());
-  return all_args;
-}
-
-struct ClientCommandCheckResult {
-  bool was_client_command_;
-  cvd_common::Args new_all_args;
-};
-Result<ClientCommandCheckResult> HandleClientCommands(
-    CvdClient& client, const cvd_common::Args& all_args) {
-  ClientCommandCheckResult output;
-  std::vector<std::string> client_internal_commands{"kill-server",
-                                                    "server-kill", "reset"};
-  FlagCollection cvd_flags = CF_EXPECT(CvdFlags());
-  FrontlineParser::ParserParam client_param{
-      .server_supported_subcmds = std::vector<std::string>{},
-      .internal_cmds = client_internal_commands,
-      .all_args = all_args,
-      .cvd_flags = cvd_flags};
-  auto client_parser_result = FrontlineParser::Parse(client_param);
-  if (!client_parser_result.ok()) {
-    return ClientCommandCheckResult{.was_client_command_ = false,
-                                    .new_all_args = all_args};
-  }
-
-  auto client_parser = std::move(*client_parser_result);
-  CF_EXPECT(client_parser != nullptr);
-  auto cvd_args = client_parser->CvdArgs();
-  auto is_help = CF_EXPECT(FilterDriverHelpOptions(cvd_flags, cvd_args));
-
-  output.new_all_args =
-      AllArgs(client_parser->ProgPath(), cvd_args, client_parser->SubCmd(),
-              client_parser->SubCmdArgs());
-  output.was_client_command_ = (!is_help && client_parser->SubCmd());
-  if (!output.was_client_command_) {
-    // could be simply "cvd"
-    output.new_all_args = cvd_common::Args{"cvd", "help"};
-    return output;
-  }
-
-  // Special case for `cvd kill-server`, handled by directly
-  // stopping the cvd_server.
-  std::vector<std::string> kill_server_cmds{"kill-server", "server-kill"};
-  std::string subcmd = client_parser->SubCmd().value_or("");
-  if (Contains(kill_server_cmds, subcmd)) {
-    CF_EXPECT(client.StopCvdServer(/*clear=*/true));
-    return output;
-  }
-  CF_EXPECT_EQ(subcmd, "reset", "unsupported subcmd: " << subcmd);
-  CF_EXPECT(HandleReset(client, client_parser->SubCmdArgs()));
-  return output;
-}
-
-enum class VersionCommandReport : std::uint32_t {
-  kNonVersion,
-  kVersion,
-};
-Result<VersionCommandReport> HandleVersionCommand(
-    CvdClient& client, const cvd_common::Args& all_args) {
-  std::vector<std::string> version_command{"version"};
-  FlagCollection cvd_flags = CF_EXPECT(CvdFlags());
-  FrontlineParser::ParserParam version_param{
-      .server_supported_subcmds = std::vector<std::string>{},
-      .internal_cmds = version_command,
-      .all_args = all_args,
-      .cvd_flags = cvd_flags};
-  auto version_parser_result = FrontlineParser::Parse(version_param);
-  if (!version_parser_result.ok()) {
-    return VersionCommandReport::kNonVersion;
-  }
-
-  auto version_parser = std::move(*version_parser_result);
-  CF_EXPECT(version_parser != nullptr);
-  const auto subcmd = version_parser->SubCmd().value_or("");
-  auto cvd_args = version_parser->CvdArgs();
-  CF_EXPECT(subcmd == "version" || subcmd.empty(),
-            "subcmd is expected to be \"version\" or empty but is " << subcmd);
-
-  if (subcmd == "version") {
-    auto version_msg = CF_EXPECT(client.HandleVersion());
-    std::cout << version_msg;
-    return VersionCommandReport::kVersion;
-  }
-  return VersionCommandReport::kNonVersion;
-}
-
 /**
  * Terminates a cvd server listening on "cvd_server"
  *
@@ -234,17 +123,6 @@
          .acloud_translator_optout = parsed.acloud_translator_optout});
   }
 
-  CF_EXPECT_EQ(android::base::Basename(all_args[0]), "cvd");
-
-  // TODO(kwstephenkim): --help should be handled here.
-  // And, the FrontlineParser takes any positional argument as
-  // a valid subcommand.
-
-  auto [was_client_command, new_all_args] =
-      CF_EXPECT(HandleClientCommands(client, all_args));
-  if (was_client_command) {
-    return {};
-  }
   /*
    * For now, the parser needs a running server. The parser will
    * be moved to the server side, and then it won't.
@@ -253,18 +131,13 @@
   CF_EXPECT(client.ValidateServerVersion(),
             "Unable to ensure cvd_server is running.");
 
-  auto version_command_handle_report =
-      CF_EXPECT(HandleVersionCommand(client, new_all_args));
-  if (version_command_handle_report == VersionCommandReport::kVersion) {
+  if (android::base::Basename(all_args[0]) == "cvd") {
+    CF_EXPECT(client.HandleCvdCommand(all_args, env));
     return {};
   }
 
-  const cvd_common::Args new_cmd_args{"cvd", "process"};
-  CF_EXPECT(!new_all_args.empty());
-  const cvd_common::Args new_selector_args{new_all_args.begin(),
-                                           new_all_args.end()};
-  // TODO(schuffelen): Deduplicate when calls to setenv are removed.
-  CF_EXPECT(client.HandleCommand(new_cmd_args, env, new_selector_args));
+  CF_EXPECT(client.HandleCommand(all_args, env, {}));
+
   return {};
 }
 
diff --git a/host/commands/cvd/parser/Android.bp b/host/commands/cvd/parser/Android.bp
index d90e8fd..c724a80 100644
--- a/host/commands/cvd/parser/Android.bp
+++ b/host/commands/cvd/parser/Android.bp
@@ -20,23 +20,23 @@
 cc_library_host_static {
     name: "libcvd_parser",
     srcs: [
-        "instance/cf_vm_configs.cpp",
-        "instance/cf_disk_configs.cpp",
-        "instance/cf_boot_configs.cpp",
-        "instance/cf_security_configs.cpp",
-        "instance/cf_graphics_configs.cpp",
-        "instance/cf_metrics_configs.cpp",
         "cf_configs_common.cpp",
         "cf_configs_instances.cpp",
+        "cf_flags_validator.cpp",
+        "cf_metrics_configs.cpp",
+        "fetch_cvd_parser.cpp",
+        "instance/cf_boot_configs.cpp",
+        "instance/cf_disk_configs.cpp",
+        "instance/cf_graphics_configs.cpp",
+        "instance/cf_security_configs.cpp",
+        "instance/cf_vm_configs.cpp",
         "launch_cvd_templates.cpp",
         "launch_cvd_parser.cpp",
-        "cf_flags_validator.cpp",
-        "fetch_cvd_parser.cpp",
         "load_configs_parser.cpp",
     ],
     static_libs: [
-        "libprotobuf-cpp-full",
         "libcuttlefish_launch_cvd_proto",
+        "libprotobuf-cpp-full",
     ],
     defaults: ["cvd_lib_defaults"],
 }
diff --git a/host/commands/cvd/parser/cf_configs_common.cpp b/host/commands/cvd/parser/cf_configs_common.cpp
index b931cee..c58906c 100644
--- a/host/commands/cvd/parser/cf_configs_common.cpp
+++ b/host/commands/cvd/parser/cf_configs_common.cpp
@@ -21,8 +21,10 @@
 #include <vector>
 
 #include <android-base/logging.h>
+#include <android-base/strings.h>
 #include <json/json.h>
 
+#include "common/libs/utils/json.h"
 #include "common/libs/utils/result.h"
 
 namespace cuttlefish {
@@ -47,46 +49,36 @@
                                  const std::string& json_flag,
                                  int default_value) {
   // Allocate and initialize with default values
-  for (int i = 0; i < instances.size(); i++) {
-    if (!instances[i].isMember(group) ||
-        (!instances[i][group].isMember(subgroup)) ||
-        (instances[i][group][subgroup].size() == 0)) {
-      instances[i][group][subgroup][0][json_flag] = default_value;
+  for (auto& instance : instances) {
+    if (!instance.isMember(group) || (!instance[group].isMember(subgroup)) ||
+        (instance[group][subgroup].size() == 0)) {
+      instance[group][subgroup][0][json_flag] = default_value;
 
     } else {
       // Check the whole array
-      int vector_size = instances[i][group][subgroup].size();
-      for (int j = 0; j < vector_size; j++) {
-        if (!instances[i][group][subgroup][j].isMember(json_flag)) {
-          instances[i][group][subgroup][j][json_flag] = default_value;
+      for (auto& subgroup_member : instance[group][subgroup]) {
+        if (!subgroup_member.isMember(json_flag)) {
+          subgroup_member[json_flag] = default_value;
         }
       }
     }
   }
 }
 
+std::string GenerateGflag(const std::string& gflag_name,
+                          const std::vector<std::string>& values) {
+  std::stringstream buff;
+  buff << "--" << gflag_name << "=";
+  buff << android::base::Join(values, ',');
+  return buff.str();
+}
+
 Result<std::string> GenerateGflag(const Json::Value& instances,
                                   const std::string& gflag_name,
                                   const std::vector<std::string>& selectors) {
-  std::stringstream buff;
-  buff << "--" << gflag_name << "=";
-
-  int size = instances.size();
-  for (int i = 0; i < size; i++) {
-    const Json::Value* traversal = &instances[i];
-    for (const auto& selector : selectors) {
-      CF_EXPECTF(traversal->isMember(selector),
-                 "JSON selector \"{}\" does not exist when trying to create "
-                 "gflag \"{}\"",
-                 selector, gflag_name);
-      traversal = &(*traversal)[selector];
-    }
-    buff << traversal->asString();
-    if (i != size - 1) {
-      buff << ",";
-    }
-  }
-  return buff.str();
+  auto values = CF_EXPECTF(GetArrayValues<std::string>(instances, selectors),
+                           "Unable to get values for gflag \"{}\"", gflag_name);
+  return GenerateGflag(gflag_name, values);
 }
 
 std::vector<std::string> MergeResults(std::vector<std::string> first_list,
@@ -106,7 +98,6 @@
  * @param src : input json object tree to be merged
  */
 void MergeTwoJsonObjs(Json::Value& dst, const Json::Value& src) {
-  // Merge all members of src into dst
   for (const auto& key : src.getMemberNames()) {
     if (src[key].type() == Json::arrayValue) {
       for (int i = 0; i < src[key].size(); i++) {
diff --git a/host/commands/cvd/parser/cf_configs_common.h b/host/commands/cvd/parser/cf_configs_common.h
index 8f39aac..643ac64 100644
--- a/host/commands/cvd/parser/cf_configs_common.h
+++ b/host/commands/cvd/parser/cf_configs_common.h
@@ -27,8 +27,6 @@
 
 #include "common/libs/utils/result.h"
 
-#define GENERATE_MVP_FLAGS_ONLY true
-
 namespace cuttlefish {
 
 Result<void> ValidateTypo(const Json::Value& root,
@@ -86,6 +84,8 @@
                                  const std::string& json_flag,
                                  int default_value);
 
+std::string GenerateGflag(const std::string& gflag_name,
+                          const std::vector<std::string>& values);
 Result<std::string> GenerateGflag(const Json::Value& instances,
                                   const std::string& gflag_name,
                                   const std::vector<std::string>& selectors);
diff --git a/host/commands/cvd/parser/cf_configs_instances.cpp b/host/commands/cvd/parser/cf_configs_instances.cpp
index d9a24db..405d9b4 100644
--- a/host/commands/cvd/parser/cf_configs_instances.cpp
+++ b/host/commands/cvd/parser/cf_configs_instances.cpp
@@ -16,39 +16,39 @@
 
 #include "host/commands/cvd/parser/cf_configs_instances.h"
 
-#include <android-base/logging.h>
 #include <iostream>
+#include <string>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <json/json.h>
 
 #include "common/libs/utils/result.h"
 #include "host/commands/cvd/parser/cf_configs_common.h"
 #include "host/commands/cvd/parser/instance/cf_boot_configs.h"
 #include "host/commands/cvd/parser/instance/cf_disk_configs.h"
 #include "host/commands/cvd/parser/instance/cf_graphics_configs.h"
-#include "host/commands/cvd/parser/instance/cf_metrics_configs.h"
 #include "host/commands/cvd/parser/instance/cf_security_configs.h"
 #include "host/commands/cvd/parser/instance/cf_vm_configs.h"
 
 namespace cuttlefish {
 
-Result<void> InitInstancesConfigs(Json::Value& root) {
-  CF_EXPECT(InitVmConfigs(root));
-  CF_EXPECT(InitDiskConfigs(root));
-  CF_EXPECT(InitBootConfigs(root));
-  CF_EXPECT(InitSecurityConfigs(root));
-  InitGraphicsConfigs(root);
+Result<void> InitInstancesConfigs(Json::Value& instances) {
+  CF_EXPECT(InitBootConfigs(instances));
+  CF_EXPECT(InitDiskConfigs(instances));
+  CF_EXPECT(InitGraphicsConfigs(instances));
+  CF_EXPECT(InitSecurityConfigs(instances));
+  CF_EXPECT(InitVmConfigs(instances));
   return {};
 }
 
 Result<std::vector<std::string>> GenerateInstancesFlags(
-    const Json::Value& root) {
-  std::vector<std::string> result = CF_EXPECT(GenerateVmFlags(root));
-  result = MergeResults(result, CF_EXPECT(GenerateDiskFlags(root)));
-  if (!GENERATE_MVP_FLAGS_ONLY) {
-    result = MergeResults(result, CF_EXPECT(GenerateBootFlags(root)));
-  }
-  result = MergeResults(result, CF_EXPECT(GenerateSecurityFlags(root)));
-  result = MergeResults(result, GenerateGraphicsFlags(root));
-  result = MergeResults(result, GenerateMetricsFlags(root));
+    const Json::Value& instances) {
+  std::vector<std::string> result = CF_EXPECT(GenerateBootFlags(instances));
+  result = MergeResults(result, CF_EXPECT(GenerateDiskFlags(instances)));
+  result = MergeResults(result, CF_EXPECT(GenerateGraphicsFlags(instances)));
+  result = MergeResults(result, CF_EXPECT(GenerateSecurityFlags(instances)));
+  result = MergeResults(result, CF_EXPECT(GenerateVmFlags(instances)));
 
   return result;
 }
diff --git a/host/commands/cvd/parser/cf_flags_validator.cpp b/host/commands/cvd/parser/cf_flags_validator.cpp
index d6209cb..c50f98a 100644
--- a/host/commands/cvd/parser/cf_flags_validator.cpp
+++ b/host/commands/cvd/parser/cf_flags_validator.cpp
@@ -30,17 +30,21 @@
 namespace cuttlefish {
 namespace {
 
-// json main parameters definitions
 static std::map<std::string, Json::ValueType> kConfigsKeyMap = {
+    {"netsim_bt", Json::ValueType::booleanValue},
+    {"instances", Json::ValueType::arrayValue},
+    {"fetch", Json::ValueType::objectValue},
+    {"metrics", Json::ValueType::objectValue},
+};
+
+static std::map<std::string, Json::ValueType> kFetchKeyMap = {
     {"api_key", Json::ValueType::stringValue},
     {"credential", Json::ValueType::stringValue},
     {"wait_retry_period", Json::ValueType::uintValue},
     {"external_dns_resolver", Json::ValueType::booleanValue},
     {"keep_downloaded_archives", Json::ValueType::booleanValue},
-    {"netsim_bt", Json::ValueType::booleanValue},
-    {"instances", Json::ValueType::arrayValue}};
+};
 
-// instance object parameters definitions
 static std::map<std::string, Json::ValueType> kInstanceKeyMap = {
     {"@import", Json::ValueType::stringValue},
     {"vm", Json::ValueType::objectValue},
@@ -56,11 +60,9 @@
     {"vehicle", Json::ValueType::objectValue},
     {"location", Json::ValueType::objectValue}};
 
-// supported import values for @import key
 static std::unordered_set<std::string> kSupportedImportValues = {
     "phone", "tablet", "tv", "wearable", "auto", "slim", "go", "foldable"};
 
-// supported import values for vm category and crosvm subcategory
 static std::map<std::string, Json::ValueType> kVmKeyMap = {
     {"cpus", Json::ValueType::uintValue},
     {"memory_mb", Json::ValueType::uintValue},
@@ -76,19 +78,25 @@
     {"enable_sandbox", Json::ValueType::booleanValue},
 };
 
-// supported import values for boot category and kernel subcategory
 static std::map<std::string, Json::ValueType> kBootKeyMap = {
-    {"extra_bootconfig_args", Json::ValueType::stringValue},
     {"kernel", Json::ValueType::objectValue},
     {"enable_bootanimation", Json::ValueType::booleanValue},
-};
-static std::map<std::string, Json::ValueType> kernelkeyMap = {
-    {"extra_kernel_cmdline", Json::ValueType::stringValue},
+    {"build", Json::ValueType::stringValue},
+    {"bootloader", Json::ValueType::objectValue},
 };
 
-// supported import values for graphics category and displays subcategory
+static std::map<std::string, Json::ValueType> kKernelKeyMap = {
+    {"extra_kernel_cmdline", Json::ValueType::stringValue},
+    {"build", Json::ValueType::stringValue},
+};
+
+static std::map<std::string, Json::ValueType> kBootloaderKeyMap = {
+    {"build", Json::ValueType::stringValue},
+};
+
 static std::map<std::string, Json::ValueType> kGraphicsKeyMap = {
     {"displays", Json::ValueType::arrayValue},
+    {"record_screen", Json::ValueType::booleanValue},
 };
 static std::map<std::string, Json::ValueType> kDisplayKeyMap = {
     {"width", Json::ValueType::uintValue},
@@ -97,23 +105,26 @@
     {"refresh_rate_hertz", Json::ValueType::uintValue},
 };
 
-// supported import values for security category
 static std::map<std::string, Json::ValueType> kSecurityKeyMap = {
     {"serial_number", Json::ValueType::stringValue},
+    {"use_random_serial", Json::ValueType::stringValue},
     {"guest_enforce_security", Json::ValueType::booleanValue},
 };
 
-// supported import values for disk category
 static std::map<std::string, Json::ValueType> kDiskKeyMap = {
     {"default_build", Json::ValueType::stringValue},
-    {"system_build", Json::ValueType::stringValue},
-    {"kernel_build", Json::ValueType::stringValue},
+    {"super", Json::ValueType::objectValue},
     {"download_img_zip", Json::ValueType::booleanValue},
     {"download_target_zip_files", Json::ValueType::booleanValue},
     {"blank_data_image_mb", Json::ValueType::uintValue},
+    {"otatools", Json::ValueType::stringValue},
+    {"host_package", Json::ValueType::stringValue},
 };
 
-// Validate the security json parameters
+static std::map<std::string, Json::ValueType> kSuperKeyMap = {
+    {"system", Json::ValueType::stringValue},
+};
+
 Result<void> ValidateSecurityConfigs(const Json::Value& root) {
   CF_EXPECT(ValidateTypo(root, kSecurityKeyMap),
             "ValidateSecurityConfigs ValidateTypo fail");
@@ -122,33 +133,32 @@
 Result<void> ValidateDiskConfigs(const Json::Value& root) {
   CF_EXPECT(ValidateTypo(root, kDiskKeyMap),
             "ValidateDiskConfigs ValidateTypo fail");
+  if (root.isMember("super")) {
+    CF_EXPECT(ValidateTypo(root["super"], kSuperKeyMap),
+              "ValidateDiskSuperConfigs ValidateTypo fail");
+  }
   return {};
 }
 
-// Validate the displays json parameters
 Result<void> ValidateDisplaysConfigs(const Json::Value& root) {
   CF_EXPECT(ValidateTypo(root, kDisplayKeyMap),
             "ValidateDisplaysConfigs ValidateTypo fail");
   return {};
 }
 
-// Validate the graphics json parameters
 Result<void> ValidateGraphicsConfigs(const Json::Value& root) {
   CF_EXPECT(ValidateTypo(root, kGraphicsKeyMap),
             "ValidateGraphicsConfigs ValidateTypo fail");
 
   if (root.isMember("displays") && root["displays"].size() != 0) {
-    int num_displays = root["displays"].size();
-    for (int i = 0; i < num_displays; i++) {
-      CF_EXPECT(ValidateDisplaysConfigs(root["displays"][i]),
-                "ValidateDisplaysConfigs fail");
+    for (const auto& display : root["displays"]) {
+      CF_EXPECT(ValidateDisplaysConfigs(display));
     }
   }
 
   return {};
 }
 
-// Validate the vm json parameters
 Result<void> ValidateVmConfigs(const Json::Value& root) {
   CF_EXPECT(ValidateTypo(root, kVmKeyMap),
             "ValidateVmConfigs ValidateTypo fail");
@@ -159,62 +169,59 @@
   return {};
 }
 
-// Validate the kernel json parameters
 Result<void> ValidateKernelConfigs(const Json::Value& root) {
-  CF_EXPECT(ValidateTypo(root, kernelkeyMap),
+  CF_EXPECT(ValidateTypo(root, kKernelKeyMap),
             "ValidateKernelConfigs ValidateTypo fail");
   return {};
 }
 
-// Validate the boot json parameters
+Result<void> ValidateBootloaderConfigs(const Json::Value& root) {
+  CF_EXPECT(ValidateTypo(root, kBootloaderKeyMap),
+            "ValidateBootloaderConfigs ValidateTypo fail");
+  return {};
+}
+
 Result<void> ValidateBootConfigs(const Json::Value& root) {
   CF_EXPECT(ValidateTypo(root, kBootKeyMap),
             "ValidateBootConfigs ValidateTypo fail");
 
   if (root.isMember("kernel")) {
-    CF_EXPECT(ValidateKernelConfigs(root["kernel"]),
-              "ValidateKernelConfigs fail");
+    CF_EXPECT(ValidateKernelConfigs(root["kernel"]));
   }
-
+  if (root.isMember("bootloader")) {
+    CF_EXPECT(ValidateBootloaderConfigs(root["bootloader"]));
+  }
   return {};
 }
 
-// Validate the instances json parameters
 Result<void> ValidateInstancesConfigs(const Json::Value& instances) {
-  int num_instances = instances.size();
-  for (unsigned int i = 0; i < num_instances; i++) {
-    CF_EXPECT(ValidateTypo(instances[i], kInstanceKeyMap),
-              "vm ValidateTypo fail");
+  for (const auto& instance : instances) {
+    CF_EXPECT(ValidateTypo(instance, kInstanceKeyMap),
+              "instance ValidateTypo fail");
 
-    if (instances[i].isMember("vm")) {
-      CF_EXPECT(ValidateVmConfigs(instances[i]["vm"]),
-                "ValidateVmConfigs fail");
+    if (instance.isMember("vm")) {
+      CF_EXPECT(ValidateVmConfigs(instance["vm"]));
     }
 
-    // Validate @import flag values are supported or not
-    if (instances[i].isMember("@import")) {
+    if (instance.isMember("@import")) {
       CF_EXPECT(
-          kSupportedImportValues.count(instances[i]["@import"].asString()) > 0,
+          kSupportedImportValues.count(instance["@import"].asString()) > 0,
           "@Import flag values are not supported");
     }
 
-    if (instances[i].isMember("boot")) {
-      CF_EXPECT(ValidateBootConfigs(instances[i]["boot"]),
-                "ValidateBootConfigs fail");
+    if (instance.isMember("boot")) {
+      CF_EXPECT(ValidateBootConfigs(instance["boot"]));
     }
-    if (instances[i].isMember("security")) {
-      CF_EXPECT(ValidateSecurityConfigs(instances[i]["security"]),
-                "ValidateSecurityConfigs fail");
+    if (instance.isMember("security")) {
+      CF_EXPECT(ValidateSecurityConfigs(instance["security"]));
     }
-    if (instances[i].isMember("disk")) {
-      CF_EXPECT(ValidateDiskConfigs(instances[i]["disk"]),
-                "ValidateDiskConfigs fail");
+    if (instance.isMember("disk")) {
+      CF_EXPECT(ValidateDiskConfigs(instance["disk"]));
     }
-    if (instances[i].isMember("graphics")) {
-      CF_EXPECT(ValidateGraphicsConfigs(instances[i]["graphics"]),
-                "ValidateGraphicsConfigs fail");
+    if (instance.isMember("graphics")) {
+      CF_EXPECT(ValidateGraphicsConfigs(instance["graphics"]));
     }
-    CF_EXPECT(ValidateConfig<std::string>(instances[i], ValidateSetupWizardMode,
+    CF_EXPECT(ValidateConfig<std::string>(instance, ValidateSetupWizardMode,
                                           {"vm", "setupwizard_mode"}),
               "Invalid value for setupwizard_mode flag");
   }
@@ -224,10 +231,17 @@
 
 }  // namespace
 
-// Validate cuttlefish config json parameters
 Result<void> ValidateCfConfigs(const Json::Value& root) {
+  static const auto& kMetricsMap = *new std::map<std::string, Json::ValueType>{
+      {"enable", Json::ValueType::booleanValue},
+  };
+
   CF_EXPECT(ValidateTypo(root, kConfigsKeyMap),
             "Typo in config main parameters");
+  CF_EXPECT(ValidateTypo(root["fetch"], kFetchKeyMap),
+            "Typo in config fetch parameters");
+  CF_EXPECT(ValidateTypo(root["metrics"], kMetricsMap),
+            "Typo in config metrics parameters");
   CF_EXPECT(root.isMember("instances"), "instances object is missing");
   CF_EXPECT(ValidateInstancesConfigs(root["instances"]),
             "ValidateInstancesConfigs failed");
diff --git a/host/commands/cvd/parser/cf_metrics_configs.cpp b/host/commands/cvd/parser/cf_metrics_configs.cpp
new file mode 100644
index 0000000..ff1909e
--- /dev/null
+++ b/host/commands/cvd/parser/cf_metrics_configs.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2022 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 "host/commands/cvd/parser/cf_metrics_configs.h"
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <json/json.h>
+
+#include "common/libs/utils/json.h"
+#include "common/libs/utils/result.h"
+#include "host/commands/cvd/parser/cf_configs_common.h"
+
+namespace cuttlefish {
+namespace {
+
+constexpr bool kEnableMetricsDefault = false;
+
+std::string EnabledToReportAnonUsageStats(const bool enabled) {
+  return enabled ? "y" : "n";
+}
+
+}  // namespace
+
+Result<void> InitMetricsConfigs(Json::Value& root) {
+  CF_EXPECT(InitConfig(root, kEnableMetricsDefault, {"metrics", "enable"}));
+  return {};
+}
+
+Result<std::vector<std::string>> GenerateMetricsFlags(const Json::Value& root) {
+  std::vector<std::string> result;
+  auto report_flag_value = EnabledToReportAnonUsageStats(
+      CF_EXPECT(GetValue<bool>(root, {"metrics", "enable"})));
+  result.emplace_back(
+      GenerateGflag("report_anonymous_usage_stats", {report_flag_value}));
+  return result;
+}
+
+}  // namespace cuttlefish
diff --git a/host/commands/cvd/parser/instance/cf_metrics_configs.h b/host/commands/cvd/parser/cf_metrics_configs.h
similarity index 81%
rename from host/commands/cvd/parser/instance/cf_metrics_configs.h
rename to host/commands/cvd/parser/cf_metrics_configs.h
index d4d0ae2..7159125 100644
--- a/host/commands/cvd/parser/instance/cf_metrics_configs.h
+++ b/host/commands/cvd/parser/cf_metrics_configs.h
@@ -15,10 +15,17 @@
  */
 
 #pragma once
-#include <json/json.h>
+
 #include <string>
 #include <vector>
 
+#include <json/json.h>
+
+#include "common/libs/utils/result.h"
+
 namespace cuttlefish {
-std::vector<std::string> GenerateMetricsFlags(const Json::Value& root);
+
+Result<void> InitMetricsConfigs(Json::Value& root);
+Result<std::vector<std::string>> GenerateMetricsFlags(const Json::Value& root);
+
 };  // namespace cuttlefish
diff --git a/host/commands/cvd/parser/fetch_cvd_parser.cpp b/host/commands/cvd/parser/fetch_cvd_parser.cpp
index 76f1455..3ebb5db 100644
--- a/host/commands/cvd/parser/fetch_cvd_parser.cpp
+++ b/host/commands/cvd/parser/fetch_cvd_parser.cpp
@@ -16,99 +16,178 @@
 
 #include "host/commands/cvd/parser/fetch_cvd_parser.h"
 
-#include <algorithm>
-#include <optional>
 #include <string>
+#include <string_view>
 #include <vector>
 
+#include <android-base/strings.h>
 #include <json/json.h>
 
+#include "common/libs/utils/json.h"
 #include "common/libs/utils/result.h"
+#include "host/commands/cvd/fetch/fetch_cvd.h"
 #include "host/commands/cvd/parser/cf_configs_common.h"
 
 namespace cuttlefish {
 namespace {
 
+constexpr std::string_view kFetchPrefix = "@ab/";
+
 Result<void> InitFetchInstanceConfigs(Json::Value& instance) {
-  CF_EXPECT(InitConfig(instance, Json::Value::nullSingleton(),
-                       {"disk", "default_build"}));
-  CF_EXPECT(InitConfig(instance, Json::Value::nullSingleton(),
-                       {"disk", "system_build"}));
-  CF_EXPECT(InitConfig(instance, Json::Value::nullSingleton(),
-                       {"disk", "kernel_build"}));
-  CF_EXPECT(InitConfig(instance, Json::Value::nullSingleton(),
+  CF_EXPECT(
+      InitConfig(instance, kDefaultBuildString, {"disk", "default_build"}));
+  CF_EXPECT(
+      InitConfig(instance, kDefaultBuildString, {"disk", "super", "system"}));
+  CF_EXPECT(
+      InitConfig(instance, kDefaultBuildString, {"boot", "kernel", "build"}));
+  CF_EXPECT(InitConfig(instance, kDefaultBuildString, {"boot", "build"}));
+  CF_EXPECT(InitConfig(instance, kDefaultBuildString,
+                       {"boot", "bootloader", "build"}));
+  CF_EXPECT(InitConfig(instance, kDefaultBuildString, {"disk", "otatools"}));
+  CF_EXPECT(
+      InitConfig(instance, kDefaultBuildString, {"disk", "host_package"}));
+  CF_EXPECT(InitConfig(instance, kDefaultDownloadImgZip,
                        {"disk", "download_img_zip"}));
-  CF_EXPECT(InitConfig(instance, Json::Value::nullSingleton(),
+  CF_EXPECT(InitConfig(instance, kDefaultDownloadTargetFilesZip,
                        {"disk", "download_target_files_zip"}));
   return {};
 }
 
 Result<void> InitFetchCvdConfigs(Json::Value& root) {
-  CF_EXPECT(InitConfig(root, Json::Value::nullSingleton(), {"api_key"}));
-  CF_EXPECT(
-      InitConfig(root, Json::Value::nullSingleton(), {"credential_source"}));
-  CF_EXPECT(
-      InitConfig(root, Json::Value::nullSingleton(), {"wait_retry_period"}));
-  CF_EXPECT(InitConfig(root, Json::Value::nullSingleton(),
-                       {"external_dns_resolver"}));
-  CF_EXPECT(InitConfig(root, Json::Value::nullSingleton(),
-                       {"keep_downloaded_archives"}));
-  Json::Value& instances = root["instances"];
-  const int size = instances.size();
-  for (int i = 0; i < size; i++) {
-    CF_EXPECT(InitFetchInstanceConfigs(instances[i]));
+  CF_EXPECT(InitConfig(root, kDefaultApiKey, {"fetch", "api_key"}));
+  CF_EXPECT(InitConfig(root, kDefaultCredentialSource,
+                       {"fetch", "credential_source"}));
+  CF_EXPECT(InitConfig(root, static_cast<int>(kDefaultWaitRetryPeriod.count()),
+                       {"fetch", "wait_retry_period"}));
+  CF_EXPECT(InitConfig(root, kDefaultExternalDnsResolver,
+                       {"fetch", "external_dns_resolver"}));
+  CF_EXPECT(InitConfig(root, kDefaultKeepDownloadedArchives,
+                       {"fetch", "keep_downloaded_archives"}));
+  for (auto& instance : root["instances"]) {
+    CF_EXPECT(InitFetchInstanceConfigs(instance));
   }
   return {};
 }
 
-std::optional<std::string> OptString(const Json::Value& value) {
-  if (value.isNull()) {
-    return std::nullopt;
+bool ShouldFetch(const Json::Value& instance) {
+  for (const auto& value :
+       {instance["disk"]["default_build"], instance["disk"]["super"]["system"],
+        instance["boot"]["kernel"]["build"], instance["boot"]["build"],
+        instance["boot"]["bootloader"]["build"], instance["disk"]["otatools"],
+        instance["disk"]["host_package"]}) {
+    // expects non-prefixed build strings already converted to empty strings
+    if (!value.empty()) {
+      return true;
+    }
   }
-  return value.asString();
+  return false;
 }
 
-bool ShouldFetch(const std::vector<std::optional<std::string>>& values) {
-  return std::any_of(std::begin(values), std::end(values),
-                     [](const std::optional<std::string>& value) {
-                       return value.has_value();
-                     });
+Result<std::string> GetFetchBuildString(const Json::Value& value) {
+  std::string strVal = value.asString();
+  std::string_view view = strVal;
+  if (!android::base::ConsumePrefix(&view, kFetchPrefix)) {
+    // intentionally return an empty string when there are local, non-prefixed
+    // paths.  Fetch does not process the local paths
+    return "";
+  }
+  CF_EXPECTF(!view.empty(),
+             "\"{}\" prefixed build string was not followed by a value",
+             kFetchPrefix);
+  return std::string(view);
 }
 
-FetchCvdInstanceConfig ParseFetchInstanceConfigs(const Json::Value& instance) {
-  auto result = FetchCvdInstanceConfig{
-      .default_build = OptString(instance["disk"]["default_build"]),
-      .system_build = OptString(instance["disk"]["system_build"]),
-      .kernel_build = OptString(instance["disk"]["kernel_build"]),
-      .download_img_zip = OptString(instance["disk"]["download_img_zip"]),
-      .download_target_files_zip =
-          OptString(instance["disk"]["download_target_files_zip"])};
-  result.should_fetch = ShouldFetch(
-      {result.default_build, result.system_build, result.kernel_build});
+Result<Json::Value> RemoveNonPrefixedBuildStrings(const Json::Value& instance) {
+  auto result = Json::Value(instance);
+  result["disk"]["default_build"] =
+      CF_EXPECT(GetFetchBuildString(result["disk"]["default_build"]));
+  result["disk"]["super"]["system"] =
+      CF_EXPECT(GetFetchBuildString(result["disk"]["super"]["system"]));
+  result["boot"]["kernel"]["build"] =
+      CF_EXPECT(GetFetchBuildString(result["boot"]["kernel"]["build"]));
+  result["boot"]["build"] =
+      CF_EXPECT(GetFetchBuildString(result["boot"]["build"]));
+  result["boot"]["bootloader"]["build"] =
+      CF_EXPECT(GetFetchBuildString(result["boot"]["bootloader"]["build"]));
+  result["disk"]["otatools"] =
+      CF_EXPECT(GetFetchBuildString(result["disk"]["otatools"]));
+  result["disk"]["host_package"] =
+      CF_EXPECT(GetFetchBuildString(result["disk"]["host_package"]));
   return result;
 }
 
-FetchCvdConfig GenerateFetchCvdFlags(const Json::Value& root) {
-  auto result = FetchCvdConfig{
-      .api_key = OptString(root["api_key"]),
-      .credential_source = OptString(root["credential_source"]),
-      .wait_retry_period = OptString(root["wait_retry_period"]),
-      .external_dns_resolver = OptString(root["external_dns_resolver"]),
-      .keep_downloaded_archives = OptString(root["keep_downloaded_archives"])};
-
-  const int num_instances = root["instances"].size();
-  for (unsigned int i = 0; i < num_instances; i++) {
-    result.instances.emplace_back(
-        ParseFetchInstanceConfigs(root["instances"][i]));
+Result<std::vector<std::string>> GenerateFetchFlags(
+    const Json::Value& root, const std::string& target_directory,
+    const std::vector<std::string>& target_subdirectories) {
+  Json::Value fetch_instances = Json::Value(Json::ValueType::arrayValue);
+  std::vector<std::string> fetch_subdirectories;
+  const auto& instances = root["instances"];
+  CF_EXPECT_EQ(instances.size(), target_subdirectories.size(),
+               "Mismatched sizes between number of subdirectories and number "
+               "of instances");
+  for (int i = 0; i < instances.size(); i++) {
+    const auto prefix_filtered =
+        CF_EXPECT(RemoveNonPrefixedBuildStrings(instances[i]));
+    if (ShouldFetch(prefix_filtered)) {
+      fetch_instances.append(prefix_filtered);
+      fetch_subdirectories.emplace_back(target_subdirectories[i]);
+    }
   }
+
+  std::vector<std::string> result;
+  if (fetch_subdirectories.empty()) {
+    return result;
+  }
+  result.emplace_back(GenerateGflag("target_directory", {target_directory}));
+  result.emplace_back(GenerateGflag(
+      "api_key",
+      {CF_EXPECT(GetValue<std::string>(root, {"fetch", "api_key"}))}));
+  result.emplace_back(GenerateGflag(
+      "credential_source", {CF_EXPECT(GetValue<std::string>(
+                               root, {"fetch", "credential_source"}))}));
+  result.emplace_back(GenerateGflag(
+      "wait_retry_period", {CF_EXPECT(GetValue<std::string>(
+                               root, {"fetch", "wait_retry_period"}))}));
+  result.emplace_back(
+      GenerateGflag("external_dns_resolver",
+                    {CF_EXPECT(GetValue<std::string>(
+                        root, {"fetch", "external_dns_resolver"}))}));
+  result.emplace_back(
+      GenerateGflag("keep_downloaded_archives",
+                    {CF_EXPECT(GetValue<std::string>(
+                        root, {"fetch", "keep_downloaded_archives"}))}));
+
+  result.emplace_back(
+      GenerateGflag("target_subdirectory", fetch_subdirectories));
+  result.emplace_back(CF_EXPECT(GenerateGflag(fetch_instances, "default_build",
+                                              {"disk", "default_build"})));
+  result.emplace_back(CF_EXPECT(GenerateGflag(fetch_instances, "system_build",
+                                              {"disk", "super", "system"})));
+  result.emplace_back(CF_EXPECT(GenerateGflag(fetch_instances, "kernel_build",
+                                              {"boot", "kernel", "build"})));
+  result.emplace_back(CF_EXPECT(
+      GenerateGflag(fetch_instances, "boot_build", {"boot", "build"})));
+  result.emplace_back(CF_EXPECT(GenerateGflag(
+      fetch_instances, "bootloader_build", {"boot", "bootloader", "build"})));
+  result.emplace_back(CF_EXPECT(
+      GenerateGflag(fetch_instances, "otatools_build", {"disk", "otatools"})));
+  result.emplace_back(CF_EXPECT(GenerateGflag(
+      fetch_instances, "host_package_build", {"disk", "host_package"})));
+  result.emplace_back(CF_EXPECT(GenerateGflag(
+      fetch_instances, "download_img_zip", {"disk", "download_img_zip"})));
+  result.emplace_back(
+      CF_EXPECT(GenerateGflag(fetch_instances, "download_target_files_zip",
+                              {"disk", "download_target_files_zip"})));
   return result;
 }
 
 }  // namespace
 
-Result<FetchCvdConfig> ParseFetchCvdConfigs(Json::Value& root) {
+Result<std::vector<std::string>> ParseFetchCvdConfigs(
+    Json::Value& root, const std::string& target_directory,
+    const std::vector<std::string>& target_subdirectories) {
   CF_EXPECT(InitFetchCvdConfigs(root));
-  return {GenerateFetchCvdFlags(root)};
+  return GenerateFetchFlags(root, target_directory, target_subdirectories);
 }
 
 }  // namespace cuttlefish
diff --git a/host/commands/cvd/parser/fetch_cvd_parser.h b/host/commands/cvd/parser/fetch_cvd_parser.h
index d51fc73..f2258b3 100644
--- a/host/commands/cvd/parser/fetch_cvd_parser.h
+++ b/host/commands/cvd/parser/fetch_cvd_parser.h
@@ -16,7 +16,6 @@
 
 #pragma once
 
-#include <optional>
 #include <string>
 #include <vector>
 
@@ -26,27 +25,8 @@
 
 namespace cuttlefish {
 
-struct FetchCvdInstanceConfig {
-  bool should_fetch = false;
-  // this subdirectory is relative to FetchCvdConfig::target_directory
-  std::string target_subdirectory;
-  std::optional<std::string> default_build;
-  std::optional<std::string> system_build;
-  std::optional<std::string> kernel_build;
-  std::optional<std::string> download_img_zip;
-  std::optional<std::string> download_target_files_zip;
-};
-
-struct FetchCvdConfig {
-  std::string target_directory;
-  std::optional<std::string> api_key;
-  std::optional<std::string> credential_source;
-  std::optional<std::string> wait_retry_period;
-  std::optional<std::string> external_dns_resolver;
-  std::optional<std::string> keep_downloaded_archives;
-  std::vector<FetchCvdInstanceConfig> instances;
-};
-
-Result<FetchCvdConfig> ParseFetchCvdConfigs(Json::Value& root);
+Result<std::vector<std::string>> ParseFetchCvdConfigs(
+    Json::Value& root, const std::string& target_directory,
+    const std::vector<std::string>& target_subdirectories);
 
 };  // namespace cuttlefish
diff --git a/host/commands/cvd/parser/instance/cf_boot_configs.cpp b/host/commands/cvd/parser/instance/cf_boot_configs.cpp
index 7a8446c..b1250d4 100644
--- a/host/commands/cvd/parser/instance/cf_boot_configs.cpp
+++ b/host/commands/cvd/parser/instance/cf_boot_configs.cpp
@@ -27,13 +27,10 @@
 namespace cuttlefish {
 
 Result<void> InitBootConfigs(Json::Value& instances) {
-  const int size = instances.size();
-  for (int i = 0; i < size; i++) {
-    CF_EXPECT(InitConfig(instances[i], CF_DEFAULTS_EXTRA_BOOTCONFIG_ARGS,
-                         {"boot", "extra_bootconfig_args"}));
-    CF_EXPECT(InitConfig(instances[i], CF_DEFAULTS_ENABLE_BOOTANIMATION,
+  for (auto& instance : instances) {
+    CF_EXPECT(InitConfig(instance, CF_DEFAULTS_ENABLE_BOOTANIMATION,
                          {"boot", "enable_bootanimation"}));
-    CF_EXPECT(InitConfig(instances[i], CF_DEFAULTS_EXTRA_KERNEL_CMDLINE,
+    CF_EXPECT(InitConfig(instance, CF_DEFAULTS_EXTRA_KERNEL_CMDLINE,
                          {"boot", "kernel", "extra_kernel_cmdline"}));
   }
   return {};
@@ -43,8 +40,6 @@
     const Json::Value& instances) {
   std::vector<std::string> result;
   result.emplace_back(CF_EXPECT(GenerateGflag(
-      instances, "extra_bootconfig_args", {"boot", "extra_bootconfig_args"})));
-  result.emplace_back(CF_EXPECT(GenerateGflag(
       instances, "enable_bootanimation", {"boot", "enable_bootanimation"})));
   result.emplace_back(
       CF_EXPECT(GenerateGflag(instances, "extra_kernel_cmdline",
diff --git a/host/commands/cvd/parser/instance/cf_disk_configs.cpp b/host/commands/cvd/parser/instance/cf_disk_configs.cpp
index 43d3b63..aad71e6 100644
--- a/host/commands/cvd/parser/instance/cf_disk_configs.cpp
+++ b/host/commands/cvd/parser/instance/cf_disk_configs.cpp
@@ -28,9 +28,8 @@
 namespace cuttlefish {
 
 Result<void> InitDiskConfigs(Json::Value& instances) {
-  const int size = instances.size();
-  for (int i = 0; i < size; i++) {
-    CF_EXPECT(InitConfig(instances[i], DEFAULT_BLANK_DATA_IMAGE_SIZE,
+  for (auto& instance : instances) {
+    CF_EXPECT(InitConfig(instance, DEFAULT_BLANK_DATA_IMAGE_SIZE,
                          {"disk", "blank_data_image_mb"}));
   }
   return {};
diff --git a/host/commands/cvd/parser/instance/cf_graphics_configs.cpp b/host/commands/cvd/parser/instance/cf_graphics_configs.cpp
index 1e17684..1c8eb43 100644
--- a/host/commands/cvd/parser/instance/cf_graphics_configs.cpp
+++ b/host/commands/cvd/parser/instance/cf_graphics_configs.cpp
@@ -28,7 +28,7 @@
 
 namespace cuttlefish {
 
-void InitGraphicsConfigs(Json::Value& instances) {
+Result<void> InitGraphicsConfigs(Json::Value& instances) {
   InitIntConfigSubGroupVector(instances, "graphics", "displays", "width",
                               CF_DEFAULTS_DISPLAY_WIDTH);
   InitIntConfigSubGroupVector(instances, "graphics", "displays", "height",
@@ -38,18 +38,20 @@
   InitIntConfigSubGroupVector(instances, "graphics", "displays",
                               "refresh_rate_hertz",
                               CF_DEFAULTS_DISPLAY_REFRESH_RATE);
+  for (auto& instance : instances) {
+    CF_EXPECT(InitConfig(instance, CF_DEFAULTS_RECORD_SCREEN,
+                         {"graphics", "record_screen"}));
+  }
+  return {};
 }
 
 std::string GenerateDisplayFlag(const Json::Value& instances_json) {
   using google::protobuf::TextFormat;
   cuttlefish::InstancesDisplays all_instances_displays;
 
-  int num_instances = instances_json.size();
-  for (int i = 0; i < num_instances; i++) {
+  for (const auto& instance_json : instances_json) {
     auto* instance = all_instances_displays.add_instances();
-    int num_displays = instances_json[i]["graphics"]["displays"].size();
-    for (int j = 0; j < num_displays; j++) {
-      Json::Value display_json = instances_json[i]["graphics"]["displays"][j];
+    for (const auto& display_json : instance_json["graphics"]["displays"]) {
       auto* display = instance->add_displays();
       display->set_width(display_json["width"].asInt());
       display->set_height(display_json["height"].asInt());
@@ -74,9 +76,12 @@
   return "--displays_binproto=" + base64_output;
 }
 
-std::vector<std::string> GenerateGraphicsFlags(const Json::Value& instances) {
+Result<std::vector<std::string>> GenerateGraphicsFlags(
+    const Json::Value& instances) {
   std::vector<std::string> result;
   result.emplace_back(GenerateDisplayFlag(instances));
+  result.emplace_back(CF_EXPECT(GenerateGflag(instances, "record_screen",
+                                              {"graphics", "record_screen"})));
   return result;
 }
 
diff --git a/host/commands/cvd/parser/instance/cf_graphics_configs.h b/host/commands/cvd/parser/instance/cf_graphics_configs.h
index c0bdccd..f577fed 100644
--- a/host/commands/cvd/parser/instance/cf_graphics_configs.h
+++ b/host/commands/cvd/parser/instance/cf_graphics_configs.h
@@ -20,6 +20,6 @@
 #include <vector>
 
 namespace cuttlefish {
-void InitGraphicsConfigs(Json::Value& root);
-std::vector<std::string> GenerateGraphicsFlags(const Json::Value& root);
+Result<void> InitGraphicsConfigs(Json::Value& root);
+Result<std::vector<std::string>> GenerateGraphicsFlags(const Json::Value& root);
 };  // namespace cuttlefish
diff --git a/host/commands/cvd/parser/instance/cf_metrics_configs.cpp b/host/commands/cvd/parser/instance/cf_metrics_configs.cpp
deleted file mode 100644
index d708343..0000000
--- a/host/commands/cvd/parser/instance/cf_metrics_configs.cpp
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2022 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 "host/commands/cvd/parser/instance/cf_metrics_configs.h"
-
-#include <android-base/logging.h>
-
-#include "host/commands/assemble_cvd/flags_defaults.h"
-#include "host/commands/cvd/parser/cf_configs_common.h"
-#include "host/libs/config/cuttlefish_config.h"
-
-// Metrics collection will be disabled by default for canonical configs MVP
-#define DEFAULT_ENABLE_REPORTING "n"
-
-namespace cuttlefish {
-
-static std::string GenerateReportFlag() {
-  std::stringstream result_flag;
-  result_flag << "--report_anonymous_usage_stats=" << DEFAULT_ENABLE_REPORTING;
-  return result_flag.str();
-}
-
-std::vector<std::string> GenerateMetricsFlags(const Json::Value&) {
-  std::vector<std::string> result;
-  result.emplace_back(GenerateReportFlag());
-  return result;
-}
-
-}  // namespace cuttlefish
diff --git a/host/commands/cvd/parser/instance/cf_security_configs.cpp b/host/commands/cvd/parser/instance/cf_security_configs.cpp
index f2bc19c..7e2a78a 100644
--- a/host/commands/cvd/parser/instance/cf_security_configs.cpp
+++ b/host/commands/cvd/parser/instance/cf_security_configs.cpp
@@ -26,29 +26,13 @@
 
 namespace cuttlefish {
 
-/*
-This function is created to cover the initiation use_random_serial flag
-when the json value of serial_number equal "@random"
-*/
-void InitRandomSerialNumber(Json::Value& instance) {
-  std::string serial_number_str =
-      instance["security"]["serial_number"].asString();
-  if (serial_number_str == "@random") {
-    instance["security"]["use_random_serial"] = true;
-  } else {
-    instance["security"]["use_random_serial"] = false;
-  }
-}
-
 Result<void> InitSecurityConfigs(Json::Value& instances) {
-  const int size = instances.size();
-  for (int i = 0; i < size; i++) {
-    CF_EXPECT(InitConfig(instances[i], CF_DEFAULTS_SERIAL_NUMBER,
+  for (auto& instance : instances) {
+    CF_EXPECT(InitConfig(instance, CF_DEFAULTS_SERIAL_NUMBER,
                          {"security", "serial_number"}));
-    // This init should be called after the InitSecurityConfigs call, since it
-    // depends on serial_number flag
-    InitRandomSerialNumber(instances[i]);
-    CF_EXPECT(InitConfig(instances[i], CF_DEFAULTS_GUEST_ENFORCE_SECURITY,
+    CF_EXPECT(InitConfig(instance, CF_DEFAULTS_USE_RANDOM_SERIAL,
+                         {"security", "use_random_serial"}));
+    CF_EXPECT(InitConfig(instance, CF_DEFAULTS_GUEST_ENFORCE_SECURITY,
                          {"security", "guest_enforce_security"}));
   }
   return {};
@@ -57,12 +41,10 @@
 Result<std::vector<std::string>> GenerateSecurityFlags(
     const Json::Value& instances) {
   std::vector<std::string> result;
-  if (!GENERATE_MVP_FLAGS_ONLY) {
-    result.emplace_back(CF_EXPECT(GenerateGflag(
-        instances, "serial_number", {"security", "serial_number"})));
-    result.emplace_back(CF_EXPECT(GenerateGflag(
-        instances, "use_random_serial", {"security", "use_random_serial"})));
-  }
+  result.emplace_back(CF_EXPECT(GenerateGflag(instances, "serial_number",
+                                              {"security", "serial_number"})));
+  result.emplace_back(CF_EXPECT(GenerateGflag(
+      instances, "use_random_serial", {"security", "use_random_serial"})));
   result.emplace_back(
       CF_EXPECT(GenerateGflag(instances, "guest_enforce_security",
                               {"security", "guest_enforce_security"})));
diff --git a/host/commands/cvd/parser/instance/cf_vm_configs.cpp b/host/commands/cvd/parser/instance/cf_vm_configs.cpp
index 1064a57..44bc990 100644
--- a/host/commands/cvd/parser/instance/cf_vm_configs.cpp
+++ b/host/commands/cvd/parser/instance/cf_vm_configs.cpp
@@ -28,38 +28,37 @@
 #define UI_DEFAULTS_MEMORY_MB 2048
 
 namespace cuttlefish {
+namespace {
 
-void InitVmManagerConfig(Json::Value& instance) {
-  if (instance.isMember("vm")) {
-    if (instance["vm"].isMember("crosvm")) {
-      instance["vm"]["vm_manager"] = "crosvm";
-    } else if (instance["vm"].isMember("qemu")) {
-      instance["vm"]["vm_manager"] = "qemu_cli";
-    } else if (instance["vm"].isMember("gem5")) {
-      instance["vm"]["vm_manager"] = "gem5";
-    } else {
-      // Set vm manager to default value (crosvm)
-      instance["vm"]["vm_manager"] = "crosvm";
-    }
+std::string GetVmManagerDefault(Json::Value& instance_vm) {
+  if (instance_vm.isNull()) {
+    return "crosvm";
+  }
+  if (instance_vm.isMember("crosvm")) {
+    return "crosvm";
+  } else if (instance_vm.isMember("qemu")) {
+    return "qemu_cli";
+  } else if (instance_vm.isMember("gem5")) {
+    return "gem5";
   } else {
-    // vm object doesn't exist, set the default vm manager to crosvm
-    instance["vm"]["vm_manager"] = "crosvm";
+    return "crosvm";
   }
 }
 
+}  // namespace
+
 Result<void> InitVmConfigs(Json::Value& instances) {
-  const int size = instances.size();
-  for (int i = 0; i < size; i++) {
-    CF_EXPECT(InitConfig(instances[i], CF_DEFAULTS_CPUS, {"vm", "cpus"}));
+  for (auto& instance : instances) {
+    CF_EXPECT(InitConfig(instance, CF_DEFAULTS_CPUS, {"vm", "cpus"}));
+    CF_EXPECT(InitConfig(instance, UI_DEFAULTS_MEMORY_MB, {"vm", "memory_mb"}));
     CF_EXPECT(
-        InitConfig(instances[i], UI_DEFAULTS_MEMORY_MB, {"vm", "memory_mb"}));
-    CF_EXPECT(
-        InitConfig(instances[i], CF_DEFAULTS_USE_SDCARD, {"vm", "use_sdcard"}));
-    CF_EXPECT(InitConfig(instances[i], CF_DEFAULTS_SETUPWIZARD_MODE,
+        InitConfig(instance, CF_DEFAULTS_USE_SDCARD, {"vm", "use_sdcard"}));
+    CF_EXPECT(InitConfig(instance, CF_DEFAULTS_SETUPWIZARD_MODE,
                          {"vm", "setupwizard_mode"}));
-    CF_EXPECT(InitConfig(instances[i], CF_DEFAULTS_UUID, {"vm", "uuid"}));
-    InitVmManagerConfig(instances[i]);
-    CF_EXPECT(InitConfig(instances[i], CF_DEFAULTS_ENABLE_SANDBOX,
+    CF_EXPECT(InitConfig(instance, CF_DEFAULTS_UUID, {"vm", "uuid"}));
+    CF_EXPECT(InitConfig(instance, GetVmManagerDefault(instance["vm"]),
+                         {"vm", "vm_manager"}));
+    CF_EXPECT(InitConfig(instance, CF_DEFAULTS_ENABLE_SANDBOX,
                          {"vm", "crosvm", "enable_sandbox"}));
   }
   return {};
@@ -68,13 +67,11 @@
 std::vector<std::string> GenerateCustomConfigsFlags(
     const Json::Value& instances) {
   std::vector<std::string> result;
-  const int size = instances.size();
-  for (int i = 0; i < size; i++) {
-    if (instances[i].isMember("vm") &&
-        instances[i]["vm"].isMember("custom_actions")) {
+  for (auto& instance : instances) {
+    if (instance.isMember("vm") && instance["vm"].isMember("custom_actions")) {
       Json::StreamWriterBuilder factory;
       std::string mapped_text =
-          Json::writeString(factory, instances[i]["vm"]["custom_actions"]);
+          Json::writeString(factory, instance["vm"]["custom_actions"]);
       // format json string string to match aosp/2374890 input format
       mapped_text = android::base::StringReplace(mapped_text, "\n", "", true);
       mapped_text = android::base::StringReplace(mapped_text, "\r", "", true);
@@ -103,10 +100,8 @@
       CF_EXPECT(GenerateGflag(instances, "vm_manager", {"vm", "vm_manager"})));
   result.emplace_back(CF_EXPECT(GenerateGflag(instances, "setupwizard_mode",
                                               {"vm", "setupwizard_mode"})));
-  if (!GENERATE_MVP_FLAGS_ONLY) {
-    result.emplace_back(
-        CF_EXPECT(GenerateGflag(instances, "uuid", {"vm", "uuid"})));
-  }
+  result.emplace_back(
+      CF_EXPECT(GenerateGflag(instances, "uuid", {"vm", "uuid"})));
   result.emplace_back(CF_EXPECT(GenerateGflag(
       instances, "enable_sandbox", {"vm", "crosvm", "enable_sandbox"})));
 
diff --git a/host/commands/cvd/parser/launch_cvd_parser.cpp b/host/commands/cvd/parser/launch_cvd_parser.cpp
index 9c18b0c..f65fd5a 100644
--- a/host/commands/cvd/parser/launch_cvd_parser.cpp
+++ b/host/commands/cvd/parser/launch_cvd_parser.cpp
@@ -13,60 +13,45 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include "host/commands/cvd/parser/launch_cvd_parser.h"
 
-#include <android-base/file.h>
-#include <gflags/gflags.h>
-
-#include <stdio.h>
-#include <fstream>
 #include <string>
+#include <vector>
 
-#include "common/libs/utils/files.h"
+#include <json/json.h>
+
 #include "common/libs/utils/json.h"
 #include "common/libs/utils/result.h"
 #include "host/commands/assemble_cvd/flags_defaults.h"
 #include "host/commands/cvd/parser/cf_configs_common.h"
 #include "host/commands/cvd/parser/cf_configs_instances.h"
-#include "host/commands/cvd/parser/launch_cvd_parser.h"
+#include "host/commands/cvd/parser/cf_metrics_configs.h"
 #include "host/commands/cvd/parser/launch_cvd_templates.h"
 
 namespace cuttlefish {
-
-std::string GenerateNumInstancesFlag(const Json::Value& root) {
-  int num_instances = root["instances"].size();
-  LOG(DEBUG) << "num_instances = " << num_instances;
-  std::string result = "--num_instances=" + std::to_string(num_instances);
-  return result;
-}
-
-std::string GenerateCommonGflag(const Json::Value& root,
-                                const std::string& gflag_name,
-                                const std::string& json_flag) {
-  std::stringstream buff;
-  // Append Header
-  buff << "--" << gflag_name << "=" << root[json_flag].asString();
-  return buff.str();
-}
+namespace {
 
 Result<std::vector<std::string>> GenerateCfFlags(const Json::Value& root) {
   std::vector<std::string> result;
-  result.emplace_back(GenerateNumInstancesFlag(root));
-  result.emplace_back(GenerateCommonGflag(root, "netsim_bt", "netsim_bt"));
-
+  result.emplace_back(GenerateGflag(
+      "num_instances", {std::to_string(root["instances"].size())}));
+  result.emplace_back(GenerateGflag(
+      "netsim_bt", {CF_EXPECT(GetValue<std::string>(root, {"netsim_bt"}))}));
+  result = MergeResults(result, CF_EXPECT(GenerateMetricsFlags(root)));
   result = MergeResults(result,
                         CF_EXPECT(GenerateInstancesFlags(root["instances"])));
   return result;
 }
 
 Result<void> InitCvdConfigs(Json::Value& root) {
-  // Handle common flags
-  if (!root.isMember("netsim_bt")) {
-    root["netsim_bt"] = CF_DEFAULTS_NETSIM_BT;
-  }
+  CF_EXPECT(InitConfig(root, CF_DEFAULTS_NETSIM_BT, {"netsim_bt"}));
+  CF_EXPECT(InitMetricsConfigs(root));
   CF_EXPECT(InitInstancesConfigs(root["instances"]));
   return {};
 }
 
+}  // namespace
+
 Result<std::vector<std::string>> ParseLaunchCvdConfigs(Json::Value& root) {
   ExtractLaunchTemplates(root["instances"]);
   CF_EXPECT(InitCvdConfigs(root));
diff --git a/host/commands/cvd/parser/load_configs_parser.cpp b/host/commands/cvd/parser/load_configs_parser.cpp
index 1aac010..8faa46c 100644
--- a/host/commands/cvd/parser/load_configs_parser.cpp
+++ b/host/commands/cvd/parser/load_configs_parser.cpp
@@ -16,21 +16,142 @@
 
 #include "host/commands/cvd/parser/load_configs_parser.h"
 
-#include <android-base/file.h>
-#include <gflags/gflags.h>
+#include <unistd.h>
 
-#include <stdio.h>
+#include <chrono>
+#include <cstdio>
 #include <fstream>
 #include <string>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+#include <json/json.h>
 
 #include "common/libs/utils/files.h"
 #include "common/libs/utils/json.h"
 #include "common/libs/utils/result.h"
+#include "host/commands/cvd/parser/cf_configs_common.h"
 #include "host/commands/cvd/parser/cf_flags_validator.h"
 #include "host/commands/cvd/parser/fetch_cvd_parser.h"
 #include "host/commands/cvd/parser/launch_cvd_parser.h"
 
 namespace cuttlefish {
+namespace {
+
+Result<void> ValidateArgFormat(const std::string& str) {
+  auto equalsPos = str.find('=');
+  CF_EXPECT(equalsPos != std::string::npos,
+            "equal value is not provided in the argument");
+  std::string prefix = str.substr(0, equalsPos);
+  CF_EXPECT(!prefix.empty(), "argument value should not be empty");
+  CF_EXPECT(prefix.find('.') != std::string::npos,
+            "argument value must be dot separated");
+  CF_EXPECT(prefix[0] != '.', "argument value should not start with a dot");
+  CF_EXPECT(prefix.find("..") == std::string::npos,
+            "argument value should not contain two consecutive dots");
+  CF_EXPECT(prefix.back() != '.', "argument value should not end with a dot");
+  return {};
+}
+
+Result<void> ValidateArgsFormat(const std::vector<std::string>& strings) {
+  for (const auto& str : strings) {
+    CF_EXPECT(ValidateArgFormat(str),
+              "Invalid  argument format. " << str << " Please use arg=value");
+  }
+  return {};
+}
+
+// TODO(moelsherif): expand this enum in the future to support more types (
+// double , float , etc) if neeeded
+enum ArgValueType { UINTEGER, BOOLEAN, TEXT };
+
+bool IsUnsignedInteger(const std::string& str) {
+  return !str.empty() && std::all_of(str.begin(), str.end(),
+                                     [](char c) { return std::isdigit(c); });
+}
+
+ArgValueType GetArgValueType(const std::string& str) {
+  if (IsUnsignedInteger(str)) {
+    return UINTEGER;
+  }
+
+  if (str == "true" || str == "false") {
+    return BOOLEAN;
+  }
+
+  // Otherwise, treat the string as text
+  return TEXT;
+}
+
+Json::Value ConvertArgToJson(const std::string& key,
+                             const std::string& leafValue) {
+  std::stack<std::string> levels;
+  std::stringstream ks(key);
+  std::string token;
+  while (std::getline(ks, token, '.')) {
+    levels.push(token);
+  }
+
+  // assign the leaf value based on the type of input value
+  Json::Value leaf;
+  if (GetArgValueType(leafValue) == UINTEGER) {
+    std::uint32_t leaf_val{};
+    if (!android::base::ParseUint(leafValue, &leaf_val)) {
+      LOG(ERROR) << "Failed to parse unsigned integer " << leafValue;
+      return Json::Value::null;
+    };
+    leaf = leaf_val;
+  } else if (GetArgValueType(leafValue) == BOOLEAN) {
+    leaf = (leafValue == "true");
+  } else {
+    leaf = leafValue;
+  }
+
+  while (!levels.empty()) {
+    Json::Value curr;
+    std::string index = levels.top();
+
+    if (GetArgValueType(index) == UINTEGER) {
+      std::uint32_t index_val{};
+      if (!android::base::ParseUint(index, &index_val)) {
+        LOG(ERROR) << "Failed to parse unsigned integer " << index;
+        return Json::Value::null;
+      }
+      curr[index_val] = leaf;
+    } else {
+      curr[index] = leaf;
+    }
+
+    leaf = curr;
+    levels.pop();
+  }
+
+  return leaf;
+}
+
+Json::Value ParseArgsToJson(const std::vector<std::string>& strings) {
+  Json::Value jsonValue;
+  for (const auto& str : strings) {
+    std::string key;
+    std::string value;
+    size_t equals_pos = str.find('=');
+    if (equals_pos != std::string::npos) {
+      key = str.substr(0, equals_pos);
+      value = str.substr(equals_pos + 1);
+    } else {
+      key = str;
+      value.clear();
+      LOG(WARNING) << "No value provided for key " << key;
+      return Json::Value::null;
+    }
+    MergeTwoJsonObjs(jsonValue, ConvertArgToJson(key, value));
+  }
+  return jsonValue;
+}
+
+}  // namespace
 
 Result<Json::Value> ParseJsonFile(const std::string& file_path) {
   CF_EXPECT(FileExists(file_path), "provided File to cvd load does not exist");
@@ -44,10 +165,56 @@
   return root;
 }
 
-Result<CvdFlags> ParseCvdConfigs(Json::Value& root) {
+Result<Json::Value> GetOverridedJsonConfig(
+    const std::string& config_path,
+    const std::vector<std::string>& override_flags) {
+  Json::Value result = CF_EXPECT(ParseJsonFile(config_path),
+                                 "Parsing json config input file failed");
+
+  if (override_flags.size() > 0) {
+    CF_EXPECT(ValidateArgsFormat(override_flags),
+              "override parameters are not in the correct format");
+    auto args_tree = ParseArgsToJson(override_flags);
+    MergeTwoJsonObjs(result, args_tree);
+  }
+
+  return result;
+}
+
+Result<LoadDirectories> GenerateLoadDirectories(const int num_instances) {
+  CF_EXPECT_GT(num_instances, 0, "No instances in config to load");
+
+  auto parent_directory = "/tmp/cvd/" + std::to_string(getuid()) + "/";
+  auto time = std::chrono::system_clock::now().time_since_epoch().count();
+  auto result = LoadDirectories{
+      .target_directory = parent_directory + std::to_string(time),
+      .launch_home_directory =
+          parent_directory + std::to_string(time) + "_home/"};
+
+  std::vector<std::string> system_image_directories;
+  for (int i = 0; i < num_instances; i++) {
+    LOG(INFO) << "Instance " << i << " directory is " << result.target_directory
+              << "/" << std::to_string(i);
+    auto target_subdirectory = std::to_string(i);
+    result.target_subdirectories.emplace_back(target_subdirectory);
+    system_image_directories.emplace_back(result.target_directory + "/" +
+                                          target_subdirectory);
+  }
+  result.first_instance_directory =
+      result.target_directory + "/" + result.target_subdirectories[0];
+  result.system_image_directory_flag =
+      "--system_image_dir=" +
+      android::base::Join(system_image_directories, ',');
+  return result;
+}
+
+Result<CvdFlags> ParseCvdConfigs(Json::Value& root,
+                                 const LoadDirectories& load_directories) {
   CF_EXPECT(ValidateCfConfigs(root), "Loaded Json validation failed");
   return CvdFlags{.launch_cvd_flags = CF_EXPECT(ParseLaunchCvdConfigs(root)),
-                  .fetch_cvd_flags = CF_EXPECT(ParseFetchCvdConfigs(root))};
+                  .fetch_cvd_flags = CF_EXPECT(ParseFetchCvdConfigs(
+                      root, load_directories.target_directory,
+                      load_directories.target_subdirectories))};
 }
 
 }  // namespace cuttlefish
diff --git a/host/commands/cvd/parser/load_configs_parser.h b/host/commands/cvd/parser/load_configs_parser.h
index caf271a..bcbec10 100644
--- a/host/commands/cvd/parser/load_configs_parser.h
+++ b/host/commands/cvd/parser/load_configs_parser.h
@@ -28,11 +28,26 @@
 
 typedef struct _CvdFlags {
   std::vector<std::string> launch_cvd_flags;
-  FetchCvdConfig fetch_cvd_flags;
+  std::vector<std::string> fetch_cvd_flags;
 } CvdFlags;
 
+struct LoadDirectories {
+  std::string target_directory;
+  std::vector<std::string> target_subdirectories;
+  std::string launch_home_directory;
+  std::string first_instance_directory;
+  std::string system_image_directory_flag;
+};
+
 Result<Json::Value> ParseJsonFile(const std::string& file_path);
 
-Result<CvdFlags> ParseCvdConfigs(Json::Value& root);
+Result<Json::Value> GetOverridedJsonConfig(
+    const std::string& config_path,
+    const std::vector<std::string>& override_flags);
+
+Result<LoadDirectories> GenerateLoadDirectories(const int num_instances);
+
+Result<CvdFlags> ParseCvdConfigs(Json::Value& root,
+                                 const LoadDirectories& load_directories);
 
 };  // namespace cuttlefish
diff --git a/host/commands/cvd/selector/creation_analyzer.cpp b/host/commands/cvd/selector/creation_analyzer.cpp
index 19b407e..16c773e 100644
--- a/host/commands/cvd/selector/creation_analyzer.cpp
+++ b/host/commands/cvd/selector/creation_analyzer.cpp
@@ -42,7 +42,7 @@
   if (cmd.empty()) {
     return false;
   }
-  return cmd == "start";
+  return cmd == "start" || cmd == "launch_cvd";
 }
 
 Result<GroupCreationInfo> CreationAnalyzer::Analyze(
diff --git a/host/commands/cvd/selector/start_selector_parser.cpp b/host/commands/cvd/selector/start_selector_parser.cpp
index 4a6e6ad..d7de75f 100644
--- a/host/commands/cvd/selector/start_selector_parser.cpp
+++ b/host/commands/cvd/selector/start_selector_parser.cpp
@@ -125,19 +125,6 @@
   return parsed.ok() ? std::optional(*parsed) : std::nullopt;
 }
 
-std::optional<unsigned> TryFromUser(const cvd_common::Envs& envs) {
-  if (!Contains(envs, "USER")) {
-    return std::nullopt;
-  }
-  std::string_view user{envs.at("USER")};
-  if (user.empty() || !android::base::ConsumePrefix(&user, kVsocUserPrefix)) {
-    return std::nullopt;
-  }
-  const auto& vsoc_num = user;
-  auto vsoc_id = ParseNaturalNumber(vsoc_num.data());
-  return vsoc_id.ok() ? std::optional(*vsoc_id) : std::nullopt;
-}
-
 }  // namespace
 
 std::optional<std::vector<unsigned>>
@@ -441,8 +428,7 @@
       .num_instances = std::move(num_instances),
       .instance_nums = std::move(instance_nums),
       .base_instance_num = std::move(base_instance_num),
-      .cuttlefish_instance_env = TryFromCuttlefishInstance(envs_),
-      .vsoc_suffix = TryFromUser(envs_)};
+      .cuttlefish_instance_env = TryFromCuttlefishInstance(envs_)};
   auto parsed_ids = CF_EXPECT(HandleInstanceIds(instance_nums_param));
   requested_num_instances_ = parsed_ids.GetNumOfInstances();
   instance_ids_ = std::move(parsed_ids.GetInstanceIds());
diff --git a/host/commands/cvd/server.cc b/host/commands/cvd/server.cc
index 4619364..95db580 100644
--- a/host/commands/cvd/server.cc
+++ b/host/commands/cvd/server.cc
@@ -58,10 +58,9 @@
 #include "host/commands/cvd/server_command/load_configs.h"
 #include "host/commands/cvd/server_command/power.h"
 #include "host/commands/cvd/server_command/reset.h"
+#include "host/commands/cvd/server_command/snapshot.h"
 #include "host/commands/cvd/server_command/start.h"
 #include "host/commands/cvd/server_command/subcmd.h"
-#include "host/commands/cvd/server_command/suspend_resume.h"
-#include "host/commands/cvd/server_command/vm_control.h"
 #include "host/commands/cvd/server_constants.h"
 #include "host/libs/config/cuttlefish_config.h"
 #include "host/libs/config/inject.h"
@@ -128,11 +127,10 @@
       .install(CvdHelpComponent)
       .install(CvdResetComponent)
       .install(CvdRestartComponent)
+      .install(CvdSnapshotComponent)
       .install(cvdShutdownComponent)
       .install(CvdStartCommandComponent)
-      .install(CvdSuspendResumeComponent)
       .install(cvdVersionComponent)
-      .install(CvdVmControlComponent)
       .install(DemoMultiVdComponent)
       .install(LoadConfigsComponent);
 }
diff --git a/host/commands/cvd/server_command/Android.bp b/host/commands/cvd/server_command/Android.bp
index 0fd5927..6fd426b 100644
--- a/host/commands/cvd/server_command/Android.bp
+++ b/host/commands/cvd/server_command/Android.bp
@@ -45,13 +45,12 @@
         "serial_launch.cpp",
         "serial_preset.cpp",
         "shutdown.cpp",
+        "snapshot.cpp",
         "start.cpp",
         "start_impl.cpp",
         "subprocess_waiter.cpp",
-        "suspend_resume.cpp",
 	"try_acloud.cpp",
         "version.cpp",
-        "vm_control.cpp",
     ],
     static_libs: [
         "libcvd_acloud",
diff --git a/host/commands/cvd/server_command/acloud_mixsuperimage.cpp b/host/commands/cvd/server_command/acloud_mixsuperimage.cpp
index c3d3138..25d45c2 100644
--- a/host/commands/cvd/server_command/acloud_mixsuperimage.cpp
+++ b/host/commands/cvd/server_command/acloud_mixsuperimage.cpp
@@ -48,6 +48,8 @@
 const std::string _TARGET_FILES_META_DIR_NAME = "META";
 const std::string _TARGET_FILES_IMAGES_DIR_NAME = "IMAGES";
 const std::string _SYSTEM_IMAGE_NAME_PATTERN = "system.img";
+const std::string _SYSTEM_EXT_IMAGE_NAME_PATTERN = "system_ext.img";
+const std::string _PRODUCT_IMAGE_NAME_PATTERN = "product.img";
 
 /*
  * Find misc info in build output dir or extracted target files.
@@ -289,14 +291,20 @@
     system_image_path = FindImage(local_system_image, {_SYSTEM_IMAGE_NAME_PATTERN});
     CF_EXPECT(system_image_path != "",
               "Cannot find system.img in " << local_system_image);
+    std::string system_ext_image_path =
+        FindImage(local_system_image, {_SYSTEM_EXT_IMAGE_NAME_PATTERN});
+    std::string product_image_path =
+        FindImage(local_system_image, {_PRODUCT_IMAGE_NAME_PATTERN});
 
     return BuildSuperImage(
         super_image, misc_info, callback_unlock,
-        [&image_dir,
-         &system_image_path](const std::string& partition) -> Result<std::string> {
-          return GetImageForPartition(
-              partition, image_dir,
-              {{"system", system_image_path}});
+        [&](const std::string& partition) -> Result<std::string> {
+          return GetImageForPartition(partition, image_dir,
+                                      {
+                                          {"system", system_image_path},
+                                          {"system_ext", system_ext_image_path},
+                                          {"product", product_image_path},
+                                      });
         });
   }
 
diff --git a/host/commands/cvd/server_command/host_tool_target.cpp b/host/commands/cvd/server_command/host_tool_target.cpp
index 91fb3de..8afc317 100644
--- a/host/commands/cvd/server_command/host_tool_target.cpp
+++ b/host/commands/cvd/server_command/host_tool_target.cpp
@@ -41,6 +41,7 @@
       {"powerwash", {"powerwash_cvd"}},
       {"suspend", {"snapshot_util_cvd"}},
       {"resume", {"snapshot_util_cvd"}},
+      {"snapshot_take", {"snapshot_util_cvd"}},
   };
   return map;
 }
diff --git a/host/commands/cvd/server_command/load_configs.cpp b/host/commands/cvd/server_command/load_configs.cpp
index b84e1b4..5d3821d 100644
--- a/host/commands/cvd/server_command/load_configs.cpp
+++ b/host/commands/cvd/server_command/load_configs.cpp
@@ -15,15 +15,12 @@
  */
 #include "host/commands/cvd/server_command/load_configs.h"
 
-#include <chrono>
 #include <iostream>
 #include <mutex>
-#include <optional>
 #include <sstream>
 #include <string>
 #include <vector>
 
-#include <android-base/parseint.h>
 #include <android-base/strings.h>
 #include <fruit/fruit.h>
 #include <json/json.h>
@@ -33,8 +30,6 @@
 #include "common/libs/utils/result.h"
 #include "host/commands/cvd/command_sequence.h"
 #include "host/commands/cvd/common_utils.h"
-#include "host/commands/cvd/parser/cf_configs_common.h"
-#include "host/commands/cvd/parser/fetch_cvd_parser.h"
 #include "host/commands/cvd/parser/load_configs_parser.h"
 #include "host/commands/cvd/selector/selector_constants.h"
 #include "host/commands/cvd/server_client.h"
@@ -42,131 +37,6 @@
 #include "host/commands/cvd/types.h"
 
 namespace cuttlefish {
-namespace {
-
-std::string JoinBySelector(
-    const std::vector<FetchCvdInstanceConfig>& collection,
-    const std::function<std::string(const FetchCvdInstanceConfig&)>& selector) {
-  std::vector<std::string> selected;
-  selected.reserve(collection.size());
-  for (const auto& instance : collection) {
-    selected.emplace_back(selector(instance));
-  }
-  return android::base::Join(selected, ',');
-}
-
-std::optional<std::string> JoinBySelectorOptional(
-    const std::vector<FetchCvdInstanceConfig>& collection,
-    const std::function<std::string(const FetchCvdInstanceConfig&)>& selector) {
-  std::string result = JoinBySelector(collection, selector);
-  // no values, empty or only ',' separators
-  if (result.size() == collection.size() - 1) {
-    return std::nullopt;
-  }
-  return result;
-}
-
-std::string GenerateSystemImageFlag(const FetchCvdConfig& config) {
-  auto get_full_path = [&target_directory = config.target_directory](
-                           const FetchCvdInstanceConfig& instance_config) {
-    return target_directory + "/" + instance_config.target_subdirectory;
-  };
-  return "--system_image_dir=" +
-         JoinBySelector(config.instances, get_full_path);
-}
-
-std::string GenerateParentDirectory() {
-  const uid_t uid = getuid();
-  // Prefix for the parent directory.
-  constexpr char kParentDirPrefix[] = "/tmp/cvd/";
-  std::stringstream ss;
-
-  // Constructs the full directory path.
-  ss << kParentDirPrefix << uid << "/";
-
-  return ss.str();
-}
-
-std::string GenerateHostArtifactsDirectory(int64_t time) {
-  return GenerateParentDirectory() + std::to_string(time);
-}
-
-std::string GenerateHomeDirectoryName(int64_t time) {
-  return GenerateParentDirectory() + std::to_string(time) + "_home/";
-}
-
-using DemoCommandSequence = std::vector<RequestWithStdio>;
-
-void AddFetchCommandArgs(
-    cvd::CommandRequest& command, const FetchCvdConfig& config,
-    const std::vector<FetchCvdInstanceConfig>& fetch_instances) {
-  command.add_args("cvd");
-  command.add_args("fetch");
-  command.add_args("--target_directory=" + config.target_directory);
-  if (config.api_key) {
-    command.add_args("--api_key=" + *config.api_key);
-  }
-  if (config.credential_source) {
-    command.add_args("--credential_source=" + *config.credential_source);
-  }
-  if (config.wait_retry_period) {
-    command.add_args("--wait_retry_period=" + *config.wait_retry_period);
-  }
-  if (config.external_dns_resolver) {
-    command.add_args("--external_dns_resolver=" +
-                     *config.external_dns_resolver);
-  }
-  if (config.keep_downloaded_archives) {
-    command.add_args("--keep_downloaded_archives=" +
-                     *config.keep_downloaded_archives);
-  }
-
-  command.add_args(
-      "--target_subdirectory=" +
-      JoinBySelector(fetch_instances,
-                     [](const FetchCvdInstanceConfig& instance_config) {
-                       return instance_config.target_subdirectory;
-                     }));
-  std::optional<std::string> default_build_params = JoinBySelectorOptional(
-      fetch_instances, [](const FetchCvdInstanceConfig& instance_config) {
-        return instance_config.default_build.value_or("");
-      });
-  if (default_build_params) {
-    command.add_args("--default_build=" + *default_build_params);
-  }
-  std::optional<std::string> system_build_params = JoinBySelectorOptional(
-      fetch_instances, [](const FetchCvdInstanceConfig& instance_config) {
-        return instance_config.system_build.value_or("");
-      });
-  if (system_build_params) {
-    command.add_args("--system_build=" + *system_build_params);
-  }
-  std::optional<std::string> kernel_build_params = JoinBySelectorOptional(
-      fetch_instances, [](const FetchCvdInstanceConfig& instance_config) {
-        return instance_config.kernel_build.value_or("");
-      });
-  if (kernel_build_params) {
-    command.add_args("--kernel_build=" + *kernel_build_params);
-  }
-  std::optional<std::string> download_img_zip_params = JoinBySelectorOptional(
-      fetch_instances, [](const FetchCvdInstanceConfig& instance_config) {
-        return instance_config.download_img_zip.value_or("");
-      });
-  if (download_img_zip_params) {
-    command.add_args("--download_img_zip=" + *download_img_zip_params);
-  }
-  std::optional<std::string> download_target_files_zip_params =
-      JoinBySelectorOptional(
-          fetch_instances, [](const FetchCvdInstanceConfig& instance_config) {
-            return instance_config.download_target_files_zip.value_or("");
-          });
-  if (download_target_files_zip_params) {
-    command.add_args("--download_target_files_zip=" +
-                     *download_target_files_zip_params);
-  }
-}
-
-}  // namespace
 
 class LoadConfigsCommand : public CvdServerHandler {
  public:
@@ -192,6 +62,7 @@
     response.mutable_command_response();
     return response;
   }
+
   Result<void> Interrupt() override {
     std::scoped_lock interrupt_lock(interrupt_mutex_);
     interrupted_ = true;
@@ -201,119 +72,7 @@
 
   cvd_common::Args CmdList() const override { return {kLoadSubCmd}; }
 
-  // TODO(moelsherif): expand this enum in the future to support more types ( double , float
-  // , etc) if neeeded
-  enum ArgValueType { UINTEGER, BOOLEAN, TEXT };
-
-  bool IsUnsignedInteger(const std::string& str) {
-    return !str.empty() && std::all_of(str.begin(), str.end(),
-                                       [](char c) { return std::isdigit(c); });
-  }
-
-  ArgValueType GetArgValueType(const std::string& str) {
-    if (IsUnsignedInteger(str)) {
-      return UINTEGER;
-    }
-
-    if (str == "true" || str == "false") {
-      return BOOLEAN;
-    }
-
-    // Otherwise, treat the string as text
-    return TEXT;
-  }
-
-  Json::Value ConvertArgToJson(const std::string& key,
-                               const std::string& leafValue) {
-    std::stack<std::string> levels;
-    std::stringstream ks(key);
-    std::string token;
-    while (std::getline(ks, token, '.')) {
-      levels.push(token);
-    }
-
-    // assign the leaf value based on the type of input value
-    Json::Value leaf;
-    if (GetArgValueType(leafValue) == UINTEGER) {
-      std::uint32_t leaf_val{};
-      if (!android::base::ParseUint(leafValue ,&leaf_val)){
-        LOG(ERROR) << "Failed to parse unsigned integer " << leafValue;
-        return Json::Value::null;
-      };
-      leaf = leaf_val;
-    } else if (GetArgValueType(leafValue) == BOOLEAN) {
-      leaf = (leafValue == "true");
-    } else {
-      leaf = leafValue;
-    }
-
-    while (!levels.empty()) {
-      Json::Value curr;
-      std::string index = levels.top();
-
-      if (GetArgValueType(index) == UINTEGER) {
-        std::uint32_t index_val{};
-        if (!android::base::ParseUint(index, &index_val)){
-          LOG(ERROR) << "Failed to parse unsigned integer " << index;
-          return Json::Value::null;
-        }
-        curr[index_val] = leaf;
-      } else {
-        curr[index] = leaf;
-      }
-
-      leaf = curr;
-      levels.pop();
-    }
-
-    return leaf;
-  }
-
-  Json::Value ParseArgsToJson(const std::vector<std::string>& strings) {
-    Json::Value jsonValue;
-    for (const auto& str : strings) {
-      std::string key;
-      std::string value;
-      size_t equals_pos = str.find('=');
-      if (equals_pos != std::string::npos) {
-        key = str.substr(0, equals_pos);
-        value = str.substr(equals_pos + 1);
-      } else {
-        key = str;
-        value.clear();
-        LOG(WARNING) << "No value provided for key " << key;
-        return Json::Value::null;
-      }
-      MergeTwoJsonObjs(jsonValue, ConvertArgToJson(key, value));
-    }
-
-    return jsonValue;
-  }
-
-  Result<void> ValidateArgFormat(const std::string& str) {
-    auto equalsPos = str.find('=');
-    CF_EXPECT(equalsPos != std::string::npos,
-              "equal value is not provided in the argument");
-    std::string prefix = str.substr(0, equalsPos);
-    CF_EXPECT(!prefix.empty(), "argument value should not be empty");
-    CF_EXPECT(prefix.find('.') != std::string::npos,
-              "argument value must be dot separated");
-    CF_EXPECT(prefix[0] != '.', "argument value should not start with a dot");
-    CF_EXPECT(prefix.find("..") == std::string::npos,
-              "argument value should not contain two consecutive dots");
-    CF_EXPECT(prefix.back() != '.', "argument value should not end with a dot");
-    return {};
-  }
-
-  Result<void> ValidateArgsFormat(const std::vector<std::string>& strings) {
-    for (const auto& str : strings) {
-      CF_EXPECT(ValidateArgFormat(str),
-                "Invalid  argument format. " << str << " Please use arg=value");
-    }
-    return {};
-  }
-
-  Result<DemoCommandSequence> CreateCommandSequence(
+  Result<std::vector<RequestWithStdio>> CreateCommandSequence(
       const RequestWithStdio& request) {
     bool help = false;
 
@@ -321,10 +80,10 @@
     flags.emplace_back(GflagsCompatFlag("help", help));
     std::vector<std::string> overrides;
     FlagAlias alias = {FlagAliasMode::kFlagPrefix, "--override="};
-    flags.emplace_back(
-        Flag().Alias(alias).Setter([&overrides](const FlagMatch& m) {
+    flags.emplace_back(Flag().Alias(alias).Setter(
+        [&overrides](const FlagMatch& m) -> Result<void> {
           overrides.push_back(m.value);
-          return true;
+          return {};
         }));
     auto args = ParseInvocation(request.Message()).arguments;
     CF_EXPECT(ParseFlags(flags, args));
@@ -340,82 +99,46 @@
       return {};
     }
 
-    // Extract the config_path from the arguments
     std::string config_path = args.front();
-    Json::Value json_configs =
-        CF_EXPECT(ParseJsonFile(config_path), "parsing input file failed");
-
-    // remove the config_path from the arguments
-    args.erase(args.begin());
-
-    // Handle the rest of the arguments (Overrides)
-    if (overrides.size() > 0) {
-      // Validate all arguments follow specific pattern
-      CF_EXPECT(ValidateArgsFormat(overrides),
-                "override parameters are not in the correct format");
-
-      // Convert all arguments to json tree
-      auto args_tree = ParseArgsToJson(overrides);
-      MergeTwoJsonObjs(json_configs, args_tree);
+    if (config_path[0] != '/') {
+      config_path = request.Message().command_request().working_directory() +
+                    "/" + config_path;
     }
-
-    auto cvd_flags =
-        CF_EXPECT(ParseCvdConfigs(json_configs), "parsing json configs failed");
-
-    int num_instances = cvd_flags.fetch_cvd_flags.instances.size();
-    CF_EXPECT_GT(num_instances, 0, "No instances to load");
-
+    Json::Value json_configs =
+        CF_EXPECT(GetOverridedJsonConfig(config_path, overrides));
+    const auto load_directories =
+        CF_EXPECT(GenerateLoadDirectories(json_configs["instances"].size()));
+    auto cvd_flags = CF_EXPECT(ParseCvdConfigs(json_configs, load_directories),
+                               "parsing json configs failed");
     std::vector<cvd::Request> req_protos;
-
     const auto& client_env = request.Message().command_request().env();
 
-    auto time = std::chrono::system_clock::now().time_since_epoch().count();
-    cvd_flags.fetch_cvd_flags.target_directory =
-        GenerateHostArtifactsDirectory(time);
-    for (int instance_index = 0; instance_index < num_instances;
-         instance_index++) {
-      LOG(INFO) << "Instance " << instance_index << " directory is "
-                << cvd_flags.fetch_cvd_flags.target_directory << "/"
-                << std::to_string(instance_index);
-      cvd_flags.fetch_cvd_flags.instances[instance_index].target_subdirectory =
-          std::to_string(instance_index);
-    }
-
-    std::vector<FetchCvdInstanceConfig> fetch_instances;
-    for (const auto& instance : cvd_flags.fetch_cvd_flags.instances) {
-      if (instance.should_fetch) {
-        fetch_instances.emplace_back(instance);
-      }
-    }
-    if (fetch_instances.size() > 0) {
+    if (!cvd_flags.fetch_cvd_flags.empty()) {
       auto& fetch_cmd = *req_protos.emplace_back().mutable_command_request();
       *fetch_cmd.mutable_env() = client_env;
-      AddFetchCommandArgs(fetch_cmd, cvd_flags.fetch_cvd_flags,
-                          fetch_instances);
+      fetch_cmd.add_args("cvd");
+      fetch_cmd.add_args("fetch");
+      for (const auto& flag : cvd_flags.fetch_cvd_flags) {
+        fetch_cmd.add_args(flag);
+      }
     }
 
-    // Create the launch home directory
-    std::string launch_home_dir = GenerateHomeDirectoryName(time);
     auto& mkdir_cmd = *req_protos.emplace_back().mutable_command_request();
     *mkdir_cmd.mutable_env() = client_env;
     mkdir_cmd.add_args("cvd");
     mkdir_cmd.add_args("mkdir");
     mkdir_cmd.add_args("-p");
-    mkdir_cmd.add_args(launch_home_dir);
+    mkdir_cmd.add_args(load_directories.launch_home_directory);
 
-    // Handle the launch command
     auto& launch_cmd = *req_protos.emplace_back().mutable_command_request();
-
-    auto first_instance_dir =
-        cvd_flags.fetch_cvd_flags.target_directory + "/" +
-        cvd_flags.fetch_cvd_flags.instances[0].target_subdirectory;
+    launch_cmd.set_working_directory(load_directories.first_instance_directory);
     *launch_cmd.mutable_env() = client_env;
-    launch_cmd.set_working_directory(first_instance_dir);
-    (*launch_cmd.mutable_env())["HOME"] = launch_home_dir;
-
-    (*launch_cmd.mutable_env())[kAndroidHostOut] = first_instance_dir;
-    (*launch_cmd.mutable_env())[kAndroidSoongHostOut] = first_instance_dir;
-
+    (*launch_cmd.mutable_env())["HOME"] =
+        load_directories.launch_home_directory;
+    (*launch_cmd.mutable_env())[kAndroidHostOut] =
+        load_directories.first_instance_directory;
+    (*launch_cmd.mutable_env())[kAndroidSoongHostOut] =
+        load_directories.first_instance_directory;
     if (Contains(*launch_cmd.mutable_env(), kAndroidProductOut)) {
       (*launch_cmd.mutable_env()).erase(kAndroidProductOut);
     }
@@ -427,11 +150,11 @@
     launch_cmd.add_args("cvd");
     launch_cmd.add_args("start");
     launch_cmd.add_args("--daemon");
-    for (auto& parsed_flag : cvd_flags.launch_cvd_flags) {
+    for (const auto& parsed_flag : cvd_flags.launch_cvd_flags) {
       launch_cmd.add_args(parsed_flag);
     }
     // Add system flag for multi-build scenario
-    launch_cmd.add_args(GenerateSystemImageFlag(cvd_flags.fetch_cvd_flags));
+    launch_cmd.add_args(load_directories.system_image_directory_flag);
 
     launch_cmd.mutable_selector_opts()->add_args(
         std::string("--") + selector::SelectorFlags::kDisableDefaultGroup);
@@ -440,7 +163,7 @@
     auto dev_null = SharedFD::Open("/dev/null", O_RDWR);
     CF_EXPECT(dev_null->IsOpen(), dev_null->StrError());
     std::vector<SharedFD> fds = {dev_null, dev_null, dev_null};
-    DemoCommandSequence ret;
+    std::vector<RequestWithStdio> ret;
 
     for (auto& request_proto : req_protos) {
       ret.emplace_back(RequestWithStdio(request.Client(), request_proto, fds,
diff --git a/host/commands/cvd/server_command/serial_launch.cpp b/host/commands/cvd/server_command/serial_launch.cpp
index 65cd527..b78a5a7 100644
--- a/host/commands/cvd/server_command/serial_launch.cpp
+++ b/host/commands/cvd/server_command/serial_launch.cpp
@@ -69,34 +69,31 @@
 
 /** Returns a `Flag` object that accepts comma-separated unsigned integers. */
 template <typename T>
-Flag DeviceSpecificUintFlag(const std::string& name, std::vector<T>& values,
-                            const RequestWithStdio& request) {
+Flag DeviceSpecificUintFlag(const std::string& name, std::vector<T>& values) {
   return GflagsCompatFlag(name).Setter(
-      [&request, &values](const FlagMatch& match) {
+      [&values](const FlagMatch& match) -> Result<void> {
         auto parsed_values = android::base::Tokenize(match.value, ", ");
         for (auto& parsed_value : parsed_values) {
           std::uint32_t num = 0;
-          if (!android::base::ParseUint(parsed_value, &num)) {
-            constexpr char kError[] = "Failed to parse integer";
-            WriteAll(request.Out(), kError, sizeof(kError));
-            return false;
-          }
+          CF_EXPECTF(android::base::ParseUint(parsed_value, &num),
+                     "Failed to parse {} as an integer", parsed_value);
           values.push_back(num);
         }
-        return true;
+        return {};
       });
 }
 
 /** Returns a `Flag` object that accepts comma-separated strings. */
 Flag DeviceSpecificStringFlag(const std::string& name,
                               std::vector<std::string>& values) {
-  return GflagsCompatFlag(name).Setter([&values](const FlagMatch& match) {
-    auto parsed_values = android::base::Tokenize(match.value, ", ");
-    for (auto& parsed_value : parsed_values) {
-      values.push_back(parsed_value);
-    }
-    return true;
-  });
+  return GflagsCompatFlag(name).Setter(
+      [&values](const FlagMatch& match) -> Result<void> {
+        auto parsed_values = android::base::Tokenize(match.value, ", ");
+        for (auto& parsed_value : parsed_values) {
+          values.push_back(parsed_value);
+        }
+        return {};
+      });
 }
 
 std::string ParentDir(const uid_t uid) {
@@ -167,19 +164,19 @@
     flags.emplace_back(GflagsCompatFlag("verbose", verbose));
 
     std::vector<std::uint32_t> x_res;
-    flags.emplace_back(DeviceSpecificUintFlag("x_res", x_res, request));
+    flags.emplace_back(DeviceSpecificUintFlag("x_res", x_res));
 
     std::vector<std::uint32_t> y_res;
-    flags.emplace_back(DeviceSpecificUintFlag("y_res", y_res, request));
+    flags.emplace_back(DeviceSpecificUintFlag("y_res", y_res));
 
     std::vector<std::uint32_t> dpi;
-    flags.emplace_back(DeviceSpecificUintFlag("dpi", dpi, request));
+    flags.emplace_back(DeviceSpecificUintFlag("dpi", dpi));
 
     std::vector<std::uint32_t> cpus;
-    flags.emplace_back(DeviceSpecificUintFlag("cpus", cpus, request));
+    flags.emplace_back(DeviceSpecificUintFlag("cpus", cpus));
 
     std::vector<std::uint32_t> memory_mb;
-    flags.emplace_back(DeviceSpecificUintFlag("memory_mb", memory_mb, request));
+    flags.emplace_back(DeviceSpecificUintFlag("memory_mb", memory_mb));
 
     std::vector<std::string> setupwizard_mode;
     flags.emplace_back(
@@ -207,27 +204,20 @@
     auto& device_flag = flags.emplace_back();
     device_flag.Alias({FlagAliasMode::kFlagPrefix, "--device="});
     device_flag.Alias({FlagAliasMode::kFlagConsumesFollowing, "--device"});
-    device_flag.Setter(
-        [this, time, client_uid, &devices, &request](const FlagMatch& mat) {
-          auto lock = lock_file_manager_.TryAcquireUnusedLock();
-          if (!lock.ok()) {
-            WriteAll(request.Err(), lock.error().Message());
-            return false;
-          } else if (!lock->has_value()) {
-            constexpr char kError[] = "could not acquire instance lock";
-            WriteAll(request.Err(), kError, sizeof(kError));
-            return false;
-          }
-          int num = (*lock)->Instance();
-          std::string home_dir = ParentDir(client_uid) + std::to_string(time) +
-                                 "_" + std::to_string(num) + "/";
-          devices.emplace_back(Device{
-              .build = mat.value,
-              .home_dir = std::move(home_dir),
-              .ins_lock = std::move(**lock),
-          });
-          return true;
-        });
+    device_flag.Setter([this, time, client_uid,
+                        &devices](const FlagMatch& mat) -> Result<void> {
+      auto lock = CF_EXPECT(lock_file_manager_.TryAcquireUnusedLock());
+      CF_EXPECT(lock.has_value(), "could not acquire instance lock");
+      int num = lock->Instance();
+      std::string home_dir = ParentDir(client_uid) + std::to_string(time) +
+                             "_" + std::to_string(num) + "/";
+      devices.emplace_back(Device{
+          .build = mat.value,
+          .home_dir = std::move(home_dir),
+          .ins_lock = std::move(*lock),
+      });
+      return {};
+    });
 
     auto args = ParseInvocation(request.Message()).arguments;
     for (const auto& arg : args) {
diff --git a/host/commands/cvd/server_command/suspend_resume.cpp b/host/commands/cvd/server_command/snapshot.cpp
similarity index 73%
rename from host/commands/cvd/server_command/suspend_resume.cpp
rename to host/commands/cvd/server_command/snapshot.cpp
index 3856561..9470923 100644
--- a/host/commands/cvd/server_command/suspend_resume.cpp
+++ b/host/commands/cvd/server_command/snapshot.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "host/commands/cvd/server_command/suspend_resume.h"
+#include "host/commands/cvd/server_command/snapshot.h"
 
 #include <android-base/file.h>
 #include <android-base/strings.h>
@@ -41,17 +41,17 @@
 
 namespace cuttlefish {
 
-static constexpr char kSuspendResume[] =
+static constexpr char kSnapshot[] =
     R"(Cuttlefish Virtual Device (CVD) CLI.
 
-Suspend/resume the cuttlefish device
+Suspend/resume the cuttlefish device, or take snapshot of the device
 
-usage: cvd [selector flags] suspend/resume [--help]
+usage: cvd [selector flags] suspend/resume/snapshot_take [--help]
 
 Common:
   Selector Flags:
     --group_name=<name>       The name of the instance group
-    --instance_name=<names>   The comma-separated list of the instance names
+    --snapshot_path=<path>>   Directory that contains saved snapshot files
 
   Args:
     --help                    print this message
@@ -64,19 +64,19 @@
 
 )";
 
-class CvdSuspendResumeCommandHandler : public CvdServerHandler {
+class CvdSnapshotCommandHandler : public CvdServerHandler {
  public:
-  INJECT(CvdSuspendResumeCommandHandler(
+  INJECT(CvdSnapshotCommandHandler(
       InstanceManager& instance_manager, SubprocessWaiter& subprocess_waiter,
       HostToolTargetManager& host_tool_target_manager))
       : instance_manager_{instance_manager},
         subprocess_waiter_(subprocess_waiter),
         host_tool_target_manager_(host_tool_target_manager),
-        cvd_suspend_resume_operations_{"suspend", "resume"} {}
+        cvd_snapshot_operations_{"suspend", "resume", "snapshot_take"} {}
 
   Result<bool> CanHandle(const RequestWithStdio& request) const {
     auto invocation = ParseInvocation(request.Message());
-    return Contains(cvd_suspend_resume_operations_, invocation.command);
+    return Contains(cvd_snapshot_operations_, invocation.command);
   }
 
   Result<cvd::Response> Handle(const RequestWithStdio& request) override {
@@ -125,13 +125,13 @@
   }
 
   cvd_common::Args CmdList() const override {
-    return cvd_common::Args(cvd_suspend_resume_operations_.begin(),
-                            cvd_suspend_resume_operations_.end());
+    return cvd_common::Args(cvd_snapshot_operations_.begin(),
+                            cvd_snapshot_operations_.end());
   }
 
  private:
   Result<cvd::Response> HandleHelp(const SharedFD& client_stderr) {
-    std::string help_message(kSuspendResume);
+    std::string help_message(kSnapshot);
     help_message.append("\n");
     CF_EXPECT(WriteAll(client_stderr, help_message) == help_message.size(),
               "Failed to write the help message");
@@ -145,32 +145,23 @@
                                  const uid_t uid, const std::string& subcmd,
                                  cvd_common::Args& subcmd_args,
                                  cvd_common::Envs envs) {
-    // test if there is --instance_num flag
-    CvdFlag<std::int32_t> instance_num_flag("instance_num");
-    auto instance_num_opt =
-        CF_EXPECT(instance_num_flag.FilterFlag(subcmd_args));
-    selector::Queries extra_queries;
-    if (instance_num_opt) {
-      extra_queries.emplace_back(selector::kInstanceIdField, *instance_num_opt);
-    }
-
     const auto& selector_opts =
         request.Message().command_request().selector_opts();
     const auto selector_args = cvd_common::ConvertToArgs(selector_opts.args());
 
-    auto instance = CF_EXPECT(instance_manager_.SelectInstance(
-        selector_args, extra_queries, envs, uid));
-    const auto& instance_group = instance.ParentGroup();
-    const auto& home = instance_group.HomeDir();
+    // create a string that is comma-separated instance IDs
+    auto instance_group =
+        CF_EXPECT(instance_manager_.SelectGroup(selector_args, envs, uid));
 
+    const auto& home = instance_group.HomeDir();
     const auto& android_host_out = instance_group.HostArtifactsPath();
-    auto cvd_suspend_resume_bin_path =
-        CF_EXPECT(GetBin(android_host_out, subcmd));
-    cvd_common::Args cvd_suspend_resume_args{"--subcmd=" + subcmd};
-    cvd_suspend_resume_args.insert(cvd_suspend_resume_args.end(),
-                                   subcmd_args.begin(), subcmd_args.end());
-    cvd_suspend_resume_args.push_back(
-        ConcatToString("--instance_num=", instance.InstanceId()));
+    auto cvd_snapshot_bin_path = CF_EXPECT(GetBin(android_host_out, subcmd));
+    const std::string& snapshot_util_cmd = subcmd;
+    cvd_common::Args cvd_snapshot_args{"--subcmd=" + snapshot_util_cmd};
+    cvd_snapshot_args.insert(cvd_snapshot_args.end(), subcmd_args.begin(),
+                             subcmd_args.end());
+    // This helps snapshot_util find CuttlefishConfig and figure out
+    // the instance ids
     envs["HOME"] = home;
     envs[kAndroidHostOut] = android_host_out;
     envs[kAndroidSoongHostOut] = android_host_out;
@@ -178,20 +169,19 @@
     std::stringstream command_to_issue;
     command_to_issue << "HOME=" << home << " " << kAndroidHostOut << "="
                      << android_host_out << " " << kAndroidSoongHostOut << "="
-                     << android_host_out << " " << cvd_suspend_resume_bin_path
-                     << " ";
-    for (const auto& arg : cvd_suspend_resume_args) {
+                     << android_host_out << " " << cvd_snapshot_bin_path << " ";
+    for (const auto& arg : cvd_snapshot_args) {
       command_to_issue << arg << " ";
     }
     WriteAll(request.Err(), command_to_issue.str());
 
     ConstructCommandParam construct_cmd_param{
-        .bin_path = cvd_suspend_resume_bin_path,
+        .bin_path = cvd_snapshot_bin_path,
         .home = home,
-        .args = cvd_suspend_resume_args,
+        .args = cvd_snapshot_args,
         .envs = envs,
         .working_dir = request.Message().command_request().working_directory(),
-        .command_name = android::base::Basename(cvd_suspend_resume_bin_path),
+        .command_name = android::base::Basename(cvd_snapshot_bin_path),
         .in = request.In(),
         .out = request.Out(),
         .err = request.Err()};
@@ -208,11 +198,11 @@
 
   Result<std::string> GetBin(const std::string& host_artifacts_path,
                              const std::string& op) const {
-    auto suspend_resume_bin = CF_EXPECT(host_tool_target_manager_.ExecBaseName({
+    auto snapshot_bin = CF_EXPECT(host_tool_target_manager_.ExecBaseName({
         .artifacts_path = host_artifacts_path,
         .op = op,
     }));
-    return suspend_resume_bin;
+    return snapshot_bin;
   }
 
   InstanceManager& instance_manager_;
@@ -220,14 +210,14 @@
   HostToolTargetManager& host_tool_target_manager_;
   std::mutex interruptible_;
   bool interrupted_ = false;
-  std::vector<std::string> cvd_suspend_resume_operations_;
+  std::vector<std::string> cvd_snapshot_operations_;
 };
 
 fruit::Component<
     fruit::Required<InstanceManager, SubprocessWaiter, HostToolTargetManager>>
-CvdSuspendResumeComponent() {
+CvdSnapshotComponent() {
   return fruit::createComponent()
-      .addMultibinding<CvdServerHandler, CvdSuspendResumeCommandHandler>();
+      .addMultibinding<CvdServerHandler, CvdSnapshotCommandHandler>();
 }
 
 }  // namespace cuttlefish
diff --git a/host/commands/cvd/server_command/suspend_resume.h b/host/commands/cvd/server_command/snapshot.h
similarity index 96%
rename from host/commands/cvd/server_command/suspend_resume.h
rename to host/commands/cvd/server_command/snapshot.h
index f0f6168..b72a8fd 100644
--- a/host/commands/cvd/server_command/suspend_resume.h
+++ b/host/commands/cvd/server_command/snapshot.h
@@ -26,6 +26,6 @@
 
 fruit::Component<
     fruit::Required<InstanceManager, SubprocessWaiter, HostToolTargetManager>>
-CvdSuspendResumeComponent();
+CvdSnapshotComponent();
 
 }  // namespace cuttlefish
diff --git a/host/commands/cvd/server_command/vm_control.cpp b/host/commands/cvd/server_command/vm_control.cpp
deleted file mode 100644
index dc8ee58..0000000
--- a/host/commands/cvd/server_command/vm_control.cpp
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Copyright (C) 2023 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 "host/commands/cvd/server_command/vm_control.h"
-
-#include <android-base/strings.h>
-
-#include <future>
-#include <iostream>
-#include <mutex>
-#include <optional>
-#include <sstream>
-#include <string>
-#include <thread>
-#include <vector>
-
-#include "common/libs/fs/shared_buf.h"
-#include "common/libs/utils/contains.h"
-#include "common/libs/utils/files.h"
-#include "common/libs/utils/subprocess.h"
-#include "host/commands/cvd/flag.h"
-#include "host/commands/cvd/selector/instance_group_record.h"
-#include "host/commands/cvd/selector/instance_record.h"
-#include "host/commands/cvd/selector/selector_constants.h"
-#include "host/commands/cvd/server_command/server_handler.h"
-#include "host/commands/cvd/server_command/subprocess_waiter.h"
-#include "host/commands/cvd/server_command/utils.h"
-#include "host/commands/cvd/types.h"
-#include "host/libs/config/cuttlefish_config.h"
-
-namespace cuttlefish {
-
-static constexpr char kSnapshot[] =
-    R"(Cuttlefish Virtual Device (CVD) CLI.
-
-Take a snapshot of a cuttlefish device or
-Create/restore a cuttlefish device from a snapshot
-
-usage: cvd [selector flags] snapshot take/restore <snapshot path> [vm args]
-       cvd snapshot take/restore --help
-
-Common:
-
-  Selector Flags:
-    --group_name=<name>       The name of the instance group
-    --instance_name=<names>   The comma-separated list of the instance names
-
-  Commands:
-    take                      Take the snapshot to the <snapshot path>
-    restore                   Restore the device from <snapshot path>
-
-  Args:
-    --help                    print this message
-
-Crosvm:
-  <snapshot path>:
-    Path to the snapshot file
-
-QEMU:
-  No QEMU-specific vm arguments yet
-)";
-
-class CvdVmControlCommandHandler : public CvdServerHandler {
- public:
-  INJECT(CvdVmControlCommandHandler(InstanceManager& instance_manager))
-      : instance_manager_{instance_manager},
-        vm_operations_{{"snapshot", kSnapshot}} {}
-
-  Result<bool> CanHandle(const RequestWithStdio& request) const {
-    auto invocation = ParseInvocation(request.Message());
-    return Contains(vm_operations_, invocation.command);
-  }
-
-  Result<cvd::Response> Handle(const RequestWithStdio& request) override {
-    std::unique_lock interrupt_lock(interruptible_);
-    CF_EXPECT(!interrupted_, "Interrupted");
-    CF_EXPECT(CanHandle(request));
-    CF_EXPECT(VerifyPrecondition(request));
-    const uid_t uid = request.Credentials()->uid;
-    cvd_common::Envs envs =
-        cvd_common::ConvertToEnvs(request.Message().command_request().env());
-
-    auto [vm_op, subcmd_args] = ParseInvocation(request.Message());
-    /*
-     * crosvm suspend/resume/snapshot support --help only. Not --helpxml, etc.
-     *
-     * Otherwise, IsHelpSubcmd() should be used here instead.
-     */
-    auto help_flag = CvdFlag("help", false);
-    cvd_common::Args subcmd_args_copy{subcmd_args};
-    auto help_parse_result = help_flag.CalculateFlag(subcmd_args_copy);
-    bool is_help = help_parse_result.ok() && (*help_parse_result);
-
-    if (is_help) {
-      auto help_response = CF_EXPECT(HandleHelp(request.Err(), vm_op));
-      return help_response;
-    }
-
-    /*
-     * TODO(kwstephenkim): Support QEMU
-     *
-     * We should add a field that indicates the vm type in the instance
-     * database. Then, we should check the field here to set/unset is_crosvm.
-     */
-    const bool is_crosvm = true;
-    CF_EXPECT(is_crosvm == true, "QEMU is not yet supported");
-
-    auto commands =
-        CF_EXPECT(CrosvmCommand(request, uid, vm_op, subcmd_args, envs));
-    subprocess_waiters_ = std::vector<SubprocessWaiter>(commands.size());
-
-    interrupt_lock.unlock();
-    return CF_EXPECT(ConstructResponse(std::move(commands)));
-  }
-
-  Result<void> Interrupt() override {
-    std::scoped_lock interrupt_lock(interruptible_);
-    interrupted_ = true;
-    for (auto& subprocess_waiter : subprocess_waiters_) {
-      CF_EXPECT(subprocess_waiter.Interrupt());
-    }
-    return {};
-  }
-
-  cvd_common::Args CmdList() const override {
-    cvd_common::Args cmd_list;
-    cmd_list.reserve(vm_operations_.size());
-    for (const auto& [op, _] : vm_operations_) {
-      cmd_list.push_back(op);
-    }
-    return cmd_list;
-  }
-
- private:
-  Result<cvd::Response> ConstructResponse(std::vector<Command> commands) {
-    std::vector<std::future<Result<siginfo_t>>> infop_futures;
-    infop_futures.reserve(commands.size());
-    auto worker = [this](const int idx, Command command) -> Result<siginfo_t> {
-      std::unique_lock interrupt_lock(interruptible_);
-      CF_EXPECT(!interrupted_, "Interrupted");
-      SubprocessOptions options;
-      auto& subprocess_waiter = subprocess_waiters_[idx];
-      CF_EXPECT(subprocess_waiter.Setup(command.Start(options)));
-      interrupt_lock.unlock();
-      return CF_EXPECT(subprocess_waiter.Wait());
-    };
-    size_t idx = 0;
-    for (auto& command : commands) {
-      std::future<Result<siginfo_t>> infop_future =
-          std::async(std::launch::async, worker, idx, std::move(command));
-      infop_futures.push_back(std::move(infop_future));
-      idx++;
-    }
-    commands.clear();
-
-    bool ok = true;
-    std::stringstream error_msg;
-    for (auto& infop_future : infop_futures) {
-      auto infop = std::move(infop_future.get());
-      if (!infop.ok()) {
-        LOG(ERROR) << infop.error().Trace();
-        ok = false;
-        continue;
-      }
-      if (infop->si_code == CLD_EXITED && infop->si_status == 0) {
-        continue;
-      }
-      // error
-      ok = false;
-      std::string status_code_str = std::to_string(infop->si_status);
-      if (infop->si_code == CLD_EXITED) {
-        error_msg << "Exited with code " << status_code_str << std::endl;
-      } else if (infop->si_code == CLD_KILLED) {
-        error_msg << "Exited with signal " << status_code_str << std::endl;
-      } else {
-        error_msg << "Quit with code " << status_code_str << std::endl;
-      }
-    }
-
-    cvd::Response response;
-    response.mutable_command_response();  // set oneof field
-    auto& status = *response.mutable_status();
-    if (ok) {
-      status.set_code(cvd::Status::OK);
-    } else {
-      status.set_code(cvd::Status::INTERNAL);
-      status.set_message(error_msg.str());
-    }
-    return response;
-  }
-
-  Result<cvd::Response> HandleHelp(const SharedFD& client_stderr,
-                                   const std::string& vm_op) {
-    CF_EXPECT(Contains(vm_operations_, vm_op));
-    std::string help_message = ConcatToString(vm_operations_.at(vm_op), "\n");
-    CF_EXPECT(WriteAll(client_stderr, help_message) == help_message.size(),
-              "Failed to write the help message");
-    cvd::Response response;
-    response.mutable_command_response();
-    response.mutable_status()->set_code(cvd::Status::OK);
-    return response;
-  }
-
-  Result<std::vector<Command>> CrosvmCommand(
-      const RequestWithStdio& request, const uid_t uid,
-      const std::string& crosvm_op, const cvd_common::Args& subcmd_args,
-      const cvd_common::Envs& envs) {
-    const auto& selector_opts =
-        request.Message().command_request().selector_opts();
-    const auto selector_args = cvd_common::ConvertToArgs(selector_opts.args());
-
-    if (CF_EXPECT(HasInstanceSpecificOption(selector_args, envs))) {
-      auto instance =
-          CF_EXPECT(instance_manager_.SelectInstance(selector_args, envs, uid));
-      return CF_EXPECT(CrosvmInstanceCommand(request, instance, crosvm_op,
-                                             subcmd_args, envs));
-    }
-    auto instance_group =
-        CF_EXPECT(instance_manager_.SelectGroup(selector_args, envs, uid));
-    return CF_EXPECT(CrosvmGroupCommand(request, instance_group, crosvm_op,
-                                        subcmd_args, envs));
-  }
-
-  Result<std::vector<Command>> CrosvmGroupCommand(
-      const RequestWithStdio& request,
-      const InstanceManager::LocalInstanceGroup& instance_group,
-      const std::string& crosvm_op, const cvd_common::Args& subcmd_args,
-      const cvd_common::Envs& envs) {
-    std::vector<Command> commands;
-    auto& instances = instance_group.Instances();
-    for (const auto& instance : instances) {
-      auto instance_commands = CF_EXPECT(CrosvmInstanceCommand(
-          request, instance->GetCopy(), crosvm_op, subcmd_args, envs));
-      CF_EXPECT_EQ(instance_commands.size(), 1);
-      commands.push_back(std::move(instance_commands.front()));
-    }
-    return commands;
-  }
-
-  Result<std::vector<Command>> CrosvmInstanceCommand(
-      const RequestWithStdio& request,
-      const InstanceManager::LocalInstance::Copy& instance,
-      const std::string& crosvm_op, const cvd_common::Args& subcmd_args,
-      const cvd_common::Envs& envs) {
-    const auto& instance_group = instance.ParentGroup();
-    const auto instance_id = instance.InstanceId();
-    const auto& internal_name = instance.InternalDeviceName();
-    auto home = instance_group.HomeDir();
-
-    // Use /tmp/cf_avd as crosvm_control.sock UDS path, if it does not exist,
-    // fallback to HOME directory(legacy).
-    const auto defaultPath =
-        ConcatToString("/tmp/cf_avd_", getuid(), "/", internal_name,
-                       "/internal/"
-                       "crosvm_control.sock");
-    const auto fallbackPath =
-        ConcatToString(home, "/cuttlefish_runtime.", instance_id,
-                       "/internal/"
-                       "crosvm_control.sock");
-
-    const auto socket_file_path =
-        FileExists(defaultPath) ? defaultPath : fallbackPath;
-
-    auto android_host_out = instance_group.HostArtifactsPath();
-    auto crosvm_bin_path = ConcatToString(android_host_out, "/bin/crosvm");
-
-    cvd_common::Args crosvm_args{crosvm_op};
-    crosvm_args.insert(crosvm_args.end(), subcmd_args.begin(),
-                       subcmd_args.end());
-    crosvm_args.push_back(socket_file_path);
-    Command non_help_command = CF_EXPECT(
-        ConstructCvdGenericNonHelpCommand({.bin_file = "crosvm",
-                                           .envs = envs,
-                                           .cmd_args = std::move(crosvm_args),
-                                           .android_host_out = android_host_out,
-                                           .home = home,
-                                           .verbose = true},
-                                          request));
-    std::vector<Command> non_help_command_in_vector;
-    non_help_command_in_vector.push_back(std::move(non_help_command));
-    return non_help_command_in_vector;
-  }
-
-  Result<bool> HasInstanceSpecificOption(cvd_common::Args selector_args,
-                                         const cvd_common::Envs& envs) const {
-    auto instance_name_flag = CF_EXPECT(selector::SelectorFlags::Get().GetFlag(
-        selector::SelectorFlags::kInstanceName));
-    std::optional<std::string> instance_name_opt =
-        CF_EXPECT(instance_name_flag.FilterFlag<std::string>(selector_args));
-    if (instance_name_opt) {
-      return true;
-    }
-    return Contains(envs, kCuttlefishInstanceEnvVarName);
-  }
-
-  InstanceManager& instance_manager_;
-  std::vector<SubprocessWaiter> subprocess_waiters_;
-  std::mutex interruptible_;
-  bool interrupted_ = false;
-  std::unordered_map<std::string, const char*> vm_operations_;
-};
-
-fruit::Component<fruit::Required<InstanceManager>> CvdVmControlComponent() {
-  return fruit::createComponent()
-      .addMultibinding<CvdServerHandler, CvdVmControlCommandHandler>();
-}
-
-}  // namespace cuttlefish
diff --git a/host/commands/cvd/server_command/vm_control.h b/host/commands/cvd/server_command/vm_control.h
deleted file mode 100644
index 3613189..0000000
--- a/host/commands/cvd/server_command/vm_control.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2023 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.
- */
-
-#pragma once
-
-#include <fruit/fruit.h>
-
-#include "host/commands/cvd/instance_manager.h"
-
-namespace cuttlefish {
-
-fruit::Component<fruit::Required<InstanceManager>> CvdVmControlComponent();
-
-}  // namespace cuttlefish
diff --git a/host/commands/cvd/unittests/parser/Android.bp b/host/commands/cvd/unittests/parser/Android.bp
index cead23e..f7566f2 100644
--- a/host/commands/cvd/unittests/parser/Android.bp
+++ b/host/commands/cvd/unittests/parser/Android.bp
@@ -41,10 +41,10 @@
         "configs_inheritance_test.cc",
         "fetch_cvd_parser_tests.cpp",
         "flags_parser_test.cc",
+        "metrics_configs_test.cc",
         "instance/vm_configs_test.cc",
         "instance/boot_configs_test.cc",
         "instance/disk_configs_test.cc",
-        "instance/metrics_configs_test.cc",
         "instance/graphics_configs_test.cc",
         "test_common.cc",
     ],
diff --git a/host/commands/cvd/unittests/parser/cf_configs_common_tests.cpp b/host/commands/cvd/unittests/parser/cf_configs_common_tests.cpp
index bb3a15f..c372e50 100644
--- a/host/commands/cvd/unittests/parser/cf_configs_common_tests.cpp
+++ b/host/commands/cvd/unittests/parser/cf_configs_common_tests.cpp
@@ -22,6 +22,7 @@
 #include <json/json.h>
 
 #include "common/libs/utils/result.h"
+#include "common/libs/utils/result_matchers.h"
 #include "host/commands/cvd/unittests/parser/test_common.h"
 
 namespace cuttlefish {
@@ -54,7 +55,8 @@
       [](const std::string&) -> Result<void> { return {}; });
   auto result = ValidateConfig(json_config["instances"][0], success_validator,
                                {"vm", "cpus"});
-  EXPECT_TRUE(result.ok());
+
+  EXPECT_THAT(result, IsOk());
 }
 
 TEST(CfConfigsCommonTests, ValidateConfigValidationFailure) {
@@ -85,7 +87,8 @@
       [](const std::string&) -> Result<void> { return CF_ERR("placeholder"); });
   auto result = ValidateConfig(json_config["instances"][0], error_validator,
                                {"vm", "cpus"});
-  EXPECT_FALSE(result.ok());
+
+  EXPECT_THAT(result, IsError());
 }
 
 TEST(CfConfigsCommonTests, ValidateConfigFieldDoesNotExist) {
@@ -115,7 +118,8 @@
       [](const std::string&) -> Result<void> { return {}; });
   auto result = ValidateConfig(json_config["instances"][0], success_validator,
                                {"disk", "cpus"});
-  EXPECT_TRUE(result.ok());
+
+  EXPECT_THAT(result, IsOk());
 }
 
 TEST(CfConfigsCommonTests, InitConfigTopLevel) {
@@ -149,7 +153,8 @@
 
   auto result =
       InitConfig(json_config, Json::Value::nullSingleton(), {"api_key"});
-  EXPECT_TRUE(result.ok());
+
+  EXPECT_THAT(result, IsOk());
   EXPECT_TRUE(json_config.isMember("api_key"));
   EXPECT_TRUE(json_config["api_key"].isNull());
 }
@@ -190,7 +195,8 @@
   auto result =
       InitConfig(json_config["instances"][0], Json::Value::nullSingleton(),
                  {"disk", "download_target_files_zip"});
-  EXPECT_TRUE(result.ok());
+
+  EXPECT_THAT(result, IsOk());
   EXPECT_TRUE(json_config["instances"][0]["disk"].isMember(
       "download_target_files_zip"));
   EXPECT_TRUE(json_config["instances"][0]["disk"]["download_target_files_zip"]
@@ -227,7 +233,8 @@
   auto result =
       InitConfig(json_config["instances"][0], Json::Value::nullSingleton(),
                  {"disk", "download_target_files_zip"});
-  EXPECT_TRUE(result.ok());
+
+  EXPECT_THAT(result, IsOk());
   ASSERT_TRUE(json_config["instances"][0].isMember("disk"));
   EXPECT_TRUE(json_config["instances"][0]["disk"].isMember(
       "download_target_files_zip"));
@@ -264,8 +271,7 @@
   ASSERT_TRUE(json_config["instances"][0]["vm"].isMember("cpus"));
   auto result = GenerateGflag(json_config["instances"], "cpus", {"vm", "cpus"});
 
-  EXPECT_TRUE(result.ok());
-  EXPECT_EQ(result.value(), "--cpus=4");
+  EXPECT_THAT(result, IsOkAndValue("--cpus=4"));
 }
 
 TEST(CfConfigsCommonTests, GenerateGflagMultiInstance) {
@@ -308,8 +314,7 @@
   ASSERT_TRUE(json_config["instances"][1]["vm"].isMember("cpus"));
   auto result = GenerateGflag(json_config["instances"], "cpus", {"vm", "cpus"});
 
-  EXPECT_TRUE(result.ok());
-  EXPECT_EQ(result.value(), "--cpus=4,2");
+  EXPECT_THAT(result, IsOkAndValue("--cpus=4,2"));
 }
 
 TEST(CfConfigsCommonTests, GenerateGflagMissingValue) {
@@ -340,7 +345,7 @@
   auto result = GenerateGflag(json_config["instances"], "setupwizard_mode",
                               {"vm", "setupwizard_mode"});
 
-  EXPECT_FALSE(result.ok());
+  EXPECT_THAT(result, IsError());
 }
 
 }  // namespace cuttlefish
diff --git a/host/commands/cvd/unittests/parser/fetch_cvd_parser_tests.cpp b/host/commands/cvd/unittests/parser/fetch_cvd_parser_tests.cpp
index e7fae7c..bf3aef2 100644
--- a/host/commands/cvd/unittests/parser/fetch_cvd_parser_tests.cpp
+++ b/host/commands/cvd/unittests/parser/fetch_cvd_parser_tests.cpp
@@ -17,14 +17,21 @@
 #include "host/commands/cvd/parser/fetch_cvd_parser.h"
 
 #include <string>
+#include <vector>
 
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 #include <json/json.h>
 
 #include "common/libs/utils/result.h"
+#include "common/libs/utils/result_matchers.h"
 #include "host/commands/cvd/parser/cf_flags_validator.h"
 #include "host/commands/cvd/unittests/parser/test_common.h"
 
+using ::testing::Contains;
+using ::testing::Eq;
+using ::testing::Not;
+
 namespace cuttlefish {
 namespace {
 
@@ -35,9 +42,11 @@
   return json_config;
 }
 
-Result<FetchCvdConfig> FetchCvdParserTestHelper(Json::Value& root) {
+Result<std::vector<std::string>> FetchCvdParserTestHelper(
+    Json::Value& root, const std::string& target_directory,
+    const std::vector<std::string>& target_subdirectories) {
   CF_EXPECT(ValidateCfConfigs(root), "Loaded Json validation failed");
-  return ParseFetchCvdConfigs(root);
+  return ParseFetchCvdConfigs(root, target_directory, target_subdirectories);
 }
 
 }  // namespace
@@ -54,21 +63,85 @@
         "cpus" : 4
       },
       "disk" : {
-        "default_build" : "git_master/cf_x86_64_phone-userdebug",
-        "download_img_zip" : true
+        "default_build" : "@ab/git_master/cf_x86_64_phone-userdebug",
+        "download_img_zip" : true,
+        "otatools" : "@ab/git_master/cf_x86_64_phone-userdebug",
+        "host_package" : "@ab/git_master/cf_x86_64_phone-userdebug"
+      },
+      "boot" : {
+        "build" : "@ab/git_master/cf_x86_64_phone-userdebug",
+        "kernel" : {
+          "build" : "@ab/git_master/cf_x86_64_phone-userdebug"
+        },
+        "bootloader" : {
+          "build" : "@ab/git_master/cf_x86_64_phone-userdebug"
+        }
       }
     }
   ],
-  "wait_retry_period" : 20,
-  "keep_downloaded_archives" : false
+  "fetch":{
+    "wait_retry_period" : 20,
+    "keep_downloaded_archives" : false
+  }
 }
   )"""";
   Json::Value json_config = GetTestJson(raw_json);
 
-  auto result_config = FetchCvdParserTestHelper(json_config);
+  auto result_flags = FetchCvdParserTestHelper(json_config, "/target", {"0"});
+  ASSERT_THAT(result_flags, IsOk())
+      << "Parsing config failed:  " << result_flags.error().Trace();
 
-  EXPECT_TRUE(result_config.ok())
-      << "Parsing config failed:  " << result_config.error().Trace();
+  const auto flags = result_flags.value();
+  EXPECT_THAT(flags, Contains("--wait_retry_period=20"));
+  EXPECT_THAT(flags, Contains("--keep_downloaded_archives=false"));
+  EXPECT_THAT(flags, Contains("--target_directory=/target"));
+  EXPECT_THAT(flags, Contains("--target_subdirectory=0"));
+  EXPECT_THAT(flags,
+              Contains("--default_build=git_master/cf_x86_64_phone-userdebug"));
+  EXPECT_THAT(flags, Contains("--download_img_zip=true"));
+  EXPECT_THAT(
+      flags, Contains("--otatools_build=git_master/cf_x86_64_phone-userdebug"));
+  EXPECT_THAT(
+      flags,
+      Contains("--host_package_build=git_master/cf_x86_64_phone-userdebug"));
+  EXPECT_THAT(flags,
+              Contains("--boot_build=git_master/cf_x86_64_phone-userdebug"));
+  EXPECT_THAT(flags,
+              Contains("--kernel_build=git_master/cf_x86_64_phone-userdebug"));
+  EXPECT_THAT(
+      flags,
+      Contains("--bootloader_build=git_master/cf_x86_64_phone-userdebug"));
+}
+
+TEST(FetchCvdParserTests, SingleFetchNoPrefix) {
+  const char* raw_json = R""""(
+{
+  "instances" : [
+    {
+      "@import" : "phone",
+      "disk" : {
+        "default_build" : "git_master/cf_x86_64_phone-userdebug",
+        "otatools" : "git_master/cf_x86_64_phone-userdebug",
+        "host_package" : "git_master/cf_x86_64_phone-userdebug"
+      },
+      "boot" : {
+        "build" : "git_master/cf_x86_64_phone-userdebug",
+        "kernel" : {
+          "build" : "git_master/cf_x86_64_phone-userdebug"
+        },
+        "bootloader" : {
+          "build" : "git_master/cf_x86_64_phone-userdebug"
+        }
+      }
+    }
+  ]
+}
+  )"""";
+  Json::Value json_config = GetTestJson(raw_json);
+
+  auto result_flags = FetchCvdParserTestHelper(json_config, "/target", {"0"});
+  ASSERT_THAT(result_flags, IsOk())
+      << "Parsing config failed:  " << result_flags.error().Trace();
 }
 
 TEST(FetchCvdParserTests, MultiFetch) {
@@ -83,8 +156,19 @@
         "cpus" : 4
       },
       "disk" : {
-        "default_build" : "git_master/cf_x86_64_phone-userdebug",
-        "download_img_zip" : true
+        "default_build" : "@ab/git_master/cf_x86_64_phone-userdebug",
+        "download_img_zip" : true,
+        "otatools" : "@ab/git_master/cf_x86_64_phone-userdebug",
+        "host_package" : "@ab/git_master/cf_x86_64_phone-userdebug"
+      },
+      "boot" : {
+        "build" : "@ab/git_master/cf_x86_64_phone-userdebug",
+        "kernel" : {
+          "build" : "@ab/git_master/cf_x86_64_phone-userdebug"
+        },
+        "bootloader" : {
+          "build" : "@ab/git_master/cf_x86_64_phone-userdebug"
+        }
       }
     },
     {
@@ -95,21 +179,47 @@
         "cpus" : 4
       },
       "disk" : {
-        "default_build" : "git_master/cf_gwear_x86-userdebug",
+        "default_build" : "@ab/git_master/cf_gwear_x86-userdebug",
         "download_img_zip" : true
       }
     }
   ],
-  "wait_retry_period" : 20,
-  "keep_downloaded_archives" : false
+  "fetch":{
+    "wait_retry_period" : 20,
+    "keep_downloaded_archives" : false
+  }
 }
   )"""";
   Json::Value json_config = GetTestJson(raw_json);
 
-  auto result_config = FetchCvdParserTestHelper(json_config);
+  auto result_flags =
+      FetchCvdParserTestHelper(json_config, "/target", {"0", "1"});
+  ASSERT_THAT(result_flags, IsOk())
+      << "Parsing config failed:  " << result_flags.error().Trace();
 
-  EXPECT_TRUE(result_config.ok())
-      << "Parsing config failed:  " << result_config.error().Trace();
+  const auto flags = result_flags.value();
+  EXPECT_THAT(flags, Contains("--wait_retry_period=20"));
+  EXPECT_THAT(flags, Contains("--keep_downloaded_archives=false"));
+  EXPECT_THAT(flags, Contains("--target_directory=/target"));
+  EXPECT_THAT(flags, Contains("--target_subdirectory=0,1"));
+  EXPECT_THAT(
+      flags,
+      Contains("--default_build=git_master/"
+               "cf_x86_64_phone-userdebug,git_master/cf_gwear_x86-userdebug"));
+  EXPECT_THAT(flags, Contains("--download_img_zip=true,true"));
+  EXPECT_THAT(
+      flags,
+      Contains("--otatools_build=git_master/cf_x86_64_phone-userdebug,"));
+  EXPECT_THAT(
+      flags,
+      Contains("--host_package_build=git_master/cf_x86_64_phone-userdebug,"));
+  EXPECT_THAT(flags,
+              Contains("--boot_build=git_master/cf_x86_64_phone-userdebug,"));
+  EXPECT_THAT(flags,
+              Contains("--kernel_build=git_master/cf_x86_64_phone-userdebug,"));
+  EXPECT_THAT(
+      flags,
+      Contains("--bootloader_build=git_master/cf_x86_64_phone-userdebug,"));
 }
 
 }  // namespace cuttlefish
diff --git a/host/commands/cvd/unittests/parser/instance/boot_configs_test.cc b/host/commands/cvd/unittests/parser/instance/boot_configs_test.cc
index 13daad9..6e767bb 100644
--- a/host/commands/cvd/unittests/parser/instance/boot_configs_test.cc
+++ b/host/commands/cvd/unittests/parser/instance/boot_configs_test.cc
@@ -19,116 +19,6 @@
 #include "host/commands/cvd/unittests/parser/test_common.h"
 
 namespace cuttlefish {
-#ifndef GENERATE_MVP_FLAGS_ONLY
-TEST(BootFlagsParserTest, ParseTwoInstancesExtraBootConfigFlagEmptyJson) {
-  const char* test_string = R""""(
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "crosvm":{
-                }
-            }
-        },
-        {
-            "vm": {
-                "crosvm":{
-                }
-            }
-        }
-    ]
-}
-  )"""";
-
-  Json::Value json_configs;
-  std::string json_text(test_string);
-
-  EXPECT_TRUE(ParseJsonString(json_text, json_configs))
-      << "Invalid Json string";
-  auto serialized_data = LaunchCvdParserTester(json_configs);
-  EXPECT_TRUE(serialized_data.ok()) << serialized_data.error().Trace();
-  EXPECT_TRUE(FindConfig(*serialized_data, R"(--extra_bootconfig_args=,)"))
-      << "extra_bootconfig_args flag is missing or wrongly formatted";
-}
-
-TEST(BootFlagsParserTest, ParseTwoInstancesExtraBootConfigFlagPartialJson) {
-  const char* test_string = R""""(
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "crosvm":{
-                }
-            },
-            "boot": {
-            }
-        },
-        {
-            "vm": {
-                "crosvm":{
-                }
-            },
-            "boot": {
-                "extra_bootconfig_args": "androidboot.X=Y"
-            }
-        }
-    ]
-}
-  )"""";
-
-  Json::Value json_configs;
-  std::string json_text(test_string);
-
-  EXPECT_TRUE(ParseJsonString(json_text, json_configs))
-      << "Invalid Json string";
-  auto serialized_data = LaunchCvdParserTester(json_configs);
-  EXPECT_TRUE(serialized_data.ok()) << serialized_data.error().Trace();
-  EXPECT_TRUE(FindConfig(*serialized_data,
-                         R"(--extra_bootconfig_args=,androidboot.X=Y)"))
-      << "extra_bootconfig_args flag is missing or wrongly formatted";
-}
-
-TEST(BootFlagsParserTest, ParseTwoInstancesExtraBootConfigFlagFullJson) {
-  const char* test_string = R""""(
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "crosvm":{
-                }
-            },
-            "boot": {
-                "extra_bootconfig_args": "androidboot.X=Y"
-            }
-        },
-        {
-            "vm": {
-                "crosvm":{
-                }
-            },
-            "boot": {
-                "extra_bootconfig_args": "androidboot.X=Z"
-            }
-        }
-    ]
-}
-  )"""";
-
-  Json::Value json_configs;
-  std::string json_text(test_string);
-
-  EXPECT_TRUE(ParseJsonString(json_text, json_configs))
-      << "Invalid Json string";
-  auto serialized_data = LaunchCvdParserTester(json_configs);
-  EXPECT_TRUE(serialized_data.ok()) << serialized_data.error().Trace();
-  EXPECT_TRUE(
-      FindConfig(*serialized_data,
-                 R"(--extra_bootconfig_args=androidboot.X=Y,androidboot.X=Z)"))
-      << "extra_bootconfig_args flag is missing or wrongly formatted";
-}
 
 TEST(BootFlagsParserTest, ParseTwoInstancesBootAnimationFlagEmptyJson) {
   const char* test_string = R""""(
@@ -350,116 +240,6 @@
       << "serial_number flag is missing or wrongly formatted";
 }
 
-TEST(BootFlagsParserTest, ParseTwoInstancesRandomSerialFlagEmptyJson) {
-  const char* test_string = R""""(
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "crosvm":{
-                }
-            }
-        },
-        {
-            "vm": {
-                "crosvm":{
-                }
-            }
-        }
-    ]
-}
-  )"""";
-
-  Json::Value json_configs;
-  std::string json_text(test_string);
-
-  EXPECT_TRUE(ParseJsonString(json_text, json_configs))
-      << "Invalid Json string";
-  auto serialized_data = LaunchCvdParserTester(json_configs);
-  EXPECT_TRUE(serialized_data.ok()) << serialized_data.error().Trace();
-  EXPECT_TRUE(
-      FindConfig(*serialized_data, R"(--use_random_serial=false,false)"))
-      << "use_random_serial flag is missing or wrongly formatted";
-}
-
-TEST(BootFlagsParserTest, ParseTwoInstancesRandomSerialFlagPartialJson) {
-  const char* test_string = R""""(
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "crosvm":{
-                }
-            },
-            "security": {
-                "serial_number": "CUTTLEFISHCVD101"
-            }
-        },
-        {
-            "vm": {
-                "crosvm":{
-                }
-            },
-            "security": {
-                "serial_number": "@random"
-            }
-        }
-    ]
-}
-  )"""";
-
-  Json::Value json_configs;
-  std::string json_text(test_string);
-
-  EXPECT_TRUE(ParseJsonString(json_text, json_configs))
-      << "Invalid Json string";
-  auto serialized_data = LaunchCvdParserTester(json_configs);
-  EXPECT_TRUE(serialized_data.ok()) << serialized_data.error().Trace();
-  EXPECT_TRUE(FindConfig(*serialized_data, R"(--use_random_serial=false,true)"))
-      << "use_random_serial flag is missing or wrongly formatted";
-}
-
-TEST(BootFlagsParserTest, ParseTwoInstancesRandomSerialFlagFullJson) {
-  const char* test_string = R""""(
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "crosvm":{
-                }
-            },
-            "security": {
-                "serial_number": "@random"
-            }
-        },
-        {
-            "vm": {
-                "crosvm":{
-                }
-            },
-            "security": {
-                "serial_number": "@random"
-            }
-        }
-    ]
-}
-  )"""";
-
-  Json::Value json_configs;
-  std::string json_text(test_string);
-
-  EXPECT_TRUE(ParseJsonString(json_text, json_configs))
-      << "Invalid Json string";
-  auto serialized_data = LaunchCvdParserTester(json_configs);
-  EXPECT_TRUE(serialized_data.ok()) << serialized_data.error().Trace();
-  EXPECT_TRUE(FindConfig(*serialized_data, R"(--use_random_serial=true,true)"))
-      << "use_random_serial flag is missing or wrongly formatted";
-}
-#endif
-
 TEST(BootFlagsParserTest, ParseTwoInstancesEnforceSecurityFlagEmptyJson) {
   const char* test_string = R""""(
 {
@@ -570,7 +350,6 @@
       << "guest_enforce_security flag is missing or wrongly formatted";
 }
 
-#ifndef GENERATE_MVP_FLAGS_ONLY
 TEST(BootFlagsParserTest, ParseTwoInstancesKernelCmdFlagEmptyJson) {
   const char* test_string = R""""(
 {
@@ -689,6 +468,5 @@
       R"(--extra_kernel_cmdline=androidboot.selinux=permissive,lpm_levels.sleep_disabled=1)"))
       << "extra_kernel_cmdline flag is missing or wrongly formatted";
 }
-#endif
 
 }  // namespace cuttlefish
diff --git a/host/commands/cvd/unittests/parser/instance/vm_configs_test.cc b/host/commands/cvd/unittests/parser/instance/vm_configs_test.cc
index f72e551..605d82e 100644
--- a/host/commands/cvd/unittests/parser/instance/vm_configs_test.cc
+++ b/host/commands/cvd/unittests/parser/instance/vm_configs_test.cc
@@ -554,7 +554,6 @@
       << "setupwizard_mode flag is missing or wrongly formatted";
 }
 
-#ifndef GENERATE_MVP_FLAGS_ONLY
 TEST(VmFlagsParserTest, ParseTwoInstancesUuidFlagEmptyJson) {
   const char* test_string = R""""(
 {
@@ -659,7 +658,6 @@
       R"(--uuid=870acfc4-c8c4-11e7-99ac-5065f31dc250,870acfc4-c8c4-11e7-99ac-5065f31dc251)"))
       << "uuid flag is missing or wrongly formatted";
 }
-#endif
 
 TEST(VmFlagsParserTest, ParseTwoInstancesSandboxFlagEmptyJson) {
   const char* test_string = R""""(
diff --git a/host/commands/cvd/unittests/parser/instance/metrics_configs_test.cc b/host/commands/cvd/unittests/parser/metrics_configs_test.cc
similarity index 63%
rename from host/commands/cvd/unittests/parser/instance/metrics_configs_test.cc
rename to host/commands/cvd/unittests/parser/metrics_configs_test.cc
index 44c7bf7..56aedb8 100644
--- a/host/commands/cvd/unittests/parser/instance/metrics_configs_test.cc
+++ b/host/commands/cvd/unittests/parser/metrics_configs_test.cc
@@ -14,31 +14,64 @@
  * limitations under the License.
  */
 
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <json/json.h>
+
+#include "common/libs/utils/result.h"
+#include "common/libs/utils/result_matchers.h"
 #include "host/commands/cvd/parser/launch_cvd_parser.h"
 #include "host/commands/cvd/unittests/parser/test_common.h"
 
 namespace cuttlefish {
-TEST(MetricsFlagsParserTest, ParseOneInstanceMetricsReportInvalidValue) {
+
+using ::testing::IsTrue;
+using ::testing::Not;
+
+TEST(MetricsFlagsParserTest, ParseOneInstanceMetricsReportValidValue) {
   const char* test_string = R""""(
 {
     "instances" :
     [
         {
-            "metrics": {
-            }
         }
-    ]
+    ],
+    "metrics": {
+      "enable": true
+    }
 }
   )"""";
 
   Json::Value json_configs;
   std::string json_text(test_string);
 
-  EXPECT_TRUE(ParseJsonString(json_text, json_configs))
+  EXPECT_THAT(ParseJsonString(json_text, json_configs), IsTrue())
       << "Invalid Json string";
   auto serialized_data = LaunchCvdParserTester(json_configs);
-  EXPECT_FALSE(serialized_data.ok()) << serialized_data.error().Trace();
+  EXPECT_THAT(serialized_data, IsOk()) << serialized_data.error().Trace();
+}
+
+TEST(MetricsFlagsParserTest, ParseOneInstanceMetricsReportInvalidValue) {
+  const char* test_string = R""""(
+{
+    "instances" :
+    [
+        {
+        }
+    ],
+    "metrics": {
+      "enable": "foo"
+    }
+}
+  )"""";
+
+  Json::Value json_configs;
+  std::string json_text(test_string);
+
+  EXPECT_THAT(ParseJsonString(json_text, json_configs), IsTrue())
+      << "Invalid Json string";
+  auto serialized_data = LaunchCvdParserTester(json_configs);
+  EXPECT_THAT(serialized_data, Not(IsOk()));
 }
 
 TEST(MetricsFlagsParserTest, ParseOneInstancesMetricsReportFlagEmptyJson) {
@@ -55,12 +88,13 @@
   Json::Value json_configs;
   std::string json_text(test_string);
 
-  EXPECT_TRUE(ParseJsonString(json_text, json_configs))
+  EXPECT_THAT(ParseJsonString(json_text, json_configs), IsTrue())
       << "Invalid Json string";
   auto serialized_data = LaunchCvdParserTester(json_configs);
-  EXPECT_TRUE(serialized_data.ok()) << serialized_data.error().Trace();
-  EXPECT_TRUE(
-      FindConfig(*serialized_data, R"(--report_anonymous_usage_stats=n)"))
+  EXPECT_THAT(serialized_data, IsOk()) << serialized_data.error().Trace();
+  EXPECT_THAT(
+      FindConfig(*serialized_data, R"(--report_anonymous_usage_stats=n)"),
+      IsTrue())
       << "report_anonymous_usage_stats flag is missing or wrongly formatted";
 }
 
@@ -80,12 +114,13 @@
   Json::Value json_configs;
   std::string json_text(test_string);
 
-  EXPECT_TRUE(ParseJsonString(json_text, json_configs))
+  EXPECT_THAT(ParseJsonString(json_text, json_configs), IsTrue())
       << "Invalid Json string";
   auto serialized_data = LaunchCvdParserTester(json_configs);
-  EXPECT_TRUE(serialized_data.ok()) << serialized_data.error().Trace();
-  EXPECT_TRUE(
-      FindConfig(*serialized_data, R"(--report_anonymous_usage_stats=n)"))
+  EXPECT_THAT(serialized_data, IsOk()) << serialized_data.error().Trace();
+  EXPECT_THAT(
+      FindConfig(*serialized_data, R"(--report_anonymous_usage_stats=n)"),
+      IsTrue())
       << "report_anonymous_usage_stats flag is missing or wrongly formatted";
 }
 
diff --git a/host/commands/cvd/unittests/parser/test_common.h b/host/commands/cvd/unittests/parser/test_common.h
index 41aec34..2d1dcc0 100644
--- a/host/commands/cvd/unittests/parser/test_common.h
+++ b/host/commands/cvd/unittests/parser/test_common.h
@@ -23,7 +23,6 @@
 
 #include "common/libs/utils/result.h"
 
-#define GENERATE_MVP_FLAGS_ONLY true
 namespace cuttlefish {
 
 bool ParseJsonString(std::string& json_text, Json::Value& root);
diff --git a/host/commands/cvd_env/Android.bp b/host/commands/cvd_env/Android.bp
index 243153b..9589060 100644
--- a/host/commands/cvd_env/Android.bp
+++ b/host/commands/cvd_env/Android.bp
@@ -42,4 +42,9 @@
     ],
     cpp_std: "c++17",
     defaults: ["cuttlefish_host"],
+    target: {
+        darwin: {
+            enabled: true,
+        },
+    },
 }
diff --git a/host/commands/cvd_env/main.cc b/host/commands/cvd_env/main.cc
index bd1ca32..b0e215b 100644
--- a/host/commands/cvd_env/main.cc
+++ b/host/commands/cvd_env/main.cc
@@ -34,7 +34,6 @@
     "    Usage: cvd [selector options] env ls [service] [method] [-l]\n"
     "      service(optional) : gRPC service name\n"
     "      method(optional)  : method name for given service\n"
-    "      -l(optional)      : Use a long listing format\n"
     "  type: get detailed information for given request/reply type\n"
     "    Usage: cvd [selector options] env type [service] [method] [type]\n"
     "      service           : gRPC service name\n"
@@ -47,6 +46,7 @@
     "      request           : Protobuffer with json format\n\n"
     "* \"cvd [selector_options] env\" can be replaced with:\n"
     "    \"cvd_internal_env [internal device name]\"\n";
+constexpr char kServiceControlEnvProxy[] = "ControlEnvProxyService";
 
 bool ContainHelpOption(int argc, char** argv) {
   for (int i = 0; i < argc; i++) {
@@ -68,15 +68,17 @@
   const auto& receiver = argv[1];
   const auto& cmd = argv[2];
 
-  std::vector<std::string> options;
   std::vector<std::string> args;
   for (int i = 3; i < argc; i++) {
-    if (android::base::StartsWith(argv[i], '-')) {
-      options.push_back(argv[i]);
-    } else {
+    // Ignore options, not to be applied when calling grpc_cli.
+    if (!android::base::StartsWith(argv[i], '-')) {
       args.push_back(argv[i]);
     }
   }
+  if (args.size() > 0) {
+    CF_EXPECT(args[0].compare(kServiceControlEnvProxy) != 0,
+              "Prohibited service name");
+  }
 
   const auto* config = CuttlefishConfig::Get();
   CF_EXPECT(config != nullptr, "Unable to find the config");
@@ -90,10 +92,8 @@
             "there is no instance of which name is "
                 << receiver << ". please check instance name by cvd fleet");
 
-  // TODO(265747873): Check if argument contains ControlEnvProxyService, not to
-  // use this service by cvd env CLI.
-  auto command_output = CF_EXPECT(
-      HandleCmds(receiver_instance->grpc_socket_path(), cmd, args, options));
+  auto command_output =
+      CF_EXPECT(HandleCmds(receiver_instance->grpc_socket_path(), cmd, args));
 
   std::cout << command_output;
 
diff --git a/host/commands/cvd_import_locations/Android.bp b/host/commands/cvd_import_locations/Android.bp
index a41f947..4f152c3 100644
--- a/host/commands/cvd_import_locations/Android.bp
+++ b/host/commands/cvd_import_locations/Android.bp
@@ -23,7 +23,6 @@
         "libbase",
         "libcuttlefish_fs",
         "liblog",
-        "libicuuc",
         "libprotobuf-cpp-full",
         "libgrpc++_unsecure",
     ],
@@ -55,6 +54,11 @@
         "-D_XOPEN_SOURCE",
     ],
     defaults: ["cvd_import_locations_defaults"],
+    target: {
+        darwin: {
+            enabled: true,
+        },
+    },
 }
 
 cc_test_host {
@@ -79,4 +83,9 @@
         "-D_XOPEN_SOURCE",
     ],
     defaults: ["cvd_import_locations_defaults"],
-}
\ No newline at end of file
+    target: {
+        darwin: {
+            enabled: true,
+        },
+    },
+}
diff --git a/host/commands/cvd_load_tester/defaults.json b/host/commands/cvd_load_tester/defaults.json
deleted file mode 100644
index 5a77af1..0000000
--- a/host/commands/cvd_load_tester/defaults.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
-        "instances" :
-        [
-            {
-                "vm": {
-                    "memory_mb": 2048
-                }
-            },
-            {
-                "vm": {
-                    "memory_mb": 4096
-                },
-                "graphics":{
-                    "displays":[
-                        {
-                            "width": 1080,
-                            "height": 600,
-                            "dpi": 120
-                        },
-                        {
-                            "width": 400,
-                            "height": 600,
-                            "dpi": 150
-                        }
-                    ]
-                    }
-            },
-            {
-                "vm": {
-                    "memory_mb": 4096
-                },
-                "graphics":{
-                    "displays":[
-                        {
-                            "width": 2560,
-                            "height": 1800,
-                            "dpi": 320
-                        }
-                    ]
-                    }
-            }
-        ]
-    }
\ No newline at end of file
diff --git a/host/commands/cvd_load_tester/end_to_end_test/multi/TC1.json b/host/commands/cvd_load_tester/end_to_end_test/multi/TC1.json
deleted file mode 100644
index a0cb406..0000000
--- a/host/commands/cvd_load_tester/end_to_end_test/multi/TC1.json
+++ /dev/null
@@ -1,43 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "memory_mb": 2048
-            }
-        },
-        {
-            "vm": {
-                "memory_mb": 4096
-            },
-            "graphics":{
-                "displays":[
-                    {
-                        "width": 1080,
-                        "height": 600,
-                        "dpi": 120
-                    },
-                    {
-                        "width": 400,
-                        "height": 600,
-                        "dpi": 150
-                    }
-                ]
-                }
-        },
-        {
-            "vm": {
-                "memory_mb": 4096
-            },
-            "graphics":{
-                "displays":[
-                    {
-                        "width": 2560,
-                        "height": 1800,
-                        "dpi": 320
-                    }
-                ]
-                }
-        }
-    ]
-}
\ No newline at end of file
diff --git a/host/commands/cvd_load_tester/end_to_end_test/single/TC_auto.json b/host/commands/cvd_load_tester/end_to_end_test/single/TC_auto.json
deleted file mode 100644
index 8f787fb..0000000
--- a/host/commands/cvd_load_tester/end_to_end_test/single/TC_auto.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "memory_mb": 4096
-            },
-            "graphics":{
-                "displays":[
-                    {
-                        "width": 1080,
-                        "height": 600,
-                        "dpi": 120
-                    },
-                    {
-                        "width": 400,
-                        "height": 600,
-                        "dpi": 120
-                    }
-                ]
-			}
-        }
-    ]
-}
diff --git a/host/commands/cvd_load_tester/end_to_end_test/single/TC_foldable.json b/host/commands/cvd_load_tester/end_to_end_test/single/TC_foldable.json
deleted file mode 100644
index 5419c22..0000000
--- a/host/commands/cvd_load_tester/end_to_end_test/single/TC_foldable.json
+++ /dev/null
@@ -1,65 +0,0 @@
-{
-        "instances" :
-        [
-            {
-                "vm": {
-                        "memory_mb": 4096,
-                        "custom_actions" : [
-                                {
-                                        "device_states": [
-                                                {
-                                                        "lid_switch_open": false,
-                                                        "hinge_angle_value": 0
-                                                }
-                                        ],
-                                        "button":{
-                                                "command":"device_state_closed",
-                                                "title":"Device State Closed",
-                                                "icon_name":"smartphone"
-                                        }
-                                },
-                                {
-                                        "device_states": [
-                                                {
-                                                        "lid_switch_open": true,
-                                                        "hinge_angle_value": 90
-                                                }
-                                        ],
-                                        "button":{
-                                                "command":"device_state_half_opened",
-                                                "title":"Device State Half-Opened",
-                                                "icon_name":"laptop"
-                                        }
-                                },
-                                {
-                                        "device_states": [
-                                                {
-                                                        "lid_switch_open": true,
-                                                        "hinge_angle_value": 180
-                                                }
-                                        ],
-                                        "button":{
-                                                "command":"device_state_opened",
-                                                "title":"Device State Opened",
-                                                "icon_name":"tablet"
-                                        }
-                                }
-                        ]
-                },
-                "graphics":{
-                        "displays":[
-                            {
-                                "width": 1768,
-                                "height": 2208,
-                                "dpi": 374
-                            },
-                            {
-                                "width": 832,
-                                "height": 2268,
-                                "dpi": 387
-                            }
-                        ]
-                }
-            }
-        ]
-}
diff --git a/host/commands/cvd_load_tester/end_to_end_test/single/TC_go.json b/host/commands/cvd_load_tester/end_to_end_test/single/TC_go.json
deleted file mode 100644
index ef24d44..0000000
--- a/host/commands/cvd_load_tester/end_to_end_test/single/TC_go.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "memory_mb": 2048
-            },
-            "graphics":{
-                "displays":[
-                    {
-                        "width": 720,
-                        "height": 1280,
-                        "dpi": 320
-                    }
-                ]
-			}
-        }
-    ]
-}
diff --git a/host/commands/cvd_load_tester/end_to_end_test/single/TC_phone.json b/host/commands/cvd_load_tester/end_to_end_test/single/TC_phone.json
deleted file mode 100644
index ef24d44..0000000
--- a/host/commands/cvd_load_tester/end_to_end_test/single/TC_phone.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "memory_mb": 2048
-            },
-            "graphics":{
-                "displays":[
-                    {
-                        "width": 720,
-                        "height": 1280,
-                        "dpi": 320
-                    }
-                ]
-			}
-        }
-    ]
-}
diff --git a/host/commands/cvd_load_tester/end_to_end_test/single/TC_slim.json b/host/commands/cvd_load_tester/end_to_end_test/single/TC_slim.json
deleted file mode 100644
index 19c4760..0000000
--- a/host/commands/cvd_load_tester/end_to_end_test/single/TC_slim.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "memory_mb": 2048,
-				"use_sdcard" : false
-            },
-            "graphics":{
-                "displays":[
-                    {
-                        "width": 720,
-                        "height": 1280,
-                        "dpi": 320
-                    }
-                ]
-			}
-        }
-    ]
-}
diff --git a/host/commands/cvd_load_tester/end_to_end_test/single/TC_tablet.json b/host/commands/cvd_load_tester/end_to_end_test/single/TC_tablet.json
deleted file mode 100644
index fe6217e..0000000
--- a/host/commands/cvd_load_tester/end_to_end_test/single/TC_tablet.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "memory_mb": 4096
-            },
-            "graphics":{
-                "displays":[
-                    {
-                        "width": 2560,
-                        "height": 1800,
-                        "dpi": 320
-                    }
-                ]
-			}
-        }
-    ]
-}
diff --git a/host/commands/cvd_load_tester/end_to_end_test/single/TC_tv.json b/host/commands/cvd_load_tester/end_to_end_test/single/TC_tv.json
deleted file mode 100644
index 7f288f4..0000000
--- a/host/commands/cvd_load_tester/end_to_end_test/single/TC_tv.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "memory_mb": 2048
-            },
-            "graphics":{
-                "displays":[
-                    {
-                        "width": 1920,
-                        "height": 1080,
-                        "dpi": 213
-                    }
-                ]
-			}
-        }
-    ]
-}
diff --git a/host/commands/cvd_load_tester/end_to_end_test/single/TC_wear.json b/host/commands/cvd_load_tester/end_to_end_test/single/TC_wear.json
deleted file mode 100644
index 311c01f..0000000
--- a/host/commands/cvd_load_tester/end_to_end_test/single/TC_wear.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "memory_mb": 1536,
-				"use_sdcard" : false
-            },
-            "graphics":{
-                "displays":[
-                    {
-                        "width": 450,
-                        "height": 450,
-                        "dpi": 320
-                    }
-                ]
-			}
-        }
-    ]
-}
diff --git a/host/commands/cvd_load_tester/main.cc b/host/commands/cvd_load_tester/main.cc
deleted file mode 100644
index 28a35dd..0000000
--- a/host/commands/cvd_load_tester/main.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-
-/*
- * Copyright (C) 2023 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 <fstream>
-#include <iostream>
-#include <string>
-
-#include <android-base/logging.h>
-#include <gflags/gflags.h>
-
-#include "host/commands/cvd/parser/load_configs_parser.h"
-
-DEFINE_string(config_file_path, "", "config file path for default configs");
-
-namespace cuttlefish {
-int CvdLoadParserMain(int argc, char** argv) {
-  ::android::base::InitLogging(argv, android::base::StderrLogger);
-  google::ParseCommandLineFlags(&argc, &argv, true);
-
-  auto json_configs = cuttlefish::ParseJsonFile(FLAGS_config_file_path);
-  if (!json_configs.ok()) {
-    LOG(INFO) << "parsing input file failed";
-    return 1;
-  }
-
-  auto cvd_flags = cuttlefish::ParseCvdConfigs(*json_configs);
-  if (!cvd_flags.ok()) {
-    LOG(INFO) << "parsing json configs failed";
-    return 1;
-  }
-  LOG(INFO) << "Parsing succeeded";
-  for (auto& parsed_launch_flag : cvd_flags->launch_cvd_flags) {
-    LOG(INFO) << parsed_launch_flag;
-  }
-
-  LOG(INFO) << "credential_source = "
-            << cvd_flags->fetch_cvd_flags.credential_source.value_or("");
-
-  int i = 0;
-  for (const auto& parsed_fetch_instance_flag :
-       cvd_flags->fetch_cvd_flags.instances) {
-    LOG(INFO) << i << " -- "
-              << parsed_fetch_instance_flag.default_build.value_or("") << ","
-              << parsed_fetch_instance_flag.system_build.value_or("") << ","
-              << parsed_fetch_instance_flag.kernel_build.value_or("") << ","
-              << parsed_fetch_instance_flag.should_fetch;
-    i++;
-  }
-
-  return 0;
-}
-}  // namespace cuttlefish
-int main(int argc, char** argv) {
-  return cuttlefish::CvdLoadParserMain(argc, argv);
-}
diff --git a/host/commands/cvd_load_tester/mvp_features/graphics/displays/TC1.json b/host/commands/cvd_load_tester/mvp_features/graphics/displays/TC1.json
deleted file mode 100644
index 3718bb7..0000000
--- a/host/commands/cvd_load_tester/mvp_features/graphics/displays/TC1.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "graphics": {
-            }
-        },
-        {
-            "graphics": {
-            }
-        }
-    ]
-}
\ No newline at end of file
diff --git a/host/commands/cvd_load_tester/mvp_features/graphics/displays/TC2.json b/host/commands/cvd_load_tester/mvp_features/graphics/displays/TC2.json
deleted file mode 100644
index c147f4a..0000000
--- a/host/commands/cvd_load_tester/mvp_features/graphics/displays/TC2.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "graphics":{
-                "displays":[
-                    {
-                    }
-                ]
-                }
-        },
-        {
-            "graphics":{
-                "displays":[
-                    {
-                    },
-                    {
-                    }
-                ]
-                }
-        }
-    ]
-}
\ No newline at end of file
diff --git a/host/commands/cvd_load_tester/mvp_features/graphics/displays/TC3.json b/host/commands/cvd_load_tester/mvp_features/graphics/displays/TC3.json
deleted file mode 100644
index 4e9195e..0000000
--- a/host/commands/cvd_load_tester/mvp_features/graphics/displays/TC3.json
+++ /dev/null
@@ -1,35 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "graphics":{
-                "displays":[
-                    {
-                        "width": 1080,
-                        "height": 600,
-                        "dpi": 120,
-                        "refresh_rate_hertz": 60
-                    },
-                    {
-                        "width": 400,
-                        "height": 600,
-                        "dpi": 120,
-                        "refresh_rate_hertz": 60
-                    }
-                ]
-                }
-        },
-        {
-            "graphics":{
-                "displays":[
-                    {
-                        "width": 2560,
-                        "height": 1800,
-                        "dpi": 320,
-                        "refresh_rate_hertz": 60
-                    }
-                ]
-                }
-        }
-    ]
-}
\ No newline at end of file
diff --git a/host/commands/cvd_load_tester/mvp_features/security/guest_enforce_security/TC1.json b/host/commands/cvd_load_tester/mvp_features/security/guest_enforce_security/TC1.json
deleted file mode 100644
index da19f0f..0000000
--- a/host/commands/cvd_load_tester/mvp_features/security/guest_enforce_security/TC1.json
+++ /dev/null
@@ -1,17 +0,0 @@
-
-{
-    "instances" :
-    [
-        {
-            "security": {
-            }
-        },
-        {
-            "vm": {
-            },
-            "security": {
-                "guest_enforce_security": false
-            }
-        }
-    ]
-}
\ No newline at end of file
diff --git a/host/commands/cvd_load_tester/mvp_features/security/guest_enforce_security/TC2.json b/host/commands/cvd_load_tester/mvp_features/security/guest_enforce_security/TC2.json
deleted file mode 100644
index a237082..0000000
--- a/host/commands/cvd_load_tester/mvp_features/security/guest_enforce_security/TC2.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "security": {
-                "guest_enforce_security": false
-            }
-        },
-        {
-            "security": {
-                "guest_enforce_security": false
-            }
-        }
-    ]
-}
\ No newline at end of file
diff --git a/host/commands/cvd_load_tester/mvp_features/vm/cpus/TC1.json b/host/commands/cvd_load_tester/mvp_features/vm/cpus/TC1.json
deleted file mode 100644
index 7c8cf89..0000000
--- a/host/commands/cvd_load_tester/mvp_features/vm/cpus/TC1.json
+++ /dev/null
@@ -1,15 +0,0 @@
-
-{
-    "instances" :
-    [
-        {
-            "vm": {
-            }
-        },
-        {
-            "vm": {
-                "cpus": 4
-            }
-        }
-    ]
-}
\ No newline at end of file
diff --git a/host/commands/cvd_load_tester/mvp_features/vm/cpus/TC2.json b/host/commands/cvd_load_tester/mvp_features/vm/cpus/TC2.json
deleted file mode 100644
index a975433..0000000
--- a/host/commands/cvd_load_tester/mvp_features/vm/cpus/TC2.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "cpus": 4
-            }
-        },
-        {
-            "vm": {
-                "cpus": 6
-            }
-        }
-    ]
-}
\ No newline at end of file
diff --git a/host/commands/cvd_load_tester/mvp_features/vm/custom_actions/TC1.json b/host/commands/cvd_load_tester/mvp_features/vm/custom_actions/TC1.json
deleted file mode 100644
index 239e0d4..0000000
--- a/host/commands/cvd_load_tester/mvp_features/vm/custom_actions/TC1.json
+++ /dev/null
@@ -1,40 +0,0 @@
-{
-        "instances" :
-        [
-            {
-                "vm": {
-                    "memory_mb": 2048
-                }
-            },
-            {
-                "vm": {
-                    "memory_mb": 2048,
-                    "custom_actions" : [
-                            {
-                                    "shell_command":"am start -a android.intent.action.VIEW -d https://www.android1.com/",
-                                    "button":{
-                                            "command":"web",
-                                            "title":"Web Page",
-                                            "icon_name":"language"
-                                    }
-                            },
-                            {
-                                    "server":"cuttlefish_example_action_server",
-                                    "buttons":[
-                                            {
-                                                    "command":"settings",
-                                                    "title":"Quick Settings",
-                                                    "icon_name":"settings"
-                                            },
-                                            {
-                                                    "command":"alert",
-                                                    "title":"Do Not Disturb",
-                                                    "icon_name":"notifications_paused"
-                                            }
-                                    ]
-                            }
-                    ]
-                }
-            }
-        ]
-}
\ No newline at end of file
diff --git a/host/commands/cvd_load_tester/mvp_features/vm/enable_sandbox/TC1.json b/host/commands/cvd_load_tester/mvp_features/vm/enable_sandbox/TC1.json
deleted file mode 100644
index 090e179..0000000
--- a/host/commands/cvd_load_tester/mvp_features/vm/enable_sandbox/TC1.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "vm": {
-            }
-        },
-        {
-            "vm": {
-                "crosvm":{
-                }
-            }
-        }
-    ]
-}
diff --git a/host/commands/cvd_load_tester/mvp_features/vm/enable_sandbox/TC2.json b/host/commands/cvd_load_tester/mvp_features/vm/enable_sandbox/TC2.json
deleted file mode 100644
index d88c7b9..0000000
--- a/host/commands/cvd_load_tester/mvp_features/vm/enable_sandbox/TC2.json
+++ /dev/null
@@ -1,19 +0,0 @@
-
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "crosvm":{
-                }
-            }
-        },
-        {
-            "vm": {
-                "crosvm":{
-                    "enable_sandbox": true
-                }
-            }
-        }
-    ]
-}
\ No newline at end of file
diff --git a/host/commands/cvd_load_tester/mvp_features/vm/enable_sandbox/TC3.json b/host/commands/cvd_load_tester/mvp_features/vm/enable_sandbox/TC3.json
deleted file mode 100644
index 03055b9..0000000
--- a/host/commands/cvd_load_tester/mvp_features/vm/enable_sandbox/TC3.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "crosvm":{
-                    "enable_sandbox": true
-                }
-            }
-        },
-        {
-            "vm": {
-                "crosvm":{
-                    "enable_sandbox": true
-                }
-            }
-        }
-    ]
-}
diff --git a/host/commands/cvd_load_tester/mvp_features/vm/memory_mb/TC1.json b/host/commands/cvd_load_tester/mvp_features/vm/memory_mb/TC1.json
deleted file mode 100644
index a4156a7..0000000
--- a/host/commands/cvd_load_tester/mvp_features/vm/memory_mb/TC1.json
+++ /dev/null
@@ -1,15 +0,0 @@
-
-{
-    "instances" :
-    [
-        {
-            "vm": {
-            }
-        },
-        {
-            "vm": {
-                "memory_mb": 4096
-            }
-        }
-    ]
-}
\ No newline at end of file
diff --git a/host/commands/cvd_load_tester/mvp_features/vm/memory_mb/TC2.json b/host/commands/cvd_load_tester/mvp_features/vm/memory_mb/TC2.json
deleted file mode 100644
index c2a0730..0000000
--- a/host/commands/cvd_load_tester/mvp_features/vm/memory_mb/TC2.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "memory_mb": 4096
-            }
-        },
-        {
-            "vm": {
-                "memory_mb": 8192
-            }
-        }
-    ]
-}
\ No newline at end of file
diff --git a/host/commands/cvd_load_tester/mvp_features/vm/setupwizard_mode/TC1.json b/host/commands/cvd_load_tester/mvp_features/vm/setupwizard_mode/TC1.json
deleted file mode 100644
index aba722d..0000000
--- a/host/commands/cvd_load_tester/mvp_features/vm/setupwizard_mode/TC1.json
+++ /dev/null
@@ -1,13 +0,0 @@
-
-  {
-    "instances" :
-    [
-        {
-            "vm": {
-                "crosvm":{
-                },
-                "setupwizard_mode": "ENABLED"
-            }
-        }
-    ]
-}
\ No newline at end of file
diff --git a/host/commands/cvd_load_tester/mvp_features/vm/setupwizard_mode/TC2.json b/host/commands/cvd_load_tester/mvp_features/vm/setupwizard_mode/TC2.json
deleted file mode 100644
index eb8815d..0000000
--- a/host/commands/cvd_load_tester/mvp_features/vm/setupwizard_mode/TC2.json
+++ /dev/null
@@ -1,18 +0,0 @@
-
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "crosvm":{
-                }
-            }
-        },
-        {
-            "vm": {
-                "crosvm":{
-                }
-            }
-        }
-    ]
-}
\ No newline at end of file
diff --git a/host/commands/cvd_load_tester/mvp_features/vm/setupwizard_mode/TC3.json b/host/commands/cvd_load_tester/mvp_features/vm/setupwizard_mode/TC3.json
deleted file mode 100644
index 4b19f60..0000000
--- a/host/commands/cvd_load_tester/mvp_features/vm/setupwizard_mode/TC3.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "crosvm":{
-                }
-            }
-        },
-        {
-            "vm": {
-                "crosvm":{
-                },
-                "setupwizard_mode": "REQUIRED"
-            }
-        }
-    ]
-}
-
diff --git a/host/commands/cvd_load_tester/mvp_features/vm/setupwizard_mode/TC4.json b/host/commands/cvd_load_tester/mvp_features/vm/setupwizard_mode/TC4.json
deleted file mode 100644
index d052087..0000000
--- a/host/commands/cvd_load_tester/mvp_features/vm/setupwizard_mode/TC4.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "crosvm":{
-                },
-                "setupwizard_mode": "OPTIONAL"
-            }
-        },
-        {
-            "vm": {
-                "crosvm":{
-                },
-                "setupwizard_mode": "REQUIRED"
-            }
-        }
-    ]
-}
diff --git a/host/commands/cvd_load_tester/mvp_features/vm/vm_manager/TC1.json b/host/commands/cvd_load_tester/mvp_features/vm/vm_manager/TC1.json
deleted file mode 100644
index 01e4963..0000000
--- a/host/commands/cvd_load_tester/mvp_features/vm/vm_manager/TC1.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "vm": {
-            }
-        },
-        {
-        }
-    ]
-}
\ No newline at end of file
diff --git a/host/commands/cvd_load_tester/mvp_features/vm/vm_manager/TC2.json b/host/commands/cvd_load_tester/mvp_features/vm/vm_manager/TC2.json
deleted file mode 100644
index 9b25147..0000000
--- a/host/commands/cvd_load_tester/mvp_features/vm/vm_manager/TC2.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "qemu":{
-                }
-            }
-        },
-        {
-            "vm": {
-                "crosvm":{
-                }
-            }
-        }
-    ]
-}
\ No newline at end of file
diff --git a/host/commands/cvd_load_tester/mvp_features/vm/vm_manager/TC3.json b/host/commands/cvd_load_tester/mvp_features/vm/vm_manager/TC3.json
deleted file mode 100644
index fe2d4ec..0000000
--- a/host/commands/cvd_load_tester/mvp_features/vm/vm_manager/TC3.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "vm": {
-                "crosvm":{
-                }
-            }
-        },
-        {
-            "vm": {
-                "gem5":{
-                }
-            }
-        }
-    ]
-}
\ No newline at end of file
diff --git a/host/commands/cvd_load_tester/templates_inheritance/custom/TC1.json b/host/commands/cvd_load_tester/templates_inheritance/custom/TC1.json
deleted file mode 100644
index 60fae2c..0000000
--- a/host/commands/cvd_load_tester/templates_inheritance/custom/TC1.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "@import" : "phone",
-            "vm": {
-                "memory_mb": 4096
-            }
-        }
-    ]
-}
diff --git a/host/commands/cvd_load_tester/templates_inheritance/custom/TC2.json b/host/commands/cvd_load_tester/templates_inheritance/custom/TC2.json
deleted file mode 100644
index 280d7f3..0000000
--- a/host/commands/cvd_load_tester/templates_inheritance/custom/TC2.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "@import" : "phone",
-            "vm": {
-                "memory_mb": 4096
-            }
-        },
-        {
-            "@import" : "tablet",
-            "vm": {
-                "memory_mb": 8192,
-                "cpus": 4
-            }
-        }
-    ]
-}
diff --git a/host/commands/cvd_load_tester/templates_inheritance/multi/TC1.json b/host/commands/cvd_load_tester/templates_inheritance/multi/TC1.json
deleted file mode 100644
index 7c4b158..0000000
--- a/host/commands/cvd_load_tester/templates_inheritance/multi/TC1.json
+++ /dev/null
@@ -1,26 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "@import" : "auto"
-        },
-        {
-            "@import" : "go"
-        },
-        {
-            "@import" : "phone"
-        },
-        {
-            "@import" : "slim"
-        },
-                {
-            "@import" : "tablet"
-        },
-                {
-            "@import" : "tv"
-        },
-        {
-            "@import" : "wearable"
-        }
-    ]
-}
diff --git a/host/commands/cvd_load_tester/templates_inheritance/multi/TC2.json b/host/commands/cvd_load_tester/templates_inheritance/multi/TC2.json
deleted file mode 100644
index bb4c7fb..0000000
--- a/host/commands/cvd_load_tester/templates_inheritance/multi/TC2.json
+++ /dev/null
@@ -1,29 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "@import" : "auto"
-        },
-                {
-            "@import" : "foldable"
-        },
-        {
-            "@import" : "go"
-        },
-        {
-            "@import" : "phone"
-        },
-        {
-            "@import" : "slim"
-        },
-                {
-            "@import" : "tablet"
-        },
-                {
-            "@import" : "tv"
-        },
-        {
-            "@import" : "wearable"
-        }
-    ]
-}
diff --git a/host/commands/cvd_load_tester/templates_inheritance/single/TC_auto.json b/host/commands/cvd_load_tester/templates_inheritance/single/TC_auto.json
deleted file mode 100644
index ded6c15..0000000
--- a/host/commands/cvd_load_tester/templates_inheritance/single/TC_auto.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "@import" : "auto"
-        }
-    ]
-}
diff --git a/host/commands/cvd_load_tester/templates_inheritance/single/TC_foldable.json b/host/commands/cvd_load_tester/templates_inheritance/single/TC_foldable.json
deleted file mode 100644
index 1df8e1a..0000000
--- a/host/commands/cvd_load_tester/templates_inheritance/single/TC_foldable.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "@import" : "foldable"
-        }
-    ]
-}
diff --git a/host/commands/cvd_load_tester/templates_inheritance/single/TC_go.json b/host/commands/cvd_load_tester/templates_inheritance/single/TC_go.json
deleted file mode 100644
index b554eaa..0000000
--- a/host/commands/cvd_load_tester/templates_inheritance/single/TC_go.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "@import" : "go"
-        }
-    ]
-}
diff --git a/host/commands/cvd_load_tester/templates_inheritance/single/TC_phone.json b/host/commands/cvd_load_tester/templates_inheritance/single/TC_phone.json
deleted file mode 100644
index 13c5f4b..0000000
--- a/host/commands/cvd_load_tester/templates_inheritance/single/TC_phone.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "@import" : "phone"
-        }
-    ]
-}
diff --git a/host/commands/cvd_load_tester/templates_inheritance/single/TC_slim.json b/host/commands/cvd_load_tester/templates_inheritance/single/TC_slim.json
deleted file mode 100644
index a0ab45f..0000000
--- a/host/commands/cvd_load_tester/templates_inheritance/single/TC_slim.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "@import" : "slim"
-        }
-    ]
-}
diff --git a/host/commands/cvd_load_tester/templates_inheritance/single/TC_tablet.json b/host/commands/cvd_load_tester/templates_inheritance/single/TC_tablet.json
deleted file mode 100644
index f62fcee..0000000
--- a/host/commands/cvd_load_tester/templates_inheritance/single/TC_tablet.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "@import" : "tablet"
-        }
-    ]
-}
diff --git a/host/commands/cvd_load_tester/templates_inheritance/single/TC_tv.json b/host/commands/cvd_load_tester/templates_inheritance/single/TC_tv.json
deleted file mode 100644
index bfbae34..0000000
--- a/host/commands/cvd_load_tester/templates_inheritance/single/TC_tv.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "@import" : "tv"
-        }
-    ]
-}
diff --git a/host/commands/cvd_load_tester/templates_inheritance/single/TC_wear.json b/host/commands/cvd_load_tester/templates_inheritance/single/TC_wear.json
deleted file mode 100644
index 06c85ab..0000000
--- a/host/commands/cvd_load_tester/templates_inheritance/single/TC_wear.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "instances" :
-    [
-        {
-            "@import" : "wearable"
-        }
-    ]
-}
diff --git a/host/commands/cvd_send_sms/Android.bp b/host/commands/cvd_send_sms/Android.bp
index 739aecd..d280cd6 100644
--- a/host/commands/cvd_send_sms/Android.bp
+++ b/host/commands/cvd_send_sms/Android.bp
@@ -28,7 +28,7 @@
     defaults: ["cuttlefish_buildhost_only"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcvd_send_sms",
     srcs: [
         "sms_sender.cc",
diff --git a/host/commands/cvd_send_sms/main.cc b/host/commands/cvd_send_sms/main.cc
index 8ada47d..19efe14 100644
--- a/host/commands/cvd_send_sms/main.cc
+++ b/host/commands/cvd_send_sms/main.cc
@@ -13,13 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include "gflags/gflags.h"
 
-#include "android-base/logging.h"
+#include <android-base/logging.h>
+#include <gflags/gflags.h>
+
 #include "common/libs/fs/shared_fd.h"
 #include "host/commands/cvd_send_sms/sms_sender.h"
 
-const std::string kUsage = R"(
+constexpr char kUsage[] = R"(
 NAME
     cvd_send_sms - send SMSs to cvds.
 
diff --git a/host/commands/cvd_update_location/Android.bp b/host/commands/cvd_update_location/Android.bp
index 7b9bf66..19fb4e9 100644
--- a/host/commands/cvd_update_location/Android.bp
+++ b/host/commands/cvd_update_location/Android.bp
@@ -23,7 +23,6 @@
         "libbase",
         "libcuttlefish_fs",
         "liblog",
-        "libicuuc",
         "libprotobuf-cpp-full",
         "libgrpc++_unsecure",
     ],
@@ -54,4 +53,9 @@
         "-D_XOPEN_SOURCE",
     ],
     defaults: ["cvd_update_location_defaults"],
-}
\ No newline at end of file
+    target: {
+        darwin: {
+            enabled: true,
+        },
+    },
+}
diff --git a/host/commands/display/main.cpp b/host/commands/display/main.cpp
index 87f1dab..d41ba78 100644
--- a/host/commands/display/main.cpp
+++ b/host/commands/display/main.cpp
@@ -189,9 +189,9 @@
   const std::vector<Flag> remove_displays_flags = {
       GflagsCompatFlag(kDisplayFlag)
           .Help("Display id of a display to remove.")
-          .Setter([&](const FlagMatch& match) {
+          .Setter([&](const FlagMatch& match) -> Result<void> {
             displays.push_back(match.value);
-            return true;
+            return {};
           }),
   };
   auto parse_res = ParseFlags(remove_displays_flags, args);
diff --git a/host/commands/echo_server/Android.bp b/host/commands/echo_server/Android.bp
index a69ba62..504d6c8 100644
--- a/host/commands/echo_server/Android.bp
+++ b/host/commands/echo_server/Android.bp
@@ -16,7 +16,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_host_static {
+cc_library {
     name: "libecho_server",
     shared_libs: [
         "libprotobuf-cpp-full",
@@ -42,6 +42,11 @@
         "external/grpc-grpc/include",
         "external/protobuf/src",
     ],
+    target: {
+        darwin: {
+            enabled: true,
+        },
+    },
 }
 
 cc_binary_host {
@@ -63,6 +68,11 @@
         "-Wno-unused-parameter",
     ],
     defaults: ["cuttlefish_host"],
+    target: {
+        darwin: {
+            enabled: true,
+        },
+    },
 }
 
 filegroup {
diff --git a/host/commands/gnss_grpc_proxy/Android.bp b/host/commands/gnss_grpc_proxy/Android.bp
index 58fd6a1..2b4ac84 100644
--- a/host/commands/gnss_grpc_proxy/Android.bp
+++ b/host/commands/gnss_grpc_proxy/Android.bp
@@ -17,7 +17,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcvd_gnss_grpc_proxy",
     shared_libs: [
         "libbase",
@@ -49,6 +49,11 @@
         "external/grpc-grpc/include",
         "external/protobuf/src",
     ],
+    target: {
+        darwin: {
+            enabled: true,
+        },
+    },
 }
 
 cc_binary_host {
@@ -75,6 +80,11 @@
         "-D_XOPEN_SOURCE",
     ],
     defaults: ["cuttlefish_host"],
+    target: {
+        darwin: {
+            enabled: true,
+        },
+    },
 }
 
 filegroup {
diff --git a/host/commands/health/Android.bp b/host/commands/health/Android.bp
index 142c79f..2ebb022 100644
--- a/host/commands/health/Android.bp
+++ b/host/commands/health/Android.bp
@@ -36,5 +36,5 @@
         "libcuttlefish_vm_manager",
         "libgflags",
     ],
-    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
+    defaults: ["cuttlefish_host"],
 }
diff --git a/host/commands/health/health.cpp b/host/commands/health/health.cpp
index aad9869..9bb01a2 100644
--- a/host/commands/health/health.cpp
+++ b/host/commands/health/health.cpp
@@ -28,7 +28,7 @@
       "crosvm_control.sock");
 }
 
-std::string USAGE_MESSAGE =
+static constexpr char kUsageMessage[] =
     "<key> [value]\n"
     "Excluding the value will enumerate the possible values to set\n"
     "\n"
@@ -74,13 +74,13 @@
 }
 
 int usage() {
-  std::cout << "health " << USAGE_MESSAGE;
+  std::cout << "health " << kUsageMessage;
   return 1;
 }
 
 int main(int argc, char** argv) {
   ::android::base::InitLogging(argv, android::base::StderrLogger);
-  gflags::SetUsageMessage(USAGE_MESSAGE);
+  gflags::SetUsageMessage(kUsageMessage);
 
   auto config = cuttlefish::CuttlefishConfig::Get();
   if (!config) {
diff --git a/host/commands/host_bugreport/Android.bp b/host/commands/host_bugreport/Android.bp
index 392f104..1f87457 100644
--- a/host/commands/host_bugreport/Android.bp
+++ b/host/commands/host_bugreport/Android.bp
@@ -38,5 +38,5 @@
         "libcuttlefish_vm_manager",
         "libgflags",
     ],
-    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
+    defaults: ["cuttlefish_host"],
 }
diff --git a/host/commands/kernel_log_monitor/kernel_log_server.cc b/host/commands/kernel_log_monitor/kernel_log_server.cc
index a67d0f9..2ced97a 100644
--- a/host/commands/kernel_log_monitor/kernel_log_server.cc
+++ b/host/commands/kernel_log_monitor/kernel_log_server.cc
@@ -57,7 +57,8 @@
     {cuttlefish::kWifiConnectedMessage, Event::WifiNetworkConnected, kBare},
     {cuttlefish::kEthernetConnectedMessage, Event::EthernetNetworkConnected, kBare},
     {cuttlefish::kAdbdStartedMessage, Event::AdbdStarted, kBare},
-    {cuttlefish::kFastbootdStartedMessage, Event::FastbootdStarted, kBare},
+    {cuttlefish::kFastbootdStartedMessage, Event::FastbootStarted, kBare},
+    {cuttlefish::kFastbootStartedMessage, Event::FastbootStarted, kBare},
     {cuttlefish::kScreenChangedMessage, Event::ScreenChanged, kKeyValuePair},
     {cuttlefish::kBootloaderLoadedMessage, Event::BootloaderLoaded, kBare},
     {cuttlefish::kKernelLoadedMessage, Event::KernelLoaded, kBare},
diff --git a/host/commands/kernel_log_monitor/kernel_log_server.h b/host/commands/kernel_log_monitor/kernel_log_server.h
index cdbd9f0..ec33f71 100644
--- a/host/commands/kernel_log_monitor/kernel_log_server.h
+++ b/host/commands/kernel_log_monitor/kernel_log_server.h
@@ -42,7 +42,7 @@
                          * that we're booting a device.
                          */
   DisplayPowerModeChanged = 10,
-  FastbootdStarted = 11
+  FastbootStarted = 11
 };
 
 enum class SubscriptionAction {
diff --git a/host/commands/log_tee/Android.bp b/host/commands/log_tee/Android.bp
index 72bc93d..ca2ea98 100644
--- a/host/commands/log_tee/Android.bp
+++ b/host/commands/log_tee/Android.bp
@@ -30,12 +30,16 @@
         "libcuttlefish_utils",
         "libfruit",
         "libjsoncpp",
-        "libnl",
     ],
     static_libs: [
         "libgflags",
         "libcuttlefish_host_config",
         "libcuttlefish_vm_manager",
     ],
-    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
+    target: {
+        darwin: {
+            enabled: true,
+        },
+    },
+    defaults: ["cuttlefish_host"],
 }
diff --git a/host/commands/log_tee/log_tee.cpp b/host/commands/log_tee/log_tee.cpp
index cdfc4a0..3c3661f 100644
--- a/host/commands/log_tee/log_tee.cpp
+++ b/host/commands/log_tee/log_tee.cpp
@@ -14,7 +14,9 @@
 // limitations under the License.
 
 #include <signal.h>
+#ifdef __linux__
 #include <sys/signalfd.h>
+#endif
 
 #include <regex>
 
@@ -84,10 +86,12 @@
   sigaddset(&mask, SIGINT);
   CHECK(sigprocmask(SIG_BLOCK, &mask, NULL) == 0)
       << "sigprocmask failed: " << strerror(errno);
+#ifdef __linux__
   int sfd = signalfd(-1, &mask, 0);
   CHECK(sfd >= 0) << "signalfd failed: " << strerror(errno);
   auto int_fd = cuttlefish::SharedFD::Dup(sfd);
   close(sfd);
+#endif
 
   auto poll_fds = std::vector<cuttlefish::PollSharedFd>{
       cuttlefish::PollSharedFd{
@@ -95,11 +99,13 @@
           .events = POLL_IN,
           .revents = 0,
       },
+#ifdef __linux__
       cuttlefish::PollSharedFd{
           .fd = int_fd,
           .events = POLL_IN,
           .revents = 0,
       },
+#endif
   };
 
   LOG(DEBUG) << "Starting to read from process " << FLAGS_process_name;
@@ -168,6 +174,7 @@
       // handle any signals yet.
       continue;
     }
+#ifdef __linux__
     if (poll_fds[1].revents) {
       struct signalfd_siginfo siginfo;
       int s = int_fd->Read(&siginfo, sizeof(siginfo));
@@ -177,6 +184,7 @@
           << "unexpected signal: " << siginfo.ssi_signo;
       break;
     }
+#endif
   }
 
   LOG(DEBUG) << "Finished reading from process " << FLAGS_process_name;
diff --git a/host/commands/mkenvimage_slim/Android.bp b/host/commands/mkenvimage_slim/Android.bp
index ead2647..53656c9 100644
--- a/host/commands/mkenvimage_slim/Android.bp
+++ b/host/commands/mkenvimage_slim/Android.bp
@@ -19,7 +19,7 @@
 
 cc_binary {
     name: "mkenvimage_slim",
-    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
+    defaults: ["cuttlefish_host"],
     srcs: [
         "mkenvimage_slim.cc",
     ],
diff --git a/host/commands/mkenvimage_slim/mkenvimage_slim.cc b/host/commands/mkenvimage_slim/mkenvimage_slim.cc
index 704d429..bffd3a0 100644
--- a/host/commands/mkenvimage_slim/mkenvimage_slim.cc
+++ b/host/commands/mkenvimage_slim/mkenvimage_slim.cc
@@ -17,8 +17,6 @@
 // https://github.com/u-boot/u-boot/blob/master/tools/mkenvimage.c The bare
 // minimum amount of functionality for our application is replicated.
 
-#include <iostream>
-
 #include <zlib.h>
 
 #include <android-base/logging.h>
@@ -40,19 +38,18 @@
 DEFINE_string(output_path, "", "output file path");
 DEFINE_string(input_path, "", "input file path");
 namespace cuttlefish {
-namespace {
-std::string USAGE_MESSAGE =
+
+static constexpr char kUsageMessage[] =
     "<flags>\n"
     "\n"
     "env_size - length in bytes of the resulting env image. Defaults to 4kb.\n"
     "input_path - path to input key value mapping as a text file\n"
     "output_path - path to write resulting environment image including CRC "
     "to\n";
-}  // namespace
 
 Result<int> MkenvimageSlimMain(int argc, char** argv) {
   ::android::base::InitLogging(argv, android::base::StderrLogger);
-  gflags::SetUsageMessage(USAGE_MESSAGE);
+  gflags::SetUsageMessage(kUsageMessage);
   gflags::ParseCommandLineFlags(&argc, &argv, true);
   CF_EXPECT(FLAGS_output_path != "", "Output env path isn't defined.");
   CF_EXPECT(FLAGS_env_size != 0, "env size can't be 0.");
diff --git a/host/commands/modem_simulator/call_service.cpp b/host/commands/modem_simulator/call_service.cpp
index 7e40870..c809e03 100644
--- a/host/commands/modem_simulator/call_service.cpp
+++ b/host/commands/modem_simulator/call_service.cpp
@@ -189,6 +189,7 @@
     ss << port;
     auto remote_port = ss.str();
     auto remote_client = ConnectToRemoteCvd(remote_port);
+    auto client_id = ClientId();
     if (!remote_client->IsOpen()) {
       client.SendCommandResponse(kCmeErrorNoNetworkService);
       return;
@@ -200,21 +201,21 @@
     }
 
     if (channel_monitor_) {
-      channel_monitor_->SetRemoteClient(remote_client, false);
+      client_id = channel_monitor_->SetRemoteClient(remote_client, false);
     }
 
     ss.clear();
     ss.str("");
     ss << "AT+REMOTECALL=4,0,0,\"" << local_host_port << "\",129";
 
-    SendCommandToRemote(remote_client, "REM0");
-    SendCommandToRemote(remote_client, ss.str());
+    SendCommandToRemote(client_id, "REM0");
+    SendCommandToRemote(client_id, ss.str());
 
     CallStatus call_status(remote_port);
     call_status.is_remote_call = true;
     call_status.is_mobile_terminated = false;
     call_status.call_state = CallStatus::CALL_STATE_DIALING;
-    call_status.remote_client = remote_client;
+    call_status.remote_client = client_id;
     auto index = FindFreeCallIndex();
 
     auto call_token = std::make_pair(index, call_status.number);
@@ -693,7 +694,7 @@
       if (network_service_) {
         if (network_service_->isRadioOff()) {
           LOG(DEBUG) << " radio is off, reject incoming call from: " << number;
-          client.client_fd->Close();
+          network_service_->CloseRemoteConnection(client.Id());
           return;
         }
       }
@@ -703,7 +704,7 @@
       call_status.is_multi_party = mpty;
       call_status.is_mobile_terminated = true;
       call_status.is_international = (num_type == 145);
-      call_status.remote_client = client.client_fd;
+      call_status.remote_client = client.Id();
       call_status.call_state = CallStatus::CALL_STATE_INCOMING;
 
       auto index = FindFreeCallIndex();
diff --git a/host/commands/modem_simulator/call_service.h b/host/commands/modem_simulator/call_service.h
index f57eb05..c3396c0 100644
--- a/host/commands/modem_simulator/call_service.h
+++ b/host/commands/modem_simulator/call_service.h
@@ -135,7 +135,7 @@
     bool is_voice_mode;
     bool is_multi_party;
     bool is_remote_call;
-    std::optional<cuttlefish::SharedFD> remote_client;
+    std::optional<ClientId> remote_client;
     std::optional<int32_t> timeout_serial;
     std::string number;
     bool can_present_number;
diff --git a/host/commands/modem_simulator/channel_monitor.cpp b/host/commands/modem_simulator/channel_monitor.cpp
index 31bc5f3..2dc032c 100644
--- a/host/commands/modem_simulator/channel_monitor.cpp
+++ b/host/commands/modem_simulator/channel_monitor.cpp
@@ -16,20 +16,33 @@
 
 #include "host/commands/modem_simulator/channel_monitor.h"
 
+#include <algorithm>
+
 #include <android-base/logging.h>
 #include <android-base/strings.h>
 
-#include <algorithm>
-
+#include "common/libs/fs/shared_buf.h"
+#include "common/libs/fs/shared_select.h"
 #include "host/commands/modem_simulator/modem_simulator.h"
 
 namespace cuttlefish {
 
 constexpr int32_t kMaxCommandLength = 4096;
 
-Client::Client(cuttlefish::SharedFD fd) : client_fd(fd) {}
+size_t ClientId::next_id_ = 0;
 
-Client::Client(cuttlefish::SharedFD fd, ClientType client_type)
+ClientId::ClientId() {
+  id_ = next_id_;
+  next_id_++;
+}
+
+bool ClientId::operator==(const ClientId& other) const {
+  return id_ == other.id_;
+}
+
+Client::Client(SharedFD fd) : client_fd(fd) {}
+
+Client::Client(SharedFD fd, ClientType client_type)
     : type(client_type), client_fd(fd) {}
 
 bool Client::operator==(const Client& other) const {
@@ -47,8 +60,8 @@
   }
   LOG(VERBOSE) << " AT< " << response;
 
-  std::lock_guard<std::mutex> autolock(const_cast<Client*>(this)->write_mutex);
-  client_fd->Write(response.data(), response.size());
+  std::lock_guard<std::mutex> lock(write_mutex);
+  WriteAll(client_fd, response);
 }
 
 void Client::SendCommandResponse(
@@ -58,19 +71,20 @@
   }
 }
 
-ChannelMonitor::ChannelMonitor(ModemSimulator* modem,
-                               cuttlefish::SharedFD server)
-    : modem_(modem), server_(server) {
-  if (!cuttlefish::SharedFD::Pipe(&read_pipe_, &write_pipe_)) {
+ChannelMonitor::ChannelMonitor(ModemSimulator& modem, SharedFD server)
+    : modem_(modem), server_(std::move(server)) {
+  if (!SharedFD::Pipe(&read_pipe_, &write_pipe_)) {
     LOG(ERROR) << "Unable to create pipe, ignore";
   }
 
-  if (server_->IsOpen())
+  if (server_->IsOpen()) {
     monitor_thread_ = std::thread([this]() { MonitorLoop(); });
+  }
 }
 
-void ChannelMonitor::SetRemoteClient(cuttlefish::SharedFD client, bool is_accepted) {
+ClientId ChannelMonitor::SetRemoteClient(SharedFD client, bool is_accepted) {
   auto remote_client = std::make_unique<Client>(client, Client::REMOTE);
+  auto id = remote_client->Id();
 
   if (is_accepted) {
     // There may be new data from remote client before select.
@@ -90,10 +104,11 @@
   } else {
     LOG(ERROR) << "Pipe created fail, can't trigger monitor loop";
   }
+  return id;
 }
 
 void ChannelMonitor::AcceptIncomingConnection() {
-  auto client_fd  = cuttlefish::SharedFD::Accept(*server_);
+  auto client_fd = SharedFD::Accept(*server_);
   if (!client_fd->IsOpen()) {
     LOG(ERROR) << "Error accepting connection on socket: " << client_fd->StrError();
   } else {
@@ -102,7 +117,7 @@
     clients_.push_back(std::move(client));
     if (clients_.size() == 1) {
       // The first connected client default to be the unsolicited commands channel
-      modem_->OnFirstClientConnected();
+      modem_.OnFirstClientConnected();
     }
   }
 }
@@ -145,7 +160,7 @@
   // Split into commands and dispatch
   size_t pos = 0, r_pos = 0;  // '\r' or '\n'
   while (r_pos != std::string::npos) {
-    if (modem_->IsWaitingSmsPdu()) {
+    if (modem_.IsWaitingSmsPdu()) {
       r_pos = commands.find('\032', pos);  // In sms, find ctrl-z
     } else {
       r_pos = commands.find('\r', pos);
@@ -154,7 +169,7 @@
       auto command = commands.substr(pos, r_pos - pos);
       if (command.size() > 0) {  // "\r\r" ?
         LOG(VERBOSE) << "AT> " << command;
-        modem_->DispatchCommand(client, command);
+        modem_.DispatchCommand(client, command);
       }
       pos = r_pos + 1;  // Skip '\r'
     } else if (pos < commands.length()) {  // Incomplete command
@@ -174,10 +189,10 @@
   }
 }
 
-void ChannelMonitor::SendRemoteCommand(cuttlefish::SharedFD client, std::string& response) {
+void ChannelMonitor::SendRemoteCommand(ClientId client, std::string& response) {
   auto iter = remote_clients_.begin();
   for (; iter != remote_clients_.end(); ++iter) {
-    if (iter->get()->client_fd == client) {
+    if (iter->get()->Id() == client) {
       iter->get()->SendCommandResponse(response);
       return;
     }
@@ -185,10 +200,10 @@
   LOG(DEBUG) << "Remote client has closed.";
 }
 
-void ChannelMonitor::CloseRemoteConnection(cuttlefish::SharedFD client) {
+void ChannelMonitor::CloseRemoteConnection(ClientId client) {
   auto iter = remote_clients_.begin();
   for (; iter != remote_clients_.end(); ++iter) {
-    if (iter->get()->client_fd == client) {
+    if (iter->get()->Id() == client) {
       iter->get()->client_fd->Close();
       iter->get()->is_valid = false;
 
@@ -216,7 +231,8 @@
   }
 }
 
-static void removeInvalidClients(std::vector<std::unique_ptr<Client>>& clients) {
+void ChannelMonitor::removeInvalidClients(
+    std::vector<std::unique_ptr<Client>>& clients) {
   auto iter = clients.begin();
   for (; iter != clients.end();) {
     if (iter->get()->is_valid) {
diff --git a/host/commands/modem_simulator/channel_monitor.h b/host/commands/modem_simulator/channel_monitor.h
index 6dc7c4a..1e86bf5 100644
--- a/host/commands/modem_simulator/channel_monitor.h
+++ b/host/commands/modem_simulator/channel_monitor.h
@@ -19,7 +19,9 @@
 #include <thread>
 #include <vector>
 
-#include "common/libs/fs/shared_select.h"
+#include "common/libs/fs/shared_fd.h"
+
+class ModemServiceTest;
 
 namespace cuttlefish {
 
@@ -31,6 +33,17 @@
   kServerError = 2,
 };
 
+class ClientId {
+ public:
+  ClientId();
+
+  bool operator==(const ClientId&) const;
+
+ private:
+  static size_t next_id_;
+  size_t id_;
+};
+
 /**
  * Client object managed by ChannelMonitor, contains two types, the RIL client
  * and the remote client of other cuttlefish instance.
@@ -41,17 +54,10 @@
  public:
   enum ClientType { RIL, REMOTE };
 
-  ClientType type = RIL;
-  cuttlefish::SharedFD client_fd;
-  std::string incomplete_command;
-  std::mutex write_mutex;
-  bool first_read_command_;  // Only used when ClientType::REMOTE
-  bool is_valid = true;
-
   Client() = default;
   ~Client() = default;
-  Client(cuttlefish::SharedFD fd);
-  Client(cuttlefish::SharedFD fd, ClientType client_type);
+  Client(SharedFD fd);
+  Client(SharedFD fd, ClientType client_type);
   Client(const Client& client) = delete;
   Client(Client&& client) = delete;
 
@@ -61,25 +67,40 @@
 
   void SendCommandResponse(std::string response) const;
   void SendCommandResponse(const std::vector<std::string>& responses) const;
+
+  ClientId Id() const { return id_; }
+  ClientType Type() const { return type; }
+
+ private:
+  friend class ChannelMonitor;
+  friend class ::ModemServiceTest;
+
+  ClientId id_;
+  ClientType type = RIL;
+  SharedFD client_fd;
+  std::string incomplete_command;
+  mutable std::mutex write_mutex;
+  bool first_read_command_;  // Only used when ClientType::REMOTE
+  bool is_valid = true;
 };
 
 class ChannelMonitor {
  public:
-  ChannelMonitor(ModemSimulator* modem, cuttlefish::SharedFD server);
+  ChannelMonitor(ModemSimulator& modem, cuttlefish::SharedFD server);
   ~ChannelMonitor();
 
   ChannelMonitor(const ChannelMonitor&) = delete;
   ChannelMonitor& operator=(const ChannelMonitor&) = delete;
 
-  void SetRemoteClient(cuttlefish::SharedFD client,  bool is_accepted);
-  void SendRemoteCommand(cuttlefish::SharedFD client, std::string& response);
-  void CloseRemoteConnection(cuttlefish::SharedFD client);
+  ClientId SetRemoteClient(SharedFD client, bool is_accepted);
+  void SendRemoteCommand(ClientId client, std::string& response);
+  void CloseRemoteConnection(ClientId client);
 
   // For modem services to send unsolicited commands
   void SendUnsolicitedCommand(std::string& response);
 
  private:
-  ModemSimulator* modem_;
+  ModemSimulator& modem_;
   std::thread monitor_thread_;
   cuttlefish::SharedFD server_;
   cuttlefish::SharedFD read_pipe_;
@@ -92,6 +113,8 @@
   void ReadCommand(Client& client);
 
   void MonitorLoop();
+  static void removeInvalidClients(
+      std::vector<std::unique_ptr<Client>>& clients);
 };
 
 }  // namespace cuttlefish
diff --git a/host/commands/modem_simulator/main.cpp b/host/commands/modem_simulator/main.cpp
index 41ab6ce..a979c36 100644
--- a/host/commands/modem_simulator/main.cpp
+++ b/host/commands/modem_simulator/main.cpp
@@ -13,16 +13,16 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include <android-base/strings.h>
-#include <gflags/gflags.h>
 #include <signal.h>
 #include <unistd.h>
 
-#include <limits>
+#include <android-base/strings.h>
+#include <fmt/format.h>
+#include <gflags/gflags.h>
 
-#include "common/libs/device_config/device_config.h"
 #include "common/libs/fs/shared_buf.h"
 #include "common/libs/fs/shared_fd.h"
+#include "common/libs/fs/shared_select.h"
 #include "common/libs/utils/tee_logging.h"
 #include "host/commands/modem_simulator/modem_simulator.h"
 #include "host/libs/config/cuttlefish_config.h"
@@ -33,7 +33,10 @@
 DEFINE_string(server_fds, "", "A comma separated list of file descriptors");
 DEFINE_int32(sim_type, 1, "Sim type: 1 for normal, 2 for CtsCarrierApiTestCases");
 
-std::vector<cuttlefish::SharedFD> ServerFdsFromCmdline() {
+namespace cuttlefish {
+namespace {
+
+std::vector<SharedFD> ServerFdsFromCmdline() {
   // Validate the parameter
   std::string fd_list = FLAGS_server_fds;
   for (auto c: fd_list) {
@@ -44,10 +47,10 @@
   }
 
   auto fds = android::base::Split(fd_list, ",");
-  std::vector<cuttlefish::SharedFD> shared_fds;
+  std::vector<SharedFD> shared_fds;
   for (auto& fd_str: fds) {
     auto fd = std::stoi(fd_str);
-    auto shared_fd = cuttlefish::SharedFD::Dup(fd);
+    auto shared_fd = SharedFD::Dup(fd);
     close(fd);
     shared_fds.push_back(shared_fd);
   }
@@ -55,12 +58,12 @@
   return shared_fds;
 }
 
-int main(int argc, char** argv) {
+int ModemSimulatorMain(int argc, char** argv) {
   ::android::base::InitLogging(argv, android::base::StderrLogger);
   google::ParseCommandLineFlags(&argc, &argv, false);
 
   // Modem simulator log saved in cuttlefish_runtime
-  auto config = cuttlefish::CuttlefishConfig::Get();
+  auto config = CuttlefishConfig::Get();
   auto instance = config->ForDefaultInstance();
 
   auto modem_log_path = instance.PerInstanceLogPath("modem_simulator.log");
@@ -68,7 +71,7 @@
   {
     auto log_path = instance.launcher_log_path();
     std::vector<std::string> log_files{log_path, modem_log_path};
-    android::base::SetLogger(cuttlefish::LogToStderrAndFiles(log_files));
+    android::base::SetLogger(LogToStderrAndFiles(log_files));
   }
 
   LOG(INFO) << "Start modem simulator, server_fds: " << FLAGS_server_fds
@@ -81,60 +84,58 @@
     return -1;
   }
 
-  cuttlefish::NvramConfig::InitNvramConfigService(server_fds.size(), FLAGS_sim_type);
+  NvramConfig::InitNvramConfigService(server_fds.size(), FLAGS_sim_type);
 
   // Don't get a SIGPIPE from the clients
   if (sigaction(SIGPIPE, nullptr, nullptr) != 0) {
     LOG(ERROR) << "Failed to set SIGPIPE to be ignored: " << strerror(errno);
   }
 
-  auto nvram_config = cuttlefish::NvramConfig::Get();
+  auto nvram_config = NvramConfig::Get();
   auto nvram_config_file = nvram_config->ConfigFileLocation();
 
   // Start channel monitor, wait for RIL to connect
   int32_t modem_id = 0;
-  std::vector<std::shared_ptr<cuttlefish::ModemSimulator>> modem_simulators;
+  std::vector<std::unique_ptr<ModemSimulator>> modem_simulators;
 
   for (auto& fd : server_fds) {
     CHECK(fd->IsOpen()) << "Error creating or inheriting modem simulator server: "
         << fd->StrError();
 
-    auto modem_simulator = std::make_shared<cuttlefish::ModemSimulator>(modem_id);
+    auto modem_simulator = std::make_unique<ModemSimulator>(modem_id);
     auto channel_monitor =
-        std::make_unique<cuttlefish::ChannelMonitor>(modem_simulator.get(), fd);
+        std::make_unique<ChannelMonitor>(*modem_simulator.get(), fd);
 
     modem_simulator->Initialize(std::move(channel_monitor));
 
-    modem_simulators.push_back(modem_simulator);
+    modem_simulators.emplace_back(std::move(modem_simulator));
 
     modem_id++;
   }
 
   // Monitor exit request and
   // remote call, remote sms from other cuttlefish instance
-  std::string monitor_socket_name = "modem_simulator";
-  std::stringstream ss;
-  ss << instance.modem_simulator_host_id();
-  monitor_socket_name.append(ss.str());
+  std::string monitor_socket_name =
+      fmt::format("modem_simulator{}", instance.modem_simulator_host_id());
 
-  auto monitor_socket = cuttlefish::SharedFD::SocketLocalServer(
-      monitor_socket_name.c_str(), true, SOCK_STREAM, 0666);
+  auto monitor_socket = SharedFD::SocketLocalServer(monitor_socket_name.c_str(),
+                                                    true, SOCK_STREAM, 0666);
   if (!monitor_socket->IsOpen()) {
     LOG(ERROR) << "Unable to create monitor socket for modem simulator";
-    std::exit(cuttlefish::kServerError);
+    std::exit(kServerError);
   }
 
   // Server loop
   while (true) {
-    cuttlefish::SharedFDSet read_set;
+    SharedFDSet read_set;
     read_set.Set(monitor_socket);
-    int num_fds = cuttlefish::Select(&read_set, nullptr, nullptr, nullptr);
+    int num_fds = Select(&read_set, nullptr, nullptr, nullptr);
     if (num_fds <= 0) {  // Ignore select error
       LOG(ERROR) << "Select call returned error : " << strerror(errno);
     } else if (read_set.IsSet(monitor_socket)) {
-      auto conn = cuttlefish::SharedFD::Accept(*monitor_socket);
+      auto conn = SharedFD::Accept(*monitor_socket);
       std::string buf(4, ' ');
-      auto read = cuttlefish::ReadExact(conn, &buf);
+      auto read = ReadExact(conn, &buf);
       if (read <= 0) {
         conn->Close();
         LOG(WARNING) << "Detected close from the other side";
@@ -143,11 +144,11 @@
       if (buf == "STOP") {  // Exit request from parent process
         LOG(INFO) << "Exit request from parent process";
         nvram_config->SaveToFile(nvram_config_file);
-        for (auto modem : modem_simulators) {
+        for (auto& modem : modem_simulators) {
           modem->SaveModemState();
         }
-        cuttlefish::WriteAll(conn, "OK"); // Ignore the return value. Exit anyway.
-        std::exit(cuttlefish::kSuccess);
+        WriteAll(conn, "OK");  // Ignore the return value. Exit anyway.
+        std::exit(kSuccess);
       } else if (buf.compare(0, 3, "REM") == 0) {  // REMO for modem id 0 ...
         // Remote request from other cuttlefish instance
         int id = std::stoi(buf.substr(3, 1));
@@ -161,3 +162,10 @@
   }
   // Until kill or exit
 }
+
+}  // namespace
+}  // namespace cuttlefish
+
+int main(int argc, char** argv) {
+  return cuttlefish::ModemSimulatorMain(argc, argv);
+}
diff --git a/host/commands/modem_simulator/modem_service.cpp b/host/commands/modem_simulator/modem_service.cpp
index 7996e31..ea32f16 100644
--- a/host/commands/modem_simulator/modem_service.cpp
+++ b/host/commands/modem_simulator/modem_service.cpp
@@ -15,39 +15,14 @@
 
 #include "host/commands/modem_simulator/modem_service.h"
 
-#include <android-base/logging.h>
-
 #include <cstring>
 
+#include <android-base/logging.h>
+
 #include "host/commands/modem_simulator/device_config.h"
 
 namespace cuttlefish {
 
-const std::string ModemService::kCmeErrorOperationNotAllowed      = "+CME ERROR: 3";
-const std::string ModemService::kCmeErrorOperationNotSupported    = "+CME ERROR: 4";
-const std::string ModemService::kCmeErrorSimNotInserted           = "+CME ERROR: 10";
-const std::string ModemService::kCmeErrorSimPinRequired           = "+CME ERROR: 11";
-const std::string ModemService::kCmeErrorSimPukRequired           = "+CME ERROR: 12";
-const std::string ModemService::kCmeErrorSimBusy                  = "+CME ERROR: 14";
-const std::string ModemService::kCmeErrorIncorrectPassword        = "+CME ERROR: 16";
-const std::string ModemService::kCmeErrorMemoryFull               = "+CME ERROR: 20";
-const std::string ModemService::kCmeErrorInvalidIndex             = "+CME ERROR: 21";
-const std::string ModemService::kCmeErrorNotFound                 = "+CME ERROR: 22";
-const std::string ModemService::kCmeErrorInvalidCharactersInTextString = "+CME ERROR: 27";
-const std::string ModemService::kCmeErrorNoNetworkService         = "+CME ERROR: 30";
-const std::string ModemService::kCmeErrorNetworkNotAllowedEmergencyCallsOnly = "+CME ERROR: 32";
-const std::string ModemService::kCmeErrorInCorrectParameters      = "+CME ERROR: 50";
-const std::string ModemService::kCmeErrorNetworkNotAttachedDueToMTFunctionalRestrictions = "+CME ERROR: 53";
-const std::string ModemService::kCmeErrorFixedDialNumberOnlyAllowed = "+CME ERROR: 56";
-
-const std::string ModemService::kCmsErrorOperationNotAllowed      = "+CMS ERROR: 302";
-const std::string ModemService::kCmsErrorOperationNotSupported    = "+CMS ERROR: 303";
-const std::string ModemService::kCmsErrorInvalidPDUModeParam      = "+CMS ERROR: 304";
-const std::string ModemService::kCmsErrorSCAddressUnknown         = "+CMS ERROR: 304";
-
-const std::pair<int, int> ModemService::kRemotePortRange =
-    std::make_pair(6520, 6527);
-
 CommandHandler::CommandHandler(const std::string& command, f_func handler)
     : command_prefix(command),
       match_mode(FULL_MATCH),
@@ -123,14 +98,15 @@
   return remote_sock;
 }
 
-void ModemService::SendCommandToRemote(cuttlefish::SharedFD remote_client, std::string response) {
+void ModemService::SendCommandToRemote(ClientId remote_client,
+                                       std::string response) {
   if (channel_monitor_) {
     channel_monitor_->SendRemoteCommand(remote_client, response);
     ;
   }
 }
 
-void ModemService::CloseRemoteConnection(cuttlefish::SharedFD remote_client) {
+void ModemService::CloseRemoteConnection(ClientId remote_client) {
   if (channel_monitor_) {
     channel_monitor_->CloseRemoteConnection(remote_client);
     ;
diff --git a/host/commands/modem_simulator/modem_service.h b/host/commands/modem_simulator/modem_service.h
index 744f618..bc85302 100644
--- a/host/commands/modem_simulator/modem_service.h
+++ b/host/commands/modem_simulator/modem_service.h
@@ -70,29 +70,36 @@
 
   bool HandleModemCommand(const Client& client, std::string command);
 
-  static const std::string kCmeErrorOperationNotAllowed;
-  static const std::string kCmeErrorOperationNotSupported;
-  static const std::string kCmeErrorSimNotInserted;
-  static const std::string kCmeErrorSimPinRequired;
-  static const std::string kCmeErrorSimPukRequired;
-  static const std::string kCmeErrorSimBusy;
-  static const std::string kCmeErrorIncorrectPassword;
-  static const std::string kCmeErrorMemoryFull;
-  static const std::string kCmeErrorInvalidIndex;
-  static const std::string kCmeErrorNotFound;
-  static const std::string kCmeErrorInvalidCharactersInTextString;
-  static const std::string kCmeErrorNoNetworkService;
-  static const std::string kCmeErrorNetworkNotAllowedEmergencyCallsOnly;
-  static const std::string kCmeErrorInCorrectParameters;
-  static const std::string kCmeErrorNetworkNotAttachedDueToMTFunctionalRestrictions;
-  static const std::string kCmeErrorFixedDialNumberOnlyAllowed;
+  static constexpr char kCmeErrorOperationNotAllowed[] = "+CME ERROR: 3";
+  static constexpr char kCmeErrorOperationNotSupported[] = "+CME ERROR: 4";
+  static constexpr char kCmeErrorSimNotInserted[] = "+CME ERROR: 10";
+  static constexpr char kCmeErrorSimPinRequired[] = "+CME ERROR: 11";
+  static constexpr char kCmeErrorSimPukRequired[] = "+CME ERROR: 12";
+  static constexpr char kCmeErrorSimBusy[] = "+CME ERROR: 14";
+  static constexpr char kCmeErrorIncorrectPassword[] = "+CME ERROR: 16";
+  static constexpr char kCmeErrorMemoryFull[] = "+CME ERROR: 20";
+  static constexpr char kCmeErrorInvalidIndex[] = "+CME ERROR: 21";
+  static constexpr char kCmeErrorNotFound[] = "+CME ERROR: 22";
+  static constexpr char kCmeErrorInvalidCharactersInTextString[] =
+      "+CME ERROR: 27";
+  static constexpr char kCmeErrorNoNetworkService[] = "+CME ERROR: 30";
+  static constexpr char kCmeErrorNetworkNotAllowedEmergencyCallsOnly[] =
+      "+CME ERROR: 32";
+  static constexpr char kCmeErrorInCorrectParameters[] = "+CME ERROR: 50";
+  static constexpr char
+      kCmeErrorNetworkNotAttachedDueToMTFunctionalRestrictions[] =
+          "+CME ERROR: 53";
+  static constexpr char kCmeErrorFixedDialNumberOnlyAllowed[] =
+      "+CME ERROR: 56";
 
-  static const std::string kCmsErrorOperationNotAllowed;
-  static const std::string kCmsErrorOperationNotSupported;
-  static const std::string kCmsErrorInvalidPDUModeParam;
-  static const std::string kCmsErrorSCAddressUnknown;
+  static constexpr char kCmsErrorOperationNotAllowed[] = "+CMS ERROR: 302";
+  static constexpr char kCmsErrorOperationNotSupported[] = "+CMS ERROR: 303";
+  static constexpr char kCmsErrorInvalidPDUModeParam[] = "+CMS ERROR: 304";
+  static constexpr char kCmsErrorSCAddressUnknown[] = "+CMS ERROR: 304";
 
-  static const std::pair<int, int> kRemotePortRange;
+  static constexpr std::pair<int, int> kRemotePortRange{6520, 6527};
+
+  void CloseRemoteConnection(ClientId remote_client);
 
  protected:
   ModemService(int32_t service_id, std::vector<CommandHandler> command_handlers,
@@ -101,9 +108,7 @@
   void SendUnsolicitedCommand(std::string unsol_command);
 
   cuttlefish::SharedFD ConnectToRemoteCvd(std::string port);
-  void SendCommandToRemote(cuttlefish::SharedFD remote_client,
-                           std::string response);
-  void CloseRemoteConnection(cuttlefish::SharedFD remote_client);
+  void SendCommandToRemote(ClientId remote_client, std::string response);
   static std::string GetHostId();
 
   int32_t service_id_;
diff --git a/host/commands/modem_simulator/modem_simulator.cpp b/host/commands/modem_simulator/modem_simulator.cpp
index ceb94a1..ed657ab 100644
--- a/host/commands/modem_simulator/modem_simulator.cpp
+++ b/host/commands/modem_simulator/modem_simulator.cpp
@@ -113,7 +113,7 @@
     }
   }
 
-  if (!success && client.type != Client::REMOTE) {
+  if (!success && client.Type() != Client::REMOTE) {
     LOG(DEBUG) << "Not supported AT command: " << command;
     client.SendCommandResponse(ModemService::kCmeErrorOperationNotSupported);
   }
diff --git a/host/commands/modem_simulator/nvram_config.cpp b/host/commands/modem_simulator/nvram_config.cpp
index f61f96f..ad06f94 100644
--- a/host/commands/modem_simulator/nvram_config.cpp
+++ b/host/commands/modem_simulator/nvram_config.cpp
@@ -20,26 +20,23 @@
 
 #include <fstream>
 #include <mutex>
-#include <sstream>
 
 #include "common/libs/utils/files.h"
 #include "host/commands/modem_simulator/device_config.h"
 
 namespace cuttlefish {
 
-const char* kInstances            = "instances";
-const char* kNetworkSelectionMode = "network_selection_mode";
-const char* kOperatorNumeric      = "operator_numeric";
-const char* kModemTechnoloy       = "modem_technoloy";
-const char* kPreferredNetworkMode = "preferred_network_mode";
-const char* kEmergencyMode        = "emergency_mode";
-const char* kSimType              = "sim_type";
+static constexpr char kInstances[] = "instances";
+static constexpr char kNetworkSelectionMode[] = "network_selection_mode";
+static constexpr char kOperatorNumeric[] = "operator_numeric";
+static constexpr char kModemTechnoloy[] = "modem_technoloy";
+static constexpr char kPreferredNetworkMode[] = "preferred_network_mode";
+static constexpr char kEmergencyMode[] = "emergency_mode";
 
-const int   kDefaultNetworkSelectionMode  = 0;     // AUTOMATIC
-const std::string kDefaultOperatorNumeric = "";
-const int   kDefaultModemTechnoloy        = 0x10;  // LTE
-const int   kDefaultPreferredNetworkMode  = 0x13;  // LTE | WCDMA | GSM
-const bool  kDefaultEmergencyMode         = false;
+static constexpr int kDefaultNetworkSelectionMode = 0;     // AUTOMATIC
+static constexpr int kDefaultModemTechnoloy = 0x10;        // LTE
+static constexpr int kDefaultPreferredNetworkMode = 0x13;  // LTE | WCDMA | GSM
+static constexpr bool kDefaultEmergencyMode = false;
 
 /**
  * Creates the (initially empty) config object and populates it with values from
diff --git a/host/commands/modem_simulator/unittest/service_test.cpp b/host/commands/modem_simulator/unittest/service_test.cpp
index 2d6289f..179174c 100644
--- a/host/commands/modem_simulator/unittest/service_test.cpp
+++ b/host/commands/modem_simulator/unittest/service_test.cpp
@@ -87,7 +87,7 @@
 
     cuttlefish::SharedFD server;
     auto channel_monitor =
-        std::make_unique<ChannelMonitor>(modem_simulator_, server);
+        std::make_unique<ChannelMonitor>(*modem_simulator_, server);
     modem_simulator_->Initialize(std::move(channel_monitor));
   }
 
@@ -106,7 +106,8 @@
   void ReadCommandResponse(std::vector<std::string>& response) {
     do {
       std::vector<char> buffer(4096);  // kMaxCommandLength
-      auto bytes_read = ril_side_->client_fd->Read(buffer.data(), buffer.size());
+      auto bytes_read =
+          ril_side_->client_fd->Read(buffer.data(), buffer.size());
       if (bytes_read <= 0) {
         // Close here to ensure the other side gets reset if it's still
         // connected
diff --git a/host/commands/openwrt_control_server/Android.bp b/host/commands/openwrt_control_server/Android.bp
index 8f32cf9..5458cb4 100644
--- a/host/commands/openwrt_control_server/Android.bp
+++ b/host/commands/openwrt_control_server/Android.bp
@@ -16,7 +16,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_host_static {
+cc_library {
     name: "libopenwrt_control_server",
     shared_libs: [
         "libprotobuf-cpp-full",
diff --git a/host/commands/powerwash_cvd/Android.bp b/host/commands/powerwash_cvd/Android.bp
index e089156..fb85e61 100644
--- a/host/commands/powerwash_cvd/Android.bp
+++ b/host/commands/powerwash_cvd/Android.bp
@@ -33,5 +33,5 @@
         "libcuttlefish_host_config",
         "libgflags",
     ],
-    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
+    defaults: ["cuttlefish_host"],
 }
diff --git a/host/commands/record_cvd/Android.bp b/host/commands/record_cvd/Android.bp
index 150e04c..109b62e 100644
--- a/host/commands/record_cvd/Android.bp
+++ b/host/commands/record_cvd/Android.bp
@@ -35,6 +35,6 @@
         "libgflags",
         "libprotobuf-cpp-full",
     ],
-    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
+    defaults: ["cuttlefish_host"],
 }
 
diff --git a/host/commands/restart_cvd/Android.bp b/host/commands/restart_cvd/Android.bp
index fd52336..66a1c15 100644
--- a/host/commands/restart_cvd/Android.bp
+++ b/host/commands/restart_cvd/Android.bp
@@ -33,5 +33,5 @@
         "libcuttlefish_host_config",
         "libgflags",
     ],
-    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
+    defaults: ["cuttlefish_host"],
 }
diff --git a/host/commands/run_cvd/Android.bp b/host/commands/run_cvd/Android.bp
index ec9035a..925b6e5 100644
--- a/host/commands/run_cvd/Android.bp
+++ b/host/commands/run_cvd/Android.bp
@@ -75,9 +75,13 @@
     ],
     required: [
         "console_forwarder",
+        "echo_server",
+        "gnss_grpc_proxy",
         "kernel_log_monitor",
         "logcat_receiver",
+        "log_tee",
         "secure_env",
+        "tcp_connector",
     ],
     target: {
         darwin: {
@@ -98,7 +102,6 @@
     },
     defaults: [
         "cuttlefish_host",
-        "cuttlefish_libicuuc",
         "cvd_cc_defaults",
     ],
     use_version_lib: true,
diff --git a/host/commands/run_cvd/launch/netsim_server.cpp b/host/commands/run_cvd/launch/netsim_server.cpp
index 543cc51..d854102 100644
--- a/host/commands/run_cvd/launch/netsim_server.cpp
+++ b/host/commands/run_cvd/launch/netsim_server.cpp
@@ -99,6 +99,11 @@
     // Netsim instance number.
     netsimd.AddParameter("--instance_num=", config_.netsim_instance_num());
 
+    // Add parameters from passthrough option --netsim-args.
+    for (auto const& arg : config_.netsim_args()) {
+      netsimd.AddParameter(arg);
+    }
+
     // Add command for forwarding the HCI port to a vsock server.
     Command hci_vsock_proxy(SocketVsockProxyBinary());
     hci_vsock_proxy.AddParameter("--server_type=vsock");
diff --git a/host/commands/run_cvd/proto/Android.bp b/host/commands/run_cvd/proto/Android.bp
index c84590b..cbf09f1 100644
--- a/host/commands/run_cvd/proto/Android.bp
+++ b/host/commands/run_cvd/proto/Android.bp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_run_cvd_proto",
     host_supported: true,
     proto: {
@@ -31,7 +31,6 @@
     },
     defaults: [
         "cuttlefish_host",
-        "cuttlefish_libicuuc",
         "cvd_cc_defaults",
     ],
 }
diff --git a/host/commands/run_cvd/proto/run_cvd.proto b/host/commands/run_cvd/proto/run_cvd.proto
index 74148e9..7f6afa6 100644
--- a/host/commands/run_cvd/proto/run_cvd.proto
+++ b/host/commands/run_cvd/proto/run_cvd.proto
@@ -24,6 +24,7 @@
     Resume resume = 6;
     StartScreenRecording start_screen_recording = 7;
     StopScreenRecording stop_screen_recording = 8;
+    SnapshotTake snapshot_take = 9;
   }
   string verbosity = 20;
 }
@@ -31,3 +32,6 @@
 message Resume {}
 message StartScreenRecording {}
 message StopScreenRecording {}
+message SnapshotTake {
+  repeated string snapshot_path = 1;
+}
diff --git a/host/commands/run_cvd/runner_defs.h b/host/commands/run_cvd/runner_defs.h
index 8bdc744..3080642 100644
--- a/host/commands/run_cvd/runner_defs.h
+++ b/host/commands/run_cvd/runner_defs.h
@@ -75,6 +75,7 @@
   kStartScreenRecording = 7,
   kStopScreenRecording = 8,
   // TODO(kwstephenkim): extend the list of operations to cover snapshot
+  kSnapshotTake = 9,
 };
 
 }  // namespace cuttlefish
diff --git a/host/commands/run_cvd/server_loop_impl.cpp b/host/commands/run_cvd/server_loop_impl.cpp
index aee7691..a79b18c 100644
--- a/host/commands/run_cvd/server_loop_impl.cpp
+++ b/host/commands/run_cvd/server_loop_impl.cpp
@@ -104,10 +104,19 @@
         HandleActionWithNoData(launcher_action.action, client, process_monitor);
         continue;
       }
-      auto result = HandleExtended(launcher_action, client);
+      auto result = HandleExtended(launcher_action, process_monitor);
+      const auto launcher_action_type_code =
+          static_cast<std::uint32_t>(launcher_action.type);
+      auto response = LauncherResponse::kSuccess;
       if (!result.ok()) {
         LOG(ERROR) << "Failed to handle extended action request.";
         LOG(DEBUG) << result.error().Trace();
+        response = LauncherResponse::kError;
+      }
+      const auto n_written = client->Write(&response, sizeof(response));
+      if (n_written != sizeof(response)) {
+        LOG(ERROR) << "Failed to write response to "
+                   << launcher_action_type_code;
       }
       // extended operations for now are 1 time request-response exchanges.
       // thus, we will close the client FD.
@@ -126,28 +135,32 @@
 }
 
 Result<void> ServerLoopImpl::HandleExtended(
-    const LauncherActionInfo& action_info, const SharedFD& client) {
+    const LauncherActionInfo& action_info, ProcessMonitor& process_monitor) {
   CF_EXPECT(action_info.action == LauncherAction::kExtended);
   switch (action_info.type) {
     case ExtendedActionType::kSuspend: {
       LOG(DEBUG) << "Run_cvd received suspend request.";
-      CF_EXPECT(HandleSuspend(action_info.serialized_data, client));
+      CF_EXPECT(HandleSuspend(action_info.serialized_data, process_monitor));
       return {};
     }
     case ExtendedActionType::kResume: {
       LOG(DEBUG) << "Run_cvd received resume request.";
-      CF_EXPECT(HandleResume(action_info.serialized_data, client));
+      CF_EXPECT(HandleResume(action_info.serialized_data, process_monitor));
+      return {};
+    }
+    case ExtendedActionType::kSnapshotTake: {
+      LOG(DEBUG) << "Run_cvd received resume request.";
+      CF_EXPECT(HandleSnapshotTake(action_info.serialized_data));
       return {};
     }
     case ExtendedActionType::kStartScreenRecording: {
       LOG(DEBUG) << "Run_cvd received start screen recording request.";
-      CF_EXPECT(
-          HandleStartScreenRecording(action_info.serialized_data, client));
+      CF_EXPECT(HandleStartScreenRecording(action_info.serialized_data));
       return {};
     }
     case ExtendedActionType::kStopScreenRecording: {
       LOG(DEBUG) << "Run_cvd received stop screen recording request.";
-      CF_EXPECT(HandleStopScreenRecording(action_info.serialized_data, client));
+      CF_EXPECT(HandleStopScreenRecording(action_info.serialized_data));
       return {};
     }
     default:
diff --git a/host/commands/run_cvd/server_loop_impl.h b/host/commands/run_cvd/server_loop_impl.h
index 4c1bf7f..bda3e5d 100644
--- a/host/commands/run_cvd/server_loop_impl.h
+++ b/host/commands/run_cvd/server_loop_impl.h
@@ -57,15 +57,14 @@
   std::unordered_set<SetupFeature*> Dependencies() const override { return {}; }
   Result<void> ResultSetup() override;
   Result<void> HandleExtended(const LauncherActionInfo& action_info,
-                              const SharedFD& client);
+                              ProcessMonitor& process_monitor);
   Result<void> HandleSuspend(const std::string& serialized_data,
-                             const SharedFD& client);
+                             ProcessMonitor& process_monitor);
   Result<void> HandleResume(const std::string& serialized_data,
-                            const SharedFD& client);
-  Result<void> HandleStartScreenRecording(const std::string& serialized_data,
-                                          const SharedFD& client);
-  Result<void> HandleStopScreenRecording(const std::string& serialized_data,
-                                         const SharedFD& client);
+                            ProcessMonitor& process_monitor);
+  Result<void> HandleSnapshotTake(const std::string& serialized_data);
+  Result<void> HandleStartScreenRecording(const std::string& serialized_data);
+  Result<void> HandleStopScreenRecording(const std::string& serialized_data);
 
   void HandleActionWithNoData(const LauncherAction action,
                               const SharedFD& client,
diff --git a/host/commands/run_cvd/server_loop_impl_record.cpp b/host/commands/run_cvd/server_loop_impl_record.cpp
index cdc94f5..0346581 100644
--- a/host/commands/run_cvd/server_loop_impl_record.cpp
+++ b/host/commands/run_cvd/server_loop_impl_record.cpp
@@ -16,7 +16,6 @@
 
 #include "host/commands/run_cvd/server_loop_impl.h"
 
-#include "common/libs/fs/shared_fd.h"
 #include "common/libs/utils/result.h"
 #include "host/commands/run_cvd/runner_defs.h"
 #include "host/libs/command_util/util.h"
@@ -26,7 +25,7 @@
 namespace run_cvd_impl {
 
 Result<void> ServerLoopImpl::HandleStartScreenRecording(
-    const std::string& serialized_data, const SharedFD& client) {
+    const std::string& serialized_data) {
   run_cvd::ExtendedLauncherAction extended_action;
   CF_EXPECT(extended_action.ParseFromString(serialized_data),
             "Failed to load ExtendedLauncherAction proto.");
@@ -34,14 +33,11 @@
       extended_action.actions_case(),
       run_cvd::ExtendedLauncherAction::ActionsCase::kStartScreenRecording);
   LOG(INFO) << "Sending the request to start screen recording.";
-  auto response = LauncherResponse::kSuccess;
-  CF_EXPECT_EQ(client->Write(&response, sizeof(response)), sizeof(response),
-               "Failed to write the screen record response.");
   return {};
 }
 
 Result<void> ServerLoopImpl::HandleStopScreenRecording(
-    const std::string& serialized_data, const SharedFD& client) {
+    const std::string& serialized_data) {
   run_cvd::ExtendedLauncherAction extended_action;
   CF_EXPECT(extended_action.ParseFromString(serialized_data),
             "Failed to load ExtendedLauncherAction proto.");
@@ -49,9 +45,6 @@
       extended_action.actions_case(),
       run_cvd::ExtendedLauncherAction::ActionsCase::kStopScreenRecording);
   LOG(INFO) << "Sending the request to stop screen recording.";
-  auto response = LauncherResponse::kSuccess;
-  CF_EXPECT_EQ(client->Write(&response, sizeof(response)), sizeof(response),
-               "Failed to write the screen record response.");
   return {};
 }
 
diff --git a/host/commands/run_cvd/server_loop_impl_snapshot.cpp b/host/commands/run_cvd/server_loop_impl_snapshot.cpp
index e2cb3d4..f700ea2 100644
--- a/host/commands/run_cvd/server_loop_impl_snapshot.cpp
+++ b/host/commands/run_cvd/server_loop_impl_snapshot.cpp
@@ -103,36 +103,55 @@
 }
 
 Result<void> ServerLoopImpl::HandleSuspend(const std::string& serialized_data,
-                                           const SharedFD& client) {
+                                           ProcessMonitor& process_monitor) {
   run_cvd::ExtendedLauncherAction extended_action;
   CF_EXPECT(extended_action.ParseFromString(serialized_data),
             "Failed to load ExtendedLauncherAction proto.");
   CF_EXPECT_EQ(extended_action.actions_case(),
                run_cvd::ExtendedLauncherAction::ActionsCase::kSuspend);
-  LOG(INFO) << "Suspending the guest..";
+  // right order: guest -> host
+  LOG(DEBUG) << "Suspending the guest..";
   CF_EXPECT(SuspendGuest());
-  LOG(INFO) << "The guest is suspended.";
-  LOG(INFO) << "Suspend host is not yet implemented.";
-  auto response = LauncherResponse::kSuccess;
-  CF_EXPECT_EQ(client->Write(&response, sizeof(response)), sizeof(response),
-               "Failed to wrote the suspend response.");
+  LOG(DEBUG) << "The guest is suspended.";
+  CF_EXPECT(process_monitor.SuspendMonitoredProcesses(),
+            "Failed to suspend host processes.");
+  LOG(DEBUG) << "The host processes are suspended.";
   return {};
 }
 
 Result<void> ServerLoopImpl::HandleResume(const std::string& serialized_data,
-                                          const SharedFD& client) {
+                                          ProcessMonitor& process_monitor) {
   run_cvd::ExtendedLauncherAction extended_action;
   CF_EXPECT(extended_action.ParseFromString(serialized_data),
             "Failed to load ExtendedLauncherAction proto.");
   CF_EXPECT_EQ(extended_action.actions_case(),
                run_cvd::ExtendedLauncherAction::ActionsCase::kResume);
-  LOG(INFO) << "Resuming the guest..";
+  // right order: host -> guest
+  CF_EXPECT(process_monitor.ResumeMonitoredProcesses(),
+            "Failed to resume host processes.");
+  LOG(DEBUG) << "The host processes are resumed.";
+  LOG(DEBUG) << "Resuming the guest..";
   CF_EXPECT(ResumeGuest());
-  LOG(INFO) << "The guest resumed.";
-  LOG(INFO) << "Resuming host is not yet implemented.";
-  auto response = LauncherResponse::kSuccess;
-  CF_EXPECT_EQ(client->Write(&response, sizeof(response)), sizeof(response),
-               "Failed to wrote the suspend response.");
+  LOG(DEBUG) << "The guest resumed.";
+  return {};
+}
+
+Result<void> ServerLoopImpl::HandleSnapshotTake(
+    const std::string& serialized_data) {
+  run_cvd::ExtendedLauncherAction extended_action;
+  CF_EXPECT(extended_action.ParseFromString(serialized_data),
+            "Failed to load ExtendedLauncherAction proto.");
+  CF_EXPECT_EQ(extended_action.actions_case(),
+               run_cvd::ExtendedLauncherAction::ActionsCase::kSnapshotTake);
+  // implement snapshot take
+  std::vector<std::string> path_to_snapshots;
+  for (const auto& path : extended_action.snapshot_take().snapshot_path()) {
+    path_to_snapshots.push_back(path);
+  }
+  CF_EXPECT_EQ(path_to_snapshots.size(), 1);
+  const auto& path_to_snapshot = path_to_snapshots.front();
+  LOG(DEBUG) << "run_cvd server loop will take snapshot to "
+             << path_to_snapshot;
   return {};
 }
 
diff --git a/host/commands/secure_env/Android.bp b/host/commands/secure_env/Android.bp
index 10ea480..c401ce7 100644
--- a/host/commands/secure_env/Android.bp
+++ b/host/commands/secure_env/Android.bp
@@ -104,7 +104,7 @@
 // 1. Missing transport implementation
 // 2. Missing file utils
 // 3. Base64 isn't supported (need for software oemlock implementation)
-cc_library_host_static {
+cc_library {
     name: "libsecure_env_not_windows",
     srcs: common_libsecure_srcs + [
         "confui_sign_server.cpp",
diff --git a/host/commands/snapshot_util_cvd/Android.bp b/host/commands/snapshot_util_cvd/Android.bp
index 7ff1e8f..a4ce525 100644
--- a/host/commands/snapshot_util_cvd/Android.bp
+++ b/host/commands/snapshot_util_cvd/Android.bp
@@ -36,5 +36,5 @@
         "libgflags",
 	"libprotobuf-cpp-full",
     ],
-    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
+    defaults: ["cuttlefish_host"],
 }
diff --git a/host/commands/snapshot_util_cvd/main.cc b/host/commands/snapshot_util_cvd/main.cc
index d48c609..3f40a6f 100644
--- a/host/commands/snapshot_util_cvd/main.cc
+++ b/host/commands/snapshot_util_cvd/main.cc
@@ -22,6 +22,7 @@
 #include <fmt/core.h>
 
 #include "common/libs/fs/shared_fd.h"
+#include "common/libs/utils/files.h"
 #include "common/libs/utils/flag_parser.h"
 #include "common/libs/utils/result.h"
 #include "host/commands/snapshot_util_cvd/parse.h"
@@ -50,11 +51,23 @@
   return serialized;
 }
 
+Result<std::string> SerializeSnapshotTakeRequest(
+    const std::string& snapshot_path) {
+  run_cvd::ExtendedLauncherAction action_proto;
+  auto* snapshot_take_request = action_proto.mutable_snapshot_take();
+  snapshot_take_request->add_snapshot_path(snapshot_path);
+  std::string serialized;
+  CF_EXPECT(action_proto.SerializeToString(&serialized),
+            "Failed to serialize Resume Request protobuf.");
+  return serialized;
+}
+
 struct RequestInfo {
   std::string serialized_data;
   ExtendedActionType extended_action_type;
 };
-Result<RequestInfo> SerializeRequest(const SnapshotCmd subcmd) {
+Result<RequestInfo> SerializeRequest(const SnapshotCmd subcmd,
+                                     const std::string& snapshot_path) {
   switch (subcmd) {
     case SnapshotCmd::kSuspend: {
       return RequestInfo{
@@ -70,35 +83,59 @@
       };
       break;
     }
+    case SnapshotCmd::kSnapshotTake: {
+      CF_EXPECT(!snapshot_path.empty(),
+                "Snapshot operation requires snapshot_path");
+      return RequestInfo{
+          .serialized_data =
+              CF_EXPECT(SerializeSnapshotTakeRequest(snapshot_path)),
+          .extended_action_type = ExtendedActionType::kSnapshotTake,
+      };
+      break;
+    }
     default:
       return CF_ERR("Operation not supported.");
   }
 }
 
-Result<void> SuspendCvdMain(std::vector<std::string> args) {
+Result<void> SnapshotCvdMain(std::vector<std::string> args) {
   CF_EXPECT(!args.empty(), "No arguments was given");
   const auto prog_path = args.front();
   args.erase(args.begin());
   auto parsed = CF_EXPECT(Parse(args));
 
+  // make sure the snapshot directory exists
+  if (parsed.cmd == SnapshotCmd::kSnapshotTake) {
+    CF_EXPECT(!parsed.snapshot_path.empty(),
+              "Snapshot operation requires snapshot path.");
+    CF_EXPECTF(EnsureDirectoryExists(parsed.snapshot_path),
+               "Failed to ensure that snapshot directory {} exists",
+               parsed.snapshot_path);
+  }
+
   const CuttlefishConfig* config =
       CF_EXPECT(CuttlefishConfig::Get(), "Failed to obtain config object");
-  SharedFD monitor_socket = CF_EXPECT(GetLauncherMonitor(
-      *config, parsed.instance_num, parsed.wait_for_launcher));
+  // TODO(kwstephenkim): copy host files that are shared by the instance group
+  for (const auto instance_num : parsed.instance_nums) {
+    SharedFD monitor_socket = CF_EXPECT(
+        GetLauncherMonitor(*config, instance_num, parsed.wait_for_launcher));
 
-  LOG(INFO) << "Requesting " << parsed.cmd;
-  auto [serialized_data, extended_type] =
-      CF_EXPECT(SerializeRequest(parsed.cmd));
-  CF_EXPECT(
-      WriteLauncherActionWithData(monitor_socket, LauncherAction::kExtended,
-                                  extended_type, std::move(serialized_data)));
-
-  LauncherResponse response = CF_EXPECT(ReadLauncherResponse(monitor_socket));
-  CF_EXPECTF(response == LauncherResponse::kSuccess,
-             "Received \"{}\" response from launcher monitor for \""
-             "{}\" request.",
-             static_cast<char>(response), static_cast<int>(parsed.cmd));
-  LOG(INFO) << parsed.cmd << " was successful.";
+    LOG(INFO) << "Requesting " << parsed.cmd << " for instance #"
+              << instance_num;
+    auto [serialized_data, extended_type] =
+        CF_EXPECT(SerializeRequest(parsed.cmd, parsed.snapshot_path));
+    CF_EXPECT(
+        WriteLauncherActionWithData(monitor_socket, LauncherAction::kExtended,
+                                    extended_type, std::move(serialized_data)));
+    LOG(INFO) << "Wrote the extended serialized data and reading response";
+    LauncherResponse response = CF_EXPECT(ReadLauncherResponse(monitor_socket));
+    LOG(INFO) << "Read the response:  " << (int)LauncherResponse::kSuccess;
+    CF_EXPECTF(response == LauncherResponse::kSuccess,
+               "Received \"{}\" response from launcher monitor for \""
+               "{}\" request.",
+               static_cast<char>(response), static_cast<int>(parsed.cmd));
+    LOG(INFO) << parsed.cmd << " was successful for instance #" << instance_num;
+  }
   return {};
 }
 
@@ -108,7 +145,7 @@
 int main(int argc, char** argv) {
   ::android::base::InitLogging(argv, android::base::StderrLogger);
   std::vector<std::string> all_args = cuttlefish::ArgsToVec(argc, argv);
-  auto result = cuttlefish::SuspendCvdMain(std::move(all_args));
+  auto result = cuttlefish::SnapshotCvdMain(std::move(all_args));
   if (!result.ok()) {
     LOG(ERROR) << result.error().Trace();
     return EXIT_FAILURE;
diff --git a/host/commands/snapshot_util_cvd/parse.cc b/host/commands/snapshot_util_cvd/parse.cc
index f8e21ef..249867f 100644
--- a/host/commands/snapshot_util_cvd/parse.cc
+++ b/host/commands/snapshot_util_cvd/parse.cc
@@ -16,9 +16,13 @@
 
 #include "host/commands/snapshot_util_cvd/parse.h"
 
+#include <cstdlib>
 #include <iostream>
 #include <unordered_map>
 
+#include <android-base/parseint.h>
+#include <android-base/strings.h>
+
 #include "common/libs/utils/contains.h"
 #include "common/libs/utils/flag_parser.h"
 #include "common/libs/utils/result.h"
@@ -29,14 +33,15 @@
 
 constexpr char snapshot_cmd_help[] =
     "Command to control regarding the snapshot operations: "
-    "suspend/resume/take";
-
-constexpr char instance_num_help[] = "Which instance to suspend.";
+    "suspend/resume/snapshot_take";
 
 constexpr char wait_for_launcher_help[] =
     "How many seconds to wait for the launcher to respond to the status "
     "command. A value of zero means wait indefinitely.";
 
+constexpr char snapshot_path_help[] =
+    "Path to the directory the taken snapshot files are saved";
+
 Flag SnapshotCmdFlag(std::string& value_buf) {
   return GflagsCompatFlag("subcmd", value_buf).Help(snapshot_cmd_help);
 }
@@ -46,15 +51,15 @@
   return GflagsCompatFlag(name, value_buf).Help(help_msg);
 }
 
-Flag InstanceNumFlag(int& instance_num) {
-  return GetInt32Flag("instance_num", instance_num, instance_num_help);
-}
-
 Flag WaitForLauncherFlag(int& wait_for_launcher) {
   return GetInt32Flag("wait_for_launcher", wait_for_launcher,
                       wait_for_launcher_help);
 }
 
+Flag SnapshotPathFlag(std::string& path_buf) {
+  return GflagsCompatFlag("snapshot_path", path_buf).Help(snapshot_path_help);
+}
+
 }  // namespace
 
 Result<Parsed> Parse(int argc, char** argv) {
@@ -65,30 +70,51 @@
 
 Result<SnapshotCmd> ConvertToSnapshotCmd(const std::string& input) {
   std::unordered_map<std::string, SnapshotCmd> mapping{
-      {"suspend", SnapshotCmd::kSuspend},   {"resume", SnapshotCmd::kResume},
-      {"take", SnapshotCmd::kSnapshotTake}, {"unset", SnapshotCmd::kUnknown},
+      {"suspend", SnapshotCmd::kSuspend},
+      {"resume", SnapshotCmd::kResume},
+      {"snapshot_take", SnapshotCmd::kSnapshotTake},
       {"unknown", SnapshotCmd::kUnknown},
   };
   CF_EXPECT(Contains(mapping, input));
   return mapping.at(input);
 }
 
+static Result<std::vector<int>> InstanceNums() {
+  CF_EXPECT(getenv("HOME") != nullptr, "\"HOME\" must be set properly.");
+  const auto* config = CuttlefishConfig::Get();
+  CF_EXPECT(config != nullptr, "CuttlefishConfig::Get() returned nullptr");
+
+  const auto instances = config->Instances();
+  std::vector<int> instance_nums;
+  CF_EXPECT(!instances.empty(), "CuttlefishConfig has no instance in it.");
+  instance_nums.reserve(instances.size());
+  for (const auto& instance : instances) {
+    int id;
+    CF_EXPECTF(android::base::ParseInt(instance.id(), &id),
+               "Parsing filed for {}", id);
+    instance_nums.push_back(id);
+  }
+  return instance_nums;
+}
+
 Result<Parsed> Parse(std::vector<std::string>& args) {
   Parsed parsed{
-      .instance_num = GetInstance(),
       .wait_for_launcher = 30,
   };
   std::vector<Flag> flags;
   bool help_xml = false;
   std::string snapshot_op("unknown");
+  std::string snapshot_path;
   flags.push_back(SnapshotCmdFlag(snapshot_op));
-  flags.push_back(InstanceNumFlag(parsed.instance_num));
   flags.push_back(WaitForLauncherFlag(parsed.wait_for_launcher));
+  flags.push_back(SnapshotPathFlag(snapshot_path));
   flags.push_back(HelpFlag(flags));
   flags.push_back(HelpXmlFlag(flags, std::cout, help_xml));
   flags.push_back(UnexpectedArgumentGuard());
   CF_EXPECT(ParseFlags(flags, args), "Flag parsing failed");
   parsed.cmd = CF_EXPECT(ConvertToSnapshotCmd(snapshot_op));
+  parsed.snapshot_path = snapshot_path;
+  parsed.instance_nums = CF_EXPECT(InstanceNums());
   return parsed;
 }
 
@@ -104,7 +130,7 @@
       out << "resume";
       break;
     case SnapshotCmd::kSnapshotTake:
-      out << "snapshot take";
+      out << "snapshot_take";
       break;
     default:
       out << "unknown";
diff --git a/host/commands/snapshot_util_cvd/parse.h b/host/commands/snapshot_util_cvd/parse.h
index 42ec492..f802072 100644
--- a/host/commands/snapshot_util_cvd/parse.h
+++ b/host/commands/snapshot_util_cvd/parse.h
@@ -38,8 +38,9 @@
 
 struct Parsed {
   SnapshotCmd cmd;
-  int instance_num;
+  std::vector<int> instance_nums;
   int wait_for_launcher;
+  std::string snapshot_path;
   std::optional<android::base::LogSeverity> verbosity_level;
 };
 Result<Parsed> Parse(int argc, char** argv);
diff --git a/host/commands/start/Android.bp b/host/commands/start/Android.bp
index 73ba0fc..1195906 100644
--- a/host/commands/start/Android.bp
+++ b/host/commands/start/Android.bp
@@ -47,5 +47,5 @@
             enabled: true,
         },
     },
-    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
+    defaults: ["cuttlefish_host"],
 }
diff --git a/host/commands/start/main.cc b/host/commands/start/main.cc
index f02a18e..2787778 100644
--- a/host/commands/start/main.cc
+++ b/host/commands/start/main.cc
@@ -247,7 +247,7 @@
                                               "enable_sandbox",
                                               "restart_subprocesses",
                                               "enable_gpu_udmabuf",
-                                              "enable_gpu_angle",
+                                              "enable_gpu_vhost_user",
                                               "enable_audio",
                                               "enable_vehicle_hal_grpc_server",
                                               "start_gnss_proxy",
diff --git a/host/commands/status/Android.bp b/host/commands/status/Android.bp
index edde718..708e3f3 100644
--- a/host/commands/status/Android.bp
+++ b/host/commands/status/Android.bp
@@ -34,5 +34,5 @@
         "libcuttlefish_host_config",
         "libgflags",
     ],
-    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
+    defaults: ["cuttlefish_host"],
 }
diff --git a/host/commands/status/main.cc b/host/commands/status/main.cc
index c4ecf53..3760b02 100644
--- a/host/commands/status/main.cc
+++ b/host/commands/status/main.cc
@@ -73,31 +73,31 @@
 
 struct WebAccessUrlParam {
   std::string sig_server_addr;
-  std::string device_name;
+  std::string webrtc_device_id;
 };
 std::string CalcWebAccessUrl(const WebAccessUrlParam& web_access_url_param) {
   if (!FileIsSocket(web_access_url_param.sig_server_addr)) {
     return "";
   }
   return std::string("https://") + "localhost" + ":" + "1443" + "/devices/" +
-         web_access_url_param.device_name + "/files" + "/client.html";
+         web_access_url_param.webrtc_device_id + "/files" + "/client.html";
 }
 
 Json::Value PopulateDevicesInfoFromInstance(
     const CuttlefishConfig& config,
     const CuttlefishConfig::InstanceSpecific& instance_config) {
   Json::Value device_info;
-  std::string device_name = instance_config.webrtc_device_id();
-  if (device_name.empty()) {
-    device_name = instance_config.instance_name();
+  std::string webrtc_device_id = instance_config.webrtc_device_id();
+  if (webrtc_device_id.empty()) {
+    webrtc_device_id = instance_config.instance_name();
   }
   device_info["assembly_dir"] = config.assembly_dir();
-  device_info["instance_name"] = device_name;
+  device_info["webrtc_device_id"] = webrtc_device_id;
   device_info["instance_dir"] = instance_config.instance_dir();
   // 1443 is the port of the global webrtc "operator" service
   device_info["web_access"] =
       CalcWebAccessUrl({.sig_server_addr = config.sig_server_address(),
-                        .device_name = device_name});
+                        .webrtc_device_id = webrtc_device_id});
   device_info["adb_serial"] = instance_config.adb_ip_and_port();
   device_info["webrtc_port"] = std::to_string(config.sig_server_port());
   for (int i = 0; i < instance_config.display_configs().size(); i++) {
diff --git a/host/commands/stop/Android.bp b/host/commands/stop/Android.bp
index 07c88e9..7d9fa5f 100644
--- a/host/commands/stop/Android.bp
+++ b/host/commands/stop/Android.bp
@@ -40,5 +40,5 @@
             enabled: true,
         },
     },
-    defaults: ["cuttlefish_host", "cuttlefish_libicuuc"],
+    defaults: ["cuttlefish_host"],
 }
diff --git a/host/commands/tcp_connector/Android.bp b/host/commands/tcp_connector/Android.bp
index a7148ef..8a3791e 100644
--- a/host/commands/tcp_connector/Android.bp
+++ b/host/commands/tcp_connector/Android.bp
@@ -34,5 +34,10 @@
         "libcuttlefish_host_config",
         "libgflags",
     ],
+    target: {
+        darwin: {
+            enabled: true,
+        },
+    },
     defaults: ["cuttlefish_buildhost_only"]
 }
diff --git a/host/commands/test_gce_driver/Android.bp b/host/commands/test_gce_driver/Android.bp
index 6b2bfb6..e8a2ca2 100644
--- a/host/commands/test_gce_driver/Android.bp
+++ b/host/commands/test_gce_driver/Android.bp
@@ -67,7 +67,7 @@
     defaults: ["cuttlefish_host"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_test_gce_proto_cpp",
     proto: {
         export_proto_headers: true,
diff --git a/host/cvd_test_configs/end_to_end_test/multi/TC1.json b/host/cvd_test_configs/end_to_end_test/multi/TC1.json
new file mode 100644
index 0000000..a359439
--- /dev/null
+++ b/host/cvd_test_configs/end_to_end_test/multi/TC1.json
@@ -0,0 +1,43 @@
+{
+  "instances":
+      [
+        {
+          "vm": {
+            "memory_mb": 2048
+          }
+        },
+        {
+          "vm": {
+            "memory_mb": 4096
+          },
+          "graphics": {
+            "displays": [
+              {
+                "width": 1080,
+                "height": 600,
+                "dpi": 120
+              },
+              {
+                "width": 400,
+                "height": 600,
+                "dpi": 150
+              }
+            ]
+          }
+        },
+        {
+          "vm": {
+            "memory_mb": 4096
+          },
+          "graphics": {
+            "displays": [
+              {
+                "width": 2560,
+                "height": 1800,
+                "dpi": 320
+              }
+            ]
+          }
+        }
+      ]
+}
\ No newline at end of file
diff --git a/host/cvd_test_configs/end_to_end_test/single/TC_auto.json b/host/cvd_test_configs/end_to_end_test/single/TC_auto.json
new file mode 100644
index 0000000..9db9453
--- /dev/null
+++ b/host/cvd_test_configs/end_to_end_test/single/TC_auto.json
@@ -0,0 +1,24 @@
+{
+  "instances":
+      [
+        {
+          "vm": {
+            "memory_mb": 4096
+          },
+          "graphics": {
+            "displays": [
+              {
+                "width": 1080,
+                "height": 600,
+                "dpi": 120
+              },
+              {
+                "width": 400,
+                "height": 600,
+                "dpi": 120
+              }
+            ]
+          }
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/end_to_end_test/single/TC_foldable.json b/host/cvd_test_configs/end_to_end_test/single/TC_foldable.json
new file mode 100644
index 0000000..1ade717
--- /dev/null
+++ b/host/cvd_test_configs/end_to_end_test/single/TC_foldable.json
@@ -0,0 +1,65 @@
+{
+  "instances":
+      [
+        {
+          "vm": {
+            "memory_mb": 4096,
+            "custom_actions": [
+              {
+                "device_states": [
+                  {
+                    "lid_switch_open": false,
+                    "hinge_angle_value": 0
+                  }
+                ],
+                "button": {
+                  "command": "device_state_closed",
+                  "title": "Device State Closed",
+                  "icon_name": "smartphone"
+                }
+              },
+              {
+                "device_states": [
+                  {
+                    "lid_switch_open": true,
+                    "hinge_angle_value": 90
+                  }
+                ],
+                "button": {
+                  "command": "device_state_half_opened",
+                  "title": "Device State Half-Opened",
+                  "icon_name": "laptop"
+                }
+              },
+              {
+                "device_states": [
+                  {
+                    "lid_switch_open": true,
+                    "hinge_angle_value": 180
+                  }
+                ],
+                "button": {
+                  "command": "device_state_opened",
+                  "title": "Device State Opened",
+                  "icon_name": "tablet"
+                }
+              }
+            ]
+          },
+          "graphics": {
+            "displays": [
+              {
+                "width": 1768,
+                "height": 2208,
+                "dpi": 374
+              },
+              {
+                "width": 832,
+                "height": 2268,
+                "dpi": 387
+              }
+            ]
+          }
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/end_to_end_test/single/TC_go.json b/host/cvd_test_configs/end_to_end_test/single/TC_go.json
new file mode 100644
index 0000000..0d67c91
--- /dev/null
+++ b/host/cvd_test_configs/end_to_end_test/single/TC_go.json
@@ -0,0 +1,19 @@
+{
+  "instances":
+      [
+        {
+          "vm": {
+            "memory_mb": 2048
+          },
+          "graphics": {
+            "displays": [
+              {
+                "width": 720,
+                "height": 1280,
+                "dpi": 320
+              }
+            ]
+          }
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/end_to_end_test/single/TC_phone.json b/host/cvd_test_configs/end_to_end_test/single/TC_phone.json
new file mode 100644
index 0000000..0d67c91
--- /dev/null
+++ b/host/cvd_test_configs/end_to_end_test/single/TC_phone.json
@@ -0,0 +1,19 @@
+{
+  "instances":
+      [
+        {
+          "vm": {
+            "memory_mb": 2048
+          },
+          "graphics": {
+            "displays": [
+              {
+                "width": 720,
+                "height": 1280,
+                "dpi": 320
+              }
+            ]
+          }
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/end_to_end_test/single/TC_slim.json b/host/cvd_test_configs/end_to_end_test/single/TC_slim.json
new file mode 100644
index 0000000..925c7fd
--- /dev/null
+++ b/host/cvd_test_configs/end_to_end_test/single/TC_slim.json
@@ -0,0 +1,20 @@
+{
+  "instances":
+      [
+        {
+          "vm": {
+            "memory_mb": 2048,
+            "use_sdcard": false
+          },
+          "graphics": {
+            "displays": [
+              {
+                "width": 720,
+                "height": 1280,
+                "dpi": 320
+              }
+            ]
+          }
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/end_to_end_test/single/TC_tablet.json b/host/cvd_test_configs/end_to_end_test/single/TC_tablet.json
new file mode 100644
index 0000000..939757f
--- /dev/null
+++ b/host/cvd_test_configs/end_to_end_test/single/TC_tablet.json
@@ -0,0 +1,19 @@
+{
+  "instances":
+      [
+        {
+          "vm": {
+            "memory_mb": 4096
+          },
+          "graphics": {
+            "displays": [
+              {
+                "width": 2560,
+                "height": 1800,
+                "dpi": 320
+              }
+            ]
+          }
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/end_to_end_test/single/TC_tv.json b/host/cvd_test_configs/end_to_end_test/single/TC_tv.json
new file mode 100644
index 0000000..741f7d4
--- /dev/null
+++ b/host/cvd_test_configs/end_to_end_test/single/TC_tv.json
@@ -0,0 +1,19 @@
+{
+  "instances":
+      [
+        {
+          "vm": {
+            "memory_mb": 2048
+          },
+          "graphics": {
+            "displays": [
+              {
+                "width": 1920,
+                "height": 1080,
+                "dpi": 213
+              }
+            ]
+          }
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/end_to_end_test/single/TC_wear.json b/host/cvd_test_configs/end_to_end_test/single/TC_wear.json
new file mode 100644
index 0000000..84e886fa
--- /dev/null
+++ b/host/cvd_test_configs/end_to_end_test/single/TC_wear.json
@@ -0,0 +1,20 @@
+{
+  "instances":
+      [
+        {
+          "vm": {
+            "memory_mb": 1536,
+            "use_sdcard": false
+          },
+          "graphics": {
+            "displays": [
+              {
+                "width": 450,
+                "height": 450,
+                "dpi": 320
+              }
+            ]
+          }
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/main_phone-main_watch.json b/host/cvd_test_configs/main_phone-main_watch.json
new file mode 100644
index 0000000..2b8881d
--- /dev/null
+++ b/host/cvd_test_configs/main_phone-main_watch.json
@@ -0,0 +1,26 @@
+{
+  "instances": [
+    {
+      "@import": "phone",
+      "vm": {
+        "memory_mb": 8192,
+        "setupwizard_mode": "OPTIONAL",
+        "cpus": 4
+      },
+      "disk": {
+        "default_build": "@ab/git_main/cf_x86_64_phone-trunk_staging-userdebug"
+      }
+    },
+    {
+      "@import": "wearable",
+      "vm": {
+        "memory_mb": 8192,
+        "setupwizard_mode": "REQUIRED",
+        "cpus": 4
+      },
+      "disk": {
+        "default_build": "@ab/git_main/cf_gwear_x86-trunk_staging-userdebug"
+      }
+    }
+  ]
+}
diff --git a/host/cvd_test_configs/main_phone.json b/host/cvd_test_configs/main_phone.json
new file mode 100644
index 0000000..9451dd2
--- /dev/null
+++ b/host/cvd_test_configs/main_phone.json
@@ -0,0 +1,15 @@
+{
+  "instances": [
+    {
+      "@import": "phone",
+      "vm": {
+        "memory_mb": 8192,
+        "setupwizard_mode": "OPTIONAL",
+        "cpus": 4
+      },
+      "disk": {
+        "default_build": "@ab/git_main/cf_x86_64_phone-trunk_staging-userdebug"
+      }
+    }
+  ]
+}
diff --git a/host/cvd_test_configs/mvp_features/graphics/displays/TC1.json b/host/cvd_test_configs/mvp_features/graphics/displays/TC1.json
new file mode 100644
index 0000000..3f023a0
--- /dev/null
+++ b/host/cvd_test_configs/mvp_features/graphics/displays/TC1.json
@@ -0,0 +1,11 @@
+{
+  "instances":
+      [
+        {
+          "graphics": {}
+        },
+        {
+          "graphics": {}
+        }
+      ]
+}
\ No newline at end of file
diff --git a/host/cvd_test_configs/mvp_features/graphics/displays/TC2.json b/host/cvd_test_configs/mvp_features/graphics/displays/TC2.json
new file mode 100644
index 0000000..1d41551
--- /dev/null
+++ b/host/cvd_test_configs/mvp_features/graphics/displays/TC2.json
@@ -0,0 +1,20 @@
+{
+  "instances":
+      [
+        {
+          "graphics": {
+            "displays": [
+              {}
+            ]
+          }
+        },
+        {
+          "graphics": {
+            "displays": [
+              {},
+              {}
+            ]
+          }
+        }
+      ]
+}
\ No newline at end of file
diff --git a/host/cvd_test_configs/mvp_features/graphics/displays/TC3.json b/host/cvd_test_configs/mvp_features/graphics/displays/TC3.json
new file mode 100644
index 0000000..64a3c1d
--- /dev/null
+++ b/host/cvd_test_configs/mvp_features/graphics/displays/TC3.json
@@ -0,0 +1,35 @@
+{
+  "instances":
+      [
+        {
+          "graphics": {
+            "displays": [
+              {
+                "width": 1080,
+                "height": 600,
+                "dpi": 120,
+                "refresh_rate_hertz": 60
+              },
+              {
+                "width": 400,
+                "height": 600,
+                "dpi": 120,
+                "refresh_rate_hertz": 60
+              }
+            ]
+          }
+        },
+        {
+          "graphics": {
+            "displays": [
+              {
+                "width": 2560,
+                "height": 1800,
+                "dpi": 320,
+                "refresh_rate_hertz": 60
+              }
+            ]
+          }
+        }
+      ]
+}
\ No newline at end of file
diff --git a/host/cvd_test_configs/mvp_features/security/guest_enforce_security/TC1.json b/host/cvd_test_configs/mvp_features/security/guest_enforce_security/TC1.json
new file mode 100644
index 0000000..32536ef
--- /dev/null
+++ b/host/cvd_test_configs/mvp_features/security/guest_enforce_security/TC1.json
@@ -0,0 +1,14 @@
+{
+  "instances":
+      [
+        {
+          "security": {}
+        },
+        {
+          "vm": {},
+          "security": {
+            "guest_enforce_security": false
+          }
+        }
+      ]
+}
\ No newline at end of file
diff --git a/host/cvd_test_configs/mvp_features/security/guest_enforce_security/TC2.json b/host/cvd_test_configs/mvp_features/security/guest_enforce_security/TC2.json
new file mode 100644
index 0000000..f69ed8d
--- /dev/null
+++ b/host/cvd_test_configs/mvp_features/security/guest_enforce_security/TC2.json
@@ -0,0 +1,15 @@
+{
+  "instances":
+      [
+        {
+          "security": {
+            "guest_enforce_security": false
+          }
+        },
+        {
+          "security": {
+            "guest_enforce_security": false
+          }
+        }
+      ]
+}
\ No newline at end of file
diff --git a/host/cvd_test_configs/mvp_features/vm/cpus/TC1.json b/host/cvd_test_configs/mvp_features/vm/cpus/TC1.json
new file mode 100644
index 0000000..edcb91e
--- /dev/null
+++ b/host/cvd_test_configs/mvp_features/vm/cpus/TC1.json
@@ -0,0 +1,13 @@
+{
+  "instances":
+      [
+        {
+          "vm": {}
+        },
+        {
+          "vm": {
+            "cpus": 4
+          }
+        }
+      ]
+}
\ No newline at end of file
diff --git a/host/cvd_test_configs/mvp_features/vm/cpus/TC2.json b/host/cvd_test_configs/mvp_features/vm/cpus/TC2.json
new file mode 100644
index 0000000..5dc89a4
--- /dev/null
+++ b/host/cvd_test_configs/mvp_features/vm/cpus/TC2.json
@@ -0,0 +1,15 @@
+{
+  "instances":
+      [
+        {
+          "vm": {
+            "cpus": 4
+          }
+        },
+        {
+          "vm": {
+            "cpus": 6
+          }
+        }
+      ]
+}
\ No newline at end of file
diff --git a/host/cvd_test_configs/mvp_features/vm/custom_actions/TC1.json b/host/cvd_test_configs/mvp_features/vm/custom_actions/TC1.json
new file mode 100644
index 0000000..502ed1c
--- /dev/null
+++ b/host/cvd_test_configs/mvp_features/vm/custom_actions/TC1.json
@@ -0,0 +1,40 @@
+{
+  "instances":
+      [
+        {
+          "vm": {
+            "memory_mb": 2048
+          }
+        },
+        {
+          "vm": {
+            "memory_mb": 2048,
+            "custom_actions": [
+              {
+                "shell_command": "am start -a android.intent.action.VIEW -d https://www.android1.com/",
+                "button": {
+                  "command": "web",
+                  "title": "Web Page",
+                  "icon_name": "language"
+                }
+              },
+              {
+                "server": "cuttlefish_example_action_server",
+                "buttons": [
+                  {
+                    "command": "settings",
+                    "title": "Quick Settings",
+                    "icon_name": "settings"
+                  },
+                  {
+                    "command": "alert",
+                    "title": "Do Not Disturb",
+                    "icon_name": "notifications_paused"
+                  }
+                ]
+              }
+            ]
+          }
+        }
+      ]
+}
\ No newline at end of file
diff --git a/host/cvd_test_configs/mvp_features/vm/enable_sandbox/TC1.json b/host/cvd_test_configs/mvp_features/vm/enable_sandbox/TC1.json
new file mode 100644
index 0000000..00a8422
--- /dev/null
+++ b/host/cvd_test_configs/mvp_features/vm/enable_sandbox/TC1.json
@@ -0,0 +1,13 @@
+{
+  "instances":
+      [
+        {
+          "vm": {}
+        },
+        {
+          "vm": {
+            "crosvm": {}
+          }
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/mvp_features/vm/enable_sandbox/TC2.json b/host/cvd_test_configs/mvp_features/vm/enable_sandbox/TC2.json
new file mode 100644
index 0000000..43fb111
--- /dev/null
+++ b/host/cvd_test_configs/mvp_features/vm/enable_sandbox/TC2.json
@@ -0,0 +1,17 @@
+{
+  "instances":
+      [
+        {
+          "vm": {
+            "crosvm": {}
+          }
+        },
+        {
+          "vm": {
+            "crosvm": {
+              "enable_sandbox": true
+            }
+          }
+        }
+      ]
+}
\ No newline at end of file
diff --git a/host/cvd_test_configs/mvp_features/vm/enable_sandbox/TC3.json b/host/cvd_test_configs/mvp_features/vm/enable_sandbox/TC3.json
new file mode 100644
index 0000000..5fd26f9
--- /dev/null
+++ b/host/cvd_test_configs/mvp_features/vm/enable_sandbox/TC3.json
@@ -0,0 +1,19 @@
+{
+  "instances":
+      [
+        {
+          "vm": {
+            "crosvm": {
+              "enable_sandbox": true
+            }
+          }
+        },
+        {
+          "vm": {
+            "crosvm": {
+              "enable_sandbox": true
+            }
+          }
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/mvp_features/vm/memory_mb/TC1.json b/host/cvd_test_configs/mvp_features/vm/memory_mb/TC1.json
new file mode 100644
index 0000000..4b79b75
--- /dev/null
+++ b/host/cvd_test_configs/mvp_features/vm/memory_mb/TC1.json
@@ -0,0 +1,13 @@
+{
+  "instances":
+      [
+        {
+          "vm": {}
+        },
+        {
+          "vm": {
+            "memory_mb": 4096
+          }
+        }
+      ]
+}
\ No newline at end of file
diff --git a/host/cvd_test_configs/mvp_features/vm/memory_mb/TC2.json b/host/cvd_test_configs/mvp_features/vm/memory_mb/TC2.json
new file mode 100644
index 0000000..622f6fd
--- /dev/null
+++ b/host/cvd_test_configs/mvp_features/vm/memory_mb/TC2.json
@@ -0,0 +1,15 @@
+{
+  "instances":
+      [
+        {
+          "vm": {
+            "memory_mb": 4096
+          }
+        },
+        {
+          "vm": {
+            "memory_mb": 8192
+          }
+        }
+      ]
+}
\ No newline at end of file
diff --git a/host/cvd_test_configs/mvp_features/vm/setupwizard_mode/TC1.json b/host/cvd_test_configs/mvp_features/vm/setupwizard_mode/TC1.json
new file mode 100644
index 0000000..488a7b5
--- /dev/null
+++ b/host/cvd_test_configs/mvp_features/vm/setupwizard_mode/TC1.json
@@ -0,0 +1,11 @@
+{
+  "instances":
+      [
+        {
+          "vm": {
+            "crosvm": {},
+            "setupwizard_mode": "ENABLED"
+          }
+        }
+      ]
+}
\ No newline at end of file
diff --git a/host/cvd_test_configs/mvp_features/vm/setupwizard_mode/TC2.json b/host/cvd_test_configs/mvp_features/vm/setupwizard_mode/TC2.json
new file mode 100644
index 0000000..c821d0f
--- /dev/null
+++ b/host/cvd_test_configs/mvp_features/vm/setupwizard_mode/TC2.json
@@ -0,0 +1,15 @@
+{
+  "instances":
+      [
+        {
+          "vm": {
+            "crosvm": {}
+          }
+        },
+        {
+          "vm": {
+            "crosvm": {}
+          }
+        }
+      ]
+}
\ No newline at end of file
diff --git a/host/cvd_test_configs/mvp_features/vm/setupwizard_mode/TC3.json b/host/cvd_test_configs/mvp_features/vm/setupwizard_mode/TC3.json
new file mode 100644
index 0000000..8902611
--- /dev/null
+++ b/host/cvd_test_configs/mvp_features/vm/setupwizard_mode/TC3.json
@@ -0,0 +1,16 @@
+{
+  "instances":
+      [
+        {
+          "vm": {
+            "crosvm": {}
+          }
+        },
+        {
+          "vm": {
+            "crosvm": {},
+            "setupwizard_mode": "REQUIRED"
+          }
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/mvp_features/vm/setupwizard_mode/TC4.json b/host/cvd_test_configs/mvp_features/vm/setupwizard_mode/TC4.json
new file mode 100644
index 0000000..7c7f434
--- /dev/null
+++ b/host/cvd_test_configs/mvp_features/vm/setupwizard_mode/TC4.json
@@ -0,0 +1,17 @@
+{
+  "instances":
+      [
+        {
+          "vm": {
+            "crosvm": {},
+            "setupwizard_mode": "OPTIONAL"
+          }
+        },
+        {
+          "vm": {
+            "crosvm": {},
+            "setupwizard_mode": "REQUIRED"
+          }
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/mvp_features/vm/vm_manager/TC1.json b/host/cvd_test_configs/mvp_features/vm/vm_manager/TC1.json
new file mode 100644
index 0000000..3225bb1
--- /dev/null
+++ b/host/cvd_test_configs/mvp_features/vm/vm_manager/TC1.json
@@ -0,0 +1,9 @@
+{
+  "instances":
+      [
+        {
+          "vm": {}
+        },
+        {}
+      ]
+}
\ No newline at end of file
diff --git a/host/cvd_test_configs/mvp_features/vm/vm_manager/TC2.json b/host/cvd_test_configs/mvp_features/vm/vm_manager/TC2.json
new file mode 100644
index 0000000..467a222
--- /dev/null
+++ b/host/cvd_test_configs/mvp_features/vm/vm_manager/TC2.json
@@ -0,0 +1,15 @@
+{
+  "instances":
+      [
+        {
+          "vm": {
+            "qemu": {}
+          }
+        },
+        {
+          "vm": {
+            "crosvm": {}
+          }
+        }
+      ]
+}
\ No newline at end of file
diff --git a/host/cvd_test_configs/mvp_features/vm/vm_manager/TC3.json b/host/cvd_test_configs/mvp_features/vm/vm_manager/TC3.json
new file mode 100644
index 0000000..5dcebe4
--- /dev/null
+++ b/host/cvd_test_configs/mvp_features/vm/vm_manager/TC3.json
@@ -0,0 +1,15 @@
+{
+  "instances":
+      [
+        {
+          "vm": {
+            "crosvm": {}
+          }
+        },
+        {
+          "vm": {
+            "gem5": {}
+          }
+        }
+      ]
+}
\ No newline at end of file
diff --git a/host/cvd_test_configs/templates_inheritance/custom/TC1.json b/host/cvd_test_configs/templates_inheritance/custom/TC1.json
new file mode 100644
index 0000000..4f9dffc
--- /dev/null
+++ b/host/cvd_test_configs/templates_inheritance/custom/TC1.json
@@ -0,0 +1,11 @@
+{
+  "instances":
+      [
+        {
+          "@import": "phone",
+          "vm": {
+            "memory_mb": 4096
+          }
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/templates_inheritance/custom/TC2.json b/host/cvd_test_configs/templates_inheritance/custom/TC2.json
new file mode 100644
index 0000000..4a689ff
--- /dev/null
+++ b/host/cvd_test_configs/templates_inheritance/custom/TC2.json
@@ -0,0 +1,18 @@
+{
+  "instances":
+      [
+        {
+          "@import": "phone",
+          "vm": {
+            "memory_mb": 4096
+          }
+        },
+        {
+          "@import": "tablet",
+          "vm": {
+            "memory_mb": 8192,
+            "cpus": 4
+          }
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/templates_inheritance/multi/TC1.json b/host/cvd_test_configs/templates_inheritance/multi/TC1.json
new file mode 100644
index 0000000..a500c4a
--- /dev/null
+++ b/host/cvd_test_configs/templates_inheritance/multi/TC1.json
@@ -0,0 +1,26 @@
+{
+  "instances":
+      [
+        {
+          "@import": "auto"
+        },
+        {
+          "@import": "go"
+        },
+        {
+          "@import": "phone"
+        },
+        {
+          "@import": "slim"
+        },
+        {
+          "@import": "tablet"
+        },
+        {
+          "@import": "tv"
+        },
+        {
+          "@import": "wearable"
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/templates_inheritance/multi/TC2.json b/host/cvd_test_configs/templates_inheritance/multi/TC2.json
new file mode 100644
index 0000000..79cf60e
--- /dev/null
+++ b/host/cvd_test_configs/templates_inheritance/multi/TC2.json
@@ -0,0 +1,29 @@
+{
+  "instances":
+      [
+        {
+          "@import": "auto"
+        },
+        {
+          "@import": "foldable"
+        },
+        {
+          "@import": "go"
+        },
+        {
+          "@import": "phone"
+        },
+        {
+          "@import": "slim"
+        },
+        {
+          "@import": "tablet"
+        },
+        {
+          "@import": "tv"
+        },
+        {
+          "@import": "wearable"
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/templates_inheritance/single/TC_auto.json b/host/cvd_test_configs/templates_inheritance/single/TC_auto.json
new file mode 100644
index 0000000..ec1b23b
--- /dev/null
+++ b/host/cvd_test_configs/templates_inheritance/single/TC_auto.json
@@ -0,0 +1,8 @@
+{
+  "instances":
+      [
+        {
+          "@import": "auto"
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/templates_inheritance/single/TC_foldable.json b/host/cvd_test_configs/templates_inheritance/single/TC_foldable.json
new file mode 100644
index 0000000..8d4614c
--- /dev/null
+++ b/host/cvd_test_configs/templates_inheritance/single/TC_foldable.json
@@ -0,0 +1,8 @@
+{
+  "instances":
+      [
+        {
+          "@import": "foldable"
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/templates_inheritance/single/TC_go.json b/host/cvd_test_configs/templates_inheritance/single/TC_go.json
new file mode 100644
index 0000000..e5aa719
--- /dev/null
+++ b/host/cvd_test_configs/templates_inheritance/single/TC_go.json
@@ -0,0 +1,8 @@
+{
+  "instances":
+      [
+        {
+          "@import": "go"
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/templates_inheritance/single/TC_phone.json b/host/cvd_test_configs/templates_inheritance/single/TC_phone.json
new file mode 100644
index 0000000..bc59f38
--- /dev/null
+++ b/host/cvd_test_configs/templates_inheritance/single/TC_phone.json
@@ -0,0 +1,8 @@
+{
+  "instances":
+      [
+        {
+          "@import": "phone"
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/templates_inheritance/single/TC_slim.json b/host/cvd_test_configs/templates_inheritance/single/TC_slim.json
new file mode 100644
index 0000000..1598986
--- /dev/null
+++ b/host/cvd_test_configs/templates_inheritance/single/TC_slim.json
@@ -0,0 +1,8 @@
+{
+  "instances":
+      [
+        {
+          "@import": "slim"
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/templates_inheritance/single/TC_tablet.json b/host/cvd_test_configs/templates_inheritance/single/TC_tablet.json
new file mode 100644
index 0000000..df3c6bb
--- /dev/null
+++ b/host/cvd_test_configs/templates_inheritance/single/TC_tablet.json
@@ -0,0 +1,8 @@
+{
+  "instances":
+      [
+        {
+          "@import": "tablet"
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/templates_inheritance/single/TC_tv.json b/host/cvd_test_configs/templates_inheritance/single/TC_tv.json
new file mode 100644
index 0000000..452120d
--- /dev/null
+++ b/host/cvd_test_configs/templates_inheritance/single/TC_tv.json
@@ -0,0 +1,8 @@
+{
+  "instances":
+      [
+        {
+          "@import": "tv"
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/templates_inheritance/single/TC_wear.json b/host/cvd_test_configs/templates_inheritance/single/TC_wear.json
new file mode 100644
index 0000000..ff2a1e1
--- /dev/null
+++ b/host/cvd_test_configs/templates_inheritance/single/TC_wear.json
@@ -0,0 +1,8 @@
+{
+  "instances":
+      [
+        {
+          "@import": "wearable"
+        }
+      ]
+}
diff --git a/host/cvd_test_configs/tm_phone-tm_watch-main_host_pkg.json b/host/cvd_test_configs/tm_phone-tm_watch-main_host_pkg.json
new file mode 100644
index 0000000..34304db
--- /dev/null
+++ b/host/cvd_test_configs/tm_phone-tm_watch-main_host_pkg.json
@@ -0,0 +1,28 @@
+{
+  "instances": [
+    {
+      "@import": "phone",
+      "vm": {
+        "memory_mb": 8192,
+        "setupwizard_mode": "OPTIONAL",
+        "cpus": 4
+      },
+      "disk": {
+        "default_build": "@ab/git_tm-qpr-dev/cf_x86_64_phone-userdebug",
+        "host_package": "@ab/aosp-main/aosp_cf_x86_64_phone-trunk_staging-userdebug"
+      }
+    },
+    {
+      "@import": "wearable",
+      "vm": {
+        "memory_mb": 8192,
+        "setupwizard_mode": "REQUIRED",
+        "cpus": 4
+      },
+      "disk": {
+        "default_build": "@ab/git_tm-wear-dev/cf_gwear_x86-userdebug",
+        "host_package": "@ab/aosp-main/aosp_cf_x86_64_phone-trunk_staging-userdebug"
+      }
+    }
+  ]
+}
diff --git a/host/frontend/webrtc/libcommon/Android.bp b/host/frontend/webrtc/libcommon/Android.bp
index f6fe47d..9afc36b 100644
--- a/host/frontend/webrtc/libcommon/Android.bp
+++ b/host/frontend/webrtc/libcommon/Android.bp
@@ -17,7 +17,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_webrtc_common",
     srcs: [
         "audio_device.cpp",
@@ -38,11 +38,18 @@
         "libwebrtc_absl_headers",
     ],
     static_libs: [
+        "libevent",
+        "libopus",
+        "libsrtp2",
+        "libvpx",
         "libwebrtc",
+        "libyuv",
     ],
     shared_libs: [
         "libbase",
+        "libcrypto",
         "libjsoncpp",
+        "libssl",
     ],
     defaults: ["cuttlefish_buildhost_only"],
 }
diff --git a/host/frontend/webrtc/libdevice/Android.bp b/host/frontend/webrtc/libdevice/Android.bp
index b4277c2..57756e5 100644
--- a/host/frontend/webrtc/libdevice/Android.bp
+++ b/host/frontend/webrtc/libdevice/Android.bp
@@ -17,7 +17,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_webrtc_device",
     srcs: [
         "audio_track_source_impl.cpp",
@@ -25,6 +25,7 @@
         "client_handler.cpp",
         "data_channels.cpp",
         "keyboard.cpp",
+        "lights_observer.cpp",
         "local_recorder.cpp",
         "streamer.cpp",
         "video_track_source_impl.cpp",
@@ -49,6 +50,7 @@
         "libcuttlefish_webrtc_common",
         "libgflags",
         "libdrm",
+        "libevent",
         "libffi",
         "libwayland_crosvm_gpu_display_extension_server_protocols",
         "libwayland_extension_server_protocols",
@@ -59,10 +61,14 @@
         "libwebrtc",
         "libcvd_gnss_grpc_proxy",
         "liblocation",
+        "libopus",
+        "libvpx",
+        "libyuv",
     ],
     shared_libs: [
         "libbase",
         "libcn-cbor",
+        "libcrypto",
         "libcuttlefish_fs",
         "libfruit",
         "libjsoncpp",
diff --git a/host/frontend/webrtc/libdevice/lights_observer.cpp b/host/frontend/webrtc/libdevice/lights_observer.cpp
new file mode 100644
index 0000000..f616b6e
--- /dev/null
+++ b/host/frontend/webrtc/libdevice/lights_observer.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2021 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 "lights_observer.h"
+
+#include <android-base/logging.h>
+#include <chrono>
+#include "common/libs/utils/vsock_connection.h"
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+LightsObserver::LightsObserver(unsigned int port, unsigned int cid)
+    : cid_(cid), port_(port), is_running_(false), session_active_(false) {}
+
+LightsObserver::~LightsObserver() { Stop(); }
+
+bool LightsObserver::Start() {
+  if (connection_thread_.joinable()) {
+    LOG(ERROR) << "Connection thread is already running.";
+    return false;
+  }
+
+  is_running_ = true;
+
+  connection_thread_ = std::thread([this] {
+    while (is_running_) {
+      while (cvd_connection_.IsConnected()) {
+        ReadServerMessages();
+      }
+
+      // Try to start a new connection. If this fails, delay retrying a bit.
+      if (is_running_ && !cvd_connection_.Connect(port_, cid_)) {
+        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
+        continue;
+      }
+    }
+
+    LOG(INFO) << "Exiting connection thread";
+  });
+
+  LOG(INFO) << "Connection thread running";
+  return true;
+}
+
+void LightsObserver::Stop() {
+  is_running_ = false;
+  cvd_connection_.Disconnect();
+
+  // The connection_thread_ should finish at any point now. Let's join it.
+  if (connection_thread_.joinable()) {
+    connection_thread_.join();
+  }
+}
+
+void LightsObserver::ReadServerMessages() {
+  //  TODO: Expand this with the rest of the protocol. Cache lights states.
+}
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/frontend/webrtc/libdevice/lights_observer.h b/host/frontend/webrtc/libdevice/lights_observer.h
new file mode 100644
index 0000000..6a55dd5
--- /dev/null
+++ b/host/frontend/webrtc/libdevice/lights_observer.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#pragma once
+#include "common/libs/utils/vsock_connection.h"
+
+#include <atomic>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+namespace cuttlefish {
+namespace webrtc_streaming {
+
+class LightsObserver {
+ public:
+  LightsObserver(unsigned int port, unsigned int cid);
+  ~LightsObserver();
+
+  LightsObserver(const LightsObserver& other) = delete;
+  LightsObserver& operator=(const LightsObserver& other) = delete;
+
+  bool Start();
+
+ private:
+  void Stop();
+  void ReadServerMessages();
+  // TODO(b/295543722): Move to a virtio_console transport instead.
+  VsockClientConnection cvd_connection_;
+  unsigned int cid_;
+  unsigned int port_;
+  std::thread connection_thread_;
+  std::atomic<bool> is_running_;
+  std::atomic<bool> session_active_;
+};
+
+}  // namespace webrtc_streaming
+}  // namespace cuttlefish
diff --git a/host/libs/audio_connector/Android.bp b/host/libs/audio_connector/Android.bp
index c26fecb..7da54ad 100644
--- a/host/libs/audio_connector/Android.bp
+++ b/host/libs/audio_connector/Android.bp
@@ -17,7 +17,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_audio_connector",
     srcs: [
         "buffers.cpp",
diff --git a/host/libs/avb/Android.bp b/host/libs/avb/Android.bp
index 49d16e1..62b6ad7 100644
--- a/host/libs/avb/Android.bp
+++ b/host/libs/avb/Android.bp
@@ -17,7 +17,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_avb",
     srcs: [
         "avb.cpp"
@@ -25,8 +25,8 @@
     shared_libs: [
         "libcuttlefish_utils",
         "libfruit",
-        // need to access host/libs/config/cuttlefish_config.h
-        "libjsoncpp",
+        "libjsoncpp", // need to access host/libs/config/cuttlefish_config.h
+        "liblog",
     ],
     static_libs: [
         "libbase",
diff --git a/host/libs/command_util/Android.bp b/host/libs/command_util/Android.bp
index 0564fa2..92f2308 100644
--- a/host/libs/command_util/Android.bp
+++ b/host/libs/command_util/Android.bp
@@ -17,13 +17,14 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_command_util",
     srcs: [
         "launcher_message.cc",
         "util.cc",
     ],
     shared_libs: [
+        "liblog",
         "libcuttlefish_fs",
         "libcuttlefish_utils",
         "libjsoncpp",
diff --git a/host/libs/command_util/launcher_message.cc b/host/libs/command_util/launcher_message.cc
index 4cd9a4a..5ef35b2 100644
--- a/host/libs/command_util/launcher_message.cc
+++ b/host/libs/command_util/launcher_message.cc
@@ -56,13 +56,6 @@
     }
   }
   LauncherActionMessage new_message(action, type, std::move(serialized_data));
-  /* To avoid -Wunused-private-field compilation error
-   *
-   * will be moved above when type_ is actually used.
-   */
-  CF_EXPECTF(IsSupportedType(new_message.type_),
-             "ExtendedActionType {} is not supported.",
-             static_cast<std::uint32_t>(new_message.type_));
   return new_message;
 }
 
@@ -83,17 +76,6 @@
   return Contains(supported_actions, action);
 }
 
-bool LauncherActionMessage::IsSupportedType(const ExtendedActionType type) {
-  std::set<ExtendedActionType> supported_action_types{
-      ExtendedActionType::kUnused,
-      ExtendedActionType::kSuspend,
-      ExtendedActionType::kResume,
-      ExtendedActionType::kStartScreenRecording,
-      ExtendedActionType::kStopScreenRecording,
-  };
-  return Contains(supported_action_types, type);
-}
-
 static Result<void> WriteBuffer(const SharedFD& fd, const std::string& buf,
                                 const std::string& description) {
   CF_EXPECT(fd->IsOpen(), "The file descriptor to write is not open.");
diff --git a/host/libs/command_util/launcher_message.h b/host/libs/command_util/launcher_message.h
index c5a7ef9..9e35260 100644
--- a/host/libs/command_util/launcher_message.h
+++ b/host/libs/command_util/launcher_message.h
@@ -53,7 +53,6 @@
                         std::string serialized_data);
   // returns true if the action does not need extended field
   static bool IsShortAction(const LauncherAction action);
-  static bool IsSupportedType(const ExtendedActionType type);
 
   const LauncherAction action_;
   const ExtendedActionType type_;
diff --git a/host/libs/config/Android.bp b/host/libs/config/Android.bp
index 113dbaa..74ff5ea 100644
--- a/host/libs/config/Android.bp
+++ b/host/libs/config/Android.bp
@@ -17,10 +17,9 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_host_config",
     srcs: [
-        "bootconfig_args.cpp",
         "display.cpp",
         "config_flag.cpp",
         "custom_actions.cpp",
diff --git a/host/libs/config/adb/Android.bp b/host/libs/config/adb/Android.bp
index 587de68..7ebc01f 100644
--- a/host/libs/config/adb/Android.bp
+++ b/host/libs/config/adb/Android.bp
@@ -17,7 +17,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_host_config_adb",
     srcs: [
         "config.cpp",
@@ -27,9 +27,10 @@
         "strings.cpp",
     ],
     shared_libs: [
-        "libcuttlefish_fs",
-        "libcuttlefish_utils",
         "libbase",
+        "libcuttlefish_fs",
+        "libcuttlefish_host_config",
+        "libcuttlefish_utils",
         "libfruit",
         "libgflags",
         "libjsoncpp",
diff --git a/host/libs/config/adb/flags.cpp b/host/libs/config/adb/flags.cpp
index 6606d34..0440f61 100644
--- a/host/libs/config/adb/flags.cpp
+++ b/host/libs/config/adb/flags.cpp
@@ -36,13 +36,14 @@
       }
       return modes.str().substr(1);  // First comma
     });
-    mode_flag_.Setter([this](const FlagMatch& match) {
+    mode_flag_.Setter([this](const FlagMatch& match) -> Result<void> {
       // TODO(schuffelen): Error on unknown types?
       std::set<AdbMode> modes;
       for (auto& mode : android::base::Split(match.value, ",")) {
         modes.insert(StringToAdbMode(mode));
       }
-      return config_.SetModes(modes);
+      CF_EXPECT(config_.SetModes(modes));
+      return {};
     });
   }
 
diff --git a/host/libs/config/adb/launch.cpp b/host/libs/config/adb/launch.cpp
index a3f7170..896ac82 100644
--- a/host/libs/config/adb/launch.cpp
+++ b/host/libs/config/adb/launch.cpp
@@ -21,6 +21,7 @@
 #include <vector>
 
 #include <fruit/fruit.h>
+#include <gflags/gflags.h>
 
 #include "common/libs/utils/result.h"
 #include "host/commands/kernel_log_monitor/utils.h"
@@ -129,8 +130,30 @@
   // CommandSource
   Result<std::vector<MonitorCommand>> Commands() override {
     std::vector<MonitorCommand> commands;
-    if (helper_.VsockTunnelEnabled()) {
-      Command adb_tunnel(SocketVsockProxyBinary());
+    const auto vsock_tunnel_enabled = helper_.VsockTunnelEnabled();
+    const auto vsock_half_tunnel_enabled = helper_.VsockHalfTunnelEnabled();
+    CF_EXPECT(!vsock_half_tunnel_enabled || !vsock_tunnel_enabled,
+              "Up to one of vsock_tunnel or vsock_half_tunnel is allowed.");
+    if (!vsock_half_tunnel_enabled && !vsock_tunnel_enabled) {
+      return commands;
+    }
+
+    Command adb_tunnel(SocketVsockProxyBinary());
+    adb_tunnel.AddParameter("--events_fd=", kernel_log_pipe_);
+    adb_tunnel.AddParameter("--start_event_id=", monitor::Event::AdbdStarted);
+    adb_tunnel.AddParameter("--stop_event_id=",
+                            monitor::Event::FastbootStarted);
+    /* fmayle@ found out that when cuttlefish starts from the saved snapshot
+     * that was saved after ADBD start event, the socket_vsock_proxy must not
+     * wait for the AdbdStarted event.
+     */
+    if (!instance_.sock_vsock_proxy_wait_adbd_start()) {
+      adb_tunnel.AddParameter("--start_immediately=true");
+    }
+    adb_tunnel.AddParameter("--server_type=tcp");
+    adb_tunnel.AddParameter("--server_tcp_port=", instance_.adb_host_port());
+
+    if (vsock_tunnel_enabled) {
       /**
        * This socket_vsock_proxy (a.k.a. sv proxy) runs on the host. It assumes
        * that another sv proxy runs inside the guest. see:
@@ -145,17 +168,9 @@
        * instance.adb_host_port()
        *
        */
-      adb_tunnel.AddParameter("--events_fd=", kernel_log_pipe_);
-      adb_tunnel.AddParameter("--start_event_id=", monitor::Event::AdbdStarted);
-      adb_tunnel.AddParameter("--server_type=tcp");
-      adb_tunnel.AddParameter("--server_fd=", tcp_server_);
       adb_tunnel.AddParameter("--client_type=vsock");
       adb_tunnel.AddParameter("--client_vsock_port=6520");
-      adb_tunnel.AddParameter("--client_vsock_id=", instance_.vsock_guest_cid());
-      commands.emplace_back(std::move(adb_tunnel));
-    }
-    if (helper_.VsockHalfTunnelEnabled()) {
-      Command adb_tunnel(SocketVsockProxyBinary());
+    } else {
       /*
        * This socket_vsock_proxy (a.k.a. sv proxy) runs on the host, and
        * cooperates with the adbd inside the guest. See this file:
@@ -166,16 +181,13 @@
        * should be therefore tcp, and the port should differ from instance to
        * instance and be equal to instance.adb_host_port()
        */
-      adb_tunnel.AddParameter("--events_fd=", kernel_log_pipe_);
-      adb_tunnel.AddParameter("--start_event_id=", monitor::Event::AdbdStarted);
-      adb_tunnel.AddParameter("--server_type=tcp");
-      adb_tunnel.AddParameter("--server_fd=", tcp_server_);
       adb_tunnel.AddParameter("--client_type=vsock");
       adb_tunnel.AddParameter("--client_vsock_port=", 5555);
-      adb_tunnel.AddParameter("--client_vsock_id=", instance_.vsock_guest_cid());
-      adb_tunnel.AddParameter("--label=", "adb");
-      commands.emplace_back(std::move(adb_tunnel));
     }
+
+    adb_tunnel.AddParameter("--client_vsock_id=", instance_.vsock_guest_cid());
+    adb_tunnel.AddParameter("--label=", "adb");
+    commands.emplace_back(std::move(adb_tunnel));
     return commands;
   }
 
@@ -189,11 +201,8 @@
   std::unordered_set<SetupFeature*> Dependencies() const override {
     return {static_cast<SetupFeature*>(&log_pipe_provider_)};
   }
+
   Result<void> ResultSetup() override {
-    tcp_server_ =
-        SharedFD::SocketLocalServer(instance_.adb_host_port(), SOCK_STREAM);
-    CF_EXPECT(tcp_server_->IsOpen(),
-              "Unable to create socket_vsock_proxy server socket: ");
     kernel_log_pipe_ = log_pipe_provider_.KernelLogPipe();
     return {};
   }
@@ -202,7 +211,6 @@
   const CuttlefishConfig::InstanceSpecific& instance_;
   KernelLogPipeProvider& log_pipe_provider_;
   SharedFD kernel_log_pipe_;
-  SharedFD tcp_server_;
 };
 
 }  // namespace
diff --git a/host/libs/config/config_flag.cpp b/host/libs/config/config_flag.cpp
index 457d60d..fd5bfce 100644
--- a/host/libs/config/config_flag.cpp
+++ b/host/libs/config/config_flag.cpp
@@ -123,7 +123,10 @@
         "device/google/cuttlefish/shared/config/config_*.json for possible "
         "values.";
     auto getter = [this]() { return config_; };
-    auto setter = [this](const FlagMatch& m) { return ChooseConfig(m.value); };
+    auto setter = [this](const FlagMatch& m) -> Result<void> {
+      CF_EXPECT(ChooseConfig(m.value));
+      return {};
+    };
     flag_ = GflagsCompatFlag("config").Help(help).Getter(getter).Setter(setter);
   }
 
@@ -163,15 +166,13 @@
   }
 
  private:
-  bool ChooseConfig(const std::string& name) {
-    if (!config_reader_.HasConfig(name)) {
-      LOG(ERROR) << "Invalid --config option '" << name << "'. Valid options: "
-                 << android::base::Join(config_reader_.AvailableConfigs(), ",");
-      return false;
-    }
+  Result<void> ChooseConfig(const std::string& name) {
+    CF_EXPECTF(config_reader_.HasConfig(name),
+               "Invalid --config option '{}'. Valid options: [{}]", name,
+               fmt::join(config_reader_.AvailableConfigs(), ","));
     config_ = name;
     is_default_ = false;
-    return true;
+    return {};
   }
   std::optional<std::string> FindAndroidInfoConfig() const {
     auto info_path = system_image_dir_flag_.Path() + "/android-info.txt";
diff --git a/host/libs/config/custom_actions.cpp b/host/libs/config/custom_actions.cpp
index e98c46c..87aa948 100644
--- a/host/libs/config/custom_actions.cpp
+++ b/host/libs/config/custom_actions.cpp
@@ -213,19 +213,19 @@
         "empty then the custom action config will be empty as well.");
     custom_action_config_flag_.Getter(
         [this]() { return custom_action_config_[0]; });
-    custom_action_config_flag_.Setter([this](const FlagMatch& match) {
-      if (!match.value.empty() &&
-          (match.value == "unset" || match.value == "\"unset\"")) {
-        custom_action_config_.push_back(DefaultCustomActionConfig());
-      } else if (!match.value.empty() && !FileExists(match.value)) {
-        LOG(ERROR) << "custom_action_config file \"" << match.value << "\" "
-                   << "does not exist.";
-        return false;
-      } else {
-        custom_action_config_.push_back(match.value);
-      }
-      return true;
-    });
+    custom_action_config_flag_.Setter(
+        [this](const FlagMatch& match) -> Result<void> {
+          if (!match.value.empty() &&
+              (match.value == "unset" || match.value == "\"unset\"")) {
+            custom_action_config_.push_back(DefaultCustomActionConfig());
+          } else if (!match.value.empty() && !FileExists(match.value)) {
+            return CF_ERRF("custom_action_config file \"{}\" does not exist.",
+                           match.value);
+          } else {
+            custom_action_config_.push_back(match.value);
+          }
+          return {};
+        });
     // TODO(schuffelen): Access ConfigFlag directly for these values.
     custom_actions_flag_ = GflagsCompatFlag("custom_actions");
     custom_actions_flag_.Help(
@@ -234,23 +234,16 @@
         "preset config files; prefer --custom_action_config to specify a "
         "custom config file on the command line. Actions in this flag are "
         "combined with actions in --custom_action_config.");
-    custom_actions_flag_.Setter([this](const FlagMatch& match) {
+    custom_actions_flag_.Setter([this](const FlagMatch& match) -> Result<void> {
       // Load the custom action from the --config preset file.
       if (match.value == "unset" || match.value == "\"unset\"") {
         AddEmptyJsonCustomActionConfigs();
-        return true;
+        return {};
       }
-      Json::CharReaderBuilder builder;
-      std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
-      std::string errorMessage;
-      Json::Value custom_action_array(Json::arrayValue);
-      if (!reader->parse(&*match.value.begin(), &*match.value.end(),
-                         &custom_action_array, &errorMessage)) {
-        LOG(ERROR) << "Could not read custom actions config flag: "
-                   << errorMessage;
-        return false;
-      }
-      return AddJsonCustomActionConfigs(custom_action_array);
+      auto custom_action_array = CF_EXPECT(
+          ParseJson(match.value), "Could not read custom actions config flag");
+      CF_EXPECT(AddJsonCustomActionConfigs(custom_action_array));
+      return {};
     });
   }
 
diff --git a/host/libs/config/cuttlefish_config.cpp b/host/libs/config/cuttlefish_config.cpp
index c9fb6c5..6e34dbd 100644
--- a/host/libs/config/cuttlefish_config.cpp
+++ b/host/libs/config/cuttlefish_config.cpp
@@ -331,6 +331,22 @@
   (*dictionary_)[kNetsimInstanceNum] = netsim_instance_num;
 }
 
+static constexpr char kNetsimArgs[] = "netsim_args";
+void CuttlefishConfig::set_netsim_args(const std::string& netsim_args) {
+  Json::Value args_json_obj(Json::arrayValue);
+  for (const auto& arg : android::base::Tokenize(netsim_args, " ")) {
+    args_json_obj.append(arg);
+  }
+  (*dictionary_)[kNetsimArgs] = args_json_obj;
+}
+std::vector<std::string> CuttlefishConfig::netsim_args() const {
+  std::vector<std::string> netsim_args;
+  for (const Json::Value& arg : (*dictionary_)[kNetsimArgs]) {
+    netsim_args.push_back(arg.asString());
+  }
+  return netsim_args;
+}
+
 static constexpr char kEnableMetrics[] = "enable_metrics";
 void CuttlefishConfig::set_enable_metrics(std::string enable_metrics) {
   (*dictionary_)[kEnableMetrics] = kUnknown;
@@ -490,6 +506,14 @@
   (*dictionary_)[kRootcanalTestPort] = rootcanal_test_port;
 }
 
+static constexpr char kSnapshotPath[] = "snapshot_path";
+std::string CuttlefishConfig::snapshot_path() const {
+  return (*dictionary_)[kSnapshotPath].asString();
+}
+void CuttlefishConfig::set_snapshot_path(const std::string& snapshot_path) {
+  (*dictionary_)[kSnapshotPath] = snapshot_path;
+}
+
 /*static*/ CuttlefishConfig* CuttlefishConfig::BuildConfigImpl(
     const std::string& path) {
   auto ret = new CuttlefishConfig();
diff --git a/host/libs/config/cuttlefish_config.h b/host/libs/config/cuttlefish_config.h
index fb83e7e..08d0f72 100644
--- a/host/libs/config/cuttlefish_config.h
+++ b/host/libs/config/cuttlefish_config.h
@@ -37,38 +37,42 @@
 }
 
 namespace cuttlefish {
-constexpr char kLogcatSerialMode[] = "serial";
-constexpr char kLogcatVsockMode[] = "vsock";
 
-constexpr char kDefaultUuidPrefix[] = "699acfc4-c8c4-11e7-882b-5065f31dc1";
-constexpr char kCuttlefishConfigEnvVarName[] = "CUTTLEFISH_CONFIG_FILE";
-constexpr char kCuttlefishInstanceEnvVarName[] = "CUTTLEFISH_INSTANCE";
-constexpr char kVsocUserPrefix[] = "vsoc-";
-constexpr char kCvdNamePrefix[] = "cvd-";
-constexpr char kBootStartedMessage[] ="VIRTUAL_DEVICE_BOOT_STARTED";
-constexpr char kBootCompletedMessage[] = "VIRTUAL_DEVICE_BOOT_COMPLETED";
-constexpr char kBootFailedMessage[] = "VIRTUAL_DEVICE_BOOT_FAILED";
-constexpr char kMobileNetworkConnectedMessage[] =
+inline constexpr char kLogcatSerialMode[] = "serial";
+inline constexpr char kLogcatVsockMode[] = "vsock";
+
+inline constexpr char kDefaultUuidPrefix[] =
+    "699acfc4-c8c4-11e7-882b-5065f31dc1";
+inline constexpr char kCuttlefishConfigEnvVarName[] = "CUTTLEFISH_CONFIG_FILE";
+inline constexpr char kCuttlefishInstanceEnvVarName[] = "CUTTLEFISH_INSTANCE";
+inline constexpr char kVsocUserPrefix[] = "vsoc-";
+inline constexpr char kCvdNamePrefix[] = "cvd-";
+inline constexpr char kBootStartedMessage[] = "VIRTUAL_DEVICE_BOOT_STARTED";
+inline constexpr char kBootCompletedMessage[] = "VIRTUAL_DEVICE_BOOT_COMPLETED";
+inline constexpr char kBootFailedMessage[] = "VIRTUAL_DEVICE_BOOT_FAILED";
+inline constexpr char kMobileNetworkConnectedMessage[] =
     "VIRTUAL_DEVICE_NETWORK_MOBILE_CONNECTED";
-constexpr char kWifiConnectedMessage[] =
+inline constexpr char kWifiConnectedMessage[] =
     "VIRTUAL_DEVICE_NETWORK_WIFI_CONNECTED";
-constexpr char kEthernetConnectedMessage[] =
+inline constexpr char kEthernetConnectedMessage[] =
     "VIRTUAL_DEVICE_NETWORK_ETHERNET_CONNECTED";
 // TODO(b/131864854): Replace this with a string less likely to change
-constexpr char kAdbdStartedMessage[] =
+inline constexpr char kAdbdStartedMessage[] =
     "init: starting service 'adbd'...";
-constexpr char kFastbootdStartedMessage[] =
+inline constexpr char kFastbootdStartedMessage[] =
     "init: starting service 'fastbootd'...";
-constexpr char kScreenChangedMessage[] = "VIRTUAL_DEVICE_SCREEN_CHANGED";
-constexpr char kDisplayPowerModeChangedMessage[] =
+inline constexpr char kFastbootStartedMessage[] =
+    "Listening for fastboot command on tcp";
+inline constexpr char kScreenChangedMessage[] = "VIRTUAL_DEVICE_SCREEN_CHANGED";
+inline constexpr char kDisplayPowerModeChangedMessage[] =
     "VIRTUAL_DEVICE_DISPLAY_POWER_MODE_CHANGED";
-constexpr char kInternalDirName[] = "internal";
-constexpr char kGrpcSocketDirName[] = "grpc_socket";
-constexpr char kSharedDirName[] = "shared";
-constexpr char kLogDirName[] = "logs";
-constexpr char kCrosvmVarEmptyDir[] = "/var/empty";
-constexpr char kKernelLoadedMessage[] = "] Linux version";
-constexpr char kBootloaderLoadedMessage[] = "U-Boot 20";
+inline constexpr char kInternalDirName[] = "internal";
+inline constexpr char kGrpcSocketDirName[] = "grpc_socket";
+inline constexpr char kSharedDirName[] = "shared";
+inline constexpr char kLogDirName[] = "logs";
+inline constexpr char kCrosvmVarEmptyDir[] = "/var/empty";
+inline constexpr char kKernelLoadedMessage[] = "] Linux version";
+inline constexpr char kBootloaderLoadedMessage[] = "U-Boot 20";
 
 enum class SecureHal {
   Unknown,
@@ -164,6 +168,8 @@
   bool netsim_radio_enabled(NetsimRadio flag) const;
   void set_netsim_instance_num(int netsim_instance_num);
   int netsim_instance_num() const;
+  void set_netsim_args(const std::string& netsim_args);
+  std::vector<std::string> netsim_args() const;
 
   enum Answer {
     kUnknown = 0,
@@ -254,6 +260,10 @@
   std::string ap_image_dev_path() const;
   void set_ap_image_dev_path(const std::string& dev_path);
 
+  // path to the saved snapshot file(s)
+  std::string snapshot_path() const;
+  void set_snapshot_path(const std::string& snapshot_path);
+
   class InstanceSpecific;
   class MutableInstanceSpecific;
 
@@ -306,6 +316,8 @@
     std::string adb_ip_and_port() const;
     // Port number to connect to the camera hal on the guest
     int camera_server_port() const;
+    // Port number to connect to the lights hal on the guest
+    int lights_server_port() const;
 
     std::string adb_device_name() const;
     std::string gnss_file_path() const;
@@ -465,6 +477,14 @@
     bool crosvm_use_balloon() const;
     bool crosvm_use_rng() const;
     bool use_pmem() const;
+    /* fmayle@ found out that when cuttlefish starts from the saved snapshot
+     * that was saved after ADBD start event, the socket_vsock_proxy must not
+     * wait for the AdbdStarted event.
+     *
+     * This instance-specific configuration tells the host sock_vsock_proxy
+     * not to wait for the adbd start event.
+     */
+    bool sock_vsock_proxy_wait_adbd_start() const;
 
     // Wifi MAC address inside the guest
     int wifi_mac_prefix() const;
@@ -560,6 +580,9 @@
     std::string gpu_angle_feature_overrides_disabled() const;
     std::string gpu_capture_binary() const;
     bool enable_gpu_udmabuf() const;
+    bool enable_gpu_vhost_user() const;
+    bool enable_gpu_external_blob() const;
+    bool enable_gpu_system_blob() const;
 
     std::string hwcomposer() const;
 
@@ -633,6 +656,7 @@
     void set_keymaster_vsock_port(int keymaster_vsock_port);
     void set_vehicle_hal_server_port(int vehicle_server_port);
     void set_audiocontrol_server_port(int audiocontrol_server_port);
+    void set_lights_server_port(int lights_server_port);
     void set_adb_host_port(int adb_host_port);
     void set_modem_simulator_host_id(int modem_simulator_id);
     void set_adb_ip_and_port(const std::string& ip_port);
@@ -668,6 +692,7 @@
     void set_crosvm_use_balloon(const bool use_balloon);
     void set_crosvm_use_rng(const bool use_rng);
     void set_use_pmem(const bool use_pmem);
+    void set_sock_vsock_proxy_wait_adbd_start(const bool);
     // Wifi MAC address inside the guest
     void set_wifi_mac_prefix(const int wifi_mac_prefix);
     // Gnss grpc proxy server port inside the host
@@ -740,6 +765,9 @@
     void set_gpu_angle_feature_overrides_disabled(const std::string& overrides);
     void set_gpu_capture_binary(const std::string&);
     void set_enable_gpu_udmabuf(const bool enable_gpu_udmabuf);
+    void set_enable_gpu_vhost_user(const bool enable_gpu_vhost_user);
+    void set_enable_gpu_external_blob(const bool enable_gpu_external_blob);
+    void set_enable_gpu_system_blob(const bool enable_gpu_system_blob);
 
     void set_hwcomposer(const std::string&);
 
diff --git a/host/libs/config/cuttlefish_config_instance.cpp b/host/libs/config/cuttlefish_config_instance.cpp
index deb7ab8..b8e73f1 100644
--- a/host/libs/config/cuttlefish_config_instance.cpp
+++ b/host/libs/config/cuttlefish_config_instance.cpp
@@ -712,6 +712,33 @@
   return (*Dictionary())[kEnableGpuUdmabuf].asBool();
 }
 
+static constexpr char kEnableGpuVhostUser[] = "enable_gpu_vhost_user";
+void CuttlefishConfig::MutableInstanceSpecific::set_enable_gpu_vhost_user(
+    const bool enable_gpu_vhost_user) {
+  (*Dictionary())[kEnableGpuVhostUser] = enable_gpu_vhost_user;
+}
+bool CuttlefishConfig::InstanceSpecific::enable_gpu_vhost_user() const {
+  return (*Dictionary())[kEnableGpuVhostUser].asBool();
+}
+
+static constexpr char kEnableGpuExternalBlob[] = "enable_gpu_external_blob";
+void CuttlefishConfig::MutableInstanceSpecific::set_enable_gpu_external_blob(
+    const bool enable_gpu_external_blob) {
+  (*Dictionary())[kEnableGpuExternalBlob] = enable_gpu_external_blob;
+}
+bool CuttlefishConfig::InstanceSpecific::enable_gpu_external_blob() const {
+  return (*Dictionary())[kEnableGpuExternalBlob].asBool();
+}
+
+static constexpr char kEnableGpuSystemBlob[] = "enable_gpu_system_blob";
+void CuttlefishConfig::MutableInstanceSpecific::set_enable_gpu_system_blob(
+    const bool enable_gpu_system_blob) {
+  (*Dictionary())[kEnableGpuSystemBlob] = enable_gpu_system_blob;
+}
+bool CuttlefishConfig::InstanceSpecific::enable_gpu_system_blob() const {
+  return (*Dictionary())[kEnableGpuSystemBlob].asBool();
+}
+
 static constexpr char kEnableAudio[] = "enable_audio";
 void CuttlefishConfig::MutableInstanceSpecific::set_enable_audio(bool enable) {
   (*Dictionary())[kEnableAudio] = enable;
@@ -1358,6 +1385,14 @@
   (*Dictionary())[kConfigServerPort] = config_server_port;
 }
 
+static constexpr char kLightsServerPort[] = "lights_server_port";
+int CuttlefishConfig::InstanceSpecific::lights_server_port() const {
+  return (*Dictionary())[kLightsServerPort].asInt();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_lights_server_port(int lights_server_port) {
+  (*Dictionary())[kLightsServerPort] = lights_server_port;
+}
+
 static constexpr char kCameraServerPort[] = "camera_server_port";
 int CuttlefishConfig::InstanceSpecific::camera_server_port() const {
   return (*Dictionary())[kCameraServerPort].asInt();
@@ -1471,6 +1506,17 @@
   return (*Dictionary())[kCrosvmUsePmem].asBool();
 }
 
+static constexpr char kSockVsockWaitAdbdStart[] =
+    "sock_vsock_proxy_wait_adbd_start";
+void CuttlefishConfig::MutableInstanceSpecific::
+    set_sock_vsock_proxy_wait_adbd_start(const bool wait_adbd_start) {
+  (*Dictionary())[kSockVsockWaitAdbdStart] = wait_adbd_start;
+}
+bool CuttlefishConfig::InstanceSpecific::sock_vsock_proxy_wait_adbd_start()
+    const {
+  return (*Dictionary())[kSockVsockWaitAdbdStart].asBool();
+}
+
 std::string CuttlefishConfig::InstanceSpecific::touch_socket_path(
     int screen_idx) const {
   return PerInstanceInternalUdsPath(
diff --git a/host/libs/config/data_image.cpp b/host/libs/config/data_image.cpp
index 7769672..9b2ea7e 100644
--- a/host/libs/config/data_image.cpp
+++ b/host/libs/config/data_image.cpp
@@ -22,7 +22,6 @@
 
 #include "common/libs/fs/shared_buf.h"
 #include "common/libs/utils/files.h"
-#include "common/libs/utils/network.h"
 #include "common/libs/utils/result.h"
 #include "common/libs/utils/subprocess.h"
 #include "host/libs/config/esp.h"
@@ -33,10 +32,10 @@
 namespace cuttlefish {
 
 namespace {
-const std::string kDataPolicyUseExisting = "use_existing";
-const std::string kDataPolicyCreateIfMissing = "create_if_missing";
-const std::string kDataPolicyAlwaysCreate = "always_create";
-const std::string kDataPolicyResizeUpTo= "resize_up_to";
+
+static constexpr std::string_view kDataPolicyUseExisting = "use_existing";
+static constexpr std::string_view kDataPolicyAlwaysCreate = "always_create";
+static constexpr std::string_view kDataPolicyResizeUpTo = "resize_up_to";
 
 const int FSCK_ERROR_CORRECTED = 1;
 const int FSCK_ERROR_CORRECTED_REQUIRES_REBOOT = 2;
@@ -142,8 +141,8 @@
     MasterBootRecord mbr = {
         .partitions = {{
             .partition_type = 0xC,
-            .first_lba = (std::uint32_t) offset_size_bytes / SECTOR_SIZE,
-            .num_sectors = (std::uint32_t) image_size_bytes / SECTOR_SIZE,
+            .first_lba = (std::uint32_t)offset_size_bytes / kSectorSize,
+            .num_sectors = (std::uint32_t)image_size_bytes / kSectorSize,
         }},
         .boot_signature = {0x55, 0xAA},
     };
diff --git a/host/libs/config/display.cpp b/host/libs/config/display.cpp
index 0e5a111..6c6540d 100644
--- a/host/libs/config/display.cpp
+++ b/host/libs/config/display.cpp
@@ -111,9 +111,9 @@
           .Help(kDisplayHelp),
       GflagsCompatFlag(kDisplayFlag)
           .Help(kDisplayHelp)
-          .Setter([&](const FlagMatch& match) {
+          .Setter([&](const FlagMatch& match) -> Result<void> {
             repeated_display_flag_values.push_back(match.value);
-            return true;
+            return {};
           }),
   };
 
@@ -148,4 +148,4 @@
   return displays_configs;
 }
 
-}  // namespace cuttlefish
\ No newline at end of file
+}  // namespace cuttlefish
diff --git a/host/libs/config/esp.cpp b/host/libs/config/esp.cpp
index c0b6bdd..f16a52d 100644
--- a/host/libs/config/esp.cpp
+++ b/host/libs/config/esp.cpp
@@ -13,7 +13,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+#include <algorithm>
+#include <array>
 #include <sstream>
+#include <string>
+#include <utility>
+#include <vector>
 
 #include "host/libs/config/esp.h"
 #include "common/libs/fs/shared_buf.h"
@@ -23,6 +28,60 @@
 
 namespace cuttlefish {
 
+// For licensing and build reproducibility reasons, pick up the bootloaders
+// from the host Linux distribution (if present) and pack them into the
+// automatically generated ESP. If the user wants their own bootloaders,
+// they can use -esp_image=/path/to/esp.img to override, so we don't need
+// to accommodate customizations of this packing process.
+
+// Currently we only support Debian based distributions, and GRUB is built
+// for those distros to always load grub.cfg from EFI/debian/grub.cfg, and
+// nowhere else. If you want to add support for other distros, make the
+// extra directories below and copy the initial grub.cfg there as well
+//
+// Currently the Cuttlefish bootloaders are built only for x86 (32-bit),
+// ARM (QEMU only, 32-bit) and AArch64 (64-bit), and U-Boot will hard-code
+// these search paths. Install all bootloaders to one of these paths.
+// NOTE: For now, just ignore the 32-bit ARM version, as Debian doesn't
+//       build an EFI monolith for this architecture.
+// These are the paths Debian installs the monoliths to. If another distro
+// uses an alternative monolith path, add it to this table
+static constexpr char kBootSrcPathIA32[] =
+    "/usr/lib/grub/i386-efi/monolithic/grubia32.efi";
+static constexpr char kBootDestPathIA32[] = "/EFI/BOOT/BOOTIA32.EFI";
+
+static constexpr char kBootSrcPathAA64[] =
+    "/usr/lib/grub/arm64-efi/monolithic/grubaa64.efi";
+static constexpr char kBootDestPathAA64[] = "/EFI/BOOT/BOOTAA64.EFI";
+
+static constexpr char kMultibootModuleSrcPathIA32[] =
+    "/usr/lib/grub/i386-efi/multiboot.mod";
+static constexpr char kMultibootModuleDestPathIA32[] =
+    "/EFI/modules/multiboot.mod";
+
+static constexpr char kMultibootModuleSrcPathAA64[] =
+    "/usr/lib/grub/arm64-efi/multiboot.mod";
+static constexpr char kMultibootModuleDestPathAA64[] =
+    "/EFI/modules/multiboot.mod";
+
+static constexpr char kKernelDestPath[] = "/vmlinuz";
+static constexpr char kInitrdDestPath[] = "/initrd";
+static constexpr char kZedbootDestPath[] = "/zedboot.zbi";
+static constexpr char kMultibootBinDestPath[] = "/multiboot.bin";
+
+// TODO(b/260338443, b/260337906) remove ubuntu and debian variations
+// after migrating to grub-mkimage or adding grub binaries as a prebuilt
+static constexpr char kGrubDebianConfigDestPath[] = "/EFI/debian/grub.cfg";
+static constexpr char kGrubUbuntuConfigDestPath[] = "/EFI/ubuntu/grub.cfg";
+static constexpr char kGrubConfigDestDirectoryPath[] = "/boot/grub";
+static constexpr char kGrubConfigDestPath[] = "/boot/grub/grub.cfg";
+
+static constexpr std::array kGrubModulesX86{
+    "normal", "configfile", "linux", "linuxefi",   "multiboot", "ls",
+    "cat",    "help",       "fat",   "part_msdos", "part_gpt"};
+static constexpr char kGrubModulesPath[] = "/usr/lib/grub/";
+static constexpr char kGrubModulesX86Name[] = "i386-efi";
+
 bool NewfsMsdos(const std::string& data_image, int data_image_mb,
                 int offset_num_mb) {
   off_t image_size_bytes = static_cast<off_t>(data_image_mb) << 20;
@@ -65,10 +124,9 @@
     case Arch::X86:
     case Arch::X86_64: {
       const auto x86_modules = std::string(kGrubModulesPath) + std::string(kGrubModulesX86Name);
-      const auto modules_presented = all_of(kGrubModulesX86.begin(), kGrubModulesX86.end(),
-                                            [&](const std::string& m) {
-                                              return FileExists(x86_modules + m);
-                                            });
+      const auto modules_presented = std::all_of(
+          kGrubModulesX86.begin(), kGrubModulesX86.end(),
+          [&](const std::string& m) { return FileExists(x86_modules + m); });
       if (modules_presented) return true;
 
       const auto monolith_presented = FileExists(kBootSrcPathIA32);
@@ -79,8 +137,8 @@
   return false;
 }
 
-bool MsdosMakeDirectories(const std::string& image_path,
-                          const std::vector<std::string>& directories) {
+static bool MsdosMakeDirectories(const std::string& image_path,
+                                 const std::vector<std::string>& directories) {
   auto mmd = HostBinaryPath("mmd");
   std::vector<std::string> command {mmd, "-i", image_path};
   command.insert(command.end(), directories.begin(), directories.end());
@@ -92,8 +150,8 @@
   return true;
 }
 
-bool CopyToMsdos(const std::string& image, const std::string& path,
-                 const std::string& destination) {
+static bool CopyToMsdos(const std::string& image, const std::string& path,
+                        const std::string& destination) {
   const auto mcopy = HostBinaryPath("mcopy");
   const auto success =
       Execute({mcopy, "-o", "-i", image, "-s", path, destination});
@@ -103,9 +161,10 @@
   return true;
 }
 
-bool GrubMakeImage(const std::string& prefix, const std::string& format,
-                   const std::string& directory, const std::string& output,
-                   std::vector<std::string> modules) {
+template <typename T>
+static bool GrubMakeImage(const std::string& prefix, const std::string& format,
+                          const std::string& directory,
+                          const std::string& output, const T& modules) {
   std::vector<std::string> command = {"grub-mkimage", "--prefix", prefix,
                                       "--format", format, "--directory", directory,
                                       "--output", output};
diff --git a/host/libs/config/esp.h b/host/libs/config/esp.h
index 8cb782b..f6850f3 100644
--- a/host/libs/config/esp.h
+++ b/host/libs/config/esp.h
@@ -15,65 +15,15 @@
 
 #pragma once
 
-#include <utility>
 #include <optional>
 #include <string>
+#include <utility>
 #include <vector>
 
-#include "host/libs/config/cuttlefish_config.h"
 #include "common/libs/utils/environment.h"
 
 namespace cuttlefish {
 
-// For licensing and build reproducibility reasons, pick up the bootloaders
-// from the host Linux distribution (if present) and pack them into the
-// automatically generated ESP. If the user wants their own bootloaders,
-// they can use -esp_image=/path/to/esp.img to override, so we don't need
-// to accommodate customizations of this packing process.
-
-// Currently we only support Debian based distributions, and GRUB is built
-// for those distros to always load grub.cfg from EFI/debian/grub.cfg, and
-// nowhere else. If you want to add support for other distros, make the
-// extra directories below and copy the initial grub.cfg there as well
-//
-// Currently the Cuttlefish bootloaders are built only for x86 (32-bit),
-// ARM (QEMU only, 32-bit) and AArch64 (64-bit), and U-Boot will hard-code
-// these search paths. Install all bootloaders to one of these paths.
-// NOTE: For now, just ignore the 32-bit ARM version, as Debian doesn't
-//       build an EFI monolith for this architecture.
-// These are the paths Debian installs the monoliths to. If another distro
-// uses an alternative monolith path, add it to this table
-static constexpr char kBootSrcPathIA32[] = "/usr/lib/grub/i386-efi/monolithic/grubia32.efi";
-static constexpr char kBootDestPathIA32[] = "/EFI/BOOT/BOOTIA32.EFI";
-
-static constexpr char kBootSrcPathAA64[] = "/usr/lib/grub/arm64-efi/monolithic/grubaa64.efi";
-static constexpr char kBootDestPathAA64[] = "/EFI/BOOT/BOOTAA64.EFI";
-
-static constexpr char kMultibootModuleSrcPathIA32[] = "/usr/lib/grub/i386-efi/multiboot.mod";
-static constexpr char kMultibootModuleDestPathIA32[] = "/EFI/modules/multiboot.mod";
-
-static constexpr char kMultibootModuleSrcPathAA64[] = "/usr/lib/grub/arm64-efi/multiboot.mod";
-static constexpr char kMultibootModuleDestPathAA64[] = "/EFI/modules/multiboot.mod";
-
-static constexpr char kKernelDestPath[] = "/vmlinuz";
-static constexpr char kInitrdDestPath[] = "/initrd";
-static constexpr char kZedbootDestPath[] = "/zedboot.zbi";
-static constexpr char kMultibootBinDestPath[] = "/multiboot.bin";
-
-// TODO(b/260338443, b/260337906) remove ubuntu and debian variations
-// after migrating to grub-mkimage or adding grub binaries as a prebuilt
-static constexpr char kGrubDebianConfigDestPath[] = "/EFI/debian/grub.cfg";
-static constexpr char kGrubUbuntuConfigDestPath[] = "/EFI/ubuntu/grub.cfg";
-static constexpr char kGrubConfigDestDirectoryPath[] = "/boot/grub";
-static constexpr char kGrubConfigDestPath[] = "/boot/grub/grub.cfg";
-
-const std::vector<std::string> kGrubModulesX86 =
-    {"normal", "configfile", "linux", "linuxefi", "multiboot",
-     "ls", "cat", "help", "fat", "part_msdos", "part_gpt"};
-static constexpr char kGrubModulesPath[] = "/usr/lib/grub/";
-static constexpr char kGrubModulesX86Name[] = "i386-efi";
-static constexpr char kGrubModulesArm64Name[] = "arm64-efi";
-
 class LinuxEspBuilder final {
  public:
   LinuxEspBuilder() = delete;
diff --git a/host/libs/config/fastboot/Android.bp b/host/libs/config/fastboot/Android.bp
index 978c4e4..c2fb041 100644
--- a/host/libs/config/fastboot/Android.bp
+++ b/host/libs/config/fastboot/Android.bp
@@ -17,7 +17,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_host_config_fastboot",
     srcs: [
         "config.cpp",
@@ -27,6 +27,9 @@
     ],
     shared_libs: [
         "libbase",
+        "libcuttlefish_fs",
+        "libcuttlefish_host_config",
+        "libcuttlefish_utils",
         "libfruit",
         "libjsoncpp",
     ],
diff --git a/host/libs/config/fastboot/fastboot.h b/host/libs/config/fastboot/fastboot.h
index ddccf1d..607a78b 100644
--- a/host/libs/config/fastboot/fastboot.h
+++ b/host/libs/config/fastboot/fastboot.h
@@ -42,7 +42,8 @@
 FastbootConfigFlagComponent();
 fruit::Component<fruit::Required<FastbootConfig>, FastbootConfigFragment>
 FastbootConfigFragmentComponent();
-fruit::Component<fruit::Required<const CuttlefishConfig::InstanceSpecific,
+fruit::Component<fruit::Required<KernelLogPipeProvider,
+                                 const CuttlefishConfig::InstanceSpecific,
                                  const FastbootConfig>>
 LaunchFastbootComponent();
 
diff --git a/host/libs/config/fastboot/launch.cpp b/host/libs/config/fastboot/launch.cpp
index adf6e5e..3686378 100644
--- a/host/libs/config/fastboot/launch.cpp
+++ b/host/libs/config/fastboot/launch.cpp
@@ -27,18 +27,23 @@
 namespace cuttlefish {
 namespace {
 
-class FastbootProxy : public CommandSource {
+class FastbootProxy : public CommandSource, public KernelLogPipeConsumer {
  public:
   INJECT(FastbootProxy(const CuttlefishConfig::InstanceSpecific& instance,
-                       const FastbootConfig& fastboot_config))
+                       const FastbootConfig& fastboot_config,
+                       KernelLogPipeProvider& log_pipe_provider))
       : instance_(instance),
-        fastboot_config_(fastboot_config) {}
+        fastboot_config_(fastboot_config),
+        log_pipe_provider_(log_pipe_provider) {}
 
   Result<std::vector<MonitorCommand>> Commands() override {
     const std::string ethernet_host = instance_.ethernet_ipv6() + "%" +
                                       instance_.ethernet_bridge_name();
 
     Command tunnel(SocketVsockProxyBinary());
+    tunnel.AddParameter("--events_fd=", kernel_log_pipe_);
+    tunnel.AddParameter("--start_event_id=", monitor::Event::FastbootStarted);
+    tunnel.AddParameter("--stop_event_id=", monitor::Event::AdbdStarted);
     tunnel.AddParameter("--server_type=", "tcp");
     tunnel.AddParameter("--server_tcp_port=", instance_.fastboot_host_port());
     tunnel.AddParameter("--client_type=", "tcp");
@@ -59,22 +64,29 @@
 
  private:
   std::unordered_set<SetupFeature*> Dependencies() const override {
+    return {static_cast<SetupFeature*>(&log_pipe_provider_)};
+  }
+
+  Result<void> ResultSetup() override {
+    kernel_log_pipe_ = log_pipe_provider_.KernelLogPipe();
     return {};
   }
 
-  Result<void> ResultSetup() override { return {}; }
-
   const CuttlefishConfig::InstanceSpecific& instance_;
   const FastbootConfig& fastboot_config_;
+  KernelLogPipeProvider& log_pipe_provider_;
+  SharedFD kernel_log_pipe_;
 };
 
 }  // namespace
 
-fruit::Component<fruit::Required<const CuttlefishConfig::InstanceSpecific,
+fruit::Component<fruit::Required<KernelLogPipeProvider,
+                                 const CuttlefishConfig::InstanceSpecific,
                                  const FastbootConfig>>
 LaunchFastbootComponent() {
   return fruit::createComponent()
       .addMultibinding<CommandSource, FastbootProxy>()
+      .addMultibinding<KernelLogPipeConsumer, FastbootProxy>()
       .addMultibinding<SetupFeature, FastbootProxy>();
 }
 
diff --git a/host/libs/config/mbr.h b/host/libs/config/mbr.h
index 3388237..33f4db7 100644
--- a/host/libs/config/mbr.h
+++ b/host/libs/config/mbr.h
@@ -15,8 +15,10 @@
  */
 #pragma once
 
-constexpr int SECTOR_SIZE_SHIFT = 9;
-constexpr int SECTOR_SIZE = 1 << SECTOR_SIZE_SHIFT;
+#include <cstdint>
+
+inline constexpr int kSectorSizeShift = 9;
+inline constexpr int kSectorSize = 1 << kSectorSizeShift;
 
 struct __attribute__((packed)) MbrPartitionEntry {
   std::uint8_t status;
@@ -33,4 +35,4 @@
   std::uint8_t boot_signature[2];
 };
 
-static_assert(sizeof(MasterBootRecord) == SECTOR_SIZE);
+static_assert(sizeof(MasterBootRecord) == kSectorSize);
diff --git a/host/libs/confui/Android.bp b/host/libs/confui/Android.bp
index be4b22a..450bda7 100644
--- a/host/libs/confui/Android.bp
+++ b/host/libs/confui/Android.bp
@@ -29,7 +29,7 @@
     ],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_confui_host",
     srcs: [
         "cbor.cc",
diff --git a/host/libs/control_env/Android.bp b/host/libs/control_env/Android.bp
index 8512584..144258a 100644
--- a/host/libs/control_env/Android.bp
+++ b/host/libs/control_env/Android.bp
@@ -17,7 +17,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_control_env",
     srcs: [
         "grpc_service_handler.cc",
@@ -25,15 +25,23 @@
     shared_libs: [
         "libbase",
         "libcuttlefish_utils",
+        "libprotobuf-cpp-full",
         "libgrpc++",
+        "libjsoncpp",
     ],
     static_libs: [
         "grpc_cli_libs",
         "libc++fs",
+        "libgflags",
     ],
     cflags: [
         "-Wno-unused-parameter",
     ],
     cpp_std: "c++17",
     defaults: ["cuttlefish_buildhost_only"],
+    target: {
+        darwin: {
+            enabled: true,
+        },
+    },
 }
diff --git a/host/libs/control_env/grpc_service_handler.cc b/host/libs/control_env/grpc_service_handler.cc
index 7ef3900..68a674d 100644
--- a/host/libs/control_env/grpc_service_handler.cc
+++ b/host/libs/control_env/grpc_service_handler.cc
@@ -18,12 +18,16 @@
 #include <unordered_map>
 
 #include <android-base/strings.h>
+#include <json/json.h>
 #include <test/cpp/util/grpc_tool.h>
 #include <test/cpp/util/test_config.h>
 
 #include "common/libs/utils/contains.h"
 #include "common/libs/utils/result.h"
 
+using android::base::EndsWith;
+using android::base::Split;
+using android::base::Trim;
 using grpc::InsecureChannelCredentials;
 
 namespace cuttlefish {
@@ -32,6 +36,12 @@
 constexpr char kDefaultOptionL[] = "-l=false";
 constexpr char kDefaultOptionJsonInput[] = "--json_input=true";
 constexpr char kDefaultOptionJsonOutput[] = "--json_output=true";
+constexpr char kServiceServerReflection[] =
+    "grpc.reflection.v1alpha.ServerReflection";
+constexpr char kServiceHealth[] = "grpc.health.v1.Health";
+constexpr char kServiceControlEnvProxy[] = "ControlEnvProxyService";
+constexpr char kServiceControlEnvProxyFull[] =
+    "controlenvproxyserver.ControlEnvProxyService";
 
 bool PrintStream(std::stringstream* ss, const grpc::string& output) {
   (*ss) << output;
@@ -91,6 +101,11 @@
   return output_stream.str();
 }
 
+Result<std::string> RunGrpcCommand(const std::vector<std::string>& arguments) {
+  std::vector<std::string> options;
+  return RunGrpcCommand(arguments, options);
+}
+
 Result<std::vector<std::string>> GetServiceList(
     const std::string& server_address) {
   std::vector<std::string> service_list;
@@ -102,7 +117,8 @@
 
   std::string service_name;
   while (std::getline(output_stream, service_name)) {
-    if (service_name.compare("grpc.reflection.v1alpha.ServerReflection") == 0) {
+    if (service_name.compare(kServiceServerReflection) == 0 ||
+        service_name.compare(kServiceHealth) == 0) {
       continue;
     }
     service_list.emplace_back(service_name);
@@ -118,7 +134,7 @@
   for (const auto& server_address : server_address_list) {
     auto service_names = CF_EXPECT(GetServiceList(server_address));
     for (auto& full_service_name : service_names) {
-      if (android::base::EndsWith(full_service_name, service_name)) {
+      if (EndsWith(full_service_name, service_name)) {
         candidates.emplace_back(server_address);
         break;
       }
@@ -136,7 +152,7 @@
   std::vector<std::string> candidates;
   auto service_names = CF_EXPECT(GetServiceList(server_address));
   for (auto& full_service_name : service_names) {
-    if (android::base::EndsWith(full_service_name, service_name)) {
+    if (EndsWith(full_service_name, service_name)) {
       candidates.emplace_back(full_service_name);
     }
   }
@@ -155,107 +171,114 @@
   return full_service_name + "/" + method_name;
 }
 
-Result<std::string> GetFullTypeName(const std::string& server_address,
-                                    const std::string& service_name,
-                                    const std::string& method_name,
-                                    const std::string& type_name) {
-  // Run grpc_cli ls -l for given method to extract full type name.
-  // Example output:
-  //   rpc OpenwrtIpaddr(google.protobuf.Empty) returns
-  //   (openwrtcontrolserver.OpenwrtIpaddrReply) {}
-  const auto& full_method_name =
-      CF_EXPECT(GetFullMethodName(server_address, service_name, method_name));
-  std::vector<std::string> arguments{"grpc_cli", "ls", server_address,
-                                     full_method_name};
-  std::vector<std::string> options{"-l"};
-  auto grpc_result = CF_EXPECT(RunGrpcCommand(arguments, options));
-
-  std::vector<std::string> candidates;
-  for (auto& full_type_name : android::base::Split(grpc_result, "()")) {
-    if (android::base::EndsWith(full_type_name, type_name)) {
-      candidates.emplace_back(full_type_name);
-    }
-  }
-
-  CF_EXPECT(candidates.size() > 0, service_name + " is not found.");
-  CF_EXPECT(candidates.size() < 2, service_name + " is ambiguous.");
-
-  return candidates[0];
-}
-
 Result<std::string> HandleLsCmd(
     const std::vector<std::string>& server_address_list,
-    const std::vector<std::string>& args,
-    const std::vector<std::string>& options) {
-  CF_EXPECT(args.size() < 3, "too many arguments");
-  std::string command_output;
+    const std::vector<std::string>& args) {
+  switch (args.size()) {
+    case 0: {
+      // ls subcommand with no arguments
+      std::string command_output;
+      for (const auto& server_address : server_address_list) {
+        std::vector<std::string> grpc_arguments{"grpc_cli", "ls",
+                                                server_address};
+        command_output += CF_EXPECT(RunGrpcCommand(grpc_arguments));
+      }
 
-  if (args.size() > 0) {
-    std::vector<std::string> grpc_arguments{"grpc_cli", "ls"};
+      Json::Value json;
+      json["services"] = Json::Value(Json::arrayValue);
+      for (auto& full_service_name : Split(Trim(command_output), "\n")) {
+        if (full_service_name.compare(kServiceServerReflection) == 0 ||
+            full_service_name.compare(kServiceHealth) == 0 ||
+            full_service_name.compare(kServiceControlEnvProxyFull) == 0) {
+          continue;
+        }
+        json["services"].append(Split(full_service_name, ".").back());
+      }
+      Json::StreamWriterBuilder builder;
+      return Json::writeString(builder, json) + "\n";
+    }
+    case 1: {
+      // ls subcommand with 1 argument; service_name
+      const auto& service_name = args[0];
+      CF_EXPECT(service_name.compare(kServiceControlEnvProxy) != 0,
+                "Prohibited service name");
+      const auto& server_address =
+          CF_EXPECT(GetServerAddress(server_address_list, service_name));
+      const auto& full_service_name =
+          CF_EXPECT(GetFullServiceName(server_address, service_name));
+      std::vector<std::string> grpc_arguments{"grpc_cli", "ls", server_address,
+                                              full_service_name};
+      std::string command_output = CF_EXPECT(RunGrpcCommand(grpc_arguments));
 
-    const auto& service_name = args[0];
-    const auto& server_address =
-        CF_EXPECT(GetServerAddress(server_address_list, service_name));
-    grpc_arguments.push_back(server_address);
-    if (args.size() > 1) {
+      Json::Value json;
+      json["methods"] = Json::Value(Json::arrayValue);
+      for (auto& method_name : Split(Trim(command_output), "\n")) {
+        json["methods"].append(method_name);
+      }
+      Json::StreamWriterBuilder builder;
+      return Json::writeString(builder, json) + "\n";
+    }
+    case 2: {
       // ls subcommand with 2 arguments; service_name and method_name
+      const auto& service_name = args[0];
+      CF_EXPECT(service_name.compare(kServiceControlEnvProxy) != 0,
+                "Prohibited service name");
+      const auto& server_address =
+          CF_EXPECT(GetServerAddress(server_address_list, service_name));
       const auto& method_name = args[1];
       const auto& full_method_name = CF_EXPECT(
           GetFullMethodName(server_address, service_name, method_name));
-      grpc_arguments.push_back(full_method_name);
-    } else {
-      // ls subcommand with 1 argument; service_name
-      const auto& full_service_name =
-          CF_EXPECT(GetFullServiceName(server_address, service_name));
-      grpc_arguments.push_back(full_service_name);
-    }
-    command_output += CF_EXPECT(RunGrpcCommand(grpc_arguments, options));
-  } else {
-    // ls subcommand with no arguments
-    for (const auto& server_address : server_address_list) {
-      std::vector<std::string> grpc_arguments{"grpc_cli", "ls", server_address};
-      command_output += CF_EXPECT(RunGrpcCommand(grpc_arguments, options));
-    }
-  }
+      std::vector<std::string> grpc_arguments{"grpc_cli", "ls", server_address,
+                                              full_method_name};
+      std::vector<std::string> options{"-l"};
+      std::string command_output =
+          CF_EXPECT(RunGrpcCommand(grpc_arguments, options));
 
-  return command_output;
+      // Example command_output:
+      //   rpc SetTxpower(wmediumdserver.SetTxpowerRequest) returns
+      // (google.protobuf.Empty) {}
+      std::vector<std::string> parsed_output =
+          Split(Trim(command_output), "()");
+      CF_EXPECT(parsed_output.size() == 5, "Unexpected parsing result");
+      Json::Value json;
+      json["request_type"] = parsed_output[1];
+      json["response_type"] = parsed_output[3];
+      Json::StreamWriterBuilder builder;
+      return Json::writeString(builder, json) + "\n";
+    }
+    default:
+      return CF_ERR("too many arguments");
+  }
 }
 
 Result<std::string> HandleTypeCmd(
     const std::vector<std::string>& server_address_list,
-    const std::vector<std::string>& args,
-    const std::vector<std::string>& options) {
-  CF_EXPECT(args.size() > 2,
-            "need to specify a service name, a method name, and type_name");
-  CF_EXPECT(args.size() < 4, "too many arguments");
-  std::string command_output;
+    const std::vector<std::string>& args) {
+  CF_EXPECT(args.size() > 1,
+            "need to specify the service name and the type_name");
+  CF_EXPECT(args.size() < 3, "too many arguments");
 
   std::vector<std::string> grpc_arguments{"grpc_cli", "type"};
   const auto& service_name = args[0];
-  const auto& method_name = args[1];
-  const auto& type_name = args[2];
+  CF_EXPECT(service_name.compare(kServiceControlEnvProxy) != 0,
+            "Prohibited service name");
+  const auto& type_name = args[1];
 
   const auto& server_address =
       CF_EXPECT(GetServerAddress(server_address_list, service_name));
   grpc_arguments.push_back(server_address);
-  const auto& full_type_name = CF_EXPECT(
-      GetFullTypeName(server_address, service_name, method_name, type_name));
-  grpc_arguments.push_back(full_type_name);
+  grpc_arguments.push_back(type_name);
 
-  command_output += CF_EXPECT(RunGrpcCommand(grpc_arguments, options));
-
-  return command_output;
+  return RunGrpcCommand(grpc_arguments);
 }
 
 Result<std::string> HandleCallCmd(
     const std::vector<std::string>& server_address_list,
-    const std::vector<std::string>& args,
-    const std::vector<std::string>& options) {
+    const std::vector<std::string>& args) {
   CF_EXPECT(args.size() > 2,
-            "need to specify a service name, a method name, and json-formatted "
-            "proto");
+            "need to specify the service name, the method name, and the "
+            "json-formatted proto");
   CF_EXPECT(args.size() < 4, "too many arguments");
-  std::string command_output;
 
   std::vector<std::string> grpc_arguments{"grpc_cli", "call"};
   // TODO(b/265384449): support calling streaming method.
@@ -271,17 +294,14 @@
   grpc_arguments.push_back(full_method_name);
   grpc_arguments.push_back(json_format_proto);
 
-  command_output += CF_EXPECT(RunGrpcCommand(grpc_arguments, options));
-
-  return command_output;
+  return RunGrpcCommand(grpc_arguments);
 }
 
 }  // namespace
 
 Result<std::string> HandleCmds(const std::string& grpc_socket_path,
                                const std::string& cmd,
-                               const std::vector<std::string>& args,
-                               const std::vector<std::string>& options) {
+                               const std::vector<std::string>& args) {
   std::vector<std::string> server_address_list;
   for (const auto& entry :
        std::filesystem::directory_iterator(grpc_socket_path)) {
@@ -292,7 +312,6 @@
   auto command_map =
       std::unordered_map<std::string, std::function<Result<std::string>(
                                           const std::vector<std::string>&,
-                                          const std::vector<std::string>&,
                                           const std::vector<std::string>&)>>{{
           {"call", HandleCallCmd},
           {"ls", HandleLsCmd},
@@ -300,8 +319,7 @@
       }};
   CF_EXPECT(Contains(command_map, cmd), cmd << " isn't supported");
 
-  auto command_output =
-      CF_EXPECT(command_map[cmd](server_address_list, args, options));
+  auto command_output = CF_EXPECT(command_map[cmd](server_address_list, args));
   return command_output;
 }
 
diff --git a/host/libs/control_env/grpc_service_handler.h b/host/libs/control_env/grpc_service_handler.h
index f743745..2978165 100644
--- a/host/libs/control_env/grpc_service_handler.h
+++ b/host/libs/control_env/grpc_service_handler.h
@@ -18,7 +18,6 @@
 
 Result<std::string> HandleCmds(const std::string& grpc_socket_path,
                                const std::string& cmd,
-                               const std::vector<std::string>& args,
-                               const std::vector<std::string>& options);
+                               const std::vector<std::string>& args);
 
 }  // namespace cuttlefish
diff --git a/host/libs/graphics_detector/Android.bp b/host/libs/graphics_detector/Android.bp
index 278bdeb..986e9a7 100644
--- a/host/libs/graphics_detector/Android.bp
+++ b/host/libs/graphics_detector/Android.bp
@@ -29,13 +29,15 @@
     defaults: ["cuttlefish_host"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_graphics_configuration",
     srcs: [
         "graphics_configuration.cpp",
     ],
     shared_libs: [
         "libbase",
+        "libcuttlefish_fs",
+        "libcuttlefish_utils",
         "libjsoncpp",
         "liblog",
     ],
@@ -45,7 +47,7 @@
     defaults: ["cuttlefish_host"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_graphics_detector",
     srcs: [
         "egl.cpp",
diff --git a/host/libs/graphics_detector/graphics_configuration.cpp b/host/libs/graphics_detector/graphics_configuration.cpp
index cd9592c..adb8f0f 100644
--- a/host/libs/graphics_detector/graphics_configuration.cpp
+++ b/host/libs/graphics_detector/graphics_configuration.cpp
@@ -127,4 +127,33 @@
   };
 }
 
+Result<VhostUserGpuHostRendererFeatures>
+GetNeededVhostUserGpuHostRendererFeatures(
+    RenderingMode mode, const GraphicsAvailability& availability) {
+  VhostUserGpuHostRendererFeatures features = {};
+  if (mode == RenderingMode::kGfxstream ||
+      mode == RenderingMode::kGfxstreamGuestAngle) {
+    features.external_blob = true;
+
+    const bool has_external_memory_host =
+        availability.discrete_gpu_device_extensions.find(
+            "VK_EXT_external_memory_host") != std::string::npos;
+
+    if (!has_external_memory_host &&
+        mode == RenderingMode::kGfxstreamGuestAngle) {
+      return CF_ERR(
+          "VK_EXT_external_memory_host is required for running with "
+          "--gpu_mode=gfxstream_guest_angle and --enable_gpu_vhost_user=true");
+    }
+
+    features.system_blob = has_external_memory_host;
+
+  } else {
+    return CF_ERR(
+        "vhost-user-gpu is only currently supported with --gpu_mode=gfxstream "
+        "and --gpu_mode=gfxstream_guest_angle");
+  }
+  return features;
+}
+
 }  // namespace cuttlefish
\ No newline at end of file
diff --git a/host/libs/graphics_detector/graphics_configuration.h b/host/libs/graphics_detector/graphics_configuration.h
index 7d8ce5d..2b5eb00 100644
--- a/host/libs/graphics_detector/graphics_configuration.h
+++ b/host/libs/graphics_detector/graphics_configuration.h
@@ -39,4 +39,24 @@
 Result<AngleFeatureOverrides> GetNeededAngleFeatures(
     RenderingMode mode, const GraphicsAvailability& availability);
 
+struct VhostUserGpuHostRendererFeatures {
+  // If true, host Virtio GPU blob resources will be allocated with
+  // external memory and exported file descriptors will be shared
+  // with the VMM for mapping resources into the guest address space.
+  bool external_blob = false;
+
+  // If true, host Virtio GPU blob resources will be allocated with
+  // shmem and exported file descriptors will be shared with the VMM
+  // for mapping resources into the guest address space.
+  //
+  // This is an extension of the above external_blob that allows the
+  // VMM to map resources without graphics API support but requires
+  // additional features (VK_EXT_external_memory_host) from the GPU
+  // driver and is potentially less performant.
+  bool system_blob = false;
+};
+Result<VhostUserGpuHostRendererFeatures>
+GetNeededVhostUserGpuHostRendererFeatures(
+    RenderingMode mode, const GraphicsAvailability& availability);
+
 }  // namespace cuttlefish
\ No newline at end of file
diff --git a/host/libs/image_aggregator/Android.bp b/host/libs/image_aggregator/Android.bp
index fe68208..11ba0c1 100644
--- a/host/libs/image_aggregator/Android.bp
+++ b/host/libs/image_aggregator/Android.bp
@@ -37,7 +37,7 @@
     },
 }
 
-cc_library_static {
+cc_library {
     name: "libimage_aggregator",
     srcs: [
         "image_aggregator.cc",
diff --git a/host/libs/image_aggregator/image_aggregator.cc b/host/libs/image_aggregator/image_aggregator.cc
index e2e7e66..632bc56 100644
--- a/host/libs/image_aggregator/image_aggregator.cc
+++ b/host/libs/image_aggregator/image_aggregator.cc
@@ -62,12 +62,12 @@
  */
 MasterBootRecord ProtectiveMbr(std::uint64_t size) {
   MasterBootRecord mbr = {
-    .partitions =  {{
-      .partition_type = 0xEE,
-      .first_lba = 1,
-      .num_sectors = (std::uint32_t) size / SECTOR_SIZE,
-    }},
-    .boot_signature = { 0x55, 0xAA },
+      .partitions = {{
+          .partition_type = 0xEE,
+          .first_lba = 1,
+          .num_sectors = (std::uint32_t)size / kSectorSize,
+      }},
+      .boot_signature = {0x55, 0xAA},
   };
   return mbr;
 }
@@ -105,7 +105,7 @@
 struct __attribute__((packed)) GptBeginning {
   MasterBootRecord protective_mbr;
   GptHeader header;
-  std::uint8_t header_padding[SECTOR_SIZE - sizeof(GptHeader)];
+  std::uint8_t header_padding[kSectorSize - sizeof(GptHeader)];
   GptPartitionEntry entries[GPT_NUM_PARTITIONS];
   std::uint8_t partition_alignment[3072];
 };
@@ -116,10 +116,10 @@
 struct __attribute__((packed)) GptEnd {
   GptPartitionEntry entries[GPT_NUM_PARTITIONS];
   GptHeader footer;
-  std::uint8_t footer_padding[SECTOR_SIZE - sizeof(GptHeader)];
+  std::uint8_t footer_padding[kSectorSize - sizeof(GptHeader)];
 };
 
-static_assert(sizeof(GptEnd) % SECTOR_SIZE == 0);
+static_assert(sizeof(GptEnd) % kSectorSize == 0);
 
 struct PartitionInfo {
   MultipleImagePartition source;
@@ -362,9 +362,9 @@
                 .revision = {0, 0, 1, 0},
                 .header_size = sizeof(GptHeader),
                 .current_lba = 1,
-                .backup_lba = (DiskSize() / SECTOR_SIZE) - 1,
-                .first_usable_lba = sizeof(GptBeginning) / SECTOR_SIZE,
-                .last_usable_lba = (next_disk_offset_ / SECTOR_SIZE) - 1,
+                .backup_lba = (DiskSize() / kSectorSize) - 1,
+                .first_usable_lba = sizeof(GptBeginning) / kSectorSize,
+                .last_usable_lba = (next_disk_offset_ / kSectorSize) - 1,
                 .partition_entries_lba = 2,
                 .num_partition_entries = GPT_NUM_PARTITIONS,
                 .partition_entry_size = sizeof(GptPartitionEntry),
@@ -374,9 +374,9 @@
     for (std::size_t i = 0; i < partitions_.size(); i++) {
       const auto& partition = partitions_[i];
       gpt.entries[i] = GptPartitionEntry{
-          .first_lba = partition.offset / SECTOR_SIZE,
+          .first_lba = partition.offset / kSectorSize,
           .last_lba =
-              (partition.offset + partition.AlignedSize()) / SECTOR_SIZE - 1,
+              (partition.offset + partition.AlignedSize()) / kSectorSize - 1,
       };
       uuid_generate(gpt.entries[i].unique_partition_guid);
       if (uuid_parse(GetPartitionGUID(partition.source),
@@ -405,7 +405,7 @@
     std::memcpy((void*)gpt.entries, (void*)head.entries, sizeof(gpt.entries));
     gpt.footer = head.header;
     gpt.footer.partition_entries_lba =
-        (DiskSize() - sizeof(gpt.entries)) / SECTOR_SIZE - 1;
+        (DiskSize() - sizeof(gpt.entries)) / kSectorSize - 1;
     std::swap(gpt.footer.current_lba, gpt.footer.backup_lba);
     gpt.footer.header_crc32 = 0;
     gpt.footer.header_crc32 =
@@ -424,8 +424,8 @@
 }
 
 bool WriteEnd(SharedFD out, const GptEnd& end) {
-  auto disk_size = (end.footer.current_lba + 1) * SECTOR_SIZE;
-  auto footer_start = (end.footer.last_usable_lba + 1) * SECTOR_SIZE;
+  auto disk_size = (end.footer.current_lba + 1) * kSectorSize;
+  auto footer_start = (end.footer.last_usable_lba + 1) * kSectorSize;
   auto padding = disk_size - footer_start - sizeof(GptEnd);
   std::string padding_str(padding, '\0');
   if (WriteAll(out, padding_str) != padding_str.size()) {
diff --git a/host/libs/input_connector/Android.bp b/host/libs/input_connector/Android.bp
index 95a48bc..29a70e6 100644
--- a/host/libs/input_connector/Android.bp
+++ b/host/libs/input_connector/Android.bp
@@ -17,7 +17,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_input_connector",
     srcs: [
         "socket_input_connector.cpp",
diff --git a/host/libs/location/Android.bp b/host/libs/location/Android.bp
index 0f0bb7c..96e58b0 100644
--- a/host/libs/location/Android.bp
+++ b/host/libs/location/Android.bp
@@ -17,7 +17,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "liblocation",
     srcs: [
         "StringParse.cpp",
@@ -31,6 +31,7 @@
         "libcuttlefish_fs",
         "libcuttlefish_utils",
         "libjsoncpp",
+        "liblog",
         "libprotobuf-cpp-full",
         "libgrpc++_unsecure",
         "libxml2",
@@ -51,4 +52,9 @@
         "external/grpc-grpc/include",
         "external/protobuf/src",
     ],
-}
\ No newline at end of file
+    target: {
+        darwin: {
+            enabled: true,
+        },
+    },
+}
diff --git a/host/libs/metrics/Android.bp b/host/libs/metrics/Android.bp
index fd33dc5..9a8196d 100644
--- a/host/libs/metrics/Android.bp
+++ b/host/libs/metrics/Android.bp
@@ -17,7 +17,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_metrics",
     srcs: [
         "metrics_receiver.cc",
diff --git a/host/libs/msg_queue/Android.bp b/host/libs/msg_queue/Android.bp
index 741db1b..41ae7a3 100644
--- a/host/libs/msg_queue/Android.bp
+++ b/host/libs/msg_queue/Android.bp
@@ -17,7 +17,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_msg_queue",
     srcs: [
         "msg_queue.cc",
diff --git a/host/libs/process_monitor/Android.bp b/host/libs/process_monitor/Android.bp
index 97ab93d..632feed 100644
--- a/host/libs/process_monitor/Android.bp
+++ b/host/libs/process_monitor/Android.bp
@@ -17,7 +17,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_process_monitor",
     srcs: [
         "process_monitor.cc",
diff --git a/host/libs/process_monitor/process_monitor.cc b/host/libs/process_monitor/process_monitor.cc
index 1d54fa4..e4c6538 100644
--- a/host/libs/process_monitor/process_monitor.cc
+++ b/host/libs/process_monitor/process_monitor.cc
@@ -31,12 +31,12 @@
 #include <algorithm>
 #include <atomic>
 #include <cstdint>
-#include <functional>
 #include <future>
 #include <memory>
 #include <string>
 #include <thread>
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 
 #include "common/libs/fs/shared_buf.h"
@@ -92,6 +92,7 @@
 }
 
 Result<void> MonitorLoop(const std::atomic_bool& running,
+                         std::mutex& properties_mutex,
                          const bool restart_subprocesses,
                          std::vector<MonitorEntry>& monitored) {
   while (running.load()) {
@@ -108,6 +109,7 @@
       break;
     }
     auto matches = [pid](const auto& it) { return it.proc->pid() == pid; };
+    std::unique_lock lock(properties_mutex);
     auto it = std::find_if(monitored.begin(), monitored.end(), matches);
     if (it == monitored.end()) {
       LogSubprocessExit("(unknown)", pid, wstatus);
@@ -115,6 +117,7 @@
       LogSubprocessExit(it->cmd->GetShortName(), it->proc->pid(), wstatus);
       if (restart_subprocesses) {
         auto options = SubprocessOptions().InGroup(true);
+        // in the future, cmd->Start might not run exec()
         it->proc.reset(new Subprocess(it->cmd->Start(options)));
       } else {
         bool is_critical = it->is_critical;
@@ -159,23 +162,89 @@
 
 }  // namespace
 
-Result<void> ProcessMonitor::ReadMonitorSocketLoopForStop(
-    std::atomic_bool& running) {
+Result<void> ProcessMonitor::ReadMonitorSocketLoop(std::atomic_bool& running) {
   LOG(DEBUG) << "Waiting for a `stop` message from the parent";
   while (running.load()) {
     using process_monitor_impl::ParentToChildMessage;
-    auto message = CF_EXPECT(ParentToChildMessage::Read(monitor_socket_));
+    auto message = CF_EXPECT(ParentToChildMessage::Read(child_monitor_socket_));
     if (message.Stop()) {
       running.store(false);
       // Wake up the wait() loop by giving it an exited child process
       if (fork() == 0) {
         std::exit(0);
       }
+      // will break the for-loop as running is now false
+      continue;
+    }
+    using process_monitor_impl::ParentToChildMessageType;
+    if (message.Type() == ParentToChildMessageType::kHostSuspend) {
+      CF_EXPECT(SuspendHostProcessesImpl());
+      continue;
+    }
+    if (message.Type() == ParentToChildMessageType::kHostResume) {
+      CF_EXPECT(ResumeHostProcessesImpl());
+      continue;
     }
   }
   return {};
 }
 
+Result<void> ProcessMonitor::SuspendHostProcessesImpl() {
+  std::lock_guard lock(properties_mutex_);
+  auto& monitor_entries = properties_.entries_;
+  for (const auto& entry : monitor_entries) {
+    if (!entry.cmd) {
+      LOG(ERROR) << "Monitor Entry has a nullptr for cmd.";
+      continue;
+    }
+    if (!entry.proc) {
+      LOG(ERROR) << "Monitor Entry has a nullptr for proc.";
+      continue;
+    }
+    auto prog_name = android::base::Basename(entry.cmd->Executable());
+    auto process_restart_bin =
+        android::base::Basename(ProcessRestarterBinary());
+    if (process_restart_bin == prog_name) {
+      CF_EXPECT(entry.proc->SendSignal(SIGTSTP));
+    } else {
+      CF_EXPECT(entry.proc->SendSignalToGroup(SIGTSTP));
+    }
+  }
+  using process_monitor_impl::ChildToParentResponse;
+  using process_monitor_impl::ChildToParentResponseType;
+  ChildToParentResponse response(ChildToParentResponseType::kSuccess);
+  CF_EXPECT(response.Write(child_monitor_socket_));
+  return {};
+}
+
+Result<void> ProcessMonitor::ResumeHostProcessesImpl() {
+  std::lock_guard lock(properties_mutex_);
+  auto& monitor_entries = properties_.entries_;
+  for (const auto& entry : monitor_entries) {
+    if (!entry.cmd) {
+      LOG(ERROR) << "Monitor Entry has a nullptr for cmd.";
+      continue;
+    }
+    if (!entry.proc) {
+      LOG(ERROR) << "Monitor Entry has a nullptr for proc.";
+      continue;
+    }
+    auto prog_name = android::base::Basename(entry.cmd->Executable());
+    auto process_restart_bin =
+        android::base::Basename(ProcessRestarterBinary());
+    if (process_restart_bin == prog_name) {
+      CF_EXPECT(entry.proc->SendSignal(SIGCONT));
+    } else {
+      CF_EXPECT(entry.proc->SendSignalToGroup(SIGCONT));
+    }
+  }
+  using process_monitor_impl::ChildToParentResponse;
+  using process_monitor_impl::ChildToParentResponseType;
+  ChildToParentResponse response(ChildToParentResponseType::kSuccess);
+  CF_EXPECT(response.Write(child_monitor_socket_));
+  return {};
+}
+
 ProcessMonitor::Properties& ProcessMonitor::Properties::RestartSubprocesses(
     bool r) & {
   restart_subprocesses_ = r;
@@ -203,15 +272,16 @@
 
 Result<void> ProcessMonitor::StopMonitoredProcesses() {
   CF_EXPECT(monitor_ != -1, "The monitor process has already exited.");
-  CF_EXPECT(monitor_socket_->IsOpen(), "The monitor socket is already closed");
+  CF_EXPECT(parent_monitor_socket_->IsOpen(),
+            "The monitor socket is already closed");
   using process_monitor_impl::ParentToChildMessage;
   using process_monitor_impl::ParentToChildMessageType;
   ParentToChildMessage message(ParentToChildMessageType::kStop);
-  CF_EXPECT(message.Write(monitor_socket_));
+  CF_EXPECT(message.Write(parent_monitor_socket_));
 
   pid_t last_monitor = monitor_;
   monitor_ = -1;
-  monitor_socket_->Close();
+  parent_monitor_socket_->Close();
   int wstatus;
   CF_EXPECT(waitpid(last_monitor, &wstatus, 0) == last_monitor,
             "Failed to wait for monitor process");
@@ -222,17 +292,49 @@
   return {};
 }
 
+Result<void> ProcessMonitor::SuspendMonitoredProcesses() {
+  CF_EXPECT(monitor_ != -1, "The monitor process has already exited.");
+  CF_EXPECT(parent_monitor_socket_->IsOpen(),
+            "The monitor socket is already closed");
+  using process_monitor_impl::ParentToChildMessage;
+  using process_monitor_impl::ParentToChildMessageType;
+  ParentToChildMessage message(ParentToChildMessageType::kHostSuspend);
+  CF_EXPECT(message.Write(parent_monitor_socket_));
+  using process_monitor_impl::ChildToParentResponse;
+  auto response =
+      CF_EXPECT(ChildToParentResponse::Read(parent_monitor_socket_));
+  CF_EXPECT(response.Success(),
+            "On kHostSuspend, the child run_cvd returned kFailure.");
+  return {};
+}
+
+Result<void> ProcessMonitor::ResumeMonitoredProcesses() {
+  CF_EXPECT(monitor_ != -1, "The monitor process has already exited.");
+  CF_EXPECT(parent_monitor_socket_->IsOpen(),
+            "The monitor socket is already closed");
+  using process_monitor_impl::ParentToChildMessage;
+  using process_monitor_impl::ParentToChildMessageType;
+  ParentToChildMessage message(ParentToChildMessageType::kHostResume);
+  CF_EXPECT(message.Write(parent_monitor_socket_));
+  using process_monitor_impl::ChildToParentResponse;
+  auto response =
+      CF_EXPECT(ChildToParentResponse::Read(parent_monitor_socket_));
+  CF_EXPECT(response.Success(),
+            "On kHostResume, the child run_cvd returned kFailure.");
+  return {};
+}
+
 Result<void> ProcessMonitor::StartAndMonitorProcesses() {
   CF_EXPECT(monitor_ == -1, "The monitor process was already started");
-  CF_EXPECT(!monitor_socket_->IsOpen(), "Monitor socket was already opened");
-
-  SharedFD client_pipe, host_pipe;
-  CF_EXPECT(SharedFD::Pipe(&client_pipe, &host_pipe),
-            "Could not create the monitor socket.");
+  CF_EXPECT(!parent_monitor_socket_->IsOpen(),
+            "Parent monitor socket was already opened");
+  SharedFD parent_sock;
+  SharedFD child_sock;
+  SharedFD::SocketPair(AF_UNIX, SOCK_STREAM, 0, &parent_sock, &child_sock);
   monitor_ = fork();
   if (monitor_ == 0) {
-    monitor_socket_ = client_pipe;
-    host_pipe->Close();
+    child_monitor_socket_ = std::move(child_sock);
+    parent_sock->Close();
     auto monitor_result = MonitorRoutine();
     if (!monitor_result.ok()) {
       LOG(ERROR) << "Monitoring processes failed:\n"
@@ -242,8 +344,8 @@
     }
     std::exit(monitor_result.ok() ? 0 : 1);
   } else {
-    client_pipe->Close();
-    monitor_socket_ = host_pipe;
+    parent_monitor_socket_ = std::move(parent_sock);
+    child_sock->Close();
     return {};
   }
 }
@@ -260,15 +362,17 @@
   StartSubprocesses(properties_.entries_);
 
   std::atomic_bool running(true);
+
   auto read_monitor_socket_loop =
       [this](std::atomic_bool& running) -> Result<void> {
-    CF_EXPECT(this->ReadMonitorSocketLoopForStop(running));
+    CF_EXPECT(this->ReadMonitorSocketLoop(running));
     return {};
   };
   auto parent_comms = std::async(std::launch::async, read_monitor_socket_loop,
                                  std::ref(running));
 
-  MonitorLoop(running, properties_.restart_subprocesses_, properties_.entries_);
+  MonitorLoop(running, properties_mutex_, properties_.restart_subprocesses_,
+              properties_.entries_);
   CF_EXPECT(parent_comms.get(), "Should have exited if monitoring stopped");
 
   StopSubprocesses(properties_.entries_);
diff --git a/host/libs/process_monitor/process_monitor.h b/host/libs/process_monitor/process_monitor.h
index ca95160..45a531a 100644
--- a/host/libs/process_monitor/process_monitor.h
+++ b/host/libs/process_monitor/process_monitor.h
@@ -74,14 +74,34 @@
   Result<void> StartAndMonitorProcesses();
   // Stops all monitored subprocesses.
   Result<void> StopMonitoredProcesses();
+  // Suspend all host subprocesses
+  Result<void> SuspendMonitoredProcesses();
+  // Resume all host subprocesses
+  Result<void> ResumeMonitoredProcesses();
 
  private:
   Result<void> MonitorRoutine();
-  Result<void> ReadMonitorSocketLoopForStop(std::atomic_bool&);
+  Result<void> ReadMonitorSocketLoop(std::atomic_bool&);
+  /*
+   * The child run_cvd process suspends the host processes
+   */
+  Result<void> SuspendHostProcessesImpl();
+  /*
+   * The child run_cvd process resumes the host processes
+   */
+  Result<void> ResumeHostProcessesImpl();
 
   Properties properties_;
   pid_t monitor_;
-  SharedFD monitor_socket_;
+  SharedFD parent_monitor_socket_;
+  SharedFD child_monitor_socket_;
+
+  /*
+   * The lock that should be acquired when multiple threads
+   * access to properties_. Currently, used by the child
+   * run_cvd process that runs MonitorRoutine()
+   */
+  std::mutex properties_mutex_;
 };
 
 }  // namespace cuttlefish
diff --git a/host/libs/screen_connector/Android.bp b/host/libs/screen_connector/Android.bp
index d0bf438..c5e6a14 100644
--- a/host/libs/screen_connector/Android.bp
+++ b/host/libs/screen_connector/Android.bp
@@ -17,7 +17,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_screen_connector",
     srcs: [
         "wayland_screen_connector.cpp",
@@ -38,9 +38,14 @@
         "libcuttlefish_confui",
         "libcuttlefish_wayland_server",
         "libcuttlefish_confui_host",
+        "libffi",
         "libft2.nodep",
         "libteeui",
         "libteeui_localization",
+        "libwayland_crosvm_gpu_display_extension_server_protocols",
+        "libwayland_extension_server_protocols",
+        "libwayland_server",
+
     ],
     defaults: ["cuttlefish_buildhost_only"],
 }
diff --git a/host/libs/vm_manager/Android.bp b/host/libs/vm_manager/Android.bp
index 1a6bfcf..7ea06ca 100644
--- a/host/libs/vm_manager/Android.bp
+++ b/host/libs/vm_manager/Android.bp
@@ -17,7 +17,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_vm_manager",
     srcs: [
         "crosvm_builder.cpp",
@@ -42,10 +42,7 @@
     static_libs: [
         "libcuttlefish_host_config",
     ],
-    defaults: [
-        "cuttlefish_host",
-        "cuttlefish_libicuuc"
-    ],
+    defaults: ["cuttlefish_host"],
     target: {
         darwin: {
             enabled: true,
diff --git a/host/libs/vm_manager/crosvm_manager.cpp b/host/libs/vm_manager/crosvm_manager.cpp
index 4d61fe8..a6b2de9 100644
--- a/host/libs/vm_manager/crosvm_manager.cpp
+++ b/host/libs/vm_manager/crosvm_manager.cpp
@@ -29,6 +29,7 @@
 #include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/strings.h>
+#include <json/json.h>
 #include <vulkan/vulkan.h>
 
 #include "common/libs/utils/environment.h"
@@ -135,13 +136,22 @@
 }
 
 Result<std::unordered_map<std::string, std::string>>
-CrosvmManager::ConfigureBootDevices(int num_disks, bool have_gpu) {
+CrosvmManager::ConfigureBootDevices(
+    const CuttlefishConfig::InstanceSpecific& instance) {
+  const int num_disks = instance.virtual_disk_paths().size();
+  const bool has_gpu = instance.hwcomposer() != kHwComposerNone;
   // TODO There is no way to control this assignment with crosvm (yet)
   if (HostArch() == Arch::X86_64) {
-    // crosvm has an additional PCI device for an ISA bridge
+    int num_gpu_pcis = has_gpu ? 1 : 0;
+    if (instance.gpu_mode() != kGpuModeNone &&
+        !instance.enable_gpu_vhost_user()) {
+      // crosvm has an additional PCI device for an ISA bridge when running
+      // with a gpu and without vhost user gpu.
+      num_gpu_pcis += 1;
+    }
     // virtio_gpu and virtio_wl precedes the first console or disk
-    return ConfigureMultipleBootDevices("pci0000:00/0000:00:",
-                                        1 + (have_gpu ? 2 : 0), num_disks);
+    return ConfigureMultipleBootDevices("pci0000:00/0000:00:", 1 + num_gpu_pcis,
+                                        num_disks);
   } else {
     // On ARM64 crosvm, block devices are on their own bridge, so we don't
     // need to calculate it, and the path is always the same
@@ -149,15 +159,245 @@
   }
 }
 
+std::string ToSingleLineString(const Json::Value& value) {
+  Json::StreamWriterBuilder builder;
+  builder["indentation"] = "";
+  return Json::writeString(builder, value);
+}
+
 constexpr auto crosvm_socket = "crosvm_control.sock";
 
+void MaybeConfigureVulkanIcd(const CuttlefishConfig& config, Command* command) {
+  const auto& gpu_mode = config.ForDefaultInstance().gpu_mode();
+  if (gpu_mode == kGpuModeGfxstreamGuestAngleHostSwiftShader) {
+    // See https://github.com/KhronosGroup/Vulkan-Loader.
+    const std::string swiftshader_icd_json =
+        HostUsrSharePath("vulkan/icd.d/vk_swiftshader_icd.json");
+    command->AddEnvironmentVariable("VK_DRIVER_FILES", swiftshader_icd_json);
+    command->AddEnvironmentVariable("VK_ICD_FILENAMES", swiftshader_icd_json);
+  }
+}
+
+Result<std::string> CrosvmPathForVhostUserGpu(const CuttlefishConfig& config) {
+  const auto& instance = config.ForDefaultInstance();
+  switch (HostArch()) {
+    case Arch::Arm64:
+      return HostBinaryPath("aarch64-linux-gnu/crosvm");
+    case Arch::X86:
+    case Arch::X86_64:
+      return instance.crosvm_binary();
+    default:
+      break;
+  }
+  return CF_ERR("Unhandled host arch " << HostArchStr()
+                                       << " for vhost user gpu crosvm");
+}
+
+struct VhostUserDeviceCommands {
+  Command device_cmd;
+  Command device_logs_cmd;
+};
+Result<VhostUserDeviceCommands> BuildVhostUserGpu(
+    const CuttlefishConfig& config, Command* main_crosvm_cmd) {
+  const auto& instance = config.ForDefaultInstance();
+  if (!instance.enable_gpu_vhost_user()) {
+    return CF_ERR("Attempting to build vhost user gpu when not enabled?");
+  }
+
+  auto gpu_device_socket_path =
+      instance.PerInstanceInternalUdsPath("vhost-user-gpu-socket");
+  auto gpu_device_socket = SharedFD::SocketLocalServer(
+      gpu_device_socket_path.c_str(), false, SOCK_STREAM, 0777);
+  CF_EXPECT(gpu_device_socket->IsOpen(),
+            "Failed to create socket for crosvm vhost user gpu's control"
+                << gpu_device_socket->StrError());
+
+  auto gpu_device_logs_path =
+      instance.PerInstanceInternalPath("crosvm_vhost_user_gpu.fifo");
+  auto gpu_device_logs = SharedFD::Fifo(gpu_device_logs_path, 0666);
+  CF_EXPECT(
+      gpu_device_logs->IsOpen(),
+      "Failed to create log fifo for crosvm vhost user gpu's stdout/stderr: "
+          << gpu_device_logs->StrError());
+
+  Command gpu_device_logs_cmd(HostBinaryPath("log_tee"));
+  gpu_device_logs_cmd.AddParameter("--process_name=crosvm_gpu");
+  gpu_device_logs_cmd.AddParameter("--log_fd_in=", gpu_device_logs);
+  gpu_device_logs_cmd.SetStopper([](Subprocess* proc) {
+    // Ask nicely so that log_tee gets a chance to process all the logs.
+    int rval = kill(proc->pid(), SIGINT);
+    if (rval != 0) {
+      LOG(ERROR) << "Failed to stop log_tee nicely, attempting to KILL";
+      return KillSubprocess(proc) == StopperResult::kStopSuccess
+                 ? StopperResult::kStopCrash
+                 : StopperResult::kStopFailure;
+    }
+    return StopperResult::kStopSuccess;
+  });
+
+  const std::string crosvm_path = CF_EXPECT(CrosvmPathForVhostUserGpu(config));
+
+  Command gpu_device_cmd(crosvm_path);
+  gpu_device_cmd.AddParameter("device");
+  gpu_device_cmd.AddParameter("gpu");
+
+  const auto& gpu_mode = instance.gpu_mode();
+  CF_EXPECT(
+      gpu_mode == kGpuModeGfxstream ||
+          gpu_mode == kGpuModeGfxstreamGuestAngle ||
+          gpu_mode == kGpuModeGfxstreamGuestAngleHostSwiftShader,
+      "GPU mode " << gpu_mode << " not yet supported with vhost user gpu.");
+
+  // Why does this need JSON instead of just following the normal flags style...
+  Json::Value gpu_params_json;
+  if (gpu_mode == kGpuModeGfxstream) {
+    gpu_params_json["context-types"] = "gfxstream-gles:gfxstream-vulkan";
+    gpu_params_json["egl"] = true;
+    gpu_params_json["gles"] = true;
+  } else if (gpu_mode == kGpuModeGfxstreamGuestAngle ||
+             gpu_mode == kGpuModeGfxstreamGuestAngleHostSwiftShader) {
+    gpu_params_json["context-types"] = "gfxstream-vulkan";
+    gpu_params_json["egl"] = false;
+    gpu_params_json["gles"] = false;
+  }
+  gpu_params_json["glx"] = false;
+  gpu_params_json["surfaceless"] = true;
+  gpu_params_json["external-blob"] = instance.enable_gpu_external_blob();
+  gpu_params_json["system-blob"] = instance.enable_gpu_system_blob();
+
+  if (instance.hwcomposer() != kHwComposerNone) {
+    // "displays": [
+    //   {
+    //    "mode": {
+    //      "windowed": [
+    //        720,
+    //        1280
+    //      ]
+    //    },
+    //    "dpi": [
+    //      320,
+    //      320
+    //    ],
+    //    "refresh-rate": 60
+    //   }
+    // ]
+    Json::Value displays(Json::arrayValue);
+    for (const auto& display_config : instance.display_configs()) {
+      Json::Value display_mode_windowed(Json::arrayValue);
+      display_mode_windowed[0] = display_config.width;
+      display_mode_windowed[1] = display_config.height;
+
+      Json::Value display_mode;
+      display_mode["windowed"] = display_mode_windowed;
+
+      Json::Value display_dpi(Json::arrayValue);
+      display_dpi[0] = display_config.dpi;
+      display_dpi[1] = display_config.dpi;
+
+      Json::Value display;
+      display["mode"] = display_mode;
+      display["dpi"] = display_dpi;
+      display["refresh-rate"] = display_config.refresh_rate_hz;
+
+      displays.append(display);
+    }
+    gpu_params_json["displays"] = displays;
+
+    gpu_device_cmd.AddParameter("--wayland-sock=",
+                                instance.frames_socket_path());
+  }
+
+  // Connect device to main crosvm:
+  gpu_device_cmd.AddParameter("--socket=", gpu_device_socket_path);
+  main_crosvm_cmd->AddParameter("--vhost-user-gpu=", gpu_device_socket_path);
+
+  gpu_device_cmd.AddParameter("--params");
+  gpu_device_cmd.AddParameter(ToSingleLineString(gpu_params_json));
+
+  MaybeConfigureVulkanIcd(config, &gpu_device_cmd);
+
+  gpu_device_cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdOut,
+                               gpu_device_logs);
+  gpu_device_cmd.RedirectStdIO(Subprocess::StdIOChannel::kStdErr,
+                               gpu_device_logs);
+
+  return VhostUserDeviceCommands{
+      .device_cmd = std::move(gpu_device_cmd),
+      .device_logs_cmd = std::move(gpu_device_logs_cmd),
+  };
+}
+
+Result<void> ConfigureGpu(const CuttlefishConfig& config, Command* crosvm_cmd) {
+  const auto& instance = config.ForDefaultInstance();
+  const auto& gpu_mode = instance.gpu_mode();
+
+  const std::string gles_string =
+      gpu_mode == kGpuModeGfxstreamGuestAngle ||
+              gpu_mode == kGpuModeGfxstreamGuestAngleHostSwiftShader
+          ? ",gles=false"
+          : ",gles=true";
+
+  // 256MB so it is small enough for a 32-bit kernel.
+  const bool target_is_32bit = instance.target_arch() == Arch::Arm ||
+                               instance.target_arch() == Arch::X86;
+  const std::string gpu_pci_bar_size =
+      target_is_32bit ? ",pci-bar-size=268435456" : "";
+
+  const std::string gpu_udmabuf_string =
+      instance.enable_gpu_udmabuf() ? ",udmabuf=true" : "";
+
+  const std::string gpu_common_string = gpu_udmabuf_string + gpu_pci_bar_size;
+  const std::string gpu_common_3d_string =
+      gpu_common_string + ",egl=true,surfaceless=true,glx=false" + gles_string;
+
+  if (gpu_mode == kGpuModeGuestSwiftshader) {
+    crosvm_cmd->AddParameter("--gpu=backend=2D", gpu_common_string);
+  } else if (gpu_mode == kGpuModeDrmVirgl) {
+    crosvm_cmd->AddParameter("--gpu=backend=virglrenderer",
+                             gpu_common_3d_string);
+  } else if (gpu_mode == kGpuModeGfxstream) {
+    crosvm_cmd->AddParameter(
+        "--gpu=context-types=gfxstream-gles:gfxstream-vulkan:gfxstream-"
+        "composer",
+        gpu_common_3d_string);
+  } else if (gpu_mode == kGpuModeGfxstreamGuestAngle ||
+             gpu_mode == kGpuModeGfxstreamGuestAngleHostSwiftShader) {
+    crosvm_cmd->AddParameter(
+        "--gpu=context-types=gfxstream-vulkan:gfxstream-composer",
+        gpu_common_3d_string);
+  }
+
+  MaybeConfigureVulkanIcd(config, crosvm_cmd);
+
+  if (instance.hwcomposer() != kHwComposerNone) {
+    for (const auto& display_config : instance.display_configs()) {
+      const auto display_w = std::to_string(display_config.width);
+      const auto display_h = std::to_string(display_config.height);
+      const auto display_dpi = std::to_string(display_config.dpi);
+      const auto display_rr = std::to_string(display_config.refresh_rate_hz);
+      const auto display_params = android::base::Join(
+          std::vector<std::string>{
+              "mode=windowed[" + display_w + "," + display_h + "]",
+              "dpi=[" + display_dpi + "," + display_dpi + "]",
+              "refresh-rate=" + display_rr,
+          },
+          ",");
+
+      crosvm_cmd->AddParameter("--gpu-display=", display_params);
+    }
+
+    crosvm_cmd->AddParameter("--wayland-sock=", instance.frames_socket_path());
+  }
+
+  return {};
+}
+
 Result<std::vector<MonitorCommand>> CrosvmManager::StartCommands(
     const CuttlefishConfig& config,
     std::vector<VmmDependencyCommand*>& dependencyCommands) {
   auto instance = config.ForDefaultInstance();
 
   CrosvmBuilder crosvm_cmd;
-
   crosvm_cmd.Cmd().AddPrerequisite([&dependencyCommands]() -> Result<void> {
     for (auto dependencyCommand : dependencyCommands) {
       CF_EXPECT(dependencyCommand->WaitForAvailability());
@@ -209,51 +449,12 @@
     crosvm_cmd.Cmd().AddParameter("--gdb=", instance.gdb_port());
   }
 
-  const auto gpu_capture_enabled = !instance.gpu_capture_binary().empty();
-  const auto gpu_mode = instance.gpu_mode();
-
-  const std::string gles_string =
-      gpu_mode == kGpuModeGfxstreamGuestAngle ||
-              gpu_mode == kGpuModeGfxstreamGuestAngleHostSwiftShader
-          ? ",gles=false"
-          : ",gles=true";
-  // 256MB so it is small enough for a 32-bit kernel.
-  const bool target_is_32bit = instance.target_arch() == Arch::Arm ||
-                               instance.target_arch() == Arch::X86;
-  const std::string gpu_pci_bar_size =
-      target_is_32bit ? ",pci-bar-size=268435456" : "";
-  const std::string gpu_udmabuf_string =
-      instance.enable_gpu_udmabuf() ? ",udmabuf=true" : "";
-
-  const std::string gpu_common_string = gpu_udmabuf_string + gpu_pci_bar_size;
-  const std::string gpu_common_3d_string =
-      gpu_common_string + ",egl=true,surfaceless=true,glx=false" + gles_string;
-
-  if (gpu_mode == kGpuModeGuestSwiftshader) {
-    crosvm_cmd.Cmd().AddParameter("--gpu=backend=2D", gpu_common_string);
-  } else if (gpu_mode == kGpuModeDrmVirgl) {
-    crosvm_cmd.Cmd().AddParameter("--gpu=backend=virglrenderer",
-                                  gpu_common_3d_string);
-  } else if (gpu_mode == kGpuModeGfxstream) {
-    crosvm_cmd.Cmd().AddParameter(
-        "--gpu=context-types=gfxstream-gles:gfxstream-vulkan:gfxstream-"
-        "composer",
-        gpu_common_3d_string);
-  } else if (gpu_mode == kGpuModeGfxstreamGuestAngle ||
-             gpu_mode == kGpuModeGfxstreamGuestAngleHostSwiftShader) {
-    crosvm_cmd.Cmd().AddParameter(
-        "--gpu=context-types=gfxstream-vulkan:gfxstream-composer",
-        gpu_common_3d_string);
-
-    if (gpu_mode == kGpuModeGfxstreamGuestAngleHostSwiftShader) {
-      // See https://github.com/KhronosGroup/Vulkan-Loader.
-      const std::string swiftshader_icd_json =
-          HostUsrSharePath("vulkan/icd.d/vk_swiftshader_icd.json");
-      crosvm_cmd.Cmd().AddEnvironmentVariable("VK_DRIVER_FILES",
-                                              swiftshader_icd_json);
-      crosvm_cmd.Cmd().AddEnvironmentVariable("VK_ICD_FILENAMES",
-                                              swiftshader_icd_json);
-    }
+  std::optional<VhostUserDeviceCommands> vhost_user_gpu;
+  if (instance.enable_gpu_vhost_user()) {
+    vhost_user_gpu.emplace(
+        CF_EXPECT(BuildVhostUserGpu(config, &crosvm_cmd.Cmd())));
+  } else {
+    CF_EXPECT(ConfigureGpu(config, &crosvm_cmd.Cmd()));
   }
 
   if (instance.hwcomposer() != kHwComposerNone) {
@@ -262,26 +463,10 @@
       crosvm_cmd.Cmd().AddParameter("--rw-pmem-device=",
                                     instance.hwcomposer_pmem_path());
     }
-
-    for (const auto& display_config : instance.display_configs()) {
-      const auto display_w = std::to_string(display_config.width);
-      const auto display_h = std::to_string(display_config.height);
-      const auto display_dpi = std::to_string(display_config.dpi);
-      const auto display_rr = std::to_string(display_config.refresh_rate_hz);
-      const auto display_params = android::base::Join(
-          std::vector<std::string>{
-              "mode=windowed[" + display_w + "," + display_h + "]",
-              "dpi=[" + display_dpi + "," + display_dpi + "]",
-              "refresh-rate=" + display_rr,
-          },
-          ",");
-      crosvm_cmd.Cmd().AddParameter("--gpu-display=", display_params);
-    }
-
-    crosvm_cmd.Cmd().AddParameter("--wayland-sock=",
-                                  instance.frames_socket_path());
   }
 
+  const auto gpu_capture_enabled = !instance.gpu_capture_binary().empty();
+
   // crosvm_cmd.Cmd().AddParameter("--null-audio");
   crosvm_cmd.Cmd().AddParameter("--mem=", instance.memory_mb());
   crosvm_cmd.Cmd().AddParameter("--cpus=", instance.cpus());
@@ -327,13 +512,13 @@
   // GPU capture can only support named files and not file descriptors due to
   // having to pass arguments to crosvm via a wrapper script.
 #ifdef __linux__
-  if (!gpu_capture_enabled && config.enable_wifi()) {
+  if (!gpu_capture_enabled) {
     // The ordering of tap devices is important. Make sure any change here
     // is reflected in ethprime u-boot variable
     crosvm_cmd.AddTap(instance.mobile_tap_name(), instance.mobile_mac());
     crosvm_cmd.AddTap(instance.ethernet_tap_name(), instance.ethernet_mac());
 
-    if (!config.virtio_mac80211_hwsim()) {
+    if (!config.virtio_mac80211_hwsim() && config.enable_wifi()) {
       wifi_tap = crosvm_cmd.AddTap(instance.wifi_tap_name());
     }
   }
@@ -586,6 +771,11 @@
     commands.emplace_back(std::move(crosvm_cmd.Cmd()), true);
   }
 
+  if (vhost_user_gpu) {
+    commands.emplace_back(std::move(vhost_user_gpu->device_cmd));
+    commands.emplace_back(std::move(vhost_user_gpu->device_logs_cmd));
+  }
+
   return commands;
 }
 
diff --git a/host/libs/vm_manager/crosvm_manager.h b/host/libs/vm_manager/crosvm_manager.h
index 822ec55..a1433d2 100644
--- a/host/libs/vm_manager/crosvm_manager.h
+++ b/host/libs/vm_manager/crosvm_manager.h
@@ -40,7 +40,7 @@
       const CuttlefishConfig::InstanceSpecific& instance) override;
 
   Result<std::unordered_map<std::string, std::string>> ConfigureBootDevices(
-      int num_disks, bool have_gpu) override;
+      const CuttlefishConfig::InstanceSpecific& instance) override;
 
   Result<std::vector<MonitorCommand>> StartCommands(
       const CuttlefishConfig& config,
diff --git a/host/libs/vm_manager/gem5_manager.cpp b/host/libs/vm_manager/gem5_manager.cpp
index 0d2cbf6..df62785 100644
--- a/host/libs/vm_manager/gem5_manager.cpp
+++ b/host/libs/vm_manager/gem5_manager.cpp
@@ -16,7 +16,6 @@
 
 #include "host/libs/vm_manager/gem5_manager.h"
 
-#include <string.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -24,11 +23,8 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
-#include <cstdlib>
 #include <fstream>
-#include <sstream>
 #include <string>
-#include <thread>
 #include <unordered_map>
 #include <utility>
 #include <vector>
@@ -37,14 +33,10 @@
 #include <android-base/logging.h>
 #include <vulkan/vulkan.h>
 
-#include "common/libs/fs/shared_select.h"
-#include "common/libs/utils/files.h"
 #include "common/libs/utils/result.h"
 #include "common/libs/utils/subprocess.h"
-#include "common/libs/utils/users.h"
 #include "host/libs/config/command_source.h"
 #include "host/libs/config/cuttlefish_config.h"
-#include "host/libs/config/known_paths.h"
 
 using cuttlefish::StringFromEnv;
 
@@ -52,10 +44,100 @@
 namespace vm_manager {
 namespace {
 
-void LogAndSetEnv(const char* key, const std::string& value) {
-  setenv(key, value.c_str(), 1);
-  LOG(INFO) << key << "=" << value;
-}
+static constexpr char kFsHeader[] = R"CPP_STR_END(import argparse
+import devices
+import os
+import shutil
+import m5
+from m5.util import addToPath
+from m5.objects import *
+from m5.options import *
+from m5.objects.Ethernet import NSGigE, IGbE_igb, IGbE_e1000, EtherTap
+from common import SysPaths
+from common import ObjectList
+from common import MemConfig
+from common.cores.arm import HPI
+m5.util.addToPath('../..')
+)CPP_STR_END";
+
+static constexpr char kFsMemPci[] = R"CPP_STR_END(
+  MemConfig.config_mem(args, root.system)
+
+  pci_devices = []
+  pci_devices.append(PciVirtIO(vio=VirtIOConsole(device=Terminal(number=0))))
+  pci_devices.append(PciVirtIO(vio=VirtIOConsole(device=Terminal(number=1, outfile="none"))))
+  pci_devices.append(PciVirtIO(vio=VirtIOConsole(device=Terminal(number=2))))
+  pci_devices.append(PciVirtIO(vio=VirtIOConsole(device=Terminal(number=3, outfile="none"))))
+  pci_devices.append(PciVirtIO(vio=VirtIOConsole(device=Terminal(number=4, outfile="none"))))
+  pci_devices.append(PciVirtIO(vio=VirtIOConsole(device=Terminal(number=5, outfile="none"))))
+  pci_devices.append(PciVirtIO(vio=VirtIOConsole(device=Terminal(number=6, outfile="none"))))
+  pci_devices.append(PciVirtIO(vio=VirtIOConsole(device=Terminal(number=7, outfile="none"))))
+  pci_devices.append(PciVirtIO(vio=VirtIOConsole(device=Terminal(number=8, outfile="none"))))
+  pci_devices.append(PciVirtIO(vio=VirtIOConsole(device=Terminal(number=9, outfile="none"))))
+
+  for each_item in args.disk_image:
+    disk_image = CowDiskImage()
+    disk_image.child.image_file = SysPaths.disk(each_item)
+    pci_devices.append(PciVirtIO(vio=VirtIOBlock(image=disk_image)))
+
+  nic = IGbE_e1000(pci_bus=0, pci_dev=0, pci_func=0, InterruptLine=1, InterruptPin=1)
+  pci_devices.append(nic)
+  root.system.pci_devices = pci_devices
+  for pci_device in root.system.pci_devices:
+    root.system.attach_pci(pci_device)
+
+  root.tap = EtherTap(tun_clone_device='/dev/net/tun', tap_device_name='cvd-mtap-01')
+  root.tap.tap = nic.interface
+  root.system.connect()
+)CPP_STR_END";
+
+static constexpr char kFsKernelCmd[] = R"CPP_STR_END(
+  kernel_cmd = [
+    "lpj=19988480",
+    "norandmaps",
+    "mem=%s" % args.mem_size,
+    "console=hvc0",
+    "panic=-1",
+    "earlycon=pl011,mmio32,0x1c090000",
+    "audit=1",
+    "printk.devkmsg=on",
+    "firmware_class.path=/vendor/etc/",
+    "kfence.sample_interval=500",
+    "loop.max_part=7",
+    "bootconfig",
+    "androidboot.force_normal_boot=1",
+  ]
+  root.system.workload.command_line = " ".join(kernel_cmd)
+  if args.restore is not None:
+    m5.instantiate(args.restore)
+  else:
+    m5.instantiate()
+
+  while True:
+    event = m5.simulate()
+    msg = event.getCause()
+    cur_tick = m5.curTick()
+    if msg == "checkpoint":
+      backup_path = backup_path = os.path.join(root_dir, "gem5_checkpoint")
+      if not os.path.isdir(backup_path):
+        os.mkdir(backup_path)
+
+      print("Checkpoint @", cur_tick)
+      src_dir = os.path.join(m5.options.outdir, "cpt.%d" % cur_tick)
+      backup_path = os.path.join(backup_path, "cpt.%d" % cur_tick)
+      m5.checkpoint(src_dir)
+      shutil.copytree(src_dir, backup_path)
+      print("Checkpoint done.")
+    else:
+      print("Exit msg: " + msg + " @", cur_tick)
+      break
+  sys.exit(event.getCode())
+)CPP_STR_END";
+
+static constexpr char kFsExeMain[] = R"CPP_STR_END(
+if __name__ == "__m5_main__":
+  main()
+)CPP_STR_END";
 
 void GenerateGem5File(const CuttlefishConfig& config,
                       const CuttlefishConfig::InstanceSpecific& instance) {
@@ -76,7 +158,7 @@
   std::string fs_path = instance.gem5_binary_dir() +
                         "/configs/example/arm/starter_fs.py";
   std::ofstream starter_fs_ofstream(fs_path.c_str());
-  starter_fs_ofstream << fs_header << "\n";
+  starter_fs_ofstream << kFsHeader << "\n";
 
   // global vars in python
   starter_fs_ofstream << "default_disk = 'linaro-minimal-aarch64.img'\n";
@@ -101,7 +183,7 @@
   starter_fs_ofstream << "  root.system = devices.SimpleSystem(has_caches, args.mem_size, mem_mode=mem_mode, workload=ArmFsLinux(object_file=SysPaths.binary(\"" << config.assembly_dir() << "/kernel\")))\n";
 
   // mem config and pci instantiate
-  starter_fs_ofstream << fs_mem_pci;
+  starter_fs_ofstream << kFsMemPci;
 
   // system settings
   starter_fs_ofstream << "  root.system.cpu_cluster = [devices.CpuCluster(root.system, " << num_cores << ", \"" << cpu_freq << "\", \"1.0V\", " << cpu_class << ", " << l1_icache_class << ", " << l1_dcache_class << ", " << walk_cache_class << ", " << l2_Cache_class << ")]\n";
@@ -113,10 +195,10 @@
   starter_fs_ofstream << "  root_dir = \"" << StringFromEnv("HOME", ".") << "\"\n";
 
   //kernel cmd
-  starter_fs_ofstream << fs_kernel_cmd << "\n";
+  starter_fs_ofstream << kFsKernelCmd << "\n";
 
   // execute main
-  starter_fs_ofstream << fs_exe_main << "\n";
+  starter_fs_ofstream << kFsExeMain << "\n";
 }
 
 }  // namespace
@@ -182,7 +264,8 @@
 }
 
 Result<std::unordered_map<std::string, std::string>>
-Gem5Manager::ConfigureBootDevices(int /*num_disks*/, bool /*have_gpu*/) {
+Gem5Manager::ConfigureBootDevices(
+    const CuttlefishConfig::InstanceSpecific& /*instance*/) {
   switch (arch_) {
     case Arch::Arm:
     case Arch::Arm64:
@@ -248,7 +331,7 @@
     gem5_cmd.AddParameter("--disk-image=", disk);
   }
 
-  LogAndSetEnv("M5_PATH", config.assembly_dir());
+  gem5_cmd.AddEnvironmentVariable("M5_PATH", config.assembly_dir());
 
   std::vector<MonitorCommand> commands;
   commands.emplace_back(std::move(gem5_cmd), true);
diff --git a/host/libs/vm_manager/gem5_manager.h b/host/libs/vm_manager/gem5_manager.h
index cb639aa..4c4bbdb 100644
--- a/host/libs/vm_manager/gem5_manager.h
+++ b/host/libs/vm_manager/gem5_manager.h
@@ -42,7 +42,7 @@
       const CuttlefishConfig::InstanceSpecific& instance) override;
 
   Result<std::unordered_map<std::string, std::string>> ConfigureBootDevices(
-      int num_disks, bool have_gpu) override;
+      const CuttlefishConfig::InstanceSpecific& instance) override;
 
   Result<std::vector<MonitorCommand>> StartCommands(
       const CuttlefishConfig& config,
@@ -52,100 +52,5 @@
   Arch arch_;
 };
 
-const std::string fs_header = R"CPP_STR_END(import argparse
-import devices
-import os
-import shutil
-import m5
-from m5.util import addToPath
-from m5.objects import *
-from m5.options import *
-from m5.objects.Ethernet import NSGigE, IGbE_igb, IGbE_e1000, EtherTap
-from common import SysPaths
-from common import ObjectList
-from common import MemConfig
-from common.cores.arm import HPI
-m5.util.addToPath('../..')
-)CPP_STR_END";
-
-const std::string fs_mem_pci = R"CPP_STR_END(
-  MemConfig.config_mem(args, root.system)
-
-  pci_devices = []
-  pci_devices.append(PciVirtIO(vio=VirtIOConsole(device=Terminal(number=0))))
-  pci_devices.append(PciVirtIO(vio=VirtIOConsole(device=Terminal(number=1, outfile="none"))))
-  pci_devices.append(PciVirtIO(vio=VirtIOConsole(device=Terminal(number=2))))
-  pci_devices.append(PciVirtIO(vio=VirtIOConsole(device=Terminal(number=3, outfile="none"))))
-  pci_devices.append(PciVirtIO(vio=VirtIOConsole(device=Terminal(number=4, outfile="none"))))
-  pci_devices.append(PciVirtIO(vio=VirtIOConsole(device=Terminal(number=5, outfile="none"))))
-  pci_devices.append(PciVirtIO(vio=VirtIOConsole(device=Terminal(number=6, outfile="none"))))
-  pci_devices.append(PciVirtIO(vio=VirtIOConsole(device=Terminal(number=7, outfile="none"))))
-  pci_devices.append(PciVirtIO(vio=VirtIOConsole(device=Terminal(number=8, outfile="none"))))
-  pci_devices.append(PciVirtIO(vio=VirtIOConsole(device=Terminal(number=9, outfile="none"))))
-
-  for each_item in args.disk_image:
-    disk_image = CowDiskImage()
-    disk_image.child.image_file = SysPaths.disk(each_item)
-    pci_devices.append(PciVirtIO(vio=VirtIOBlock(image=disk_image)))
-
-  nic = IGbE_e1000(pci_bus=0, pci_dev=0, pci_func=0, InterruptLine=1, InterruptPin=1)
-  pci_devices.append(nic)
-  root.system.pci_devices = pci_devices
-  for pci_device in root.system.pci_devices:
-    root.system.attach_pci(pci_device)
-
-  root.tap = EtherTap(tun_clone_device='/dev/net/tun', tap_device_name='cvd-mtap-01')
-  root.tap.tap = nic.interface
-  root.system.connect()
-)CPP_STR_END";
-
-const std::string fs_kernel_cmd = R"CPP_STR_END(
-  kernel_cmd = [
-    "lpj=19988480",
-    "norandmaps",
-    "mem=%s" % args.mem_size,
-    "console=hvc0",
-    "panic=-1",
-    "earlycon=pl011,mmio32,0x1c090000",
-    "audit=1",
-    "printk.devkmsg=on",
-    "firmware_class.path=/vendor/etc/",
-    "kfence.sample_interval=500",
-    "loop.max_part=7",
-    "bootconfig",
-    "androidboot.force_normal_boot=1",
-  ]
-  root.system.workload.command_line = " ".join(kernel_cmd)
-  if args.restore is not None:
-    m5.instantiate(args.restore)
-  else:
-    m5.instantiate()
-
-  while True:
-    event = m5.simulate()
-    msg = event.getCause()
-    cur_tick = m5.curTick()
-    if msg == "checkpoint":
-      backup_path = backup_path = os.path.join(root_dir, "gem5_checkpoint")
-      if not os.path.isdir(backup_path):
-        os.mkdir(backup_path)
-
-      print("Checkpoint @", cur_tick)
-      src_dir = os.path.join(m5.options.outdir, "cpt.%d" % cur_tick)
-      backup_path = os.path.join(backup_path, "cpt.%d" % cur_tick)
-      m5.checkpoint(src_dir)
-      shutil.copytree(src_dir, backup_path)
-      print("Checkpoint done.")
-    else:
-      print("Exit msg: " + msg + " @", cur_tick)
-      break
-  sys.exit(event.getCode())
-)CPP_STR_END";
-
-const std::string fs_exe_main = R"CPP_STR_END(
-if __name__ == "__m5_main__":
-  main()
-)CPP_STR_END";
-
 } // namespace vm_manager
 } // namespace cuttlefish
diff --git a/host/libs/vm_manager/qemu_manager.cpp b/host/libs/vm_manager/qemu_manager.cpp
index aa25938..0253b98 100644
--- a/host/libs/vm_manager/qemu_manager.cpp
+++ b/host/libs/vm_manager/qemu_manager.cpp
@@ -25,9 +25,7 @@
 #include <unistd.h>
 
 #include <cstdlib>
-#include <sstream>
 #include <string>
-#include <thread>
 #include <unordered_map>
 #include <utility>
 #include <vector>
@@ -37,15 +35,11 @@
 #include <vulkan/vulkan.h>
 
 #include "common/libs/device_config/device_config.h"
-#include "common/libs/fs/shared_select.h"
-#include "common/libs/utils/contains.h"
 #include "common/libs/utils/files.h"
 #include "common/libs/utils/result.h"
 #include "common/libs/utils/subprocess.h"
-#include "common/libs/utils/users.h"
 #include "host/libs/config/command_source.h"
 #include "host/libs/config/cuttlefish_config.h"
-#include "host/libs/config/known_paths.h"
 
 namespace cuttlefish {
 namespace vm_manager {
@@ -56,11 +50,6 @@
       "qemu_monitor.sock");
 }
 
-void LogAndSetEnv(const char* key, const std::string& value) {
-  setenv(key, value.c_str(), 1);
-  LOG(INFO) << key << "=" << value;
-}
-
 bool Stop() {
   auto config = CuttlefishConfig::Get();
   auto monitor_path = GetMonitorPath(*config);
@@ -199,7 +188,10 @@
 }
 
 Result<std::unordered_map<std::string, std::string>>
-QemuManager::ConfigureBootDevices(int num_disks, bool have_gpu) {
+QemuManager::ConfigureBootDevices(
+    const CuttlefishConfig::InstanceSpecific& instance) {
+  const int num_disks = instance.virtual_disk_paths().size();
+  const int num_gpu = instance.hwcomposer() != kHwComposerNone;
   switch (arch_) {
     case Arch::Arm:
       return {{{"androidboot.boot_devices", "3f000000.pcie"}}};
@@ -215,8 +207,8 @@
     case Arch::X86_64: {
       // QEMU has additional PCI devices for an ISA bridge and PIIX4
       // virtio_gpu precedes the first console or disk
-      return ConfigureMultipleBootDevices("pci0000:00/0000:00:",
-                                          2 + (have_gpu ? 1 : 0), num_disks);
+      return ConfigureMultipleBootDevices("pci0000:00/0000:00:", 2 + num_gpu,
+                                          num_disks);
     }
   }
 }
@@ -788,7 +780,7 @@
     qemu_cmd.AddParameter("tcp::", instance.gdb_port());
   }
 
-  LogAndSetEnv("QEMU_AUDIO_DRV", "none");
+  qemu_cmd.AddEnvironmentVariable("QEMU_AUDIO_DRV", "none");
 
   std::vector<MonitorCommand> commands;
   commands.emplace_back(std::move(qemu_cmd), true);
diff --git a/host/libs/vm_manager/qemu_manager.h b/host/libs/vm_manager/qemu_manager.h
index 65f30ea..c0e4624 100644
--- a/host/libs/vm_manager/qemu_manager.h
+++ b/host/libs/vm_manager/qemu_manager.h
@@ -42,7 +42,7 @@
       const CuttlefishConfig::InstanceSpecific& instance) override;
 
   Result<std::unordered_map<std::string, std::string>> ConfigureBootDevices(
-      int num_disks, bool have_gpu) override;
+      const CuttlefishConfig::InstanceSpecific& instance) override;
 
   Result<std::vector<MonitorCommand>> StartCommands(
       const CuttlefishConfig& config,
diff --git a/host/libs/vm_manager/vm_manager.h b/host/libs/vm_manager/vm_manager.h
index 9483354..d52fc15 100644
--- a/host/libs/vm_manager/vm_manager.h
+++ b/host/libs/vm_manager/vm_manager.h
@@ -84,7 +84,7 @@
   ConfigureGraphics(const CuttlefishConfig::InstanceSpecific& instance) = 0;
 
   virtual Result<std::unordered_map<std::string, std::string>>
-  ConfigureBootDevices(int num_disks, bool have_gpu) = 0;
+  ConfigureBootDevices(const CuttlefishConfig::InstanceSpecific& instance) = 0;
 
   // Starts the VMM. It will usually build a command and pass it to the
   // command_starter function, although it may start more than one. The
diff --git a/host/libs/wayland/Android.bp b/host/libs/wayland/Android.bp
index 12700f3..2aefda3 100644
--- a/host/libs/wayland/Android.bp
+++ b/host/libs/wayland/Android.bp
@@ -17,7 +17,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "libcuttlefish_wayland_server",
     srcs: [
         "wayland_compositor.cpp",
diff --git a/host/libs/web/credential_source.cc b/host/libs/web/credential_source.cc
index 33b878d..da77d29 100644
--- a/host/libs/web/credential_source.cc
+++ b/host/libs/web/credential_source.cc
@@ -13,7 +13,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "credential_source.h"
+#include "host/libs/web/credential_source.h"
+
+#include <chrono>
 
 #include <android-base/logging.h>
 #include <android-base/strings.h>
@@ -23,16 +25,11 @@
 #include <openssl/pem.h>
 
 #include "common/libs/utils/base64.h"
+#include "common/libs/utils/result.h"
 
 namespace cuttlefish {
-namespace {
 
-std::chrono::steady_clock::duration REFRESH_WINDOW =
-    std::chrono::minutes(2);
-std::string REFRESH_URL = "http://metadata.google.internal/computeMetadata/"
-    "v1/instance/service-accounts/default/token";
-
-} // namespace
+static constexpr auto kRefreshWindow = std::chrono::minutes(2);
 
 GceMetadataCredentialSource::GceMetadataCredentialSource(
     HttpClient& http_client)
@@ -42,15 +39,18 @@
 }
 
 Result<std::string> GceMetadataCredentialSource::Credential() {
-  if (expiration - std::chrono::steady_clock::now() < REFRESH_WINDOW) {
+  if (expiration - std::chrono::steady_clock::now() < kRefreshWindow) {
     CF_EXPECT(RefreshCredential());
   }
   return latest_credential;
 }
 
 Result<void> GceMetadataCredentialSource::RefreshCredential() {
+  static constexpr char kRefreshUrl[] =
+      "http://metadata.google.internal/computeMetadata/v1/instance/"
+      "service-accounts/default/token";
   auto response = CF_EXPECT(
-      http_client.DownloadToJson(REFRESH_URL, {"Metadata-Flavor: Google"}));
+      http_client.DownloadToJson(kRefreshUrl, {"Metadata-Flavor: Google"}));
   const auto& json = response.data;
   CF_EXPECT(response.HttpSuccess(),
             "Error fetching credentials. The server response was \""
@@ -132,7 +132,7 @@
       refresh_token_(refresh_token) {}
 
 Result<std::string> RefreshCredentialSource::Credential() {
-  if (expiration_ - std::chrono::steady_clock::now() < REFRESH_WINDOW) {
+  if (expiration_ - std::chrono::steady_clock::now() < kRefreshWindow) {
     CF_EXPECT(UpdateLatestCredential());
   }
   return latest_credential_;
@@ -294,10 +294,10 @@
 }
 
 Result<std::string> ServiceAccountOauthCredentialSource::Credential() {
-  if (expiration_ - std::chrono::steady_clock::now() < REFRESH_WINDOW) {
+  if (expiration_ - std::chrono::steady_clock::now() < kRefreshWindow) {
     CF_EXPECT(RefreshCredential());
   }
   return latest_credential_;
 }
 
-} // namespace cuttlefish
+}  // namespace cuttlefish
diff --git a/host/libs/websocket/Android.bp b/host/libs/websocket/Android.bp
index 327224b..640e37d 100644
--- a/host/libs/websocket/Android.bp
+++ b/host/libs/websocket/Android.bp
@@ -17,7 +17,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_host_static {
+cc_library {
     name: "libcuttlefish_host_websocket",
     srcs: [
         "websocket_handler.cpp",
diff --git a/recovery/Android.bp b/recovery/Android.bp
index 0923d17..4392c4e 100644
--- a/recovery/Android.bp
+++ b/recovery/Android.bp
@@ -18,7 +18,7 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_library_static {
+cc_library {
     name: "librecovery_ui_cuttlefish",
     owner: "google",
     cflags: [
diff --git a/shared/BoardConfig.mk b/shared/BoardConfig.mk
index 5277d99..2eee523 100644
--- a/shared/BoardConfig.mk
+++ b/shared/BoardConfig.mk
@@ -57,6 +57,17 @@
 # GKI >5.10 will have and require virtio_pci_modern_dev.ko
 BOARD_VENDOR_RAMDISK_KERNEL_MODULES += $(wildcard $(KERNEL_MODULES_PATH)/virtio_pci_modern_dev.ko)
 
+# TODO(b/176860479) once virt_wifi is deprecated we can stop loading mac80211 in
+# first stage init. To minimize scope of modules options to first stage init,
+# mac80211_hwsim.radios=0 has to be specified in the modules options file (which we
+# only read in first stage) and mac80211_hwsim has to be loaded in first stage consequently..
+BOARD_VENDOR_RAMDISK_KERNEL_MODULES += $(wildcard $(SYSTEM_DLKM_SRC)/libarc4.ko)
+BOARD_VENDOR_RAMDISK_KERNEL_MODULES += $(wildcard $(SYSTEM_DLKM_SRC)/rfkill.ko)
+BOARD_VENDOR_RAMDISK_KERNEL_MODULES += $(wildcard $(KERNEL_MODULES_PATH)/cfg80211.ko)
+BOARD_VENDOR_RAMDISK_KERNEL_MODULES += $(wildcard $(KERNEL_MODULES_PATH)/mac80211.ko)
+BOARD_VENDOR_RAMDISK_KERNEL_MODULES += $(wildcard $(KERNEL_MODULES_PATH)/mac80211_hwsim.ko)
+BOARD_DO_NOT_STRIP_VENDOR_RAMDISK_MODULES := true
+
 ALL_KERNEL_MODULES := $(wildcard $(KERNEL_MODULES_PATH)/*.ko)
 BOARD_VENDOR_KERNEL_MODULES := \
     $(filter-out $(BOARD_VENDOR_RAMDISK_KERNEL_MODULES),\
@@ -279,7 +290,7 @@
 TARGET_RELEASETOOLS_EXTENSIONS := device/google/cuttlefish/shared
 
 # Generate a partial ota update package for partitions in vbmeta_system
-BOARD_PARTIAL_OTA_UPDATE_PARTITIONS_LIST := product system system_ext vbmeta_system
+BOARD_PARTIAL_OTA_UPDATE_PARTITIONS_LIST := product system system_ext vbmeta_system init_boot
 
 BOARD_BOOTLOADER_IN_UPDATE_PACKAGE := true
 BOARD_RAMDISK_USE_LZ4 := true
diff --git a/shared/auto/device_vendor.mk b/shared/auto/device_vendor.mk
index fb7510e..4cc46dc 100644
--- a/shared/auto/device_vendor.mk
+++ b/shared/auto/device_vendor.mk
@@ -29,7 +29,6 @@
 $(call inherit-product, device/google/cuttlefish/shared/swiftshader/device_vendor.mk)
 $(call inherit-product, device/google/cuttlefish/shared/telephony/device_vendor.mk)
 $(call inherit-product, device/google/cuttlefish/shared/sensors/device_vendor.mk)
-$(call inherit-product, device/google/cuttlefish/shared/virgl/device_vendor.mk)
 $(call inherit-product, device/google/cuttlefish/shared/device.mk)
 
 # Extend cuttlefish common sepolicy with auto-specific functionality
diff --git a/shared/config/manifest.xml b/shared/config/manifest.xml
index f121c95..eab12db 100644
--- a/shared/config/manifest.xml
+++ b/shared/config/manifest.xml
@@ -17,15 +17,6 @@
 */
 -->
 <manifest version="1.0" type="device" target-level="9">
-    <hal format="hidl">
-        <name>android.hardware.authsecret</name>
-        <transport>hwbinder</transport>
-        <version>1.0</version>
-        <interface>
-            <name>IAuthSecret</name>
-            <instance>default</instance>
-        </interface>
-    </hal>
 
     <!-- DO NOT ADD MORE - use vintf_fragments -->
 
diff --git a/shared/config/previous_manifest.xml b/shared/config/previous_manifest.xml
new file mode 100644
index 0000000..40b9e1b
--- /dev/null
+++ b/shared/config/previous_manifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2023, 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.
+*/
+-->
+<manifest version="1.0" type="device" target-level="8">
+
+    <!-- DO NOT ADD MORE - use vintf_fragments -->
+
+</manifest>
diff --git a/shared/device.mk b/shared/device.mk
index 24af8e0..08f1a7a 100644
--- a/shared/device.mk
+++ b/shared/device.mk
@@ -37,7 +37,6 @@
 
 PRODUCT_SOONG_NAMESPACES += device/generic/goldfish # for audio and wifi
 
-PRODUCT_SHIPPING_API_LEVEL := 35
 PRODUCT_USE_DYNAMIC_PARTITIONS := true
 DISABLE_RILD_OEM_HOOK := true
 
@@ -182,7 +181,13 @@
 #
 # Common manifest for all targets
 #
+ifeq ($(RELEASE_AIDL_USE_UNFROZEN),true)
+PRODUCT_SHIPPING_API_LEVEL := 35
 LOCAL_DEVICE_FCM_MANIFEST_FILE ?= device/google/cuttlefish/shared/config/manifest.xml
+else
+PRODUCT_SHIPPING_API_LEVEL := 34
+LOCAL_DEVICE_FCM_MANIFEST_FILE ?= device/google/cuttlefish/shared/config/previous_manifest.xml
+endif
 DEVICE_MANIFEST_FILE += $(LOCAL_DEVICE_FCM_MANIFEST_FILE)
 
 #
@@ -255,18 +260,11 @@
 PRODUCT_PACKAGES += \
     android.hardware.weaver-service.example
 
-
-#
-# Authsecret HAL
-#
-PRODUCT_PACKAGES += \
-    android.hardware.authsecret@1.0-service
-
 #
 # Authsecret AIDL HAL
 #
 PRODUCT_PACKAGES += \
-    android.hardware.authsecret-service.example
+    com.android.hardware.authsecret
 
 #
 # Audio HAL
@@ -408,7 +406,7 @@
 # KeyMint HAL
 #
 ifeq ($(LOCAL_KEYMINT_PRODUCT_PACKAGE),)
-    LOCAL_KEYMINT_PRODUCT_PACKAGE := android.hardware.security.keymint-service.rust
+    LOCAL_KEYMINT_PRODUCT_PACKAGE := com.google.cf.keymint.rust
 endif
 
 PRODUCT_PACKAGES += \
@@ -553,11 +551,8 @@
 endif
 
 # UWB HAL
-PRODUCT_PACKAGES += \
-    android.hardware.uwb-service
-PRODUCT_COPY_FILES += \
-    device/google/cuttlefish/guest/hals/uwb/uwb-service.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/uwb-service.rc
-
+PRODUCT_PACKAGES += com.android.hardware.uwb
+PRODUCT_VENDOR_PROPERTIES += ro.vendor.uwb.dev=/dev/hvc9
 
 # Host packages to install
 PRODUCT_HOST_PACKAGES += socket_vsock_proxy
@@ -598,4 +593,4 @@
     android.hardware.threadnetwork-service.sim \
     ot-cli-ftd
 PRODUCT_COPY_FILES += \
-    frameworks/native/data/etc/android.hardware.threadnetwork.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.threadnetwork.xml
+    frameworks/native/data/etc/android.hardware.thread_network.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.thread_network.xml
diff --git a/shared/phone/device_vendor.mk b/shared/phone/device_vendor.mk
index 4091c3f..5982a60 100644
--- a/shared/phone/device_vendor.mk
+++ b/shared/phone/device_vendor.mk
@@ -53,6 +53,8 @@
 
 endif
 
+DEVICE_PACKAGE_OVERLAYS += device/google/cuttlefish/shared/phone/overlay
+
 # Runtime Resource Overlays
 ifeq ($(LOCAL_PREFER_VENDOR_APEX),true)
 PRODUCT_PACKAGES += com.google.aosp_cf_phone.rros
diff --git a/shared/phone/overlay/frameworks/base/libs/WindowManager/Shell/res/values/dimen.xml b/shared/phone/overlay/frameworks/base/libs/WindowManager/Shell/res/values/dimen.xml
new file mode 100644
index 0000000..c500636
--- /dev/null
+++ b/shared/phone/overlay/frameworks/base/libs/WindowManager/Shell/res/values/dimen.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2023, 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.
+*/
+-->
+
+<resources>
+   <dimen name="dismiss_circle_size">60dp</dimen>
+</resources>
diff --git a/shared/sepolicy/vendor/bug_map b/shared/sepolicy/vendor/bug_map
index b6d528f..6417191 100644
--- a/shared/sepolicy/vendor/bug_map
+++ b/shared/sepolicy/vendor/bug_map
@@ -1,3 +1,4 @@
 init system_lib_file dir b/133444385
 init system_lib_file file b/133444385
 priv_app radio_vendor_data_file dir b/188833462
+rs privapp_data_file file b/291029681
diff --git a/shared/sepolicy/vendor/file_contexts b/shared/sepolicy/vendor/file_contexts
index 619dc93..a9b1422 100644
--- a/shared/sepolicy/vendor/file_contexts
+++ b/shared/sepolicy/vendor/file_contexts
@@ -72,7 +72,7 @@
 /vendor/bin/hw/android\.hardware\.gatekeeper@1\.0-service\.software  u:object_r:hal_gatekeeper_default_exec:s0
 /vendor/bin/hw/android\.hardware\.health-service\.cuttlefish u:object_r:hal_health_default_exec:s0
 /vendor/bin/hw/android\.hardware\.health\.storage-service\.cuttlefish u:object_r:hal_health_storage_default_exec:s0
-/vendor/bin/hw/android\.hardware\.lights-service\.cuttlefish u:object_r:hal_light_default_exec:s0
+/vendor/bin/hw/android\.hardware\.lights-service\.cuttlefish u:object_r:hal_light_cuttlefish_exec:s0
 /vendor/bin/hw/android\.hardware\.neuralnetworks-shim-service-sample   u:object_r:hal_neuralnetworks_sample_exec:s0
 /vendor/bin/hw/android\.hardware\.neuralnetworks-service-sample-.*   u:object_r:hal_neuralnetworks_sample_exec:s0
 /vendor/bin/hw/android\.hardware\.nfc-service\.cuttlefish  u:object_r:hal_nfc_default_exec:s0
diff --git a/shared/sepolicy/vendor/hal_light_cuttlefish.te b/shared/sepolicy/vendor/hal_light_cuttlefish.te
new file mode 100644
index 0000000..e02f8e0
--- /dev/null
+++ b/shared/sepolicy/vendor/hal_light_cuttlefish.te
@@ -0,0 +1,7 @@
+type hal_light_cuttlefish, domain;
+hal_server_domain(hal_light_cuttlefish, hal_light)
+
+type hal_light_cuttlefish_exec, exec_type, vendor_file_type, file_type;
+init_daemon_domain(hal_light_cuttlefish)
+
+allow hal_light_cuttlefish self:{ socket vsock_socket } { create_socket_perms_no_ioctl listen accept };
diff --git a/shared/sepolicy/vendor/property.te b/shared/sepolicy/vendor/property.te
index 371ce92..6f3dca1 100644
--- a/shared/sepolicy/vendor/property.te
+++ b/shared/sepolicy/vendor/property.te
@@ -4,3 +4,4 @@
 vendor_internal_prop(vendor_hwcomposer_prop)
 vendor_restricted_prop(vendor_wlan_versions_prop)
 vendor_internal_prop(vendor_device_prop)
+vendor_internal_prop(vendor_uwb_prop)
\ No newline at end of file
diff --git a/shared/sepolicy/vendor/property_contexts b/shared/sepolicy/vendor/property_contexts
index d4235ff..9acb483 100644
--- a/shared/sepolicy/vendor/property_contexts
+++ b/shared/sepolicy/vendor/property_contexts
@@ -13,6 +13,7 @@
 ro.vendor.hwcomposer.display_finder_mode  u:object_r:vendor_hwcomposer_prop:s0 exact string
 ro.vendor.hwcomposer.mode  u:object_r:vendor_hwcomposer_prop:s0 exact string
 ro.vendor.hwcomposer.pmem  u:object_r:vendor_hwcomposer_prop:s0 exact string
+ro.vendor.uwb.dev              u:object_r:vendor_uwb_prop:s0 exact string
 vendor.wlan.firmware.version   u:object_r:vendor_wlan_versions_prop:s0 exact string
 vendor.wlan.driver.version     u:object_r:vendor_wlan_versions_prop:s0 exact string
 vendor.dlkm.modules.ready      u:object_r:vendor_device_prop:s0 exact bool
diff --git a/shared/sepolicy/vendor/vendor_init.te b/shared/sepolicy/vendor/vendor_init.te
index 613a78f..b36ae67 100644
--- a/shared/sepolicy/vendor/vendor_init.te
+++ b/shared/sepolicy/vendor/vendor_init.te
@@ -10,5 +10,6 @@
 
 vendor_internal_prop(vendor_wifi_impl)
 set_prop(vendor_init, vendor_wifi_impl)
+set_prop(vendor_init, vendor_uwb_prop)
 
 set_prop(vendor_init, vendor_boot_security_patch_level_prop)
diff --git a/host/commands/cvd_load_tester/Android.bp b/tests/fastboot/Android.bp
similarity index 61%
rename from host/commands/cvd_load_tester/Android.bp
rename to tests/fastboot/Android.bp
index b51cea3..813abdd 100644
--- a/host/commands/cvd_load_tester/Android.bp
+++ b/tests/fastboot/Android.bp
@@ -1,4 +1,3 @@
-//
 // Copyright (C) 2023 The Android Open Source Project
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,25 +16,15 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-cc_binary {
-    name: "test_cvd_load_parser",
-    shared_libs: [
-        "libbase",
-        "libcuttlefish_fs",
-        "libcuttlefish_utils",
-        "libjsoncpp",
-        "libgrpc++_unsecure",
-        "libxml2",
-    ],
-    static_libs: [
-        "libprotobuf-cpp-full",
-        "libcuttlefish_launch_cvd_proto",
-        "libcvd_parser",
-        "libcuttlefish_host_config",
-        "libgflags",
-    ],
+java_test_host {
+    name: "FastbootRebootTest",
     srcs: [
-        "main.cc",
+        "src/com/android/cuttlefish/tests/FastbootRebootTest.java",
     ],
-    defaults: ["cvd_load_defaults"],
-}
\ No newline at end of file
+    test_suites: [
+        "device-tests",
+    ],
+    libs: [
+        "tradefed",
+    ],
+}
diff --git a/tests/fastboot/src/com/android/cuttlefish/tests/FastbootRebootTest.java b/tests/fastboot/src/com/android/cuttlefish/tests/FastbootRebootTest.java
new file mode 100644
index 0000000..d883cc4
--- /dev/null
+++ b/tests/fastboot/src/com/android/cuttlefish/tests/FastbootRebootTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+package com.android.cuttlefish.tests;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tradefed.device.TestDeviceState;
+import com.android.tradefed.invoker.TestInformation;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.AfterClassWithInfo;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class FastbootRebootTest extends BaseHostJUnit4Test {
+
+    @Before
+    public void rebootToBootloader() throws Exception {
+        getDevice().rebootIntoBootloader();
+    }
+
+    @AfterClassWithInfo
+    public static void rebootToAndroid(TestInformation information) throws Exception {
+        information.getDevice().reboot();
+    }
+
+    @Test
+    public void testReboot() throws Exception {
+        getDevice().rebootUserspace();
+        assertEquals(TestDeviceState.ONLINE, getDevice().getDeviceState());
+    }
+
+    @Test
+    public void testRebootRecovery() throws Exception {
+        getDevice().rebootIntoRecovery();
+        assertEquals(TestDeviceState.RECOVERY, getDevice().getDeviceState());
+    }
+
+    @Test
+    public void testRebootBootloader() throws Exception {
+        getDevice().rebootIntoBootloader();
+        assertEquals(TestDeviceState.FASTBOOT, getDevice().getDeviceState());
+    }
+
+    @Test
+    @Ignore("b/296629925")
+    public void testRebootFastboot() throws Exception {
+        getDevice().rebootIntoFastbootd();
+        assertEquals(TestDeviceState.FASTBOOTD, getDevice().getDeviceState());
+    }
+}
diff --git a/tests/hal/Android.bp b/tests/hal/Android.bp
index 1a63d6e..acf49bf 100644
--- a/tests/hal/Android.bp
+++ b/tests/hal/Android.bp
@@ -32,6 +32,11 @@
         "libutils",
         "packagemanager_aidl-cpp",
     ],
+    product_variables: {
+        release_aidl_use_unfrozen: {
+            cflags: ["-DAIDL_USE_UNFROZEN"],
+        },
+    },
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/tests/hal/hal_implementation_test.cpp b/tests/hal/hal_implementation_test.cpp
index 0c8abe4..3429fb1 100644
--- a/tests/hal/hal_implementation_test.cpp
+++ b/tests/hal/hal_implementation_test.cpp
@@ -33,6 +33,12 @@
 #include <string>
 #include <vector>
 
+#ifdef AIDL_USE_UNFROZEN
+constexpr bool kAidlUseUnfrozen = true;
+#else
+constexpr bool kAidlUseUnfrozen = false;
+#endif
+
 using namespace android;
 
 // clang-format off
@@ -59,6 +65,7 @@
     "android.hardware.audio.effect@4.0",
     "android.hardware.audio.effect@5.0",
     "android.hardware.audio.effect@6.0",
+    "android.hardware.authsecret@1.0", // converted to AIDL, see b/182976659
     "android.hardware.automotive.audiocontrol@1.0",
     "android.hardware.automotive.audiocontrol@2.0",
     "android.hardware.automotive.evs@1.1",
@@ -453,6 +460,7 @@
 }
 
 TEST(Hal, AllHidlInterfacesAreInAosp) {
+  if (!kAidlUseUnfrozen) GTEST_SKIP() << "Not valid in 'next' configuration";
   for (const FQName& name : allHidlManifestInterfaces()) {
     EXPECT_TRUE(isAospHidlInterface(name))
         << "This device should only have AOSP interfaces, not: "
@@ -461,6 +469,7 @@
 }
 
 TEST(Hal, HidlInterfacesImplemented) {
+  if (!kAidlUseUnfrozen) GTEST_SKIP() << "Not valid in 'next' configuration";
   // instances -> major version -> minor versions
   std::map<std::string, std::map<size_t, std::set<size_t>>> unimplemented;
 
@@ -516,6 +525,7 @@
 }
 
 TEST(Hal, AllAidlInterfacesAreInAosp) {
+  if (!kAidlUseUnfrozen) GTEST_SKIP() << "Not valid in 'next' configuration";
   for (const auto& package : allAidlManifestInterfaces()) {
     EXPECT_TRUE(isAospAidlInterface(package.name))
         << "This device should only have AOSP interfaces, not: "
@@ -529,6 +539,7 @@
 };
 
 TEST(Hal, AidlInterfacesImplemented) {
+  if (!kAidlUseUnfrozen) GTEST_SKIP() << "Not valid in 'next' configuration";
   std::vector<VersionedAidlPackage> manifest = allAidlManifestInterfaces();
   std::vector<VersionedAidlPackage> thoughtMissing = kKnownMissingAidl;
 
diff --git a/tools/create_base_image_arm.sh b/tools/create_base_image_arm.sh
index a5fe3ad..20fb758 100755
--- a/tools/create_base_image_arm.sh
+++ b/tools/create_base_image_arm.sh
@@ -118,7 +118,7 @@
 fastboot_raw_partition_raw1=0x0 0x2000000
 EOF
 echo "Sha=`${script_dir}/gen_sha.sh --uboot ${UBOOT_DIST} --kernel ${KERNEL_DIST}`" >> ${bootenv_src}
-${ANDROID_BUILD_TOP}/device/google/cuttlefish_prebuilts/uboot_tools/mkenvimage -s 32768 -o ${bootenv} - < ${bootenv_src}
+mkenvimage -s 32768 -o ${bootenv} - < ${bootenv_src}
 rm -f ${bootenv_src}
 
 IMAGE=`mktemp`
diff --git a/tools/launch_cvd_arm64_server.sh b/tools/launch_cvd_arm64_server.sh
index c8740ff..cbb5f33 100755
--- a/tools/launch_cvd_arm64_server.sh
+++ b/tools/launch_cvd_arm64_server.sh
@@ -35,7 +35,11 @@
 
 # copy and compress the artifacts to the temp directory
 ssh $server -t "mkdir -p ~/.cvd_artifact; mkdir -p ~/cvd_home"
-rsync -aSvch --recursive $ANDROID_PRODUCT_OUT --files-from=$ANDROID_PRODUCT_OUT/required_images $server:~/cvd_home --info=progress2
+if [ -f $ANDROID_PRODUCT_OUT/required_images ]; then
+  rsync -aSvch --recursive $ANDROID_PRODUCT_OUT --files-from=$ANDROID_PRODUCT_OUT/required_images $server:~/cvd_home --info=progress2
+else
+  rsync -aSvch --recursive $ANDROID_PRODUCT_OUT/bootloader $ANDROID_PRODUCT_OUT/*.img $server:~/cvd_home --info=progress2
+fi
 
 # copy the cvd host package
 cvd_host_tool_dir=$ANDROID_HOST_OUT/../linux_musl-arm64
@@ -56,7 +60,6 @@
 
 web_ui_port=$((8443+$base_instance_num-1))
 adb_port=$((6520+$base_instance_num-1))
-fastboot_port=$((7520+$base_instance_num-1))
 instance_id=$(uuidgen)
 # sets up SSH port forwarding to the remote server for various ports and launch cvd instance
 # port forward rule as base_instance_num=1 in local
@@ -64,5 +67,5 @@
   -L 15550:127.0.0.1:15550 -L 15551:127.0.0.1:15551 -L 15552:127.0.0.1:15552 \
   -L 15553:127.0.0.1:15553 -L 15554:127.0.0.1:15554 -L 15555:127.0.0.1:15555 \
   -L 15556:127.0.0.1:15556 -L 15557:127.0.0.1:15557 -L 15558:127.0.0.1:15558 \
-  -L 6520:127.0.0.1:$adb_port -L 7520:127.0.0.1:$fastboot_port \
+  -L 6520:127.0.0.1:$adb_port \
   -t "cd cvd_home && HOME=~/cvd_home bin/launch_cvd --base_instance_num=$base_instance_num"
diff --git a/tools/raw2iso.sh b/tools/raw2iso.sh
index 25fdd41..103bfa3 100755
--- a/tools/raw2iso.sh
+++ b/tools/raw2iso.sh
@@ -125,27 +125,21 @@
 dd if="\${SCRIPT_DIR}"/esp.img of=\${1}\${partition}1 bs=16M
 mkfs.ext4 -L ROOT -U \$(cat \${SCRIPT_DIR}/rootfs_uuid) \${1}\${partition}2
 mount \${1}\${partition}2 /media
-tar -C /media -Spxf \${SCRIPT_DIR}/rootfs.tar.lz4
+tar -C /media -Spxf \${SCRIPT_DIR}/rootfs.tar.xz
 umount /media
 EOF
 chmod a+x "${workdir}"/install.sh
 
-cat >"${workdir}"/installer.service <<EOF
-[Unit]
-Description=Installer script starter
-After=getty.target
-Conflicts=serial-getty@ttyAMA0.service
-
+cat >"${workdir}"/override-getty.conf <<EOF
 [Service]
-Type=oneshot
-RemainAfterExit=yes
-ExecStart=/bin/bash
-StandardInput=tty-force
-StandardOutput=inherit
-StandardError=inherit
+ExecStart=
+ExecStart=-/sbin/agetty -a root --noclear tty1 \$TERM
+EOF
 
-[Install]
-WantedBy=graphical.target
+cat >"${workdir}"/override-serial-getty.conf <<EOF
+[Service]
+ExecStart=
+ExecStart=-/sbin/agetty -a root --keep-baud 115200,57600,38400,9600 ttyAMA0 \$TERM
 EOF
 
 # Back up the GPT so we can restore it when installing
@@ -194,13 +188,13 @@
 sudo mount -o loop,offset=${root_partition_offset} "${input}" "${mount}"
 trap unmount EXIT
 sudo rm -f "${mount}"/root/esp.img "${mount}"/root/gpt.img
-sudo rm -f "${mount}"/root/rootfs.tar.lz4
+sudo rm -f "${mount}"/root/rootfs.tar.xz
 sudo rm -f "${mount}"/root/rootfs_uuid
 sudo rm -f "${mount}"/boot/grub/eltorito.img
 sudo rm -f "${mount}"/boot/grub/${grub_arch}/grub.cfg
 sudo rm -rf "${mount}"/tmp/*
 sudo rm -rf "${mount}"/var/tmp/*
-( cd "${mount}" && sudo tar -Szcpf "${workdir}"/rootfs.tar.lz4 * )
+( cd "${mount}" && sudo tar -SJcpf "${workdir}"/rootfs.tar.xz * )
 
 # Prepare a new ESP for the ISO's El Torito image
 mkdir -p "${workdir}/EFI/Boot"
@@ -214,22 +208,34 @@
 
 # Build ISO from rootfs
 sudo cp "${workdir}"/esp.img "${workdir}"/gpt.img "${mount}"/root
-sudo cp "${workdir}"/rootfs.tar.lz4 "${workdir}"/install.sh "${mount}"/root
+sudo cp "${workdir}"/rootfs.tar.xz "${workdir}"/install.sh "${mount}"/root
 echo -n "${rootfs_uuid}" | sudo tee "${mount}"/root/rootfs_uuid >/dev/null
 sudo cp "${workdir}"/eltorito.img "${mount}"/boot/grub
 sudo cp "${workdir}"/grub.cfg "${mount}"/boot/grub/${grub_arch}/grub.cfg
-sudo cp "${workdir}"/installer.service "${mount}"/usr/lib/systemd/system/installer.service
-sudo ln -f -r -s "${mount}"/usr/lib/systemd/system/installer.service "${mount}"/usr/lib/systemd/system/getty.target.wants/installer.service
+sudo mkdir -p "${mount}"/etc/systemd/system/getty@tty1.service.d
+sudo cp "${workdir}"/override-getty.conf "${mount}"/etc/systemd/system/getty@tty1.service.d/override.conf
+sudo mkdir -p "${mount}"/etc/systemd/system/serial-getty@ttyAMA0.service.d
+sudo cp "${workdir}"/override-serial-getty.conf "${mount}"/etc/systemd/system/serial-getty@ttyAMA0.service.d/override.conf
 sudo chown root:root \
   "${mount}"/root/esp.img "${mount}"/root/gpt.img \
   "${mount}"/boot/grub/eltorito.img \
   "${mount}"/boot/grub/${grub_arch}/grub.cfg
+sudo mv "${mount}"/usr "${mount}"/usr_o
+sudo mkzftree "${mount}"/usr_o "${mount}"/usr
+sudo rm -rf "${mount}"/usr_o
+sudo mv "${mount}"/root "${mount}"/root_o
+sudo mkzftree "${mount}"/root_o "${mount}"/root
+sudo rm -rf "${mount}"/root_o
+sudo mv "${mount}"/var "${mount}"/var_o
+sudo mkzftree "${mount}"/var_o "${mount}"/var
+sudo rm -rf "${mount}"/var_o
 rm -f "${output}"
 touch "${output}"
 sudo xorriso \
   -as mkisofs -r -checksum_algorithm_iso sha256,sha512 -V install "${mount}" \
   -o "${output}" -e boot/grub/eltorito.img -no-emul-boot \
   -append_partition 2 0xef "${workdir}"/eltorito.img \
+  -z \
   -partition_cyl_align all
 
 echo "Output ISO generated at '${output}'."
diff --git a/vsoc_arm64/BoardConfig.mk b/vsoc_arm64/BoardConfig.mk
index ae9e686..eed5fb3 100644
--- a/vsoc_arm64/BoardConfig.mk
+++ b/vsoc_arm64/BoardConfig.mk
@@ -44,4 +44,7 @@
 -include device/google/cuttlefish/shared/sensors/BoardConfig.mk
 -include device/google/cuttlefish/shared/swiftshader/BoardConfig.mk
 -include device/google/cuttlefish/shared/telephony/BoardConfig.mk
+
+ifneq ($(BOARD_IS_AUTOMOTIVE), true)
 -include device/google/cuttlefish/shared/virgl/BoardConfig.mk
+endif
diff --git a/vsoc_arm64_only/BoardConfig.mk b/vsoc_arm64_only/BoardConfig.mk
index 740eaf1..8b8dfeb 100644
--- a/vsoc_arm64_only/BoardConfig.mk
+++ b/vsoc_arm64_only/BoardConfig.mk
@@ -40,4 +40,7 @@
 -include device/google/cuttlefish/shared/sensors/BoardConfig.mk
 -include device/google/cuttlefish/shared/swiftshader/BoardConfig.mk
 -include device/google/cuttlefish/shared/telephony/BoardConfig.mk
+
+ifneq ($(BOARD_IS_AUTOMOTIVE), true)
 -include device/google/cuttlefish/shared/virgl/BoardConfig.mk
+endif
diff --git a/vsoc_arm64_only/phone/aosp_cf_pgagnostic.mk b/vsoc_arm64_only/phone/aosp_cf_pgagnostic.mk
new file mode 100644
index 0000000..0498cc2
--- /dev/null
+++ b/vsoc_arm64_only/phone/aosp_cf_pgagnostic.mk
@@ -0,0 +1,21 @@
+#
+# Copyright (C) 2023 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.
+#
+
+$(call inherit-product, device/google/cuttlefish/vsoc_arm64_only/phone/aosp_cf.mk)
+
+PRODUCT_NAME := aosp_cf_arm64_phone_pgagnostic
+PRODUCT_PAGE_SIZE_AGNOSTIC := true
+PRODUCT_MAX_PAGE_SIZE_SUPPORTED := 65536
diff --git a/vsoc_riscv64/phone/aosp_cf.mk b/vsoc_riscv64/phone/aosp_cf.mk
index c5a19a3..bc2af1f 100644
--- a/vsoc_riscv64/phone/aosp_cf.mk
+++ b/vsoc_riscv64/phone/aosp_cf.mk
@@ -39,6 +39,8 @@
 LOCAL_PREFER_VENDOR_APEX := true
 $(call inherit-product, device/google/cuttlefish/shared/phone/device_vendor.mk)
 
+PRODUCT_ENFORCE_MAC80211_HWSIM := false
+
 # TODO: Nested virtualization support
 # $(call inherit-product, packages/modules/Virtualization/apex/product_packages.mk)
 
diff --git a/vsoc_riscv64/slim/aosp_cf.mk b/vsoc_riscv64/slim/aosp_cf.mk
index ab79b49..b85b738 100644
--- a/vsoc_riscv64/slim/aosp_cf.mk
+++ b/vsoc_riscv64/slim/aosp_cf.mk
@@ -40,8 +40,7 @@
 LOCAL_PREFER_VENDOR_APEX := true
 $(call inherit-product, device/google/cuttlefish/shared/slim/device_vendor.mk)
 
-# TODO(b/205788876) remove this when openwrt has an image for riscv64
-#PRODUCT_ENFORCE_MAC80211_HWSIM := false
+PRODUCT_ENFORCE_MAC80211_HWSIM := false
 
 #
 # Special settings for the target
diff --git a/vsoc_riscv64/wear/aosp_cf.mk b/vsoc_riscv64/wear/aosp_cf.mk
index 215ede6..aa44c7f 100644
--- a/vsoc_riscv64/wear/aosp_cf.mk
+++ b/vsoc_riscv64/wear/aosp_cf.mk
@@ -37,6 +37,8 @@
 PRODUCT_COPY_FILES += \
     frameworks/native/data/etc/android.software.app_widgets.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.software.app_widgets.xml \
 
+PRODUCT_ENFORCE_MAC80211_HWSIM := false
+
 #
 # All components inherited here go to system_ext image
 #
diff --git a/vsoc_riscv64_minidroid/aosp_cf.mk b/vsoc_riscv64_minidroid/aosp_cf.mk
index a49ec77..8436a7b 100644
--- a/vsoc_riscv64_minidroid/aosp_cf.mk
+++ b/vsoc_riscv64_minidroid/aosp_cf.mk
@@ -24,6 +24,8 @@
 PRODUCT_MANUFACTURER := Google
 PRODUCT_MODEL := Cuttlefish riscv64 minidroid
 
+PRODUCT_ENFORCE_MAC80211_HWSIM := false
+
 PRODUCT_VENDOR_PROPERTIES += \
     ro.soc.manufacturer=$(PRODUCT_MANUFACTURER) \
     ro.soc.model=$(PRODUCT_DEVICE)
diff --git a/vsoc_x86_64/BoardConfig.mk b/vsoc_x86_64/BoardConfig.mk
index d0ff0b3..cda2a45 100644
--- a/vsoc_x86_64/BoardConfig.mk
+++ b/vsoc_x86_64/BoardConfig.mk
@@ -47,4 +47,7 @@
 -include device/google/cuttlefish/shared/sensors/BoardConfig.mk
 -include device/google/cuttlefish/shared/swiftshader/BoardConfig.mk
 -include device/google/cuttlefish/shared/telephony/BoardConfig.mk
+
+ifneq ($(BOARD_IS_AUTOMOTIVE), true)
 -include device/google/cuttlefish/shared/virgl/BoardConfig.mk
+endif
diff --git a/vsoc_x86_64/phone/aosp_cf.mk b/vsoc_x86_64/phone/aosp_cf.mk
index e5c8b47..f9e8d62 100644
--- a/vsoc_x86_64/phone/aosp_cf.mk
+++ b/vsoc_x86_64/phone/aosp_cf.mk
@@ -60,11 +60,8 @@
 PRODUCT_MANUFACTURER := Google
 PRODUCT_MODEL := Cuttlefish x86_64 phone
 
-# Window sidecar and extensions to enhance activity embedding, multi-display,
-# tablet, and foldable support.
-PRODUCT_PACKAGES += \
-    androidx.window.extensions \
-    androidx.window.sidecar \
+# Window Extensions
+$(call inherit-product, $(SRC_TARGET_DIR)/product/window_extensions.mk)
 
 PRODUCT_VENDOR_PROPERTIES += \
     ro.soc.manufacturer=$(PRODUCT_MANUFACTURER) \
diff --git a/vsoc_x86_64_only/BoardConfig.mk b/vsoc_x86_64_only/BoardConfig.mk
index 3afdbf0..d36821b 100644
--- a/vsoc_x86_64_only/BoardConfig.mk
+++ b/vsoc_x86_64_only/BoardConfig.mk
@@ -40,4 +40,7 @@
 -include device/google/cuttlefish/shared/sensors/BoardConfig.mk
 -include device/google/cuttlefish/shared/swiftshader/BoardConfig.mk
 -include device/google/cuttlefish/shared/telephony/BoardConfig.mk
+
+ifneq ($(BOARD_IS_AUTOMOTIVE), true)
 -include device/google/cuttlefish/shared/virgl/BoardConfig.mk
+endif
diff --git a/vsoc_x86_64_only/phone/aosp_cf.mk b/vsoc_x86_64_only/phone/aosp_cf.mk
index 45fed56..d843574 100644
--- a/vsoc_x86_64_only/phone/aosp_cf.mk
+++ b/vsoc_x86_64_only/phone/aosp_cf.mk
@@ -55,6 +55,9 @@
 PRODUCT_MANUFACTURER := Google
 PRODUCT_MODEL := Cuttlefish x86_64 phone 64-bit only
 
+# Window Extensions
+$(call inherit-product, $(SRC_TARGET_DIR)/product/window_extensions.mk)
+
 PRODUCT_VENDOR_PROPERTIES += \
     ro.soc.manufacturer=$(PRODUCT_MANUFACTURER) \
     ro.soc.model=$(PRODUCT_DEVICE)