Bug 1140406 - [mozdevice] Allow connecting to a remote ADB server in adb.py. r=bclary
authorDave Hunt <dhunt@mozilla.com>
Wed, 25 Mar 2015 12:25:44 +0000
changeset 265808 48d6322d42b7128627eb6683597a567135b197b6
parent 265807 b6044f33b3e438638270ee9f981227d5b2710be2
child 265809 eb3e4c2fa35edb81788b382ac8cea15a34b5f555
push id830
push userraliiev@mozilla.com
push dateFri, 19 Jun 2015 19:24:37 +0000
treeherdermozilla-release@932614382a68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbclary
bugs1140406
milestone39.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1140406 - [mozdevice] Allow connecting to a remote ADB server in adb.py. r=bclary
testing/mozbase/mozdevice/mozdevice/adb.py
--- a/testing/mozbase/mozdevice/mozdevice/adb.py
+++ b/testing/mozbase/mozdevice/mozdevice/adb.py
@@ -117,34 +117,40 @@ class ADBCommand(object):
            adbcommand = ADBCommand()
        except NotImplementedError:
            print "ADBCommand can not be instantiated."
 
     """
 
     def __init__(self,
                  adb='adb',
+                 adb_host=None,
+                 adb_port=None,
                  logger_name='adb',
                  timeout=300,
                  verbose=False):
         """Initializes the ADBCommand object.
 
         :param adb: path to adb executable. Defaults to 'adb'.
+        :param adb_host: host of the adb server.
+        :param adb_port: port of the adb server.
         :param logger_name: logging logger name. Defaults to 'adb'.
 
         :raises: * ADBError
                  * ADBTimeoutError
 
         """
         if self.__class__ == ADBCommand:
             raise NotImplementedError
 
         self._logger = self._get_logger(logger_name)
         self._verbose = verbose
         self._adb_path = adb
+        self._adb_host = adb_host
+        self._adb_port = adb_port
         self._timeout = timeout
         self._polling_interval = 0.1
 
         self._logger.debug("%s: %s" % (self.__class__.__name__,
                                        self.__dict__))
 
         # catch early a missing or non executable adb command
         try:
@@ -199,16 +205,20 @@ class ADBCommand(object):
         directed to temporary files. If the process takes longer than
         the specified timeout, the process is terminated.
 
         It is the caller's responsibilty to clean up by closing
         the stdout and stderr temporary files.
 
         """
         args = [self._adb_path]
+        if self._adb_host:
+            args.extend(['-H', self._adb_host])
+        if self._adb_port:
+            args.extend(['-P', str(self._adb_port)])
         if device_serial:
             args.extend(['-s', device_serial, 'wait-for-device'])
         args.extend(cmds)
 
         adb_process = ADBProcess(args)
 
         if timeout is None:
             timeout = self._timeout
@@ -289,29 +299,34 @@ class ADBHost(ADBCommand):
        from mozdevice import ADBHost
 
        adbhost = ADBHost()
        adbhost.start_server()
 
     """
     def __init__(self,
                  adb='adb',
+                 adb_host=None,
+                 adb_port=None,
                  logger_name='adb',
                  timeout=300,
                  verbose=False):
         """Initializes the ADBHost object.
 
         :param adb: path to adb executable. Defaults to 'adb'.
+        :param adb_host: host of the adb server.
+        :param adb_port: port of the adb server.
         :param logger_name: logging logger name. Defaults to 'adb'.
 
         :raises: * ADBError
                  * ADBTimeoutError
 
         """
-        ADBCommand.__init__(self, adb=adb, logger_name=logger_name,
+        ADBCommand.__init__(self, adb=adb, adb_host=adb_host,
+                            adb_port=adb_port, logger_name=logger_name,
                             timeout=timeout, verbose=verbose)
 
     def command(self, cmds, timeout=None):
         """Executes an adb command on the host.
 
         :param cmds: list containing the command and its arguments to be
             executed.
         :param timeout: optional integer specifying the maximum time in
@@ -367,16 +382,34 @@ class ADBHost(ADBCommand):
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
             throwing an ADBTimeoutError.  This timeout is per adb call. The
             total time spent may exceed this value. If it is not
             specified, the value set in the ADBHost constructor is used.
         :raises: * ADBTimeoutError
                  * ADBError
 
