Browse Source

Fix up some mozdevice changes

Ian Neal 4 months ago
parent
commit
2aa8d540a6

+ 53 - 0
mozilla-release/patches/1434664-1-60a1.patch

@@ -0,0 +1,53 @@
+# HG changeset patch
+# User William Lachance <wlachance@mozilla.com>
+# Date 1517422110 18000
+# Node ID 82b26c23e07b9ac2f377e855bc8c37136b05814f
+# Parent  819f7292dc2e97812f756d6c04579afad861f304
+Bug 1434664 - Fix mozdevice's pull/push methods on Windows r=bc
+
+We should use posixpath's normpath for calculating the remote
+(i.e. device path) with these methods.
+
+MozReview-Commit-ID: zwfsRvCxoe
+
+diff --git a/testing/mozbase/mozdevice/mozdevice/adb.py b/testing/mozbase/mozdevice/mozdevice/adb.py
+--- a/testing/mozbase/mozdevice/mozdevice/adb.py
++++ b/testing/mozbase/mozdevice/mozdevice/adb.py
+@@ -1723,17 +1723,17 @@ class ADBDevice(ADBCommand):
+             may exceed this value. If it is not specified, the value
+             set in the ADBDevice constructor is used.
+         :type timeout: integer or None
+         :raises: * ADBTimeoutError
+                  * ADBError
+         """
+         # remove trailing /
+         local = os.path.normpath(local)
+-        remote = os.path.normpath(remote)
++        remote = posixpath.normpath(remote)
+         copy_required = False
+         if os.path.isdir(local):
+             copy_required = True
+             temp_parent = tempfile.mkdtemp()
+             remote_name = os.path.basename(remote)
+             new_local = os.path.join(temp_parent, remote_name)
+             dir_util.copy_tree(local, new_local)
+             local = new_local
+@@ -1768,17 +1768,17 @@ class ADBDevice(ADBCommand):
+             may exceed this value. If it is not specified, the value
+             set in the ADBDevice constructor is used.
+         :type timeout: integer or None
+         :raises: * ADBTimeoutError
+                  * ADBError
+         """
+         # remove trailing /
+         local = os.path.normpath(local)
+-        remote = os.path.normpath(remote)
++        remote = posixpath.normpath(remote)
+         copy_required = False
+         original_local = local
+         if self._adb_version >= '1.0.36' and \
+            os.path.isdir(local) and self.is_dir(remote):
+             # See do_sync_pull in
+             # https://android.googlesource.com/platform/system/core/+/master/adb/file_sync_client.cpp
+             # Work around change in behavior in adb 1.0.36 where if
+             # the local destination directory exists, adb pull will

+ 31 - 0
mozilla-release/patches/1434664-2-60a1.patch

