Add the ability for VHAL Emulator to select a specific device

When multiple devices are connected, ADB needs a -s flag to pick a specific one to talk to
This commit plumbs the logic to enable this device selection logic to the HAL emulator as well
as the diagnostic injector tool

Additionally, since multiple HAL emulators might be in flight at a given time on a given host
with this change, it also changes the port selection logic to pick any free local port to
bind to instead of hardcoding to the same port number on local and remote side

Test: manual with one and two devices connected to a host
Bug: b/63098807
Change-Id: Idc3336919bbb4edf438f12fd05ff7d186d706faf
diff --git a/tools/emulator/diagnostic_injector.py b/tools/emulator/diagnostic_injector.py
index 4bd3317..6cc9965 100755
--- a/tools/emulator/diagnostic_injector.py
+++ b/tools/emulator/diagnostic_injector.py
@@ -20,8 +20,9 @@
 # Use thusly:
 # $ ./diagnostic_injector.py <path/to/diagnostic.json>
 
-import sys
+import argparse
 import json
+import sys
 import time
 
 import vhal_consts_2_1 as c
@@ -48,8 +49,8 @@
 from diagnostic_builder import DiagnosticEventBuilder
 
 class DiagnosticHalWrapper(object):
-    def __init__(self):
-        self.vhal = Vhal(c.vhal_types_2_0)
+    def __init__(self, device):
+        self.vhal = Vhal(c.vhal_types_2_0, device)
         self.liveFrameConfig = self.chat(
             lambda hal: hal.getConfig(c.VEHICLEPROPERTY_OBD2_LIVE_FRAME))
         self.freezeFrameConfig = self.chat(
@@ -105,11 +106,17 @@
             else:
                 print("fail: %s" % status)
 
-if len(sys.argv) < 2:
+parser = argparse.ArgumentParser(description='Diagnostic Events Injector')
+parser.add_argument('jsondoc', action='append', default=[], nargs='+')
+parser.add_argument('-s', action='store', dest='deviceid', default=None)
+
+args = parser.parse_args()
+
+if len(args.jsondoc) == 0:
     print("Syntax: diagnostic_injector.py <path/to/diagnostic.json>")
     sys.exit(1)
 
-halWrapper = DiagnosticHalWrapper()
+halWrapper = DiagnosticHalWrapper(device=args.deviceid)
 
 for arg in sys.argv[1:]:
     halWrapper.inject(arg)
diff --git a/tools/emulator/vhal_emulator.py b/tools/emulator/vhal_emulator.py
index 4c94e4f..7cc6da7 100644
--- a/tools/emulator/vhal_emulator.py
+++ b/tools/emulator/vhal_emulator.py
@@ -129,17 +129,22 @@
         """
         print("len = ", len(data), "str = ", ":".join("{:02x}".format(ord(d)) for d in data))
 
-    def openSocket(self):
+    def openSocket(self, device=None):
         """
             Connects to an Android Auto device running a Vehicle HAL with simulator.
         """
         # Hard-coded socket port needs to match the one in DefaultVehicleHal
-        portNumber = 33452
-        # Setup ADB port forwarding
-        subprocess.call("adb forward tcp:%d tcp:%d" % (portNumber, portNumber), shell=True)
+        remotePortNumber = 33452
+        extraArgs = '' if device is None else '-s %s' % device
+        adbCmd = 'adb %s forward tcp:0 tcp:%d' % (extraArgs, remotePortNumber)
+        adbResp = subprocess.check_output(adbCmd, shell=True)[0:-1]
+        localPortNumber = int(adbResp)
+        print('Connecting local port %s to remote port %s on %s' % (
+            localPortNumber, remotePortNumber,
+            'default device' if device is None else 'device %s' % device))
         # Open the socket and connect
         self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-        self.sock.connect(('localhost', portNumber))
+        self.sock.connect(('localhost', localPortNumber))
 
     def rxMsg(self):
         """
@@ -249,11 +254,11 @@
             return
         self._txCmd(cmd)
 
-    def __init__(self, types):
+    def __init__(self, types, device=None):
         # Save the list of types constants
         self._types = types
         # Open the socket
-        self.openSocket()
+        self.openSocket(device)
         # Get the list of configs
         self.getConfigAll()
         msg = self.rxMsg()