Browse Source

Remove mozdevice changes / patches

Ian Neal 3 months ago
parent
commit
8a05dbc448

+ 0 - 223
mozilla-release/patches/1190701-64a1.patch

@@ -1,223 +0,0 @@
-# HG changeset patch
-# User Edwin Gao <egao@mozilla.com>
-# Date 1538505578 0
-# Node ID 1c7f3cf86aed6b4476ffa66605f373b2ff74f960
-# Parent  3ee8f62f5081cc37725c7fdd59289f502a342ad5
-Bug 1190701 - make ADBAndroidMixin.is_app_installed() unambiguous r=bc,gbrown
-
-Behavior changes:
-- ADBAndroidMixin.is_app_installed() will now perform a strict check on `app_name` provided. Previously, the behavior was to do a fuzzy match, where as long as the provided `app_name` matched some item on the list it would return True. Now, the exact string as shown when user calls `adb shell > pm list packages` will be required in order to generate a True return value.
-
-Other changes:
-- bumped mozdevice version to 1.1.2 reflecting minor behavior change.
-- addition of unit tests for ADBAndroidMixin.is_app_installed() method call and surrounding helper methods such as mocked fixtures, manifest changes.
-
-Differential Revision: https://phabricator.services.mozilla.com/D7322
-
-diff --git a/testing/mozbase/mozdevice/mozdevice/adb_android.py b/testing/mozbase/mozdevice/mozdevice/adb_android.py
---- a/testing/mozbase/mozdevice/mozdevice/adb_android.py
-+++ b/testing/mozbase/mozdevice/mozdevice/adb_android.py
-@@ -277,34 +277,32 @@ class ADBAndroid(ADBDevice):
-         data = self.command_output(cmd, timeout=timeout)
-         if data.find('Success') == -1:
-             raise ADBError("install failed for %s. Got: %s" %
-                            (apk_path, data))
- 
-     def is_app_installed(self, app_name, timeout=None):
-         """Returns True if an app is installed on the device.
- 
--        :param str app_name: The name of the app to be checked.
--        :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 ADB constructor is used.
--        :type timeout: integer or None
-+        :param str app_name: name of the app to be checked.
-+        :param timeout: maximum time in seconds for any spawned
-+            adb process to complete before throwing an ADBTimeoutError.
-+            This timeout is per adb call. If it is not specified,
-+            the value set in the ADB constructor is used.
-+        :type timeout: integer or None
-+
-         :raises: * ADBTimeoutError
-                  * ADBError
-         """
-         pm_error_string = 'Error: Could not access the Package Manager'
-         data = self.shell_output("pm list package %s" % app_name, timeout=timeout)
-         if pm_error_string in data:
-             raise ADBError(pm_error_string)
--        if app_name not in data:
--            return False
--        return True
-+        output = [line for line in data.splitlines() if line.strip()]
-+        return any(['package:{}'.format(app_name) == out for out in output])
- 
-     def launch_application(self, app_name, activity_name, intent, url=None,
-                            extras=None, wait=True, fail_if_running=True,
-                            timeout=None):
-         """Launches an Android application
- 
-         :param str app_name: Name of application (e.g. `com.android.chrome`)
-         :param str activity_name: Name of activity to launch (e.g. `.Main`)
-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 = '1.1.1'
-+PACKAGE_VERSION = '1.1.2'
- 
- deps = ['mozfile >= 1.0',
-         'mozlog >= 3.0',
-         'moznetwork >= 0.24',
-         'mozprocess >= 0.19',
-         ]
- 
- setup(name=PACKAGE_NAME,
-diff --git a/testing/mozbase/mozdevice/tests/conftest.py.1190701.later b/testing/mozbase/mozdevice/tests/conftest.py.1190701.later
-new file mode 100644
---- /dev/null
-+++ b/testing/mozbase/mozdevice/tests/conftest.py.1190701.later
-@@ -0,0 +1,71 @@
-+--- conftest.py
-++++ conftest.py
-+@@ -22,17 +22,17 @@ def random_tcp_port():
-+     return randint(8000, 12000)
-+ 
-+ 
-+ @pytest.fixture(autouse=True)
-+ def mock_command_output(monkeypatch):
-+     """Monkeypatches the ADBDevice.command_output() method call.
-+ 
-+     Instead of calling the concrete method implemented in adb.py::ADBDevice,
-+-    this method simply returns a string representaton of the command that was
-++    this method simply returns a string representation of the command that was
-+     received.
-+ 
-+     :param object monkeypatch: pytest provided fixture for mocking.
-+     """
-+     def command_output_wrapper(object, cmd, timeout):
-+         """Actual monkeypatch implementation of the comand_output method call.
-+ 
-+         :param object object: placeholder object representing ADBDevice
-+@@ -43,16 +43,49 @@ def mock_command_output(monkeypatch):
-+         print(str(cmd))
-+         return str(cmd)
-+ 
-+     monkeypatch.setattr(mozdevice.ADBDevice,
-+                         'command_output', command_output_wrapper)
-+ 
-+ 
-+ @pytest.fixture(autouse=True)
-++def mock_shell_output(monkeypatch):
-++    """Monkeypatches the ADBDevice.shell_output() method call.
-++
-++    Instead of returning the output of an adb call, this method will
-++    return appropriate string output. Content of the string output is
-++    in line with the calling method's expectations.
-++
-++    :param object monkeypatch: pytest provided fixture for mocking.
-++    """
-++    def shell_output_wrapper(object, cmd, env=None, cwd=None, timeout=None, root=False):
-++        """Actual monkeypatch implementation of the shell_output method call.
-++
-++        :param object object: placeholder object representing ADBDevice
-++        :param str cmd: command to be executed
-++        :param env: contains the environment variable
-++        :type env: dict or None
-++        :param cwd: The directory from which to execute.
-++        :type cwd: str or None
-++        :param timeout: unused parameter tp represent timeout threshold
-++        :returns: string - string representation of a simulated call to adb
-++        """
-++        if 'pm list package error' in cmd:
-++            return 'Error: Could not access the Package Manager'
-++        elif 'pm list package none' in cmd:
-++            return ''
-++        elif 'pm list package' in cmd:
-++            apps = ["org.mozilla.fennec", "org.mozilla.geckoview_example"]
-++            return ('package:{}\n' * len(apps)).format(*apps)
-++
-++    monkeypatch.setattr(mozdevice.ADBDevice, 'shell_output', shell_output_wrapper)
-++
-++
-++@pytest.fixture(autouse=True)
-+ def mock_adb_object():
-+     """Patches the __init__ method call when instantiating ADBAndroid.
-+ 
-+     This is the key to test abstract methods implemented in ADBDevice.
-+     ADBAndroid normally requires instantiated objects including but not
-+     limited to ADBDevice in order to execute its commands.
-+ 
-+     With a pytest-mock patch, we are able to mock the initialization of
-diff --git a/testing/mozbase/mozdevice/tests/manifest.ini.1190701.later b/testing/mozbase/mozdevice/tests/manifest.ini.1190701.later
-new file mode 100644
---- /dev/null
-+++ b/testing/mozbase/mozdevice/tests/manifest.ini.1190701.later
-@@ -0,0 +1,8 @@
-+--- manifest.ini
-++++ manifest.ini
-+@@ -1,4 +1,5 @@
-+ [DEFAULT]
-+ subsuite = mozbase, os == "linux"
-+ skip-if = python == 3
-+ [test_socket_connection.py]
-++[test_is_app_installed.py]
-diff --git a/testing/mozbase/mozdevice/tests/test_is_app_installed.py b/testing/mozbase/mozdevice/tests/test_is_app_installed.py
-new file mode 100644
---- /dev/null
-+++ b/testing/mozbase/mozdevice/tests/test_is_app_installed.py
-@@ -0,0 +1,44 @@
-+#!/usr/bin/env python
-+
-+from __future__ import absolute_import
-+
-+import pytest
-+import mozunit
-+
-+from mozdevice import ADBError
-+
-+
-+def test_is_app_installed(mock_adb_object):
-+    """Tests that is_app_installed returns True if app is installed."""
-+    assert mock_adb_object.is_app_installed(
-+        'org.mozilla.geckoview_example')
-+
-+
-+def test_is_app_installed_not_installed(mock_adb_object):
-+    """Tests that is_app_installed returns False if provided app_name
-+    does not resolve."""
-+    assert not mock_adb_object.is_app_installed(
-+        'some_random_name')
-+
-+
-+def test_is_app_installed_partial_name(mock_adb_object):
-+    """Tests that is_app_installed returns False if provided app_name
-+    is only a partial match."""
-+    assert not mock_adb_object.is_app_installed(
-+        'fennec')
-+
-+
-+def test_is_app_installed_package_manager_error(mock_adb_object):
-+    """Tests that is_app_installed is able to raise an exception."""
-+    with pytest.raises(ADBError):
-+        mock_adb_object.is_app_installed('error')
-+
-+
-+def test_is_app_installed_no_installed_package_found(mock_adb_object):
-+    """Tests that is_app_installed is able to handle scenario
-+    where no installed packages are found."""
-+    assert not mock_adb_object.is_app_installed('none')
-+
-+
-+if __name__ == '__main__':
-+    mozunit.main()

+ 0 - 48
mozilla-release/patches/1428708-2-67a1.patch

@@ -1,48 +0,0 @@
-# HG changeset patch
-# User AndreiH <ahutusoru@mozilla.com>
-# Date 1549307996 0
-# Node ID baee8b94d34e3139d1cc22eae0c6da42053d0769
-# Parent  4e436ec5cf1489551140e7b5f1ecde73e3c4a364
-Bug 1428708 - [mozdevice] Bump version number and prepare for Python 3 release r=davehunt
-
-Differential Revision: https://phabricator.services.mozilla.com/D18553
-
-diff --git a/testing/mozbase/mozdevice/setup.cfg b/testing/mozbase/mozdevice/setup.cfg
-new file mode 100644
---- /dev/null
-+++ b/testing/mozbase/mozdevice/setup.cfg
-@@ -0,0 +1,2 @@
-+[bdist_wheel]
-+universal = 1
-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,26 +3,26 @@
- # 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 = '2.0.1'
-+PACKAGE_VERSION = '3.0.0'
- 
- deps = ['mozlog >= 3.0']
- 
- setup(name=PACKAGE_NAME,
-       version=PACKAGE_VERSION,
-       description="Mozilla-authored device management",
-       long_description="see https://firefox-source-docs.mozilla.org/mozbase/index.html",
-       classifiers=['Programming Language :: Python :: 2.7',
--                   'Programming Language :: Python :: 2 :: Only'],
-+                   'Programming Language :: Python :: 3.5'],
-       # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
-       keywords='',
-       author='Mozilla Automation and Testing Team',
-       author_email='tools@lists.mozilla.org',
-       url='https://wiki.mozilla.org/Auto-tools/Projects/Mozbase',
-       license='MPL',
-       packages=['mozdevice'],
-       include_package_data=True,

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

@@ -1,53 +0,0 @@
-# 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

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

@@ -1,31 +0,0 @@
-# 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,

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

@@ -1,57 +0,0 @@
-# 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

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

@@ -1,403 +0,0 @@
-# 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",

+ 0 - 40
mozilla-release/patches/1440714-13-61a1.patch

@@ -1,40 +0,0 @@
-# HG changeset patch
-# User Bob Clary <bclary@bclary.com>
-# Date 1523427149 25200
-# Node ID 7bdb7ce278c1ea4de5658f14ff3585b7bdedb0fb
-# Parent  de0b20d81f08817039307bfa704801a4f34ddbfd
-Bug 1440714 - make sure to use root=True when determining/creating test_root, r=gbrown
-
-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
-@@ -805,24 +805,25 @@ class ADBDevice(ADBCommand):
-             if attempt != max_attempts:
-                 time.sleep(20)
- 
-         raise ADBError("Unable to set up test root using paths: [%s]"
-                        % ", ".join(paths))
- 
-     def _try_test_root(self, test_root):
-         base_path, sub_path = posixpath.split(test_root)
--        if not self.is_dir(base_path):
-+        if not self.is_dir(base_path, root=True):
-             return False
- 
-         try:
-             dummy_dir = posixpath.join(test_root, 'dummy')
--            if self.is_dir(dummy_dir):
--                self.rm(dummy_dir, recursive=True)
--            self.mkdir(dummy_dir, parents=True)
-+            if self.is_dir(dummy_dir, root=True):
-+                self.rm(dummy_dir, recursive=True, root=True)
-+            self.mkdir(dummy_dir, parents=True, root=True)
-+            self.chmod(test_root, recursive=True, root=True)
-         except ADBError:
-             self._logger.debug("%s is not writable" % test_root)
-             return False
- 
-         return True
- 
-     # Host Command methods
- 

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

@@ -5,2443 +5,6 @@
 # Parent  7bc9cdc13e72d98c1700debfea3e37aee4ab2354
 # Parent  7bc9cdc13e72d98c1700debfea3e37aee4ab2354
 Bug 1440714 - Remove DeviceManagerADB and Droid classes from mozdevice; r=bc
 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
 diff --git a/testing/xpcshell/runxpcshelltests.py b/testing/xpcshell/runxpcshelltests.py
 --- a/testing/xpcshell/runxpcshelltests.py
 --- a/testing/xpcshell/runxpcshelltests.py
 +++ b/testing/xpcshell/runxpcshelltests.py
 +++ b/testing/xpcshell/runxpcshelltests.py

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

@@ -1,29 +0,0 @@
-# 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,

+ 0 - 103
mozilla-release/patches/1482898-63a1.patch

@@ -1,103 +0,0 @@
-# HG changeset patch
-# User William Lachance <wlachance@mozilla.com>
-# Date 1534171872 14400
-# Node ID 6f69e808328401eba4d3984f5c755f82ebbcd631
-# Parent  983ebf8312a68c6eb2a10ac9c3e2f9a39ae1a51f
-Bug 1482898 - Support running adb commands in mozdevice as non-root;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
-@@ -134,34 +134,38 @@ class ADBCommand(object):
-     """
- 
-     def __init__(self,
-                  adb='adb',
-                  adb_host=None,
-                  adb_port=None,
-                  logger_name='adb',
-                  timeout=300,
--                 verbose=False):
-+                 verbose=False,
-+                 require_root=True):
-         """Initializes the ADBCommand object.
- 
-         :param str adb: path to adb executable. Defaults to 'adb'.
-         :param adb_host: host of the adb server.
-         :type adb_host: str or None
-         :param adb_port: port of the adb server.
-         :type adb_port: integer or None
-         :param str logger_name: logging logger name. Defaults to 'adb'.
-+        :param bool verbose: provide verbose output
-+        :param bool require_root: check that we have root permissions on device
- 
-         :raises: * ADBError
-                  * ADBTimeoutError
-         """
-         if self.__class__ == ADBCommand:
-             raise NotImplementedError
- 
-         self._logger = self._get_logger(logger_name)
-         self._verbose = verbose
-+        self._require_root = require_root
-         self._adb_path = adb
-         self._adb_host = adb_host
-         self._adb_port = adb_port
-         self._timeout = timeout
-         self._polling_interval = 0.1
-         self._adb_version = ''
- 
-         self._logger.debug("%s: %s" % (self.__class__.__name__,
-@@ -805,25 +809,25 @@ class ADBDevice(ADBCommand):
-             if attempt != max_attempts:
-                 time.sleep(20)
- 
-         raise ADBError("Unable to set up test root using paths: [%s]"
-                        % ", ".join(paths))
- 
-     def _try_test_root(self, test_root):
-         base_path, sub_path = posixpath.split(test_root)
--        if not self.is_dir(base_path, root=True):
-+        if not self.is_dir(base_path, root=self._require_root):
-             return False
- 
-         try:
-             dummy_dir = posixpath.join(test_root, 'dummy')
--            if self.is_dir(dummy_dir, root=True):
--                self.rm(dummy_dir, recursive=True, root=True)
--            self.mkdir(dummy_dir, parents=True, root=True)
--            self.chmod(test_root, recursive=True, root=True)
-+            if self.is_dir(dummy_dir, root=self._require_root):
-+                self.rm(dummy_dir, recursive=True, root=self._require_root)
-+            self.mkdir(dummy_dir, parents=True, root=self._require_root)
-+            self.chmod(test_root, recursive=True, root=self._require_root)
-         except ADBError:
-             self._logger.debug("%s is not writable" % test_root)
-             return False
- 
-         return True
- 
-     # Host Command methods
- 
-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 = '1.0.0'
-+PACKAGE_VERSION = '1.0.1'
- 
- deps = ['mozfile >= 1.0',
-         'mozlog >= 3.0',
-         'moznetwork >= 0.24',
-         'mozprocess >= 0.19',
-         ]
- 
- setup(name=PACKAGE_NAME,

+ 0 - 257
mozilla-release/patches/1484238-64a1.patch

@@ -1,257 +0,0 @@
-# HG changeset patch
-# User egao <egao@mozilla.com>
-# Date 1536070542 0
-# Node ID 1ea388fd649a82bde842f39f47c99f6c4efd3848
-# Parent  5800f04e622d308d2b2829995a07f5311c1dcd5b
-Bug 1484238 - Add an 'adb_reverse' command to mozdevice.ADBAndroid r=gbrown,bc
-
-Differential Revision: https://phabricator.services.mozilla.com/D4775
-
-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
-@@ -509,16 +509,19 @@ class ADBHost(ADBCommand):
- class ADBDevice(ADBCommand):
-     """ADBDevice is an abstract base class which provides methods which
-     can be used to interact with the associated Android or B2G based
-     device. It must be used via one of the concrete implementations in
-     :class:`ADBAndroid` or :class:`ADBB2G`.
-     """
-     __metaclass__ = ABCMeta
- 
-+    SOCKET_DIRECTON_REVERSE = "reverse"
-+    SOCKET_DIRECTON_FORWARD = "forward"
-+
-     def __init__(self,
-                  device=None,
-                  adb='adb',
-                  adb_host=None,
-                  adb_port=None,
-                  test_root='',
-                  logger_name='adb',
-                  timeout=300,
-@@ -885,105 +888,171 @@ class ADBDevice(ADBCommand):
- 
-         :raises: * ADBTimeoutError
-                  * ADBError
-         """
-         return ADBCommand.command_output(self, cmds,
-                                          device_serial=self._device_serial,
-                                          timeout=timeout)
- 
--    # Port forwarding methods
-+    # Networking methods
- 
-     def _validate_port(self, port, is_local=True):
-         """Validate a port forwarding specifier. Raises ValueError on failure.
- 
-         :param str port: The port specifier to validate
-         :param bool is_local: Flag indicating whether the port represents a local port.
-         """
-         prefixes = ["tcp", "localabstract", "localreserved", "localfilesystem", "dev"]
- 
-         if not is_local:
-             prefixes += ["jdwp"]
- 
-         parts = port.split(":", 1)
-         if len(parts) != 2 or parts[0] not in prefixes:
--            raise ValueError("Invalid forward specifier %s" % port)
--
--    def forward(self, local, remote, allow_rebind=True, timeout=None):
--        """Forward a local port to a specific port on the device.
--
--        Ports are specified in the form:
--            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)
--
--        :param str local: Local port to forward
--        :param str remote: Remote port to which to forward
--        :param bool allow_rebind: Don't error if the local port is already forwarded
-+            raise ValueError("Invalid port specifier %s" % port)
-+
-+    def _validate_direction(self, direction):
-+        """Validate direction of the socket connection. Raises ValueError on failure.
-+
-+        :param str direction: The socket direction specifier to validate
-+        :raises: * ValueError
-+        """
-+        if direction not in [self.SOCKET_DIRECTON_FORWARD, self.SOCKET_DIRECTON_REVERSE]:
-+            raise ValueError('Invalid direction specifier {}'.format(direction))
-+
-+    def create_socket_connection(self, direction, local, remote, allow_rebind=True, timeout=None):
-+        """Sets up a socket connection in the specified direction.
-+
-+        :param str direction: Direction of the socket connection
-+        :param str local: Local port
-+        :param str remote: Remote port
-+        :param bool allow_rebind: Do not fail if port is already bound
-         :param timeout: The maximum time in seconds
-             for any spawned adb process to complete before throwing
-             an ADBTimeoutError. If it is not specified, the value
-             set in the ADBDevice constructor is used.
-         :type timeout: integer or None
-         :raises: * ValueError
-                  * ADBTimeoutError
-                  * ADBError
-         """
--
-+        # validate socket direction, and local and remote port formatting.
-+        self._validate_direction(direction)
-         for port, is_local in [(local, True), (remote, False)]:
-             self._validate_port(port, is_local=is_local)
- 
--        cmd = ["forward", local, remote]
-+        cmd = [direction, local, remote]
-+
-         if not allow_rebind:
-             cmd.insert(1, "--no-rebind")
-+
-+        # execute commands to establish socket connection.
-         self.command_output(cmd, timeout=timeout)
- 
--    def list_forwards(self, timeout=None):
--        """Return a list of tuples specifying active forwards
-+    def list_socket_connections(self, direction, timeout=None):
-+        """Return a list of tuples specifying active socket connectionss.
- 
-         Return values are of the form (device, local, remote).
- 
-+        :param str direction: 'forward' to list forward socket connections
-+                              'reverse' to list reverse socket connections
-         :param timeout: The maximum time in seconds
-             for any spawned adb process to complete before throwing
-             an ADBTimeoutError. If it is not specified, the value
-             set in the ADBDevice constructor is used.
-         :type timeout: integer or None
--        :raises: * ADBTimeoutError
--                 * ADBError
--        """
--        forwards = self.command_output(["forward", "--list"], timeout=timeout)
--        return [tuple(line.split(" ")) for line in forwards.splitlines() if line.strip()]
--
--    def remove_forwards(self, local=None, timeout=None):
--        """Remove existing port forwards.
--
-+        :raises: * ValueError
-+                 * ADBTimeoutError
-+                 * ADBError
-+        """
-+        self._validate_direction(direction)
-+
-+        cmd = [direction, "--list"]
-+        output = self.command_output(cmd, timeout=timeout)
-+        return [tuple(line.split(" ")) for line in output.splitlines() if line.strip()]
-+
-+    def remove_socket_connections(self, direction, local=None, timeout=None):
-+        """Remove existing socket connections for a given direction.
-+
-+        :param str direction: 'forward' to remove forward socket connection
-+                              'reverse' to remove reverse socket connection
-         :param local: local port specifier as for ADBDevice.forward. If local
-             is not specified removes all forwards.
-         :type local: str or None
-         :param timeout: The maximum time in seconds
-             for any spawned adb process to complete before throwing
-             an ADBTimeoutError. If it is not specified, the value
-             set in the ADBDevice constructor is used.
-         :type timeout: integer or None
-         :raises: * ValueError
-                  * ADBTimeoutError
-                  * ADBError
-         """
--        cmd = ["forward"]
-+        self._validate_direction(direction)
-+
-+        cmd = [direction]
-+
-         if local is None:
-             cmd.extend(["--remove-all"])
-         else:
-             self._validate_port(local, is_local=True)
-             cmd.extend(["--remove", local])
- 
-         self.command_output(cmd, timeout=timeout)
- 
-+    # Legacy port forward methods
-+
-+    def forward(self, local, remote, allow_rebind=True, timeout=None):
-+        """Forward a local port to a specific port on the device.
-+
-+        See `ADBDevice.create_socket_connection`.
-+        """
-+        self.create_socket_connection(self.SOCKET_DIRECTON_FORWARD,
-+                                      local, remote, allow_rebind, timeout)
-+
-+    def list_forwards(self, timeout=None):
-+        """Return a list of tuples specifying active forwards.
-+
-+        See `ADBDevice.list_socket_connection`.
-+        """
-+        return self.list_socket_connections(self.SOCKET_DIRECTON_FORWARD, timeout)
-+
-+    def remove_forwards(self, local=None, timeout=None):
-+        """Remove existing port forwards.
-+
-+        See `ADBDevice.remove_socket_connection`.
-+        """
-+        self.remove_socket_connections(self.SOCKET_DIRECTON_FORWARD, local, timeout)
-+
-+    # Legacy port reverse methods
-+
-+    def reverse(self, local, remote, allow_rebind=True, timeout=None):
-+        """Sets up a reverse socket connection from device to host.
-+
-+        See `ADBDevice.create_socket_connection`.
-+        """
-+        self.create_socket_connection(self.SOCKET_DIRECTON_REVERSE,
-+                                      local, remote, allow_rebind, timeout)
-+
-+    def list_reverses(self, timeout=None):
-+        """Returns a list of tuples showing active reverse socket connections.
-+
-+        See `ADBDevice.list_socket_connection`.
-+        """
-+        return self.list_socket_connections(self.SOCKET_DIRECTON_REVERSE, timeout)
-+
-+    def remove_reverses(self, local=None, timeout=None):
-+        """Remove existing reverse socket connections.
-+
-+        See `ADBDevice.remove_socket_connection`.
-+        """
-+        self.remove_socket_connections(self.SOCKET_DIRECTON_REVERSE,
-+                                       local, timeout)
-+
-     # Device Shell methods
- 
-     def shell(self, cmd, env=None, cwd=None, timeout=None, root=False):
-         """Executes a shell command on the device.
- 
-         :param str cmd: The command to be executed.
-         :param env: Contains the environment variables and
-             their values.
-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 = '1.1.0'
-+PACKAGE_VERSION = '1.1.1'
- 
- deps = ['mozfile >= 1.0',
-         'mozlog >= 3.0',
-         'moznetwork >= 0.24',
-         'mozprocess >= 0.19',
-         ]
- 
- setup(name=PACKAGE_NAME,

+ 0 - 29
mozilla-release/patches/1487130-63a1.patch

@@ -1,29 +0,0 @@
-# HG changeset patch
-# User Bob Clary <bclary@bclary.com>
-# Date 1535565472 25200
-# Node ID 1a993af26c1335241575bf3235934570bd23bc0c
-# Parent  a433f0c5c042e10d8d0917503186d85fb33f4b25
-Bug 1487130 - [mozdevice] Update version to 1.1.0, r=wlach
-
-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 = '1.0.1'
-+PACKAGE_VERSION = '1.1.0'
- 
- deps = ['mozfile >= 1.0',
-         'mozlog >= 3.0',
-         'moznetwork >= 0.24',
-         'mozprocess >= 0.19',
-         ]
- 
- setup(name=PACKAGE_NAME,

+ 0 - 57
mozilla-release/patches/1499102-64a1.patch

@@ -1,57 +0,0 @@
-# HG changeset patch
-# User Bob Clary <bclary@bclary.com>
-# Date 1539662580 25200
-# Node ID 24d8d0ea578a8d683794237561a825abe8b1d32e
-# Parent  f30059f3b8028de26d36d4ac9304bae7e4d20937
-Bug 1499102 - [mozdevice] Allow HOST:PORT as device serial number, bump mozdevice to version 1.1.3, r=gbrown.
-
-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
-@@ -655,18 +655,23 @@ class ADBDevice(ADBCommand):
-                 raise ValueError("ADBDevice called with multiple devices "
-                                  "attached and no device specified")
-             elif len(devices) == 0:
-                 # We could error here, but this way we'll wait-for-device before we next
-                 # run a command, which seems more friendly
-                 return
-             device = devices[0]
- 
-+        # Allow : in device serial if it matches a tcpip device serial.
-+        re_device_serial_tcpip = re.compile(r'[^:]+:[0-9]+$')
-+
-         def is_valid_serial(serial):
--            return ":" not in serial or serial.startswith("usb:")
-+            return serial.startswith("usb:") or \
-+                re_device_serial_tcpip.match(serial) is not None or \
-+                ":" not in serial
- 
-         if isinstance(device, (str, unicode)):
-             # Treat this as a device serial
-             if not is_valid_serial(device):
-                 raise ValueError("Device serials containing ':' characters are "
-                                  "invalid. Pass the output from "
-                                  "ADBHost.devices() for the device instead")
-             return device
-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 = '1.1.2'
-+PACKAGE_VERSION = '1.1.3'
- 
- deps = ['mozfile >= 1.0',
-         'mozlog >= 3.0',
-         'moznetwork >= 0.24',
-         'mozprocess >= 0.19',
-         ]
- 
- setup(name=PACKAGE_NAME,

+ 0 - 29
mozilla-release/patches/1502190-2-65a1.patch

@@ -1,29 +0,0 @@
-# HG changeset patch
-# User Bob Clary <bclary@bclary.com>
-# Date 1540572697 25200
-# Node ID dec76ef6d620d436cc618324dbff32196eb4d5a6
-# Parent  f741259071982f3ce8b49dc08029aa68cf2934f9
-Bug 1502190 - release mozdevice 1.1.5, r=gbrown.
-
-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 = '1.1.3'
-+PACKAGE_VERSION = '1.1.5'
- 
- deps = ['mozfile >= 1.0',
-         'mozlog >= 3.0',
-         'moznetwork >= 0.24',
-         'mozprocess >= 0.19',
-         ]
- 
- setup(name=PACKAGE_NAME,

+ 0 - 29
mozilla-release/patches/1504117-2-65a1.patch

@@ -1,29 +0,0 @@
-# HG changeset patch
-# User Bob Clary <bclary@bclary.com>
-# Date 1541169773 25200
-# Node ID 9a7adcaed611db0b494d77f3f235ef8d273f40a6
-# Parent  631000de70272e7052db47459fa6a5b12af1b377
-Bug 1504117 - [mozdevice] Release mozdevice 1.1.6, r=gbrown.
-
-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 = '1.1.5'
-+PACKAGE_VERSION = '1.1.6'
- 
- deps = ['mozfile >= 1.0',
-         'mozlog >= 3.0',
-         'moznetwork >= 0.24',
-         'mozprocess >= 0.19',
-         ]
- 
- setup(name=PACKAGE_NAME,

+ 0 - 260
mozilla-release/patches/1506385-65a1.patch

@@ -1,260 +0,0 @@
-# HG changeset patch
-# User William Lachance <wlachance@mozilla.com>
-# Date 1541881028 0
-# Node ID e93794d169f164f424c591f248a5aa657b7adfb7
-# Parent  c4075a2c6e9f854cd640af0027e43bb11860a8cd
-Summary: Bug 1506385 - Remove b2g support and unnecessary dependencies from mozdevice r=bc
-
-Differential Revision: https://phabricator.services.mozilla.com/D11564
-
-diff --git a/testing/mozbase/docs/mozdevice.rst.1506385.later b/testing/mozbase/docs/mozdevice.rst.1506385.later
-new file mode 100644
---- /dev/null
-+++ b/testing/mozbase/docs/mozdevice.rst.1506385.later
-@@ -0,0 +1,45 @@
-+--- mozdevice.rst
-++++ mozdevice.rst
-+@@ -1,12 +1,12 @@
-+-:mod:`mozdevice` --- Interact with Android or B2G devices
-+-=========================================================
-++:mod:`mozdevice` --- Interact with Android devices
-++==================================================
-+ 
-+-Mozdevice provides several interfaces to interact with an Android or B2G
-++Mozdevice provides several interfaces to interact with an Android
-+ device such as a phone, tablet, or emulator. It allows you to push
-+ files to these types of devices, launch processes, and more. There are
-+ currently two available interfaces:
-+ 
-+ * :ref:`ADB`: Uses the Android Debugger Protocol explicitly
-+ 
-+ .. automodule:: mozdevice
-+ 
-+@@ -111,26 +111,16 @@ Application management methods
-+ .. automethod:: ADBAndroid.is_app_installed
-+ .. automethod:: ADBAndroid.launch_application
-+ .. automethod:: ADBAndroid.launch_fennec
-+ .. automethod:: ADBAndroid.launch_geckoview_example
-+ .. automethod:: ADBAndroid.stop_application
-+ .. automethod:: ADBAndroid.uninstall_app
-+ .. automethod:: ADBAndroid.update_app
-+ 
-+-ADBB2G
-+-``````
-+-.. autoclass:: ADBB2G
-+-
-+-Informational methods
-+-+++++++++++++++++++++
-+-.. automethod:: ADBB2G.get_battery_percentage
-+-.. automethod:: ADBB2G.get_info
-+-.. automethod:: ADBB2G.get_memory_total
-+-
-+ ADBProcess
-+ ``````````
-+ .. autoclass:: mozdevice.ADBProcess
-+ 
-+ ADBError
-+ ````````
-+ .. autoexception:: mozdevice.ADBError
-+ 
-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
-@@ -2,12 +2,11 @@
- # 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, ADBProcessError, ADBRootError, ADBTimeoutError
- from .adb import ADBProcess, ADBCommand, ADBHost, ADBDevice
- from .adb_android import ADBAndroid
--from .adb_b2g import ADBB2G
- 
- __all__ = ['ADBError', 'ADBProcessError', 'ADBRootError', 'ADBTimeoutError',
--           'ADBProcess', 'ADBCommand', 'ADBHost', 'ADBDevice', 'ADBAndroid', 'ADBB2G']
-+           'ADBProcess', 'ADBCommand', 'ADBHost', 'ADBDevice', 'ADBAndroid']
-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
-@@ -503,19 +503,19 @@ class ADBHost(ADBCommand):
-                     "\n# adb kill-server\n# adb start-server\n"
-                     "\nor maybe configure your udev rules.",
-                     devices)
-         return devices
- 
- 
- class ADBDevice(ADBCommand):
-     """ADBDevice is an abstract base class which provides methods which
--    can be used to interact with the associated Android or B2G based
--    device. It must be used via one of the concrete implementations in
--    :class:`ADBAndroid` or :class:`ADBB2G`.
-+    can be used to interact with the associated Android-based
-+    device. It must be used via the concrete implementation in
-+    :class:`ADBAndroid`.
-     """
-     __metaclass__ = ABCMeta
- 
-     SOCKET_DIRECTON_REVERSE = "reverse"
-     SOCKET_DIRECTON_FORWARD = "forward"
- 
-     def __init__(self,
-                  device=None,
-diff --git a/testing/mozbase/mozdevice/mozdevice/adb_b2g.py b/testing/mozbase/mozdevice/mozdevice/adb_b2g.py
-deleted file mode 100644
---- a/testing/mozbase/mozdevice/mozdevice/adb_b2g.py
-+++ /dev/null
-@@ -1,124 +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 traceback
--
--import mozfile
--
--from .adb import ADBDevice, ADBError
--
--
--class ADBB2G(ADBDevice):
--    """ADBB2G implements :class:`ADBDevice` providing B2G-specific
--    functionality.
--
--    ::
--
--       from mozdevice import ADBB2G
--
--       adbdevice = ADBB2G()
--       print adbdevice.list_files("/mnt/sdcard")
--       if adbdevice.process_exist("b2g"):
--           print "B2G is running"
--    """
--
--    def get_battery_percentage(self, timeout=None):
--        """Returns the battery charge as a percentage.
--
--        :param timeout: optional integer specifying the maximum time in
--            seconds for any spawned adb process to complete before
--            throwing an ADBTimeoutError.
--            This timeout is per adb call. The total time spent
--            may exceed this value. If it is not specified, the value
--            set in the ADBDevice constructor is used.
--        :returns: battery charge as a percentage.
--        :raises: * ADBTimeoutError
--                 * ADBError
--        """
--        with mozfile.NamedTemporaryFile() as tf:
--            self.pull('/sys/class/power_supply/battery/capacity', tf.name,
--                      timeout=timeout)
--            try:
--                with open(tf.name) as tf2:
--                    return tf2.read().splitlines()[0]
--            except Exception as e:
--                raise ADBError(traceback.format_exception_only(
--                    type(e), e)[0].strip())
--
--    def get_memory_total(self, timeout=None):
--        """Returns the total memory available with units.
--
--        :param timeout: optional integer specifying the maximum time in
--            seconds for any spawned adb process to complete before
--            throwing an ADBTimeoutError.
--            This timeout is per adb call. The total time spent
--            may exceed this value. If it is not specified, the value
--            set in the ADBDevice constructor is used.
--        :returns: memory total with units.
--        :raises: * ADBTimeoutError
--                 * ADBError
--        """
--        meminfo = {}
--        with mozfile.NamedTemporaryFile() as tf:
--            self.pull('/proc/meminfo', tf.name, timeout=timeout)
--            try:
--                with open(tf.name) as tf2:
--                    for line in tf2.read().splitlines():
--                        key, value = line.split(':')
--                        meminfo[key] = value.strip()
--            except Exception as e:
--                raise ADBError(traceback.format_exception_only(
--                    type(e), e)[0].strip())
--        return meminfo['MemTotal']
--
--    def get_info(self, directive=None, timeout=None):
--        """
--        Returns a dictionary of information strings about the device.
--
--        :param directive: information you want to get. Options are:
--             - `battery` - battery charge as a percentage
--             - `disk` - total, free, available bytes on disk
--             - `id` - unique id of the device
--             - `memtotal` - total memory available on the device
--             - `os` - name of the os
--             - `process` - list of running processes (same as ps)
--             - `systime` - system time of the device
--             - `uptime` - uptime of the device
--
--            If `directive` is `None`, will return all available information
--        :param timeout: optional integer specifying the maximum time in
--            seconds for any spawned adb process to complete before
--            throwing an ADBTimeoutError.
--            This timeout is per adb call. The total time spent
--            may exceed this value. If it is not specified, the value
--            set in the ADB constructor is used.
--        :raises: * ADBTimeoutError
--                 * ADBError
--        """
--        info = super(ADBB2G, self).get_info(directive=directive,
--                                            timeout=timeout)
--
--        directives = ['memtotal']
--        if directive in directives:
--            directives = [directive]
--
--        if 'memtotal' in directives:
--            info['memtotal'] = self.get_memory_total(timeout=timeout)
--        return info
--
--    def is_device_ready(self, timeout=None):
--        """Returns True if the device is ready.
--
--        :param timeout: optional integer specifying the maximum time in
--            seconds for any spawned adb process to complete before
--            throwing an ADBTimeoutError.
--            This timeout is per adb call. The total time spent
--            may exceed this value. If it is not specified, the value
--            set in the ADB constructor is used.
--        :raises: * ADBTimeoutError
--                 * ADBError
--        """
--        return self.shell_bool('ls /sbin', timeout=timeout)
-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,23 +3,19 @@
- # 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 = '1.1.6'
-+PACKAGE_VERSION = '2.0'
- 
--deps = ['mozfile >= 1.0',
--        'mozlog >= 3.0',
--        'moznetwork >= 0.24',
--        'mozprocess >= 0.19',
--        ]
-+deps = ['mozlog >= 3.0']
- 
- setup(name=PACKAGE_NAME,
-       version=PACKAGE_VERSION,
-       description="Mozilla-authored device management",
-       long_description="see https://firefox-source-docs.mozilla.org/mozbase/index.html",
-       classifiers=['Programming Language :: Python :: 2.7',
-                    'Programming Language :: Python :: 2 :: Only'],
-       # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers

+ 0 - 56
mozilla-release/patches/1524150-67a1.patch

@@ -1,56 +0,0 @@
-# HG changeset patch
-# User Bob Clary <bclary@bclary.com>
-# Date 1548995756 28800
-# Node ID 3feead6581fcbfdcd9e82e0c2efc978486268dc9
-# Parent  12113fa42f1930accb3f550955acb5f1c7d9a685
-Bug 1524150 - [mozdevice] remove -s <serialno> from ADBProcess-based error messages, r=gbrown.
-
-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
-@@ -40,18 +40,22 @@ class ADBProcess(object):
-         if not self.stdout_file or self.stdout_file.closed:
-             content = ""
-         else:
-             self.stdout_file.seek(0, os.SEEK_SET)
-             content = self.stdout_file.read().rstrip()
-         return content
- 
-     def __str__(self):
-+        # Remove -s <serialno> from the error message to allow bug suggestions
-+        # to be independent of the individual failing device.
-+        arg_string = ' '.join(self.args)
-+        arg_string = re.sub(' -s \w+', '', arg_string)
-         return ('args: %s, exitcode: %s, stdout: %s' % (
--            ' '.join(self.args), self.exitcode, self.stdout))
-+            arg_string, self.exitcode, self.stdout))
- 
- # ADBError, ADBRootError, and ADBTimeoutError are treated
- # differently in order that unhandled ADBRootErrors and
- # ADBTimeoutErrors can be handled distinctly from ADBErrors.
- 
- 
- class ADBError(Exception):
-     """ADBError is raised in situations where a command executed on a
-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 = '2.0'
-+PACKAGE_VERSION = '2.0.1'
- 
- deps = ['mozlog >= 3.0']
- 
- setup(name=PACKAGE_NAME,
-       version=PACKAGE_VERSION,
-       description="Mozilla-authored device management",
-       long_description="see https://firefox-source-docs.mozilla.org/mozbase/index.html",
-       classifiers=['Programming Language :: Python :: 2.7',

+ 2 - 2
mozilla-release/patches/1527610-69a1.patch

@@ -2,7 +2,7 @@
 # User Nikki S <nikkisharpley@gmail.com>
 # User Nikki S <nikkisharpley@gmail.com>
 # Date 1558451060 0
 # Date 1558451060 0
 # Node ID 2180deaa2c68afd96ad39b6a0cba9c3d45a49c62
 # Node ID 2180deaa2c68afd96ad39b6a0cba9c3d45a49c62
-# Parent  a628fd0d5d52e65e644e635e5ffc5002a9b1cce0
+# Parent  4af50fa1b9ef20cac138c863e064f35e7b1e3d09
 Bug 1527610 - [mozlog] Library fails after python 3 update; TypeError: vars() argument must have _dict_ attribute r=ahal
 Bug 1527610 - [mozlog] Library fails after python 3 update; TypeError: vars() argument must have _dict_ attribute r=ahal
 
 
 Updated from Differential D20458.
 Updated from Differential D20458.
@@ -84,7 +84,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>=3.0.1',
+     'mozdevice>=1.1.6',
      'mozfile>=1.2',
      'mozfile>=1.2',
      'mozinfo>=0.7,<2',
      'mozinfo>=0.7,<2',
 -    'mozlog~=4.1',
 -    'mozlog~=4.1',

+ 0 - 114
mozilla-release/patches/1533517-67a1.patch

@@ -1,114 +0,0 @@
-# HG changeset patch
-# User Kartikaya Gupta <kgupta@mozilla.com>
-# Date 1552398951 0
-# Node ID 1aa0df07fbddd6007b3a8023e32509b55aabdc46
-# Parent  c8da01c4ba1c9fb4b535a51150720bf8708ec056
-Bug 1533517 - [mozdevice] Remove FirefoxOS candidate test root paths. r=bc
-
-Differential Revision: https://phabricator.services.mozilla.com/D22952
-
-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,13 +1,13 @@
- browsermob-proxy >= 0.8.0
- manifestparser >= 1.1
- marionette-driver >= 2.8.0
- mozcrash >= 1.1.0
--mozdevice >= 3.0.0
-+mozdevice >= 3.0.1
- mozinfo >= 1.0.0
- mozlog >= 4.0
- moznetwork >= 0.27
- mozprocess >= 1.0.0
- mozprofile >= 2.2.0
- mozrunner >= 7.4.0
- moztest >= 0.8
- mozversion >= 2.1.0
-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
-@@ -773,18 +773,16 @@ class ADBDevice(ADBCommand):
-         The first time test_root it is called it determines and caches a value
-         for the test root on the device. It determines the appropriate test
-         root by attempting to create a 'dummy' directory on each of a list of
-         directories and returning the first successful directory as the
-         test_root value.
- 
-         The default list of directories checked by test_root are:
- 
--        - /storage/sdcard0/tests
--        - /storage/sdcard1/tests
-         - /sdcard/tests
-         - /mnt/sdcard/tests
-         - /data/local/tests
- 
-         You may override the default list by providing a test_root argument to
-         the :class:`ADBDevice` constructor which will then be used when
-         attempting to create the 'dummy' directory.
- 
-@@ -793,19 +791,17 @@ class ADBDevice(ADBCommand):
-                  * ADBError
-         """
-         if self._test_root is not None:
-             return self._test_root
- 
-         if self._initial_test_root:
-             paths = [self._initial_test_root]
-         else:
--            paths = ['/storage/sdcard0/tests',
--                     '/storage/sdcard1/tests',
--                     '/sdcard/tests',
-+            paths = ['/sdcard/tests',
-                      '/mnt/sdcard/tests',
-                      '/data/local/tests']
- 
-         max_attempts = 3
-         for attempt in range(1, max_attempts + 1):
-             for test_root in paths:
-                 self._logger.debug("Setting test root to %s attempt %d of %d" %
-                                    (test_root, attempt, max_attempts))
-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 = '3.0.0'
-+PACKAGE_VERSION = '3.0.1'
- 
- deps = ['mozlog >= 3.0']
- 
- setup(name=PACKAGE_NAME,
-       version=PACKAGE_VERSION,
-       description="Mozilla-authored device management",
-       long_description="see https://firefox-source-docs.mozilla.org/mozbase/index.html",
-       classifiers=['Programming Language :: Python :: 2.7',
-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
-@@ -7,17 +7,17 @@ from __future__ import absolute_import
- from setuptools import setup, find_packages
- 
- PACKAGE_NAME = 'mozrunner'
- PACKAGE_VERSION = '7.4.0'
- 
- desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""
- 
- deps = [
--    'mozdevice>=1.1.6',
-+    'mozdevice>=3.0.1',
-     'mozfile>=1.2',
-     'mozinfo>=0.7,<2',
-     'mozlog~=4.0',
-     'mozprocess>=0.23,<2',
-     'mozprofile~=2.1',
-     'six>=1.10.0,<2',
- ]
- 

+ 2 - 2
mozilla-release/patches/1550565-68a1.patch

@@ -2,7 +2,7 @@
 # User Nikki S <nikkisharpley@gmail.com>
 # User Nikki S <nikkisharpley@gmail.com>
 # Date 1557484189 0
 # Date 1557484189 0
 # Node ID 757f1c83278b03859f4f23e85e22e732c2bc313f
 # Node ID 757f1c83278b03859f4f23e85e22e732c2bc313f
-# Parent  ed3b4c335e736fd7248900f9a15010d41a9e6b22
+# Parent  2a0d16df2e1313eb2de12b6ce74c9db03299cce2
 Bug 1550565 - [mozlog] Update mozlog version number to 4.1 r=jgraham
 Bug 1550565 - [mozlog] Update mozlog version number to 4.1 r=jgraham
 
 
 The Mozlog version number needed to be updated to 4.1 for the new
 The Mozlog version number needed to be updated to 4.1 for the new
@@ -65,7 +65,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>=3.0.1',
+     'mozdevice>=1.1.6',
      'mozfile>=1.2',
      'mozfile>=1.2',
      'mozinfo>=0.7,<2',
      'mozinfo>=0.7,<2',
 -    'mozlog~=4.0',
 -    'mozlog~=4.0',

+ 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  5c5c8a4fca6b2007a259b14f2ab86422a8cca577
+# Parent  699d95e025f8a357cb868edc11f6684d3d2241cd
 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
-@@ -48,50 +49,50 @@ class RemoteCPPUnitTests(cppunittests.CP
+@@ -55,50 +56,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.push(local_file, remote_file)
+                         self.device.pushFile(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.push(local_file, remote_file)
+                     self.device.pushFile(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.push(local_file, remote_file)
+                                 self.device.pushFile(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.push(local_file, remote_file)
+             self.device.pushFile(local_file, remote_file)
  
  
-@@ -221,26 +222,26 @@ def run_test_harness(options, args):
+@@ -263,26 +264,26 @@ def run_test_harness(options, args):
      return result
      return result
  
  
  
  

+ 0 - 41
mozilla-release/patches/1567642-1-71a1.patch

@@ -405,47 +405,6 @@ diff --git a/testing/mozbase/mozcrash/mozcrash/mozcrash.py b/testing/mozbase/moz
                                             CREATE_ALWAYS,
                                             CREATE_ALWAYS,
                                             FILE_ATTRIBUTE_NORMAL,
                                             FILE_ATTRIBUTE_NORMAL,
                                             None)
                                             None)
-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
-@@ -290,17 +290,17 @@ class ADBCommand(object):
-                                    (' '.join(adb_process.args),
-                                     timeout,
-                                     adb_process.timedout,
-                                     adb_process.exitcode,
-                                     output))
- 
-             return output
-         finally:
--            if adb_process and isinstance(adb_process.stdout_file, file):
-+            if adb_process and isinstance(adb_process.stdout_file, io.IOBase):
-                 adb_process.stdout_file.close()
- 
- 
- class ADBHost(ADBCommand):
-     """ADBHost provides a basic interface to adb host commands
-     which do not target a specific device.
- 
-     ::
-@@ -1912,17 +1912,17 @@ class ADBDevice(ADBCommand):
-                     self._logger.error('get_process_list: %s %s\n%s' % (
-                         header, line, traceback.format_exc()))
-                     raise ADBError('get_process_list: %s: %s: %s' % (
-                         header, line, adb_process))
-                 line = adb_process.stdout_file.readline()
-             self._logger.debug('get_process_list: %s' % ret)
-             return ret
-         finally:
--            if adb_process and isinstance(adb_process.stdout_file, file):
-+            if adb_process and isinstance(adb_process.stdout_file, io.IOBase):
-                 adb_process.stdout_file.close()
- 
-     def kill(self, pids, sig=None, attempts=3, wait=5,
-              timeout=None, root=False):
-         """Kills processes on the device given a list of process ids.
- 
-         :param list pids: process ids to be killed.
-         :param sig: signal to be sent to the process.
 diff --git a/testing/mozbase/mozinfo/mozinfo/mozinfo.py b/testing/mozbase/mozinfo/mozinfo/mozinfo.py
 diff --git a/testing/mozbase/mozinfo/mozinfo/mozinfo.py b/testing/mozbase/mozinfo/mozinfo/mozinfo.py
 --- a/testing/mozbase/mozinfo/mozinfo/mozinfo.py
 --- a/testing/mozbase/mozinfo/mozinfo/mozinfo.py
 +++ b/testing/mozbase/mozinfo/mozinfo/mozinfo.py
 +++ b/testing/mozbase/mozinfo/mozinfo/mozinfo.py

+ 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  f107ad811bf40e61866d225d3485b15c9aaa6b44
+# Parent  5b47d07f3bb48d37d8e80c3a68d86e740e21129c
 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
-@@ -79,17 +79,17 @@ class RemoteCPPUnitTests(cppunittests.CP
+@@ -86,17 +86,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.push(local_file, remote_file)
+                                 self.device.pushFile(local_file, remote_file)
  
  
      def push_progs(self, progs):
      def push_progs(self, progs):
          for local_file in progs:
          for local_file in progs:

+ 0 - 17
mozilla-release/patches/series

@@ -1639,8 +1639,6 @@ 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
@@ -2861,7 +2859,6 @@ 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
@@ -3132,7 +3129,6 @@ 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
@@ -3804,7 +3800,6 @@ servo-20619-61a1.patch
 1456422-61a1.patch
 1456422-61a1.patch
 1440714-16-61a1.patch
 1440714-16-61a1.patch
 1440714-17-61a1.patch
 1440714-17-61a1.patch
-1440714-18-61a1.patch
 1440714-19-61a1.patch
 1440714-19-61a1.patch
 887889-1-61a1.patch
 887889-1-61a1.patch
 887889-2-61a1.patch
 887889-2-61a1.patch
@@ -6783,27 +6778,15 @@ NOBUG-nukemozlinker-25319.patch
 1890514-11511.patch
 1890514-11511.patch
 1893340-PARTIAL-NOTESTS-11511.patch
 1893340-PARTIAL-NOTESTS-11511.patch
 1897801-about-seamonkey-mozilla-25319.patch
 1897801-about-seamonkey-mozilla-25319.patch
-1440714-13-61a1.patch
 1449035-62a1.patch
 1449035-62a1.patch
-1482898-63a1.patch
 1485454-1-63a1.patch
 1485454-1-63a1.patch
 1485454-2-63a1.patch
 1485454-2-63a1.patch
-1487130-63a1.patch
-1484238-64a1.patch
-1190701-64a1.patch
 1488468-1-64a1.patch
 1488468-1-64a1.patch
-1499102-64a1.patch
-1502190-2-65a1.patch
-1504117-2-65a1.patch
-1506385-65a1.patch
 1519358-66a1.patch
 1519358-66a1.patch
-1524150-67a1.patch
-1428708-2-67a1.patch
 1526990-67a1.patch
 1526990-67a1.patch
 1530794-1-67a1.patch
 1530794-1-67a1.patch
 1530794-2-67a1.patch
 1530794-2-67a1.patch
 1532919-67a1.patch
 1532919-67a1.patch
-1533517-67a1.patch
 1524961-68a1.patch
 1524961-68a1.patch
 1550565-68a1.patch
 1550565-68a1.patch
 1527610-69a1.patch
 1527610-69a1.patch