@@ -0,0 +1,31 @@
+# HG changeset patch
+# User William Lachance <wlachance@mozilla.com>
+# Date 1517597614 18000
+# Node ID 8b359f41473be85fe780e2543e09f38a34f7985c
+# Parent  b8e332cb697281687f739414408ca1f8ab2f78d6
+Bug 1434664 - Bump mozdevice to 0.52 r=bc
+
+MozReview-Commit-ID: 9u3Abd15R6E
+
+diff --git a/testing/mozbase/mozdevice/setup.py b/testing/mozbase/mozdevice/setup.py
+--- a/testing/mozbase/mozdevice/setup.py
++++ b/testing/mozbase/mozdevice/setup.py
+@@ -3,17 +3,17 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ # You can obtain one at http://mozilla.org/MPL/2.0/.
+ 
+ from __future__ import absolute_import
+ 
+ from setuptools import setup
+ 
+ PACKAGE_NAME = 'mozdevice'
+-PACKAGE_VERSION = '0.51'
++PACKAGE_VERSION = '0.52'
+ 
+ deps = ['mozfile >= 1.0',
+         'mozlog >= 3.0',
+         'moznetwork >= 0.24',
+         'mozprocess >= 0.19',
+         ]
+ 
+ setup(name=PACKAGE_NAME,

+ 57 - 0
mozilla-release/patches/1440714-03-60a1.patch

@@ -0,0 +1,57 @@
+# HG changeset patch
+# User Geoff Brown <gbrown@mozilla.com>
+# Date 1520612828 25200
+# Node ID bfe063307abd3fe4444b701af6c2e26b4e7ed02d
+# Parent  ef05f485aaea2833ebb5e017deeef309c89b7786
+Bug 1440714 - Add ADBDevice.get_file() to pull and read a remote file; r=bc
+
+diff --git a/testing/mozbase/mozdevice/mozdevice/adb.py b/testing/mozbase/mozdevice/mozdevice/adb.py
+--- a/testing/mozbase/mozdevice/mozdevice/adb.py
++++ b/testing/mozbase/mozdevice/mozdevice/adb.py
+@@ -1803,16 +1803,46 @@ class ADBDevice(ADBCommand):
+             self.command_output(["pull", remote, local], timeout=timeout)
+         except BaseException:
+             raise
+         finally:
+             if copy_required:
+                 dir_util.copy_tree(local, original_local)
+                 shutil.rmtree(temp_parent)
+ 
++    def get_file(self, remote, offset=None, length=None, timeout=None):
++        """Pull file from device and return the file's content
++
++        :param str remote: The path of the remote file.
++        :param offset: If specified, return only content beyond this offset.
++        :param length: If specified, limit content length accordingly.
++        :param timeout: 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 ADBDevice constructor is used.
++        :type timeout: integer or None
++        :raises: * ADBTimeoutError
++                 * ADBError
++        """
++        with tempfile.NamedTemporaryFile() as tf:
++            self.pull(remote, tf.name, timeout=timeout)
++            with open(tf.name) as tf2:
++                # ADB pull does not support offset and length, but we can
++                # instead read only the requested portion of the local file
++                if offset is not None and length is not None:
++                    tf2.seek(offset)
++                    return tf2.read(length)
++                elif offset is not None:
++                    tf2.seek(offset)
++                    return tf2.read()
++                else:
++                    return tf2.read()
++
+     def rm(self, path, recursive=False, force=False, timeout=None, root=False):
+         """Delete files or directories on the device.
+ 
+         :param str path: The path of the remote file or directory.
+         :param bool recursive: Flag specifying if the command is
+             to be applied recursively to the target. Default is False.
+         :param bool force: Flag which if True will not raise an
+             error when attempting to delete a non-existent file. Default

+ 403 - 0
mozilla-release/patches/1440714-07-61a1.patch

@@ -0,0 +1,403 @@
+# HG changeset patch
+# User Geoff Brown <gbrown@mozilla.com>
+# Date 1521214668 21600
+# Node ID 0d0760485016d2fc3449a5366d364fe9e589f818
+# Parent  3c15d2bc6d2492729fb27e7a4a9eb396004dc8b0
+Bug 1440714 - Convert Android cppunit test harness to adb.py; r=bc
+
+diff --git a/testing/mozbase/mozdevice/mozdevice/__init__.py b/testing/mozbase/mozdevice/mozdevice/__init__.py
+--- a/testing/mozbase/mozdevice/mozdevice/__init__.py
++++ b/testing/mozbase/mozdevice/mozdevice/__init__.py
+@@ -1,17 +1,17 @@
+ # This Source Code Form is subject to the terms of the Mozilla Public
+ # License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ # You can obtain one at http://mozilla.org/MPL/2.0/.
+ 
+ from __future__ import absolute_import
+ 
+-from .adb import ADBError, ADBRootError, ADBTimeoutError
++from .adb import ADBError, ADBProcessError, ADBRootError, ADBTimeoutError
+ from .adb import ADBProcess, ADBCommand, ADBHost, ADBDevice
+ from .adb_android import ADBAndroid
+ from .adb_b2g import ADBB2G
+ from .devicemanager import DeviceManager, DMError
+ from .devicemanagerADB import DeviceManagerADB
+ from .droid import DroidADB
+ 
+-__all__ = ['ADBError', 'ADBRootError', 'ADBTimeoutError', 'ADBProcess', 'ADBCommand', 'ADBHost',
+-           'ADBDevice', 'ADBAndroid', 'ADBB2G', 'DeviceManager', 'DMError',
+-           'DeviceManagerADB', 'DroidADB']
++__all__ = ['ADBError', 'ADBProcessError', 'ADBRootError', 'ADBTimeoutError',
++           'ADBProcess', 'ADBCommand', 'ADBHost', 'ADBDevice', 'ADBAndroid', 'ADBB2G',
++           'DeviceManager', 'DMError', 'DeviceManagerADB', 'DroidADB']
+diff --git a/testing/mozbase/mozdevice/mozdevice/adb.py b/testing/mozbase/mozdevice/mozdevice/adb.py
+--- a/testing/mozbase/mozdevice/mozdevice/adb.py
++++ b/testing/mozbase/mozdevice/mozdevice/adb.py
+@@ -57,16 +57,25 @@ class ADBError(Exception):
+     """ADBError is raised in situations where a command executed on a
+     device either exited with a non-zero exitcode or when an
+     unexpected error condition has occurred. Generally, ADBErrors can
+     be handled and the device can continue to be used.
+     """
+     pass
+ 
+ 
++class ADBProcessError(ADBError):
++    """ADBProcessError is raised when an associated ADBProcess is
++    available and relevant.
++    """
++    def __init__(self, adb_process):
++        ADBError.__init__(self, str(adb_process))
++        self.adb_process = adb_process
++
++
+ class ADBListDevicesError(ADBError):
+     """ADBListDevicesError is raised when errors are found listing the
+     devices, typically not any permissions.
+ 
+     The devices information is stocked with the *devices* member.
+     """
+ 
+     def __init__(self, msg, devices):
+@@ -275,17 +284,17 @@ class ADBCommand(object):
+             # since ADBDevice will redefine command and call its
+             # own version otherwise.
+             adb_process = ADBCommand.command(self, cmds,
+                                              device_serial=device_serial,
+                                              timeout=timeout)
+             if adb_process.timedout:
+                 raise ADBTimeoutError("%s" % adb_process)
+             elif adb_process.exitcode:
+-                raise ADBError("%s" % adb_process)
++                raise ADBProcessError(adb_process)
+             output = adb_process.stdout_file.read().rstrip()
+             if self._verbose:
+                 self._logger.debug('command_output: %s, '
+                                    'timeout: %s, '
+                                    'timedout: %s, '
+                                    'exitcode: %s, output: %s' %
+                                    (' '.join(adb_process.args),
+                                     timeout,
+@@ -1133,17 +1142,17 @@ class ADBDevice(ADBCommand):
+         """
+         adb_process = None
+         try:
+             adb_process = self.shell(cmd, env=env, cwd=cwd,
+                                      timeout=timeout, root=root)
+             if adb_process.timedout:
+                 raise ADBTimeoutError("%s" % adb_process)
+             elif adb_process.exitcode:
+-                raise ADBError("%s" % adb_process)
++                raise ADBProcessError(adb_process)
+             output = adb_process.stdout_file.read().rstrip()
+             if self._verbose:
+                 self._logger.debug('shell_output: %s, '
+                                    'timeout: %s, '
+                                    'root: %s, '
+                                    'timedout: %s, '
+                                    'exitcode: %s, '
+                                    'output: %s' %
+@@ -1911,17 +1920,17 @@ class ADBDevice(ADBCommand):
+                  * ADBError
+         """
+         adb_process = None
+         try:
+             adb_process = self.shell("ps", timeout=timeout)
+             if adb_process.timedout:
+                 raise ADBTimeoutError("%s" % adb_process)
+             elif adb_process.exitcode:
+-                raise ADBError("%s" % adb_process)
++                raise ADBProcessError(adb_process)
+             # first line is the headers
+             header = adb_process.stdout_file.readline()
+             pid_i = -1
+             user_i = -1
+             els = header.split()
+             for i in range(len(els)):
+                 item = els[i].lower()
+                 if item == 'user':
+diff --git a/testing/remotecppunittests.py b/testing/remotecppunittests.py
+--- a/testing/remotecppunittests.py
++++ b/testing/remotecppunittests.py
+@@ -8,55 +8,48 @@ import os
+ import sys
+ import subprocess
+ from zipfile import ZipFile
+ import runcppunittests as cppunittests
+ import mozcrash
+ import mozfile
+ import mozinfo
+ import mozlog
+-import StringIO
+ import posixpath
+-from mozdevice import devicemanagerADB
++from mozdevice import ADBAndroid, ADBProcessError
+ 
+ try:
+     from mozbuild.base import MozbuildObject
+     build_obj = MozbuildObject.from_environment()
+ except ImportError:
+     build_obj = None
+ 
+ 
+ class RemoteCPPUnitTests(cppunittests.CPPUnitTests):
+ 
+-    def __init__(self, devmgr, options, progs):
++    def __init__(self, options, progs):
+         cppunittests.CPPUnitTests.__init__(self)
+         self.options = options
+-        self.device = devmgr
+-        self.remote_test_root = self.device.deviceRoot + "/cppunittests"
++        self.device = ADBAndroid(adb=options.adb_path,
++                                 device=options.device_serial,
++                                 test_root=options.remote_test_root)
++        self.remote_test_root = posixpath.join(self.device.test_root, "cppunittests")
+         self.remote_bin_dir = posixpath.join(self.remote_test_root, "b")
+         self.remote_tmp_dir = posixpath.join(self.remote_test_root, "tmp")
+         self.remote_home_dir = posixpath.join(self.remote_test_root, "h")
+         if options.setup:
+             self.setup_bin(progs)
+ 
+     def setup_bin(self, progs):
+-        if not self.device.dirExists(self.remote_test_root):
+-            self.device.mkDir(self.remote_test_root)
+-        if self.device.dirExists(self.remote_tmp_dir):
+-            self.device.removeDir(self.remote_tmp_dir)
+-        self.device.mkDir(self.remote_tmp_dir)
+-        if self.device.dirExists(self.remote_bin_dir):
+-            self.device.removeDir(self.remote_bin_dir)
+-        self.device.mkDir(self.remote_bin_dir)
+-        if self.device.dirExists(self.remote_home_dir):
+-            self.device.removeDir(self.remote_home_dir)
+-        self.device.mkDir(self.remote_home_dir)
++        self.device.rm(self.remote_test_root, force=True, recursive=True)
++        self.device.mkdir(self.remote_home_dir, parents=True)
++        self.device.mkdir(self.remote_tmp_dir)
+         self.push_libs()
+         self.push_progs(progs)
+-        self.device.chmodDir(self.remote_bin_dir)
++        self.device.chmod(self.remote_bin_dir, recursive=True)
+ 
+     def push_libs(self):
+         if self.options.local_apk:
+             with mozfile.TemporaryDirectory() as tmpdir:
+                 apk_contents = ZipFile(self.options.local_apk)
+ 
+                 for info in apk_contents.infolist():
+                     if info.filename.endswith(".so"):
+@@ -68,44 +61,44 @@ class RemoteCPPUnitTests(cppunittests.CP
+                         with open(local_file) as f:
+                             # Decompress xz-compressed file.
+                             if f.read(5)[1:] == '7zXZ':
+                                 cmd = [
+                                     'xz', '-df', '--suffix', '.so', local_file]
+                                 subprocess.check_output(cmd)
+                                 # xz strips the ".so" file suffix.
+                                 os.rename(local_file[:-3], local_file)
+-                        self.device.pushFile(local_file, remote_file)
++                        self.device.push(local_file, remote_file)
+ 
+         elif self.options.local_lib:
+             for file in os.listdir(self.options.local_lib):
+                 if file.endswith(".so"):
+                     print >> sys.stderr, "Pushing %s.." % file
+                     remote_file = posixpath.join(self.remote_bin_dir, file)
+                     local_file = os.path.join(self.options.local_lib, file)
+-                    self.device.pushFile(local_file, remote_file)
++                    self.device.push(local_file, remote_file)
+             # Additional libraries may be found in a sub-directory such as
+             # "lib/armeabi-v7a"
+             for subdir in ["assets", "lib"]:
+                 local_arm_lib = os.path.join(self.options.local_lib, subdir)
+                 if os.path.isdir(local_arm_lib):
+                     for root, dirs, files in os.walk(local_arm_lib):
+                         for file in files:
+                             if (file.endswith(".so")):
+                                 print >> sys.stderr, "Pushing %s.." % file
+                                 remote_file = posixpath.join(
+                                     self.remote_bin_dir, file)
+                                 local_file = os.path.join(root, file)
+-                                self.device.pushFile(local_file, remote_file)
++                                self.device.push(local_file, remote_file)
+ 
+     def push_progs(self, progs):
+         for local_file in progs:
+             remote_file = posixpath.join(
+                 self.remote_bin_dir, os.path.basename(local_file))
+-            self.device.pushFile(local_file, remote_file)
++            self.device.push(local_file, remote_file)
+ 
+     def build_environment(self):
+         env = self.build_core_environment()
+         env['LD_LIBRARY_PATH'] = self.remote_bin_dir
+         env["TMPDIR"] = self.remote_tmp_dir
+         env["HOME"] = self.remote_home_dir
+         env["MOZ_XRE_DIR"] = self.remote_bin_dir
+         if self.options.add_env:
+@@ -133,26 +126,32 @@ class RemoteCPPUnitTests(cppunittests.CP
+                         symbol files for producing stack traces on crash.
+         * timeout_factor: An optional test-specific timeout multiplier.
+ 
+         Return True if the program exits with a zero status, False otherwise.
+         """
+         basename = os.path.basename(prog)
+         remote_bin = posixpath.join(self.remote_bin_dir, basename)
+         self.log.test_start(basename)
+-        buf = StringIO.StringIO()
+         test_timeout = cppunittests.CPPUnitTests.TEST_PROC_TIMEOUT * \
+             timeout_factor
+-        returncode = self.device.shell(
+-            [remote_bin], buf, env=env, cwd=self.remote_home_dir,
+-            timeout=test_timeout)
+-        self.log.process_output(basename, "\n%s" % buf.getvalue(),
++
++        try:
++            output = self.device.shell_output(remote_bin, env=env,
++                                              cwd=self.remote_home_dir,
++                                              timeout=test_timeout)
++            returncode = 0
++        except ADBProcessError as e:
++            output = e.adb_process.stdout
++            returncode = e.adb_process.exitcode
++
++        self.log.process_output(basename, "\n%s" % output,
+                                 command=[remote_bin])
+         with mozfile.TemporaryDirectory() as tempdir:
+-            self.device.getDirectory(self.remote_home_dir, tempdir)
++            self.device.pull(self.remote_home_dir, tempdir)
+             if mozcrash.check_for_crashes(tempdir, symbols_path,
+                                           test_name=basename):
+                 self.log.test_end(basename, status='CRASH', expected='PASS')
+                 return False
+         result = returncode == 0
+         if not result:
+             self.log.test_end(basename, status='FAIL', expected='PASS',
+                               message=("test failed with return code %s" %
+@@ -163,25 +162,20 @@ class RemoteCPPUnitTests(cppunittests.CP
+ 
+ 
+ class RemoteCPPUnittestOptions(cppunittests.CPPUnittestOptions):
+ 
+     def __init__(self):
+         cppunittests.CPPUnittestOptions.__init__(self)
+         defaults = {}
+ 
+-        self.add_option("--deviceIP", action="store",
+-                        type="string", dest="device_ip",
+-                        help="ip address of remote device to test")
+-        defaults["device_ip"] = None
+-
+-        self.add_option("--devicePort", action="store",
+-                        type="string", dest="device_port",
+-                        help="port of remote device to test")
+-        defaults["device_port"] = 20701
++        self.add_option("--deviceSerial", action="store",
++                        type="string", dest="device_serial",
++                        help="serial ID of device")
++        defaults["device_serial"] = None
+ 
+         self.add_option("--noSetup", action="store_false",
+                         dest="setup",
+                         help="do not copy any files to device (to be used only if "
+                         "device is already setup)")
+         defaults["setup"] = True
+ 
+         self.add_option("--localLib", action="store",
+@@ -202,69 +196,33 @@ class RemoteCPPUnittestOptions(cppunitte
+ 
+         self.add_option("--remoteTestRoot", action="store",
+                         type="string", dest="remote_test_root",
+                         help="remote directory to use as test root (eg. /data/local/tests)")
+         # /data/local/tests is used because it is usually not possible to set +x permissions
+         # on binaries on /mnt/sdcard
+         defaults["remote_test_root"] = "/data/local/tests"
+ 
+-        self.add_option("--with-b2g-emulator", action="store",
+-                        type="string", dest="with_b2g_emulator",
+-                        help="Start B2G Emulator (specify path to b2g home)")
+-        self.add_option("--emulator", default="arm", choices=["x86", "arm"],
+-                        help="Architecture of emulator to use: x86 or arm")
+         self.add_option("--addEnv", action="append",
+                         type="string", dest="add_env",
+                         help="additional remote environment variable definitions "
+                         "(eg. --addEnv \"somevar=something\")")
+         defaults["add_env"] = None
+ 
+         self.set_defaults(**defaults)
+ 
+ 
+ def run_test_harness(options, args):
+-    if options.with_b2g_emulator:
+-        from mozrunner import B2GEmulatorRunner
+-        runner = B2GEmulatorRunner(
+-            arch=options.emulator, b2g_home=options.with_b2g_emulator)
+-        runner.start()
+-        # because we just started the emulator, we need more than the
+-        # default number of retries here.
+-        retryLimit = 50
+-    else:
+-        retryLimit = 5
+-    try:
+-        dm_args = {'deviceRoot': options.remote_test_root}
+-        dm_args['retryLimit'] = retryLimit
+-        if options.device_ip:
+-            dm_args['host'] = options.device_ip
+-            dm_args['port'] = options.device_port
+-        if options.log_tbpl_level == 'debug' or options.log_mach_level == 'debug':
+-            dm_args['logLevel'] = logging.DEBUG # noqa python 2 / 3
+-        dm = devicemanagerADB.DeviceManagerADB(**dm_args)
+-    except BaseException:
+-        if options.with_b2g_emulator:
+-            runner.cleanup()
+-            runner.wait()
+-        raise
+-
+     options.xre_path = os.path.abspath(options.xre_path)
+     cppunittests.update_mozinfo()
+     progs = cppunittests.extract_unittests_from_args(args,
+                                                      mozinfo.info,
+                                                      options.manifest_path)
+-    tester = RemoteCPPUnitTests(dm, options, [item[0] for item in progs])
+-    try:
+-        result = tester.run_tests(
+-            progs, options.xre_path, options.symbols_path)
+-    finally:
+-        if options.with_b2g_emulator:
+-            runner.cleanup()
+-            runner.wait()
++    tester = RemoteCPPUnitTests(options, [item[0] for item in progs])
++    result = tester.run_tests(progs, options.xre_path, options.symbols_path)
+     return result
+ 
+ 
+ def main():
+     parser = RemoteCPPUnittestOptions()
+     mozlog.commandline.add_logging_group(parser)
+     options, args = parser.parse_args()
+     if not args:
+diff --git a/testing/remotecppunittests.py.1440714-07.later b/testing/remotecppunittests.py.1440714-07.later
+new file mode 100644
+--- /dev/null
++++ b/testing/remotecppunittests.py.1440714-07.later
+@@ -0,0 +1,21 @@
++--- remotecppunittests.py
+++++ remotecppunittests.py
++@@ -163,17 +163,17 @@ class RemoteCPPUnitTests(cppunittests.CP
++         self.add_option("--deviceSerial", action="store",
++                         type="string", dest="device_serial",
++                         help="serial ID of device")
++         defaults["device_serial"] = None
++ 
++         self.add_option("--adbPath", action="store",
++                         type="string", dest="adb_path",
++                         help="Path to adb")
++-        defaults["adb_path"] = None
+++        defaults["adb_path"] = "adb"
++ 
++         self.add_option("--noSetup", action="store_false",
++                         dest="setup",
++                         help="do not copy any files to device (to be used only if "
++                         "device is already setup)")
++         defaults["setup"] = True
++ 
++         self.add_option("--localLib", action="store",

+ 2466 - 0
mozilla-release/patches/1440714-17-61a1.patch

@@ -0,0 +1,2466 @@
+# HG changeset patch
+# User Geoff Brown <gbrown@mozilla.com>
+# Date 1524760988 21600
+# Node ID ad8b8a0eb0d2e98f3dbe51979d16d3200d95fc6a
+# Parent  7bc9cdc13e72d98c1700debfea3e37aee4ab2354
+Bug 1440714 - Remove DeviceManagerADB and Droid classes from mozdevice; r=bc
+
+diff --git a/testing/mozbase/mozdevice/adb_tests/test_device_running_adb_as_root.py b/testing/mozbase/mozdevice/adb_tests/test_device_running_adb_as_root.py
+deleted file mode 100644
+--- a/testing/mozbase/mozdevice/adb_tests/test_device_running_adb_as_root.py
++++ /dev/null
+@@ -1,52 +0,0 @@
+-"""
+- This test is to test devices that adbd does not get started as root.
+- Specifically devices that have ro.secure == 1 and ro.debuggable == 1
+-
+- Running this test case requires various reboots which makes it a
+- very slow test case to run.
+-"""
+-
+-from __future__ import absolute_import, print_function
+-
+-import unittest
+-import sys
+-
+-from mozdevice import DeviceManagerADB
+-
+-
+-class TestFileOperations(unittest.TestCase):
+-
+-    def setUp(self):
+-        dm = DeviceManagerADB()
+-        dm.reboot(wait=True)
+-
+-    def test_run_adb_as_root_parameter(self):
+-        dm = DeviceManagerADB()
+-        self.assertTrue(dm.processInfo("adbd")[2] != "root")
+-        dm = DeviceManagerADB(runAdbAsRoot=True)
+-        self.assertTrue(dm.processInfo("adbd")[2] == "root")
+-
+-    def test_after_reboot_adb_runs_as_root(self):
+-        dm = DeviceManagerADB(runAdbAsRoot=True)
+-        self.assertTrue(dm.processInfo("adbd")[2] == "root")
+-        dm.reboot(wait=True)
+-        self.assertTrue(dm.processInfo("adbd")[2] == "root")
+-
+-    def tearDown(self):
+-        dm = DeviceManagerADB()
+-        dm.reboot()
+-
+-
+-if __name__ == "__main__":
+-    dm = DeviceManagerADB()
+-    if not dm.devices():
+-        print("There are no connected adb devices")
+-        sys.exit(1)
+-    else:
+-        if not (int(dm._runCmd(["shell", "getprop", "ro.secure"]).output[0]) and
+-                int(dm._runCmd(["shell", "getprop", "ro.debuggable"]).output[0])):
+-            print("This test case is meant for devices with devices that start "
+-                  "adbd as non-root and allows for adbd to be restarted as root.")
+-            sys.exit(1)
+-
+-    unittest.main()
+diff --git a/testing/mozbase/mozdevice/adb_tests/test_devicemanagerADB.py b/testing/mozbase/mozdevice/adb_tests/test_devicemanagerADB.py
+deleted file mode 100644
+--- a/testing/mozbase/mozdevice/adb_tests/test_devicemanagerADB.py
++++ /dev/null
+@@ -1,220 +0,0 @@
+-"""
+- Info:
+-   This tests DeviceManagerADB with a real device
+-
+- Requirements:
+-   - You must have a device connected
+-      - It should be listed under 'adb devices'
+-
+- Notes:
+-   - Not all functions have been covered.
+-     In particular, functions from the parent class
+-   - No testing of properties is done
+-   - The test case are very simple and it could be
+-     done with deeper inspection of the return values
+-
+- Author(s):
+-   - Armen Zambrano <armenzg@mozilla.com>
+-
+- Functions that are not being tested:
+- - launchProcess - DEPRECATED
+- - getIP
+- - recordLogcat
+- - saveScreenshot
+- - validateDir
+- - mkDirs
+- - getDeviceRoot
+- - shellCheckOutput
+- - processExist
+-
+- I assume these functions are only useful for Android
+- - getAppRoot()
+- - updateApp()
+- - uninstallApp()
+- - uninstallAppAndReboot()
+-"""
+-from __future__ import absolute_import, print_function
+-
+-import os
+-import re
+-import socket
+-import sys
+-import tempfile
+-import unittest
+-from StringIO import StringIO
+-
+-from mozdevice import DeviceManagerADB, DMError
+-
+-
+-def find_mount_permissions(dm, mount_path):
+-    for mount_point in dm._runCmd(["shell", "mount"]).output:
+-        if mount_point.find(mount_path) > 0:
+-            return re.search('(ro|rw)(?=,)', mount_point).group(0)
+-
+-
+-class DeviceManagerADBTestCase(unittest.TestCase):
+-    tempLocalDir = "tempDir"
+-    tempLocalFile = os.path.join(tempLocalDir, "tempfile.txt")
+-    tempRemoteDir = None
+-    tempRemoteFile = None
+-    tempRemoteSystemFile = None
+-
+-    def setUp(self):
+-        self.assertTrue(find_mount_permissions(self.dm, "/system"), "ro")
+-
+-        self.assertTrue(os.path.exists(self.tempLocalDir))
+-        self.assertTrue(os.path.exists(self.tempLocalFile))
+-
+-        if self.dm.fileExists(self.tempRemoteFile):
+-            self.dm.removeFile(self.tempRemoteFile)
+-        self.assertFalse(self.dm.fileExists(self.tempRemoteFile))
+-
+-        if self.dm.fileExists(self.tempRemoteSystemFile):
+-            self.dm.removeFile(self.tempRemoteSystemFile)
+-
+-        self.assertTrue(self.dm.dirExists(self.tempRemoteDir))
+-
+-    @classmethod
+-    def setUpClass(self):
+-        self.dm = DeviceManagerADB()
+-        if not os.path.exists(self.tempLocalDir):
+-            os.mkdir(self.tempLocalDir)
+-        if not os.path.exists(self.tempLocalFile):
+-            # Create empty file
+-            open(self.tempLocalFile, 'w').close()
+-        self.tempRemoteDir = self.dm.getTempDir()
+-        self.tempRemoteFile = os.path.join(self.tempRemoteDir,
+-                                           os.path.basename(self.tempLocalFile))
+-        self.tempRemoteSystemFile = \
+-            os.path.join("/system", os.path.basename(self.tempLocalFile))
+-
+-    @classmethod
+-    def tearDownClass(self):
+-        os.remove(self.tempLocalFile)
+-        os.rmdir(self.tempLocalDir)
+-        if self.dm.dirExists(self.tempRemoteDir):
+-            # self.tempRemoteFile will get deleted with it
+-            self.dm.removeDir(self.tempRemoteDir)
+-        if self.dm.fileExists(self.tempRemoteSystemFile):
+-            self.dm.removeFile(self.tempRemoteSystemFile)
+-
+-
+-class TestFileOperations(DeviceManagerADBTestCase):
+-
+-    def test_make_and_remove_directory(self):
+-        dir1 = os.path.join(self.tempRemoteDir, "dir1")
+-        self.assertFalse(self.dm.dirExists(dir1))
+-        self.dm.mkDir(dir1)
+-        self.assertTrue(self.dm.dirExists(dir1))
+-        self.dm.removeDir(dir1)
+-        self.assertFalse(self.dm.dirExists(dir1))
+-
+-    def test_push_and_remove_file(self):
+-        self.dm.pushFile(self.tempLocalFile, self.tempRemoteFile)
+-        self.assertTrue(self.dm.fileExists(self.tempRemoteFile))
+-        self.dm.removeFile(self.tempRemoteFile)
+-        self.assertFalse(self.dm.fileExists(self.tempRemoteFile))
+-
+-    def test_push_and_pull_file(self):
+-        self.dm.pushFile(self.tempLocalFile, self.tempRemoteFile)
+-        self.assertTrue(self.dm.fileExists(self.tempRemoteFile))
+-        self.assertFalse(os.path.exists("pulled.txt"))
+-        self.dm.getFile(self.tempRemoteFile, "pulled.txt")
+-        self.assertTrue(os.path.exists("pulled.txt"))
+-        os.remove("pulled.txt")
+-
+-    def test_push_and_pull_directory_and_list_files(self):
+-        self.dm.removeDir(self.tempRemoteDir)
+-        self.assertFalse(self.dm.dirExists(self.tempRemoteDir))
+-        self.dm.pushDir(self.tempLocalDir, self.tempRemoteDir)
+-        self.assertTrue(self.dm.dirExists(self.tempRemoteDir))
+-        response = self.dm.listFiles(self.tempRemoteDir)
+-        # The local dir that was pushed contains the tempLocalFile
+-        self.assertIn(os.path.basename(self.tempLocalFile), response)
+-        # Create a temp dir to pull to
+-        temp_dir = tempfile.mkdtemp()
+-        self.assertTrue(os.path.exists(temp_dir))
+-        self.dm.getDirectory(self.tempRemoteDir, temp_dir)
+-        self.assertTrue(os.path.exists(self.tempLocalFile))
+-
+-    def test_move_and_remove_directories(self):
+-        dir1 = os.path.join(self.tempRemoteDir, "dir1")
+-        dir2 = os.path.join(self.tempRemoteDir, "dir2")
+-
+-        self.assertFalse(self.dm.dirExists(dir1))
+-        self.dm.mkDir(dir1)
+-        self.assertTrue(self.dm.dirExists(dir1))
+-
+-        self.assertFalse(self.dm.dirExists(dir2))
+-        self.dm.moveTree(dir1, dir2)
+-        self.assertTrue(self.dm.dirExists(dir2))
+-
+-        self.dm.removeDir(dir1)
+-        self.dm.removeDir(dir2)
+-        self.assertFalse(self.dm.dirExists(dir1))
+-        self.assertFalse(self.dm.dirExists(dir2))
+-
+-    def test_push_and_remove_system_file(self):
+-        out = StringIO()
+-        self.assertTrue(find_mount_permissions(self.dm, "/system") == "ro")
+-        self.assertFalse(self.dm.fileExists(self.tempRemoteSystemFile))
+-        self.assertRaises(DMError, self.dm.pushFile, self.tempLocalFile, self.tempRemoteSystemFile)
+-        self.dm.shell(['mount', '-w', '-o', 'remount', '/system'], out)
+-        self.assertTrue(find_mount_permissions(self.dm, "/system") == "rw")
+-        self.assertFalse(self.dm.fileExists(self.tempRemoteSystemFile))
+-        self.dm.pushFile(self.tempLocalFile, self.tempRemoteSystemFile)
+-        self.assertTrue(self.dm.fileExists(self.tempRemoteSystemFile))
+-        self.dm.removeFile(self.tempRemoteSystemFile)
+-        self.assertFalse(self.dm.fileExists(self.tempRemoteSystemFile))
+-        self.dm.shell(['mount', '-r', '-o', 'remount', '/system'], out)
+-        out.close()
+-        self.assertTrue(find_mount_permissions(self.dm, "/system") == "ro")
+-
+-
+-class TestOther(DeviceManagerADBTestCase):
+-
+-    def test_get_list_of_processes(self):
+-        self.assertEquals(type(self.dm.getProcessList()), list)
+-
+-    def test_get_current_time(self):
+-        self.assertEquals(type(self.dm.getCurrentTime()), int)
+-
+-    def test_get_info(self):
+-        self.assertEquals(type(self.dm.getInfo()), dict)
+-
+-    def test_list_devices(self):
+-        self.assertEquals(len(list(self.dm.devices())), 1)
+-
+-    def test_shell(self):
+-        out = StringIO()
+-        self.dm.shell(["echo", "$COMPANY", ";", "pwd"], out,
+-                      env={"COMPANY": "Mozilla"}, cwd="/", timeout=4, root=True)
+-        output = str(out.getvalue()).rstrip().splitlines()
+-        out.close()
+-        self.assertEquals(output, ['Mozilla', '/'])
+-
+-    def test_port_forwarding(self):
+-        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+-        s.bind(("", 0))
+-        port = s.getsockname()[1]
+-        s.close()
+-        # If successful then no exception is raised
+-        self.dm.forward("tcp:%s" % port, "tcp:2828")
+-
+-    def test_port_forwarding_error(self):
+-        self.assertRaises(DMError, self.dm.forward, "", "")
+-
+-
+-if __name__ == '__main__':
+-    dm = DeviceManagerADB()
+-    if not dm.devices():
+-        print("There are no connected adb devices")
+-        sys.exit(1)
+-
+-    if find_mount_permissions(dm, "/system") == "rw":
+-        print("We've found out that /system is mounted as 'rw'. This is because the command "
+-              "'adb remount' has been run before running this test case. Please reboot the "
+-              "device and try again.")
+-        sys.exit(1)
+-
+-    unittest.main()
+diff --git a/testing/mozbase/mozdevice/mozdevice/__init__.py b/testing/mozbase/mozdevice/mozdevice/__init__.py
+--- a/testing/mozbase/mozdevice/mozdevice/__init__.py
++++ b/testing/mozbase/mozdevice/mozdevice/__init__.py
+@@ -3,15 +3,11 @@
+ # You can obtain one at http://mozilla.org/MPL/2.0/.
+ 
+ from __future__ import absolute_import
+ 
+ from .adb import ADBError, ADBProcessError, ADBRootError, ADBTimeoutError
+ from .adb import ADBProcess, ADBCommand, ADBHost, ADBDevice
+ from .adb_android import ADBAndroid
+ from .adb_b2g import ADBB2G
+-from .devicemanager import DeviceManager, DMError
+-from .devicemanagerADB import DeviceManagerADB
+-from .droid import DroidADB
+ 
+ __all__ = ['ADBError', 'ADBProcessError', 'ADBRootError', 'ADBTimeoutError',
+-           'ADBProcess', 'ADBCommand', 'ADBHost', 'ADBDevice', 'ADBAndroid', 'ADBB2G',
+-           'DeviceManager', 'DMError', 'DeviceManagerADB', 'DroidADB']
++           'ADBProcess', 'ADBCommand', 'ADBHost', 'ADBDevice', 'ADBAndroid', 'ADBB2G']
+diff --git a/testing/mozbase/mozdevice/mozdevice/devicemanager.py b/testing/mozbase/mozdevice/mozdevice/devicemanager.py
+deleted file mode 100644
+--- a/testing/mozbase/mozdevice/mozdevice/devicemanager.py
++++ /dev/null
+@@ -1,638 +0,0 @@
+-# This Source Code Form is subject to the terms of the Mozilla Public
+-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+-# You can obtain one at http://mozilla.org/MPL/2.0/.
+-
+-from __future__ import absolute_import
+-
+-import hashlib
+-import mozlog
+-import logging
+-import os
+-import posixpath
+-import re
+-import struct
+-import StringIO
+-import zlib
+-
+-from functools import wraps
+-
+-
+-class DMError(Exception):
+-    "generic devicemanager exception."
+-
+-    def __init__(self, msg='', fatal=False):
+-        self.msg = msg
+-        self.fatal = fatal
+-
+-    def __str__(self):
+-        return self.msg
+-
+-
+-def abstractmethod(method):
+-    line = method.func_code.co_firstlineno
+-    filename = method.func_code.co_filename
+-
+-    @wraps(method)
+-    def not_implemented(*args, **kwargs):
+-        raise NotImplementedError('Abstract method %s at File "%s", line %s '
+-                                  'should be implemented by a concrete class' %
+-                                  (repr(method), filename, line))
+-    return not_implemented
+-
+-
+-class DeviceManager(object):
+-    """
+-    Represents a connection to a device. Once an implementation of this class
+-    is successfully instantiated, you may do things like list/copy files to
+-    the device, launch processes on the device, and install or remove
+-    applications from the device.
+-
+-    Never instantiate this class directly! Instead, instantiate an
+-    implementation of it like DeviceManagerADB. New projects should strongly
+-    consider using adb.py as an alternative.
+-    """
+-
+-    _logcatNeedsRoot = True
+-    default_timeout = 300
+-    short_timeout = 30
+-
+-    def __init__(self, logLevel=None, deviceRoot=None):
+-        try:
+-            self._logger = mozlog.get_default_logger(component="mozdevice")
+-            if not self._logger:  # no global structured logger, fall back to reg logging
+-                self._logger = mozlog.unstructured.getLogger("mozdevice")
+-                if logLevel is not None:
+-                    self._logger.setLevel(logLevel)
+-        except AttributeError:
+-            # Structured logging doesn't work on Python 2.6
+-            self._logger = None
+-        self._logLevel = logLevel
+-        self._remoteIsWin = None
+-        self._isDeviceRootSetup = False
+-        self._deviceRoot = deviceRoot
+-
+-    def _log(self, data):
+-        """
+-        This helper function is called by ProcessHandler to log
+-        the output produced by processes
+-        """
+-        self._logger.debug(data)
+-
+-    @property
+-    def remoteIsWin(self):
+-        if self._remoteIsWin is None:
+-            self._remoteIsWin = self.getInfo("os")["os"][0] == "windows"
+-        return self._remoteIsWin
+-
+-    @property
+-    def logLevel(self):
+-        return self._logLevel
+-
+-    @logLevel.setter
+-    def logLevel_setter(self, newLogLevel):
+-        self._logLevel = newLogLevel
+-        self._logger.setLevel(self._logLevel)
+-
+-    @property
+-    def debug(self):
+-        self._logger.warning("dm.debug is deprecated. Use logLevel.")
+-        levels = {logging.DEBUG: 5, logging.INFO: 3, logging.WARNING: 2,
+-                  logging.ERROR: 1, logging.CRITICAL: 0}
+-        return levels[self.logLevel]
+-
+-    @debug.setter
+-    def debug_setter(self, newDebug):
+-        self._logger.warning("dm.debug is deprecated. Use logLevel.")
+-        newDebug = 5 if newDebug > 5 else newDebug  # truncate >=5 to 5
+-        levels = {5: logging.DEBUG, 3: logging.INFO, 2: logging.WARNING,
+-                  1: logging.ERROR, 0: logging.CRITICAL}
+-        self.logLevel = levels[newDebug]
+-
+-    @abstractmethod
+-    def getInfo(self, directive=None):
+-        """
+-        Returns a dictionary of information strings about the device.
+-
+-        :param directive: information you want to get. Options are:
+-
+-          - `os` - name of the os
+-          - `id` - unique id of the device
+-          - `uptime` - uptime of the device
+-          - `uptimemillis` - uptime of the device in milliseconds
+-            (NOT supported on all implementations)
+-          - `systime` - system time of the device
+-          - `screen` - screen resolution
+-          - `memory` - memory stats
+-          - `memtotal` - total memory available on the device, for example 927208 kB
+-          - `process` - list of running processes (same as ps)
+-          - `disk` - total, free, available bytes on disk
+-          - `power` - power status (charge, battery temp)
+-          - `temperature` - device temperature
+-
+-         If `directive` is `None`, will return all available information
+-        """
+-
+-    @abstractmethod
+-    def getCurrentTime(self):
+-        """
+-        Returns device time in milliseconds since the epoch.
+-        """
+-
+-    def getIP(self, interfaces=['eth0', 'wlan0']):
+-        """
+-        Returns the IP of the device, or None if no connection exists.
+-        """
+-        for interface in interfaces:
+-            match = re.match(r"%s: ip (\S+)" % interface,
+-                             self.shellCheckOutput(['ifconfig', interface],
+-                                                   timeout=self.short_timeout))
+-            if match:
+-                return match.group(1)
+-
+-    def recordLogcat(self):
+-        """
+-        Clears the logcat file making it easier to view specific events.
+-        """
+-        # TODO: spawn this off in a separate thread/process so we can collect all
+-        # the logcat information
+-
+-        # Right now this is just clearing the logcat so we can only see what
+-        # happens after this call.
+-        self.shellCheckOutput(['/system/bin/logcat', '-c'], root=self._logcatNeedsRoot,
+-                              timeout=self.short_timeout)
+-
+-    def getLogcat(self, filterSpecs=["dalvikvm:I", "ConnectivityService:S",
+-                                     "WifiMonitor:S", "WifiStateTracker:S",
+-                                     "wpa_supplicant:S", "NetworkStateTracker:S"],
+-                  format="time",
+-                  filterOutRegexps=[]):
+-        """
+-        Returns the contents of the logcat file as a list of
+-        '\n' terminated strings
+-        """
+-        cmdline = ["/system/bin/logcat", "-v", format, "-d"] + filterSpecs
+-        output = self.shellCheckOutput(cmdline,
+-                                       root=self._logcatNeedsRoot,
+-                                       timeout=self.short_timeout)
+-        lines = output.replace('\r\n', '\n').splitlines(True)
+-
+-        for regex in filterOutRegexps:
+-            lines = [line for line in lines if not re.search(regex, line)]
+-
+-        return lines
+-
+-    def saveScreenshot(self, filename):
+-        """
+-        Takes a screenshot of what's being display on the device. Uses
+-        "screencap" on newer (Android 3.0+) devices (and some older ones with
+-        the functionality backported). This function also works on B2G.
+-
+-        Throws an exception on failure. This will always fail on devices
+-        without the screencap utility.
+-        """
+-        screencap = '/system/bin/screencap'
+-        if not self.fileExists(screencap):
+-            raise DMError("Unable to capture screenshot on device: no screencap utility")
+-
+-        with open(filename, 'w') as pngfile:
+-            # newer versions of screencap can write directly to a png, but some
+-            # older versions can't
+-            tempScreenshotFile = self.deviceRoot + "/ss-dm.tmp"
+-            self.shellCheckOutput(["sh", "-c", "%s > %s" %
+-                                   (screencap, tempScreenshotFile)],
+-                                  root=True)
+-            buf = self.pullFile(tempScreenshotFile)
+-            width = int(struct.unpack("I", buf[0:4])[0])
+-            height = int(struct.unpack("I", buf[4:8])[0])
+-            with open(filename, 'w') as pngfile:
+-                pngfile.write(self._writePNG(buf[12:], width, height))
+-            self.removeFile(tempScreenshotFile)
+-
+-    @abstractmethod
+-    def pushFile(self, localFilename, remoteFilename, retryLimit=1, createDir=True):
+-        """
+-        Copies localname from the host to destname on the device.
+-        """
+-
+-    @abstractmethod
+-    def pushDir(self, localDirname, remoteDirname, retryLimit=1, timeout=None):
+-        """
+-        Push local directory from host to remote directory on the device,
+-        """
+-
+-    @abstractmethod
+-    def pullFile(self, remoteFilename, offset=None, length=None):
+-        """
+-        Returns contents of remoteFile using the "pull" command.
+-
+-        :param remoteFilename: Path to file to pull from remote device.
+-        :param offset: Offset in bytes from which to begin reading (optional)
+-        :param length: Number of bytes to read (optional)
+-        """
+-
+-    @abstractmethod
+-    def getFile(self, remoteFilename, localFilename):
+-        """
+-        Copy file from remote device to local file on host.
+-        """
+-
+-    @abstractmethod
+-    def getDirectory(self, remoteDirname, localDirname, checkDir=True):
+-        """
+-        Copy directory structure from device (remoteDirname) to host (localDirname).
+-        """
+-
+-    @abstractmethod
+-    def validateFile(self, remoteFilename, localFilename):
+-        """
+-        Returns True if a file on the remote device has the same md5 hash as a local one.
+-        """
+-
+-    def validateDir(self, localDirname, remoteDirname):
+-        """
+-        Returns True if remoteDirname on device is same as localDirname on host.
+-        """
+-
+-        self._logger.info("validating directory: %s to %s" % (localDirname, remoteDirname))
+-        for root, dirs, files in os.walk(localDirname):
+-            parts = root.split(localDirname)
+-            for f in files:
+-                remoteRoot = remoteDirname + '/' + parts[1]
+-                remoteRoot = remoteRoot.replace('/', '/')
+-                if (parts[1] == ""):
+-                    remoteRoot = remoteDirname
+-                remoteName = remoteRoot + '/' + f
+-                if (self.validateFile(remoteName, os.path.join(root, f)) is not True):
+-                    return False
+-        return True
+-
+-    @abstractmethod
+-    def mkDir(self, remoteDirname):
+-        """
+-        Creates a single directory on the device file system.
+-        """
+-
+-    def mkDirs(self, filename):
+-        """
+-        Make directory structure on the device.
+-
+-        WARNING: does not create last part of the path. For example, if asked to
+-        create `/mnt/sdcard/foo/bar/baz`, it will only create `/mnt/sdcard/foo/bar`
+-        """
+-        filename = posixpath.normpath(filename)
+-        containing = posixpath.dirname(filename)
+-        if not self.dirExists(containing):
+-            parts = filename.split('/')
+-            name = "/" if not self.remoteIsWin else parts.pop(0)
+-            for part in parts[:-1]:
+-                if part != "":
+-                    name = posixpath.join(name, part)
+-                    self.mkDir(name)  # mkDir will check previous existence
+-
+-    @abstractmethod
+-    def dirExists(self, dirpath):
+-        """
+-        Returns whether dirpath exists and is a directory on the device file system.
+-        """
+-
+-    @abstractmethod
+-    def fileExists(self, filepath):
+-        """
+-        Return whether filepath exists on the device file system,
+-        regardless of file type.
+-        """
+-
+-    @abstractmethod
+-    def listFiles(self, rootdir):
+-        """
+-        Lists files on the device rootdir.
+-
+-        Returns array of filenames, ['file1', 'file2', ...]
+-        """
+-
+-    @abstractmethod
+-    def removeFile(self, filename):
+-        """
+-        Removes filename from the device.
+-        """
+-
+-    @abstractmethod
+-    def removeDir(self, remoteDirname):
+-        """
+-        Does a recursive delete of directory on the device: rm -Rf remoteDirname.
+-        """
+-
+-    @abstractmethod
+-    def moveTree(self, source, destination):
+-        """
+-        Does a move of the file or directory on the device.
+-
+-       :param source: Path to the original file or directory
+-       :param destination: Path to the destination file or directory
+-        """
+-
+-    @abstractmethod
+-    def copyTree(self, source, destination):
+-        """
+-        Does a copy of the file or directory on the device.
+-
+-       :param source: Path to the original file or directory
+-       :param destination: Path to the destination file or directory
+-        """
+-
+-    @abstractmethod
+-    def chmodDir(self, remoteDirname, mask="777"):
+-        """
+-        Recursively changes file permissions in a directory.
+-        """
+-
+-    @property
+-    def deviceRoot(self):
+-        """
+-        The device root on the device filesystem for putting temporary
+-        testing files.
+-        """
+-        # derive deviceroot value if not set
+-        if not self._deviceRoot or not self._isDeviceRootSetup:
+-            self._deviceRoot = self._setupDeviceRoot(self._deviceRoot)
+-            self._isDeviceRootSetup = True
+-
+-        return self._deviceRoot
+-
+-    @abstractmethod
+-    def _setupDeviceRoot(self):
+-        """
+-        Sets up and returns a device root location that can be written to by tests.
+-        """
+-
+-    def getDeviceRoot(self):
+-        """
+-        Get the device root on the device filesystem for putting temporary
+-        testing files.
+-
+-        .. deprecated:: 0.38
+-          Use the :py:attr:`deviceRoot` property instead.
+-        """
+-        return self.deviceRoot
+-
+-    @abstractmethod
+-    def getTempDir(self):
+-        """
+-        Returns a temporary directory we can use on this device, ensuring
+-        also that it exists.
+-        """
+-
+-    @abstractmethod
+-    def shell(self, cmd, outputfile, env=None, cwd=None, timeout=None, root=False):
+-        """
+-        Executes shell command on device and returns exit code.
+-
+-        :param cmd: Commandline list to execute
+-        :param outputfile: File to store output
+-        :param env: Environment to pass to exec command
+-        :param cwd: Directory to execute command from
+-        :param timeout: specified in seconds, defaults to 'default_timeout'
+-        :param root: Specifies whether command requires root privileges
+-        """
+-
+-    def shellCheckOutput(self, cmd, env=None, cwd=None, timeout=None, root=False):
+-        """
+-        Executes shell command on device and returns output as a string. Raises if
+-        the return code is non-zero.
+-
+-        :param cmd: Commandline list to execute
+-        :param env: Environment to pass to exec command
+-        :param cwd: Directory to execute command from
+-        :param timeout: specified in seconds, defaults to 'default_timeout'
+-        :param root: Specifies whether command requires root privileges
+-        :raises: DMError
+-        """
+-        buf = StringIO.StringIO()
+-        retval = self.shell(cmd, buf, env=env, cwd=cwd, timeout=timeout, root=root)
+-        output = str(buf.getvalue()[0:-1]).rstrip()
+-        buf.close()
+-        if retval != 0:
+-            raise DMError(
+-                "Non-zero return code for command: %s "
+-                "(output: '%s', retval: '%s')" % (cmd, output, retval))
+-        return output
+-
+-    @abstractmethod
+-    def getProcessList(self):
+-        """
+-        Returns array of tuples representing running processes on the device.
+-
+-        Format of tuples is (processId, processName, userId)
+-        """
+-
+-    def processInfo(self, processName):
+-        """
+-        Returns information on the process with processName.
+-        Information on process is in tuple format: (pid, process path, user)
+-        If a process with the specified name does not exist this function will return None.
+-        """
+-        if not isinstance(processName, basestring):
+-            raise TypeError("Process name %s is not a string" % processName)
+-
+-        processInfo = None
+-
+-        # filter out extra spaces
+-        parts = filter(lambda x: x != '', processName.split(' '))
+-        processName = ' '.join(parts)
+-
+-        # filter out the quoted env string if it exists
+-        # ex: '"name=value;name2=value2;etc=..." process args' -> 'process args'
+-        parts = processName.split('"')
+-        if (len(parts) > 2):
+-            processName = ' '.join(parts[2:]).strip()
+-
+-        pieces = processName.split(' ')
+-        parts = pieces[0].split('/')
+-        app = parts[-1]
+-
+-        procList = self.getProcessList()
+-        if (procList == []):
+-            return None
+-
+-        for proc in procList:
+-            procName = proc[1].split('/')[-1]
+-            if (procName == app):
+-                processInfo = proc
+-                break
+-        return processInfo
+-
+-    def processExist(self, processName):
+-        """
+-        Returns True if process with name processName is running on device.
+-        """
+-        processInfo = self.processInfo(processName)
+-        if processInfo:
+-            return processInfo[0]
+-
+-    @abstractmethod
+-    def killProcess(self, processName, sig=None):
+-        """
+-        Kills the process named processName. If sig is not None, process is
+-        killed with the specified signal.
+-
+-        :param processName: path or name of the process to kill
+-        :param sig: signal to pass into the kill command (optional)
+-        """
+-
+-    @abstractmethod
+-    def reboot(self, wait=False, ipAddr=None):
+-        """
+-        Reboots the device.
+-
+-        :param wait: block on device to come back up before returning
+-        :param ipAddr: deprecated; do not use
+-        """
+-
+-    @abstractmethod
+-    def installApp(self, appBundlePath, destPath=None):
+-        """
+-        Installs an application onto the device.
+-
+-        :param appBundlePath: path to the application bundle on the device
+-        :param destPath: destination directory of where application should be
+-                         installed to (optional)
+-        """
+-
+-    @abstractmethod
+-    def uninstallApp(self, appName, installPath=None):
+-        """
+-        Uninstalls the named application from device and DOES NOT cause a reboot.
+-
+-        :param appName: the name of the application (e.g org.mozilla.fennec)
+-        :param installPath: the path to where the application was installed (optional)
+-        """
+-
+-    @abstractmethod
+-    def uninstallAppAndReboot(self, appName, installPath=None):
+-        """
+-        Uninstalls the named application from device and causes a reboot.
+-
+-        :param appName: the name of the application (e.g org.mozilla.fennec)
+-        :param installPath: the path to where the application was installed (optional)
+-        """
+-
+-    @abstractmethod
+-    def updateApp(self, appBundlePath, processName=None, destPath=None,
+-                  wait=False, ipAddr=None):
+-        """
+-        Updates the application on the device and reboots.
+-
+-        :param appBundlePath: path to the application bundle on the device
+-        :param processName: used to end the process if the applicaiton is
+-                            currently running (optional)
+-        :param destPath: Destination directory to where the application should
+-                         be installed (optional)
+-        :param wait: block on device to come back up before returning
+-        :param ipAddr: deprecated; do not use
+-        """
+-
+-    @staticmethod
+-    def _writePNG(buf, width, height):
+-        """
+-        Method for writing a PNG from a buffer, used by getScreenshot on older devices,
+-        """
+-        # Based on: http://code.activestate.com/recipes/577443-write-a-png-image-in-native-python/
+-        width_byte_4 = width * 4
+-        raw_data = b"".join(b'\x00' + buf[span:span + width_byte_4]
+-                            for span in range(0, (height - 1) * width * 4, width_byte_4))
+-
+-        def png_pack(png_tag, data):
+-            chunk_head = png_tag + data
+-            return struct.pack("!I", len(data)) \
+-                + chunk_head \
+-                + struct.pack("!I", 0xFFFFFFFF & zlib.crc32(chunk_head))
+-        return b"".join([
+-            b'\x89PNG\r\n\x1a\n',
+-            png_pack(b'IHDR', struct.pack("!2I5B", width, height, 8, 6, 0, 0, 0)),
+-            png_pack(b'IDAT', zlib.compress(raw_data, 9)),
+-            png_pack(b'IEND', b'')])
+-
+-    @abstractmethod
+-    def _getRemoteHash(self, filename):
+-        """
+-        Return the md5 sum of a file on the device.
+-        """
+-
+-    @staticmethod
+-    def _getLocalHash(filename):
+-        """
+-        Return the MD5 sum of a file on the host.
+-        """
+-        f = open(filename, 'rb')
+-        if f is None:
+-            return None
+-
+-        try:
+-            mdsum = hashlib.md5()
+-        except Exception:
+-            return None
+-
+-        while 1:
+-            data = f.read(1024)
+-            if not data:
+-                break
+-            mdsum.update(data)
+-
+-        f.close()
+-        hexval = mdsum.hexdigest()
+-        return hexval
+-
+-    @staticmethod
+-    def _escapedCommandLine(cmd):
+-        """
+-        Utility function to return escaped and quoted version of command line.
+-        """
+-        quotedCmd = []
+-
+-        for arg in cmd:
+-            arg.replace('&', '\&')
+-
+-            needsQuoting = False
+-            for char in [' ', '(', ')', '"', '&']:
+-                if arg.find(char) >= 0:
+-                    needsQuoting = True
+-                    break
+-            if needsQuoting:
+-                arg = '\'%s\'' % arg
+-
+-            quotedCmd.append(arg)
+-
+-        return " ".join(quotedCmd)
+-
+-
+-def _pop_last_line(file_obj):
+-    """
+-    Utility function to get the last line from a file. Function also removes
+-    it from the file. Intended to strip off the return code from a shell
+-    command.
+-    """
+-    bytes_from_end = 1
+-    file_obj.seek(0, 2)
+-    length = file_obj.tell() + 1
+-    while bytes_from_end < length:
+-        file_obj.seek((-1) * bytes_from_end, 2)
+-        data = file_obj.read()
+-
+-        if bytes_from_end == length - 1 and len(data) == 0:  # no data, return None
+-            return None
+-
+-        if data[0] == '\n' or bytes_from_end == length - 1:
+-            # found the last line, which should have the return value
+-            if data[0] == '\n':
+-                data = data[1:]
+-
+-            # truncate off the return code line
+-            file_obj.truncate(length - bytes_from_end)
+-            file_obj.seek(0, 2)
+-            file_obj.write('\0')
+-
+-            return data
+-
+-        bytes_from_end += 1
+-
+-    return None
+diff --git a/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py b/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py
+deleted file mode 100644
+--- a/testing/mozbase/mozdevice/mozdevice/devicemanagerADB.py
++++ /dev/null
+@@ -1,886 +0,0 @@
+-# This Source Code Form is subject to the terms of the Mozilla Public
+-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+-# You can obtain one at http://mozilla.org/MPL/2.0/.
+-
+-from __future__ import absolute_import
+-
+-import logging
+-import re
+-import os
+-import tempfile
+-import time
+-import traceback
+-
+-from distutils import dir_util
+-
+-from .devicemanager import DeviceManager, DMError
+-from mozprocess import ProcessHandler
+-import mozfile
+-from . import version_codes
+-
+-
+-class DeviceManagerADB(DeviceManager):
+-    """
+-    Implementation of DeviceManager interface that uses the Android "adb"
+-    utility to communicate with the device. Normally used to communicate
+-    with a device that is directly connected with the host machine over a USB
+-    port.
+-    """
+-
+-    _haveRootShell = None
+-    _haveSu = None
+-    _suModifier = None
+-    _lsModifier = None
+-    _useZip = False
+-    _logcatNeedsRoot = False
+-    _pollingInterval = 0.01
+-    _packageName = None
+-    _tempDir = None
+-    _adb_version = None
+-    _sdk_version = None
+-    connected = False
+-
+-    def __init__(self, host=None, port=5555, retryLimit=5, packageName='fennec',
+-                 adbPath=None, deviceSerial=None, deviceRoot=None,
+-                 logLevel=logging.ERROR, autoconnect=True, runAdbAsRoot=False,
+-                 serverHost=None, serverPort=None, **kwargs):
+-        DeviceManager.__init__(self, logLevel=logLevel,
+-                               deviceRoot=deviceRoot)
+-        self.host = host
+-        self.port = port
+-        self.retryLimit = retryLimit
+-
+-        self._serverHost = serverHost
+-        self._serverPort = serverPort
+-
+-        # the path to adb, or 'adb' to assume that it's on the PATH
+-        self._adbPath = adbPath or 'adb'
+-
+-        # The serial number of the device to use with adb, used in cases
+-        # where multiple devices are being managed by the same adb instance.
+-        self._deviceSerial = deviceSerial
+-
+-        # Some devices do no start adb as root, if allowed you can use
+-        # this to reboot adbd on the device as root automatically
+-        self._runAdbAsRoot = runAdbAsRoot
+-
+-        if packageName == 'fennec':
+-            if os.getenv('USER'):
+-                self._packageName = 'org.mozilla.fennec_' + os.getenv('USER')
+-            else:
+-                self._packageName = 'org.mozilla.fennec_'
+-        elif packageName:
+-            self._packageName = packageName
+-
+-        # verify that we can run the adb command. can't continue otherwise
+-        self._verifyADB()
+-
+-        if autoconnect:
+-            self.connect()
+-
+-    def connect(self):
+-        if not self.connected:
+-            # try to connect to the device over tcp/ip if we have a hostname
+-            if self.host:
+-                self._connectRemoteADB()
+-
+-            # verify that we can connect to the device. can't continue
+-            self._verifyDevice()
+-
+-            # Note SDK version
+-            try:
+-                proc = self._runCmd(["shell", "getprop", "ro.build.version.sdk"],
+-                                    timeout=self.short_timeout)
+-                self._sdk_version = int(proc.output[0])
+-            except (OSError, ValueError):
+-                self._sdk_version = 0
+-            self._logger.info("Detected Android sdk %d" % self._sdk_version)
+-
+-            # Some commands require root to work properly, even with ADB (e.g.
+-            # grabbing APKs out of /data). For these cases, we check whether
+-            # we're running as root. If that isn't true, check for the
+-            # existence of an su binary
+-            self._checkForRoot()
+-
+-            # can we use zip to speed up some file operations? (currently not
+-            # required)
+-            try:
+-                self._verifyZip()
+-            except DMError:
+-                pass
+-
+-    def __del__(self):
+-        if self.host:
+-            self._disconnectRemoteADB()
+-
+-    def shell(self, cmd, outputfile, env=None, cwd=None, timeout=None, root=False):
+-        # FIXME: this function buffers all output of the command into memory,
+-        # always. :(
+-
+-        # If requested to run as root, check that we can actually do that
+-        if root:
+-            if self._haveRootShell is None and self._haveSu is None:
+-                self._checkForRoot()
+-            if not self._haveRootShell and not self._haveSu:
+-                raise DMError(
+-                    "Shell command '%s' requested to run as root but root "
+-                    "is not available on this device. Root your device or "
+-                    "refactor the test/harness to not require root." %
+-                    self._escapedCommandLine(cmd))
+-
+-        # Getting the return code is more complex than you'd think because adb
+-        # doesn't actually return the return code from a process, so we have to
+-        # capture the output to get it
+-        if root and self._haveSu:
+-            cmdline = "su %s \"%s\"" % (self._suModifier,
+-                                        self._escapedCommandLine(cmd))
+-        else:
+-            cmdline = self._escapedCommandLine(cmd)
+-        cmdline += "; echo $?"
+-
+-        # prepend cwd and env to command if necessary
+-        if cwd:
+-            cmdline = "cd %s; %s" % (cwd, cmdline)
+-        if env:
+-            envstr = '; '.join(map(lambda x: 'export %s=%s' % (x[0], x[1]), env.iteritems()))
+-            cmdline = envstr + "; " + cmdline
+-
+-        # all output should be in stdout
+-        args = [self._adbPath]
+-        if self._serverHost is not None:
+-            args.extend(['-H', self._serverHost])
+-        if self._serverPort is not None:
+-            args.extend(['-P', str(self._serverPort)])
+-        if self._deviceSerial:
+-            args.extend(['-s', self._deviceSerial])
+-        args.extend(["shell", cmdline])
+-
+-        def _timeout():
+-            self._logger.error("Timeout exceeded for shell call '%s'" % ' '.join(args))
+-
+-        self._logger.debug("shell - command: %s" % ' '.join(args))
+-        proc = ProcessHandler(args, processOutputLine=self._log, onTimeout=_timeout)
+-
+-        if not timeout:
+-            # We are asserting that all commands will complete in this time unless
+-            # otherwise specified
+-            timeout = self.default_timeout
+-
+-        timeout = int(timeout)
+-        proc.run(timeout)
+-        proc.wait()
+-        output = proc.output
+-
+-        if output:
+-            lastline = output[-1]
+-            if lastline:
+-                m = re.search('([0-9]+)', lastline)
+-                if m:
+-                    return_code = m.group(1)
+-                    for line in output:
+-                        outputfile.write(line + '\n')
+-                    outputfile.seek(-2, 2)
+-                    outputfile.truncate()  # truncate off the return code
+-                    return int(return_code)
+-
+-        return None
+-
+-    def forward(self, local, remote):
+-        """
+-        Forward socket connections.
+-
+-        Forward specs are one of:
+-          tcp:<port>
+-          localabstract:<unix domain socket name>
+-          localreserved:<unix domain socket name>
+-          localfilesystem:<unix domain socket name>
+-          dev:<character device name>
+-          jdwp:<process pid> (remote only)
+-        """
+-        if not self._checkCmd(['forward', local, remote], timeout=self.short_timeout) == 0:
+-            raise DMError("Failed to forward socket connection.")
+-
+-    def remove_forward(self, local=None):
+-        """
+-        Turn off forwarding of socket connection.
+-        """
+-        cmd = ['forward']
+-        if local is None:
+-            cmd.extend(['--remove-all'])
+-        else:
+-            cmd.extend(['--remove', local])
+-        if not self._checkCmd(cmd, timeout=self.short_timeout) == 0:
+-            raise DMError("Failed to remove connection forwarding.")
+-
+-    def remount(self):
+-        "Remounts the /system partition on the device read-write."
+-        return self._checkCmd(['remount'], timeout=self.short_timeout)
+-
+-    def devices(self):
+-        "Return a list of connected devices as (serial, status) tuples."
+-        proc = self._runCmd(['devices'])
+-        proc.output.pop(0)  # ignore first line of output
+-        devices = []
+-        for line in proc.output:
+-            result = re.match('(.*?)\t(.*)', line)
+-            if result:
+-                devices.append((result.group(1), result.group(2)))
+-        return devices
+-
+-    def _connectRemoteADB(self):
+-        self._checkCmd(["connect", self.host + ":" + str(self.port)])
+-
+-    def _disconnectRemoteADB(self):
+-        self._checkCmd(["disconnect", self.host + ":" + str(self.port)])
+-
+-    def pushFile(self, localname, destname, retryLimit=None, createDir=True):
+-        # you might expect us to put the file *in* the directory in this case,
+-        # but that would be inconsistent with historical behavior.
+-        retryLimit = retryLimit or self.retryLimit
+-        if self.dirExists(destname):
+-            raise DMError("Attempted to push a file (%s) to a directory (%s)!" %
+-                          (localname, destname))
+-        if not os.access(localname, os.F_OK):
+-            raise DMError("File not found: %s" % localname)
+-
+-        proc = self._runCmd(["push", os.path.realpath(localname), destname],
+-                            retryLimit=retryLimit)
+-        if proc.returncode != 0:
+-            raise DMError("Error pushing file %s -> %s; output: %s" %
+-                          (localname, destname, proc.output))
+-
+-    def mkDir(self, name):
+-        result = self._runCmd(["shell", "mkdir", name], timeout=self.short_timeout).output
+-        if len(result) and 'read-only file system' in result[0].lower():
+-            raise DMError("Error creating directory: read only file system")
+-
+-    def pushDir(self, localDir, remoteDir, retryLimit=None, timeout=None):
+-        # adb "push" accepts a directory as an argument, but if the directory
+-        # contains symbolic links, the links are pushed, rather than the linked
+-        # files; we either zip/unzip or re-copy the directory into a temporary
+-        # one to get around this limitation
+-        retryLimit = retryLimit or self.retryLimit
+-        if self._useZip:
+-            self.removeDir(remoteDir)
+-            self.mkDirs(remoteDir + "/x")
+-            try:
+-                localZip = tempfile.mktemp() + ".zip"
+-                remoteZip = remoteDir + "/adbdmtmp.zip"
+-                proc = ProcessHandler(["zip", "-r", localZip, '.'], cwd=localDir,
+-                                      processOutputLine=self._log)
+-                proc.run()
+-                proc.wait()
+-                self.pushFile(localZip, remoteZip, retryLimit=retryLimit, createDir=False)
+-                mozfile.remove(localZip)
+-                data = self._runCmd(["shell", "unzip", "-o", remoteZip,
+-                                     "-d", remoteDir]).output[0]
+-                self._checkCmd(["shell", "rm", remoteZip],
+-                               retryLimit=retryLimit, timeout=self.short_timeout)
+-                if re.search("unzip: exiting", data) or re.search("Operation not permitted", data):
+-                    raise Exception("unzip failed, or permissions error")
+-            except Exception:
+-                self._logger.warning(traceback.format_exc())
+-                self._logger.warning("zip/unzip failure: falling back to normal push")
+-                self._useZip = False
+-                self.pushDir(localDir, remoteDir, retryLimit=retryLimit, timeout=timeout)
+-        else:
+-            localDir = os.path.normpath(localDir)
+-            remoteDir = os.path.normpath(remoteDir)
+-            tempParent = tempfile.mkdtemp()
+-            remoteName = os.path.basename(remoteDir)
+-            newLocal = os.path.join(tempParent, remoteName)
+-            dir_util.copy_tree(localDir, newLocal)
+-            # See do_sync_push in
+-            # https://android.googlesource.com/platform/system/core/+/master/adb/file_sync_client.cpp
+-            # Work around change in behavior in adb 1.0.36 where if
+-            # the remote destination directory exists, adb push will
+-            # copy the source directory *into* the destination
+-            # directory otherwise it will copy the source directory
+-            # *onto* the destination directory.
+-            if self._adb_version >= '1.0.36':
+-                remoteDir = '/'.join(remoteDir.rstrip('/').split('/')[:-1])
+-            try:
+-                if self._checkCmd(["push", newLocal, remoteDir],
+-                                  retryLimit=retryLimit, timeout=timeout):
+-                    raise DMError("failed to push %s (copy of %s) to %s" %
+-                                  (newLocal, localDir, remoteDir))
+-            except BaseException:
+-                raise
+-            finally:
+-                mozfile.remove(tempParent)
+-
+-    def dirExists(self, remotePath):
+-        self._detectLsModifier()
+-        data = self._runCmd(["shell", "ls", self._lsModifier, remotePath + '/'],
+-                            timeout=self.short_timeout).output
+-
+-        if len(data) == 1:
+-            res = data[0]
+-            if "Not a directory" in res or "No such file or directory" in res:
+-                return False
+-        return True
+-
+-    def fileExists(self, filepath):
+-        self._detectLsModifier()
+-        data = self._runCmd(["shell", "ls", self._lsModifier, filepath],
+-                            timeout=self.short_timeout).output
+-        if len(data) == 1:
+-            foundpath = data[0].decode('utf-8').rstrip()
+-            if foundpath == filepath:
+-                return True
+-        return False
+-
+-    def removeFile(self, filename):
+-        if self.fileExists(filename):
+-            self._checkCmd(["shell", "rm", filename], timeout=self.short_timeout)
+-
+-    def removeDir(self, remoteDir):
+-        if self.dirExists(remoteDir):
+-            self._checkCmd(["shell", "rm", "-r", remoteDir], timeout=self.short_timeout)
+-        else:
+-            self.removeFile(remoteDir.strip())
+-
+-    def moveTree(self, source, destination):
+-        self._checkCmd(["shell", "mv", source, destination], timeout=self.short_timeout)
+-
+-    def copyTree(self, source, destination):
+-        self._checkCmd(["shell", "dd", "if=%s" % source, "of=%s" % destination])
+-
+-    def listFiles(self, rootdir):
+-        self._detectLsModifier()
+-        data = self._runCmd(["shell", "ls", self._lsModifier, rootdir],
+-                            timeout=self.short_timeout).output
+-        data[:] = [item.rstrip('\r\n') for item in data]
+-        if (len(data) == 1):
+-            if (data[0] == rootdir):
+-                return []
+-            if (data[0].find("No such file or directory") != -1):
+-                return []
+-            if (data[0].find("Not a directory") != -1):
+-                return []
+-            if (data[0].find("Permission denied") != -1):
+-                return []
+-            if (data[0].find("opendir failed") != -1):
+-                return []
+-            if (data[0].find("Device or resource busy") != -1):
+-                return []
+-        return data
+-
+-    def getProcessList(self):
+-        ret = []
+-        p = self._runCmd(["shell", "ps"], timeout=self.short_timeout)
+-        if not p or not p.output or len(p.output) < 1:
+-            return ret
+-        # first line is the headers
+-        p.output.pop(0)
+-        for proc in p.output:
+-            els = proc.split()
+-            # We need to figure out if this is "user pid name" or
+-            # "pid user vsz stat command"
+-            if els[1].isdigit():
+-                ret.append(list([int(els[1]), els[len(els) - 1], els[0]]))
+-            else:
+-                ret.append(list([int(els[0]), els[len(els) - 1], els[1]]))
+-        return ret
+-
+-    def fireProcess(self, appname, failIfRunning=False):
+-        """
+-        Starts a process
+-
+-        returns: pid
+-
+-        DEPRECATED: Use shell() or launchApplication() for new code
+-        """
+-        # strip out env vars
+-        parts = appname.split('"')
+-        if (len(parts) > 2):
+-            parts = parts[2:]
+-        return self.launchProcess(parts, failIfRunning)
+-
+-    def launchProcess(self, cmd, outputFile="process.txt", cwd='', env='', failIfRunning=False):
+-        """
+-        Launches a process, redirecting output to standard out
+-
+-        WARNING: Does not work how you expect on Android! The application's
+-        own output will be flushed elsewhere.
+-
+-        DEPRECATED: Use shell() or launchApplication() for new code
+-        """
+-        if cmd[0] == "am":
+-            self._checkCmd(["shell"] + cmd)
+-            return outputFile
+-
+-        acmd = ["-W"]
+-        cmd = ' '.join(cmd).strip()
+-        i = cmd.find(" ")
+-        re_url = re.compile('^[http|file|chrome|about].*')
+-        last = cmd.rfind(" ")
+-        uri = ""
+-        args = ""
+-        if re_url.match(cmd[last:].strip()):
+-            args = cmd[i:last].strip()
+-            uri = cmd[last:].strip()
+-        else:
+-            args = cmd[i:].strip()
+-        acmd.append("-n")
+-        acmd.append(cmd[0:i] + "/org.mozilla.gecko.BrowserApp")
+-        if args != "":
+-            acmd.append("--es")
+-            acmd.append("args")
+-            acmd.append(args)
+-        if env != '' and env is not None:
+-            envCnt = 0
+-            # env is expected to be a dict of environment variables
+-            for envkey, envval in env.iteritems():
+-                acmd.append("--es")
+-                acmd.append("env" + str(envCnt))
+-                acmd.append(envkey + "=" + envval)
+-                envCnt += 1
+-        if uri != "":
+-            acmd.append("-d")
+-            acmd.append(uri)
+-
+-        acmd = ["shell", ' '.join(map(lambda x: '"' + x + '"', ["am", "start"] + acmd))]
+-        self._logger.info(acmd)
+-        self._checkCmd(acmd)
+-        return outputFile
+-
+-    def killProcess(self, appname, sig=None):
+-        try:
+-            self.shellCheckOutput(["am", "force-stop", appname], timeout=self.short_timeout)
+-        except Exception:
+-            # no problem - will kill it instead
+-            self._logger.info("killProcess failed force-stop of %s" % appname)
+-
+-        shell_args = ["shell"]
+-        if self._sdk_version >= version_codes.N:
+-            # Bug 1334613 - force use of root
+-            if self._haveRootShell is None and self._haveSu is None:
+-                self._checkForRoot()
+-            if not self._haveRootShell and not self._haveSu:
+-                raise DMError(
+-                    "killProcess '%s' requested to run as root but root "
+-                    "is not available on this device. Root your device or "
+-                    "refactor the test/harness to not require root." %
+-                    appname)
+-            if not self._haveRootShell:
+-                shell_args.extend(["su", self._suModifier])
+-
+-        procs = self.getProcessList()
+-        for (pid, name, user) in procs:
+-            if name == appname:
+-                args = list(shell_args)
+-                args.append("kill")
+-                if sig:
+-                    args.append("-%d" % sig)
+-                args.append(str(pid))
+-                p = self._runCmd(args, timeout=self.short_timeout)
+-                if p.returncode != 0 and len(p.output) > 0 and \
+-                   'No such process' not in p.output[0]:
+-                    raise DMError("Error killing process "
+-                                  "'%s': %s" % (appname, p.output))
+-
+-    def _runPull(self, remoteFile, localFile):
+-        """
+-        Pulls remoteFile from device to host
+-        """
+-        try:
+-            self._runCmd(["pull",  remoteFile, localFile])
+-        except (OSError, ValueError):
+-            raise DMError("Error pulling remote file '%s' to '%s'" % (remoteFile, localFile))
+-
+-    def pullFile(self, remoteFile, offset=None, length=None):
+-        # TODO: add debug flags and allow for printing stdout
+-        with mozfile.NamedTemporaryFile() as tf:
+-            self._runPull(remoteFile, tf.name)
+-            # we need to reopen the file to get the written contents
+-            with open(tf.name) as tf2:
+-                # ADB pull does not support offset and length, but we can
+-                # instead read only the requested portion of the local file
+-                if offset is not None and length is not None:
+-                    tf2.seek(offset)
+-                    return tf2.read(length)
+-                elif offset is not None:
+-                    tf2.seek(offset)
+-                    return tf2.read()
+-                else:
+-                    return tf2.read()
+-
+-    def getFile(self, remoteFile, localFile):
+-        self._runPull(remoteFile, localFile)
+-
+-    def getDirectory(self, remoteDir, localDir, checkDir=True):
+-        localDir = os.path.normpath(localDir)
+-        remoteDir = os.path.normpath(remoteDir)
+-        copyRequired = False
+-        originalLocal = localDir
+-        if self._adb_version >= '1.0.36' and \
+-           os.path.isdir(localDir) and self.dirExists(remoteDir):
+-            # See do_sync_pull in
+-            # https://android.googlesource.com/platform/system/core/+/master/adb/file_sync_client.cpp
+-            # Work around change in behavior in adb 1.0.36 where if
+-            # the local destination directory exists, adb pull will
+-            # copy the source directory *into* the destination
+-            # directory otherwise it will copy the source directory
+-            # *onto* the destination directory.
+-            #
+-            # If the destination directory does exist, pull to its
+-            # parent directory. If the source and destination leaf
+-            # directory names are different, pull the source directory
+-            # into a temporary directory and then copy the temporary
+-            # directory onto the destination.
+-            localName = os.path.basename(localDir)
+-            remoteName = os.path.basename(remoteDir)
+-            if localName != remoteName:
+-                copyRequired = True
+-                tempParent = tempfile.mkdtemp()
+-                localDir = os.path.join(tempParent, remoteName)
+-            else:
+-                localDir = '/'.join(localDir.rstrip('/').split('/')[:-1])
+-        self._runCmd(["pull", remoteDir, localDir]).wait()
+-        if copyRequired:
+-            dir_util.copy_tree(localDir, originalLocal)
+-            mozfile.remove(tempParent)
+-
+-    def validateFile(self, remoteFile, localFile):
+-        md5Remote = self._getRemoteHash(remoteFile)
+-        md5Local = self._getLocalHash(localFile)
+-        if md5Remote is None or md5Local is None:
+-            return None
+-        return md5Remote == md5Local
+-
+-    def _getRemoteHash(self, remoteFile):
+-        """
+-        Return the md5 sum of a file on the device
+-        """
+-        with tempfile.NamedTemporaryFile() as f:
+-            self._runPull(remoteFile, f.name)
+-
+-            return self._getLocalHash(f.name)
+-
+-    def _setupDeviceRoot(self, deviceRoot):
+-        # user-specified device root, create it and return it
+-        if deviceRoot:
+-            self.mkDir(deviceRoot)
+-            return deviceRoot
+-
+-        # we must determine the device root ourselves
+-        paths = [('/storage/sdcard0', 'tests'),
+-                 ('/storage/sdcard1', 'tests'),
+-                 ('/storage/sdcard', 'tests'),
+-                 ('/mnt/sdcard', 'tests'),
+-                 ('/sdcard', 'tests'),
+-                 ('/data/local', 'tests')]
+-        for (basePath, subPath) in paths:
+-            if self.dirExists(basePath):
+-                root = os.path.join(basePath, subPath)
+-                try:
+-                    self.mkDir(root)
+-                    return root
+-                except Exception:
+-                    pass
+-
+-        raise DMError("Unable to set up device root using paths: [%s]"
+-                      % ", ".join(["'%s'" % os.path.join(b, s) for b, s in paths]))
+-
+-    def getTempDir(self):
+-        # Cache result to speed up operations depending
+-        # on the temporary directory.
+-        if not self._tempDir:
+-            self._tempDir = "%s/tmp" % self.deviceRoot
+-            self.mkDir(self._tempDir)
+-
+-        return self._tempDir
+-
+-    def reboot(self, wait=False, **kwargs):
+-        self._checkCmd(["reboot"])
+-        if wait:
+-            self._checkCmd(["wait-for-device"])
+-            if self._runAdbAsRoot:
+-                self._adb_root()
+-            self._checkCmd(["shell", "ls", "/sbin"], timeout=self.short_timeout)
+-
+-    def updateApp(self, appBundlePath, **kwargs):
+-        return self._runCmd(["install", "-r", appBundlePath]).output
+-
+-    def getCurrentTime(self):
+-        timestr = str(self._runCmd(["shell", "date", "+%s"], timeout=self.short_timeout).output[0])
+-        if (not timestr or not timestr.isdigit()):
+-            raise DMError("Unable to get current time using date (got: '%s')" % timestr)
+-        return int(timestr) * 1000
+-
+-    def getInfo(self, directive=None):
+-        directive = directive or "all"
+-        ret = {}
+-        if directive == "id" or directive == "all":
+-            ret["id"] = self._runCmd(["get-serialno"], timeout=self.short_timeout).output[0]
+-        if directive == "os" or directive == "all":
+-            ret["os"] = self.shellCheckOutput(
+-                ["getprop", "ro.build.display.id"], timeout=self.short_timeout)
+-        if directive == "uptime" or directive == "all":
+-            uptime = self.shellCheckOutput(["uptime"], timeout=self.short_timeout)
+-            if not uptime:
+-                raise DMError("error getting uptime")
+-            m = re.match("up time: ((\d+) days, )*(\d{2}):(\d{2}):(\d{2})", uptime)
+-            if m:
+-                uptime = "%d days %d hours %d minutes %d seconds" % tuple(
+-                    [int(g or 0) for g in m.groups()[1:]])
+-            ret["uptime"] = uptime
+-        if directive == "process" or directive == "all":
+-            data = self.shellCheckOutput(["ps"], timeout=self.short_timeout)
+-            ret["process"] = data.split('\n')
+-        if directive == "systime" or directive == "all":
+-            ret["systime"] = self.shellCheckOutput(["date"], timeout=self.short_timeout)
+-        if directive == "memtotal" or directive == "all":
+-            meminfo = {}
+-            for line in self.pullFile("/proc/meminfo").splitlines():
+-                key, value = line.split(":")
+-                meminfo[key] = value.strip()
+-            ret["memtotal"] = meminfo["MemTotal"]
+-        if directive == "disk" or directive == "all":
+-            data = self.shellCheckOutput(
+-                ["df", "/data", "/system", "/sdcard"], timeout=self.short_timeout)
+-            ret["disk"] = data.split('\n')
+-        self._logger.debug("getInfo: %s" % ret)
+-        return ret
+-
+-    def uninstallApp(self, appName, installPath=None):
+-        status = self._runCmd(["uninstall", appName]).output[0].strip()
+-        if status != 'Success':
+-            raise DMError("uninstall failed for %s. Got: %s" % (appName, status))
+-
+-    def uninstallAppAndReboot(self, appName, installPath=None):
+-        self.uninstallApp(appName)
+-        self.reboot()
+-
+-    def _runCmd(self, args, timeout=None, retryLimit=None):
+-        """
+-        Runs a command using adb
+-        If timeout is specified, the process is killed after <timeout> seconds.
+-
+-        returns: instance of ProcessHandler
+-        """
+-        retryLimit = retryLimit or self.retryLimit
+-        finalArgs = [self._adbPath]
+-        if self._serverHost is not None:
+-            finalArgs.extend(['-H', self._serverHost])
+-        if self._serverPort is not None:
+-            finalArgs.extend(['-P', str(self._serverPort)])
+-        if self._deviceSerial:
+-            finalArgs.extend(['-s', self._deviceSerial])
+-        finalArgs.extend(args)
+-        self._logger.debug("_runCmd - command: %s" % ' '.join(finalArgs))
+-        if not timeout:
+-            timeout = self.default_timeout
+-
+-        def _timeout():
+-            self._logger.error("Timeout exceeded for _runCmd call '%s'" % ' '.join(finalArgs))
+-
+-        retries = 0
+-        while retries < retryLimit:
+-            proc = ProcessHandler(finalArgs, storeOutput=True,
+-                                  processOutputLine=self._log, onTimeout=_timeout)
+-            proc.run(timeout=timeout)
+-            proc.returncode = proc.wait()
+-            if proc.returncode is None:
+-                proc.kill()
+-                retries += 1
+-            else:
+-                return proc
+-
+-    # timeout is specified in seconds, and if no timeout is given,
+-    # we will run until we hit the default_timeout specified in the __init__
+-    def _checkCmd(self, args, timeout=None, retryLimit=None):
+-        """
+-        Runs a command using adb and waits for the command to finish.
+-        If timeout is specified, the process is killed after <timeout> seconds.
+-
+-        returns: returncode from process
+-        """
+-        retryLimit = retryLimit or self.retryLimit
+-        finalArgs = [self._adbPath]
+-        if self._serverHost is not None:
+-            finalArgs.extend(['-H', self._serverHost])
+-        if self._serverPort is not None:
+-            finalArgs.extend(['-P', str(self._serverPort)])
+-        if self._deviceSerial:
+-            finalArgs.extend(['-s', self._deviceSerial])
+-        finalArgs.extend(args)
+-        self._logger.debug("_checkCmd - command: %s" % ' '.join(finalArgs))
+-        if not timeout:
+-            # We are asserting that all commands will complete in this
+-            # time unless otherwise specified
+-            timeout = self.default_timeout
+-
+-        def _timeout():
+-            self._logger.error("Timeout exceeded for _checkCmd call '%s'" % ' '.join(finalArgs))
+-
+-        timeout = int(timeout)
+-        retries = 0
+-        while retries < retryLimit:
+-            proc = ProcessHandler(finalArgs, processOutputLine=self._log, onTimeout=_timeout)
+-            proc.run(timeout=timeout)
+-            ret_code = proc.wait()
+-            if ret_code is None:
+-                proc.kill()
+-                retries += 1
+-            else:
+-                return ret_code
+-
+-        raise DMError("Timeout exceeded for _checkCmd call after %d retries." % retries)
+-
+-    def chmodDir(self, remoteDir, mask="777"):
+-        if (self.dirExists(remoteDir)):
+-            if '/sdcard' in remoteDir:
+-                self._logger.debug("chmod %s -- skipped (/sdcard)" % remoteDir)
+-            else:
+-                files = self.listFiles(remoteDir.strip())
+-                for f in files:
+-                    remoteEntry = remoteDir.strip() + "/" + f.strip()
+-                    if (self.dirExists(remoteEntry)):
+-                        self.chmodDir(remoteEntry)
+-                    else:
+-                        self._checkCmd(["shell", "chmod", mask, remoteEntry],
+-                                       timeout=self.short_timeout)
+-                        self._logger.info("chmod %s" % remoteEntry)
+-                self._checkCmd(["shell", "chmod", mask, remoteDir], timeout=self.short_timeout)
+-                self._logger.debug("chmod %s" % remoteDir)
+-        else:
+-            self._checkCmd(["shell", "chmod", mask, remoteDir.strip()], timeout=self.short_timeout)
+-            self._logger.debug("chmod %s" % remoteDir.strip())
+-
+-    def _verifyADB(self):
+-        """
+-        Check to see if adb itself can be executed.
+-        """
+-        if self._adbPath != 'adb':
+-            if not os.access(self._adbPath, os.X_OK):
+-                raise DMError("invalid adb path, or adb not executable: %s" % self._adbPath)
+-
+-        try:
+-            re_version = re.compile(r'Android Debug Bridge version (.*)')
+-            proc = self._runCmd(["version"], timeout=self.short_timeout)
+-            self._adb_version = re_version.match(proc.output[0]).group(1)
+-            self._logger.info("Detected adb %s" % self._adb_version)
+-        except os.error as err:
+-            raise DMError(
+-                "unable to execute ADB (%s): ensure Android SDK is installed "
+-                "and adb is in your $PATH" % err)
+-
+-    def _verifyDevice(self):
+-        # If there is a device serial number, see if adb is connected to it
+-        if self._deviceSerial:
+-            deviceStatus = None
+-            for line in self._runCmd(["devices"]).output:
+-                m = re.match('(.+)?\s+(.+)$', line)
+-                if m:
+-                    if self._deviceSerial == m.group(1):
+-                        deviceStatus = m.group(2)
+-            if deviceStatus is None:
+-                raise DMError("device not found: %s" % self._deviceSerial)
+-            elif deviceStatus != "device":
+-                raise DMError("bad status for device %s: %s" % (self._deviceSerial, deviceStatus))
+-
+-        # Check to see if we can connect to device and run a simple command
+-        if not self._checkCmd(["shell", "echo"], timeout=self.short_timeout) == 0:
+-            raise DMError("unable to connect to device")
+-
+-    def _checkForRoot(self):
+-        self._haveRootShell = False
+-        self._haveSu = False
+-        # If requested to attempt to run adbd as root, do so before
+-        # checking whether adbs is running as root.
+-        if self._runAdbAsRoot:
+-            self._adb_root()
+-
+-        # Check whether we _are_ root by default (some development boards work
+-        # this way, this is also the result of some relatively rare rooting
+-        # techniques)
+-        proc = self._runCmd(["shell", "id"], timeout=self.short_timeout)
+-        if proc.output and 'uid=0(root)' in proc.output[0]:
+-            self._haveRootShell = True
+-            # if this returns true, we don't care about su
+-            return
+-
+-        # if root shell is not available, check if 'su' can be used to gain
+-        # root
+-        def su_id(su_modifier, timeout):
+-            proc = self._runCmd(["shell", "su", su_modifier, "id"],
+-                                timeout=timeout)
+-
+-            # wait for response for maximum of 15 seconds, in case su
+-            # prompts for a password or triggers the Android SuperUser
+-            # prompt
+-            start_time = time.time()
+-            retcode = None
+-            while (time.time() - start_time) <= 15 and retcode is None:
+-                retcode = proc.poll()
+-            if retcode is None:  # still not terminated, kill
+-                proc.kill()
+-
+-            if proc.output and 'uid=0(root)' in proc.output[0]:
+-                return True
+-            return False
+-
+-        if su_id('0', self.short_timeout):
+-            self._haveSu = True
+-            self._suModifier = '0'
+-        elif su_id('-c', self.short_timeout):
+-            self._haveSu = True
+-            self._suModifier = '-c'
+-
+-    def _isUnzipAvailable(self):
+-        data = self._runCmd(["shell", "unzip"]).output
+-        for line in data:
+-            if (re.search('Usage', line)):
+-                return True
+-        return False
+-
+-    def _isLocalZipAvailable(self):
+-        def _noOutput(line):
+-            # suppress output from zip ProcessHandler
+-            pass
+-        try:
+-            proc = ProcessHandler(["zip", "-?"], storeOutput=False, processOutputLine=_noOutput)
+-            proc.run()
+-            proc.wait()
+-        except Exception:
+-            return False
+-        return True
+-
+-    def _verifyZip(self):
+-        # If "zip" can be run locally, and "unzip" can be run remotely, then pushDir
+-        # can use these to push just one file per directory -- a significant
+-        # optimization for large directories.
+-        self._useZip = False
+-        if (self._isUnzipAvailable() and self._isLocalZipAvailable()):
+-            self._logger.info("will use zip to push directories")
+-            self._useZip = True
+-        else:
+-            raise DMError("zip not available")
+-
+-    def _adb_root(self):
+-        """ Some devices require us to reboot adbd as root.
+-            This function takes care of it.
+-        """
+-        if self.processInfo("adbd")[2] != "root":
+-            self._checkCmd(["root"])
+-            self._checkCmd(["wait-for-device"])
+-            if self.processInfo("adbd")[2] != "root":
+-                raise DMError("We tried rebooting adbd as root, however, it failed.")
+-
+-    def _detectLsModifier(self):
+-        if self._lsModifier is None:
+-            # Check if busybox -1A is required in order to get one
+-            # file per line.
+-            output = self._runCmd(["shell", "ls", "-1A", "/"],
+-                                  timeout=self.short_timeout).output
+-            output = ' '.join(output)
+-            if 'error: device not found' in output:
+-                raise DMError(output)
+-            if "Unknown option '-1'. Aborting." in output:
+-                self._lsModifier = "-a"
+-            elif "No such file or directory" in output:
+-                self._lsModifier = "-a"
+-            else:
+-                self._lsModifier = "-1A"
+diff --git a/testing/mozbase/mozdevice/mozdevice/dmcli.py b/testing/mozbase/mozdevice/mozdevice/dmcli.py
+deleted file mode 100644
+--- a/testing/mozbase/mozdevice/mozdevice/dmcli.py
++++ /dev/null
+@@ -1,352 +0,0 @@
+-# This Source Code Form is subject to the terms of the Mozilla Public
+-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+-# You can obtain one at http://mozilla.org/MPL/2.0/.
+-
+-"""
+-Command-line client to control a device
+-"""
+-from __future__ import absolute_import, print_function
+-
+-import errno
+-import logging
+-import os
+-import posixpath
+-import StringIO
+-import sys
+-import mozdevice
+-import mozlog
+-import argparse
+-
+-
+-class DMCli(object):
+-
+-    def __init__(self):
+-        self.commands = {'deviceroot': {'function': self.deviceroot,
+-                                        'help': 'get device root directory for storing temporary '
+-                                        'files'},
+-                         'install': {'function': self.install,
+-                                     'args': [{'name': 'file'}],
+-                                     'help': 'push this package file to the device'
+-                                     ' and install it'},
+-                         'uninstall': {'function': self.uninstall,
+-                                       'args': [{'name': 'packagename'}],
+-                                       'help': 'uninstall the named app from the device'},
+-                         'killapp': {'function': self.kill,
+-                                     'args': [{'name': 'process_name', 'nargs': '*'}],
+-                                     'help': 'kills any processes with name(s) on device'},
+-                         'launchapp': {'function': self.launchapp,
+-                                       'args': [{'name': 'appname'},
+-                                                {'name': 'activity_name'},
+-                                                {'name': '--intent',
+-                                                 'action': 'store',
+-                                                 'default': 'android.intent.action.VIEW'},
+-                                                {'name': '--url',
+-                                                 'action': 'store'},
+-                                                {'name': '--no-fail-if-running',
+-                                                 'action': 'store_true',
+-                                                 'help': 'Don\'t fail if application is'
+-                                                 ' already running'}
+-                                                ],
+-                                       'help': 'launches application on device'},
+-                         'listapps': {'function': self.listapps,
+-                                      'help': 'list applications on device'},
+-                         'push': {'function': self.push,
+-                                  'args': [{'name': 'local_file'},
+-                                           {'name': 'remote_file'}
+-                                           ],
+-                                  'help': 'copy file/dir to device'},
+-                         'pull': {'function': self.pull,
+-                                  'args': [{'name': 'local_file'},
+-                                           {'name': 'remote_file', 'nargs': '?'}],
+-                                  'help': 'copy file/dir from device'},
+-                         'shell': {'function': self.shell,
+-                                   'args': [{'name': 'command', 'nargs': argparse.REMAINDER},
+-                                            {'name': '--root', 'action': 'store_true',
+-                                             'help': 'Run command as root'}],
+-                                   'help': 'run shell command on device'},
+-                         'info': {'function': self.getinfo,
+-                                  'args': [{'name': 'directive', 'nargs': '?'}],
+-                                  'help': 'get information on specified '
+-                                  'aspect of the device (if no argument '
+-                                  'given, print all available information)'
+-                                  },
+-                         'ps': {'function': self.processlist,
+-                                'help': 'get information on running processes on device'
+-                                },
+-                         'logcat': {'function': self.logcat,
+-                                    'help': 'get logcat from device'
+-                                    },
+-                         'ls': {'function': self.listfiles,
+-                                'args': [{'name': 'remote_dir'}],
+-                                'help': 'list files on device'
+-                                },
+-                         'rm': {'function': self.removefile,
+-                                'args': [{'name': 'remote_file'}],
+-                                'help': 'remove file from device'
+-                                },
+-                         'isdir': {'function': self.isdir,
+-                                   'args': [{'name': 'remote_dir'}],
+-                                   'help': 'print if remote file is a directory'
+-                                   },
+-                         'mkdir': {'function': self.mkdir,
+-                                   'args': [{'name': 'remote_dir'}],
+-                                   'help': 'makes a directory on device'
+-                                   },
+-                         'rmdir': {'function': self.rmdir,
+-                                   'args': [{'name': 'remote_dir'}],
+-                                   'help': 'recursively remove directory from device'
+-                                   },
+-                         'screencap': {'function': self.screencap,
+-                                       'args': [{'name': 'png_file'}],
+-                                       'help': 'capture screenshot of device in action'
+-                                       },
+-                         'clearlogcat': {'function': self.clearlogcat,
+-                                         'help': 'clear the logcat'
+-                                         },
+-                         'reboot': {'function': self.reboot,
+-                                    'help': 'reboot the device',
+-                                    'args': [{'name': '--wait',
+-                                              'action': 'store_true',
+-                                              'help': 'Wait for device to come back up'
+-                                              ' before exiting'}]
+-
+-                                    },
+-                         'isfile': {'function': self.isfile,
+-                                    'args': [{'name': 'remote_file'}],
+-                                    'help': 'check whether a file exists on the device'
+-                                    },
+-                         'launchfennec': {'function': self.launchfennec,
+-                                          'args': [{'name': 'appname'},
+-                                                   {'name': '--intent', 'action': 'store',
+-                                                    'default': 'android.intent.action.VIEW'},
+-                                                   {'name': '--url', 'action': 'store'},
+-                                                   {'name': '--extra-args', 'action': 'store'},
+-                                                   {'name': '--mozenv', 'action': 'store',
+-                                                    'help': 'Gecko environment variables to set'
+-                                                    ' in "KEY1=VAL1 KEY2=VAL2" format'},
+-                                                   {'name': '--no-fail-if-running',
+-                                                    'action': 'store_true',
+-                                                    'help': 'Don\'t fail if application is '
+-                                                    'already running'}
+-                                                   ],
+-                                          'help': 'launch fennec'
+-                                          },
+-                         'getip': {'function': self.getip,
+-                                   'args': [{'name': 'interface', 'nargs': '*'}],
+-                                   'help': 'get the ip address of the device'
+-                                   }
+-                         }
+-
+-        self.parser = argparse.ArgumentParser()
+-        self.add_options(self.parser)
+-        self.add_commands(self.parser)
+-        mozlog.commandline.add_logging_group(self.parser)
+-
+-    def run(self, args=sys.argv[1:]):
+-        args = self.parser.parse_args()
+-
+-        mozlog.commandline.setup_logging(
+-            'mozdevice', args, {'mach': sys.stdout})
+-
+-        self.dm = self.getDevice(hwid=args.hwid,
+-                                 host=args.host, port=args.port,
+-                                 verbose=args.verbose)
+-
+-        ret = args.func(args)
+-        if ret is None:
+-            ret = 0
+-
+-        sys.exit(ret)
+-
+-    def add_options(self, parser):
+-        parser.add_argument("-v", "--verbose", action="store_true",
+-                            help="Verbose output from DeviceManager",
+-                            default=bool(os.environ.get('VERBOSE')))
+-        parser.add_argument("--host", action="store",
+-                            help="Device hostname (only if using TCP/IP, "
+-                            "defaults to TEST_DEVICE environment "
+-                            "variable if present)",
+-                            default=os.environ.get('TEST_DEVICE'))
+-        parser.add_argument("-p", "--port", action="store",
+-                            type=int,
+-                            help="Custom device port (if using "
+-                            "adb-over-tcp)", default=None)
+-        parser.add_argument("-d", "--hwid", action="store",
+-                            help="HWID", default=None)
+-        parser.add_argument("--package-name", action="store",
+-                            help="Packagename (if using DeviceManagerADB)",
+-                            default=None)
+-
+-    def add_commands(self, parser):
+-        subparsers = parser.add_subparsers(title="Commands", metavar="<command>")
+-        for (commandname, commandprops) in sorted(self.commands.iteritems()):
+-            subparser = subparsers.add_parser(commandname, help=commandprops['help'])
+-            if commandprops.get('args'):
+-                for arg in commandprops['args']:
+-                    # this is more elegant but doesn't work in python 2.6
+-                    # (which we still use on tbpl @ mozilla where we install
+-                    # this package)
+-                    # kwargs = { k: v for k,v in arg.items() if k is not 'name' }
+-                    kwargs = {}
+-                    for (k, v) in arg.items():
+-                        if k is not 'name':
+-                            kwargs[k] = v
+-                    subparser.add_argument(arg['name'], **kwargs)
+-            subparser.set_defaults(func=commandprops['function'])
+-
+-    def getDevice(self, hwid=None, host=None, port=None,
+-                  packagename=None, verbose=False):
+-        '''
+-        Returns a device with the specified parameters
+-        '''
+-        logLevel = logging.ERROR
+-        if verbose:
+-            logLevel = logging.DEBUG
+-
+-        if host and not port:
+-            port = 5555
+-        return mozdevice.DroidADB(packageName=packagename,
+-                                  host=host, port=port,
+-                                  logLevel=logLevel)
+-
+-    def deviceroot(self, args):
+-        print(self.dm.deviceRoot)
+-
+-    def push(self, args):
+-        (src, dest) = (args.local_file, args.remote_file)
+-        if os.path.isdir(src):
+-            self.dm.pushDir(src, dest)
+-        else:
+-            dest_is_dir = dest[-1] == '/' or self.dm.dirExists(dest)
+-            dest = posixpath.normpath(dest)
+-            if dest_is_dir:
+-                dest = posixpath.join(dest, os.path.basename(src))
+-            self.dm.pushFile(src, dest)
+-
+-    def pull(self, args):
+-        (src, dest) = (args.local_file, args.remote_file)
+-        if not self.dm.fileExists(src):
+-            print('No such file or directory')
+-            return
+-        if not dest:
+-            dest = posixpath.basename(src)
+-        if self.dm.dirExists(src):
+-            self.dm.getDirectory(src, dest)
+-        else:
+-            self.dm.getFile(src, dest)
+-
+-    def install(self, args):
+-        basename = os.path.basename(args.file)
+-        app_path_on_device = posixpath.join(self.dm.deviceRoot,
+-                                            basename)
+-        self.dm.pushFile(args.file, app_path_on_device)
+-        self.dm.installApp(app_path_on_device)
+-
+-    def uninstall(self, args):
+-        self.dm.uninstallApp(args.packagename)
+-
+-    def launchapp(self, args):
+-        self.dm.launchApplication(args.appname, args.activity_name,
+-                                  args.intent, url=args.url,
+-                                  failIfRunning=(not args.no_fail_if_running))
+-
+-    def listapps(self, args):
+-        for app in self.dm.getInstalledApps():
+-            print(app)
+-
+-    def stopapp(self, args):
+-        self.dm.stopApplication(args.appname)
+-
+-    def kill(self, args):
+-        for name in args.process_name:
+-            self.dm.killProcess(name)
+-
+-    def shell(self, args):
+-        buf = StringIO.StringIO()
+-        self.dm.shell(args.command, buf, root=args.root)
+-        print(str(buf.getvalue()[0:-1]).rstrip())
+-
+-    def getinfo(self, args):
+-        info = self.dm.getInfo(directive=args.directive)
+-        for (infokey, infoitem) in sorted(info.iteritems()):
+-            if infokey == "process":
+-                pass  # skip process list: get that through ps
+-            elif args.directive is None:
+-                print("%s: %s" % (infokey.upper(), infoitem))
+-            else:
+-                print(infoitem)
+-
+-    def logcat(self, args):
+-        print(''.join(self.dm.getLogcat()))
+-
+-    def clearlogcat(self, args):
+-        self.dm.recordLogcat()
+-
+-    def reboot(self, args):
+-        self.dm.reboot(wait=args.wait)
+-
+-    def processlist(self, args):
+-        pslist = self.dm.getProcessList()
+-        for ps in pslist:
+-            print(" ".join(str(i) for i in ps))
+-
+-    def listfiles(self, args):
+-        filelist = self.dm.listFiles(args.remote_dir)
+-        for file in filelist:
+-            print(file)
+-
+-    def removefile(self, args):
+-        self.dm.removeFile(args.remote_file)
+-
+-    def isdir(self, args):
+-        if self.dm.dirExists(args.remote_dir):
+-            print("TRUE")
+-            return
+-
+-        print("FALSE")
+-        return errno.ENOTDIR
+-
+-    def mkdir(self, args):
+-        self.dm.mkDir(args.remote_dir)
+-
+-    def rmdir(self, args):
+-        self.dm.removeDir(args.remote_dir)
+-
+-    def screencap(self, args):
+-        self.dm.saveScreenshot(args.png_file)
+-
+-    def isfile(self, args):
+-        if self.dm.fileExists(args.remote_file):
+-            print("TRUE")
+-            return
+-        print("FALSE")
+-        return errno.ENOENT
+-
+-    def launchfennec(self, args):
+-        mozEnv = None
+-        if args.mozenv:
+-            mozEnv = {}
+-            keyvals = args.mozenv.split()
+-            for keyval in keyvals:
+-                (key, _, val) = keyval.partition("=")
+-                mozEnv[key] = val
+-        self.dm.launchFennec(args.appname, intent=args.intent,
+-                             mozEnv=mozEnv,
+-                             extraArgs=args.extra_args, url=args.url,
+-                             failIfRunning=(not args.no_fail_if_running))
+-
+-    def getip(self, args):
+-        if args.interface:
+-            print(self.dm.getIP(args.interface))
+-        else:
+-            print(self.dm.getIP())
+-
+-
+-def cli(args=sys.argv[1:]):
+-    # process the command line
+-    cli = DMCli()
+-    cli.run(args)
+-
+-
+-if __name__ == '__main__':
+-    cli()
+diff --git a/testing/mozbase/mozdevice/mozdevice/droid.py b/testing/mozbase/mozdevice/mozdevice/droid.py
+deleted file mode 100644
+--- a/testing/mozbase/mozdevice/mozdevice/droid.py
++++ /dev/null
+@@ -1,198 +0,0 @@
+-# This Source Code Form is subject to the terms of the Mozilla Public
+-# License, v. 2.0. If a copy of the MPL was not distributed with this file,
+-# You can obtain one at http://mozilla.org/MPL/2.0/.
+-
+-from __future__ import absolute_import
+-
+-import StringIO
+-import re
+-import time
+-
+-from mozdevice import version_codes
+-
+-from .devicemanagerADB import DeviceManagerADB
+-from .devicemanager import DMError
+-
+-
+-class DroidMixin(object):
+-    """Mixin to extend DeviceManager with Android-specific functionality"""
+-
+-    _stopApplicationNeedsRoot = True
+-
+-    def _getExtraAmStartArgs(self):
+-        return []
+-
+-    def launchApplication(self, appName, activityName, intent, url=None,
+-                          extras=None, wait=True, failIfRunning=True):
+-        """
+-        Launches an Android application
+-
+-        :param appName: Name of application (e.g. `com.android.chrome`)
+-        :param activityName: Name of activity to launch (e.g. `.Main`)
+-        :param intent: Intent to launch application with
+-        :param url: URL to open
+-        :param extras: Dictionary of extra arguments to launch application with
+-        :param wait: If True, wait for application to start before returning
+-        :param failIfRunning: Raise an exception if instance of application is already running
+-        """
+-
+-        # If failIfRunning is True, we throw an exception here. Only one
+-        # instance of an application can be running at once on Android,
+-        # starting a new instance may not be what we want depending on what
+-        # we want to do
+-        if failIfRunning and self.processExist(appName):
+-            raise DMError("Only one instance of an application may be running "
+-                          "at once")
+-
+-        acmd = ["am", "start"] + self._getExtraAmStartArgs() + \
+-            ["-W" if wait else '', "-n", "%s/%s" % (appName, activityName)]
+-
+-        if intent:
+-            acmd.extend(["-a", intent])
+-
+-        if extras:
+-            for (key, val) in extras.iteritems():
+-                if type(val) is int:
+-                    extraTypeParam = "--ei"
+-                elif type(val) is bool:
+-                    extraTypeParam = "--ez"
+-                else:
+-                    extraTypeParam = "--es"
+-                acmd.extend([extraTypeParam, str(key), str(val)])
+-
+-        if url:
+-            acmd.extend(["-d", url])
+-
+-        # shell output not that interesting and debugging logs should already
+-        # show what's going on here... so just create an empty memory buffer
+-        # and ignore (except on error)
+-        shellOutput = StringIO.StringIO()
+-        if self.shell(acmd, shellOutput) == 0:
+-            return
+-
+-        shellOutput.seek(0)
+-        raise DMError("Unable to launch application (shell output: '%s')" % shellOutput.read())
+-
+-    def launchFennec(self, appName, intent="android.intent.action.VIEW",
+-                     mozEnv=None, extraArgs=None, url=None, wait=True,
+-                     failIfRunning=True):
+-        """
+-        Convenience method to launch Fennec on Android with various debugging
+-        arguments
+-
+-        :param appName: Name of fennec application (e.g. `org.mozilla.fennec`)
+-        :param intent: Intent to launch application with
+-        :param mozEnv: Mozilla specific environment to pass into application
+-        :param extraArgs: Extra arguments to be parsed by fennec
+-        :param url: URL to open
+-        :param wait: If True, wait for application to start before returning
+-        :param failIfRunning: Raise an exception if instance of application is already running
+-        """
+-        extras = {}
+-
+-        if mozEnv:
+-            # mozEnv is expected to be a dictionary of environment variables: Fennec
+-            # itself will set them when launched
+-            for (envCnt, (envkey, envval)) in enumerate(mozEnv.iteritems()):
+-                extras["env" + str(envCnt)] = envkey + "=" + envval
+-
+-        # Additional command line arguments that fennec will read and use (e.g.
+-        # with a custom profile)
+-        if extraArgs:
+-            extras['args'] = " ".join(extraArgs)
+-
+-        self.launchApplication(appName, "org.mozilla.gecko.BrowserApp", intent, url=url,
+-                               extras=extras,
+-                               wait=wait, failIfRunning=failIfRunning)
+-
+-    def getInstalledApps(self):
+-        """
+-        Lists applications installed on this Android device
+-
+-        Returns a list of application names in the form [ 'org.mozilla.fennec', ... ]
+-        """
+-        output = self.shellCheckOutput(["pm", "list", "packages", "-f"])
+-        apps = []
+-        for line in output.splitlines():
+-            # lines are of form: package:/system/app/qik-tmo.apk=com.qiktmobile.android
+-            apps.append(line.split('=')[1])
+-
+-        return apps
+-
+-    def stopApplication(self, appName):
+-        """
+-        Stops the specified application
+-
+-        For Android 3.0+, we use the "am force-stop" to do this, which is
+-        reliable and does not require root. For earlier versions of Android,
+-        we simply try to manually kill the processes started by the app
+-        repeatedly until none is around any more. This is less reliable and
+-        does require root.
+-
+-        :param appName: Name of application (e.g. `com.android.chrome`)
+-        """
+-        version = self.shellCheckOutput(["getprop", "ro.build.version.sdk"])
+-        if int(version) >= version_codes.HONEYCOMB:
+-            self.shellCheckOutput(["am", "force-stop", appName],
+-                                  root=self._stopApplicationNeedsRoot)
+-        else:
+-            num_tries = 0
+-            max_tries = 5
+-            while self.processExist(appName):
+-                if num_tries > max_tries:
+-                    raise DMError("Couldn't successfully kill %s after %s "
+-                                  "tries" % (appName, max_tries))
+-                self.killProcess(appName)
+-                num_tries += 1
+-
+-                # sleep for a short duration to make sure there are no
+-                # additional processes in the process of being launched
+-                # (this is not 100% guaranteed to work since it is inherently
+-                # racey, but it's the best we can do)
+-                time.sleep(1)
+-
+-
+-class DroidADB(DeviceManagerADB, DroidMixin):
+-
+-    _stopApplicationNeedsRoot = False
+-
+-    def getTopActivity(self):
+-        package = None
+-        data = None
+-        try:
+-            # Increased timeout to 60 seconds after intermittent timeouts at 30.
+-            data = self.shellCheckOutput(
+-                ["dumpsys", "window", "windows"], timeout=60)
+-        except Exception:
+-            # dumpsys seems to intermittently fail (seen on 4.3 emulator), producing
+-            # no output.
+-            return ""
+-        # "dumpsys window windows" produces many lines of input. The top/foreground
+-        # activity is indicated by something like:
+-        #   mFocusedApp=AppWindowToken{483e6db0 token=HistoryRecord{484dcad8 com.mozilla.something/.something}} # noqa
+-        # or, on other devices:
+-        #   FocusedApplication: name='AppWindowToken{41a65340 token=ActivityRecord{418fbd68 org.mozilla.fennec_mozdev/org.mozilla.gecko.BrowserApp}}', dispatchingTimeout=5000.000ms # noqa
+-        # Extract this line, ending in the forward slash:
+-        m = re.search('mFocusedApp(.+)/', data)
+-        if not m:
+-            m = re.search('FocusedApplication(.+)/', data)
+-        if m:
+-            line = m.group(0)
+-            # Extract package name: string of non-whitespace ending in forward slash
+-            m = re.search('(\S+)/$', line)
+-            if m:
+-                package = m.group(1)
+-        if not package:
+-            # On some Android 4.4 devices, when the home screen is displayed,
+-            # dumpsys reports "mFocusedApp=null". Guard against this case and
+-            # others where the focused app can not be determined by returning
+-            # an empty string.
+-            package = ""
+-        return package
+-
+-    def getAppRoot(self, packageName):
+-        """
+-        Returns the root directory for the specified android application
+-        """
+-        # relying on convention
+-        return '/data/data/%s' % packageName
+diff --git a/testing/mozbase/mozdevice/setup.py b/testing/mozbase/mozdevice/setup.py
+--- a/testing/mozbase/mozdevice/setup.py
++++ b/testing/mozbase/mozdevice/setup.py
+@@ -29,12 +29,10 @@ setup(name=PACKAGE_NAME,
+       url='https://wiki.mozilla.org/Auto-tools/Projects/Mozbase',
+       license='MPL',
+       packages=['mozdevice'],
+       include_package_data=True,
+       zip_safe=False,
+       install_requires=deps,
+       entry_points="""
+       # -*- Entry points: -*-
+-      [console_scripts]
+-      dm = mozdevice.dmcli:cli
+       """,
+       )
+diff --git a/testing/mozbase/moztest/moztest/output/base.py.1440714-17.later b/testing/mozbase/moztest/moztest/output/base.py.1440714-17.later
+new file mode 100644
+--- /dev/null
++++ b/testing/mozbase/moztest/moztest/output/base.py.1440714-17.later
+@@ -0,0 +1,20 @@
++--- base.py
+++++ base.py
++@@ -6,17 +6,16 @@ from __future__ import absolute_import, 
++ 
++ from contextlib import closing
++ from StringIO import StringIO
++ 
++ try:
++     from abc import abstractmethod
++ except ImportError:
++     # abc is python 2.6+
++-    # from https://github.com/mozilla/mozbase/blob/master/mozdevice/mozdevice/devicemanager.py
++     def abstractmethod(method):
++         line = method.func_code.co_firstlineno
++         filename = method.func_code.co_filename
++ 
++         def not_implemented(*args, **kwargs):
++             raise NotImplementedError('Abstract method %s at File "%s", '
++                                       'line %s  should be implemented by a concrete class' %
++                                       (repr(method), filename, line))
+diff --git a/testing/xpcshell/runxpcshelltests.py b/testing/xpcshell/runxpcshelltests.py
+--- a/testing/xpcshell/runxpcshelltests.py
++++ b/testing/xpcshell/runxpcshelltests.py
+@@ -248,17 +248,17 @@ class XPCShellTestThread(Thread):
+         return proc.communicate()
+ 
+     def launchProcess(self, cmd, stdout, stderr, env, cwd, timeout=None):
+         """
+           Simple wrapper to launch a process.
+           On a remote system, this is more complex and we need to overload this function.
+         """
+         # timeout is needed by remote xpcshell to extend the
+-        # devicemanager.shell() timeout. It is not used in this function.
++        # remote device timeout. It is not used in this function.
+         if HAVE_PSUTIL:
+             popen_func = psutil.Popen
+         else:
+             popen_func = Popen
+         proc = popen_func(cmd, stdout=stdout, stderr=stderr,
+                           env=env, cwd=cwd)
+         return proc
+ 

+ 29 - 0
mozilla-release/patches/1440714-18-61a1.patch

@@ -0,0 +1,29 @@
+# HG changeset patch
+# User Geoff Brown <gbrown@mozilla.com>
+# Date 1524760988 21600
+# Node ID ea92acbc6e59ddfa2569b161b31f45027a5d85f0
+# Parent  8747f48aa62b7a2893029f00f6872018fb2d2364
+Bug 1440714 - Bump mozdevice version to 1.0.0; r=bc
+
+diff --git a/testing/mozbase/mozdevice/setup.py b/testing/mozbase/mozdevice/setup.py
+--- a/testing/mozbase/mozdevice/setup.py
++++ b/testing/mozbase/mozdevice/setup.py
+@@ -3,17 +3,17 @@
+ # License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ # You can obtain one at http://mozilla.org/MPL/2.0/.
+ 
+ from __future__ import absolute_import
+ 
+ from setuptools import setup
+ 
+ PACKAGE_NAME = 'mozdevice'
+-PACKAGE_VERSION = '0.52'
++PACKAGE_VERSION = '1.0.0'
+ 
+ deps = ['mozfile >= 1.0',
+         'mozlog >= 3.0',
+         'moznetwork >= 0.24',
+         'mozprocess >= 0.19',
+         ]
+ 
+ setup(name=PACKAGE_NAME,

+ 29 - 0
mozilla-release/patches/1440714-19-61a1.patch

@@ -0,0 +1,29 @@
+# HG changeset patch
+# User Geoff Brown <gbrown@mozilla.com>
+# Date 1524767423 21600
+# Node ID 1472f261db239683061a82d3ceeeb14c31bbc158
+# Parent  f88b82631394a18196be002cf68adbebe03b0432
+Bug 1440714 - Follow-up: Update mozrunner's mozdevice requirements; r=me on a CLOSED TREE
+
+diff --git a/testing/mozbase/mozrunner/setup.py b/testing/mozbase/mozrunner/setup.py
+--- a/testing/mozbase/mozrunner/setup.py
++++ b/testing/mozbase/mozrunner/setup.py
+@@ -8,17 +8,17 @@ import sys
+ from setuptools import setup, find_packages
+ 
+ PACKAGE_NAME = 'mozrunner'
+ PACKAGE_VERSION = '7.0.0'
+ 
+ desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
+ 
+ deps = [
+-    'mozdevice>=0.37,<1',
++    'mozdevice>=1.*',
+     'mozfile==1.*',
+     'mozinfo>=0.7,<1',
+     'mozlog==3.*',
+     'mozprocess>=0.23,<1',
+     'mozprofile>=1.1.0,<2',
+     'six>=1.10.0,<2',
+ ]
+ 

+ 2 - 2
mozilla-release/patches/1457600-61a1.patch

@@ -2,7 +2,7 @@
 # User Geoff Brown <gbrown@mozilla.com>
 # User Geoff Brown <gbrown@mozilla.com>
 # Date 1525094309 21600
 # Date 1525094309 21600
 # Node ID 5ce2a15a464ccbadd91e816e5d62a793f2733427
 # Node ID 5ce2a15a464ccbadd91e816e5d62a793f2733427
-# Parent  31bc8a26015a80284e4e62ba5dd2334880df634d
+# Parent  0d32eb4c7d8890d5bd109b0546d54cac6bbf9e34
 Bug 1457600 - Version bump for mozrunner; r=rwood
 Bug 1457600 - Version bump for mozrunner; r=rwood
 
 
 In bug 1440714, mozdevice had its version bumped to 1.0.0, outside of the required
 In bug 1440714, mozdevice had its version bumped to 1.0.0, outside of the required
@@ -28,7 +28,7 @@ diff --git a/testing/mozbase/mozrunner/setup.py b/testing/mozbase/mozrunner/setu
  desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
  desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
  
  
  deps = [
  deps = [
-     'mozdevice>=0.37,<1',
+     'mozdevice>=1.*',
      'mozfile==1.*',
      'mozfile==1.*',
      'mozinfo>=0.7,<1',
      'mozinfo>=0.7,<1',
      'mozlog==3.*',
      'mozlog==3.*',

+ 77 - 0
mozilla-release/patches/1458280-61a1.patch

@@ -0,0 +1,77 @@
+# HG changeset patch
+# User Geoff Brown <gbrown@mozilla.com>
+# Date 1525212650 21600
+# Node ID 721395128428203131d5575848cdb986009643b9
+# Parent  f35e931fbdc866e26801eeedb798243a33e5eac6
+Bug 1458280 - Release marionette_driver 2.7.0 and marionette_harness 4.5.0; r=whimboo
+
+diff --git a/testing/marionette/client/marionette_driver/__init__.py b/testing/marionette/client/marionette_driver/__init__.py
+--- a/testing/marionette/client/marionette_driver/__init__.py
++++ b/testing/marionette/client/marionette_driver/__init__.py
+@@ -1,15 +1,15 @@
+ # This Source Code Form is subject to the terms of the Mozilla Public
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ 
+ from __future__ import absolute_import
+ 
+-__version__ = '2.6.0'
++__version__ = '2.7.0'
+ 
+ from marionette_driver import (
+     addons,
+     by,
+     date_time_value,
+     decorators,
+     errors,
+     expected,
+diff --git a/testing/marionette/client/requirements.txt b/testing/marionette/client/requirements.txt
+--- a/testing/marionette/client/requirements.txt
++++ b/testing/marionette/client/requirements.txt
+@@ -1,3 +1,3 @@
+-mozrunner >= 6.15
++mozrunner >= 7.0.1
+ mozversion >= 1.1
+ six
+diff --git a/testing/marionette/harness/marionette_harness/__init__.py b/testing/marionette/harness/marionette_harness/__init__.py
+--- a/testing/marionette/harness/marionette_harness/__init__.py
++++ b/testing/marionette/harness/marionette_harness/__init__.py
+@@ -1,15 +1,15 @@
+ # This Source Code Form is subject to the terms of the Mozilla Public
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ 
+ from __future__ import absolute_import
+ 
+-__version__ = '4.4.0'
++__version__ = '4.5.0'
+ 
+ from .marionette_test import (
+     CommonTestCase,
+     expectedFailure,
+     MarionetteTestCase,
+     parameterized,
+     run_if_e10s,
+     run_if_manage_instance,
+diff --git a/testing/marionette/harness/requirements.txt b/testing/marionette/harness/requirements.txt
+--- a/testing/marionette/harness/requirements.txt
++++ b/testing/marionette/harness/requirements.txt
+@@ -1,15 +1,15 @@
+ browsermob-proxy >= 0.6.0
+ manifestparser >= 1.1
+-marionette-driver >= 2.6.0
++marionette-driver >= 2.7.0
+ mozcrash >= 0.5
+-mozdevice >= 0.44
++mozdevice >= 1.0.0
+ mozinfo >= 0.8
+ mozlog >= 3.0
+ moznetwork >= 0.21
+ mozprocess >= 0.9
+ mozprofile >= 0.7
+-mozrunner >= 6.15
++mozrunner >= 7.0.1
+ moztest >= 0.8
+ mozversion >= 1.1
+ six
+ wptserve >= 1.3.0

+ 2 - 2
mozilla-release/patches/1471622-5-64a1.patch

@@ -2,7 +2,7 @@
 # User Raphael Pierzina <rpierzina@mozilla.com>
 # User Raphael Pierzina <rpierzina@mozilla.com>
 # Date 1539166273 0
 # Date 1539166273 0
 # Node ID d3ae81a06c155ff71e69fb35a0985dfaf1a684ba
 # Node ID d3ae81a06c155ff71e69fb35a0985dfaf1a684ba
-# Parent  7f2767d1e2d558f4fe685618c23fbc2130869bcb
+# Parent  86da98b8e09b038b0b64d875225c02ce3ea362e4
 Bug 1471622 - Update dependency specifier for mozfile in mozrunner; r=davehunt
 Bug 1471622 - Update dependency specifier for mozfile in mozrunner; r=davehunt
 
 
 Depends on D8096
 Depends on D8096
@@ -20,7 +20,7 @@ diff --git a/testing/mozbase/mozrunner/setup.py b/testing/mozbase/mozrunner/setu
  desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
  desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
  
  
  deps = [
  deps = [
-     'mozdevice>=0.37,<1',
+     'mozdevice>=1.*',
 -    'mozfile==1.*',
 -    'mozfile==1.*',
 +    'mozfile>=1.2',
 +    'mozfile>=1.2',
      'mozinfo>=0.7,<2',
      'mozinfo>=0.7,<2',

+ 2 - 2
mozilla-release/patches/1471625-3-63a1.patch

@@ -2,7 +2,7 @@
 # User Raphael Pierzina <rpierzina@mozilla.com>
 # User Raphael Pierzina <rpierzina@mozilla.com>
 # Date 1530620531 -7200
 # Date 1530620531 -7200
 # Node ID ff2f24e2bab5cdb2e5706d7105e566b7df40c2bc
 # Node ID ff2f24e2bab5cdb2e5706d7105e566b7df40c2bc
-# Parent  3ca502ad698bd4d616e0b4597715a8cbb21bc28f
+# Parent  662ebe6570a7512aa92b293593a3737f130c59ec
 Bug 1471625 - Bump mozinfo to v1.0.0 and update classifiers;r=davehunt
 Bug 1471625 - Bump mozinfo to v1.0.0 and update classifiers;r=davehunt
 
 
 MozReview-Commit-ID: 1Kgl4fCzCyq
 MozReview-Commit-ID: 1Kgl4fCzCyq
@@ -81,7 +81,7 @@ diff --git a/testing/mozbase/mozrunner/setup.py b/testing/mozbase/mozrunner/setu
  desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
  desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
  
  
  deps = [
  deps = [
-     'mozdevice>=0.37,<1',
+     'mozdevice>=1.*',
      'mozfile==1.*',
      'mozfile==1.*',
 -    'mozinfo>=0.7,<1',
 -    'mozinfo>=0.7,<1',
 +    'mozinfo>=0.7,<2',
 +    'mozinfo>=0.7,<2',

+ 2 - 2
mozilla-release/patches/1471888-1-64a1.patch

@@ -2,7 +2,7 @@
 # User Pavel Slepushkin <slepushkin@yandex.ru>
 # User Pavel Slepushkin <slepushkin@yandex.ru>
 # Date 1536692285 0
 # Date 1536692285 0
 # Node ID 0ec82a778cede6ffedfe748d0e104661216b4a01
 # Node ID 0ec82a778cede6ffedfe748d0e104661216b4a01
-# Parent  848e8a34269e479016b105ee59f345bcabe98fdd
+# Parent  8bab629d292e496e9fbe6129823b2468c148c91c
 Bug 1471888 - [mozprofile] Add support for Python 3. r=davehunt
 Bug 1471888 - [mozprofile] Add support for Python 3. r=davehunt
 
 
 Bug 1471888 - [mozprofile] Add support for Python 3.
 Bug 1471888 - [mozprofile] Add support for Python 3.
@@ -512,7 +512,7 @@ diff --git a/testing/mozbase/mozrunner/setup.py b/testing/mozbase/mozrunner/setu
  desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
  desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
  
  
  deps = [
  deps = [
-     'mozdevice>=0.37,<1',
+     'mozdevice>=1.*',
      'mozfile==1.*',
      'mozfile==1.*',
      'mozinfo>=0.7,<2',
      'mozinfo>=0.7,<2',
      'mozlog==3.*',
      'mozlog==3.*',

+ 2 - 2
mozilla-release/patches/1492341-64a1.patch

@@ -2,7 +2,7 @@
 # User Dave Hunt <dhunt@mozilla.com>
 # User Dave Hunt <dhunt@mozilla.com>
 # Date 1537461236 0
 # Date 1537461236 0
 # Node ID 483e333ad24b323c1326a8df7414500c08ae433b
 # Node ID 483e333ad24b323c1326a8df7414500c08ae433b
-# Parent  3c3f039f330e792663ec6521d8bae40977678f5d
+# Parent  382c522f9319d0124de824be0c6eeadd643d0394
 Bug 1492341 - Bump mozrunner version to 7.0.2; r=tcsc
 Bug 1492341 - Bump mozrunner version to 7.0.2; r=tcsc
 
 
 TPS is currently depending on mozrunner v7.0.1, which depends on an earlier version of mozprofile. For TPS to be able to use the latest version of mozprofile we need to release a new version of mozrunner with the recent mozprofile version identifier update.
 TPS is currently depending on mozrunner v7.0.1, which depends on an earlier version of mozprofile. For TPS to be able to use the latest version of mozprofile we need to release a new version of mozrunner with the recent mozprofile version identifier update.
@@ -27,7 +27,7 @@ diff --git a/testing/mozbase/mozrunner/setup.py b/testing/mozbase/mozrunner/setu
  desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
  desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
  
  
  deps = [
  deps = [
-     'mozdevice>=0.37,<1',
+     'mozdevice>=1.*',
      'mozfile==1.*',
      'mozfile==1.*',
      'mozinfo>=0.7,<2',
      'mozinfo>=0.7,<2',
      'mozlog==3.*',
      'mozlog==3.*',

+ 2 - 2
mozilla-release/patches/1494398-64a1.patch

@@ -2,7 +2,7 @@
 # User Aaron Klotz <aklotz@mozilla.com>
 # User Aaron Klotz <aklotz@mozilla.com>
 # Date 1537996780 0
 # Date 1537996780 0
 # Node ID 073b690ff354d293616e47ee15d399306f358766
 # Node ID 073b690ff354d293616e47ee15d399306f358766
-# Parent  18ebc962b42428fac83a211f7a571fd63c9e75fe
+# Parent  7f51ad01b2e774c2f7ef6d90c7931ee79832666f
 Bug 1494398: Bump mozrunner version to 7.1.0 to reflect wait-for-browser changes; r=wlach
 Bug 1494398: Bump mozrunner version to 7.1.0 to reflect wait-for-browser changes; r=wlach
 
 
 Differential Revision: https://phabricator.services.mozilla.com/D6997
 Differential Revision: https://phabricator.services.mozilla.com/D6997
@@ -25,7 +25,7 @@ diff --git a/testing/mozbase/mozrunner/setup.py b/testing/mozbase/mozrunner/setu
  desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
  desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
  
  
  deps = [
  deps = [
-     'mozdevice>=0.37,<1',
+     'mozdevice>=1.*',
      'mozfile==1.*',
      'mozfile==1.*',
      'mozinfo>=0.7,<2',
      'mozinfo>=0.7,<2',
      'mozlog==3.*',
      'mozlog==3.*',

+ 2 - 2
mozilla-release/patches/1501227-1-65a1.patch

@@ -2,7 +2,7 @@
 # User Raphael Pierzina <rpierzina@mozilla.com>
 # User Raphael Pierzina <rpierzina@mozilla.com>
 # Date 1540370108 0
 # Date 1540370108 0
 # Node ID 765bb35eb5b9dcf5199b45401863a1948c9b714c
 # Node ID 765bb35eb5b9dcf5199b45401863a1948c9b714c
-# Parent  b2236365a741795498d3c804afa92649df2c1a00
+# Parent  d8ac1960c68bf0c1bf517f3f718217a07b994d2f
 Bug 1501227 - Bump mozrunner to version 7.2.0; r=davehunt
 Bug 1501227 - Bump mozrunner to version 7.2.0; r=davehunt
 
 
 Differential Revision: https://phabricator.services.mozilla.com/D9527
 Differential Revision: https://phabricator.services.mozilla.com/D9527
@@ -25,7 +25,7 @@ diff --git a/testing/mozbase/mozrunner/setup.py b/testing/mozbase/mozrunner/setu
  desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
  desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
  
  
  deps = [
  deps = [
-     'mozdevice>=0.37,<1',
+     'mozdevice>=1.*',
      'mozfile>=1.2',
      'mozfile>=1.2',
      'mozinfo>=0.7,<2',
      'mozinfo>=0.7,<2',
      'mozlog==3.*',
      'mozlog==3.*',

+ 2 - 2
mozilla-release/patches/1501227-2-65a1.patch

@@ -2,7 +2,7 @@
 # User Raphael Pierzina <rpierzina@mozilla.com>
 # User Raphael Pierzina <rpierzina@mozilla.com>
 # Date 1540370125 0
 # Date 1540370125 0
 # Node ID 11dac3c17f666e91972181598b47a5069e30fa74
 # Node ID 11dac3c17f666e91972181598b47a5069e30fa74
-# Parent  b639a52ed604583b59a3f21a81a5621d0a551da6
+# Parent  2e5a1a4f8805a17f7591eb9abba0dc00cfa0a346
 Bug 1501227 - Update version requirement on mozprofile for mozrunner; r=davehunt
 Bug 1501227 - Update version requirement on mozprofile for mozrunner; r=davehunt
 
 
 Depends on D9527
 Depends on D9527
@@ -16,7 +16,7 @@ diff --git a/testing/mozbase/mozrunner/setup.py b/testing/mozbase/mozrunner/setu
  desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
  desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
  
  
  deps = [
  deps = [
-     'mozdevice>=0.37,<1',
+     'mozdevice>=1.*',
      'mozfile>=1.2',
      'mozfile>=1.2',
      'mozinfo>=0.7,<2',
      'mozinfo>=0.7,<2',
      'mozlog==3.*',
      'mozlog==3.*',

+ 5 - 5
mozilla-release/patches/1502190-3-65a1.patch

@@ -2,7 +2,7 @@
 # User Bob Clary <bclary@bclary.com>
 # User Bob Clary <bclary@bclary.com>
 # Date 1540572697 25200
 # Date 1540572697 25200
 # Node ID 43d1a6288fb9b9104dd477344f128ed69e6c6ec0
 # Node ID 43d1a6288fb9b9104dd477344f128ed69e6c6ec0
-# Parent  07ff44ad60e9185053fe627e62c65b43cb594bd8
+# Parent  47f971c58eb9250aaf882b55d61c1ddad0ba4f80
 Bug 1502190 - bump mozdevice requirements for raptor, marionette, mozrunner, r=gbrown.
 Bug 1502190 - bump mozdevice requirements for raptor, marionette, mozrunner, r=gbrown.
 
 
 diff --git a/testing/marionette/harness/requirements.txt b/testing/marionette/harness/requirements.txt
 diff --git a/testing/marionette/harness/requirements.txt b/testing/marionette/harness/requirements.txt
@@ -11,16 +11,16 @@ diff --git a/testing/marionette/harness/requirements.txt b/testing/marionette/ha
 @@ -1,13 +1,13 @@
 @@ -1,13 +1,13 @@
  browsermob-proxy >= 0.6.0
  browsermob-proxy >= 0.6.0
  manifestparser >= 1.1
  manifestparser >= 1.1
- marionette-driver >= 2.6.0
+ marionette-driver >= 2.7.0
  mozcrash >= 0.5
  mozcrash >= 0.5
--mozdevice >= 0.44
+-mozdevice >= 1.0.0
 +mozdevice >= 1.1.5
 +mozdevice >= 1.1.5
  mozinfo >= 0.8
  mozinfo >= 0.8
  mozlog >= 3.0
  mozlog >= 3.0
  moznetwork >= 0.21
  moznetwork >= 0.21
  mozprocess >= 0.9
  mozprocess >= 0.9
  mozprofile >= 0.7
  mozprofile >= 0.7
- mozrunner >= 6.15
+ mozrunner >= 7.0.1
  moztest >= 0.8
  moztest >= 0.8
  mozversion >= 1.1
  mozversion >= 1.1
 diff --git a/testing/mozbase/mozrunner/setup.py b/testing/mozbase/mozrunner/setup.py
 diff --git a/testing/mozbase/mozrunner/setup.py b/testing/mozbase/mozrunner/setup.py
@@ -35,7 +35,7 @@ diff --git a/testing/mozbase/mozrunner/setup.py b/testing/mozbase/mozrunner/setu
  desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
  desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
  
  
  deps = [
  deps = [
--    'mozdevice>=0.37,<1',
+-    'mozdevice>=1.*',
 +    'mozdevice>=1.1.5',
 +    'mozdevice>=1.1.5',
      'mozfile>=1.2',
      'mozfile>=1.2',
      'mozinfo>=0.7,<2',
      'mozinfo>=0.7,<2',

+ 3 - 3
mozilla-release/patches/1504117-3-65a1.patch

@@ -2,7 +2,7 @@
 # User Bob Clary <bclary@bclary.com>
 # User Bob Clary <bclary@bclary.com>
 # Date 1541171042 25200
 # Date 1541171042 25200
 # Node ID 3389e75974f74fd6ecd2ed2824eb69a89e4772f8
 # Node ID 3389e75974f74fd6ecd2ed2824eb69a89e4772f8
-# Parent  dbb2e4d35c1e30b32b81668d40c7b3604251e1b8
+# Parent  04827e108f006b2d8899a16906f611e94de671c4
 Bug 1504117 - [mozdevice] Bump mozdevice requirements to 1.1.6 for raptor, marionette, mozrunner, r=gbrown.
 Bug 1504117 - [mozdevice] Bump mozdevice requirements to 1.1.6 for raptor, marionette, mozrunner, r=gbrown.
 
 
 diff --git a/testing/marionette/harness/requirements.txt b/testing/marionette/harness/requirements.txt
 diff --git a/testing/marionette/harness/requirements.txt b/testing/marionette/harness/requirements.txt
@@ -11,7 +11,7 @@ diff --git a/testing/marionette/harness/requirements.txt b/testing/marionette/ha
 @@ -1,13 +1,13 @@
 @@ -1,13 +1,13 @@
  browsermob-proxy >= 0.6.0
  browsermob-proxy >= 0.6.0
  manifestparser >= 1.1
  manifestparser >= 1.1
- marionette-driver >= 2.6.0
+ marionette-driver >= 2.7.0
  mozcrash >= 0.5
  mozcrash >= 0.5
 -mozdevice >= 1.1.5
 -mozdevice >= 1.1.5
 +mozdevice >= 1.1.6
 +mozdevice >= 1.1.6
@@ -20,7 +20,7 @@ diff --git a/testing/marionette/harness/requirements.txt b/testing/marionette/ha
  moznetwork >= 0.21
  moznetwork >= 0.21
  mozprocess >= 0.9
  mozprocess >= 0.9
  mozprofile >= 0.7
  mozprofile >= 0.7
- mozrunner >= 6.15
+ mozrunner >= 7.0.1
  moztest >= 0.8
  moztest >= 0.8
  mozversion >= 1.1
  mozversion >= 1.1
 diff --git a/testing/mozbase/mozrunner/setup.py b/testing/mozbase/mozrunner/setup.py
 diff --git a/testing/mozbase/mozrunner/setup.py b/testing/mozbase/mozrunner/setup.py

+ 7 - 7
mozilla-release/patches/1559975-04-69a1.patch

@@ -2,7 +2,7 @@
 # User Marco Castelluccio <mcastelluccio@mozilla.com>
 # User Marco Castelluccio <mcastelluccio@mozilla.com>
 # Date 1561729677 0
 # Date 1561729677 0
 # Node ID 4c7e3b86897452bd41104b676a16d97a77296eb9
 # Node ID 4c7e3b86897452bd41104b676a16d97a77296eb9
-# Parent  8c93ec16127085d96cd81a043d8925127d702baf
+# Parent  5c5c8a4fca6b2007a259b14f2ab86422a8cca577
 Bug 1559975 - Add future imports to testing/remotecppunittests.py and testing/runcppunittests.py and remove them from py2 exclusion list r=ahal
 Bug 1559975 - Add future imports to testing/remotecppunittests.py and testing/runcppunittests.py and remove them from py2 exclusion list r=ahal
 
 
 Differential Revision: https://phabricator.services.mozilla.com/D35246
 Differential Revision: https://phabricator.services.mozilla.com/D35246
@@ -26,7 +26,7 @@ diff --git a/testing/remotecppunittests.py b/testing/remotecppunittests.py
  import mozcrash
  import mozcrash
  import mozfile
  import mozfile
  import mozinfo
  import mozinfo
-@@ -55,50 +56,50 @@ class RemoteCPPUnitTests(cppunittests.CP
+@@ -48,50 +49,50 @@ class RemoteCPPUnitTests(cppunittests.CP
  
  
      def push_libs(self):
      def push_libs(self):
          if self.options.local_apk:
          if self.options.local_apk:
@@ -49,7 +49,7 @@ diff --git a/testing/remotecppunittests.py b/testing/remotecppunittests.py
                                  subprocess.check_output(cmd)
                                  subprocess.check_output(cmd)
                                  # xz strips the ".so" file suffix.
                                  # xz strips the ".so" file suffix.
                                  os.rename(local_file[:-3], local_file)
                                  os.rename(local_file[:-3], local_file)
-                         self.device.pushFile(local_file, remote_file)
+                         self.device.push(local_file, remote_file)
  
  
          elif self.options.local_lib:
          elif self.options.local_lib:
 -            for file in os.listdir(self.options.local_lib):
 -            for file in os.listdir(self.options.local_lib):
@@ -62,7 +62,7 @@ diff --git a/testing/remotecppunittests.py b/testing/remotecppunittests.py
 +                    print("Pushing {}..".format(path), file=sys.stderr)
 +                    print("Pushing {}..".format(path), file=sys.stderr)
 +                    remote_file = posixpath.join(self.remote_bin_dir, path)
 +                    remote_file = posixpath.join(self.remote_bin_dir, path)
 +                    local_file = os.path.join(self.options.local_lib, path)
 +                    local_file = os.path.join(self.options.local_lib, path)
-                     self.device.pushFile(local_file, remote_file)
+                     self.device.push(local_file, remote_file)
              # Additional libraries may be found in a sub-directory such as
              # Additional libraries may be found in a sub-directory such as
              # "lib/armeabi-v7a"
              # "lib/armeabi-v7a"
              for subdir in ["assets", "lib"]:
              for subdir in ["assets", "lib"]:
@@ -81,15 +81,15 @@ diff --git a/testing/remotecppunittests.py b/testing/remotecppunittests.py
 -                                local_file = os.path.join(root, file)
 -                                local_file = os.path.join(root, file)
 +                                    self.remote_bin_dir, path)
 +                                    self.remote_bin_dir, path)
 +                                local_file = os.path.join(root, path)
 +                                local_file = os.path.join(root, path)
-                                 self.device.pushFile(local_file, remote_file)
+                                 self.device.push(local_file, remote_file)
  
  
      def push_progs(self, progs):
      def push_progs(self, progs):
          for local_file in progs:
          for local_file in progs:
              remote_file = posixpath.join(
              remote_file = posixpath.join(
                  self.remote_bin_dir, os.path.basename(local_file))
                  self.remote_bin_dir, os.path.basename(local_file))
-             self.device.pushFile(local_file, remote_file)
+             self.device.push(local_file, remote_file)
  
  
-@@ -263,26 +264,26 @@ def run_test_harness(options, args):
+@@ -221,26 +222,26 @@ def run_test_harness(options, args):
      return result
      return result
  
  
  
  

+ 3 - 3
mozilla-release/patches/1638954-78a1.patch

@@ -2,7 +2,7 @@
 # User Geoff Brown <gbrown@mozilla.com>
 # User Geoff Brown <gbrown@mozilla.com>
 # Date 1590677150 0
 # Date 1590677150 0
 # Node ID 9069294ec5cb3ec8f254e244886408d288772078
 # Node ID 9069294ec5cb3ec8f254e244886408d288772078
-# Parent  269899041c312d9dad69c0be1888de16e9c661eb
+# Parent  f107ad811bf40e61866d225d3485b15c9aaa6b44
 Bug 1638954 - Run 'mach cppunittest' with python 3; r=bc
 Bug 1638954 - Run 'mach cppunittest' with python 3; r=bc
 
 
 Differential Revision: https://phabricator.services.mozilla.com/D77258
 Differential Revision: https://phabricator.services.mozilla.com/D77258
@@ -31,7 +31,7 @@ diff --git a/mach b/mach
 diff --git a/testing/remotecppunittests.py b/testing/remotecppunittests.py
 diff --git a/testing/remotecppunittests.py b/testing/remotecppunittests.py
 --- a/testing/remotecppunittests.py
 --- a/testing/remotecppunittests.py
 +++ b/testing/remotecppunittests.py
 +++ b/testing/remotecppunittests.py
-@@ -86,17 +86,17 @@ class RemoteCPPUnitTests(cppunittests.CP
+@@ -79,17 +79,17 @@ class RemoteCPPUnitTests(cppunittests.CP
              # Additional libraries may be found in a sub-directory such as
              # Additional libraries may be found in a sub-directory such as
              # "lib/armeabi-v7a"
              # "lib/armeabi-v7a"
              for subdir in ["assets", "lib"]:
              for subdir in ["assets", "lib"]:
@@ -45,7 +45,7 @@ diff --git a/testing/remotecppunittests.py b/testing/remotecppunittests.py
                                  remote_file = posixpath.join(
                                  remote_file = posixpath.join(
                                      self.remote_bin_dir, path)
                                      self.remote_bin_dir, path)
                                  local_file = os.path.join(root, path)
                                  local_file = os.path.join(root, path)
-                                 self.device.pushFile(local_file, remote_file)
+                                 self.device.push(local_file, remote_file)
  
  
      def push_progs(self, progs):
      def push_progs(self, progs):
          for local_file in progs:
          for local_file in progs:

+ 8 - 0
mozilla-release/patches/series

@@ -1631,6 +1631,8 @@ servo-19927-60a1.patch
 1435244-60a1.patch
 1435244-60a1.patch
 1435366-60a1.patch
 1435366-60a1.patch
 1435180-60a1.patch
 1435180-60a1.patch
+1434664-1-60a1.patch
+1434664-2-60a1.patch
 1435307-60a1.patch
 1435307-60a1.patch
 1435286-60a1.patch
 1435286-60a1.patch
 1435382-60a1.patch
 1435382-60a1.patch
@@ -2851,6 +2853,7 @@ servo-20254-60a1.patch
 1443232-1-60a1.patch
 1443232-1-60a1.patch
 1443232-2-60a1.patch
 1443232-2-60a1.patch
 1428430-60a1.patch
 1428430-60a1.patch
+1440714-03-60a1.patch
 1443228-60a1.patch
 1443228-60a1.patch
 1444175-60a1.patch
 1444175-60a1.patch
 1443807-1-60a1.patch
 1443807-1-60a1.patch
@@ -3121,6 +3124,7 @@ NOBUG-20180313-inspector-61a1.patch
 1438839-3-61a1.patch
 1438839-3-61a1.patch
 1438839-4-61a1.patch
 1438839-4-61a1.patch
 1440714-05-61a1.patch
 1440714-05-61a1.patch
+1440714-07-61a1.patch
 1439006-61a1.patch
 1439006-61a1.patch
 1397795-1-61a1.patch
 1397795-1-61a1.patch
 1369711-1-61a1.patch
 1369711-1-61a1.patch
@@ -3791,6 +3795,9 @@ servo-20619-61a1.patch
 1457030-61a1.patch
 1457030-61a1.patch
 1456422-61a1.patch
 1456422-61a1.patch
 1440714-16-61a1.patch
 1440714-16-61a1.patch
+1440714-17-61a1.patch
+1440714-18-61a1.patch
+1440714-19-61a1.patch
 887889-1-61a1.patch
 887889-1-61a1.patch
 887889-2-61a1.patch
 887889-2-61a1.patch
 887889-3-61a1.patch
 887889-3-61a1.patch
@@ -3842,6 +3849,7 @@ servo-20619-61a1.patch
 1458199-61a1.patch
 1458199-61a1.patch
 1433968-3only-61a1.patch
 1433968-3only-61a1.patch
 1454888-61a1.patch
 1454888-61a1.patch
+1458280-61a1.patch
 1451168-1-61a1.patch
 1451168-1-61a1.patch
 1451168-2-61a1.patch
 1451168-2-61a1.patch
 1458588-61a1.patch
 1458588-61a1.patch