+        Attempting to use start_server with any adb_host value other than None
+        will fail with an ADBError exception.
+
+        You will need to start the server on the remote host via the command:
+
+        .. code-block:: shell
+
+            adb -a fork-server server
+
+        If you wish the remote adb server to restart automatically, you can
+        enclose the command in a loop as in:
+
+        .. code-block:: shell
+
+            while true; do
+              adb -a fork-server server
+            done
+
         """
         self.command_output(["start-server"], timeout=timeout)
 
     def kill_server(self, timeout=None):
         """Kills the adb server.
 
         :param timeout: optional integer specifying the maximum time in
             seconds for any spawned adb process to complete before
@@ -455,16 +488,18 @@ class ADBDevice(ADBCommand):
        if adbdevice.process_exist("org.mozilla.fennec"):
            print "Fennec is running"
 
     """
 
     def __init__(self,
                  device=None,
                  adb='adb',
+                 adb_host=None,
+                 adb_port=None,
                  test_root='',
                  logger_name='adb',
                  timeout=300,
                  verbose=False,
                  device_ready_retry_wait=20,
                  device_ready_retry_attempts=3):
         """Initializes the ADBDevice object.
 
@@ -480,30 +515,33 @@ class ADBDevice(ADBCommand):
             valid serial not containing a ":" it will be used to
             identify the device, otherwise the value of the usb key,
             prefixed with "usb:" is used.
             If None is passed and there is exactly one device attached
             to the host, that device is used. If there is more than one
             device attached, ValueError is raised. If no device is
             attached the constructor will block until a device is
             attached or the timeout is reached.
+        :param adb_host: host of the adb server to connect to.
+        :param adb_port: port of the adb server to connect to.
         :param logger_name: logging logger name. Defaults to 'adb'.
         :param device_ready_retry_wait: number of seconds to wait
             between attempts to check if the device is ready after a
             reboot.
         :param device_ready_retry_attempts: number of attempts when
             checking if a device is ready.
 
         :raises: * ADBError
                  * ADBTimeoutError
                  * ValueError
 
 
         """
-        ADBCommand.__init__(self, adb=adb, logger_name=logger_name,
+        ADBCommand.__init__(self, adb=adb, adb_host=adb_host,
+                            adb_port=adb_port, logger_name=logger_name,
                             timeout=timeout, verbose=verbose)
         self._device_serial = self._get_device_serial(device)
         self._initial_test_root = test_root
         self._test_root = None
         self._device_ready_retry_wait = device_ready_retry_wait
         self._device_ready_retry_attempts = device_ready_retry_attempts
         self._have_root_shell = False
         self._have_su = False
@@ -550,17 +588,18 @@ class ADBDevice(ADBCommand):
             self._ls += " -1A"
         except ADBError:
             self._ls += " -a"
 
         self._logger.debug("ADBDevice: %s" % self.__dict__)
 
     def _get_device_serial(self, device):
         if device is None:
-            devices = ADBHost().devices()
+            devices = ADBHost(adb=self._adb_path, adb_host=self._adb_host,
+                              adb_port=self._adb_port).devices()
             if len(devices) > 1:
                 raise ValueError("ADBDevice called with multiple devices "
                                  "attached and no device specified")
             elif len(devices) == 0:
                 # We could error here, but this way we'll wait-for-device before we next
                 # run a command, which seems more friendly
                 return
             device = devices[0]
@@ -921,20 +960,23 @@ class ADBDevice(ADBCommand):
             cmd = "cd %s && %s" % (cwd, cmd)
         if env:
             envstr = '&& '.join(map(lambda x: 'export %s=%s' %
                                     (x[0], x[1]), env.iteritems()))
             cmd = envstr + "&& " + cmd
         cmd += "; echo rc=$?"
 
         args = [self._adb_path]
+        if self._adb_host:
+            args.extend(['-H', self._adb_host])
+        if self._adb_port:
+            args.extend(['-P', str(self._adb_port)])
         if self._device_serial:
             args.extend(['-s', self._device_serial])
         args.extend(["wait-for-device", "shell", cmd])
-
         adb_process = ADBProcess(args)
 
         if timeout is None:
             timeout = self._timeout
 
         start_time = time.time()
         exitcode = adb_process.proc.poll()
         while ((time.time() - start_time) <= timeout) and exitcode == None: