Uses vhci port associated with instances number.

Bug: 79779940
Test: build/boot omr1 locally with explicit other ports, run two
instances on gce at the same time and see them both show up in adb
devices, run one after another is already complete and use --vhci_port
to force it to use the same flag and observe failure

Change-Id: I809ad6b6ebedf8813daf663c6b7b5394c644ca4c
diff --git a/host/commands/launch/main.cc b/host/commands/launch/main.cc
index 266dc0a..06aaac1 100644
--- a/host/commands/launch/main.cc
+++ b/host/commands/launch/main.cc
@@ -127,6 +127,7 @@
               "Mode for adb connection. Can be usb for usb forwarding, or "
               "tunnel for tcp connection. If using tunnel, you may have to "
               "run 'adb kill-server' to get the device to show up.");
+DEFINE_int32(vhci_port, GetPerInstanceDefault(0), "VHCI port to use for usb");
 DEFINE_bool(start_wifi_relay, true, "Whether to start the wifi_relay process.");
 DEFINE_string(wifi_relay_binary,
               StringFromEnv("ANDROID_HOST_OUT", StringFromEnv("HOME", ".")) +
@@ -170,9 +171,9 @@
 // VirtualUSBManager manages virtual USB device presence for Cuttlefish.
 class VirtualUSBManager {
  public:
-  VirtualUSBManager(const std::string& usbsocket,
+  VirtualUSBManager(const std::string& usbsocket, int vhci_port,
                     const std::string& android_usbipsocket)
-      : adb_{usbsocket, android_usbipsocket},
+      : adb_{usbsocket, vhci_port, android_usbipsocket},
         usbip_{android_usbipsocket, adb_.Pool()} {}
 
   ~VirtualUSBManager() = default;
@@ -545,7 +546,7 @@
     LOG(INFO) << "Using XML:\n" << xml;
   }
 
-  VirtualUSBManager vadb(cfg.GetUSBV1SocketName(),
+  VirtualUSBManager vadb(cfg.GetUSBV1SocketName(), FLAGS_vhci_port,
                          GetPerInstanceDefault("android_usbip"));
   vadb.Start();
   IVServerManager ivshmem(json_root);
diff --git a/host/libs/usbip/vhci_instrument.cpp b/host/libs/usbip/vhci_instrument.cpp
index 10025fc..13cb867 100644
--- a/host/libs/usbip/vhci_instrument.cpp
+++ b/host/libs/usbip/vhci_instrument.cpp
@@ -23,6 +23,7 @@
 
 #include <glog/logging.h>
 #include <fstream>
+#include <limits>
 #include <sstream>
 #include "common/libs/fs/shared_select.h"
 
@@ -52,8 +53,8 @@
 
 // Subsystem and device type where VHCI driver is located.
 const char* const kVHCIPlatformPaths[] = {
-  "/sys/devices/platform/vhci_hcd",
-  "/sys/devices/platform/vhci_hcd.1",
+    "/sys/devices/platform/vhci_hcd",
+    "/sys/devices/platform/vhci_hcd.1",
 };
 
 // Control messages.
@@ -70,15 +71,10 @@
   kVHCIEvent,
 };
 
-// Port status values deducted from /sys/devices/platform/vhci_hcd/status
-enum {
-  // kVHCIPortFree indicates the port is not currently in use.
-  kVHCIStatusPortFree = 4
-};
 }  // anonymous namespace
 
-VHCIInstrument::VHCIInstrument(const std::string& name)
-    : name_(name) {}
+VHCIInstrument::VHCIInstrument(int port, const std::string& name)
+    : name_(name), port_{port} {}
 
 VHCIInstrument::~VHCIInstrument() {
   control_write_end_->Write(&kControlExit, sizeof(kControlExit));
@@ -103,40 +99,46 @@
     return false;
   }
 
-  if (!FindFreePort()) {
-    LOG(ERROR) << "It appears all your VHCI ports are currently occupied.";
-    LOG(ERROR) << "New VHCI device cannot be registered unless one of the "
-               << "ports is freed.";
+  if (!VerifyPortIsFree()) {
+    LOG(ERROR) << "Trying to use VHCI port " << port_ << " but it is already in"
+               << " use.";
     return false;
   }
 
+  LOG(INFO) << "Using VHCI port " << port_;
   attach_thread_ = std::thread([this] { AttachThread(); });
   return true;
 }
 
-bool VHCIInstrument::FindFreePort() {
-  std::ifstream stat(syspath_ + "/status");
-  int port;
-  int status;
-  std::string everything_else;
+bool VHCIInstrument::VerifyPortIsFree() const {
+  std::ifstream status_file(syspath_ + "/status");
 
-  if (!stat.is_open()) {
+  if (!status_file.good()) {
     LOG(ERROR) << "Could not open usb-ip status file.";
     return false;
   }
 
   // Skip past the header line.
-  std::getline(stat, everything_else);
+  status_file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
 
-  while (stat.rdstate() == std::ios_base::goodbit) {
-    stat >> port >> status;
-    std::getline(stat, everything_else);
-    if (status == kVHCIStatusPortFree) {
-      port_ = port;
-      LOG(INFO) << "Using VHCI port " << port_;
-      return true;
+  while (true) {
+    // Port status values deducted from /sys/devices/platform/vhci_hcd/status
+    // kVHCIPortFree indicates the port is not currently in use.
+    constexpr static int kVHCIStatusPortFree = 4;
+
+    int port{};
+    int status{};
+    status_file >> port >> status;
+    if (!status_file.good()) {
+      break;
+    }
+
+    status_file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
+    if (port_ == port) {
+      return status == kVHCIStatusPortFree;
     }
   }
+  LOG(ERROR) << "Couldn't find status for VHCI port " << port_;
   return false;
 }
 
@@ -245,8 +247,8 @@
     // It is unclear whether duplicate FD should remain open or not. There are
     // cases supporting both assumptions, likely related to kernel version.
     // Kernel 4.10 is having problems communicating with USB/IP server if the
-    // socket is closed after it's passed to kernel. It is a clear indication that
-    // the kernel requires the socket to be kept open.
+    // socket is closed after it's passed to kernel. It is a clear indication
+    // that the kernel requires the socket to be kept open.
     success = attach.rdstate() == std::ios_base::goodbit;
     // Make sure everything was written and flushed. This happens when we close
     // the ofstream attach.
diff --git a/host/libs/usbip/vhci_instrument.h b/host/libs/usbip/vhci_instrument.h
index 3a4a7e3..aa2f5d4 100644
--- a/host/libs/usbip/vhci_instrument.h
+++ b/host/libs/usbip/vhci_instrument.h
@@ -26,7 +26,7 @@
 // VHCIInstrument class configures VHCI-HCD on local kernel.
 class VHCIInstrument {
  public:
-  VHCIInstrument(const std::string& name);
+  VHCIInstrument(int port, const std::string& name);
   virtual ~VHCIInstrument();
 
   // Init opens vhci-hcd driver and allocates port to which remote USB device
@@ -54,7 +54,7 @@
   // AttachThread is a background thread that responds to configuration
   // requests.
   void AttachThread();
-  bool FindFreePort();
+  bool VerifyPortIsFree() const;
 
  private:
   std::string name_;
@@ -63,7 +63,7 @@
   cvd::SharedFD control_write_end_;
   cvd::SharedFD control_read_end_;
   cvd::SharedFD vhci_socket_;
-  int port_;
+  int port_{};
 
   VHCIInstrument(const VHCIInstrument& other) = delete;
   VHCIInstrument& operator=(const VHCIInstrument& other) = delete;
diff --git a/host/libs/vadb/virtual_adb_client.cpp b/host/libs/vadb/virtual_adb_client.cpp
index 71a5c73..9d06814 100644
--- a/host/libs/vadb/virtual_adb_client.cpp
+++ b/host/libs/vadb/virtual_adb_client.cpp
@@ -35,8 +35,9 @@
 }  // namespace
 
 VirtualADBClient::VirtualADBClient(usbip::DevicePool* pool, cvd::SharedFD fd,
+                                   int vhci_port,
                                    const std::string& usbip_socket_name)
-    : pool_{pool}, fd_{fd}, vhci_{usbip_socket_name} {
+    : pool_{pool}, fd_{fd}, vhci_{vhci_port, usbip_socket_name} {
   CHECK(vhci_.Init());
   timer_ = cvd::SharedFD::TimerFD(CLOCK_MONOTONIC, 0);
   SendHeartbeat();
diff --git a/host/libs/vadb/virtual_adb_client.h b/host/libs/vadb/virtual_adb_client.h
index d521c74..b2b2d0a 100644
--- a/host/libs/vadb/virtual_adb_client.h
+++ b/host/libs/vadb/virtual_adb_client.h
@@ -35,7 +35,7 @@
 // remote USB devices possible with help of USB/IP protocol.
 class VirtualADBClient {
  public:
-  VirtualADBClient(usbip::DevicePool* pool, cvd::SharedFD fd,
+  VirtualADBClient(usbip::DevicePool* pool, cvd::SharedFD fd, int vhci_port,
                    const std::string& usbip_socket_name);
 
   virtual ~VirtualADBClient() = default;
diff --git a/host/libs/vadb/virtual_adb_server.cpp b/host/libs/vadb/virtual_adb_server.cpp
index cf87940..fae84d2 100644
--- a/host/libs/vadb/virtual_adb_server.cpp
+++ b/host/libs/vadb/virtual_adb_server.cpp
@@ -36,7 +36,9 @@
 
 void VirtualADBServer::BeforeSelect(cvd::SharedFDSet* fd_read) const {
   fd_read->Set(server_);
-  for (const auto& client : clients_) client.BeforeSelect(fd_read);
+  for (const auto& client : clients_) {
+    client.BeforeSelect(fd_read);
+  }
 }
 
 void VirtualADBServer::AfterSelect(const cvd::SharedFDSet& fd_read) {
@@ -62,7 +64,7 @@
     return;
   }
 
-  clients_.emplace_back(&pool_, client, usbip_name_);
+  clients_.emplace_back(&pool_, client, vhci_port_, usbip_name_);
 }
 
 }  // namespace vadb
diff --git a/host/libs/vadb/virtual_adb_server.h b/host/libs/vadb/virtual_adb_server.h
index d679a5d..6e09ef7 100644
--- a/host/libs/vadb/virtual_adb_server.h
+++ b/host/libs/vadb/virtual_adb_server.h
@@ -26,9 +26,11 @@
 // VirtualADBServer manages incoming VirtualUSB/ADB connections from QEmu.
 class VirtualADBServer {
  public:
-  VirtualADBServer(const std::string& usb_socket_name,
+  VirtualADBServer(const std::string& usb_socket_name, int vhci_port,
                    const std::string& usbip_socket_name)
-      : name_(usb_socket_name), usbip_name_(usbip_socket_name) {}
+      : name_(usb_socket_name),
+        vhci_port_{vhci_port},
+        usbip_name_(usbip_socket_name) {}
 
   ~VirtualADBServer() = default;
 
@@ -52,6 +54,7 @@
 
   usbip::DevicePool pool_;
   std::string name_;
+  int vhci_port_{};
   std::string usbip_name_;
   cvd::SharedFD server_;
   std::list<VirtualADBClient> clients_;