summaryrefslogtreecommitdiff
path: root/third_party/catapult/devil/devil
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/catapult/devil/devil')
-rw-r--r--third_party/catapult/devil/devil/__init__.py7
-rw-r--r--third_party/catapult/devil/devil/android/__init__.py3
-rw-r--r--third_party/catapult/devil/devil/android/apk_helper.py164
-rwxr-xr-xthird_party/catapult/devil/devil/android/apk_helper_test.py169
-rw-r--r--third_party/catapult/devil/devil/android/app_ui.py243
-rw-r--r--third_party/catapult/devil/devil/android/app_ui_test.py191
-rw-r--r--third_party/catapult/devil/devil/android/battery_utils.py699
-rwxr-xr-xthird_party/catapult/devil/devil/android/battery_utils_test.py694
-rw-r--r--third_party/catapult/devil/devil/android/constants/__init__.py3
-rw-r--r--third_party/catapult/devil/devil/android/constants/chrome.py57
-rw-r--r--third_party/catapult/devil/devil/android/constants/file_system.py5
-rw-r--r--third_party/catapult/devil/devil/android/decorators.py176
-rw-r--r--third_party/catapult/devil/devil/android/decorators_test.py332
-rw-r--r--third_party/catapult/devil/devil/android/device_blacklist.py80
-rw-r--r--third_party/catapult/devil/devil/android/device_blacklist_test.py38
-rw-r--r--third_party/catapult/devil/devil/android/device_errors.py180
-rwxr-xr-xthird_party/catapult/devil/devil/android/device_errors_test.py72
-rw-r--r--third_party/catapult/devil/devil/android/device_list.py52
-rw-r--r--third_party/catapult/devil/devil/android/device_signal.py41
-rw-r--r--third_party/catapult/devil/devil/android/device_temp_file.py63
-rw-r--r--third_party/catapult/devil/devil/android/device_test_case.py54
-rw-r--r--third_party/catapult/devil/devil/android/device_utils.py2640
-rwxr-xr-xthird_party/catapult/devil/devil/android/device_utils_devicetest.py229
-rwxr-xr-xthird_party/catapult/devil/devil/android/device_utils_test.py2900
-rw-r--r--third_party/catapult/devil/devil/android/fastboot_utils.py256
-rwxr-xr-xthird_party/catapult/devil/devil/android/fastboot_utils_test.py375
-rw-r--r--third_party/catapult/devil/devil/android/flag_changer.py300
-rw-r--r--third_party/catapult/devil/devil/android/flag_changer_devicetest.py88
-rwxr-xr-xthird_party/catapult/devil/devil/android/flag_changer_test.py135
-rw-r--r--third_party/catapult/devil/devil/android/forwarder.py464
-rw-r--r--third_party/catapult/devil/devil/android/install_commands.py57
-rw-r--r--third_party/catapult/devil/devil/android/logcat_monitor.py255
-rwxr-xr-xthird_party/catapult/devil/devil/android/logcat_monitor_test.py230
-rw-r--r--third_party/catapult/devil/devil/android/md5sum.py120
-rwxr-xr-xthird_party/catapult/devil/devil/android/md5sum_test.py237
-rw-r--r--third_party/catapult/devil/devil/android/perf/__init__.py3
-rw-r--r--third_party/catapult/devil/devil/android/perf/cache_control.py15
-rw-r--r--third_party/catapult/devil/devil/android/perf/perf_control.py210
-rw-r--r--third_party/catapult/devil/devil/android/perf/perf_control_devicetest.py38
-rw-r--r--third_party/catapult/devil/devil/android/perf/surface_stats_collector.py186
-rw-r--r--third_party/catapult/devil/devil/android/perf/thermal_throttle.py135
-rw-r--r--third_party/catapult/devil/devil/android/ports.py178
-rw-r--r--third_party/catapult/devil/devil/android/sdk/__init__.py6
-rw-r--r--third_party/catapult/devil/devil/android/sdk/aapt.py43
-rw-r--r--third_party/catapult/devil/devil/android/sdk/adb_compatibility_devicetest.py230
-rw-r--r--third_party/catapult/devil/devil/android/sdk/adb_wrapper.py917
-rwxr-xr-xthird_party/catapult/devil/devil/android/sdk/adb_wrapper_devicetest.py118
-rwxr-xr-xthird_party/catapult/devil/devil/android/sdk/adb_wrapper_test.py59
-rw-r--r--third_party/catapult/devil/devil/android/sdk/build_tools.py51
-rw-r--r--third_party/catapult/devil/devil/android/sdk/dexdump.py31
-rw-r--r--third_party/catapult/devil/devil/android/sdk/fastboot.py98
-rw-r--r--third_party/catapult/devil/devil/android/sdk/gce_adb_wrapper.py154
-rw-r--r--third_party/catapult/devil/devil/android/sdk/intent.py129
-rw-r--r--third_party/catapult/devil/devil/android/sdk/keyevent.py63
-rw-r--r--third_party/catapult/devil/devil/android/sdk/shared_prefs.py420
-rwxr-xr-xthird_party/catapult/devil/devil/android/sdk/shared_prefs_test.py171
-rw-r--r--third_party/catapult/devil/devil/android/sdk/split_select.py63
-rw-r--r--third_party/catapult/devil/devil/android/sdk/test/data/push_directory/push_directory_contents.txt1
-rw-r--r--third_party/catapult/devil/devil/android/sdk/test/data/push_file.txt1
-rw-r--r--third_party/catapult/devil/devil/android/sdk/version_codes.py20
-rw-r--r--third_party/catapult/devil/devil/android/settings.py273
-rw-r--r--third_party/catapult/devil/devil/android/tools/__init__.py3
-rwxr-xr-xthird_party/catapult/devil/devil/android/tools/adb_run_shell_cmd.py61
-rwxr-xr-xthird_party/catapult/devil/devil/android/tools/cpufreq.py87
-rwxr-xr-xthird_party/catapult/devil/devil/android/tools/device_monitor.py231
-rwxr-xr-xthird_party/catapult/devil/devil/android/tools/device_monitor_test.py168
-rwxr-xr-xthird_party/catapult/devil/devil/android/tools/device_recovery.py208
-rwxr-xr-xthird_party/catapult/devil/devil/android/tools/device_status.py313
-rwxr-xr-xthird_party/catapult/devil/devil/android/tools/flash_device.py70
-rwxr-xr-xthird_party/catapult/devil/devil/android/tools/keyboard.py129
-rwxr-xr-xthird_party/catapult/devil/devil/android/tools/provision_devices.py637
-rwxr-xr-xthird_party/catapult/devil/devil/android/tools/screenshot.py59
-rw-r--r--third_party/catapult/devil/devil/android/tools/script_common.py29
-rwxr-xr-xthird_party/catapult/devil/devil/android/tools/script_common_test.py58
-rwxr-xr-xthird_party/catapult/devil/devil/android/tools/video_recorder.py175
-rwxr-xr-xthird_party/catapult/devil/devil/android/tools/wait_for_devices.py50
-rw-r--r--third_party/catapult/devil/devil/android/valgrind_tools/__init__.py21
-rw-r--r--third_party/catapult/devil/devil/android/valgrind_tools/base_tool.py53
-rw-r--r--third_party/catapult/devil/devil/base_error.py24
-rw-r--r--third_party/catapult/devil/devil/constants/__init__.py3
-rw-r--r--third_party/catapult/devil/devil/constants/exit_codes.py9
-rw-r--r--third_party/catapult/devil/devil/devil_dependencies.json127
-rw-r--r--third_party/catapult/devil/devil/devil_env.py194
-rwxr-xr-xthird_party/catapult/devil/devil/devil_env_test.py63
-rw-r--r--third_party/catapult/devil/devil/utils/__init__.py23
-rwxr-xr-xthird_party/catapult/devil/devil/utils/battor_device_mapping.py309
-rw-r--r--third_party/catapult/devil/devil/utils/cmd_helper.py394
-rwxr-xr-xthird_party/catapult/devil/devil/utils/cmd_helper_test.py262
-rw-r--r--third_party/catapult/devil/devil/utils/file_utils.py31
-rwxr-xr-xthird_party/catapult/devil/devil/utils/find_usb_devices.py532
-rwxr-xr-xthird_party/catapult/devil/devil/utils/find_usb_devices_test.py379
-rw-r--r--third_party/catapult/devil/devil/utils/geometry.py75
-rw-r--r--third_party/catapult/devil/devil/utils/geometry_test.py61
-rw-r--r--third_party/catapult/devil/devil/utils/host_utils.py16
-rw-r--r--third_party/catapult/devil/devil/utils/lazy/__init__.py5
-rw-r--r--third_party/catapult/devil/devil/utils/lazy/weak_constant.py29
-rw-r--r--third_party/catapult/devil/devil/utils/lsusb.py174
-rwxr-xr-xthird_party/catapult/devil/devil/utils/lsusb_test.py250
-rwxr-xr-xthird_party/catapult/devil/devil/utils/markdown.py320
-rwxr-xr-xthird_party/catapult/devil/devil/utils/markdown_test.py121
-rw-r--r--third_party/catapult/devil/devil/utils/mock_calls.py180
-rwxr-xr-xthird_party/catapult/devil/devil/utils/mock_calls_test.py173
-rw-r--r--third_party/catapult/devil/devil/utils/parallelizer.py238
-rw-r--r--third_party/catapult/devil/devil/utils/parallelizer_test.py162
-rw-r--r--third_party/catapult/devil/devil/utils/reraiser_thread.py228
-rw-r--r--third_party/catapult/devil/devil/utils/reraiser_thread_unittest.py117
-rwxr-xr-xthird_party/catapult/devil/devil/utils/reset_usb.py111
-rw-r--r--third_party/catapult/devil/devil/utils/run_tests_helper.py44
-rw-r--r--third_party/catapult/devil/devil/utils/signal_handler.py48
-rw-r--r--third_party/catapult/devil/devil/utils/test/data/test_serial_map.json1
-rw-r--r--third_party/catapult/devil/devil/utils/timeout_retry.py175
-rwxr-xr-xthird_party/catapult/devil/devil/utils/timeout_retry_unittest.py79
-rwxr-xr-xthird_party/catapult/devil/devil/utils/update_mapping.py47
-rw-r--r--third_party/catapult/devil/devil/utils/usb_hubs.py165
-rw-r--r--third_party/catapult/devil/devil/utils/watchdog_timer.py47
-rw-r--r--third_party/catapult/devil/devil/utils/zip_utils.py33
116 files changed, 0 insertions, 22823 deletions
diff --git a/third_party/catapult/devil/devil/__init__.py b/third_party/catapult/devil/devil/__init__.py
deleted file mode 100644
index 7de59c941c..0000000000
--- a/third_party/catapult/devil/devil/__init__.py
+++ /dev/null
@@ -1,7 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import logging
-
-logging.getLogger('devil').addHandler(logging.NullHandler())
diff --git a/third_party/catapult/devil/devil/android/__init__.py b/third_party/catapult/devil/devil/android/__init__.py
deleted file mode 100644
index 50b23dff63..0000000000
--- a/third_party/catapult/devil/devil/android/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
diff --git a/third_party/catapult/devil/devil/android/apk_helper.py b/third_party/catapult/devil/devil/android/apk_helper.py
deleted file mode 100644
index 1a9b8c5510..0000000000
--- a/third_party/catapult/devil/devil/android/apk_helper.py
+++ /dev/null
@@ -1,164 +0,0 @@
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Module containing utilities for apk packages."""
-
-import itertools
-import re
-
-from devil import base_error
-from devil.android.sdk import aapt
-
-
-_MANIFEST_ATTRIBUTE_RE = re.compile(
- r'\s*A: ([^\(\)= ]*)(?:\([^\(\)= ]*\))?='
- r'(?:"(.*)" \(Raw: .*\)|\(type.*?\)(.*))$')
-_MANIFEST_ELEMENT_RE = re.compile(r'\s*(?:E|N): (\S*) .*$')
-
-
-def GetPackageName(apk_path):
- """Returns the package name of the apk."""
- return ApkHelper(apk_path).GetPackageName()
-
-
-# TODO(jbudorick): Deprecate and remove this function once callers have been
-# converted to ApkHelper.GetInstrumentationName
-def GetInstrumentationName(apk_path):
- """Returns the name of the Instrumentation in the apk."""
- return ApkHelper(apk_path).GetInstrumentationName()
-
-
-def ToHelper(path_or_helper):
- """Creates an ApkHelper unless one is already given."""
- if isinstance(path_or_helper, basestring):
- return ApkHelper(path_or_helper)
- return path_or_helper
-
-
-def _ParseManifestFromApk(apk_path):
- aapt_output = aapt.Dump('xmltree', apk_path, 'AndroidManifest.xml')
-
- parsed_manifest = {}
- node_stack = [parsed_manifest]
- indent = ' '
-
- for line in aapt_output[1:]:
- if len(line) == 0:
- continue
-
- indent_depth = 0
- while line[(len(indent) * indent_depth):].startswith(indent):
- indent_depth += 1
-
- node_stack = node_stack[:indent_depth]
- node = node_stack[-1]
-
- m = _MANIFEST_ELEMENT_RE.match(line[len(indent) * indent_depth:])
- if m:
- manifest_key = m.group(1)
- if manifest_key in node:
- node[manifest_key] += [{}]
- else:
- node[manifest_key] = [{}]
- node_stack += [node[manifest_key][-1]]
- continue
-
- m = _MANIFEST_ATTRIBUTE_RE.match(line[len(indent) * indent_depth:])
- if m:
- manifest_key = m.group(1)
- if manifest_key in node:
- raise base_error.BaseError(
- "A single attribute should have one key and one value")
- else:
- node[manifest_key] = m.group(2) or m.group(3)
- continue
-
- return parsed_manifest
-
-
-class ApkHelper(object):
-
- def __init__(self, path):
- self._apk_path = path
- self._manifest = None
-
- @property
- def path(self):
- return self._apk_path
-
- def GetActivityName(self):
- """Returns the name of the Activity in the apk."""
- manifest_info = self._GetManifest()
- try:
- activity = (
- manifest_info['manifest'][0]['application'][0]['activity'][0]
- ['android:name'])
- except KeyError:
- return None
- if '.' not in activity:
- activity = '%s.%s' % (self.GetPackageName(), activity)
- elif activity.startswith('.'):
- activity = '%s%s' % (self.GetPackageName(), activity)
- return activity
-
- def GetInstrumentationName(
- self, default='android.test.InstrumentationTestRunner'):
- """Returns the name of the Instrumentation in the apk."""
- all_instrumentations = self.GetAllInstrumentations(default=default)
- if len(all_instrumentations) != 1:
- raise base_error.BaseError(
- 'There is more than one instrumentation. Expected one.')
- else:
- return all_instrumentations[0]['android:name']
-
- def GetAllInstrumentations(
- self, default='android.test.InstrumentationTestRunner'):
- """Returns a list of all Instrumentations in the apk."""
- try:
- return self._GetManifest()['manifest'][0]['instrumentation']
- except KeyError:
- return [{'android:name': default}]
-
- def GetPackageName(self):
- """Returns the package name of the apk."""
- manifest_info = self._GetManifest()
- try:
- return manifest_info['manifest'][0]['package']
- except KeyError:
- raise Exception('Failed to determine package name of %s' % self._apk_path)
-
- def GetPermissions(self):
- manifest_info = self._GetManifest()
- try:
- return [p['android:name'] for
- p in manifest_info['manifest'][0]['uses-permission']]
- except KeyError:
- return []
-
- def GetSplitName(self):
- """Returns the name of the split of the apk."""
- manifest_info = self._GetManifest()
- try:
- return manifest_info['manifest'][0]['split']
- except KeyError:
- return None
-
- def HasIsolatedProcesses(self):
- """Returns whether any services exist that use isolatedProcess=true."""
- manifest_info = self._GetManifest()
- try:
- applications = manifest_info['manifest'][0].get('application', [])
- services = itertools.chain(
- *(application.get('service', []) for application in applications))
- return any(
- int(s.get('android:isolatedProcess', '0'), 0)
- for s in services)
- except KeyError:
- return False
-
- def _GetManifest(self):
- if not self._manifest:
- self._manifest = _ParseManifestFromApk(self._apk_path)
- return self._manifest
-
diff --git a/third_party/catapult/devil/devil/android/apk_helper_test.py b/third_party/catapult/devil/devil/android/apk_helper_test.py
deleted file mode 100755
index f7d077dd62..0000000000
--- a/third_party/catapult/devil/devil/android/apk_helper_test.py
+++ /dev/null
@@ -1,169 +0,0 @@
-#! /usr/bin/env python
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-from devil import base_error
-from devil import devil_env
-from devil.android import apk_helper
-from devil.utils import mock_calls
-
-with devil_env.SysPath(devil_env.PYMOCK_PATH):
- import mock # pylint: disable=import-error
-
-
-_MANIFEST_DUMP = """N: android=http://schemas.android.com/apk/res/android
- E: manifest (line=1)
- A: package="org.chromium.abc" (Raw: "org.chromium.abc")
- A: split="random_split" (Raw: "random_split")
- E: uses-permission (line=2)
- A: android:name(0x01010003)="android.permission.INTERNET" (Raw: "android.permission.INTERNET")
- E: uses-permission (line=3)
- A: android:name(0x01010003)="android.permission.READ_EXTERNAL_STORAGE" (Raw: "android.permission.READ_EXTERNAL_STORAGE")
- E: uses-permission (line=4)
- A: android:name(0x01010003)="android.permission.ACCESS_FINE_LOCATION" (Raw: "android.permission.ACCESS_FINE_LOCATION")
- E: application (line=5)
- E: activity (line=6)
- A: android:name(0x01010003)="org.chromium.ActivityName" (Raw: "org.chromium.ActivityName")
- A: android:exported(0x01010010)=(type 0x12)0xffffffff
- E: service (line=7)
- A: android:name(0x01010001)="org.chromium.RandomService" (Raw: "org.chromium.RandomService")
- A: android:isolatedProcess(0x01010888)=(type 0x12)0xffffffff
- E: instrumentation (line=8)
- A: android:label(0x01010001)="abc" (Raw: "abc")
- A: android:name(0x01010003)="org.chromium.RandomJUnit4TestRunner" (Raw: "org.chromium.RandomJUnit4TestRunner")
- A: android:targetPackage(0x01010021)="org.chromium.random_package" (Raw:"org.chromium.random_pacakge")
- A: junit4=(type 0x12)0xffffffff (Raw: "true")
- E: instrumentation (line=9)
- A: android:label(0x01010001)="abc" (Raw: "abc")
- A: android:name(0x01010003)="org.chromium.RandomTestRunner" (Raw: "org.chromium.RandomTestRunner")
- A: android:targetPackage(0x01010021)="org.chromium.random_package" (Raw:"org.chromium.random_pacakge")
-"""
-
-_NO_ISOLATED_SERVICES = """N: android=http://schemas.android.com/apk/res/android
- E: manifest (line=1)
- A: package="org.chromium.abc" (Raw: "org.chromium.abc")
- E: application (line=5)
- E: activity (line=6)
- A: android:name(0x01010003)="org.chromium.ActivityName" (Raw: "org.chromium.ActivityName")
- A: android:exported(0x01010010)=(type 0x12)0xffffffff
- E: service (line=7)
- A: android:name(0x01010001)="org.chromium.RandomService" (Raw: "org.chromium.RandomService")
-"""
-
-_NO_SERVICES = """N: android=http://schemas.android.com/apk/res/android
- E: manifest (line=1)
- A: package="org.chromium.abc" (Raw: "org.chromium.abc")
- E: application (line=5)
- E: activity (line=6)
- A: android:name(0x01010003)="org.chromium.ActivityName" (Raw: "org.chromium.ActivityName")
- A: android:exported(0x01010010)=(type 0x12)0xffffffff
-"""
-
-_NO_APPLICATION = """N: android=http://schemas.android.com/apk/res/android
- E: manifest (line=1)
- A: package="org.chromium.abc" (Raw: "org.chromium.abc")
-"""
-
-_SINGLE_INSTRUMENTATION_MANIFEST_DUMP = """N: android=http://schemas.android.com/apk/res/android
- E: manifest (line=1)
- A: package="org.chromium.xyz" (Raw: "org.chromium.xyz")
- E: instrumentation (line=8)
- A: android:label(0x01010001)="xyz" (Raw: "xyz")
- A: android:name(0x01010003)="org.chromium.RandomTestRunner" (Raw: "org.chromium.RandomTestRunner")
- A: android:targetPackage(0x01010021)="org.chromium.random_package" (Raw:"org.chromium.random_pacakge")
-"""
-
-_SINGLE_J4_INSTRUMENTATION_MANIFEST_DUMP = """N: android=http://schemas.android.com/apk/res/android
- E: manifest (line=1)
- A: package="org.chromium.xyz" (Raw: "org.chromium.xyz")
- E: instrumentation (line=8)
- A: android:label(0x01010001)="xyz" (Raw: "xyz")
- A: android:name(0x01010003)="org.chromium.RandomJ4TestRunner" (Raw: "org.chromium.RandomJ4TestRunner")
- A: android:targetPackage(0x01010021)="org.chromium.random_package" (Raw:"org.chromium.random_pacakge")
- A: junit4=(type 0x12)0xffffffff (Raw: "true")
-"""
-
-
-def _MockAaptDump(manifest_dump):
- return mock.patch(
- 'devil.android.sdk.aapt.Dump',
- mock.Mock(side_effect=None, return_value=manifest_dump.split('\n')))
-
-class ApkHelperTest(mock_calls.TestCase):
-
- def testGetInstrumentationName(self):
- with _MockAaptDump(_MANIFEST_DUMP):
- helper = apk_helper.ApkHelper("")
- with self.assertRaises(base_error.BaseError):
- helper.GetInstrumentationName()
-
- def testGetActivityName(self):
- with _MockAaptDump(_MANIFEST_DUMP):
- helper = apk_helper.ApkHelper("")
- self.assertEquals(
- helper.GetActivityName(), 'org.chromium.ActivityName')
-
- def testGetAllInstrumentations(self):
- with _MockAaptDump(_MANIFEST_DUMP):
- helper = apk_helper.ApkHelper("")
- all_instrumentations = helper.GetAllInstrumentations()
- self.assertEquals(len(all_instrumentations), 2)
- self.assertEquals(all_instrumentations[0]['android:name'],
- 'org.chromium.RandomJUnit4TestRunner')
- self.assertEquals(all_instrumentations[1]['android:name'],
- 'org.chromium.RandomTestRunner')
-
- def testGetPackageName(self):
- with _MockAaptDump(_MANIFEST_DUMP):
- helper = apk_helper.ApkHelper("")
- self.assertEquals(helper.GetPackageName(), 'org.chromium.abc')
-
- def testGetPermssions(self):
- with _MockAaptDump(_MANIFEST_DUMP):
- helper = apk_helper.ApkHelper("")
- all_permissions = helper.GetPermissions()
- self.assertEquals(len(all_permissions), 3)
- self.assertTrue('android.permission.INTERNET' in all_permissions)
- self.assertTrue(
- 'android.permission.READ_EXTERNAL_STORAGE' in all_permissions)
- self.assertTrue(
- 'android.permission.ACCESS_FINE_LOCATION' in all_permissions)
-
- def testGetSplitName(self):
- with _MockAaptDump(_MANIFEST_DUMP):
- helper = apk_helper.ApkHelper("")
- self.assertEquals(helper.GetSplitName(), 'random_split')
-
- def testHasIsolatedProcesses_noApplication(self):
- with _MockAaptDump(_NO_APPLICATION):
- helper = apk_helper.ApkHelper("")
- self.assertFalse(helper.HasIsolatedProcesses())
-
- def testHasIsolatedProcesses_noServices(self):
- with _MockAaptDump(_NO_SERVICES):
- helper = apk_helper.ApkHelper("")
- self.assertFalse(helper.HasIsolatedProcesses())
-
- def testHasIsolatedProcesses_oneNotIsolatedProcess(self):
- with _MockAaptDump(_NO_ISOLATED_SERVICES):
- helper = apk_helper.ApkHelper("")
- self.assertFalse(helper.HasIsolatedProcesses())
-
- def testHasIsolatedProcesses_oneIsolatedProcess(self):
- with _MockAaptDump(_MANIFEST_DUMP):
- helper = apk_helper.ApkHelper("")
- self.assertTrue(helper.HasIsolatedProcesses())
-
- def testGetSingleInstrumentationName(self):
- with _MockAaptDump(_SINGLE_INSTRUMENTATION_MANIFEST_DUMP):
- helper = apk_helper.ApkHelper("")
- self.assertEquals('org.chromium.RandomTestRunner',
- helper.GetInstrumentationName())
-
- def testGetSingleJUnit4InstrumentationName(self):
- with _MockAaptDump(_SINGLE_J4_INSTRUMENTATION_MANIFEST_DUMP):
- helper = apk_helper.ApkHelper("")
- self.assertEquals('org.chromium.RandomJ4TestRunner',
- helper.GetInstrumentationName())
-
diff --git a/third_party/catapult/devil/devil/android/app_ui.py b/third_party/catapult/devil/devil/android/app_ui.py
deleted file mode 100644
index 2b04e8b800..0000000000
--- a/third_party/catapult/devil/devil/android/app_ui.py
+++ /dev/null
@@ -1,243 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Provides functionality to interact with UI elements of an Android app."""
-
-import collections
-import re
-from xml.etree import ElementTree as element_tree
-
-from devil.android import decorators
-from devil.android import device_temp_file
-from devil.utils import geometry
-from devil.utils import timeout_retry
-
-_DEFAULT_SHORT_TIMEOUT = 10
-_DEFAULT_SHORT_RETRIES = 3
-_DEFAULT_LONG_TIMEOUT = 30
-_DEFAULT_LONG_RETRIES = 0
-
-# Parse rectangle bounds given as: '[left,top][right,bottom]'.
-_RE_BOUNDS = re.compile(
- r'\[(?P<left>\d+),(?P<top>\d+)\]\[(?P<right>\d+),(?P<bottom>\d+)\]')
-
-
-class _UiNode(object):
-
- def __init__(self, device, xml_node, package=None):
- """Object to interact with a UI node from an xml snapshot.
-
- Note: there is usually no need to call this constructor directly. Instead,
- use an AppUi object (below) to grab an xml screenshot from a device and
- find nodes in it.
-
- Args:
- device: A device_utils.DeviceUtils instance.
- xml_node: An ElementTree instance of the node to interact with.
- package: An optional package name for the app owning this node.
- """
- self._device = device
- self._xml_node = xml_node
- self._package = package
-
- def _GetAttribute(self, key):
- """Get the value of an attribute of this node."""
- return self._xml_node.attrib.get(key)
-
- @property
- def bounds(self):
- """Get a rectangle with the bounds of this UI node.
-
- Returns:
- A geometry.Rectangle instance.
- """
- d = _RE_BOUNDS.match(self._GetAttribute('bounds')).groupdict()
- return geometry.Rectangle.FromDict({k: int(v) for k, v in d.iteritems()})
-
- def Tap(self, point=None, dp_units=False):
- """Send a tap event to the UI node.
-
- Args:
- point: An optional geometry.Point instance indicating the location to
- tap, relative to the bounds of the UI node, i.e. (0, 0) taps the
- top-left corner. If ommited, the center of the node is tapped.
- dp_units: If True, indicates that the coordinates of the point are given
- in device-independent pixels; otherwise they are assumed to be "real"
- pixels. This option has no effect when the point is ommited.
- """
- if point is None:
- point = self.bounds.center
- else:
- if dp_units:
- point = (float(self._device.pixel_density) / 160) * point
- point += self.bounds.top_left
-
- x, y = (str(int(v)) for v in point)
- self._device.RunShellCommand(['input', 'tap', x, y], check_return=True)
-
- def Dump(self):
- """Get a brief summary of the child nodes that can be found on this node.
-
- Returns:
- A list of lines that can be logged or otherwise printed.
- """
- summary = collections.defaultdict(set)
- for node in self._xml_node.iter():
- package = node.get('package') or '(no package)'
- label = node.get('resource-id') or '(no id)'
- text = node.get('text')
- if text:
- label = '%s[%r]' % (label, text)
- summary[package].add(label)
- lines = []
- for package, labels in sorted(summary.iteritems()):
- lines.append('- %s:' % package)
- for label in sorted(labels):
- lines.append(' - %s' % label)
- return lines
-
- def __getitem__(self, key):
- """Retrieve a child of this node by its index.
-
- Args:
- key: An integer with the index of the child to retrieve.
- Returns:
- A UI node instance of the selected child.
- Raises:
- IndexError if the index is out of range.
- """
- return type(self)(self._device, self._xml_node[key], package=self._package)
-
- def _Find(self, **kwargs):
- """Find the first descendant node that matches a given criteria.
-
- Note: clients would usually call AppUi.GetUiNode or AppUi.WaitForUiNode
- instead.
-
- For example:
-
- app = app_ui.AppUi(device, package='org.my.app')
- app.GetUiNode(resource_id='some_element', text='hello')
-
- would retrieve the first matching node with both of the xml attributes:
-
- resource-id='org.my.app:id/some_element'
- text='hello'
-
- As the example shows, if given and needed, the value of the resource_id key
- is auto-completed with the package name specified in the AppUi constructor.
-
- Args:
- Arguments are specified as key-value pairs, where keys correnspond to
- attribute names in xml nodes (replacing any '-' with '_' to make them
- valid identifiers). At least one argument must be supplied, and arguments
- with a None value are ignored.
- Returns:
- A UI node instance of the first descendant node that matches ALL the
- given key-value criteria; or None if no such node is found.
- Raises:
- TypeError if no search arguments are provided.
- """
- matches_criteria = self._NodeMatcher(kwargs)
- for node in self._xml_node.iter():
- if matches_criteria(node):
- return type(self)(self._device, node, package=self._package)
- return None
-
- def _NodeMatcher(self, kwargs):
- # Auto-complete resource-id's using the package name if available.
- resource_id = kwargs.get('resource_id')
- if (resource_id is not None
- and self._package is not None
- and ':id/' not in resource_id):
- kwargs['resource_id'] = '%s:id/%s' % (self._package, resource_id)
-
- criteria = [(k.replace('_', '-'), v)
- for k, v in kwargs.iteritems()
- if v is not None]
- if not criteria:
- raise TypeError('At least one search criteria should be specified')
- return lambda node: all(node.get(k) == v for k, v in criteria)
-
-
-class AppUi(object):
- # timeout and retry arguments appear unused, but are handled by decorator.
- # pylint: disable=unused-argument
-
- def __init__(self, device, package=None):
- """Object to interact with the UI of an Android app.
-
- Args:
- device: A device_utils.DeviceUtils instance.
- package: An optional package name for the app.
- """
- self._device = device
- self._package = package
-
- @property
- def package(self):
- return self._package
-
- @decorators.WithTimeoutAndRetriesDefaults(_DEFAULT_SHORT_TIMEOUT,
- _DEFAULT_SHORT_RETRIES)
- def _GetRootUiNode(self, timeout=None, retries=None):
- """Get a node pointing to the root of the UI nodes on screen.
-
- Note: This is currently implemented via adb calls to uiatomator and it
- is *slow*, ~2 secs per call. Do not rely on low-level implementation
- details that may change in the future.
-
- TODO(crbug.com/567217): Swap to a more efficient implementation.
-
- Args:
- timeout: A number of seconds to wait for the uiautomator dump.
- retries: Number of times to retry if the adb command fails.
- Returns:
- A UI node instance pointing to the root of the xml screenshot.
- """
- with device_temp_file.DeviceTempFile(self._device.adb) as dtemp:
- self._device.RunShellCommand(['uiautomator', 'dump', dtemp.name],
- check_return=True)
- xml_node = element_tree.fromstring(
- self._device.ReadFile(dtemp.name, force_pull=True))
- return _UiNode(self._device, xml_node, package=self._package)
-
- def ScreenDump(self):
- """Get a brief summary of the nodes that can be found on the screen.
-
- Returns:
- A list of lines that can be logged or otherwise printed.
- """
- return self._GetRootUiNode().Dump()
-
- def GetUiNode(self, **kwargs):
- """Get the first node found matching a specified criteria.
-
- Args:
- See _UiNode._Find.
- Returns:
- A UI node instance of the node if found, otherwise None.
- """
- # pylint: disable=protected-access
- return self._GetRootUiNode()._Find(**kwargs)
-
- @decorators.WithTimeoutAndRetriesDefaults(_DEFAULT_LONG_TIMEOUT,
- _DEFAULT_LONG_RETRIES)
- def WaitForUiNode(self, timeout=None, retries=None, **kwargs):
- """Wait for a node matching a given criteria to appear on the screen.
-
- Args:
- timeout: A number of seconds to wait for the matching node to appear.
- retries: Number of times to retry in case of adb command errors.
- For other args, to specify the search criteria, see _UiNode._Find.
- Returns:
- The UI node instance found.
- Raises:
- device_errors.CommandTimeoutError if the node is not found before the
- timeout.
- """
- def node_found():
- return self.GetUiNode(**kwargs)
-
- return timeout_retry.WaitFor(node_found)
diff --git a/third_party/catapult/devil/devil/android/app_ui_test.py b/third_party/catapult/devil/devil/android/app_ui_test.py
deleted file mode 100644
index 3472985118..0000000000
--- a/third_party/catapult/devil/devil/android/app_ui_test.py
+++ /dev/null
@@ -1,191 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Unit tests for the app_ui module."""
-
-import unittest
-from xml.etree import ElementTree as element_tree
-
-from devil import devil_env
-from devil.android import app_ui
-from devil.android import device_errors
-from devil.utils import geometry
-
-with devil_env.SysPath(devil_env.PYMOCK_PATH):
- import mock # pylint: disable=import-error
-
-
-MOCK_XML_LOADING = '''
-<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
-<hierarchy rotation="0">
- <node bounds="[0,50][1536,178]" content-desc="Loading"
- resource-id="com.example.app:id/spinner"/>
-</hierarchy>
-'''.strip()
-
-
-MOCK_XML_LOADED = '''
-<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
-<hierarchy rotation="0">
- <node bounds="[0,50][1536,178]" content-desc=""
- resource-id="com.example.app:id/toolbar">
- <node bounds="[0,58][112,170]" content-desc="Open navigation drawer"/>
- <node bounds="[121,50][1536,178]"
- resource-id="com.example.app:id/actionbar_custom_view">
- <node bounds="[121,50][1424,178]"
- resource-id="com.example.app:id/actionbar_title" text="Primary"/>
- <node bounds="[1424,50][1536,178]" content-desc="Search"
- resource-id="com.example.app:id/actionbar_search_button"/>
- </node>
- </node>
- <node bounds="[0,178][576,1952]" resource-id="com.example.app:id/drawer">
- <node bounds="[0,178][144,1952]"
- resource-id="com.example.app:id/mini_drawer">
- <node bounds="[40,254][104,318]" resource-id="com.example.app:id/avatar"/>
- <node bounds="[16,354][128,466]" content-desc="Primary"
- resource-id="com.example.app:id/image_view"/>
- <node bounds="[16,466][128,578]" content-desc="Social"
- resource-id="com.example.app:id/image_view"/>
- <node bounds="[16,578][128,690]" content-desc="Promotions"
- resource-id="com.example.app:id/image_view"/>
- </node>
- </node>
-</hierarchy>
-'''.strip()
-
-
-class UiAppTest(unittest.TestCase):
-
- def setUp(self):
- self.device = mock.Mock()
- self.device.pixel_density = 320 # Each dp pixel is 2 real pixels.
- self.app = app_ui.AppUi(self.device, package='com.example.app')
- self._setMockXmlScreenshots([MOCK_XML_LOADED])
-
- def _setMockXmlScreenshots(self, xml_docs):
- """Mock self.app._GetRootUiNode to load nodes from some test xml_docs.
-
- Each time the method is called it will return a UI node for each string
- given in |xml_docs|, or rise a time out error when the list is exhausted.
- """
- # pylint: disable=protected-access
- def get_mock_root_ui_node(value):
- if isinstance(value, Exception):
- raise value
- return app_ui._UiNode(
- self.device, element_tree.fromstring(value), self.app.package)
-
- xml_docs.append(device_errors.CommandTimeoutError('Timed out!'))
-
- self.app._GetRootUiNode = mock.Mock(
- side_effect=(get_mock_root_ui_node(doc) for doc in xml_docs))
-
- def assertNodeHasAttribs(self, node, attr):
- # pylint: disable=protected-access
- for key, value in attr.iteritems():
- self.assertEquals(node._GetAttribute(key), value)
-
- def assertTappedOnceAt(self, x, y):
- self.device.RunShellCommand.assert_called_once_with(
- ['input', 'tap', str(x), str(y)], check_return=True)
-
- def testFind_byText(self):
- node = self.app.GetUiNode(text='Primary')
- self.assertNodeHasAttribs(node, {
- 'text': 'Primary',
- 'content-desc': None,
- 'resource-id': 'com.example.app:id/actionbar_title',
- })
- self.assertEquals(node.bounds, geometry.Rectangle([121, 50], [1424, 178]))
-
- def testFind_byContentDesc(self):
- node = self.app.GetUiNode(content_desc='Social')
- self.assertNodeHasAttribs(node, {
- 'text': None,
- 'content-desc': 'Social',
- 'resource-id': 'com.example.app:id/image_view',
- })
- self.assertEquals(node.bounds, geometry.Rectangle([16, 466], [128, 578]))
-
- def testFind_byResourceId_autocompleted(self):
- node = self.app.GetUiNode(resource_id='image_view')
- self.assertNodeHasAttribs(node, {
- 'content-desc': 'Primary',
- 'resource-id': 'com.example.app:id/image_view',
- })
-
- def testFind_byResourceId_absolute(self):
- node = self.app.GetUiNode(resource_id='com.example.app:id/image_view')
- self.assertNodeHasAttribs(node, {
- 'content-desc': 'Primary',
- 'resource-id': 'com.example.app:id/image_view',
- })
-
- def testFind_byMultiple(self):
- node = self.app.GetUiNode(resource_id='image_view',
- content_desc='Promotions')
- self.assertNodeHasAttribs(node, {
- 'content-desc': 'Promotions',
- 'resource-id': 'com.example.app:id/image_view',
- })
- self.assertEquals(node.bounds, geometry.Rectangle([16, 578], [128, 690]))
-
- def testFind_notFound(self):
- node = self.app.GetUiNode(resource_id='does_not_exist')
- self.assertIsNone(node)
-
- def testFind_noArgsGiven(self):
- # Same exception given by Python for a function call with not enough args.
- with self.assertRaises(TypeError):
- self.app.GetUiNode()
-
- def testGetChildren(self):
- node = self.app.GetUiNode(resource_id='mini_drawer')
- self.assertNodeHasAttribs(
- node[0], {'resource-id': 'com.example.app:id/avatar'})
- self.assertNodeHasAttribs(node[1], {'content-desc': 'Primary'})
- self.assertNodeHasAttribs(node[2], {'content-desc': 'Social'})
- self.assertNodeHasAttribs(node[3], {'content-desc': 'Promotions'})
- with self.assertRaises(IndexError):
- # pylint: disable=pointless-statement
- node[4]
-
- def testTap_center(self):
- node = self.app.GetUiNode(content_desc='Open navigation drawer')
- node.Tap()
- self.assertTappedOnceAt(56, 114)
-
- def testTap_topleft(self):
- node = self.app.GetUiNode(content_desc='Open navigation drawer')
- node.Tap(geometry.Point(0, 0))
- self.assertTappedOnceAt(0, 58)
-
- def testTap_withOffset(self):
- node = self.app.GetUiNode(content_desc='Open navigation drawer')
- node.Tap(geometry.Point(10, 20))
- self.assertTappedOnceAt(10, 78)
-
- def testTap_withOffsetInDp(self):
- node = self.app.GetUiNode(content_desc='Open navigation drawer')
- node.Tap(geometry.Point(10, 20), dp_units=True)
- self.assertTappedOnceAt(20, 98)
-
- def testTap_dpUnitsIgnored(self):
- node = self.app.GetUiNode(content_desc='Open navigation drawer')
- node.Tap(dp_units=True)
- self.assertTappedOnceAt(56, 114) # Still taps at center.
-
- @mock.patch('time.sleep', mock.Mock())
- def testWaitForUiNode_found(self):
- self._setMockXmlScreenshots(
- [MOCK_XML_LOADING, MOCK_XML_LOADING, MOCK_XML_LOADED])
- node = self.app.WaitForUiNode(resource_id='actionbar_title')
- self.assertNodeHasAttribs(node, {'text': 'Primary'})
-
- @mock.patch('time.sleep', mock.Mock())
- def testWaitForUiNode_notFound(self):
- self._setMockXmlScreenshots(
- [MOCK_XML_LOADING, MOCK_XML_LOADING, MOCK_XML_LOADING])
- with self.assertRaises(device_errors.CommandTimeoutError):
- self.app.WaitForUiNode(resource_id='actionbar_title')
diff --git a/third_party/catapult/devil/devil/android/battery_utils.py b/third_party/catapult/devil/devil/android/battery_utils.py
deleted file mode 100644
index 3b225aa106..0000000000
--- a/third_party/catapult/devil/devil/android/battery_utils.py
+++ /dev/null
@@ -1,699 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Provides a variety of device interactions with power.
-"""
-# pylint: disable=unused-argument
-
-import collections
-import contextlib
-import csv
-import logging
-
-from devil.android import decorators
-from devil.android import device_errors
-from devil.android import device_utils
-from devil.android.sdk import version_codes
-from devil.utils import timeout_retry
-
-logger = logging.getLogger(__name__)
-
-_DEFAULT_TIMEOUT = 30
-_DEFAULT_RETRIES = 3
-
-
-_DEVICE_PROFILES = [
- {
- 'name': ['Nexus 4'],
- 'enable_command': (
- 'echo 0 > /sys/module/pm8921_charger/parameters/disabled && '
- 'dumpsys battery reset'),
- 'disable_command': (
- 'echo 1 > /sys/module/pm8921_charger/parameters/disabled && '
- 'dumpsys battery set ac 0 && dumpsys battery set usb 0'),
- 'charge_counter': None,
- 'voltage': None,
- 'current': None,
- },
- {
- 'name': ['Nexus 5'],
- # Nexus 5
- # Setting the HIZ bit of the bq24192 causes the charger to actually ignore
- # energy coming from USB. Setting the power_supply offline just updates the
- # Android system to reflect that.
- 'enable_command': (
- 'echo 0x4A > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && '
- 'chmod 644 /sys/class/power_supply/usb/online && '
- 'echo 1 > /sys/class/power_supply/usb/online && '
- 'dumpsys battery reset'),
- 'disable_command': (
- 'echo 0xCA > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && '
- 'chmod 644 /sys/class/power_supply/usb/online && '
- 'echo 0 > /sys/class/power_supply/usb/online && '
- 'dumpsys battery set ac 0 && dumpsys battery set usb 0'),
- 'charge_counter': None,
- 'voltage': None,
- 'current': None,
- },
- {
- 'name': ['Nexus 6'],
- 'enable_command': (
- 'echo 1 > /sys/class/power_supply/battery/charging_enabled && '
- 'dumpsys battery reset'),
- 'disable_command': (
- 'echo 0 > /sys/class/power_supply/battery/charging_enabled && '
- 'dumpsys battery set ac 0 && dumpsys battery set usb 0'),
- 'charge_counter': (
- '/sys/class/power_supply/max170xx_battery/charge_counter_ext'),
- 'voltage': '/sys/class/power_supply/max170xx_battery/voltage_now',
- 'current': '/sys/class/power_supply/max170xx_battery/current_now',
- },
- {
- 'name': ['Nexus 9'],
- 'enable_command': (
- 'echo Disconnected > '
- '/sys/bus/i2c/drivers/bq2419x/0-006b/input_cable_state && '
- 'dumpsys battery reset'),
- 'disable_command': (
- 'echo Connected > '
- '/sys/bus/i2c/drivers/bq2419x/0-006b/input_cable_state && '
- 'dumpsys battery set ac 0 && dumpsys battery set usb 0'),
- 'charge_counter': '/sys/class/power_supply/battery/charge_counter_ext',
- 'voltage': '/sys/class/power_supply/battery/voltage_now',
- 'current': '/sys/class/power_supply/battery/current_now',
- },
- {
- 'name': ['Nexus 10'],
- 'enable_command': None,
- 'disable_command': None,
- 'charge_counter': None,
- 'voltage': '/sys/class/power_supply/ds2784-fuelgauge/voltage_now',
- 'current': '/sys/class/power_supply/ds2784-fuelgauge/current_now',
-
- },
- {
- 'name': ['Nexus 5X'],
- 'enable_command': (
- 'echo 1 > /sys/class/power_supply/battery/charging_enabled && '
- 'dumpsys battery reset'),
- 'disable_command': (
- 'echo 0 > /sys/class/power_supply/battery/charging_enabled && '
- 'dumpsys battery set ac 0 && dumpsys battery set usb 0'),
- 'charge_counter': None,
- 'voltage': None,
- 'current': None,
- },
- { # Galaxy s5
- 'name': ['SM-G900H'],
- 'enable_command': (
- 'chmod 644 /sys/class/power_supply/battery/test_mode && '
- 'chmod 644 /sys/class/power_supply/sec-charger/current_now && '
- 'echo 0 > /sys/class/power_supply/battery/test_mode && '
- 'echo 9999 > /sys/class/power_supply/sec-charger/current_now &&'
- 'dumpsys battery reset'),
- 'disable_command': (
- 'chmod 644 /sys/class/power_supply/battery/test_mode && '
- 'chmod 644 /sys/class/power_supply/sec-charger/current_now && '
- 'echo 1 > /sys/class/power_supply/battery/test_mode && '
- 'echo 0 > /sys/class/power_supply/sec-charger/current_now && '
- 'dumpsys battery set ac 0 && dumpsys battery set usb 0'),
- 'charge_counter': None,
- 'voltage': '/sys/class/power_supply/sec-fuelgauge/voltage_now',
- 'current': '/sys/class/power_supply/sec-charger/current_now',
- },
- { # Galaxy s6, Galaxy s6, Galaxy s6 edge
- 'name': ['SM-G920F', 'SM-G920V', 'SM-G925V'],
- 'enable_command': (
- 'chmod 644 /sys/class/power_supply/battery/test_mode && '
- 'chmod 644 /sys/class/power_supply/max77843-charger/current_now && '
- 'echo 0 > /sys/class/power_supply/battery/test_mode && '
- 'echo 9999 > /sys/class/power_supply/max77843-charger/current_now &&'
- 'dumpsys battery reset'),
- 'disable_command': (
- 'chmod 644 /sys/class/power_supply/battery/test_mode && '
- 'chmod 644 /sys/class/power_supply/max77843-charger/current_now && '
- 'echo 1 > /sys/class/power_supply/battery/test_mode && '
- 'echo 0 > /sys/class/power_supply/max77843-charger/current_now && '
- 'dumpsys battery set ac 0 && dumpsys battery set usb 0'),
- 'charge_counter': None,
- 'voltage': '/sys/class/power_supply/max77843-fuelgauge/voltage_now',
- 'current': '/sys/class/power_supply/max77843-charger/current_now',
- },
-]
-
-# The list of useful dumpsys columns.
-# Index of the column containing the format version.
-_DUMP_VERSION_INDEX = 0
-# Index of the column containing the type of the row.
-_ROW_TYPE_INDEX = 3
-# Index of the column containing the uid.
-_PACKAGE_UID_INDEX = 4
-# Index of the column containing the application package.
-_PACKAGE_NAME_INDEX = 5
-# The column containing the uid of the power data.
-_PWI_UID_INDEX = 1
-# The column containing the type of consumption. Only consumption since last
-# charge are of interest here.
-_PWI_AGGREGATION_INDEX = 2
-_PWS_AGGREGATION_INDEX = _PWI_AGGREGATION_INDEX
-# The column containing the amount of power used, in mah.
-_PWI_POWER_CONSUMPTION_INDEX = 5
-_PWS_POWER_CONSUMPTION_INDEX = _PWI_POWER_CONSUMPTION_INDEX
-
-_MAX_CHARGE_ERROR = 20
-
-
-class BatteryUtils(object):
-
- def __init__(self, device, default_timeout=_DEFAULT_TIMEOUT,
- default_retries=_DEFAULT_RETRIES):
- """BatteryUtils constructor.
-
- Args:
- device: A DeviceUtils instance.
- default_timeout: An integer containing the default number of seconds to
- wait for an operation to complete if no explicit value
- is provided.
- default_retries: An integer containing the default number or times an
- operation should be retried on failure if no explicit
- value is provided.
- Raises:
- TypeError: If it is not passed a DeviceUtils instance.
- """
- if not isinstance(device, device_utils.DeviceUtils):
- raise TypeError('Must be initialized with DeviceUtils object.')
- self._device = device
- self._cache = device.GetClientCache(self.__class__.__name__)
- self._default_timeout = default_timeout
- self._default_retries = default_retries
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def SupportsFuelGauge(self, timeout=None, retries=None):
- """Detect if fuel gauge chip is present.
-
- Args:
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- True if known fuel gauge files are present.
- False otherwise.
- """
- self._DiscoverDeviceProfile()
- return (self._cache['profile']['enable_command'] != None
- and self._cache['profile']['charge_counter'] != None)
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def GetFuelGaugeChargeCounter(self, timeout=None, retries=None):
- """Get value of charge_counter on fuel gauge chip.
-
- Device must have charging disabled for this, not just battery updates
- disabled. The only device that this currently works with is the nexus 5.
-
- Args:
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- value of charge_counter for fuel gauge chip in units of nAh.
-
- Raises:
- device_errors.CommandFailedError: If fuel gauge chip not found.
- """
- if self.SupportsFuelGauge():
- return int(self._device.ReadFile(
- self._cache['profile']['charge_counter']))
- raise device_errors.CommandFailedError(
- 'Unable to find fuel gauge.')
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def GetNetworkData(self, package, timeout=None, retries=None):
- """Get network data for specific package.
-
- Args:
- package: package name you want network data for.
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- Tuple of (sent_data, recieved_data)
- None if no network data found
- """
- # If device_utils clears cache, cache['uids'] doesn't exist
- if 'uids' not in self._cache:
- self._cache['uids'] = {}
- if package not in self._cache['uids']:
- self.GetPowerData()
- if package not in self._cache['uids']:
- logger.warning('No UID found for %s. Can\'t get network data.',
- package)
- return None
-
- network_data_path = '/proc/uid_stat/%s/' % self._cache['uids'][package]
- try:
- send_data = int(self._device.ReadFile(network_data_path + 'tcp_snd'))
- # If ReadFile throws exception, it means no network data usage file for
- # package has been recorded. Return 0 sent and 0 received.
- except device_errors.AdbShellCommandFailedError:
- logger.warning('No sent data found for package %s', package)
- send_data = 0
- try:
- recv_data = int(self._device.ReadFile(network_data_path + 'tcp_rcv'))
- except device_errors.AdbShellCommandFailedError:
- logger.warning('No received data found for package %s', package)
- recv_data = 0
- return (send_data, recv_data)
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def GetPowerData(self, timeout=None, retries=None):
- """Get power data for device.
-
- Args:
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- Dict containing system power, and a per-package power dict keyed on
- package names.
- {
- 'system_total': 23.1,
- 'per_package' : {
- package_name: {
- 'uid': uid,
- 'data': [1,2,3]
- },
- }
- }
- """
- if 'uids' not in self._cache:
- self._cache['uids'] = {}
- dumpsys_output = self._device.RunShellCommand(
- ['dumpsys', 'batterystats', '-c'],
- check_return=True, large_output=True)
- csvreader = csv.reader(dumpsys_output)
- pwi_entries = collections.defaultdict(list)
- system_total = None
- for entry in csvreader:
- if entry[_DUMP_VERSION_INDEX] not in ['8', '9']:
- # Wrong dumpsys version.
- raise device_errors.DeviceVersionError(
- 'Dumpsys version must be 8 or 9. "%s" found.'
- % entry[_DUMP_VERSION_INDEX])
- if _ROW_TYPE_INDEX < len(entry) and entry[_ROW_TYPE_INDEX] == 'uid':
- current_package = entry[_PACKAGE_NAME_INDEX]
- if (self._cache['uids'].get(current_package)
- and self._cache['uids'].get(current_package)
- != entry[_PACKAGE_UID_INDEX]):
- raise device_errors.CommandFailedError(
- 'Package %s found multiple times with different UIDs %s and %s'
- % (current_package, self._cache['uids'][current_package],
- entry[_PACKAGE_UID_INDEX]))
- self._cache['uids'][current_package] = entry[_PACKAGE_UID_INDEX]
- elif (_PWI_POWER_CONSUMPTION_INDEX < len(entry)
- and entry[_ROW_TYPE_INDEX] == 'pwi'
- and entry[_PWI_AGGREGATION_INDEX] == 'l'):
- pwi_entries[entry[_PWI_UID_INDEX]].append(
- float(entry[_PWI_POWER_CONSUMPTION_INDEX]))
- elif (_PWS_POWER_CONSUMPTION_INDEX < len(entry)
- and entry[_ROW_TYPE_INDEX] == 'pws'
- and entry[_PWS_AGGREGATION_INDEX] == 'l'):
- # This entry should only appear once.
- assert system_total is None
- system_total = float(entry[_PWS_POWER_CONSUMPTION_INDEX])
-
- per_package = {p: {'uid': uid, 'data': pwi_entries[uid]}
- for p, uid in self._cache['uids'].iteritems()}
- return {'system_total': system_total, 'per_package': per_package}
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def GetBatteryInfo(self, timeout=None, retries=None):
- """Gets battery info for the device.
-
- Args:
- timeout: timeout in seconds
- retries: number of retries
- Returns:
- A dict containing various battery information as reported by dumpsys
- battery.
- """
- result = {}
- # Skip the first line, which is just a header.
- for line in self._device.RunShellCommand(
- ['dumpsys', 'battery'], check_return=True)[1:]:
- # If usb charging has been disabled, an extra line of header exists.
- if 'UPDATES STOPPED' in line:
- logger.warning('Dumpsys battery not receiving updates. '
- 'Run dumpsys battery reset if this is in error.')
- elif ':' not in line:
- logger.warning('Unknown line found in dumpsys battery: "%s"', line)
- else:
- k, v = line.split(':', 1)
- result[k.strip()] = v.strip()
- return result
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def GetCharging(self, timeout=None, retries=None):
- """Gets the charging state of the device.
-
- Args:
- timeout: timeout in seconds
- retries: number of retries
- Returns:
- True if the device is charging, false otherwise.
- """
- battery_info = self.GetBatteryInfo()
- for k in ('AC powered', 'USB powered', 'Wireless powered'):
- if (k in battery_info and
- battery_info[k].lower() in ('true', '1', 'yes')):
- return True
- return False
-
- # TODO(rnephew): Make private when all use cases can use the context manager.
- @decorators.WithTimeoutAndRetriesFromInstance()
- def DisableBatteryUpdates(self, timeout=None, retries=None):
- """Resets battery data and makes device appear like it is not
- charging so that it will collect power data since last charge.
-
- Args:
- timeout: timeout in seconds
- retries: number of retries
-
- Raises:
- device_errors.CommandFailedError: When resetting batterystats fails to
- reset power values.
- device_errors.DeviceVersionError: If device is not L or higher.
- """
- def battery_updates_disabled():
- return self.GetCharging() is False
-
- self._ClearPowerData()
- self._device.RunShellCommand(['dumpsys', 'battery', 'set', 'ac', '0'],
- check_return=True)
- self._device.RunShellCommand(['dumpsys', 'battery', 'set', 'usb', '0'],
- check_return=True)
- timeout_retry.WaitFor(battery_updates_disabled, wait_period=1)
-
- # TODO(rnephew): Make private when all use cases can use the context manager.
- @decorators.WithTimeoutAndRetriesFromInstance()
- def EnableBatteryUpdates(self, timeout=None, retries=None):
- """Restarts device charging so that dumpsys no longer collects power data.
-
- Args:
- timeout: timeout in seconds
- retries: number of retries
-
- Raises:
- device_errors.DeviceVersionError: If device is not L or higher.
- """
- def battery_updates_enabled():
- return (self.GetCharging()
- or not bool('UPDATES STOPPED' in self._device.RunShellCommand(
- ['dumpsys', 'battery'], check_return=True)))
-
- self._device.RunShellCommand(['dumpsys', 'battery', 'reset'],
- check_return=True)
- timeout_retry.WaitFor(battery_updates_enabled, wait_period=1)
-
- @contextlib.contextmanager
- def BatteryMeasurement(self, timeout=None, retries=None):
- """Context manager that enables battery data collection. It makes
- the device appear to stop charging so that dumpsys will start collecting
- power data since last charge. Once the with block is exited, charging is
- resumed and power data since last charge is no longer collected.
-
- Only for devices L and higher.
-
- Example usage:
- with BatteryMeasurement():
- browser_actions()
- get_power_data() # report usage within this block
- after_measurements() # Anything that runs after power
- # measurements are collected
-
- Args:
- timeout: timeout in seconds
- retries: number of retries
-
- Raises:
- device_errors.DeviceVersionError: If device is not L or higher.
- """
- if self._device.build_version_sdk < version_codes.LOLLIPOP:
- raise device_errors.DeviceVersionError('Device must be L or higher.')
- try:
- self.DisableBatteryUpdates(timeout=timeout, retries=retries)
- yield
- finally:
- self.EnableBatteryUpdates(timeout=timeout, retries=retries)
-
- def _DischargeDevice(self, percent, wait_period=120):
- """Disables charging and waits for device to discharge given amount
-
- Args:
- percent: level of charge to discharge.
-
- Raises:
- ValueError: If percent is not between 1 and 99.
- """
- battery_level = int(self.GetBatteryInfo().get('level'))
- if not 0 < percent < 100:
- raise ValueError('Discharge amount(%s) must be between 1 and 99'
- % percent)
- if battery_level is None:
- logger.warning('Unable to find current battery level. Cannot discharge.')
- return
- # Do not discharge if it would make battery level too low.
- if percent >= battery_level - 10:
- logger.warning('Battery is too low or discharge amount requested is too '
- 'high. Cannot discharge phone %s percent.', percent)
- return
-
- self._HardwareSetCharging(False)
-
- def device_discharged():
- self._HardwareSetCharging(True)
- current_level = int(self.GetBatteryInfo().get('level'))
- logger.info('current battery level: %s', current_level)
- if battery_level - current_level >= percent:
- return True
- self._HardwareSetCharging(False)
- return False
-
- timeout_retry.WaitFor(device_discharged, wait_period=wait_period)
-
- def ChargeDeviceToLevel(self, level, wait_period=60):
- """Enables charging and waits for device to be charged to given level.
-
- Args:
- level: level of charge to wait for.
- wait_period: time in seconds to wait between checking.
- Raises:
- device_errors.DeviceChargingError: If error while charging is detected.
- """
- self.SetCharging(True)
- charge_status = {
- 'charge_failure_count': 0,
- 'last_charge_value': 0
- }
- def device_charged():
- battery_level = self.GetBatteryInfo().get('level')
- if battery_level is None:
- logger.warning('Unable to find current battery level.')
- battery_level = 100
- else:
- logger.info('current battery level: %s', battery_level)
- battery_level = int(battery_level)
-
- # Use > so that it will not reset if charge is going down.
- if battery_level > charge_status['last_charge_value']:
- charge_status['last_charge_value'] = battery_level
- charge_status['charge_failure_count'] = 0
- else:
- charge_status['charge_failure_count'] += 1
-
- if (not battery_level >= level
- and charge_status['charge_failure_count'] >= _MAX_CHARGE_ERROR):
- raise device_errors.DeviceChargingError(
- 'Device not charging properly. Current level:%s Previous level:%s'
- % (battery_level, charge_status['last_charge_value']))
- return battery_level >= level
-
- timeout_retry.WaitFor(device_charged, wait_period=wait_period)
-
- def LetBatteryCoolToTemperature(self, target_temp, wait_period=180):
- """Lets device sit to give battery time to cool down
- Args:
- temp: maximum temperature to allow in tenths of degrees c.
- wait_period: time in seconds to wait between checking.
- """
- def cool_device():
- temp = self.GetBatteryInfo().get('temperature')
- if temp is None:
- logger.warning('Unable to find current battery temperature.')
- temp = 0
- else:
- logger.info('Current battery temperature: %s', temp)
- if int(temp) <= target_temp:
- return True
- else:
- if 'Nexus 5' in self._cache['profile']['name']:
- self._DischargeDevice(1)
- return False
-
- self._DiscoverDeviceProfile()
- self.EnableBatteryUpdates()
- logger.info('Waiting for the device to cool down to %s (0.1 C)',
- target_temp)
- timeout_retry.WaitFor(cool_device, wait_period=wait_period)
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def SetCharging(self, enabled, timeout=None, retries=None):
- """Enables or disables charging on the device.
-
- Args:
- enabled: A boolean indicating whether charging should be enabled or
- disabled.
- timeout: timeout in seconds
- retries: number of retries
- """
- if self.GetCharging() == enabled:
- logger.warning('Device charging already in expected state: %s', enabled)
- return
-
- self._DiscoverDeviceProfile()
- if enabled:
- if self._cache['profile']['enable_command']:
- self._HardwareSetCharging(enabled)
- else:
- logger.info('Unable to enable charging via hardware. '
- 'Falling back to software enabling.')
- self.EnableBatteryUpdates()
- else:
- if self._cache['profile']['enable_command']:
- self._ClearPowerData()
- self._HardwareSetCharging(enabled)
- else:
- logger.info('Unable to disable charging via hardware. '
- 'Falling back to software disabling.')
- self.DisableBatteryUpdates()
-
- def _HardwareSetCharging(self, enabled, timeout=None, retries=None):
- """Enables or disables charging on the device.
-
- Args:
- enabled: A boolean indicating whether charging should be enabled or
- disabled.
- timeout: timeout in seconds
- retries: number of retries
-
- Raises:
- device_errors.CommandFailedError: If method of disabling charging cannot
- be determined.
- """
- self._DiscoverDeviceProfile()
- if not self._cache['profile']['enable_command']:
- raise device_errors.CommandFailedError(
- 'Unable to find charging commands.')
-
- command = (self._cache['profile']['enable_command'] if enabled
- else self._cache['profile']['disable_command'])
-
- def verify_charging():
- return self.GetCharging() == enabled
-
- self._device.RunShellCommand(
- command, check_return=True, as_root=True, large_output=True)
- timeout_retry.WaitFor(verify_charging, wait_period=1)
-
- @contextlib.contextmanager
- def PowerMeasurement(self, timeout=None, retries=None):
- """Context manager that enables battery power collection.
-
- Once the with block is exited, charging is resumed. Will attempt to disable
- charging at the hardware level, and if that fails will fall back to software
- disabling of battery updates.
-
- Only for devices L and higher.
-
- Example usage:
- with PowerMeasurement():
- browser_actions()
- get_power_data() # report usage within this block
- after_measurements() # Anything that runs after power
- # measurements are collected
-
- Args:
- timeout: timeout in seconds
- retries: number of retries
- """
- try:
- self.SetCharging(False, timeout=timeout, retries=retries)
- yield
- finally:
- self.SetCharging(True, timeout=timeout, retries=retries)
-
- def _ClearPowerData(self):
- """Resets battery data and makes device appear like it is not
- charging so that it will collect power data since last charge.
-
- Returns:
- True if power data cleared.
- False if power data clearing is not supported (pre-L)
-
- Raises:
- device_errors.DeviceVersionError: If power clearing is supported,
- but fails.
- """
- if self._device.build_version_sdk < version_codes.LOLLIPOP:
- logger.warning('Dumpsys power data only available on 5.0 and above. '
- 'Cannot clear power data.')
- return False
-
- self._device.RunShellCommand(
- ['dumpsys', 'battery', 'set', 'usb', '1'], check_return=True)
- self._device.RunShellCommand(
- ['dumpsys', 'battery', 'set', 'ac', '1'], check_return=True)
-
- def test_if_clear():
- self._device.RunShellCommand(
- ['dumpsys', 'batterystats', '--reset'], check_return=True)
- battery_data = self._device.RunShellCommand(
- ['dumpsys', 'batterystats', '--charged', '-c'],
- check_return=True, large_output=True)
- for line in battery_data:
- l = line.split(',')
- if (len(l) > _PWI_POWER_CONSUMPTION_INDEX
- and l[_ROW_TYPE_INDEX] == 'pwi'
- and float(l[_PWI_POWER_CONSUMPTION_INDEX]) != 0.0):
- return False
- return True
-
- try:
- timeout_retry.WaitFor(test_if_clear, wait_period=1)
- return True
- finally:
- self._device.RunShellCommand(
- ['dumpsys', 'battery', 'reset'], check_return=True)
-
- def _DiscoverDeviceProfile(self):
- """Checks and caches device information.
-
- Returns:
- True if profile is found, false otherwise.
- """
-
- if 'profile' in self._cache:
- return True
- for profile in _DEVICE_PROFILES:
- if self._device.product_model in profile['name']:
- self._cache['profile'] = profile
- return True
- self._cache['profile'] = {
- 'name': [],
- 'enable_command': None,
- 'disable_command': None,
- 'charge_counter': None,
- 'voltage': None,
- 'current': None,
- }
- return False
diff --git a/third_party/catapult/devil/devil/android/battery_utils_test.py b/third_party/catapult/devil/devil/android/battery_utils_test.py
deleted file mode 100755
index beaba3b001..0000000000
--- a/third_party/catapult/devil/devil/android/battery_utils_test.py
+++ /dev/null
@@ -1,694 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""
-Unit tests for the contents of battery_utils.py
-"""
-
-# pylint: disable=protected-access,unused-argument
-
-import logging
-import unittest
-
-from devil import devil_env
-from devil.android import battery_utils
-from devil.android import device_errors
-from devil.android import device_utils
-from devil.android import device_utils_test
-from devil.utils import mock_calls
-
-with devil_env.SysPath(devil_env.PYMOCK_PATH):
- import mock # pylint: disable=import-error
-
-_DUMPSYS_OUTPUT = [
- '9,0,i,uid,1000,test_package1',
- '9,0,i,uid,1001,test_package2',
- '9,1000,l,pwi,uid,1',
- '9,1001,l,pwi,uid,2',
- '9,0,l,pws,1728,2000,190,207',
-]
-
-
-class BatteryUtilsTest(mock_calls.TestCase):
-
- _NEXUS_5 = {
- 'name': 'Nexus 5',
- 'witness_file': '/sys/kernel/debug/bq24192/INPUT_SRC_CONT',
- 'enable_command': (
- 'echo 0x4A > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && '
- 'echo 1 > /sys/class/power_supply/usb/online'),
- 'disable_command': (
- 'echo 0xCA > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && '
- 'chmod 644 /sys/class/power_supply/usb/online && '
- 'echo 0 > /sys/class/power_supply/usb/online'),
- 'charge_counter': None,
- 'voltage': None,
- 'current': None,
- }
-
- _NEXUS_6 = {
- 'name': 'Nexus 6',
- 'witness_file': None,
- 'enable_command': None,
- 'disable_command': None,
- 'charge_counter': (
- '/sys/class/power_supply/max170xx_battery/charge_counter_ext'),
- 'voltage': '/sys/class/power_supply/max170xx_battery/voltage_now',
- 'current': '/sys/class/power_supply/max170xx_battery/current_now',
- }
-
- _NEXUS_10 = {
- 'name': 'Nexus 10',
- 'witness_file': None,
- 'enable_command': None,
- 'disable_command': None,
- 'charge_counter': (
- '/sys/class/power_supply/ds2784-fuelgauge/charge_counter_ext'),
- 'voltage': '/sys/class/power_supply/ds2784-fuelgauge/voltage_now',
- 'current': '/sys/class/power_supply/ds2784-fuelgauge/current_now',
- }
-
- def ShellError(self, output=None, status=1):
- def action(cmd, *args, **kwargs):
- raise device_errors.AdbShellCommandFailedError(
- cmd, output, status, str(self.device))
- if output is None:
- output = 'Permission denied\n'
- return action
-
- def setUp(self):
- self.adb = device_utils_test._AdbWrapperMock('0123456789abcdef')
- self.device = device_utils.DeviceUtils(
- self.adb, default_timeout=10, default_retries=0)
- self.watchMethodCalls(self.call.adb, ignore=['GetDeviceSerial'])
- self.battery = battery_utils.BatteryUtils(
- self.device, default_timeout=10, default_retries=0)
-
-
-class BatteryUtilsInitTest(unittest.TestCase):
-
- def testInitWithDeviceUtil(self):
- serial = '0fedcba987654321'
- d = device_utils.DeviceUtils(serial)
- b = battery_utils.BatteryUtils(d)
- self.assertEqual(d, b._device)
-
- def testInitWithMissing_fails(self):
- with self.assertRaises(TypeError):
- battery_utils.BatteryUtils(None)
- with self.assertRaises(TypeError):
- battery_utils.BatteryUtils('')
-
-
-class BatteryUtilsSetChargingTest(BatteryUtilsTest):
-
- @mock.patch('time.sleep', mock.Mock())
- def testHardwareSetCharging_enabled(self):
- self.battery._cache['profile'] = self._NEXUS_5
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- mock.ANY, check_return=True, as_root=True, large_output=True), []),
- (self.call.battery.GetCharging(), False),
- (self.call.battery.GetCharging(), True)):
- self.battery._HardwareSetCharging(True)
-
- def testHardwareSetCharging_alreadyEnabled(self):
- self.battery._cache['profile'] = self._NEXUS_5
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- mock.ANY, check_return=True, as_root=True, large_output=True), []),
- (self.call.battery.GetCharging(), True)):
- self.battery._HardwareSetCharging(True)
-
- @mock.patch('time.sleep', mock.Mock())
- def testHardwareSetCharging_disabled(self):
- self.battery._cache['profile'] = self._NEXUS_5
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- mock.ANY, check_return=True, as_root=True, large_output=True), []),
- (self.call.battery.GetCharging(), True),
- (self.call.battery.GetCharging(), False)):
- self.battery._HardwareSetCharging(False)
-
-
-class BatteryUtilsSetBatteryMeasurementTest(BatteryUtilsTest):
-
- @mock.patch('time.sleep', mock.Mock())
- def testBatteryMeasurementWifi(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=22):
- with self.assertCalls(
- (self.call.battery._ClearPowerData(), True),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery', 'set', 'ac', '0'], check_return=True), []),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery', 'set', 'usb', '0'], check_return=True),
- []),
- (self.call.battery.GetCharging(), False),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery', 'reset'], check_return=True), []),
- (self.call.battery.GetCharging(), False),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery'], check_return=True), ['UPDATES STOPPED']),
- (self.call.battery.GetCharging(), False),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery'], check_return=True), [])):
- with self.battery.BatteryMeasurement():
- pass
-
- @mock.patch('time.sleep', mock.Mock())
- def testBatteryMeasurementUsb(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=22):
- with self.assertCalls(
- (self.call.battery._ClearPowerData(), True),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery', 'set', 'ac', '0'], check_return=True), []),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery', 'set', 'usb', '0'], check_return=True),
- []),
- (self.call.battery.GetCharging(), False),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery', 'reset'], check_return=True), []),
- (self.call.battery.GetCharging(), False),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery'], check_return=True), ['UPDATES STOPPED']),
- (self.call.battery.GetCharging(), True)):
- with self.battery.BatteryMeasurement():
- pass
-
-
-class BatteryUtilsGetPowerData(BatteryUtilsTest):
-
- def testGetPowerData(self):
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- ['dumpsys', 'batterystats', '-c'],
- check_return=True, large_output=True),
- _DUMPSYS_OUTPUT)):
- data = self.battery.GetPowerData()
- check = {
- 'system_total': 2000.0,
- 'per_package': {
- 'test_package1': {'uid': '1000', 'data': [1.0]},
- 'test_package2': {'uid': '1001', 'data': [2.0]}
- }
- }
- self.assertEqual(data, check)
-
- def testGetPowerData_packageCollisionSame(self):
- self.battery._cache['uids'] = {'test_package1': '1000'}
- with self.assertCall(
- self.call.device.RunShellCommand(
- ['dumpsys', 'batterystats', '-c'],
- check_return=True, large_output=True),
- _DUMPSYS_OUTPUT):
- data = self.battery.GetPowerData()
- check = {
- 'system_total': 2000.0,
- 'per_package': {
- 'test_package1': {'uid': '1000', 'data': [1.0]},
- 'test_package2': {'uid': '1001', 'data': [2.0]}
- }
- }
- self.assertEqual(data, check)
-
- def testGetPowerData_packageCollisionDifferent(self):
- self.battery._cache['uids'] = {'test_package1': '1'}
- with self.assertCall(
- self.call.device.RunShellCommand(
- ['dumpsys', 'batterystats', '-c'],
- check_return=True, large_output=True),
- _DUMPSYS_OUTPUT):
- with self.assertRaises(device_errors.CommandFailedError):
- self.battery.GetPowerData()
-
- def testGetPowerData_cacheCleared(self):
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- ['dumpsys', 'batterystats', '-c'],
- check_return=True, large_output=True),
- _DUMPSYS_OUTPUT)):
- self.battery._cache.clear()
- data = self.battery.GetPowerData()
- check = {
- 'system_total': 2000.0,
- 'per_package': {
- 'test_package1': {'uid': '1000', 'data': [1.0]},
- 'test_package2': {'uid': '1001', 'data': [2.0]}
- }
- }
- self.assertEqual(data, check)
-
-
-class BatteryUtilsChargeDevice(BatteryUtilsTest):
-
- @mock.patch('time.sleep', mock.Mock())
- def testChargeDeviceToLevel_pass(self):
- with self.assertCalls(
- (self.call.battery.SetCharging(True)),
- (self.call.battery.GetBatteryInfo(), {'level': '50'}),
- (self.call.battery.GetBatteryInfo(), {'level': '100'})):
- self.battery.ChargeDeviceToLevel(95)
-
- @mock.patch('time.sleep', mock.Mock())
- def testChargeDeviceToLevel_failureSame(self):
- with self.assertCalls(
- (self.call.battery.SetCharging(True)),
- (self.call.battery.GetBatteryInfo(), {'level': '50'}),
- (self.call.battery.GetBatteryInfo(), {'level': '50'}),
-
- (self.call.battery.GetBatteryInfo(), {'level': '50'})):
- with self.assertRaises(device_errors.DeviceChargingError):
- old_max = battery_utils._MAX_CHARGE_ERROR
- try:
- battery_utils._MAX_CHARGE_ERROR = 2
- self.battery.ChargeDeviceToLevel(95)
- finally:
- battery_utils._MAX_CHARGE_ERROR = old_max
-
- @mock.patch('time.sleep', mock.Mock())
- def testChargeDeviceToLevel_failureDischarge(self):
- with self.assertCalls(
- (self.call.battery.SetCharging(True)),
- (self.call.battery.GetBatteryInfo(), {'level': '50'}),
- (self.call.battery.GetBatteryInfo(), {'level': '49'}),
- (self.call.battery.GetBatteryInfo(), {'level': '48'})):
- with self.assertRaises(device_errors.DeviceChargingError):
- old_max = battery_utils._MAX_CHARGE_ERROR
- try:
- battery_utils._MAX_CHARGE_ERROR = 2
- self.battery.ChargeDeviceToLevel(95)
- finally:
- battery_utils._MAX_CHARGE_ERROR = old_max
-
-
-class BatteryUtilsDischargeDevice(BatteryUtilsTest):
-
- @mock.patch('time.sleep', mock.Mock())
- def testDischargeDevice_exact(self):
- with self.assertCalls(
- (self.call.battery.GetBatteryInfo(), {'level': '100'}),
- (self.call.battery._HardwareSetCharging(False)),
- (self.call.battery._HardwareSetCharging(True)),
- (self.call.battery.GetBatteryInfo(), {'level': '99'})):
- self.battery._DischargeDevice(1)
-
- @mock.patch('time.sleep', mock.Mock())
- def testDischargeDevice_over(self):
- with self.assertCalls(
- (self.call.battery.GetBatteryInfo(), {'level': '100'}),
- (self.call.battery._HardwareSetCharging(False)),
- (self.call.battery._HardwareSetCharging(True)),
- (self.call.battery.GetBatteryInfo(), {'level': '50'})):
- self.battery._DischargeDevice(1)
-
- @mock.patch('time.sleep', mock.Mock())
- def testDischargeDevice_takeslong(self):
- with self.assertCalls(
- (self.call.battery.GetBatteryInfo(), {'level': '100'}),
- (self.call.battery._HardwareSetCharging(False)),
- (self.call.battery._HardwareSetCharging(True)),
- (self.call.battery.GetBatteryInfo(), {'level': '100'}),
- (self.call.battery._HardwareSetCharging(False)),
- (self.call.battery._HardwareSetCharging(True)),
- (self.call.battery.GetBatteryInfo(), {'level': '99'}),
- (self.call.battery._HardwareSetCharging(False)),
- (self.call.battery._HardwareSetCharging(True)),
- (self.call.battery.GetBatteryInfo(), {'level': '98'}),
- (self.call.battery._HardwareSetCharging(False)),
- (self.call.battery._HardwareSetCharging(True)),
- (self.call.battery.GetBatteryInfo(), {'level': '97'})):
- self.battery._DischargeDevice(3)
-
- @mock.patch('time.sleep', mock.Mock())
- def testDischargeDevice_dischargeTooClose(self):
- with self.assertCalls(
- (self.call.battery.GetBatteryInfo(), {'level': '100'})):
- self.battery._DischargeDevice(99)
-
- @mock.patch('time.sleep', mock.Mock())
- def testDischargeDevice_percentageOutOfBounds(self):
- with self.assertCalls(
- (self.call.battery.GetBatteryInfo(), {'level': '100'})):
- with self.assertRaises(ValueError):
- self.battery._DischargeDevice(100)
- with self.assertCalls(
- (self.call.battery.GetBatteryInfo(), {'level': '100'})):
- with self.assertRaises(ValueError):
- self.battery._DischargeDevice(0)
-
-
-class BatteryUtilsGetBatteryInfoTest(BatteryUtilsTest):
-
- def testGetBatteryInfo_normal(self):
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery'], check_return=True),
- [
- 'Current Battery Service state:',
- ' AC powered: false',
- ' USB powered: true',
- ' level: 100',
- ' temperature: 321',
- ])):
- self.assertEquals(
- {
- 'AC powered': 'false',
- 'USB powered': 'true',
- 'level': '100',
- 'temperature': '321',
- },
- self.battery.GetBatteryInfo())
-
- def testGetBatteryInfo_nothing(self):
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery'], check_return=True), [])):
- self.assertEquals({}, self.battery.GetBatteryInfo())
-
-
-class BatteryUtilsGetChargingTest(BatteryUtilsTest):
-
- def testGetCharging_usb(self):
- with self.assertCall(
- self.call.battery.GetBatteryInfo(), {'USB powered': 'true'}):
- self.assertTrue(self.battery.GetCharging())
-
- def testGetCharging_usbFalse(self):
- with self.assertCall(
- self.call.battery.GetBatteryInfo(), {'USB powered': 'false'}):
- self.assertFalse(self.battery.GetCharging())
-
- def testGetCharging_ac(self):
- with self.assertCall(
- self.call.battery.GetBatteryInfo(), {'AC powered': 'true'}):
- self.assertTrue(self.battery.GetCharging())
-
- def testGetCharging_wireless(self):
- with self.assertCall(
- self.call.battery.GetBatteryInfo(), {'Wireless powered': 'true'}):
- self.assertTrue(self.battery.GetCharging())
-
- def testGetCharging_unknown(self):
- with self.assertCall(
- self.call.battery.GetBatteryInfo(), {'level': '42'}):
- self.assertFalse(self.battery.GetCharging())
-
-
-class BatteryUtilsGetNetworkDataTest(BatteryUtilsTest):
-
- def testGetNetworkData_noDataUsage(self):
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- ['dumpsys', 'batterystats', '-c'],
- check_return=True, large_output=True),
- _DUMPSYS_OUTPUT),
- (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_snd'),
- self.ShellError()),
- (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_rcv'),
- self.ShellError())):
- self.assertEquals(self.battery.GetNetworkData('test_package1'), (0, 0))
-
- def testGetNetworkData_badPackage(self):
- with self.assertCall(
- self.call.device.RunShellCommand(
- ['dumpsys', 'batterystats', '-c'],
- check_return=True, large_output=True),
- _DUMPSYS_OUTPUT):
- self.assertEqual(self.battery.GetNetworkData('asdf'), None)
-
- def testGetNetworkData_packageNotCached(self):
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- ['dumpsys', 'batterystats', '-c'],
- check_return=True, large_output=True),
- _DUMPSYS_OUTPUT),
- (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_snd'), 1),
- (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_rcv'), 2)):
- self.assertEqual(self.battery.GetNetworkData('test_package1'), (1, 2))
-
- def testGetNetworkData_packageCached(self):
- self.battery._cache['uids'] = {'test_package1': '1000'}
- with self.assertCalls(
- (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_snd'), 1),
- (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_rcv'), 2)):
- self.assertEqual(self.battery.GetNetworkData('test_package1'), (1, 2))
-
- def testGetNetworkData_clearedCache(self):
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- ['dumpsys', 'batterystats', '-c'],
- check_return=True, large_output=True),
- _DUMPSYS_OUTPUT),
- (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_snd'), 1),
- (self.call.device.ReadFile('/proc/uid_stat/1000/tcp_rcv'), 2)):
- self.battery._cache.clear()
- self.assertEqual(self.battery.GetNetworkData('test_package1'), (1, 2))
-
-
-class BatteryUtilsLetBatteryCoolToTemperatureTest(BatteryUtilsTest):
-
- @mock.patch('time.sleep', mock.Mock())
- def testLetBatteryCoolToTemperature_startUnder(self):
- self.battery._cache['profile'] = self._NEXUS_6
- with self.assertCalls(
- (self.call.battery.EnableBatteryUpdates(), []),
- (self.call.battery.GetBatteryInfo(), {'temperature': '500'})):
- self.battery.LetBatteryCoolToTemperature(600)
-
- @mock.patch('time.sleep', mock.Mock())
- def testLetBatteryCoolToTemperature_startOver(self):
- self.battery._cache['profile'] = self._NEXUS_6
- with self.assertCalls(
- (self.call.battery.EnableBatteryUpdates(), []),
- (self.call.battery.GetBatteryInfo(), {'temperature': '500'}),
- (self.call.battery.GetBatteryInfo(), {'temperature': '400'})):
- self.battery.LetBatteryCoolToTemperature(400)
-
- @mock.patch('time.sleep', mock.Mock())
- def testLetBatteryCoolToTemperature_nexus5Hot(self):
- self.battery._cache['profile'] = self._NEXUS_5
- with self.assertCalls(
- (self.call.battery.EnableBatteryUpdates(), []),
- (self.call.battery.GetBatteryInfo(), {'temperature': '500'}),
- (self.call.battery._DischargeDevice(1), []),
- (self.call.battery.GetBatteryInfo(), {'temperature': '400'})):
- self.battery.LetBatteryCoolToTemperature(400)
-
- @mock.patch('time.sleep', mock.Mock())
- def testLetBatteryCoolToTemperature_nexus5Cool(self):
- self.battery._cache['profile'] = self._NEXUS_5
- with self.assertCalls(
- (self.call.battery.EnableBatteryUpdates(), []),
- (self.call.battery.GetBatteryInfo(), {'temperature': '400'})):
- self.battery.LetBatteryCoolToTemperature(400)
-
-
-class BatteryUtilsSupportsFuelGaugeTest(BatteryUtilsTest):
-
- def testSupportsFuelGauge_false(self):
- self.battery._cache['profile'] = self._NEXUS_5
- self.assertFalse(self.battery.SupportsFuelGauge())
-
- def testSupportsFuelGauge_trueMax(self):
- self.battery._cache['profile'] = self._NEXUS_6
- # TODO(rnephew): Change this to assertTrue when we have support for
- # disabling hardware charging on nexus 6.
- self.assertFalse(self.battery.SupportsFuelGauge())
-
- def testSupportsFuelGauge_trueDS(self):
- self.battery._cache['profile'] = self._NEXUS_10
- # TODO(rnephew): Change this to assertTrue when we have support for
- # disabling hardware charging on nexus 10.
- self.assertFalse(self.battery.SupportsFuelGauge())
-
-
-class BatteryUtilsGetFuelGaugeChargeCounterTest(BatteryUtilsTest):
-
- def testGetFuelGaugeChargeCounter_noFuelGauge(self):
- self.battery._cache['profile'] = self._NEXUS_5
- with self.assertRaises(device_errors.CommandFailedError):
- self.battery.GetFuelGaugeChargeCounter()
-
- def testGetFuelGaugeChargeCounter_fuelGaugePresent(self):
- self.battery._cache['profile'] = self._NEXUS_6
- with self.assertCalls(
- (self.call.battery.SupportsFuelGauge(), True),
- (self.call.device.ReadFile(mock.ANY), '123')):
- self.assertEqual(self.battery.GetFuelGaugeChargeCounter(), 123)
-
-
-class BatteryUtilsSetCharging(BatteryUtilsTest):
-
- @mock.patch('time.sleep', mock.Mock())
- def testSetCharging_softwareSetTrue(self):
- self.battery._cache['profile'] = self._NEXUS_6
- with self.assertCalls(
- (self.call.battery.GetCharging(), False),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery', 'reset'], check_return=True), []),
- (self.call.battery.GetCharging(), False),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery'], check_return=True), ['UPDATES STOPPED']),
- (self.call.battery.GetCharging(), True)):
- self.battery.SetCharging(True)
-
- @mock.patch('time.sleep', mock.Mock())
- def testSetCharging_softwareSetFalse(self):
- self.battery._cache['profile'] = self._NEXUS_6
- with self.assertCalls(
- (self.call.battery.GetCharging(), True),
- (self.call.battery._ClearPowerData(), True),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery', 'set', 'ac', '0'], check_return=True), []),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery', 'set', 'usb', '0'], check_return=True), []),
- (self.call.battery.GetCharging(), False)):
- self.battery.SetCharging(False)
-
- @mock.patch('time.sleep', mock.Mock())
- def testSetCharging_hardwareSetTrue(self):
- self.battery._cache['profile'] = self._NEXUS_5
- with self.assertCalls(
- (self.call.battery.GetCharging(), False),
- (self.call.battery._HardwareSetCharging(True))):
- self.battery.SetCharging(True)
-
- @mock.patch('time.sleep', mock.Mock())
- def testSetCharging_hardwareSetFalse(self):
- self.battery._cache['profile'] = self._NEXUS_5
- with self.assertCalls(
- (self.call.battery.GetCharging(), True),
- (self.call.battery._ClearPowerData(), True),
- (self.call.battery._HardwareSetCharging(False))):
- self.battery.SetCharging(False)
-
- def testSetCharging_expectedStateAlreadyTrue(self):
- with self.assertCalls((self.call.battery.GetCharging(), True)):
- self.battery.SetCharging(True)
-
- def testSetCharging_expectedStateAlreadyFalse(self):
- with self.assertCalls((self.call.battery.GetCharging(), False)):
- self.battery.SetCharging(False)
-
-
-class BatteryUtilsPowerMeasurement(BatteryUtilsTest):
-
- def testPowerMeasurement_hardware(self):
- self.battery._cache['profile'] = self._NEXUS_5
- with self.assertCalls(
- (self.call.battery.GetCharging(), True),
- (self.call.battery._ClearPowerData(), True),
- (self.call.battery._HardwareSetCharging(False)),
- (self.call.battery.GetCharging(), False),
- (self.call.battery._HardwareSetCharging(True))):
- with self.battery.PowerMeasurement():
- pass
-
- @mock.patch('time.sleep', mock.Mock())
- def testPowerMeasurement_software(self):
- self.battery._cache['profile'] = self._NEXUS_6
- with self.assertCalls(
- (self.call.battery.GetCharging(), True),
- (self.call.battery._ClearPowerData(), True),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery', 'set', 'ac', '0'], check_return=True), []),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery', 'set', 'usb', '0'], check_return=True), []),
- (self.call.battery.GetCharging(), False),
- (self.call.battery.GetCharging(), False),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery', 'reset'], check_return=True), []),
- (self.call.battery.GetCharging(), False),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery'], check_return=True), ['UPDATES STOPPED']),
- (self.call.battery.GetCharging(), True)):
- with self.battery.PowerMeasurement():
- pass
-
-
-class BatteryUtilsDiscoverDeviceProfile(BatteryUtilsTest):
-
- def testDiscoverDeviceProfile_known(self):
- with self.patch_call(self.call.device.product_model,
- return_value='Nexus 4'):
- self.battery._DiscoverDeviceProfile()
- self.assertListEqual(self.battery._cache['profile']['name'], ["Nexus 4"])
-
- def testDiscoverDeviceProfile_unknown(self):
- with self.patch_call(self.call.device.product_model,
- return_value='Other'):
- self.battery._DiscoverDeviceProfile()
- self.assertListEqual(self.battery._cache['profile']['name'], [])
-
-
-class BatteryUtilsClearPowerData(BatteryUtilsTest):
-
- def testClearPowerData_preL(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=20):
- self.assertFalse(self.battery._ClearPowerData())
-
- def testClearPowerData_clearedL(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=22):
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery', 'set', 'usb', '1'], check_return=True),
- []),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery', 'set', 'ac', '1'], check_return=True), []),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'batterystats', '--reset'], check_return=True), []),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'batterystats', '--charged', '-c'],
- check_return=True, large_output=True), []),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery', 'reset'], check_return=True), [])):
- self.assertTrue(self.battery._ClearPowerData())
-
- @mock.patch('time.sleep', mock.Mock())
- def testClearPowerData_notClearedL(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=22):
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery', 'set', 'usb', '1'], check_return=True),
- []),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery', 'set', 'ac', '1'], check_return=True), []),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'batterystats', '--reset'], check_return=True), []),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'batterystats', '--charged', '-c'],
- check_return=True, large_output=True),
- ['9,1000,l,pwi,uid,0.0327']),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'batterystats', '--reset'], check_return=True), []),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'batterystats', '--charged', '-c'],
- check_return=True, large_output=True),
- ['9,1000,l,pwi,uid,0.0327']),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'batterystats', '--reset'], check_return=True), []),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'batterystats', '--charged', '-c'],
- check_return=True, large_output=True),
- ['9,1000,l,pwi,uid,0.0327']),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'batterystats', '--reset'], check_return=True), []),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'batterystats', '--charged', '-c'],
- check_return=True, large_output=True),
- ['9,1000,l,pwi,uid,0.0']),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'battery', 'reset'], check_return=True), [])):
- self.battery._ClearPowerData()
-
-
-if __name__ == '__main__':
- logging.getLogger().setLevel(logging.DEBUG)
- unittest.main(verbosity=2)
diff --git a/third_party/catapult/devil/devil/android/constants/__init__.py b/third_party/catapult/devil/devil/android/constants/__init__.py
deleted file mode 100644
index 50b23dff63..0000000000
--- a/third_party/catapult/devil/devil/android/constants/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
diff --git a/third_party/catapult/devil/devil/android/constants/chrome.py b/third_party/catapult/devil/devil/android/constants/chrome.py
deleted file mode 100644
index dca04bdc87..0000000000
--- a/third_party/catapult/devil/devil/android/constants/chrome.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import collections
-
-PackageInfo = collections.namedtuple(
- 'PackageInfo',
- ['package', 'activity', 'cmdline_file', 'devtools_socket'])
-
-PACKAGE_INFO = {
- 'chrome_document': PackageInfo(
- 'com.google.android.apps.chrome.document',
- 'com.google.android.apps.chrome.document.ChromeLauncherActivity',
- 'chrome-command-line',
- 'chrome_devtools_remote'),
- 'chrome': PackageInfo(
- 'com.google.android.apps.chrome',
- 'com.google.android.apps.chrome.Main',
- 'chrome-command-line',
- 'chrome_devtools_remote'),
- 'chrome_beta': PackageInfo(
- 'com.chrome.beta',
- 'com.google.android.apps.chrome.Main',
- 'chrome-command-line',
- 'chrome_devtools_remote'),
- 'chrome_stable': PackageInfo(
- 'com.android.chrome',
- 'com.google.android.apps.chrome.Main',
- 'chrome-command-line',
- 'chrome_devtools_remote'),
- 'chrome_dev': PackageInfo(
- 'com.chrome.dev',
- 'com.google.android.apps.chrome.Main',
- 'chrome-command-line',
- 'chrome_devtools_remote'),
- 'chrome_canary': PackageInfo(
- 'com.chrome.canary',
- 'com.google.android.apps.chrome.Main',
- 'chrome-command-line',
- 'chrome_devtools_remote'),
- 'chrome_work': PackageInfo(
- 'com.chrome.work',
- 'com.google.android.apps.chrome.Main',
- 'chrome-command-line',
- 'chrome_devtools_remote'),
- 'chromium': PackageInfo(
- 'org.chromium.chrome',
- 'com.google.android.apps.chrome.Main',
- 'chrome-command-line',
- 'chrome_devtools_remote'),
- 'content_shell': PackageInfo(
- 'org.chromium.content_shell_apk',
- '.ContentShellActivity',
- 'content-shell-command-line',
- 'content_shell_devtools_remote'),
-}
diff --git a/third_party/catapult/devil/devil/android/constants/file_system.py b/third_party/catapult/devil/devil/android/constants/file_system.py
deleted file mode 100644
index bffec61442..0000000000
--- a/third_party/catapult/devil/devil/android/constants/file_system.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-TEST_EXECUTABLE_DIR = '/data/local/tmp'
diff --git a/third_party/catapult/devil/devil/android/decorators.py b/third_party/catapult/devil/devil/android/decorators.py
deleted file mode 100644
index 3844b49a1e..0000000000
--- a/third_party/catapult/devil/devil/android/decorators.py
+++ /dev/null
@@ -1,176 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""
-Function/method decorators that provide timeout and retry logic.
-"""
-
-import functools
-import itertools
-import sys
-
-from devil.android import device_errors
-from devil.utils import cmd_helper
-from devil.utils import reraiser_thread
-from devil.utils import timeout_retry
-
-DEFAULT_TIMEOUT_ATTR = '_default_timeout'
-DEFAULT_RETRIES_ATTR = '_default_retries'
-
-
-def _TimeoutRetryWrapper(
- f, timeout_func, retries_func, retry_if_func=timeout_retry.AlwaysRetry,
- pass_values=False):
- """ Wraps a funcion with timeout and retry handling logic.
-
- Args:
- f: The function to wrap.
- timeout_func: A callable that returns the timeout value.
- retries_func: A callable that returns the retries value.
- pass_values: If True, passes the values returned by |timeout_func| and
- |retries_func| to the wrapped function as 'timeout' and
- 'retries' kwargs, respectively.
- Returns:
- The wrapped function.
- """
- @functools.wraps(f)
- def timeout_retry_wrapper(*args, **kwargs):
- timeout = timeout_func(*args, **kwargs)
- retries = retries_func(*args, **kwargs)
- if pass_values:
- kwargs['timeout'] = timeout
- kwargs['retries'] = retries
-
- @functools.wraps(f)
- def impl():
- return f(*args, **kwargs)
- try:
- if timeout_retry.CurrentTimeoutThreadGroup():
- # Don't wrap if there's already an outer timeout thread.
- return impl()
- else:
- desc = '%s(%s)' % (f.__name__, ', '.join(itertools.chain(
- (str(a) for a in args),
- ('%s=%s' % (k, str(v)) for k, v in kwargs.iteritems()))))
- return timeout_retry.Run(impl, timeout, retries, desc=desc,
- retry_if_func=retry_if_func)
- except reraiser_thread.TimeoutError as e:
- raise device_errors.CommandTimeoutError(str(e)), None, (
- sys.exc_info()[2])
- except cmd_helper.TimeoutError as e:
- raise device_errors.CommandTimeoutError(str(e)), None, (
- sys.exc_info()[2])
- return timeout_retry_wrapper
-
-
-def WithTimeoutAndRetries(f):
- """A decorator that handles timeouts and retries.
-
- 'timeout' and 'retries' kwargs must be passed to the function.
-
- Args:
- f: The function to decorate.
- Returns:
- The decorated function.
- """
- get_timeout = lambda *a, **kw: kw['timeout']
- get_retries = lambda *a, **kw: kw['retries']
- return _TimeoutRetryWrapper(f, get_timeout, get_retries)
-
-
-def WithTimeoutAndConditionalRetries(retry_if_func):
- """Returns a decorator that handles timeouts and, in some cases, retries.
-
- 'timeout' and 'retries' kwargs must be passed to the function.
-
- Args:
- retry_if_func: A unary callable that takes an exception and returns
- whether failures should be retried.
- Returns:
- The actual decorator.
- """
- def decorator(f):
- get_timeout = lambda *a, **kw: kw['timeout']
- get_retries = lambda *a, **kw: kw['retries']
- return _TimeoutRetryWrapper(
- f, get_timeout, get_retries, retry_if_func=retry_if_func)
- return decorator
-
-
-def WithExplicitTimeoutAndRetries(timeout, retries):
- """Returns a decorator that handles timeouts and retries.
-
- The provided |timeout| and |retries| values are always used.
-
- Args:
- timeout: The number of seconds to wait for the decorated function to
- return. Always used.
- retries: The number of times the decorated function should be retried on
- failure. Always used.
- Returns:
- The actual decorator.
- """
- def decorator(f):
- get_timeout = lambda *a, **kw: timeout
- get_retries = lambda *a, **kw: retries
- return _TimeoutRetryWrapper(f, get_timeout, get_retries)
- return decorator
-
-
-def WithTimeoutAndRetriesDefaults(default_timeout, default_retries):
- """Returns a decorator that handles timeouts and retries.
-
- The provided |default_timeout| and |default_retries| values are used only
- if timeout and retries values are not provided.
-
- Args:
- default_timeout: The number of seconds to wait for the decorated function
- to return. Only used if a 'timeout' kwarg is not passed
- to the decorated function.
- default_retries: The number of times the decorated function should be
- retried on failure. Only used if a 'retries' kwarg is not
- passed to the decorated function.
- Returns:
- The actual decorator.
- """
- def decorator(f):
- get_timeout = lambda *a, **kw: kw.get('timeout', default_timeout)
- get_retries = lambda *a, **kw: kw.get('retries', default_retries)
- return _TimeoutRetryWrapper(f, get_timeout, get_retries, pass_values=True)
- return decorator
-
-
-def WithTimeoutAndRetriesFromInstance(
- default_timeout_name=DEFAULT_TIMEOUT_ATTR,
- default_retries_name=DEFAULT_RETRIES_ATTR,
- min_default_timeout=None):
- """Returns a decorator that handles timeouts and retries.
-
- The provided |default_timeout_name| and |default_retries_name| are used to
- get the default timeout value and the default retries value from the object
- instance if timeout and retries values are not provided.
-
- Note that this should only be used to decorate methods, not functions.
-
- Args:
- default_timeout_name: The name of the default timeout attribute of the
- instance.
- default_retries_name: The name of the default retries attribute of the
- instance.
- min_timeout: Miniumum timeout to be used when using instance timeout.
- Returns:
- The actual decorator.
- """
- def decorator(f):
- def get_timeout(inst, *_args, **kwargs):
- ret = getattr(inst, default_timeout_name)
- if min_default_timeout is not None:
- ret = max(min_default_timeout, ret)
- return kwargs.get('timeout', ret)
-
- def get_retries(inst, *_args, **kwargs):
- return kwargs.get('retries', getattr(inst, default_retries_name))
- return _TimeoutRetryWrapper(f, get_timeout, get_retries, pass_values=True)
- return decorator
-
diff --git a/third_party/catapult/devil/devil/android/decorators_test.py b/third_party/catapult/devil/devil/android/decorators_test.py
deleted file mode 100644
index f60953e1f2..0000000000
--- a/third_party/catapult/devil/devil/android/decorators_test.py
+++ /dev/null
@@ -1,332 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""
-Unit tests for decorators.py.
-"""
-
-# pylint: disable=W0613
-
-import time
-import traceback
-import unittest
-
-from devil.android import decorators
-from devil.android import device_errors
-from devil.utils import reraiser_thread
-
-_DEFAULT_TIMEOUT = 30
-_DEFAULT_RETRIES = 3
-
-
-class DecoratorsTest(unittest.TestCase):
- _decorated_function_called_count = 0
-
- def testFunctionDecoratorDoesTimeouts(self):
- """Tests that the base decorator handles the timeout logic."""
- DecoratorsTest._decorated_function_called_count = 0
-
- @decorators.WithTimeoutAndRetries
- def alwaysTimesOut(timeout=None, retries=None):
- DecoratorsTest._decorated_function_called_count += 1
- time.sleep(100)
-
- start_time = time.time()
- with self.assertRaises(device_errors.CommandTimeoutError):
- alwaysTimesOut(timeout=1, retries=0)
- elapsed_time = time.time() - start_time
- self.assertTrue(elapsed_time >= 1)
- self.assertEquals(1, DecoratorsTest._decorated_function_called_count)
-
- def testFunctionDecoratorDoesRetries(self):
- """Tests that the base decorator handles the retries logic."""
- DecoratorsTest._decorated_function_called_count = 0
-
- @decorators.WithTimeoutAndRetries
- def alwaysRaisesCommandFailedError(timeout=None, retries=None):
- DecoratorsTest._decorated_function_called_count += 1
- raise device_errors.CommandFailedError('testCommand failed')
-
- with self.assertRaises(device_errors.CommandFailedError):
- alwaysRaisesCommandFailedError(timeout=30, retries=10)
- self.assertEquals(11, DecoratorsTest._decorated_function_called_count)
-
- def testFunctionDecoratorRequiresParams(self):
- """Tests that the base decorator requires timeout and retries params."""
- @decorators.WithTimeoutAndRetries
- def requiresExplicitTimeoutAndRetries(timeout=None, retries=None):
- return (timeout, retries)
-
- with self.assertRaises(KeyError):
- requiresExplicitTimeoutAndRetries()
- with self.assertRaises(KeyError):
- requiresExplicitTimeoutAndRetries(timeout=10)
- with self.assertRaises(KeyError):
- requiresExplicitTimeoutAndRetries(retries=0)
- expected_timeout = 10
- expected_retries = 1
- (actual_timeout, actual_retries) = (
- requiresExplicitTimeoutAndRetries(timeout=expected_timeout,
- retries=expected_retries))
- self.assertEquals(expected_timeout, actual_timeout)
- self.assertEquals(expected_retries, actual_retries)
-
- def testFunctionDecoratorTranslatesReraiserExceptions(self):
- """Tests that the explicit decorator translates reraiser exceptions."""
- @decorators.WithTimeoutAndRetries
- def alwaysRaisesProvidedException(exception, timeout=None, retries=None):
- raise exception
-
- exception_desc = 'Reraiser thread timeout error'
- with self.assertRaises(device_errors.CommandTimeoutError) as e:
- alwaysRaisesProvidedException(
- reraiser_thread.TimeoutError(exception_desc),
- timeout=10, retries=1)
- self.assertEquals(exception_desc, str(e.exception))
-
- def testConditionalRetriesDecoratorRetries(self):
- def do_not_retry_no_adb_error(exc):
- return not isinstance(exc, device_errors.NoAdbError)
-
- actual_tries = [0]
-
- @decorators.WithTimeoutAndConditionalRetries(do_not_retry_no_adb_error)
- def alwaysRaisesCommandFailedError(timeout=None, retries=None):
- actual_tries[0] += 1
- raise device_errors.CommandFailedError('Command failed :(')
-
- with self.assertRaises(device_errors.CommandFailedError):
- alwaysRaisesCommandFailedError(timeout=10, retries=10)
- self.assertEquals(11, actual_tries[0])
-
- def testConditionalRetriesDecoratorDoesntRetry(self):
- def do_not_retry_no_adb_error(exc):
- return not isinstance(exc, device_errors.NoAdbError)
-
- actual_tries = [0]
-
- @decorators.WithTimeoutAndConditionalRetries(do_not_retry_no_adb_error)
- def alwaysRaisesNoAdbError(timeout=None, retries=None):
- actual_tries[0] += 1
- raise device_errors.NoAdbError()
-
- with self.assertRaises(device_errors.NoAdbError):
- alwaysRaisesNoAdbError(timeout=10, retries=10)
- self.assertEquals(1, actual_tries[0])
-
- def testDefaultsFunctionDecoratorDoesTimeouts(self):
- """Tests that the defaults decorator handles timeout logic."""
- DecoratorsTest._decorated_function_called_count = 0
-
- @decorators.WithTimeoutAndRetriesDefaults(1, 0)
- def alwaysTimesOut(timeout=None, retries=None):
- DecoratorsTest._decorated_function_called_count += 1
- time.sleep(100)
-
- start_time = time.time()
- with self.assertRaises(device_errors.CommandTimeoutError):
- alwaysTimesOut()
- elapsed_time = time.time() - start_time
- self.assertTrue(elapsed_time >= 1)
- self.assertEquals(1, DecoratorsTest._decorated_function_called_count)
-
- DecoratorsTest._decorated_function_called_count = 0
- with self.assertRaises(device_errors.CommandTimeoutError):
- alwaysTimesOut(timeout=2)
- elapsed_time = time.time() - start_time
- self.assertTrue(elapsed_time >= 2)
- self.assertEquals(1, DecoratorsTest._decorated_function_called_count)
-
- def testDefaultsFunctionDecoratorDoesRetries(self):
- """Tests that the defaults decorator handles retries logic."""
- DecoratorsTest._decorated_function_called_count = 0
-
- @decorators.WithTimeoutAndRetriesDefaults(30, 10)
- def alwaysRaisesCommandFailedError(timeout=None, retries=None):
- DecoratorsTest._decorated_function_called_count += 1
- raise device_errors.CommandFailedError('testCommand failed')
-
- with self.assertRaises(device_errors.CommandFailedError):
- alwaysRaisesCommandFailedError()
- self.assertEquals(11, DecoratorsTest._decorated_function_called_count)
-
- DecoratorsTest._decorated_function_called_count = 0
- with self.assertRaises(device_errors.CommandFailedError):
- alwaysRaisesCommandFailedError(retries=5)
- self.assertEquals(6, DecoratorsTest._decorated_function_called_count)
-
- def testDefaultsFunctionDecoratorPassesValues(self):
- """Tests that the defaults decorator passes timeout and retries kwargs."""
- @decorators.WithTimeoutAndRetriesDefaults(30, 10)
- def alwaysReturnsTimeouts(timeout=None, retries=None):
- return timeout
-
- self.assertEquals(30, alwaysReturnsTimeouts())
- self.assertEquals(120, alwaysReturnsTimeouts(timeout=120))
-
- @decorators.WithTimeoutAndRetriesDefaults(30, 10)
- def alwaysReturnsRetries(timeout=None, retries=None):
- return retries
-
- self.assertEquals(10, alwaysReturnsRetries())
- self.assertEquals(1, alwaysReturnsRetries(retries=1))
-
- def testDefaultsFunctionDecoratorTranslatesReraiserExceptions(self):
- """Tests that the explicit decorator translates reraiser exceptions."""
- @decorators.WithTimeoutAndRetriesDefaults(30, 10)
- def alwaysRaisesProvidedException(exception, timeout=None, retries=None):
- raise exception
-
- exception_desc = 'Reraiser thread timeout error'
- with self.assertRaises(device_errors.CommandTimeoutError) as e:
- alwaysRaisesProvidedException(
- reraiser_thread.TimeoutError(exception_desc))
- self.assertEquals(exception_desc, str(e.exception))
-
- def testExplicitFunctionDecoratorDoesTimeouts(self):
- """Tests that the explicit decorator handles timeout logic."""
- DecoratorsTest._decorated_function_called_count = 0
-
- @decorators.WithExplicitTimeoutAndRetries(1, 0)
- def alwaysTimesOut():
- DecoratorsTest._decorated_function_called_count += 1
- time.sleep(100)
-
- start_time = time.time()
- with self.assertRaises(device_errors.CommandTimeoutError):
- alwaysTimesOut()
- elapsed_time = time.time() - start_time
- self.assertTrue(elapsed_time >= 1)
- self.assertEquals(1, DecoratorsTest._decorated_function_called_count)
-
- def testExplicitFunctionDecoratorDoesRetries(self):
- """Tests that the explicit decorator handles retries logic."""
- DecoratorsTest._decorated_function_called_count = 0
-
- @decorators.WithExplicitTimeoutAndRetries(30, 10)
- def alwaysRaisesCommandFailedError():
- DecoratorsTest._decorated_function_called_count += 1
- raise device_errors.CommandFailedError('testCommand failed')
-
- with self.assertRaises(device_errors.CommandFailedError):
- alwaysRaisesCommandFailedError()
- self.assertEquals(11, DecoratorsTest._decorated_function_called_count)
-
- def testExplicitDecoratorTranslatesReraiserExceptions(self):
- """Tests that the explicit decorator translates reraiser exceptions."""
- @decorators.WithExplicitTimeoutAndRetries(30, 10)
- def alwaysRaisesProvidedException(exception):
- raise exception
-
- exception_desc = 'Reraiser thread timeout error'
- with self.assertRaises(device_errors.CommandTimeoutError) as e:
- alwaysRaisesProvidedException(
- reraiser_thread.TimeoutError(exception_desc))
- self.assertEquals(exception_desc, str(e.exception))
-
- class _MethodDecoratorTestObject(object):
- """An object suitable for testing the method decorator."""
-
- def __init__(self, test_case, default_timeout=_DEFAULT_TIMEOUT,
- default_retries=_DEFAULT_RETRIES):
- self._test_case = test_case
- self.default_timeout = default_timeout
- self.default_retries = default_retries
- self.function_call_counters = {
- 'alwaysRaisesCommandFailedError': 0,
- 'alwaysTimesOut': 0,
- 'requiresExplicitTimeoutAndRetries': 0,
- }
-
- @decorators.WithTimeoutAndRetriesFromInstance(
- 'default_timeout', 'default_retries')
- def alwaysTimesOut(self, timeout=None, retries=None):
- self.function_call_counters['alwaysTimesOut'] += 1
- time.sleep(100)
- self._test_case.assertFalse(True, msg='Failed to time out?')
-
- @decorators.WithTimeoutAndRetriesFromInstance(
- 'default_timeout', 'default_retries')
- def alwaysRaisesCommandFailedError(self, timeout=None, retries=None):
- self.function_call_counters['alwaysRaisesCommandFailedError'] += 1
- raise device_errors.CommandFailedError('testCommand failed')
-
- # pylint: disable=no-self-use
-
- @decorators.WithTimeoutAndRetriesFromInstance(
- 'default_timeout', 'default_retries')
- def alwaysReturnsTimeout(self, timeout=None, retries=None):
- return timeout
-
- @decorators.WithTimeoutAndRetriesFromInstance(
- 'default_timeout', 'default_retries', min_default_timeout=100)
- def alwaysReturnsTimeoutWithMin(self, timeout=None, retries=None):
- return timeout
-
- @decorators.WithTimeoutAndRetriesFromInstance(
- 'default_timeout', 'default_retries')
- def alwaysReturnsRetries(self, timeout=None, retries=None):
- return retries
-
- @decorators.WithTimeoutAndRetriesFromInstance(
- 'default_timeout', 'default_retries')
- def alwaysRaisesProvidedException(self, exception, timeout=None,
- retries=None):
- raise exception
-
- # pylint: enable=no-self-use
-
- def testMethodDecoratorDoesTimeout(self):
- """Tests that the method decorator handles timeout logic."""
- test_obj = self._MethodDecoratorTestObject(self)
- start_time = time.time()
- with self.assertRaises(device_errors.CommandTimeoutError):
- try:
- test_obj.alwaysTimesOut(timeout=1, retries=0)
- except:
- traceback.print_exc()
- raise
- elapsed_time = time.time() - start_time
- self.assertTrue(elapsed_time >= 1)
- self.assertEquals(1, test_obj.function_call_counters['alwaysTimesOut'])
-
- def testMethodDecoratorDoesRetries(self):
- """Tests that the method decorator handles retries logic."""
- test_obj = self._MethodDecoratorTestObject(self)
- with self.assertRaises(device_errors.CommandFailedError):
- try:
- test_obj.alwaysRaisesCommandFailedError(retries=10)
- except:
- traceback.print_exc()
- raise
- self.assertEquals(
- 11, test_obj.function_call_counters['alwaysRaisesCommandFailedError'])
-
- def testMethodDecoratorPassesValues(self):
- """Tests that the method decorator passes timeout and retries kwargs."""
- test_obj = self._MethodDecoratorTestObject(
- self, default_timeout=42, default_retries=31)
- self.assertEquals(42, test_obj.alwaysReturnsTimeout())
- self.assertEquals(41, test_obj.alwaysReturnsTimeout(timeout=41))
- self.assertEquals(31, test_obj.alwaysReturnsRetries())
- self.assertEquals(32, test_obj.alwaysReturnsRetries(retries=32))
-
- def testMethodDecoratorUsesMiniumumTimeout(self):
- test_obj = self._MethodDecoratorTestObject(
- self, default_timeout=42, default_retries=31)
- self.assertEquals(100, test_obj.alwaysReturnsTimeoutWithMin())
- self.assertEquals(41, test_obj.alwaysReturnsTimeoutWithMin(timeout=41))
-
- def testMethodDecoratorTranslatesReraiserExceptions(self):
- test_obj = self._MethodDecoratorTestObject(self)
-
- exception_desc = 'Reraiser thread timeout error'
- with self.assertRaises(device_errors.CommandTimeoutError) as e:
- test_obj.alwaysRaisesProvidedException(
- reraiser_thread.TimeoutError(exception_desc))
- self.assertEquals(exception_desc, str(e.exception))
-
-if __name__ == '__main__':
- unittest.main(verbosity=2)
-
diff --git a/third_party/catapult/devil/devil/android/device_blacklist.py b/third_party/catapult/devil/devil/android/device_blacklist.py
deleted file mode 100644
index 010e99652f..0000000000
--- a/third_party/catapult/devil/devil/android/device_blacklist.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import json
-import logging
-import os
-import threading
-import time
-
-logger = logging.getLogger(__name__)
-
-
-class Blacklist(object):
-
- def __init__(self, path):
- self._blacklist_lock = threading.RLock()
- self._path = path
-
- def Read(self):
- """Reads the blacklist from the blacklist file.
-
- Returns:
- A dict containing bad devices.
- """
- with self._blacklist_lock:
- blacklist = dict()
- if not os.path.exists(self._path):
- return blacklist
-
- try:
- with open(self._path, 'r') as f:
- blacklist = json.load(f)
- except (IOError, ValueError) as e:
- logger.warning('Unable to read blacklist: %s', str(e))
- os.remove(self._path)
-
- if not isinstance(blacklist, dict):
- logger.warning('Ignoring %s: %s (a dict was expected instead)',
- self._path, blacklist)
- blacklist = dict()
-
- return blacklist
-
- def Write(self, blacklist):
- """Writes the provided blacklist to the blacklist file.
-
- Args:
- blacklist: list of bad devices to write to the blacklist file.
- """
- with self._blacklist_lock:
- with open(self._path, 'w') as f:
- json.dump(blacklist, f)
-
- def Extend(self, devices, reason='unknown'):
- """Adds devices to blacklist file.
-
- Args:
- devices: list of bad devices to be added to the blacklist file.
- reason: string specifying the reason for blacklist (eg: 'unauthorized')
- """
- timestamp = time.time()
- event_info = {
- 'timestamp': timestamp,
- 'reason': reason,
- }
- device_dicts = {device: event_info for device in devices}
- logger.info('Adding %s to blacklist %s for reason: %s',
- ','.join(devices), self._path, reason)
- with self._blacklist_lock:
- blacklist = self.Read()
- blacklist.update(device_dicts)
- self.Write(blacklist)
-
- def Reset(self):
- """Erases the blacklist file if it exists."""
- logger.info('Resetting blacklist %s', self._path)
- with self._blacklist_lock:
- if os.path.exists(self._path):
- os.remove(self._path)
diff --git a/third_party/catapult/devil/devil/android/device_blacklist_test.py b/third_party/catapult/devil/devil/android/device_blacklist_test.py
deleted file mode 100644
index bc44da557b..0000000000
--- a/third_party/catapult/devil/devil/android/device_blacklist_test.py
+++ /dev/null
@@ -1,38 +0,0 @@
-#! /usr/bin/env python
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import os
-import tempfile
-import unittest
-
-from devil.android import device_blacklist
-
-
-class DeviceBlacklistTest(unittest.TestCase):
-
- def testBlacklistFileDoesNotExist(self):
- with tempfile.NamedTemporaryFile() as blacklist_file:
- # Allow the temporary file to be deleted.
- pass
-
- test_blacklist = device_blacklist.Blacklist(blacklist_file.name)
- self.assertEquals({}, test_blacklist.Read())
-
- def testBlacklistFileIsEmpty(self):
- try:
- with tempfile.NamedTemporaryFile(delete=False) as blacklist_file:
- # Allow the temporary file to be closed.
- pass
-
- test_blacklist = device_blacklist.Blacklist(blacklist_file.name)
- self.assertEquals({}, test_blacklist.Read())
-
- finally:
- if os.path.exists(blacklist_file.name):
- os.remove(blacklist_file.name)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/third_party/catapult/devil/devil/android/device_errors.py b/third_party/catapult/devil/devil/android/device_errors.py
deleted file mode 100644
index 568e497496..0000000000
--- a/third_party/catapult/devil/devil/android/device_errors.py
+++ /dev/null
@@ -1,180 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""
-Exception classes raised by AdbWrapper and DeviceUtils.
-"""
-
-from devil import base_error
-from devil.utils import cmd_helper
-from devil.utils import parallelizer
-
-
-class CommandFailedError(base_error.BaseError):
- """Exception for command failures."""
-
- def __init__(self, message, device_serial=None):
- device_leader = '(device: %s)' % device_serial
- if device_serial is not None and not message.startswith(device_leader):
- message = '%s %s' % (device_leader, message)
- self.device_serial = device_serial
- super(CommandFailedError, self).__init__(message)
-
- def __eq__(self, other):
- return (super(CommandFailedError, self).__eq__(other)
- and self.device_serial == other.device_serial)
-
- def __ne__(self, other):
- return not self == other
-
-
-class _BaseCommandFailedError(CommandFailedError):
- """Base Exception for adb and fastboot command failures."""
-
- def __init__(self, args, output, status=None, device_serial=None,
- message=None):
- self.args = args
- self.output = output
- self.status = status
- if not message:
- adb_cmd = ' '.join(cmd_helper.SingleQuote(arg) for arg in self.args)
- message = ['adb %s: failed ' % adb_cmd]
- if status:
- message.append('with exit status %s ' % self.status)
- if output:
- message.append('and output:\n')
- message.extend('- %s\n' % line for line in output.splitlines())
- else:
- message.append('and no output.')
- message = ''.join(message)
- super(_BaseCommandFailedError, self).__init__(message, device_serial)
-
- def __eq__(self, other):
- return (super(_BaseCommandFailedError, self).__eq__(other)
- and self.args == other.args
- and self.output == other.output
- and self.status == other.status)
-
- def __ne__(self, other):
- return not self == other
-
- def __reduce__(self):
- """Support pickling."""
- result = [None, None, None, None, None]
- super_result = super(_BaseCommandFailedError, self).__reduce__()
- for i in range(len(super_result)):
- result[i] = super_result[i]
-
- # Update the args used to reconstruct this exception.
- result[1] = (
- self.args, self.output, self.status, self.device_serial, self.message)
- return tuple(result)
-
-
-class AdbCommandFailedError(_BaseCommandFailedError):
- """Exception for adb command failures."""
-
- def __init__(self, args, output, status=None, device_serial=None,
- message=None):
- super(AdbCommandFailedError, self).__init__(
- args, output, status=status, message=message,
- device_serial=device_serial)
-
-
-class FastbootCommandFailedError(_BaseCommandFailedError):
- """Exception for fastboot command failures."""
-
- def __init__(self, args, output, status=None, device_serial=None,
- message=None):
- super(FastbootCommandFailedError, self).__init__(
- args, output, status=status, message=message,
- device_serial=device_serial)
-
-
-class DeviceVersionError(CommandFailedError):
- """Exception for device version failures."""
-
- def __init__(self, message, device_serial=None):
- super(DeviceVersionError, self).__init__(message, device_serial)
-
-
-class AdbShellCommandFailedError(AdbCommandFailedError):
- """Exception for shell command failures run via adb."""
-
- def __init__(self, command, output, status, device_serial=None):
- self.command = command
- message = ['shell command run via adb failed on the device:\n',
- ' command: %s\n' % command]
- message.append(' exit status: %s\n' % status)
- if output:
- message.append(' output:\n')
- if isinstance(output, basestring):
- output_lines = output.splitlines()
- else:
- output_lines = output
- message.extend(' - %s\n' % line for line in output_lines)
- else:
- message.append(" output: ''\n")
- message = ''.join(message)
- super(AdbShellCommandFailedError, self).__init__(
- ['shell', command], output, status, device_serial, message)
-
- def __reduce__(self):
- """Support pickling."""
- result = [None, None, None, None, None]
- super_result = super(AdbShellCommandFailedError, self).__reduce__()
- for i in range(len(super_result)):
- result[i] = super_result[i]
-
- # Update the args used to reconstruct this exception.
- result[1] = (self.command, self.output, self.status, self.device_serial)
- return tuple(result)
-
-
-class CommandTimeoutError(base_error.BaseError):
- """Exception for command timeouts."""
- pass
-
-
-class DeviceUnreachableError(base_error.BaseError):
- """Exception for device unreachable failures."""
- pass
-
-
-class NoDevicesError(base_error.BaseError):
- """Exception for having no devices attached."""
-
- def __init__(self, msg=None):
- super(NoDevicesError, self).__init__(
- msg or 'No devices attached.', is_infra_error=True)
-
-
-class MultipleDevicesError(base_error.BaseError):
- """Exception for having multiple attached devices without selecting one."""
-
- def __init__(self, devices):
- parallel_devices = parallelizer.Parallelizer(devices)
- descriptions = parallel_devices.pMap(
- lambda d: d.build_description).pGet(None)
- msg = ('More than one device available. Use -d/--device to select a device '
- 'by serial.\n\nAvailable devices:\n')
- for d, desc in zip(devices, descriptions):
- msg += ' %s (%s)\n' % (d, desc)
-
- super(MultipleDevicesError, self).__init__(msg, is_infra_error=True)
-
-
-class NoAdbError(base_error.BaseError):
- """Exception for being unable to find ADB."""
-
- def __init__(self, msg=None):
- super(NoAdbError, self).__init__(
- msg or 'Unable to find adb.', is_infra_error=True)
-
-
-class DeviceChargingError(CommandFailedError):
- """Exception for device charging errors."""
-
- def __init__(self, message, device_serial=None):
- super(DeviceChargingError, self).__init__(message, device_serial)
diff --git a/third_party/catapult/devil/devil/android/device_errors_test.py b/third_party/catapult/devil/devil/android/device_errors_test.py
deleted file mode 100755
index 68a4f16770..0000000000
--- a/third_party/catapult/devil/devil/android/device_errors_test.py
+++ /dev/null
@@ -1,72 +0,0 @@
-#! /usr/bin/env python
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import pickle
-import sys
-import unittest
-
-from devil.android import device_errors
-
-
-class DeviceErrorsTest(unittest.TestCase):
-
- def assertIsPicklable(self, original):
- pickled = pickle.dumps(original)
- reconstructed = pickle.loads(pickled)
- self.assertEquals(original, reconstructed)
-
- def testPicklable_AdbCommandFailedError(self):
- original = device_errors.AdbCommandFailedError(
- ['these', 'are', 'adb', 'args'], 'adb failure output', status=':(',
- device_serial='0123456789abcdef')
- self.assertIsPicklable(original)
-
- def testPicklable_AdbShellCommandFailedError(self):
- original = device_errors.AdbShellCommandFailedError(
- 'foo', 'erroneous foo output', '1', device_serial='0123456789abcdef')
- self.assertIsPicklable(original)
-
- def testPicklable_CommandFailedError(self):
- original = device_errors.CommandFailedError(
- 'sample command failed')
- self.assertIsPicklable(original)
-
- def testPicklable_CommandTimeoutError(self):
- original = device_errors.CommandTimeoutError(
- 'My fake command timed out :(')
- self.assertIsPicklable(original)
-
- def testPicklable_DeviceChargingError(self):
- original = device_errors.DeviceChargingError(
- 'Fake device failed to charge')
- self.assertIsPicklable(original)
-
- def testPicklable_DeviceUnreachableError(self):
- original = device_errors.DeviceUnreachableError
- self.assertIsPicklable(original)
-
- def testPicklable_FastbootCommandFailedError(self):
- original = device_errors.FastbootCommandFailedError(
- ['these', 'are', 'fastboot', 'args'], 'fastboot failure output',
- status=':(', device_serial='0123456789abcdef')
- self.assertIsPicklable(original)
-
- def testPicklable_MultipleDevicesError(self):
- # TODO(jbudorick): Implement this after implementing a stable DeviceUtils
- # fake. https://github.com/catapult-project/catapult/issues/3145
- pass
-
- def testPicklable_NoAdbError(self):
- original = device_errors.NoAdbError()
- self.assertIsPicklable(original)
-
- def testPicklable_NoDevicesError(self):
- original = device_errors.NoDevicesError()
- self.assertIsPicklable(original)
-
-
-
-if __name__ == '__main__':
- sys.exit(unittest.main())
diff --git a/third_party/catapult/devil/devil/android/device_list.py b/third_party/catapult/devil/devil/android/device_list.py
deleted file mode 100644
index 0fbb0f151a..0000000000
--- a/third_party/catapult/devil/devil/android/device_list.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""A module to keep track of devices across builds."""
-
-import json
-import logging
-import os
-
-logger = logging.getLogger(__name__)
-
-
-def GetPersistentDeviceList(file_name):
- """Returns a list of devices.
-
- Args:
- file_name: the file name containing a list of devices.
-
- Returns: List of device serial numbers that were on the bot.
- """
- if not os.path.isfile(file_name):
- logger.warning("Device file %s doesn't exist.", file_name)
- return []
-
- try:
- with open(file_name) as f:
- devices = json.load(f)
- if not isinstance(devices, list) or not all(isinstance(d, basestring)
- for d in devices):
- logger.warning('Unrecognized device file format: %s', devices)
- return []
- return [d for d in devices if d != '(error)']
- except ValueError:
- logger.exception(
- 'Error reading device file %s. Falling back to old format.', file_name)
-
- # TODO(bpastene) Remove support for old unstructured file format.
- with open(file_name) as f:
- return [d for d in f.read().splitlines() if d != '(error)']
-
-
-def WritePersistentDeviceList(file_name, device_list):
- path = os.path.dirname(file_name)
- assert isinstance(device_list, list)
- # If there is a problem with ADB "(error)" can be added to the device list.
- # These should be removed before saving.
- device_list = [d for d in device_list if d != '(error)']
- if not os.path.exists(path):
- os.makedirs(path)
- with open(file_name, 'w') as f:
- json.dump(device_list, f)
diff --git a/third_party/catapult/devil/devil/android/device_signal.py b/third_party/catapult/devil/devil/android/device_signal.py
deleted file mode 100644
index 2cec46d7d2..0000000000
--- a/third_party/catapult/devil/devil/android/device_signal.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Defines constants for signals that should be supported on devices.
-
-Note: Obtained by running `kill -l` on a user device.
-"""
-
-
-SIGHUP = 1 # Hangup
-SIGINT = 2 # Interrupt
-SIGQUIT = 3 # Quit
-SIGILL = 4 # Illegal instruction
-SIGTRAP = 5 # Trap
-SIGABRT = 6 # Aborted
-SIGBUS = 7 # Bus error
-SIGFPE = 8 # Floating point exception
-SIGKILL = 9 # Killed
-SIGUSR1 = 10 # User signal 1
-SIGSEGV = 11 # Segmentation fault
-SIGUSR2 = 12 # User signal 2
-SIGPIPE = 13 # Broken pipe
-SIGALRM = 14 # Alarm clock
-SIGTERM = 15 # Terminated
-SIGSTKFLT = 16 # Stack fault
-SIGCHLD = 17 # Child exited
-SIGCONT = 18 # Continue
-SIGSTOP = 19 # Stopped (signal)
-SIGTSTP = 20 # Stopped
-SIGTTIN = 21 # Stopped (tty input)
-SIGTTOU = 22 # Stopped (tty output)
-SIGURG = 23 # Urgent I/O condition
-SIGXCPU = 24 # CPU time limit exceeded
-SIGXFSZ = 25 # File size limit exceeded
-SIGVTALRM = 26 # Virtual timer expired
-SIGPROF = 27 # Profiling timer expired
-SIGWINCH = 28 # Window size changed
-SIGIO = 29 # I/O possible
-SIGPWR = 30 # Power failure
-SIGSYS = 31 # Bad system call
diff --git a/third_party/catapult/devil/devil/android/device_temp_file.py b/third_party/catapult/devil/devil/android/device_temp_file.py
deleted file mode 100644
index 4d0c7adb5c..0000000000
--- a/third_party/catapult/devil/devil/android/device_temp_file.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""A temp file that automatically gets pushed and deleted from a device."""
-
-# pylint: disable=W0622
-
-import posixpath
-import random
-import threading
-
-from devil.android import device_errors
-from devil.utils import cmd_helper
-
-
-class DeviceTempFile(object):
-
- def __init__(self, adb, suffix='', prefix='temp_file', dir='/data/local/tmp'):
- """Find an unused temporary file path on the device.
-
- When this object is closed, the file will be deleted on the device.
-
- Args:
- adb: An instance of AdbWrapper
- suffix: The suffix of the name of the temp file.
- prefix: The prefix of the name of the temp file.
- dir: The directory on the device where to place the temp file.
- Raises:
- ValueError if any of suffix, prefix, or dir are None.
- """
- if None in (dir, prefix, suffix):
- m = 'Provided None path component. (dir: %s, prefix: %s, suffix: %s)' % (
- dir, prefix, suffix)
- raise ValueError(m)
-
- self._adb = adb
- # Python's random module use 52-bit numbers according to its docs.
- random_hex = hex(random.randint(0, 2 ** 52))[2:]
- self.name = posixpath.join(dir, '%s-%s%s' % (prefix, random_hex, suffix))
- self.name_quoted = cmd_helper.SingleQuote(self.name)
-
- def close(self):
- """Deletes the temporary file from the device."""
- # ignore exception if the file is already gone.
- def delete_temporary_file():
- try:
- self._adb.Shell('rm -f %s' % self.name_quoted, expect_status=None)
- except device_errors.AdbCommandFailedError:
- # file does not exist on Android version without 'rm -f' support (ICS)
- pass
-
- # It shouldn't matter when the temp file gets deleted, so do so
- # asynchronously.
- threading.Thread(
- target=delete_temporary_file,
- name='delete_temporary_file(%s)' % self._adb.GetDeviceSerial()).start()
-
- def __enter__(self):
- return self
-
- def __exit__(self, type, value, traceback):
- self.close()
diff --git a/third_party/catapult/devil/devil/android/device_test_case.py b/third_party/catapult/devil/devil/android/device_test_case.py
deleted file mode 100644
index b995fa6f94..0000000000
--- a/third_party/catapult/devil/devil/android/device_test_case.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import threading
-import unittest
-
-from devil.android import device_errors
-from devil.android import device_utils
-
-_devices_lock = threading.Lock()
-_devices_condition = threading.Condition(_devices_lock)
-_devices = set()
-
-
-def PrepareDevices(*_args):
-
- raw_devices = device_utils.DeviceUtils.HealthyDevices()
- live_devices = []
- for d in raw_devices:
- try:
- d.WaitUntilFullyBooted(timeout=5, retries=0)
- live_devices.append(str(d))
- except (device_errors.CommandFailedError,
- device_errors.CommandTimeoutError):
- pass
- with _devices_lock:
- _devices.update(set(live_devices))
-
- if not _devices:
- raise Exception('No live devices attached.')
-
-
-class DeviceTestCase(unittest.TestCase):
-
- def __init__(self, *args, **kwargs):
- super(DeviceTestCase, self).__init__(*args, **kwargs)
- self.serial = None
-
- #override
- def setUp(self):
- super(DeviceTestCase, self).setUp()
- with _devices_lock:
- while not _devices:
- _devices_condition.wait(5)
- self.serial = _devices.pop()
-
- #override
- def tearDown(self):
- super(DeviceTestCase, self).tearDown()
- with _devices_lock:
- _devices.add(self.serial)
- _devices_condition.notify()
-
diff --git a/third_party/catapult/devil/devil/android/device_utils.py b/third_party/catapult/devil/devil/android/device_utils.py
deleted file mode 100644
index 50f362c383..0000000000
--- a/third_party/catapult/devil/devil/android/device_utils.py
+++ /dev/null
@@ -1,2640 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Provides a variety of device interactions based on adb.
-
-Eventually, this will be based on adb_wrapper.
-"""
-# pylint: disable=unused-argument
-
-import calendar
-import collections
-import itertools
-import json
-import logging
-import multiprocessing
-import os
-import posixpath
-import pprint
-import re
-import shutil
-import stat
-import tempfile
-import time
-import threading
-import uuid
-import zipfile
-
-from devil import base_error
-from devil import devil_env
-from devil.utils import cmd_helper
-from devil.android import apk_helper
-from devil.android import device_signal
-from devil.android import decorators
-from devil.android import device_errors
-from devil.android import device_temp_file
-from devil.android import install_commands
-from devil.android import logcat_monitor
-from devil.android import md5sum
-from devil.android.constants import chrome
-from devil.android.sdk import adb_wrapper
-from devil.android.sdk import intent
-from devil.android.sdk import keyevent
-from devil.android.sdk import split_select
-from devil.android.sdk import version_codes
-from devil.utils import host_utils
-from devil.utils import parallelizer
-from devil.utils import reraiser_thread
-from devil.utils import timeout_retry
-from devil.utils import zip_utils
-
-logger = logging.getLogger(__name__)
-
-_DEFAULT_TIMEOUT = 30
-_DEFAULT_RETRIES = 3
-
-# A sentinel object for default values
-# TODO(jbudorick,perezju): revisit how default values are handled by
-# the timeout_retry decorators.
-DEFAULT = object()
-
-_RESTART_ADBD_SCRIPT = """
- trap '' HUP
- trap '' TERM
- trap '' PIPE
- function restart() {
- stop adbd
- start adbd
- }
- restart &
-"""
-
-# Not all permissions can be set.
-_PERMISSIONS_BLACKLIST = [
- 'android.permission.ACCESS_LOCATION_EXTRA_COMMANDS',
- 'android.permission.ACCESS_MOCK_LOCATION',
- 'android.permission.ACCESS_NETWORK_STATE',
- 'android.permission.ACCESS_NOTIFICATION_POLICY',
- 'android.permission.ACCESS_WIFI_STATE',
- 'android.permission.AUTHENTICATE_ACCOUNTS',
- 'android.permission.BLUETOOTH',
- 'android.permission.BLUETOOTH_ADMIN',
- 'android.permission.BROADCAST_STICKY',
- 'android.permission.CHANGE_NETWORK_STATE',
- 'android.permission.CHANGE_WIFI_MULTICAST_STATE',
- 'android.permission.CHANGE_WIFI_STATE',
- 'android.permission.DISABLE_KEYGUARD',
- 'android.permission.DOWNLOAD_WITHOUT_NOTIFICATION',
- 'android.permission.EXPAND_STATUS_BAR',
- 'android.permission.GET_PACKAGE_SIZE',
- 'android.permission.INSTALL_SHORTCUT',
- 'android.permission.INTERNET',
- 'android.permission.KILL_BACKGROUND_PROCESSES',
- 'android.permission.MANAGE_ACCOUNTS',
- 'android.permission.MODIFY_AUDIO_SETTINGS',
- 'android.permission.NFC',
- 'android.permission.READ_SYNC_SETTINGS',
- 'android.permission.READ_SYNC_STATS',
- 'android.permission.RECEIVE_BOOT_COMPLETED',
- 'android.permission.RECORD_VIDEO',
- 'android.permission.REORDER_TASKS',
- 'android.permission.REQUEST_INSTALL_PACKAGES',
- 'android.permission.RUN_INSTRUMENTATION',
- 'android.permission.SET_ALARM',
- 'android.permission.SET_TIME_ZONE',
- 'android.permission.SET_WALLPAPER',
- 'android.permission.SET_WALLPAPER_HINTS',
- 'android.permission.TRANSMIT_IR',
- 'android.permission.USE_CREDENTIALS',
- 'android.permission.USE_FINGERPRINT',
- 'android.permission.VIBRATE',
- 'android.permission.WAKE_LOCK',
- 'android.permission.WRITE_SYNC_SETTINGS',
- 'com.android.browser.permission.READ_HISTORY_BOOKMARKS',
- 'com.android.browser.permission.WRITE_HISTORY_BOOKMARKS',
- 'com.android.launcher.permission.INSTALL_SHORTCUT',
- 'com.chrome.permission.DEVICE_EXTRAS',
- 'com.google.android.apps.now.CURRENT_ACCOUNT_ACCESS',
- 'com.google.android.c2dm.permission.RECEIVE',
- 'com.google.android.providers.gsf.permission.READ_GSERVICES',
- 'com.sec.enterprise.knox.MDM_CONTENT_PROVIDER',
-]
-for package_info in chrome.PACKAGE_INFO.itervalues():
- _PERMISSIONS_BLACKLIST.extend([
- '%s.permission.C2D_MESSAGE' % package_info.package,
- '%s.permission.READ_WRITE_BOOKMARK_FOLDERS' % package_info.package,
- '%s.TOS_ACKED' % package_info.package])
-
-_CURRENT_FOCUS_CRASH_RE = re.compile(
- r'\s*mCurrentFocus.*Application (Error|Not Responding): (\S+)}')
-
-_GETPROP_RE = re.compile(r'\[(.*?)\]: \[(.*?)\]')
-
-# Regex to parse the long (-l) output of 'ls' command, c.f.
-# https://github.com/landley/toybox/blob/master/toys/posix/ls.c#L446
-_LONG_LS_OUTPUT_RE = re.compile(
- r'(?P<st_mode>[\w-]{10})\s+' # File permissions
- r'(?:(?P<st_nlink>\d+)\s+)?' # Number of links (optional)
- r'(?P<st_owner>\w+)\s+' # Name of owner
- r'(?P<st_group>\w+)\s+' # Group of owner
- r'(?:' # Either ...
- r'(?P<st_rdev_major>\d+),\s+' # Device major, and
- r'(?P<st_rdev_minor>\d+)\s+' # Device minor
- r'|' # .. or
- r'(?P<st_size>\d+)\s+' # Size in bytes
- r')?' # .. or nothing
- r'(?P<st_mtime>\d{4}-\d\d-\d\d \d\d:\d\d)\s+' # Modification date/time
- r'(?P<filename>.+?)' # File name
- r'(?: -> (?P<symbolic_link_to>.+))?' # Symbolic link (optional)
- r'$' # End of string
-)
-_LS_DATE_FORMAT = '%Y-%m-%d %H:%M'
-_FILE_MODE_RE = re.compile(r'[dbclps-](?:[r-][w-][xSs-]){2}[r-][w-][xTt-]$')
-_FILE_MODE_KIND = {
- 'd': stat.S_IFDIR, 'b': stat.S_IFBLK, 'c': stat.S_IFCHR,
- 'l': stat.S_IFLNK, 'p': stat.S_IFIFO, 's': stat.S_IFSOCK,
- '-': stat.S_IFREG}
-_FILE_MODE_PERMS = [
- stat.S_IRUSR, stat.S_IWUSR, stat.S_IXUSR,
- stat.S_IRGRP, stat.S_IWGRP, stat.S_IXGRP,
- stat.S_IROTH, stat.S_IWOTH, stat.S_IXOTH,
-]
-_FILE_MODE_SPECIAL = [
- ('s', stat.S_ISUID),
- ('s', stat.S_ISGID),
- ('t', stat.S_ISVTX),
-]
-_SELINUX_MODE = {
- 'enforcing': True,
- 'permissive': False,
- 'disabled': None
-}
-# Some devices require different logic for checking if root is necessary
-_SPECIAL_ROOT_DEVICE_LIST = [
- 'marlin',
- 'sailfish',
-]
-
-
-@decorators.WithExplicitTimeoutAndRetries(
- _DEFAULT_TIMEOUT, _DEFAULT_RETRIES)
-def GetAVDs():
- """Returns a list of Android Virtual Devices.
-
- Returns:
- A list containing the configured AVDs.
- """
- lines = cmd_helper.GetCmdOutput([
- os.path.join(devil_env.config.LocalPath('android_sdk'),
- 'tools', 'android'),
- 'list', 'avd']).splitlines()
- avds = []
- for line in lines:
- if 'Name:' not in line:
- continue
- key, value = (s.strip() for s in line.split(':', 1))
- if key == 'Name':
- avds.append(value)
- return avds
-
-
-@decorators.WithExplicitTimeoutAndRetries(
- _DEFAULT_TIMEOUT, _DEFAULT_RETRIES)
-def RestartServer():
- """Restarts the adb server.
-
- Raises:
- CommandFailedError if we fail to kill or restart the server.
- """
- def adb_killed():
- return not adb_wrapper.AdbWrapper.IsServerOnline()
-
- def adb_started():
- return adb_wrapper.AdbWrapper.IsServerOnline()
-
- adb_wrapper.AdbWrapper.KillServer()
- if not timeout_retry.WaitFor(adb_killed, wait_period=1, max_tries=5):
- # TODO(perezju): raise an exception after fixng http://crbug.com/442319
- logger.warning('Failed to kill adb server')
- adb_wrapper.AdbWrapper.StartServer()
- if not timeout_retry.WaitFor(adb_started, wait_period=1, max_tries=5):
- raise device_errors.CommandFailedError('Failed to start adb server')
-
-
-def _ParseModeString(mode_str):
- """Parse a mode string, e.g. 'drwxrwxrwx', into a st_mode value.
-
- Effectively the reverse of |mode_to_string| in, e.g.:
- https://github.com/landley/toybox/blob/master/lib/lib.c#L896
- """
- if not _FILE_MODE_RE.match(mode_str):
- raise ValueError('Unexpected file mode %r', mode_str)
- mode = _FILE_MODE_KIND[mode_str[0]]
- for c, flag in zip(mode_str[1:], _FILE_MODE_PERMS):
- if c != '-' and c.islower():
- mode |= flag
- for c, (t, flag) in zip(mode_str[3::3], _FILE_MODE_SPECIAL):
- if c.lower() == t:
- mode |= flag
- return mode
-
-
-def _GetTimeStamp():
- """Return a basic ISO 8601 time stamp with the current local time."""
- return time.strftime('%Y%m%dT%H%M%S', time.localtime())
-
-
-def _JoinLines(lines):
- # makes sure that the last line is also terminated, and is more memory
- # efficient than first appending an end-line to each line and then joining
- # all of them together.
- return ''.join(s for line in lines for s in (line, '\n'))
-
-
-def _CreateAdbWrapper(device):
- if isinstance(device, adb_wrapper.AdbWrapper):
- return device
- else:
- return adb_wrapper.AdbWrapper(device)
-
-
-def _FormatPartialOutputError(output):
- lines = output.splitlines() if isinstance(output, basestring) else output
- message = ['Partial output found:']
- if len(lines) > 11:
- message.extend('- %s' % line for line in lines[:5])
- message.extend('<snip>')
- message.extend('- %s' % line for line in lines[-5:])
- else:
- message.extend('- %s' % line for line in lines)
- return '\n'.join(message)
-
-
-class DeviceUtils(object):
-
- _MAX_ADB_COMMAND_LENGTH = 512
- _MAX_ADB_OUTPUT_LENGTH = 32768
- _LAUNCHER_FOCUSED_RE = re.compile(
- r'\s*mCurrentFocus.*(Launcher|launcher).*')
- _VALID_SHELL_VARIABLE = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$')
-
- LOCAL_PROPERTIES_PATH = posixpath.join('/', 'data', 'local.prop')
-
- # Property in /data/local.prop that controls Java assertions.
- JAVA_ASSERT_PROPERTY = 'dalvik.vm.enableassertions'
-
- def __init__(self, device, enable_device_files_cache=False,
- default_timeout=_DEFAULT_TIMEOUT,
- default_retries=_DEFAULT_RETRIES):
- """DeviceUtils constructor.
-
- Args:
- device: Either a device serial, an existing AdbWrapper instance, or an
- an existing AndroidCommands instance.
- enable_device_files_cache: For PushChangedFiles(), cache checksums of
- pushed files rather than recomputing them on a subsequent call.
- default_timeout: An integer containing the default number of seconds to
- wait for an operation to complete if no explicit value is provided.
- default_retries: An integer containing the default number or times an
- operation should be retried on failure if no explicit value is provided.
- """
- self.adb = None
- if isinstance(device, basestring):
- self.adb = _CreateAdbWrapper(device)
- elif isinstance(device, adb_wrapper.AdbWrapper):
- self.adb = device
- else:
- raise ValueError('Unsupported device value: %r' % device)
- self._commands_installed = None
- self._default_timeout = default_timeout
- self._default_retries = default_retries
- self._enable_device_files_cache = enable_device_files_cache
- self._cache = {}
- self._client_caches = {}
- self._cache_lock = threading.RLock()
- assert hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR)
- assert hasattr(self, decorators.DEFAULT_RETRIES_ATTR)
-
- self._ClearCache()
-
- @property
- def serial(self):
- """Returns the device serial."""
- return self.adb.GetDeviceSerial()
-
- def __eq__(self, other):
- """Checks whether |other| refers to the same device as |self|.
-
- Args:
- other: The object to compare to. This can be a basestring, an instance
- of adb_wrapper.AdbWrapper, or an instance of DeviceUtils.
- Returns:
- Whether |other| refers to the same device as |self|.
- """
- return self.serial == str(other)
-
- def __lt__(self, other):
- """Compares two instances of DeviceUtils.
-
- This merely compares their serial numbers.
-
- Args:
- other: The instance of DeviceUtils to compare to.
- Returns:
- Whether |self| is less than |other|.
- """
- return self.serial < other.serial
-
- def __str__(self):
- """Returns the device serial."""
- return self.serial
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def IsOnline(self, timeout=None, retries=None):
- """Checks whether the device is online.
-
- Args:
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- True if the device is online, False otherwise.
-
- Raises:
- CommandTimeoutError on timeout.
- """
- try:
- return self.adb.GetState() == 'device'
- except base_error.BaseError as exc:
- logger.info('Failed to get state: %s', exc)
- return False
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def HasRoot(self, timeout=None, retries=None):
- """Checks whether or not adbd has root privileges.
-
- Args:
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- True if adbd has root privileges, False otherwise.
-
- Raises:
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- try:
- if self.product_name in _SPECIAL_ROOT_DEVICE_LIST:
- return self.GetProp('service.adb.root') == '1'
- self.RunShellCommand(['ls', '/root'], check_return=True)
- return True
- except device_errors.AdbCommandFailedError:
- return False
-
- def NeedsSU(self, timeout=DEFAULT, retries=DEFAULT):
- """Checks whether 'su' is needed to access protected resources.
-
- Args:
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- True if 'su' is available on the device and is needed to to access
- protected resources; False otherwise if either 'su' is not available
- (e.g. because the device has a user build), or not needed (because adbd
- already has root privileges).
-
- Raises:
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- if 'needs_su' not in self._cache:
- cmd = '%s && ! ls /root' % self._Su('ls /root')
- if self.product_name in _SPECIAL_ROOT_DEVICE_LIST:
- if self.HasRoot():
- self._cache['needs_su'] = False
- return False
- cmd = 'which which && which su'
- try:
- self.RunShellCommand(cmd, shell=True, check_return=True,
- timeout=self._default_timeout if timeout is DEFAULT else timeout,
- retries=self._default_retries if retries is DEFAULT else retries)
- self._cache['needs_su'] = True
- except device_errors.AdbCommandFailedError:
- self._cache['needs_su'] = False
- return self._cache['needs_su']
-
-
- def _Su(self, command):
- if self.build_version_sdk >= version_codes.MARSHMALLOW:
- return 'su 0 %s' % command
- return 'su -c %s' % command
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def EnableRoot(self, timeout=None, retries=None):
- """Restarts adbd with root privileges.
-
- Args:
- timeout: timeout in seconds
- retries: number of retries
-
- Raises:
- CommandFailedError if root could not be enabled.
- CommandTimeoutError on timeout.
- """
- if self.IsUserBuild():
- raise device_errors.CommandFailedError(
- 'Cannot enable root in user builds.', str(self))
- if 'needs_su' in self._cache:
- del self._cache['needs_su']
- self.adb.Root()
- self.WaitUntilFullyBooted()
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def IsUserBuild(self, timeout=None, retries=None):
- """Checks whether or not the device is running a user build.
-
- Args:
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- True if the device is running a user build, False otherwise (i.e. if
- it's running a userdebug build).
-
- Raises:
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- return self.build_type == 'user'
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def GetExternalStoragePath(self, timeout=None, retries=None):
- """Get the device's path to its SD card.
-
- Args:
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- The device's path to its SD card.
-
- Raises:
- CommandFailedError if the external storage path could not be determined.
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- self._EnsureCacheInitialized()
- if not self._cache['external_storage']:
- raise device_errors.CommandFailedError('$EXTERNAL_STORAGE is not set',
- str(self))
- return self._cache['external_storage']
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def GetApplicationPaths(self, package, timeout=None, retries=None):
- """Get the paths of the installed apks on the device for the given package.
-
- Args:
- package: Name of the package.
-
- Returns:
- List of paths to the apks on the device for the given package.
- """
- return self._GetApplicationPathsInternal(package)
-
- def _GetApplicationPathsInternal(self, package, skip_cache=False):
- cached_result = self._cache['package_apk_paths'].get(package)
- if cached_result is not None and not skip_cache:
- if package in self._cache['package_apk_paths_to_verify']:
- self._cache['package_apk_paths_to_verify'].remove(package)
- # Don't verify an app that is not thought to be installed. We are
- # concerned only with apps we think are installed having been
- # uninstalled manually.
- if cached_result and not self.PathExists(cached_result):
- cached_result = None
- self._cache['package_apk_checksums'].pop(package, 0)
- if cached_result is not None:
- return list(cached_result)
- # 'pm path' is liable to incorrectly exit with a nonzero number starting
- # in Lollipop.
- # TODO(jbudorick): Check if this is fixed as new Android versions are
- # released to put an upper bound on this.
- should_check_return = (self.build_version_sdk < version_codes.LOLLIPOP)
- output = self.RunShellCommand(
- ['pm', 'path', package], check_return=should_check_return)
- apks = []
- for line in output:
- if not line.startswith('package:'):
- continue
- apks.append(line[len('package:'):])
- if not apks and output:
- raise device_errors.CommandFailedError(
- 'pm path returned: %r' % '\n'.join(output), str(self))
- self._cache['package_apk_paths'][package] = list(apks)
- return apks
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def GetApplicationVersion(self, package, timeout=None, retries=None):
- """Get the version name of a package installed on the device.
-
- Args:
- package: Name of the package.
-
- Returns:
- A string with the version name or None if the package is not found
- on the device.
- """
- output = self.RunShellCommand(
- ['dumpsys', 'package', package], check_return=True)
- if not output:
- return None
- for line in output:
- line = line.strip()
- if line.startswith('versionName='):
- return line[len('versionName='):]
- raise device_errors.CommandFailedError(
- 'Version name for %s not found on dumpsys output' % package, str(self))
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def GetApplicationDataDirectory(self, package, timeout=None, retries=None):
- """Get the data directory on the device for the given package.
-
- Args:
- package: Name of the package.
-
- Returns:
- The package's data directory.
- Raises:
- CommandFailedError if the package's data directory can't be found,
- whether because it's not installed or otherwise.
- """
- output = self._RunPipedShellCommand(
- 'pm dump %s | grep dataDir=' % cmd_helper.SingleQuote(package))
- for line in output:
- _, _, dataDir = line.partition('dataDir=')
- if dataDir:
- return dataDir
- raise device_errors.CommandFailedError(
- 'Could not find data directory for %s', package)
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None):
- """Wait for the device to fully boot.
-
- This means waiting for the device to boot, the package manager to be
- available, and the SD card to be ready. It can optionally mean waiting
- for wifi to come up, too.
-
- Args:
- wifi: A boolean indicating if we should wait for wifi to come up or not.
- timeout: timeout in seconds
- retries: number of retries
-
- Raises:
- CommandFailedError on failure.
- CommandTimeoutError if one of the component waits times out.
- DeviceUnreachableError if the device becomes unresponsive.
- """
- def sd_card_ready():
- try:
- self.RunShellCommand(['test', '-d', self.GetExternalStoragePath()],
- check_return=True)
- return True
- except device_errors.AdbCommandFailedError:
- return False
-
- def pm_ready():
- try:
- return self._GetApplicationPathsInternal('android', skip_cache=True)
- except device_errors.CommandFailedError:
- return False
-
- def boot_completed():
- try:
- return self.GetProp('sys.boot_completed', cache=False) == '1'
- except device_errors.CommandFailedError:
- return False
-
- def wifi_enabled():
- return 'Wi-Fi is enabled' in self.RunShellCommand(['dumpsys', 'wifi'],
- check_return=False)
-
- self.adb.WaitForDevice()
- timeout_retry.WaitFor(sd_card_ready)
- timeout_retry.WaitFor(pm_ready)
- timeout_retry.WaitFor(boot_completed)
- if wifi:
- timeout_retry.WaitFor(wifi_enabled)
-
- REBOOT_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT
-
- @decorators.WithTimeoutAndRetriesFromInstance(
- min_default_timeout=REBOOT_DEFAULT_TIMEOUT)
- def Reboot(self, block=True, wifi=False, timeout=None, retries=None):
- """Reboot the device.
-
- Args:
- block: A boolean indicating if we should wait for the reboot to complete.
- wifi: A boolean indicating if we should wait for wifi to be enabled after
- the reboot. The option has no effect unless |block| is also True.
- timeout: timeout in seconds
- retries: number of retries
-
- Raises:
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- def device_offline():
- return not self.IsOnline()
-
- self.adb.Reboot()
- self._ClearCache()
- timeout_retry.WaitFor(device_offline, wait_period=1)
- if block:
- self.WaitUntilFullyBooted(wifi=wifi)
-
- INSTALL_DEFAULT_TIMEOUT = 4 * _DEFAULT_TIMEOUT
-
- @decorators.WithTimeoutAndRetriesFromInstance(
- min_default_timeout=INSTALL_DEFAULT_TIMEOUT)
- def Install(self, apk, allow_downgrade=False, reinstall=False,
- permissions=None, timeout=None, retries=None):
- """Install an APK.
-
- Noop if an identical APK is already installed.
-
- Args:
- apk: An ApkHelper instance or string containing the path to the APK.
- allow_downgrade: A boolean indicating if we should allow downgrades.
- reinstall: A boolean indicating if we should keep any existing app data.
- permissions: Set of permissions to set. If not set, finds permissions with
- apk helper. To set no permissions, pass [].
- timeout: timeout in seconds
- retries: number of retries
-
- Raises:
- CommandFailedError if the installation fails.
- CommandTimeoutError if the installation times out.
- DeviceUnreachableError on missing device.
- """
- self._InstallInternal(apk, None, allow_downgrade=allow_downgrade,
- reinstall=reinstall, permissions=permissions)
-
- @decorators.WithTimeoutAndRetriesFromInstance(
- min_default_timeout=INSTALL_DEFAULT_TIMEOUT)
- def InstallSplitApk(self, base_apk, split_apks, allow_downgrade=False,
- reinstall=False, allow_cached_props=False,
- permissions=None, timeout=None, retries=None):
- """Install a split APK.
-
- Noop if all of the APK splits are already installed.
-
- Args:
- base_apk: An ApkHelper instance or string containing the path to the base
- APK.
- split_apks: A list of strings of paths of all of the APK splits.
- allow_downgrade: A boolean indicating if we should allow downgrades.
- reinstall: A boolean indicating if we should keep any existing app data.
- allow_cached_props: Whether to use cached values for device properties.
- permissions: Set of permissions to set. If not set, finds permissions with
- apk helper. To set no permissions, pass [].
- timeout: timeout in seconds
- retries: number of retries
-
- Raises:
- CommandFailedError if the installation fails.
- CommandTimeoutError if the installation times out.
- DeviceUnreachableError on missing device.
- DeviceVersionError if device SDK is less than Android L.
- """
- self._InstallInternal(base_apk, split_apks, reinstall=reinstall,
- allow_cached_props=allow_cached_props,
- permissions=permissions,
- allow_downgrade=allow_downgrade)
-
- def _InstallInternal(self, base_apk, split_apks, allow_downgrade=False,
- reinstall=False, allow_cached_props=False,
- permissions=None):
- if split_apks:
- self._CheckSdkLevel(version_codes.LOLLIPOP)
-
- base_apk = apk_helper.ToHelper(base_apk)
-
- all_apks = [base_apk.path]
- if split_apks:
- all_apks += split_select.SelectSplits(
- self, base_apk.path, split_apks, allow_cached_props=allow_cached_props)
- if len(all_apks) == 1:
- logger.warning('split-select did not select any from %s', split_apks)
-
- missing_apks = [apk for apk in all_apks if not os.path.exists(apk)]
- if missing_apks:
- raise device_errors.CommandFailedError(
- 'Attempted to install non-existent apks: %s'
- % pprint.pformat(missing_apks))
-
- package_name = base_apk.GetPackageName()
- device_apk_paths = self._GetApplicationPathsInternal(package_name)
-
- apks_to_install = None
- host_checksums = None
- if not device_apk_paths:
- apks_to_install = all_apks
- elif len(device_apk_paths) > 1 and not split_apks:
- logger.warning(
- 'Installing non-split APK when split APK was previously installed')
- apks_to_install = all_apks
- elif len(device_apk_paths) == 1 and split_apks:
- logger.warning(
- 'Installing split APK when non-split APK was previously installed')
- apks_to_install = all_apks
- else:
- try:
- apks_to_install, host_checksums = (
- self._ComputeStaleApks(package_name, all_apks))
- except EnvironmentError as e:
- logger.warning('Error calculating md5: %s', e)
- apks_to_install, host_checksums = all_apks, None
- if apks_to_install and not reinstall:
- self.Uninstall(package_name)
- apks_to_install = all_apks
-
- if apks_to_install:
- # Assume that we won't know the resulting device state.
- self._cache['package_apk_paths'].pop(package_name, 0)
- self._cache['package_apk_checksums'].pop(package_name, 0)
- if split_apks:
- partial = package_name if len(apks_to_install) < len(all_apks) else None
- self.adb.InstallMultiple(
- apks_to_install, partial=partial, reinstall=reinstall,
- allow_downgrade=allow_downgrade)
- else:
- self.adb.Install(
- base_apk.path, reinstall=reinstall, allow_downgrade=allow_downgrade)
- if (permissions is None
- and self.build_version_sdk >= version_codes.MARSHMALLOW):
- permissions = base_apk.GetPermissions()
- self.GrantPermissions(package_name, permissions)
- # Upon success, we know the device checksums, but not their paths.
- if host_checksums is not None:
- self._cache['package_apk_checksums'][package_name] = host_checksums
- else:
- # Running adb install terminates running instances of the app, so to be
- # consistent, we explicitly terminate it when skipping the install.
- self.ForceStop(package_name)
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def Uninstall(self, package_name, keep_data=False, timeout=None,
- retries=None):
- """Remove the app |package_name| from the device.
-
- This is a no-op if the app is not already installed.
-
- Args:
- package_name: The package to uninstall.
- keep_data: (optional) Whether to keep the data and cache directories.
- timeout: Timeout in seconds.
- retries: Number of retries.
-
- Raises:
- CommandFailedError if the uninstallation fails.
- CommandTimeoutError if the uninstallation times out.
- DeviceUnreachableError on missing device.
- """
- installed = self._GetApplicationPathsInternal(package_name)
- if not installed:
- return
- try:
- self.adb.Uninstall(package_name, keep_data)
- self._cache['package_apk_paths'][package_name] = []
- self._cache['package_apk_checksums'][package_name] = set()
- except:
- # Clear cache since we can't be sure of the state.
- self._cache['package_apk_paths'].pop(package_name, 0)
- self._cache['package_apk_checksums'].pop(package_name, 0)
- raise
-
- def _CheckSdkLevel(self, required_sdk_level):
- """Raises an exception if the device does not have the required SDK level.
- """
- if self.build_version_sdk < required_sdk_level:
- raise device_errors.DeviceVersionError(
- ('Requires SDK level %s, device is SDK level %s' %
- (required_sdk_level, self.build_version_sdk)),
- device_serial=self.serial)
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def RunShellCommand(self, cmd, shell=False, check_return=False, cwd=None,
- env=None, run_as=None, as_root=False, single_line=False,
- large_output=False, raw_output=False, timeout=None,
- retries=None):
- """Run an ADB shell command.
-
- The command to run |cmd| should be a sequence of program arguments
- (preferred) or a single string with a shell script to run.
-
- When |cmd| is a sequence, it is assumed to contain the name of the command
- to run followed by its arguments. In this case, arguments are passed to the
- command exactly as given, preventing any further processing by the shell.
- This allows callers to easily pass arguments with spaces or special
- characters without having to worry about quoting rules. Whenever possible,
- it is recomended to pass |cmd| as a sequence.
-
- When |cmd| is passed as a single string, |shell| should be set to True.
- The command will be interpreted and run by the shell on the device,
- allowing the use of shell features such as pipes, wildcards, or variables.
- Failing to set shell=True will issue a warning, but this will be changed
- to a hard failure in the future (see: catapult:#3242).
-
- This behaviour is consistent with that of command runners in cmd_helper as
- well as Python's own subprocess.Popen.
-
- TODO(perezju) Change the default of |check_return| to True when callers
- have switched to the new behaviour.
-
- Args:
- cmd: A sequence containing the command to run and its arguments, or a
- string with a shell script to run (should also set shell=True).
- shell: A boolean indicating whether shell features may be used in |cmd|.
- check_return: A boolean indicating whether or not the return code should
- be checked.
- cwd: The device directory in which the command should be run.
- env: The environment variables with which the command should be run.
- run_as: A string containing the package as which the command should be
- run.
- as_root: A boolean indicating whether the shell command should be run
- with root privileges.
- single_line: A boolean indicating if only a single line of output is
- expected.
- large_output: Uses a work-around for large shell command output. Without
- this large output will be truncated.
- raw_output: Whether to only return the raw output
- (no splitting into lines).
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- If single_line is False, the output of the command as a list of lines,
- otherwise, a string with the unique line of output emmited by the command
- (with the optional newline at the end stripped).
-
- Raises:
- AdbCommandFailedError if check_return is True and the exit code of
- the command run on the device is non-zero.
- CommandFailedError if single_line is True but the output contains two or
- more lines.
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- def env_quote(key, value):
- if not DeviceUtils._VALID_SHELL_VARIABLE.match(key):
- raise KeyError('Invalid shell variable name %r' % key)
- # using double quotes here to allow interpolation of shell variables
- return '%s=%s' % (key, cmd_helper.DoubleQuote(value))
-
- def run(cmd):
- return self.adb.Shell(cmd)
-
- def handle_check_return(cmd):
- try:
- return run(cmd)
- except device_errors.AdbCommandFailedError as exc:
- if check_return:
- raise
- else:
- return exc.output
-
- def handle_large_command(cmd):
- if len(cmd) < self._MAX_ADB_COMMAND_LENGTH:
- return handle_check_return(cmd)
- else:
- with device_temp_file.DeviceTempFile(self.adb, suffix='.sh') as script:
- self._WriteFileWithPush(script.name, cmd)
- logger.info('Large shell command will be run from file: %s ...',
- cmd[:self._MAX_ADB_COMMAND_LENGTH])
- return handle_check_return('sh %s' % script.name_quoted)
-
- def handle_large_output(cmd, large_output_mode):
- if large_output_mode:
- with device_temp_file.DeviceTempFile(self.adb) as large_output_file:
- cmd = '( %s )>%s' % (cmd, large_output_file.name)
- logger.debug('Large output mode enabled. Will write output to '
- 'device and read results from file.')
- handle_large_command(cmd)
- return self.ReadFile(large_output_file.name, force_pull=True)
- else:
- try:
- return handle_large_command(cmd)
- except device_errors.AdbCommandFailedError as exc:
- if exc.status is None:
- logger.error(_FormatPartialOutputError(exc.output))
- logger.warning('Attempting to run in large_output mode.')
- logger.warning('Use RunShellCommand(..., large_output=True) for '
- 'shell commands that expect a lot of output.')
- return handle_large_output(cmd, True)
- else:
- raise
-
- if isinstance(cmd, basestring):
- if not shell:
- logging.warning(
- 'The command to run should preferably be passed as a sequence of'
- ' args. If shell features are needed (pipes, wildcards, variables)'
- ' clients should explicitly set shell=True.')
- else:
- cmd = ' '.join(cmd_helper.SingleQuote(s) for s in cmd)
- if env:
- env = ' '.join(env_quote(k, v) for k, v in env.iteritems())
- cmd = '%s %s' % (env, cmd)
- if cwd:
- cmd = 'cd %s && %s' % (cmd_helper.SingleQuote(cwd), cmd)
- if run_as:
- cmd = 'run-as %s sh -c %s' % (cmd_helper.SingleQuote(run_as),
- cmd_helper.SingleQuote(cmd))
- if as_root and self.NeedsSU():
- # "su -c sh -c" allows using shell features in |cmd|
- cmd = self._Su('sh -c %s' % cmd_helper.SingleQuote(cmd))
-
- output = handle_large_output(cmd, large_output)
-
- if raw_output:
- return output
-
- output = output.splitlines()
- if single_line:
- if not output:
- return ''
- elif len(output) == 1:
- return output[0]
- else:
- msg = 'one line of output was expected, but got: %s'
- raise device_errors.CommandFailedError(msg % output, str(self))
- else:
- return output
-
- def _RunPipedShellCommand(self, script, **kwargs):
- PIPESTATUS_LEADER = 'PIPESTATUS: '
-
- script += '; echo "%s${PIPESTATUS[@]}"' % PIPESTATUS_LEADER
- kwargs.update(shell=True, check_return=True)
- output = self.RunShellCommand(script, **kwargs)
- pipestatus_line = output[-1]
-
- if not pipestatus_line.startswith(PIPESTATUS_LEADER):
- logger.error('Pipe exit statuses of shell script missing.')
- raise device_errors.AdbShellCommandFailedError(
- script, output, status=None,
- device_serial=self.serial)
-
- output = output[:-1]
- statuses = [
- int(s) for s in pipestatus_line[len(PIPESTATUS_LEADER):].split()]
- if any(statuses):
- raise device_errors.AdbShellCommandFailedError(
- script, output, status=statuses,
- device_serial=self.serial)
- return output
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def KillAll(self, process_name, exact=False, signum=device_signal.SIGKILL,
- as_root=False, blocking=False, quiet=False,
- timeout=None, retries=None):
- """Kill all processes with the given name on the device.
-
- Args:
- process_name: A string containing the name of the process to kill.
- exact: A boolean indicating whether to kill all processes matching
- the string |process_name| exactly, or all of those which contain
- |process_name| as a substring. Defaults to False.
- signum: An integer containing the signal number to send to kill. Defaults
- to SIGKILL (9).
- as_root: A boolean indicating whether the kill should be executed with
- root privileges.
- blocking: A boolean indicating whether we should wait until all processes
- with the given |process_name| are dead.
- quiet: A boolean indicating whether to ignore the fact that no processes
- to kill were found.
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- The number of processes attempted to kill.
-
- Raises:
- CommandFailedError if no process was killed and |quiet| is False.
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- procs_pids = self.GetPids(process_name)
- if exact:
- procs_pids = {process_name: procs_pids.get(process_name, [])}
- pids = set(itertools.chain(*procs_pids.values()))
- if not pids:
- if quiet:
- return 0
- else:
- raise device_errors.CommandFailedError(
- 'No process "%s"' % process_name, str(self))
-
- logger.info(
- 'KillAll(%r, ...) attempting to kill the following:', process_name)
- for name, ids in procs_pids.iteritems():
- for i in ids:
- logger.info(' %05s %s', str(i), name)
-
- cmd = ['kill', '-%d' % signum] + sorted(pids)
- self.RunShellCommand(cmd, as_root=as_root, check_return=True)
-
- def all_pids_killed():
- procs_pids_remain = self.GetPids(process_name)
- return not pids.intersection(itertools.chain(*procs_pids_remain.values()))
-
- if blocking:
- timeout_retry.WaitFor(all_pids_killed, wait_period=0.1)
-
- return len(pids)
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def StartActivity(self, intent_obj, blocking=False, trace_file_name=None,
- force_stop=False, timeout=None, retries=None):
- """Start package's activity on the device.
-
- Args:
- intent_obj: An Intent object to send.
- blocking: A boolean indicating whether we should wait for the activity to
- finish launching.
- trace_file_name: If present, a string that both indicates that we want to
- profile the activity and contains the path to which the
- trace should be saved.
- force_stop: A boolean indicating whether we should stop the activity
- before starting it.
- timeout: timeout in seconds
- retries: number of retries
-
- Raises:
- CommandFailedError if the activity could not be started.
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- cmd = ['am', 'start']
- if blocking:
- cmd.append('-W')
- if trace_file_name:
- cmd.extend(['--start-profiler', trace_file_name])
- if force_stop:
- cmd.append('-S')
- cmd.extend(intent_obj.am_args)
- for line in self.RunShellCommand(cmd, check_return=True):
- if line.startswith('Error:'):
- raise device_errors.CommandFailedError(line, str(self))
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def StartInstrumentation(self, component, finish=True, raw=False,
- extras=None, timeout=None, retries=None):
- if extras is None:
- extras = {}
-
- cmd = ['am', 'instrument']
- if finish:
- cmd.append('-w')
- if raw:
- cmd.append('-r')
- for k, v in extras.iteritems():
- cmd.extend(['-e', str(k), str(v)])
- cmd.append(component)
-
- # Store the package name in a shell variable to help the command stay under
- # the _MAX_ADB_COMMAND_LENGTH limit.
- package = component.split('/')[0]
- shell_snippet = 'p=%s;%s' % (package,
- cmd_helper.ShrinkToSnippet(cmd, 'p', package))
- return self.RunShellCommand(shell_snippet, shell=True, check_return=True,
- large_output=True)
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def BroadcastIntent(self, intent_obj, timeout=None, retries=None):
- """Send a broadcast intent.
-
- Args:
- intent: An Intent to broadcast.
- timeout: timeout in seconds
- retries: number of retries
-
- Raises:
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- cmd = ['am', 'broadcast'] + intent_obj.am_args
- self.RunShellCommand(cmd, check_return=True)
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def GoHome(self, timeout=None, retries=None):
- """Return to the home screen and obtain launcher focus.
-
- This command launches the home screen and attempts to obtain
- launcher focus until the timeout is reached.
-
- Args:
- timeout: timeout in seconds
- retries: number of retries
-
- Raises:
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- def is_launcher_focused():
- output = self.RunShellCommand(['dumpsys', 'window', 'windows'],
- check_return=True, large_output=True)
- return any(self._LAUNCHER_FOCUSED_RE.match(l) for l in output)
-
- def dismiss_popups():
- # There is a dialog present; attempt to get rid of it.
- # Not all dialogs can be dismissed with back.
- self.SendKeyEvent(keyevent.KEYCODE_ENTER)
- self.SendKeyEvent(keyevent.KEYCODE_BACK)
- return is_launcher_focused()
-
- # If Home is already focused, return early to avoid unnecessary work.
- if is_launcher_focused():
- return
-
- self.StartActivity(
- intent.Intent(action='android.intent.action.MAIN',
- category='android.intent.category.HOME'),
- blocking=True)
-
- if not is_launcher_focused():
- timeout_retry.WaitFor(dismiss_popups, wait_period=1)
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def ForceStop(self, package, timeout=None, retries=None):
- """Close the application.
-
- Args:
- package: A string containing the name of the package to stop.
- timeout: timeout in seconds
- retries: number of retries
-
- Raises:
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- cmd = 'p=%s;if [[ "$(ps)" = *$p* ]]; then am force-stop $p; fi'
- self.RunShellCommand(cmd % package, shell=True, check_return=True)
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def ClearApplicationState(
- self, package, permissions=None, timeout=None, retries=None):
- """Clear all state for the given package.
-
- Args:
- package: A string containing the name of the package to stop.
- permissions: List of permissions to set after clearing data.
- timeout: timeout in seconds
- retries: number of retries
-
- Raises:
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- # Check that the package exists before clearing it for android builds below
- # JB MR2. Necessary because calling pm clear on a package that doesn't exist
- # may never return.
- if ((self.build_version_sdk >= version_codes.JELLY_BEAN_MR2)
- or self._GetApplicationPathsInternal(package)):
- self.RunShellCommand(['pm', 'clear', package], check_return=True)
- self.GrantPermissions(package, permissions)
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def SendKeyEvent(self, keycode, timeout=None, retries=None):
- """Sends a keycode to the device.
-
- See the devil.android.sdk.keyevent module for suitable keycode values.
-
- Args:
- keycode: A integer keycode to send to the device.
- timeout: timeout in seconds
- retries: number of retries
-
- Raises:
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- self.RunShellCommand(['input', 'keyevent', format(keycode, 'd')],
- check_return=True)
-
- PUSH_CHANGED_FILES_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT
-
- @decorators.WithTimeoutAndRetriesFromInstance(
- min_default_timeout=PUSH_CHANGED_FILES_DEFAULT_TIMEOUT)
- def PushChangedFiles(self, host_device_tuples, timeout=None,
- retries=None, delete_device_stale=False):
- """Push files to the device, skipping files that don't need updating.
-
- When a directory is pushed, it is traversed recursively on the host and
- all files in it are pushed to the device as needed.
- Additionally, if delete_device_stale option is True,
- files that exist on the device but don't exist on the host are deleted.
-
- Args:
- host_device_tuples: A list of (host_path, device_path) tuples, where
- |host_path| is an absolute path of a file or directory on the host
- that should be minimially pushed to the device, and |device_path| is
- an absolute path of the destination on the device.
- timeout: timeout in seconds
- retries: number of retries
- delete_device_stale: option to delete stale files on device
-
- Raises:
- CommandFailedError on failure.
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
-
- all_changed_files = []
- all_stale_files = []
- missing_dirs = []
- cache_commit_funcs = []
- for h, d in host_device_tuples:
- assert os.path.isabs(h) and posixpath.isabs(d)
- h = os.path.realpath(h)
- changed_files, up_to_date_files, stale_files, cache_commit_func = (
- self._GetChangedAndStaleFiles(h, d, delete_device_stale))
- all_changed_files += changed_files
- all_stale_files += stale_files
- cache_commit_funcs.append(cache_commit_func)
- if changed_files and not up_to_date_files and not stale_files:
- if os.path.isdir(h):
- missing_dirs.append(d)
- else:
- missing_dirs.append(posixpath.dirname(d))
-
- if delete_device_stale and all_stale_files:
- self.RunShellCommand(['rm', '-f'] + all_stale_files, check_return=True)
-
- if all_changed_files:
- if missing_dirs:
- self.RunShellCommand(['mkdir', '-p'] + missing_dirs, check_return=True)
- self._PushFilesImpl(host_device_tuples, all_changed_files)
- for func in cache_commit_funcs:
- func()
-
- def _GetChangedAndStaleFiles(self, host_path, device_path, track_stale=False):
- """Get files to push and delete
-
- Args:
- host_path: an absolute path of a file or directory on the host
- device_path: an absolute path of a file or directory on the device
- track_stale: whether to bother looking for stale files (slower)
-
- Returns:
- a four-element tuple
- 1st element: a list of (host_files_path, device_files_path) tuples to push
- 2nd element: a list of host_files_path that are up-to-date
- 3rd element: a list of stale files under device_path, or [] when
- track_stale == False
- 4th element: a cache commit function.
- """
- try:
- # Length calculations below assume no trailing /.
- host_path = host_path.rstrip('/')
- device_path = device_path.rstrip('/')
-
- specific_device_paths = [device_path]
- ignore_other_files = not track_stale and os.path.isdir(host_path)
- if ignore_other_files:
- specific_device_paths = []
- for root, _, filenames in os.walk(host_path):
- relative_dir = root[len(host_path) + 1:]
- specific_device_paths.extend(
- posixpath.join(device_path, relative_dir, f) for f in filenames)
-
- def calculate_host_checksums():
- return md5sum.CalculateHostMd5Sums([host_path])
-
- def calculate_device_checksums():
- if self._enable_device_files_cache:
- cache_entry = self._cache['device_path_checksums'].get(device_path)
- if cache_entry and cache_entry[0] == ignore_other_files:
- return dict(cache_entry[1])
-
- sums = md5sum.CalculateDeviceMd5Sums(specific_device_paths, self)
-
- cache_entry = [ignore_other_files, sums]
- self._cache['device_path_checksums'][device_path] = cache_entry
- return dict(sums)
-
- host_checksums, device_checksums = reraiser_thread.RunAsync((
- calculate_host_checksums,
- calculate_device_checksums))
- except EnvironmentError as e:
- logger.warning('Error calculating md5: %s', e)
- return ([(host_path, device_path)], [], [], lambda: 0)
-
- to_push = []
- up_to_date = []
- to_delete = []
- if os.path.isfile(host_path):
- host_checksum = host_checksums.get(host_path)
- device_checksum = device_checksums.get(device_path)
- if host_checksum == device_checksum:
- up_to_date.append(host_path)
- else:
- to_push.append((host_path, device_path))
- else:
- for host_abs_path, host_checksum in host_checksums.iteritems():
- device_abs_path = posixpath.join(
- device_path, os.path.relpath(host_abs_path, host_path))
- device_checksum = device_checksums.pop(device_abs_path, None)
- if device_checksum == host_checksum:
- up_to_date.append(host_abs_path)
- else:
- to_push.append((host_abs_path, device_abs_path))
- to_delete = device_checksums.keys()
-
- def cache_commit_func():
- new_sums = {posixpath.join(device_path, path[len(host_path) + 1:]): val
- for path, val in host_checksums.iteritems()}
- cache_entry = [ignore_other_files, new_sums]
- self._cache['device_path_checksums'][device_path] = cache_entry
-
- return (to_push, up_to_date, to_delete, cache_commit_func)
-
- def _ComputeDeviceChecksumsForApks(self, package_name):
- ret = self._cache['package_apk_checksums'].get(package_name)
- if ret is None:
- device_paths = self._GetApplicationPathsInternal(package_name)
- file_to_checksums = md5sum.CalculateDeviceMd5Sums(device_paths, self)
- ret = set(file_to_checksums.values())
- self._cache['package_apk_checksums'][package_name] = ret
- return ret
-
- def _ComputeStaleApks(self, package_name, host_apk_paths):
- def calculate_host_checksums():
- return md5sum.CalculateHostMd5Sums(host_apk_paths)
-
- def calculate_device_checksums():
- return self._ComputeDeviceChecksumsForApks(package_name)
-
- host_checksums, device_checksums = reraiser_thread.RunAsync((
- calculate_host_checksums, calculate_device_checksums))
- stale_apks = [k for (k, v) in host_checksums.iteritems()
- if v not in device_checksums]
- return stale_apks, set(host_checksums.values())
-
- def _PushFilesImpl(self, host_device_tuples, files):
- if not files:
- return
-
- size = sum(host_utils.GetRecursiveDiskUsage(h) for h, _ in files)
- file_count = len(files)
- dir_size = sum(host_utils.GetRecursiveDiskUsage(h)
- for h, _ in host_device_tuples)
- dir_file_count = 0
- for h, _ in host_device_tuples:
- if os.path.isdir(h):
- dir_file_count += sum(len(f) for _r, _d, f in os.walk(h))
- else:
- dir_file_count += 1
-
- push_duration = self._ApproximateDuration(
- file_count, file_count, size, False)
- dir_push_duration = self._ApproximateDuration(
- len(host_device_tuples), dir_file_count, dir_size, False)
- zip_duration = self._ApproximateDuration(1, 1, size, True)
-
- if (dir_push_duration < push_duration and dir_push_duration < zip_duration
- # TODO(jbudorick): Resume directory pushing once clients have switched
- # to 1.0.36-compatible syntax.
- and False):
- self._PushChangedFilesIndividually(host_device_tuples)
- elif push_duration < zip_duration:
- self._PushChangedFilesIndividually(files)
- elif self._commands_installed is False:
- # Already tried and failed to install unzip command.
- self._PushChangedFilesIndividually(files)
- elif not self._PushChangedFilesZipped(
- files, [d for _, d in host_device_tuples]):
- self._PushChangedFilesIndividually(files)
-
- def _MaybeInstallCommands(self):
- if self._commands_installed is None:
- try:
- if not install_commands.Installed(self):
- install_commands.InstallCommands(self)
- self._commands_installed = True
- except device_errors.CommandFailedError as e:
- logger.warning('unzip not available: %s', str(e))
- self._commands_installed = False
- return self._commands_installed
-
- @staticmethod
- def _ApproximateDuration(adb_calls, file_count, byte_count, is_zipping):
- # We approximate the time to push a set of files to a device as:
- # t = c1 * a + c2 * f + c3 + b / c4 + b / (c5 * c6), where
- # t: total time (sec)
- # c1: adb call time delay (sec)
- # a: number of times adb is called (unitless)
- # c2: push time delay (sec)
- # f: number of files pushed via adb (unitless)
- # c3: zip time delay (sec)
- # c4: zip rate (bytes/sec)
- # b: total number of bytes (bytes)
- # c5: transfer rate (bytes/sec)
- # c6: compression ratio (unitless)
-
- # All of these are approximations.
- ADB_CALL_PENALTY = 0.1 # seconds
- ADB_PUSH_PENALTY = 0.01 # seconds
- ZIP_PENALTY = 2.0 # seconds
- ZIP_RATE = 10000000.0 # bytes / second
- TRANSFER_RATE = 2000000.0 # bytes / second
- COMPRESSION_RATIO = 2.0 # unitless
-
- adb_call_time = ADB_CALL_PENALTY * adb_calls
- adb_push_setup_time = ADB_PUSH_PENALTY * file_count
- if is_zipping:
- zip_time = ZIP_PENALTY + byte_count / ZIP_RATE
- transfer_time = byte_count / (TRANSFER_RATE * COMPRESSION_RATIO)
- else:
- zip_time = 0
- transfer_time = byte_count / TRANSFER_RATE
- return adb_call_time + adb_push_setup_time + zip_time + transfer_time
-
- def _PushChangedFilesIndividually(self, files):
- for h, d in files:
- self.adb.Push(h, d)
-
- def _PushChangedFilesZipped(self, files, dirs):
- with tempfile.NamedTemporaryFile(suffix='.zip') as zip_file:
- zip_proc = multiprocessing.Process(
- target=DeviceUtils._CreateDeviceZip,
- args=(zip_file.name, files))
- zip_proc.start()
- try:
- # While it's zipping, ensure the unzip command exists on the device.
- if not self._MaybeInstallCommands():
- zip_proc.terminate()
- return False
-
- # Warm up NeedsSU cache while we're still zipping.
- self.NeedsSU()
- with device_temp_file.DeviceTempFile(
- self.adb, suffix='.zip') as device_temp:
- zip_proc.join()
- self.adb.Push(zip_file.name, device_temp.name)
- quoted_dirs = ' '.join(cmd_helper.SingleQuote(d) for d in dirs)
- self.RunShellCommand(
- 'unzip %s&&chmod -R 777 %s' % (device_temp.name, quoted_dirs),
- shell=True, as_root=True,
- env={'PATH': '%s:$PATH' % install_commands.BIN_DIR},
- check_return=True)
- finally:
- if zip_proc.is_alive():
- zip_proc.terminate()
- return True
-
- @staticmethod
- def _CreateDeviceZip(zip_path, host_device_tuples):
- with zipfile.ZipFile(zip_path, 'w') as zip_file:
- for host_path, device_path in host_device_tuples:
- zip_utils.WriteToZipFile(zip_file, host_path, device_path)
-
- # TODO(nednguyen): remove this and migrate the callsite to PathExists().
- @decorators.WithTimeoutAndRetriesFromInstance()
- def FileExists(self, device_path, timeout=None, retries=None):
- """Checks whether the given file exists on the device.
-
- Arguments are the same as PathExists.
- """
- return self.PathExists(device_path, timeout=timeout, retries=retries)
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def PathExists(self, device_paths, as_root=False, timeout=None, retries=None):
- """Checks whether the given path(s) exists on the device.
-
- Args:
- device_path: A string containing the absolute path to the file on the
- device, or an iterable of paths to check.
- as_root: Whether root permissions should be use to check for the existence
- of the given path(s).
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- True if the all given paths exist on the device, False otherwise.
-
- Raises:
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- paths = device_paths
- if isinstance(paths, basestring):
- paths = (paths,)
- if not paths:
- return True
- cmd = ['test', '-e', paths[0]]
- for p in paths[1:]:
- cmd.extend(['-a', '-e', p])
- try:
- self.RunShellCommand(cmd, as_root=as_root, check_return=True,
- timeout=timeout, retries=retries)
- return True
- except device_errors.CommandFailedError:
- return False
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def RemovePath(self, device_path, force=False, recursive=False,
- as_root=False, timeout=None, retries=None):
- """Removes the given path(s) from the device.
-
- Args:
- device_path: A string containing the absolute path to the file on the
- device, or an iterable of paths to check.
- force: Whether to remove the path(s) with force (-f).
- recursive: Whether to remove any directories in the path(s) recursively.
- as_root: Whether root permissions should be use to remove the given
- path(s).
- timeout: timeout in seconds
- retries: number of retries
- """
- args = ['rm']
- if force:
- args.append('-f')
- if recursive:
- args.append('-r')
- if isinstance(device_path, basestring):
- args.append(device_path)
- else:
- args.extend(device_path)
- self.RunShellCommand(args, as_root=as_root, check_return=True)
-
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def PullFile(self, device_path, host_path, timeout=None, retries=None):
- """Pull a file from the device.
-
- Args:
- device_path: A string containing the absolute path of the file to pull
- from the device.
- host_path: A string containing the absolute path of the destination on
- the host.
- timeout: timeout in seconds
- retries: number of retries
-
- Raises:
- CommandFailedError on failure.
- CommandTimeoutError on timeout.
- """
- # Create the base dir if it doesn't exist already
- dirname = os.path.dirname(host_path)
- if dirname and not os.path.exists(dirname):
- os.makedirs(dirname)
- self.adb.Pull(device_path, host_path)
-
- def _ReadFileWithPull(self, device_path):
- try:
- d = tempfile.mkdtemp()
- host_temp_path = os.path.join(d, 'tmp_ReadFileWithPull')
- self.adb.Pull(device_path, host_temp_path)
- with open(host_temp_path, 'r') as host_temp:
- return host_temp.read()
- finally:
- if os.path.exists(d):
- shutil.rmtree(d)
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def ReadFile(self, device_path, as_root=False, force_pull=False,
- timeout=None, retries=None):
- """Reads the contents of a file from the device.
-
- Args:
- device_path: A string containing the absolute path of the file to read
- from the device.
- as_root: A boolean indicating whether the read should be executed with
- root privileges.
- force_pull: A boolean indicating whether to force the operation to be
- performed by pulling a file from the device. The default is, when the
- contents are short, to retrieve the contents using cat instead.
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- The contents of |device_path| as a string. Contents are intepreted using
- universal newlines, so the caller will see them encoded as '\n'. Also,
- all lines will be terminated.
-
- Raises:
- AdbCommandFailedError if the file can't be read.
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- def get_size(path):
- return self.FileSize(path, as_root=as_root)
-
- if (not force_pull
- and 0 < get_size(device_path) <= self._MAX_ADB_OUTPUT_LENGTH):
- return _JoinLines(self.RunShellCommand(
- ['cat', device_path], as_root=as_root, check_return=True))
- elif as_root and self.NeedsSU():
- with device_temp_file.DeviceTempFile(self.adb) as device_temp:
- cmd = 'SRC=%s DEST=%s;cp "$SRC" "$DEST" && chmod 666 "$DEST"' % (
- cmd_helper.SingleQuote(device_path),
- cmd_helper.SingleQuote(device_temp.name))
- self.RunShellCommand(cmd, shell=True, as_root=True, check_return=True)
- return self._ReadFileWithPull(device_temp.name)
- else:
- return self._ReadFileWithPull(device_path)
-
- def _WriteFileWithPush(self, device_path, contents):
- with tempfile.NamedTemporaryFile() as host_temp:
- host_temp.write(contents)
- host_temp.flush()
- self.adb.Push(host_temp.name, device_path)
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def WriteFile(self, device_path, contents, as_root=False, force_push=False,
- timeout=None, retries=None):
- """Writes |contents| to a file on the device.
-
- Args:
- device_path: A string containing the absolute path to the file to write
- on the device.
- contents: A string containing the data to write to the device.
- as_root: A boolean indicating whether the write should be executed with
- root privileges (if available).
- force_push: A boolean indicating whether to force the operation to be
- performed by pushing a file to the device. The default is, when the
- contents are short, to pass the contents using a shell script instead.
- timeout: timeout in seconds
- retries: number of retries
-
- Raises:
- CommandFailedError if the file could not be written on the device.
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- if not force_push and len(contents) < self._MAX_ADB_COMMAND_LENGTH:
- # If the contents are small, for efficieny we write the contents with
- # a shell command rather than pushing a file.
- cmd = 'echo -n %s > %s' % (cmd_helper.SingleQuote(contents),
- cmd_helper.SingleQuote(device_path))
- self.RunShellCommand(cmd, shell=True, as_root=as_root, check_return=True)
- elif as_root and self.NeedsSU():
- # Adb does not allow to "push with su", so we first push to a temp file
- # on a safe location, and then copy it to the desired location with su.
- with device_temp_file.DeviceTempFile(self.adb) as device_temp:
- self._WriteFileWithPush(device_temp.name, contents)
- # Here we need 'cp' rather than 'mv' because the temp and
- # destination files might be on different file systems (e.g.
- # on internal storage and an external sd card).
- self.RunShellCommand(['cp', device_temp.name, device_path],
- as_root=True, check_return=True)
- else:
- # If root is not needed, we can push directly to the desired location.
- self._WriteFileWithPush(device_path, contents)
-
- def _ParseLongLsOutput(self, device_path, as_root=False, **kwargs):
- """Run and scrape the output of 'ls -a -l' on a device directory."""
- device_path = posixpath.join(device_path, '') # Force trailing '/'.
- output = self.RunShellCommand(
- ['ls', '-a', '-l', device_path], as_root=as_root,
- check_return=True, env={'TZ': 'utc'}, **kwargs)
- if output and output[0].startswith('total '):
- output.pop(0) # pylint: disable=maybe-no-member
-
- entries = []
- for line in output:
- m = _LONG_LS_OUTPUT_RE.match(line)
- if m:
- if m.group('filename') not in ['.', '..']:
- entries.append(m.groupdict())
- else:
- logger.info('Skipping: %s', line)
-
- return entries
-
- def ListDirectory(self, device_path, as_root=False, **kwargs):
- """List all files on a device directory.
-
- Mirroring os.listdir (and most client expectations) the resulting list
- does not include the special entries '.' and '..' even if they are present
- in the directory.
-
- Args:
- device_path: A string containing the path of the directory on the device
- to list.
- as_root: A boolean indicating whether the to use root privileges to list
- the directory contents.
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- A list of filenames for all entries contained in the directory.
-
- Raises:
- AdbCommandFailedError if |device_path| does not specify a valid and
- accessible directory in the device.
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- entries = self._ParseLongLsOutput(device_path, as_root=as_root, **kwargs)
- return [d['filename'] for d in entries]
-
- def StatDirectory(self, device_path, as_root=False, **kwargs):
- """List file and stat info for all entries on a device directory.
-
- Implementation notes: this is currently implemented by parsing the output
- of 'ls -a -l' on the device. Whether possible and convenient, we attempt to
- make parsing strict and return values mirroring those of the standard |os|
- and |stat| Python modules.
-
- Mirroring os.listdir (and most client expectations) the resulting list
- does not include the special entries '.' and '..' even if they are present
- in the directory.
-
- Args:
- device_path: A string containing the path of the directory on the device
- to list.
- as_root: A boolean indicating whether the to use root privileges to list
- the directory contents.
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- A list of dictionaries, each containing the following keys:
- filename: A string with the file name.
- st_mode: File permissions, use the stat module to interpret these.
- st_nlink: Number of hard links (may be missing).
- st_owner: A string with the user name of the owner.
- st_group: A string with the group name of the owner.
- st_rdev_pair: Device type as (major, minior) (only if inode device).
- st_size: Size of file, in bytes (may be missing for non-regular files).
- st_mtime: Time of most recent modification, in seconds since epoch
- (although resolution is in minutes).
- symbolic_link_to: If entry is a symbolic link, path where it points to;
- missing otherwise.
-
- Raises:
- AdbCommandFailedError if |device_path| does not specify a valid and
- accessible directory in the device.
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- entries = self._ParseLongLsOutput(device_path, as_root=as_root, **kwargs)
- for d in entries:
- for key, value in d.items():
- if value is None:
- del d[key] # Remove missing fields.
- d['st_mode'] = _ParseModeString(d['st_mode'])
- d['st_mtime'] = calendar.timegm(
- time.strptime(d['st_mtime'], _LS_DATE_FORMAT))
- for key in ['st_nlink', 'st_size', 'st_rdev_major', 'st_rdev_minor']:
- if key in d:
- d[key] = int(d[key])
- if 'st_rdev_major' in d and 'st_rdev_minor' in d:
- d['st_rdev_pair'] = (d.pop('st_rdev_major'), d.pop('st_rdev_minor'))
- return entries
-
- def StatPath(self, device_path, as_root=False, **kwargs):
- """Get the stat attributes of a file or directory on the device.
-
- Args:
- device_path: A string containing the path of a file or directory from
- which to get attributes.
- as_root: A boolean indicating whether the to use root privileges to
- access the file information.
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- A dictionary with the stat info collected; see StatDirectory for details.
-
- Raises:
- CommandFailedError if device_path cannot be found on the device.
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- dirname, filename = posixpath.split(posixpath.normpath(device_path))
- for entry in self.StatDirectory(dirname, as_root=as_root, **kwargs):
- if entry['filename'] == filename:
- return entry
- raise device_errors.CommandFailedError(
- 'Cannot find file or directory: %r' % device_path, str(self))
-
- def FileSize(self, device_path, as_root=False, **kwargs):
- """Get the size of a file on the device.
-
- Note: This is implemented by parsing the output of the 'ls' command on
- the device. On some Android versions, when passing a directory or special
- file, the size is *not* reported and this function will throw an exception.
-
- Args:
- device_path: A string containing the path of a file on the device.
- as_root: A boolean indicating whether the to use root privileges to
- access the file information.
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- The size of the file in bytes.
-
- Raises:
- CommandFailedError if device_path cannot be found on the device, or
- its size cannot be determited for some reason.
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- entry = self.StatPath(device_path, as_root=as_root, **kwargs)
- try:
- return entry['st_size']
- except KeyError:
- raise device_errors.CommandFailedError(
- 'Could not determine the size of: %s' % device_path, str(self))
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def SetJavaAsserts(self, enabled, timeout=None, retries=None):
- """Enables or disables Java asserts.
-
- Args:
- enabled: A boolean indicating whether Java asserts should be enabled
- or disabled.
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- True if the device-side property changed and a restart is required as a
- result, False otherwise.
-
- Raises:
- CommandTimeoutError on timeout.
- """
- def find_property(lines, property_name):
- for index, line in enumerate(lines):
- if line.strip() == '':
- continue
- key_value = tuple(s.strip() for s in line.split('=', 1))
- if len(key_value) != 2:
- continue
- key, value = key_value
- if key == property_name:
- return index, value
- return None, ''
-
- new_value = 'all' if enabled else ''
-
- # First ensure the desired property is persisted.
- try:
- properties = self.ReadFile(self.LOCAL_PROPERTIES_PATH).splitlines()
- except device_errors.CommandFailedError:
- properties = []
- index, value = find_property(properties, self.JAVA_ASSERT_PROPERTY)
- if new_value != value:
- if new_value:
- new_line = '%s=%s' % (self.JAVA_ASSERT_PROPERTY, new_value)
- if index is None:
- properties.append(new_line)
- else:
- properties[index] = new_line
- else:
- assert index is not None # since new_value == '' and new_value != value
- properties.pop(index)
- self.WriteFile(self.LOCAL_PROPERTIES_PATH, _JoinLines(properties))
-
- # Next, check the current runtime value is what we need, and
- # if not, set it and report that a reboot is required.
- value = self.GetProp(self.JAVA_ASSERT_PROPERTY)
- if new_value != value:
- self.SetProp(self.JAVA_ASSERT_PROPERTY, new_value)
- return True
- else:
- return False
-
- def GetLanguage(self, cache=False):
- """Returns the language setting on the device.
- Args:
- cache: Whether to use cached properties when available.
- """
- return self.GetProp('persist.sys.language', cache=cache)
-
- def GetCountry(self, cache=False):
- """Returns the country setting on the device.
-
- Args:
- cache: Whether to use cached properties when available.
- """
- return self.GetProp('persist.sys.country', cache=cache)
-
- @property
- def screen_density(self):
- """Returns the screen density of the device."""
- DPI_TO_DENSITY = {
- 120: 'ldpi',
- 160: 'mdpi',
- 240: 'hdpi',
- 320: 'xhdpi',
- 480: 'xxhdpi',
- 640: 'xxxhdpi',
- }
- return DPI_TO_DENSITY.get(self.pixel_density, 'tvdpi')
-
- @property
- def pixel_density(self):
- return int(self.GetProp('ro.sf.lcd_density', cache=True))
-
- @property
- def build_description(self):
- """Returns the build description of the system.
-
- For example:
- nakasi-user 4.4.4 KTU84P 1227136 release-keys
- """
- return self.GetProp('ro.build.description', cache=True)
-
- @property
- def build_fingerprint(self):
- """Returns the build fingerprint of the system.
-
- For example:
- google/nakasi/grouper:4.4.4/KTU84P/1227136:user/release-keys
- """
- return self.GetProp('ro.build.fingerprint', cache=True)
-
- @property
- def build_id(self):
- """Returns the build ID of the system (e.g. 'KTU84P')."""
- return self.GetProp('ro.build.id', cache=True)
-
- @property
- def build_product(self):
- """Returns the build product of the system (e.g. 'grouper')."""
- return self.GetProp('ro.build.product', cache=True)
-
- @property
- def build_type(self):
- """Returns the build type of the system (e.g. 'user')."""
- return self.GetProp('ro.build.type', cache=True)
-
- @property
- def build_version_sdk(self):
- """Returns the build version sdk of the system as a number (e.g. 19).
-
- For version code numbers see:
- http://developer.android.com/reference/android/os/Build.VERSION_CODES.html
-
- For named constants see devil.android.sdk.version_codes
-
- Raises:
- CommandFailedError if the build version sdk is not a number.
- """
- value = self.GetProp('ro.build.version.sdk', cache=True)
- try:
- return int(value)
- except ValueError:
- raise device_errors.CommandFailedError(
- 'Invalid build version sdk: %r' % value)
-
- @property
- def product_cpu_abi(self):
- """Returns the product cpu abi of the device (e.g. 'armeabi-v7a')."""
- return self.GetProp('ro.product.cpu.abi', cache=True)
-
- @property
- def product_model(self):
- """Returns the name of the product model (e.g. 'Nexus 7')."""
- return self.GetProp('ro.product.model', cache=True)
-
- @property
- def product_name(self):
- """Returns the product name of the device (e.g. 'nakasi')."""
- return self.GetProp('ro.product.name', cache=True)
-
- @property
- def product_board(self):
- """Returns the product board name of the device (e.g. 'shamu')."""
- return self.GetProp('ro.product.board', cache=True)
-
- def _EnsureCacheInitialized(self):
- """Populates cache token, runs getprop and fetches $EXTERNAL_STORAGE."""
- if self._cache['token']:
- return
- with self._cache_lock:
- if self._cache['token']:
- return
- # Change the token every time to ensure that it will match only the
- # previously dumped cache.
- token = str(uuid.uuid1())
- cmd = (
- 'c=/data/local/tmp/cache_token;'
- 'echo $EXTERNAL_STORAGE;'
- 'cat $c 2>/dev/null||echo;'
- 'echo "%s">$c &&' % token +
- 'getprop'
- )
- output = self.RunShellCommand(
- cmd, shell=True, check_return=True, large_output=True)
- # Error-checking for this existing is done in GetExternalStoragePath().
- self._cache['external_storage'] = output[0]
- self._cache['prev_token'] = output[1]
- output = output[2:]
-
- prop_cache = self._cache['getprop']
- prop_cache.clear()
- for key, value in _GETPROP_RE.findall(''.join(output)):
- prop_cache[key] = value
- self._cache['token'] = token
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def GetProp(self, property_name, cache=False, timeout=None, retries=None):
- """Gets a property from the device.
-
- Args:
- property_name: A string containing the name of the property to get from
- the device.
- cache: Whether to use cached properties when available.
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- The value of the device's |property_name| property.
-
- Raises:
- CommandTimeoutError on timeout.
- """
- assert isinstance(property_name, basestring), (
- "property_name is not a string: %r" % property_name)
-
- if cache:
- # It takes ~120ms to query a single property, and ~130ms to query all
- # properties. So, when caching we always query all properties.
- self._EnsureCacheInitialized()
- else:
- # timeout and retries are handled down at run shell, because we don't
- # want to apply them in the other branch when reading from the cache
- value = self.RunShellCommand(
- ['getprop', property_name], single_line=True, check_return=True,
- timeout=timeout, retries=retries)
- self._cache['getprop'][property_name] = value
- # Non-existent properties are treated as empty strings by getprop.
- return self._cache['getprop'].get(property_name, '')
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def SetProp(self, property_name, value, check=False, timeout=None,
- retries=None):
- """Sets a property on the device.
-
- Args:
- property_name: A string containing the name of the property to set on
- the device.
- value: A string containing the value to set to the property on the
- device.
- check: A boolean indicating whether to check that the property was
- successfully set on the device.
- timeout: timeout in seconds
- retries: number of retries
-
- Raises:
- CommandFailedError if check is true and the property was not correctly
- set on the device (e.g. because it is not rooted).
- CommandTimeoutError on timeout.
- """
- assert isinstance(property_name, basestring), (
- "property_name is not a string: %r" % property_name)
- assert isinstance(value, basestring), "value is not a string: %r" % value
-
- self.RunShellCommand(['setprop', property_name, value], check_return=True)
- prop_cache = self._cache['getprop']
- if property_name in prop_cache:
- del prop_cache[property_name]
- # TODO(perezju) remove the option and make the check mandatory, but using a
- # single shell script to both set- and getprop.
- if check and value != self.GetProp(property_name, cache=False):
- raise device_errors.CommandFailedError(
- 'Unable to set property %r on the device to %r'
- % (property_name, value), str(self))
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def GetABI(self, timeout=None, retries=None):
- """Gets the device main ABI.
-
- Args:
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- The device's main ABI name.
-
- Raises:
- CommandTimeoutError on timeout.
- """
- return self.GetProp('ro.product.cpu.abi', cache=True)
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def GetPids(self, process_name=None, timeout=None, retries=None):
- """Returns the PIDs of processes containing the given name as substring.
-
- Note that the |process_name| is often the package name.
-
- Args:
- process_name: A string containing the process name to get the PIDs for.
- If missing returns PIDs for all processes.
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- A dict mapping process name to a list of PIDs for each process that
- contained the provided |process_name|.
-
- Raises:
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- procs_pids = collections.defaultdict(list)
- try:
- ps_cmd = 'ps'
- # ps behavior was changed in Android above N, http://crbug.com/686716
- if (self.build_version_sdk >= version_codes.NOUGAT_MR1
- and self.build_id[0] > 'N'):
- ps_cmd = 'ps -e'
- if process_name:
- ps_output = self._RunPipedShellCommand(
- '%s | grep -F %s' % (ps_cmd, cmd_helper.SingleQuote(process_name)))
- else:
- ps_output = self.RunShellCommand(
- ps_cmd.split(), check_return=True, large_output=True)
- except device_errors.AdbShellCommandFailedError as e:
- if e.status and isinstance(e.status, list) and not e.status[0]:
- # If ps succeeded but grep failed, there were no processes with the
- # given name.
- return procs_pids
- else:
- raise
-
- process_name = process_name or ''
- for line in ps_output:
- try:
- ps_data = line.split()
- pid, process = ps_data[1], ps_data[-1]
- if process_name in process and pid != 'PID':
- procs_pids[process].append(pid)
- except IndexError:
- pass
- return procs_pids
-
- def GetApplicationPids(self, process_name, at_most_one=False, **kwargs):
- """Returns the PID or PIDs of a given process name.
-
- Note that the |process_name|, often the package name, must match exactly.
-
- Args:
- process_name: A string containing the process name to get the PIDs for.
- at_most_one: A boolean indicating that at most one PID is expected to
- be found.
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- A list of the PIDs for the named process. If at_most_one=True returns
- the single PID found or None otherwise.
-
- Raises:
- CommandFailedError if at_most_one=True and more than one PID is found
- for the named process.
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- pids = self.GetPids(process_name, **kwargs).get(process_name, [])
- if at_most_one:
- if len(pids) > 1:
- raise device_errors.CommandFailedError(
- 'Expected a single process but found PIDs: %s.' % ', '.join(pids),
- device_serial=str(self))
- return pids[0] if pids else None
- else:
- return pids
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def GetEnforce(self, timeout=None, retries=None):
- """Get the current mode of SELinux.
-
- Args:
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- True (enforcing), False (permissive), or None (disabled).
-
- Raises:
- CommandFailedError on failure.
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- output = self.RunShellCommand(
- ['getenforce'], check_return=True, single_line=True).lower()
- if output not in _SELINUX_MODE:
- raise device_errors.CommandFailedError(
- 'Unexpected getenforce output: %s' % output)
- return _SELINUX_MODE[output]
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def SetEnforce(self, enabled, timeout=None, retries=None):
- """Modify the mode SELinux is running in.
-
- Args:
- enabled: a boolean indicating whether to put SELinux in encorcing mode
- (if True), or permissive mode (otherwise).
- timeout: timeout in seconds
- retries: number of retries
-
- Raises:
- CommandFailedError on failure.
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- self.RunShellCommand(
- ['setenforce', '1' if int(enabled) else '0'], as_root=True,
- check_return=True)
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def TakeScreenshot(self, host_path=None, timeout=None, retries=None):
- """Takes a screenshot of the device.
-
- Args:
- host_path: A string containing the path on the host to save the
- screenshot to. If None, a file name in the current
- directory will be generated.
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- The name of the file on the host to which the screenshot was saved.
-
- Raises:
- CommandFailedError on failure.
- CommandTimeoutError on timeout.
- DeviceUnreachableError on missing device.
- """
- if not host_path:
- host_path = os.path.abspath('screenshot-%s-%s.png' % (
- self.serial, _GetTimeStamp()))
- with device_temp_file.DeviceTempFile(self.adb, suffix='.png') as device_tmp:
- self.RunShellCommand(['/system/bin/screencap', '-p', device_tmp.name],
- check_return=True)
- self.PullFile(device_tmp.name, host_path)
- return host_path
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def GetMemoryUsageForPid(self, pid, timeout=None, retries=None):
- """Gets the memory usage for the given PID.
-
- Args:
- pid: PID of the process.
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- A dict containing memory usage statistics for the PID. May include:
- Size, Rss, Pss, Shared_Clean, Shared_Dirty, Private_Clean,
- Private_Dirty, VmHWM
-
- Raises:
- CommandTimeoutError on timeout.
- """
- result = collections.defaultdict(int)
-
- try:
- result.update(self._GetMemoryUsageForPidFromSmaps(pid))
- except device_errors.CommandFailedError:
- logger.exception('Error getting memory usage from smaps')
-
- try:
- result.update(self._GetMemoryUsageForPidFromStatus(pid))
- except device_errors.CommandFailedError:
- logger.exception('Error getting memory usage from status')
-
- return result
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def DismissCrashDialogIfNeeded(self, timeout=None, retries=None):
- """Dismiss the error/ANR dialog if present.
-
- Returns: Name of the crashed package if a dialog is focused,
- None otherwise.
- """
- def _FindFocusedWindow():
- match = None
- # TODO(jbudorick): Try to grep the output on the device instead of using
- # large_output if/when DeviceUtils exposes a public interface for piped
- # shell command handling.
- for line in self.RunShellCommand(['dumpsys', 'window', 'windows'],
- check_return=True, large_output=True):
- match = re.match(_CURRENT_FOCUS_CRASH_RE, line)
- if match:
- break
- return match
-
- match = _FindFocusedWindow()
- if not match:
- return None
- package = match.group(2)
- logger.warning('Trying to dismiss %s dialog for %s', *match.groups())
- self.SendKeyEvent(keyevent.KEYCODE_DPAD_RIGHT)
- self.SendKeyEvent(keyevent.KEYCODE_DPAD_RIGHT)
- self.SendKeyEvent(keyevent.KEYCODE_ENTER)
- match = _FindFocusedWindow()
- if match:
- logger.error('Still showing a %s dialog for %s', *match.groups())
- return package
-
- def _GetMemoryUsageForPidFromSmaps(self, pid):
- SMAPS_COLUMNS = (
- 'Size', 'Rss', 'Pss', 'Shared_Clean', 'Shared_Dirty', 'Private_Clean',
- 'Private_Dirty')
-
- showmap_out = self._RunPipedShellCommand(
- 'showmap %d | grep TOTAL' % int(pid), as_root=True)
-
- split_totals = showmap_out[-1].split()
- if (not split_totals
- or len(split_totals) != 9
- or split_totals[-1] != 'TOTAL'):
- raise device_errors.CommandFailedError(
- 'Invalid output from showmap: %s' % '\n'.join(showmap_out))
-
- return dict(itertools.izip(SMAPS_COLUMNS, (int(n) for n in split_totals)))
-
- def _GetMemoryUsageForPidFromStatus(self, pid):
- for line in self.ReadFile(
- '/proc/%s/status' % str(pid), as_root=True).splitlines():
- if line.startswith('VmHWM:'):
- return {'VmHWM': int(line.split()[1])}
- raise device_errors.CommandFailedError(
- 'Could not find memory peak value for pid %s', str(pid))
-
- def GetLogcatMonitor(self, *args, **kwargs):
- """Returns a new LogcatMonitor associated with this device.
-
- Parameters passed to this function are passed directly to
- |logcat_monitor.LogcatMonitor| and are documented there.
- """
- return logcat_monitor.LogcatMonitor(self.adb, *args, **kwargs)
-
- def GetClientCache(self, client_name):
- """Returns client cache."""
- if client_name not in self._client_caches:
- self._client_caches[client_name] = {}
- return self._client_caches[client_name]
-
- def _ClearCache(self):
- """Clears all caches."""
- for client in self._client_caches:
- self._client_caches[client].clear()
- self._cache = {
- # Map of packageId -> list of on-device .apk paths
- 'package_apk_paths': {},
- # Set of packageId that were loaded from LoadCacheData and not yet
- # verified.
- 'package_apk_paths_to_verify': set(),
- # Map of packageId -> set of on-device .apk checksums
- 'package_apk_checksums': {},
- # Map of property_name -> value
- 'getprop': {},
- # Map of device_path -> [ignore_other_files, map of path->checksum]
- 'device_path_checksums': {},
- # Location of sdcard ($EXTERNAL_STORAGE).
- 'external_storage': None,
- # Token used to detect when LoadCacheData is stale.
- 'token': None,
- 'prev_token': None,
- }
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def LoadCacheData(self, data, timeout=None, retries=None):
- """Initializes the cache from data created using DumpCacheData.
-
- The cache is used only if its token matches the one found on the device.
- This prevents a stale cache from being used (which can happen when sharing
- devices).
-
- Args:
- data: A previously serialized cache (string).
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- Whether the cache was loaded.
- """
- obj = json.loads(data)
- self._EnsureCacheInitialized()
- given_token = obj.get('token')
- if not given_token or self._cache['prev_token'] != given_token:
- logger.warning('Stale cache detected. Not using it.')
- return False
-
- self._cache['package_apk_paths'] = obj.get('package_apk_paths', {})
- # When using a cache across script invokations, verify that apps have
- # not been uninstalled.
- self._cache['package_apk_paths_to_verify'] = set(
- self._cache['package_apk_paths'].iterkeys())
-
- package_apk_checksums = obj.get('package_apk_checksums', {})
- for k, v in package_apk_checksums.iteritems():
- package_apk_checksums[k] = set(v)
- self._cache['package_apk_checksums'] = package_apk_checksums
- device_path_checksums = obj.get('device_path_checksums', {})
- self._cache['device_path_checksums'] = device_path_checksums
- return True
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def DumpCacheData(self, timeout=None, retries=None):
- """Dumps the current cache state to a string.
-
- Args:
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- A serialized cache as a string.
- """
- self._EnsureCacheInitialized()
- obj = {}
- obj['token'] = self._cache['token']
- obj['package_apk_paths'] = self._cache['package_apk_paths']
- obj['package_apk_checksums'] = self._cache['package_apk_checksums']
- # JSON can't handle sets.
- for k, v in obj['package_apk_checksums'].iteritems():
- obj['package_apk_checksums'][k] = list(v)
- obj['device_path_checksums'] = self._cache['device_path_checksums']
- return json.dumps(obj, separators=(',', ':'))
-
- @classmethod
- def parallel(cls, devices, async=False):
- """Creates a Parallelizer to operate over the provided list of devices.
-
- Args:
- devices: A list of either DeviceUtils instances or objects from
- from which DeviceUtils instances can be constructed. If None,
- all attached devices will be used.
- async: If true, returns a Parallelizer that runs operations
- asynchronously.
-
- Returns:
- A Parallelizer operating over |devices|.
- """
- devices = [d if isinstance(d, cls) else cls(d) for d in devices]
- if async:
- return parallelizer.Parallelizer(devices)
- else:
- return parallelizer.SyncParallelizer(devices)
-
- @classmethod
- def HealthyDevices(cls, blacklist=None, device_arg='default', **kwargs):
- """Returns a list of DeviceUtils instances.
-
- Returns a list of DeviceUtils instances that are attached, not blacklisted,
- and optionally filtered by --device flags or ANDROID_SERIAL environment
- variable.
-
- Args:
- blacklist: A DeviceBlacklist instance (optional). Device serials in this
- blacklist will never be returned, but a warning will be logged if they
- otherwise would have been.
- device_arg: The value of the --device flag. This can be:
- 'default' -> Same as [], but returns an empty list rather than raise a
- NoDevicesError.
- [] -> Returns all devices, unless $ANDROID_SERIAL is set.
- None -> Use $ANDROID_SERIAL if set, otherwise looks for a single
- attached device. Raises an exception if multiple devices are
- attached.
- 'serial' -> Returns an instance for the given serial, if not
- blacklisted.
- ['A', 'B', ...] -> Returns instances for the subset that is not
- blacklisted.
- A device serial, or a list of device serials (optional).
-
- Returns:
- A list of DeviceUtils instances.
-
- Raises:
- NoDevicesError: Raised when no non-blacklisted devices exist and
- device_arg is passed.
- MultipleDevicesError: Raise when multiple devices exist, but |device_arg|
- is None.
- """
- allow_no_devices = False
- if device_arg == 'default':
- allow_no_devices = True
- device_arg = ()
-
- select_multiple = True
- if not (isinstance(device_arg, tuple) or isinstance(device_arg, list)):
- select_multiple = False
- if device_arg:
- device_arg = (device_arg,)
-
- blacklisted_devices = blacklist.Read() if blacklist else []
-
- # adb looks for ANDROID_SERIAL, so support it as well.
- android_serial = os.environ.get('ANDROID_SERIAL')
- if not device_arg and android_serial:
- device_arg = (android_serial,)
-
- def blacklisted(serial):
- if serial in blacklisted_devices:
- logger.warning('Device %s is blacklisted.', serial)
- return True
- return False
-
- if device_arg:
- devices = [cls(x, **kwargs) for x in device_arg if not blacklisted(x)]
- else:
- devices = []
- for adb in adb_wrapper.AdbWrapper.Devices():
- if not blacklisted(adb.GetDeviceSerial()):
- devices.append(cls(_CreateAdbWrapper(adb), **kwargs))
-
- if len(devices) == 0 and not allow_no_devices:
- raise device_errors.NoDevicesError()
- if len(devices) > 1 and not select_multiple:
- raise device_errors.MultipleDevicesError(devices)
- return sorted(devices)
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def RestartAdbd(self, timeout=None, retries=None):
- logger.info('Restarting adbd on device.')
- with device_temp_file.DeviceTempFile(self.adb, suffix='.sh') as script:
- self.WriteFile(script.name, _RESTART_ADBD_SCRIPT)
- self.RunShellCommand(
- ['source', script.name], check_return=True, as_root=True)
- self.adb.WaitForDevice()
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def GrantPermissions(self, package, permissions, timeout=None, retries=None):
- # Permissions only need to be set on M and above because of the changes to
- # the permission model.
- if not permissions or self.build_version_sdk < version_codes.MARSHMALLOW:
- return
- logger.info('Setting permissions for %s.', package)
- permissions = [p for p in permissions if p not in _PERMISSIONS_BLACKLIST]
- if ('android.permission.WRITE_EXTERNAL_STORAGE' in permissions
- and 'android.permission.READ_EXTERNAL_STORAGE' not in permissions):
- permissions.append('android.permission.READ_EXTERNAL_STORAGE')
- cmd = '&&'.join('pm grant %s %s' % (package, p) for p in permissions)
- if cmd:
- output = self.RunShellCommand(cmd, shell=True, check_return=True)
- if output:
- logger.warning('Possible problem when granting permissions. Blacklist '
- 'may need to be updated.')
- for line in output:
- logger.warning(' %s', line)
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def IsScreenOn(self, timeout=None, retries=None):
- """Determines if screen is on.
-
- Dumpsys input_method exposes screen on/off state. Below is an explination of
- the states.
-
- Pre-L:
- On: mScreenOn=true
- Off: mScreenOn=false
- L+:
- On: mInteractive=true
- Off: mInteractive=false
-
- Returns:
- True if screen is on, false if it is off.
-
- Raises:
- device_errors.CommandFailedError: If screen state cannot be found.
- """
- if self.build_version_sdk < version_codes.LOLLIPOP:
- input_check = 'mScreenOn'
- check_value = 'mScreenOn=true'
- else:
- input_check = 'mInteractive'
- check_value = 'mInteractive=true'
- dumpsys_out = self._RunPipedShellCommand(
- 'dumpsys input_method | grep %s' % input_check)
- if not dumpsys_out:
- raise device_errors.CommandFailedError(
- 'Unable to detect screen state', str(self))
- return check_value in dumpsys_out[0]
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def SetScreen(self, on, timeout=None, retries=None):
- """Turns screen on and off.
-
- Args:
- on: bool to decide state to switch to. True = on False = off.
- """
- def screen_test():
- return self.IsScreenOn() == on
-
- if screen_test():
- logger.info('Screen already in expected state.')
- return
- self.SendKeyEvent(keyevent.KEYCODE_POWER)
- timeout_retry.WaitFor(screen_test, wait_period=1)
diff --git a/third_party/catapult/devil/devil/android/device_utils_devicetest.py b/third_party/catapult/devil/devil/android/device_utils_devicetest.py
deleted file mode 100755
index e69cc90991..0000000000
--- a/third_party/catapult/devil/devil/android/device_utils_devicetest.py
+++ /dev/null
@@ -1,229 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""
-Unit tests for the contents of device_utils.py (mostly DeviceUtils).
-The test will invoke real devices
-"""
-
-import os
-import posixpath
-import sys
-import tempfile
-import unittest
-
-if __name__ == '__main__':
- sys.path.append(
- os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', )))
-
-from devil.android import device_test_case
-from devil.android import device_utils
-from devil.android.sdk import adb_wrapper
-from devil.utils import cmd_helper
-
-_OLD_CONTENTS = "foo"
-_NEW_CONTENTS = "bar"
-_DEVICE_DIR = "/data/local/tmp/device_utils_test"
-_SUB_DIR = "sub"
-_SUB_DIR1 = "sub1"
-_SUB_DIR2 = "sub2"
-
-
-class DeviceUtilsPushDeleteFilesTest(device_test_case.DeviceTestCase):
-
- def setUp(self):
- super(DeviceUtilsPushDeleteFilesTest, self).setUp()
- self.adb = adb_wrapper.AdbWrapper(self.serial)
- self.adb.WaitForDevice()
- self.device = device_utils.DeviceUtils(
- self.adb, default_timeout=10, default_retries=0)
-
- @staticmethod
- def _MakeTempFile(contents):
- """Make a temporary file with the given contents.
-
- Args:
- contents: string to write to the temporary file.
-
- Returns:
- the tuple contains the absolute path to the file and the file name
- """
- fi, path = tempfile.mkstemp(text=True)
- with os.fdopen(fi, 'w') as f:
- f.write(contents)
- file_name = os.path.basename(path)
- return (path, file_name)
-
- @staticmethod
- def _MakeTempFileGivenDir(directory, contents):
- """Make a temporary file under the given directory
- with the given contents
-
- Args:
- directory: the temp directory to create the file
- contents: string to write to the temp file
-
- Returns:
- the list contains the absolute path to the file and the file name
- """
- fi, path = tempfile.mkstemp(dir=directory, text=True)
- with os.fdopen(fi, 'w') as f:
- f.write(contents)
- file_name = os.path.basename(path)
- return (path, file_name)
-
- @staticmethod
- def _ChangeTempFile(path, contents):
- with os.open(path, 'w') as f:
- f.write(contents)
-
- @staticmethod
- def _DeleteTempFile(path):
- os.remove(path)
-
- def testPushChangedFiles_noFileChange(self):
- (host_file_path, file_name) = self._MakeTempFile(_OLD_CONTENTS)
- device_file_path = "%s/%s" % (_DEVICE_DIR, file_name)
- self.adb.Push(host_file_path, device_file_path)
- self.device.PushChangedFiles([(host_file_path, device_file_path)])
- result = self.device.RunShellCommand(
- ['cat', device_file_path], check_return=True, single_line=True)
- self.assertEqual(_OLD_CONTENTS, result)
-
- cmd_helper.RunCmd(['rm', host_file_path])
- self.device.RemovePath(_DEVICE_DIR, recursive=True, force=True)
-
- def testPushChangedFiles_singleFileChange(self):
- (host_file_path, file_name) = self._MakeTempFile(_OLD_CONTENTS)
- device_file_path = "%s/%s" % (_DEVICE_DIR, file_name)
- self.adb.Push(host_file_path, device_file_path)
-
- with open(host_file_path, 'w') as f:
- f.write(_NEW_CONTENTS)
- self.device.PushChangedFiles([(host_file_path, device_file_path)])
- result = self.device.RunShellCommand(
- ['cat', device_file_path], check_return=True, single_line=True)
- self.assertEqual(_NEW_CONTENTS, result)
-
- cmd_helper.RunCmd(['rm', host_file_path])
- self.device.RemovePath(_DEVICE_DIR, recursive=True, force=True)
-
- def testDeleteFiles(self):
- host_tmp_dir = tempfile.mkdtemp()
- (host_file_path, file_name) = self._MakeTempFileGivenDir(
- host_tmp_dir, _OLD_CONTENTS)
-
- device_file_path = "%s/%s" % (_DEVICE_DIR, file_name)
- self.adb.Push(host_file_path, device_file_path)
-
- cmd_helper.RunCmd(['rm', host_file_path])
- self.device.PushChangedFiles([(host_tmp_dir, _DEVICE_DIR)],
- delete_device_stale=True)
- filenames = self.device.ListDirectory(_DEVICE_DIR)
- self.assertEqual([], filenames)
-
- cmd_helper.RunCmd(['rm', '-rf', host_tmp_dir])
- self.device.RemovePath(_DEVICE_DIR, recursive=True, force=True)
-
- def testPushAndDeleteFiles_noSubDir(self):
- host_tmp_dir = tempfile.mkdtemp()
- (host_file_path1, file_name1) = self._MakeTempFileGivenDir(
- host_tmp_dir, _OLD_CONTENTS)
- (host_file_path2, file_name2) = self._MakeTempFileGivenDir(
- host_tmp_dir, _OLD_CONTENTS)
-
- device_file_path1 = "%s/%s" % (_DEVICE_DIR, file_name1)
- device_file_path2 = "%s/%s" % (_DEVICE_DIR, file_name2)
- self.adb.Push(host_file_path1, device_file_path1)
- self.adb.Push(host_file_path2, device_file_path2)
-
- with open(host_file_path1, 'w') as f:
- f.write(_NEW_CONTENTS)
- cmd_helper.RunCmd(['rm', host_file_path2])
-
- self.device.PushChangedFiles([(host_tmp_dir, _DEVICE_DIR)],
- delete_device_stale=True)
- result = self.device.RunShellCommand(
- ['cat', device_file_path1], check_return=True, single_line=True)
- self.assertEqual(_NEW_CONTENTS, result)
-
- filenames = self.device.ListDirectory(_DEVICE_DIR)
- self.assertEqual([file_name1], filenames)
-
- cmd_helper.RunCmd(['rm', '-rf', host_tmp_dir])
- self.device.RemovePath(_DEVICE_DIR, recursive=True, force=True)
-
- def testPushAndDeleteFiles_SubDir(self):
- host_tmp_dir = tempfile.mkdtemp()
- host_sub_dir1 = "%s/%s" % (host_tmp_dir, _SUB_DIR1)
- host_sub_dir2 = "%s/%s/%s" % (host_tmp_dir, _SUB_DIR, _SUB_DIR2)
- cmd_helper.RunCmd(['mkdir', '-p', host_sub_dir1])
- cmd_helper.RunCmd(['mkdir', '-p', host_sub_dir2])
-
- (host_file_path1, file_name1) = self._MakeTempFileGivenDir(
- host_tmp_dir, _OLD_CONTENTS)
- (host_file_path2, file_name2) = self._MakeTempFileGivenDir(
- host_tmp_dir, _OLD_CONTENTS)
- (host_file_path3, file_name3) = self._MakeTempFileGivenDir(
- host_sub_dir1, _OLD_CONTENTS)
- (host_file_path4, file_name4) = self._MakeTempFileGivenDir(
- host_sub_dir2, _OLD_CONTENTS)
-
- device_file_path1 = "%s/%s" % (_DEVICE_DIR, file_name1)
- device_file_path2 = "%s/%s" % (_DEVICE_DIR, file_name2)
- device_file_path3 = "%s/%s/%s" % (_DEVICE_DIR, _SUB_DIR1, file_name3)
- device_file_path4 = "%s/%s/%s/%s" % (_DEVICE_DIR, _SUB_DIR,
- _SUB_DIR2, file_name4)
-
- self.adb.Push(host_file_path1, device_file_path1)
- self.adb.Push(host_file_path2, device_file_path2)
- self.adb.Push(host_file_path3, device_file_path3)
- self.adb.Push(host_file_path4, device_file_path4)
-
- with open(host_file_path1, 'w') as f:
- f.write(_NEW_CONTENTS)
- cmd_helper.RunCmd(['rm', host_file_path2])
- cmd_helper.RunCmd(['rm', host_file_path4])
-
- self.device.PushChangedFiles([(host_tmp_dir, _DEVICE_DIR)],
- delete_device_stale=True)
- result = self.device.RunShellCommand(
- ['cat', device_file_path1], check_return=True, single_line=True)
- self.assertEqual(_NEW_CONTENTS, result)
-
- filenames = self.device.ListDirectory(_DEVICE_DIR)
- self.assertIn(file_name1, filenames)
- self.assertIn(_SUB_DIR1, filenames)
- self.assertIn(_SUB_DIR, filenames)
- self.assertEqual(3, len(filenames))
-
- result = self.device.RunShellCommand(
- ['cat', device_file_path3], check_return=True, single_line=True)
- self.assertEqual(_OLD_CONTENTS, result)
-
- filenames = self.device.ListDirectory(
- posixpath.join(_DEVICE_DIR, _SUB_DIR, _SUB_DIR2))
- self.assertEqual([], filenames)
-
- cmd_helper.RunCmd(['rm', '-rf', host_tmp_dir])
- self.device.RemovePath(_DEVICE_DIR, recursive=True, force=True)
-
- def testRestartAdbd(self):
- def get_adbd_pid():
- # TODO(catapult:#3215): Migrate to device.GetPids().
- ps_output = self.device.RunShellCommand(['ps'], check_return=True)
- for ps_line in ps_output:
- if 'adbd' in ps_line:
- return ps_line.split()[1]
- self.fail('Unable to find adbd')
-
- old_adbd_pid = get_adbd_pid()
- self.device.RestartAdbd()
- new_adbd_pid = get_adbd_pid()
- self.assertNotEqual(old_adbd_pid, new_adbd_pid)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/third_party/catapult/devil/devil/android/device_utils_test.py b/third_party/catapult/devil/devil/android/device_utils_test.py
deleted file mode 100755
index 2490209631..0000000000
--- a/third_party/catapult/devil/devil/android/device_utils_test.py
+++ /dev/null
@@ -1,2900 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""
-Unit tests for the contents of device_utils.py (mostly DeviceUtils).
-"""
-
-# pylint: disable=protected-access
-# pylint: disable=unused-argument
-
-import json
-import logging
-import os
-import stat
-import unittest
-
-from devil import devil_env
-from devil.android import device_errors
-from devil.android import device_signal
-from devil.android import device_utils
-from devil.android.sdk import adb_wrapper
-from devil.android.sdk import intent
-from devil.android.sdk import keyevent
-from devil.android.sdk import version_codes
-from devil.utils import cmd_helper
-from devil.utils import mock_calls
-
-with devil_env.SysPath(devil_env.PYMOCK_PATH):
- import mock # pylint: disable=import-error
-
-
-class AnyStringWith(object):
- def __init__(self, value):
- self._value = value
-
- def __eq__(self, other):
- return self._value in other
-
- def __repr__(self):
- return '<AnyStringWith: %s>' % self._value
-
-
-class _MockApkHelper(object):
-
- def __init__(self, path, package_name, perms=None):
- self.path = path
- self.package_name = package_name
- self.perms = perms
-
- def GetPackageName(self):
- return self.package_name
-
- def GetPermissions(self):
- return self.perms
-
-
-class _MockMultipleDevicesError(Exception):
- pass
-
-
-class DeviceUtilsInitTest(unittest.TestCase):
-
- def testInitWithStr(self):
- serial_as_str = str('0123456789abcdef')
- d = device_utils.DeviceUtils('0123456789abcdef')
- self.assertEqual(serial_as_str, d.adb.GetDeviceSerial())
-
- def testInitWithUnicode(self):
- serial_as_unicode = unicode('fedcba9876543210')
- d = device_utils.DeviceUtils(serial_as_unicode)
- self.assertEqual(serial_as_unicode, d.adb.GetDeviceSerial())
-
- def testInitWithAdbWrapper(self):
- serial = '123456789abcdef0'
- a = adb_wrapper.AdbWrapper(serial)
- d = device_utils.DeviceUtils(a)
- self.assertEqual(serial, d.adb.GetDeviceSerial())
-
- def testInitWithMissing_fails(self):
- with self.assertRaises(ValueError):
- device_utils.DeviceUtils(None)
- with self.assertRaises(ValueError):
- device_utils.DeviceUtils('')
-
-
-class DeviceUtilsGetAVDsTest(mock_calls.TestCase):
-
- def testGetAVDs(self):
- mocked_attrs = {
- 'android_sdk': '/my/sdk/path'
- }
- with mock.patch('devil.devil_env._Environment.LocalPath',
- mock.Mock(side_effect=lambda a: mocked_attrs[a])):
- with self.assertCall(
- mock.call.devil.utils.cmd_helper.GetCmdOutput(
- [mock.ANY, 'list', 'avd']),
- 'Available Android Virtual Devices:\n'
- ' Name: my_android5.0\n'
- ' Path: /some/path/to/.android/avd/my_android5.0.avd\n'
- ' Target: Android 5.0 (API level 21)\n'
- ' Tag/ABI: default/x86\n'
- ' Skin: WVGA800\n'):
- self.assertEquals(['my_android5.0'], device_utils.GetAVDs())
-
-
-class DeviceUtilsRestartServerTest(mock_calls.TestCase):
-
- @mock.patch('time.sleep', mock.Mock())
- def testRestartServer_succeeds(self):
- with self.assertCalls(
- mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.KillServer(),
- (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutput(
- ['pgrep', 'adb']),
- (1, '')),
- mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.StartServer(),
- (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutput(
- ['pgrep', 'adb']),
- (1, '')),
- (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutput(
- ['pgrep', 'adb']),
- (0, '123\n'))):
- device_utils.RestartServer()
-
-
-class MockTempFile(object):
-
- def __init__(self, name='/tmp/some/file'):
- self.file = mock.MagicMock(spec=file)
- self.file.name = name
- self.file.name_quoted = cmd_helper.SingleQuote(name)
-
- def __enter__(self):
- return self.file
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- pass
-
- @property
- def name(self):
- return self.file.name
-
-
-class _PatchedFunction(object):
-
- def __init__(self, patched=None, mocked=None):
- self.patched = patched
- self.mocked = mocked
-
-
-def _AdbWrapperMock(test_serial, is_ready=True):
- adb = mock.Mock(spec=adb_wrapper.AdbWrapper)
- adb.__str__ = mock.Mock(return_value=test_serial)
- adb.GetDeviceSerial.return_value = test_serial
- adb.is_ready = is_ready
- return adb
-
-
-class DeviceUtilsTest(mock_calls.TestCase):
-
- def setUp(self):
- self.adb = _AdbWrapperMock('0123456789abcdef')
- self.device = device_utils.DeviceUtils(
- self.adb, default_timeout=10, default_retries=0)
- self.watchMethodCalls(self.call.adb, ignore=['GetDeviceSerial'])
-
- def AdbCommandError(self, args=None, output=None, status=None, msg=None):
- if args is None:
- args = ['[unspecified]']
- return mock.Mock(side_effect=device_errors.AdbCommandFailedError(
- args, output, status, msg, str(self.device)))
-
- def CommandError(self, msg=None):
- if msg is None:
- msg = 'Command failed'
- return mock.Mock(side_effect=device_errors.CommandFailedError(
- msg, str(self.device)))
-
- def ShellError(self, output=None, status=1):
- def action(cmd, *args, **kwargs):
- raise device_errors.AdbShellCommandFailedError(
- cmd, output, status, str(self.device))
- if output is None:
- output = 'Permission denied\n'
- return action
-
- def TimeoutError(self, msg=None):
- if msg is None:
- msg = 'Operation timed out'
- return mock.Mock(side_effect=device_errors.CommandTimeoutError(
- msg, str(self.device)))
-
- def EnsureCacheInitialized(self, props=None, sdcard='/sdcard'):
- props = props or []
- ret = [sdcard, 'TOKEN'] + props
- return (self.call.device.RunShellCommand(
- AnyStringWith('getprop'),
- shell=True, check_return=True, large_output=True), ret)
-
-
-class DeviceUtilsEqTest(DeviceUtilsTest):
-
- def testEq_equal_deviceUtils(self):
- other = device_utils.DeviceUtils(_AdbWrapperMock('0123456789abcdef'))
- self.assertTrue(self.device == other)
- self.assertTrue(other == self.device)
-
- def testEq_equal_adbWrapper(self):
- other = adb_wrapper.AdbWrapper('0123456789abcdef')
- self.assertTrue(self.device == other)
- self.assertTrue(other == self.device)
-
- def testEq_equal_string(self):
- other = '0123456789abcdef'
- self.assertTrue(self.device == other)
- self.assertTrue(other == self.device)
-
- def testEq_devicesNotEqual(self):
- other = device_utils.DeviceUtils(_AdbWrapperMock('0123456789abcdee'))
- self.assertFalse(self.device == other)
- self.assertFalse(other == self.device)
-
- def testEq_identity(self):
- self.assertTrue(self.device == self.device)
-
- def testEq_serialInList(self):
- devices = [self.device]
- self.assertTrue('0123456789abcdef' in devices)
-
-
-class DeviceUtilsLtTest(DeviceUtilsTest):
-
- def testLt_lessThan(self):
- other = device_utils.DeviceUtils(_AdbWrapperMock('ffffffffffffffff'))
- self.assertTrue(self.device < other)
- self.assertTrue(other > self.device)
-
- def testLt_greaterThan_lhs(self):
- other = device_utils.DeviceUtils(_AdbWrapperMock('0000000000000000'))
- self.assertFalse(self.device < other)
- self.assertFalse(other > self.device)
-
- def testLt_equal(self):
- other = device_utils.DeviceUtils(_AdbWrapperMock('0123456789abcdef'))
- self.assertFalse(self.device < other)
- self.assertFalse(other > self.device)
-
- def testLt_sorted(self):
- devices = [
- device_utils.DeviceUtils(_AdbWrapperMock('ffffffffffffffff')),
- device_utils.DeviceUtils(_AdbWrapperMock('0000000000000000')),
- ]
- sorted_devices = sorted(devices)
- self.assertEquals('0000000000000000',
- sorted_devices[0].adb.GetDeviceSerial())
- self.assertEquals('ffffffffffffffff',
- sorted_devices[1].adb.GetDeviceSerial())
-
-
-class DeviceUtilsStrTest(DeviceUtilsTest):
-
- def testStr_returnsSerial(self):
- with self.assertCalls(
- (self.call.adb.GetDeviceSerial(), '0123456789abcdef')):
- self.assertEqual('0123456789abcdef', str(self.device))
-
-
-class DeviceUtilsIsOnlineTest(DeviceUtilsTest):
-
- def testIsOnline_true(self):
- with self.assertCall(self.call.adb.GetState(), 'device'):
- self.assertTrue(self.device.IsOnline())
-
- def testIsOnline_false(self):
- with self.assertCall(self.call.adb.GetState(), 'offline'):
- self.assertFalse(self.device.IsOnline())
-
- def testIsOnline_error(self):
- with self.assertCall(self.call.adb.GetState(), self.CommandError()):
- self.assertFalse(self.device.IsOnline())
-
-
-class DeviceUtilsHasRootTest(DeviceUtilsTest):
-
- def testHasRoot_true(self):
- with self.patch_call(self.call.device.product_name,
- return_value='notasailfish'), (
- self.assertCall(self.call.adb.Shell('ls /root'), 'foo\n')):
- self.assertTrue(self.device.HasRoot())
-
- def testhasRootSpecial_true(self):
- with self.patch_call(self.call.device.product_name,
- return_value='sailfish'), (
- self.assertCall(self.call.adb.Shell('getprop service.adb.root'),
- '1\n')):
- self.assertTrue(self.device.HasRoot())
-
- def testHasRoot_false(self):
- with self.patch_call(self.call.device.product_name,
- return_value='notasailfish'), (
- self.assertCall(self.call.adb.Shell('ls /root'),
- self.ShellError())):
- self.assertFalse(self.device.HasRoot())
-
- def testHasRootSpecial_false(self):
- with self.patch_call(self.call.device.product_name,
- return_value='sailfish'), (
- self.assertCall(self.call.adb.Shell('getprop service.adb.root'),
- '\n')):
- self.assertFalse(self.device.HasRoot())
-
-
-class DeviceUtilsEnableRootTest(DeviceUtilsTest):
-
- def testEnableRoot_succeeds(self):
- with self.assertCalls(
- (self.call.device.IsUserBuild(), False),
- self.call.adb.Root(),
- self.call.device.WaitUntilFullyBooted()):
- self.device.EnableRoot()
-
- def testEnableRoot_userBuild(self):
- with self.assertCalls(
- (self.call.device.IsUserBuild(), True)):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device.EnableRoot()
-
- def testEnableRoot_rootFails(self):
- with self.assertCalls(
- (self.call.device.IsUserBuild(), False),
- (self.call.adb.Root(), self.CommandError())):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device.EnableRoot()
-
-
-class DeviceUtilsIsUserBuildTest(DeviceUtilsTest):
-
- def testIsUserBuild_yes(self):
- with self.assertCall(
- self.call.device.GetProp('ro.build.type', cache=True), 'user'):
- self.assertTrue(self.device.IsUserBuild())
-
- def testIsUserBuild_no(self):
- with self.assertCall(
- self.call.device.GetProp('ro.build.type', cache=True), 'userdebug'):
- self.assertFalse(self.device.IsUserBuild())
-
-
-class DeviceUtilsGetExternalStoragePathTest(DeviceUtilsTest):
-
- def testGetExternalStoragePath_succeeds(self):
- with self.assertCalls(
- self.EnsureCacheInitialized(sdcard='/fake/storage/path')):
- self.assertEquals('/fake/storage/path',
- self.device.GetExternalStoragePath())
-
- def testGetExternalStoragePath_fails(self):
- with self.assertCalls(
- self.EnsureCacheInitialized(sdcard='')):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device.GetExternalStoragePath()
-
-
-class DeviceUtilsGetApplicationPathsInternalTest(DeviceUtilsTest):
-
- def testGetApplicationPathsInternal_exists(self):
- with self.assertCalls(
- (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'),
- (self.call.device.RunShellCommand(
- ['pm', 'path', 'android'], check_return=True),
- ['package:/path/to/android.apk'])):
- self.assertEquals(['/path/to/android.apk'],
- self.device._GetApplicationPathsInternal('android'))
-
- def testGetApplicationPathsInternal_notExists(self):
- with self.assertCalls(
- (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'),
- (self.call.device.RunShellCommand(
- ['pm', 'path', 'not.installed.app'], check_return=True),
- '')):
- self.assertEquals([],
- self.device._GetApplicationPathsInternal('not.installed.app'))
-
- def testGetApplicationPathsInternal_garbageFirstLine(self):
- with self.assertCalls(
- (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'),
- (self.call.device.RunShellCommand(
- ['pm', 'path', 'android'], check_return=True),
- ['garbage first line'])):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device._GetApplicationPathsInternal('android')
-
- def testGetApplicationPathsInternal_fails(self):
- with self.assertCalls(
- (self.call.device.GetProp('ro.build.version.sdk', cache=True), '19'),
- (self.call.device.RunShellCommand(
- ['pm', 'path', 'android'], check_return=True),
- self.CommandError('ERROR. Is package manager running?\n'))):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device._GetApplicationPathsInternal('android')
-
-
-class DeviceUtils_GetApplicationVersionTest(DeviceUtilsTest):
-
- def test_GetApplicationVersion_exists(self):
- with self.assertCalls(
- (self.call.adb.Shell('dumpsys package com.android.chrome'),
- 'Packages:\n'
- ' Package [com.android.chrome] (3901ecfb):\n'
- ' userId=1234 gids=[123, 456, 789]\n'
- ' pkg=Package{1fecf634 com.android.chrome}\n'
- ' versionName=45.0.1234.7\n')):
- self.assertEquals('45.0.1234.7',
- self.device.GetApplicationVersion('com.android.chrome'))
-
- def test_GetApplicationVersion_notExists(self):
- with self.assertCalls(
- (self.call.adb.Shell('dumpsys package com.android.chrome'), '')):
- self.assertEquals(None,
- self.device.GetApplicationVersion('com.android.chrome'))
-
- def test_GetApplicationVersion_fails(self):
- with self.assertCalls(
- (self.call.adb.Shell('dumpsys package com.android.chrome'),
- 'Packages:\n'
- ' Package [com.android.chrome] (3901ecfb):\n'
- ' userId=1234 gids=[123, 456, 789]\n'
- ' pkg=Package{1fecf634 com.android.chrome}\n')):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device.GetApplicationVersion('com.android.chrome')
-
-
-class DeviceUtilsGetApplicationDataDirectoryTest(DeviceUtilsTest):
-
- def testGetApplicationDataDirectory_exists(self):
- with self.assertCall(
- self.call.device._RunPipedShellCommand(
- 'pm dump foo.bar.baz | grep dataDir='),
- ['dataDir=/data/data/foo.bar.baz']):
- self.assertEquals(
- '/data/data/foo.bar.baz',
- self.device.GetApplicationDataDirectory('foo.bar.baz'))
-
- def testGetApplicationDataDirectory_notExists(self):
- with self.assertCall(
- self.call.device._RunPipedShellCommand(
- 'pm dump foo.bar.baz | grep dataDir='),
- self.ShellError()):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device.GetApplicationDataDirectory('foo.bar.baz')
-
-
-@mock.patch('time.sleep', mock.Mock())
-class DeviceUtilsWaitUntilFullyBootedTest(DeviceUtilsTest):
-
- def testWaitUntilFullyBooted_succeedsNoWifi(self):
- with self.assertCalls(
- self.call.adb.WaitForDevice(),
- # sd_card_ready
- (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
- (self.call.adb.Shell('test -d /fake/storage/path'), ''),
- # pm_ready
- (self.call.device._GetApplicationPathsInternal('android',
- skip_cache=True),
- ['package:/some/fake/path']),
- # boot_completed
- (self.call.device.GetProp('sys.boot_completed', cache=False), '1')):
- self.device.WaitUntilFullyBooted(wifi=False)
-
- def testWaitUntilFullyBooted_succeedsWithWifi(self):
- with self.assertCalls(
- self.call.adb.WaitForDevice(),
- # sd_card_ready
- (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
- (self.call.adb.Shell('test -d /fake/storage/path'), ''),
- # pm_ready
- (self.call.device._GetApplicationPathsInternal('android',
- skip_cache=True),
- ['package:/some/fake/path']),
- # boot_completed
- (self.call.device.GetProp('sys.boot_completed', cache=False), '1'),
- # wifi_enabled
- (self.call.adb.Shell('dumpsys wifi'),
- 'stuff\nWi-Fi is enabled\nmore stuff\n')):
- self.device.WaitUntilFullyBooted(wifi=True)
-
- def testWaitUntilFullyBooted_deviceNotInitiallyAvailable(self):
- with self.assertCalls(
- self.call.adb.WaitForDevice(),
- # sd_card_ready
- (self.call.device.GetExternalStoragePath(), self.AdbCommandError()),
- # sd_card_ready
- (self.call.device.GetExternalStoragePath(), self.AdbCommandError()),
- # sd_card_ready
- (self.call.device.GetExternalStoragePath(), self.AdbCommandError()),
- # sd_card_ready
- (self.call.device.GetExternalStoragePath(), self.AdbCommandError()),
- # sd_card_ready
- (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
- (self.call.adb.Shell('test -d /fake/storage/path'), ''),
- # pm_ready
- (self.call.device._GetApplicationPathsInternal('android',
- skip_cache=True),
- ['package:/some/fake/path']),
- # boot_completed
- (self.call.device.GetProp('sys.boot_completed', cache=False), '1')):
- self.device.WaitUntilFullyBooted(wifi=False)
-
- def testWaitUntilFullyBooted_deviceBrieflyOffline(self):
- with self.assertCalls(
- self.call.adb.WaitForDevice(),
- # sd_card_ready
- (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
- (self.call.adb.Shell('test -d /fake/storage/path'), ''),
- # pm_ready
- (self.call.device._GetApplicationPathsInternal('android',
- skip_cache=True),
- ['package:/some/fake/path']),
- # boot_completed
- (self.call.device.GetProp('sys.boot_completed', cache=False),
- self.AdbCommandError()),
- # boot_completed
- (self.call.device.GetProp('sys.boot_completed', cache=False), '1')):
- self.device.WaitUntilFullyBooted(wifi=False)
-
- def testWaitUntilFullyBooted_sdCardReadyFails_noPath(self):
- with self.assertCalls(
- self.call.adb.WaitForDevice(),
- # sd_card_ready
- (self.call.device.GetExternalStoragePath(), self.CommandError())):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device.WaitUntilFullyBooted(wifi=False)
-
- def testWaitUntilFullyBooted_sdCardReadyFails_notExists(self):
- with self.assertCalls(
- self.call.adb.WaitForDevice(),
- # sd_card_ready
- (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
- (self.call.adb.Shell('test -d /fake/storage/path'), self.ShellError()),
- # sd_card_ready
- (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
- (self.call.adb.Shell('test -d /fake/storage/path'), self.ShellError()),
- # sd_card_ready
- (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
- (self.call.adb.Shell('test -d /fake/storage/path'),
- self.TimeoutError())):
- with self.assertRaises(device_errors.CommandTimeoutError):
- self.device.WaitUntilFullyBooted(wifi=False)
-
- def testWaitUntilFullyBooted_devicePmFails(self):
- with self.assertCalls(
- self.call.adb.WaitForDevice(),
- # sd_card_ready
- (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
- (self.call.adb.Shell('test -d /fake/storage/path'), ''),
- # pm_ready
- (self.call.device._GetApplicationPathsInternal('android',
- skip_cache=True),
- self.CommandError()),
- # pm_ready
- (self.call.device._GetApplicationPathsInternal('android',
- skip_cache=True),
- self.CommandError()),
- # pm_ready
- (self.call.device._GetApplicationPathsInternal('android',
- skip_cache=True),
- self.TimeoutError())):
- with self.assertRaises(device_errors.CommandTimeoutError):
- self.device.WaitUntilFullyBooted(wifi=False)
-
- def testWaitUntilFullyBooted_bootFails(self):
- with self.assertCalls(
- self.call.adb.WaitForDevice(),
- # sd_card_ready
- (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
- (self.call.adb.Shell('test -d /fake/storage/path'), ''),
- # pm_ready
- (self.call.device._GetApplicationPathsInternal('android',
- skip_cache=True),
- ['package:/some/fake/path']),
- # boot_completed
- (self.call.device.GetProp('sys.boot_completed', cache=False), '0'),
- # boot_completed
- (self.call.device.GetProp('sys.boot_completed', cache=False), '0'),
- # boot_completed
- (self.call.device.GetProp('sys.boot_completed', cache=False),
- self.TimeoutError())):
- with self.assertRaises(device_errors.CommandTimeoutError):
- self.device.WaitUntilFullyBooted(wifi=False)
-
- def testWaitUntilFullyBooted_wifiFails(self):
- with self.assertCalls(
- self.call.adb.WaitForDevice(),
- # sd_card_ready
- (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
- (self.call.adb.Shell('test -d /fake/storage/path'), ''),
- # pm_ready
- (self.call.device._GetApplicationPathsInternal('android',
- skip_cache=True),
- ['package:/some/fake/path']),
- # boot_completed
- (self.call.device.GetProp('sys.boot_completed', cache=False), '1'),
- # wifi_enabled
- (self.call.adb.Shell('dumpsys wifi'), 'stuff\nmore stuff\n'),
- # wifi_enabled
- (self.call.adb.Shell('dumpsys wifi'), 'stuff\nmore stuff\n'),
- # wifi_enabled
- (self.call.adb.Shell('dumpsys wifi'), self.TimeoutError())):
- with self.assertRaises(device_errors.CommandTimeoutError):
- self.device.WaitUntilFullyBooted(wifi=True)
-
-
-@mock.patch('time.sleep', mock.Mock())
-class DeviceUtilsRebootTest(DeviceUtilsTest):
-
- def testReboot_nonBlocking(self):
- with self.assertCalls(
- self.call.adb.Reboot(),
- (self.call.device.IsOnline(), True),
- (self.call.device.IsOnline(), False)):
- self.device.Reboot(block=False)
-
- def testReboot_blocking(self):
- with self.assertCalls(
- self.call.adb.Reboot(),
- (self.call.device.IsOnline(), True),
- (self.call.device.IsOnline(), False),
- self.call.device.WaitUntilFullyBooted(wifi=False)):
- self.device.Reboot(block=True)
-
- def testReboot_blockUntilWifi(self):
- with self.assertCalls(
- self.call.adb.Reboot(),
- (self.call.device.IsOnline(), True),
- (self.call.device.IsOnline(), False),
- self.call.device.WaitUntilFullyBooted(wifi=True)):
- self.device.Reboot(block=True, wifi=True)
-
-
-class DeviceUtilsInstallTest(DeviceUtilsTest):
-
- mock_apk = _MockApkHelper('/fake/test/app.apk', 'test.package', ['p1'])
-
- def testInstall_noPriorInstall(self):
- with self.patch_call(self.call.device.build_version_sdk, return_value=23):
- with self.assertCalls(
- (mock.call.os.path.exists('/fake/test/app.apk'), True),
- (self.call.device._GetApplicationPathsInternal('test.package'), []),
- self.call.adb.Install('/fake/test/app.apk', reinstall=False,
- allow_downgrade=False),
- (self.call.device.GrantPermissions('test.package', ['p1']), [])):
- self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
-
- def testInstall_permissionsPreM(self):
- with self.patch_call(self.call.device.build_version_sdk, return_value=20):
- with self.assertCalls(
- (mock.call.os.path.exists('/fake/test/app.apk'), True),
- (self.call.device._GetApplicationPathsInternal('test.package'), []),
- (self.call.adb.Install('/fake/test/app.apk', reinstall=False,
- allow_downgrade=False))):
- self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
-
- def testInstall_findPermissions(self):
- with self.patch_call(self.call.device.build_version_sdk, return_value=23):
- with self.assertCalls(
- (mock.call.os.path.exists('/fake/test/app.apk'), True),
- (self.call.device._GetApplicationPathsInternal('test.package'), []),
- (self.call.adb.Install('/fake/test/app.apk', reinstall=False,
- allow_downgrade=False)),
- (self.call.device.GrantPermissions('test.package', ['p1']), [])):
- self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
-
- def testInstall_passPermissions(self):
- with self.assertCalls(
- (mock.call.os.path.exists('/fake/test/app.apk'), True),
- (self.call.device._GetApplicationPathsInternal('test.package'), []),
- (self.call.adb.Install('/fake/test/app.apk', reinstall=False,
- allow_downgrade=False)),
- (self.call.device.GrantPermissions('test.package', ['p1', 'p2']), [])):
- self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0,
- permissions=['p1', 'p2'])
-
- def testInstall_differentPriorInstall(self):
- with self.assertCalls(
- (mock.call.os.path.exists('/fake/test/app.apk'), True),
- (self.call.device._GetApplicationPathsInternal('test.package'),
- ['/fake/data/app/test.package.apk']),
- (self.call.device._ComputeStaleApks('test.package',
- ['/fake/test/app.apk']),
- (['/fake/test/app.apk'], None)),
- self.call.device.Uninstall('test.package'),
- self.call.adb.Install('/fake/test/app.apk', reinstall=False,
- allow_downgrade=False)):
- self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0,
- permissions=[])
-
- def testInstall_differentPriorInstall_reinstall(self):
- with self.assertCalls(
- (mock.call.os.path.exists('/fake/test/app.apk'), True),
- (self.call.device._GetApplicationPathsInternal('test.package'),
- ['/fake/data/app/test.package.apk']),
- (self.call.device._ComputeStaleApks('test.package',
- ['/fake/test/app.apk']),
- (['/fake/test/app.apk'], None)),
- self.call.adb.Install('/fake/test/app.apk', reinstall=True,
- allow_downgrade=False)):
- self.device.Install(DeviceUtilsInstallTest.mock_apk,
- reinstall=True, retries=0, permissions=[])
-
- def testInstall_identicalPriorInstall_reinstall(self):
- with self.assertCalls(
- (mock.call.os.path.exists('/fake/test/app.apk'), True),
- (self.call.device._GetApplicationPathsInternal('test.package'),
- ['/fake/data/app/test.package.apk']),
- (self.call.device._ComputeStaleApks('test.package',
- ['/fake/test/app.apk']),
- ([], None)),
- (self.call.device.ForceStop('test.package'))):
- self.device.Install(DeviceUtilsInstallTest.mock_apk,
- reinstall=True, retries=0, permissions=[])
-
- def testInstall_missingApk(self):
- with self.assertCalls(
- (mock.call.os.path.exists('/fake/test/app.apk'), False)):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
-
- def testInstall_fails(self):
- with self.assertCalls(
- (mock.call.os.path.exists('/fake/test/app.apk'), True),
- (self.call.device._GetApplicationPathsInternal('test.package'), []),
- (self.call.adb.Install('/fake/test/app.apk', reinstall=False,
- allow_downgrade=False),
- self.CommandError('Failure\r\n'))):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device.Install(DeviceUtilsInstallTest.mock_apk, retries=0)
-
- def testInstall_downgrade(self):
- with self.assertCalls(
- (mock.call.os.path.exists('/fake/test/app.apk'), True),
- (self.call.device._GetApplicationPathsInternal('test.package'),
- ['/fake/data/app/test.package.apk']),
- (self.call.device._ComputeStaleApks('test.package',
- ['/fake/test/app.apk']),
- (['/fake/test/app.apk'], None)),
- self.call.adb.Install('/fake/test/app.apk', reinstall=True,
- allow_downgrade=True)):
- self.device.Install(DeviceUtilsInstallTest.mock_apk,
- reinstall=True, retries=0, permissions=[], allow_downgrade=True)
-
-
-class DeviceUtilsInstallSplitApkTest(DeviceUtilsTest):
-
- mock_apk = _MockApkHelper('base.apk', 'test.package', ['p1'])
-
- def testInstallSplitApk_noPriorInstall(self):
- with self.assertCalls(
- (self.call.device._CheckSdkLevel(21)),
- (mock.call.devil.android.sdk.split_select.SelectSplits(
- self.device, 'base.apk',
- ['split1.apk', 'split2.apk', 'split3.apk'],
- allow_cached_props=False),
- ['split2.apk']),
- (mock.call.os.path.exists('base.apk'), True),
- (mock.call.os.path.exists('split2.apk'), True),
- (self.call.device._GetApplicationPathsInternal('test.package'), []),
- (self.call.adb.InstallMultiple(
- ['base.apk', 'split2.apk'], partial=None, reinstall=False,
- allow_downgrade=False))):
- self.device.InstallSplitApk(DeviceUtilsInstallSplitApkTest.mock_apk,
- ['split1.apk', 'split2.apk', 'split3.apk'], permissions=[], retries=0)
-
- def testInstallSplitApk_partialInstall(self):
- with self.assertCalls(
- (self.call.device._CheckSdkLevel(21)),
- (mock.call.devil.android.sdk.split_select.SelectSplits(
- self.device, 'base.apk',
- ['split1.apk', 'split2.apk', 'split3.apk'],
- allow_cached_props=False),
- ['split2.apk']),
- (mock.call.os.path.exists('base.apk'), True),
- (mock.call.os.path.exists('split2.apk'), True),
- (self.call.device._GetApplicationPathsInternal('test.package'),
- ['base-on-device.apk', 'split2-on-device.apk']),
- (self.call.device._ComputeStaleApks('test.package',
- ['base.apk', 'split2.apk']),
- (['split2.apk'], None)),
- (self.call.adb.InstallMultiple(
- ['split2.apk'], partial='test.package', reinstall=True,
- allow_downgrade=False))):
- self.device.InstallSplitApk(DeviceUtilsInstallSplitApkTest.mock_apk,
- ['split1.apk', 'split2.apk', 'split3.apk'],
- reinstall=True, permissions=[], retries=0)
-
- def testInstallSplitApk_downgrade(self):
- with self.assertCalls(
- (self.call.device._CheckSdkLevel(21)),
- (mock.call.devil.android.sdk.split_select.SelectSplits(
- self.device, 'base.apk',
- ['split1.apk', 'split2.apk', 'split3.apk'],
- allow_cached_props=False),
- ['split2.apk']),
- (mock.call.os.path.exists('base.apk'), True),
- (mock.call.os.path.exists('split2.apk'), True),
- (self.call.device._GetApplicationPathsInternal('test.package'),
- ['base-on-device.apk', 'split2-on-device.apk']),
- (self.call.device._ComputeStaleApks('test.package',
- ['base.apk', 'split2.apk']),
- (['split2.apk'], None)),
- (self.call.adb.InstallMultiple(
- ['split2.apk'], partial='test.package', reinstall=True,
- allow_downgrade=True))):
- self.device.InstallSplitApk(DeviceUtilsInstallSplitApkTest.mock_apk,
- ['split1.apk', 'split2.apk', 'split3.apk'],
- reinstall=True, permissions=[], retries=0,
- allow_downgrade=True)
-
- def testInstallSplitApk_missingSplit(self):
- with self.assertCalls(
- (self.call.device._CheckSdkLevel(21)),
- (mock.call.devil.android.sdk.split_select.SelectSplits(
- self.device, 'base.apk',
- ['split1.apk', 'split2.apk', 'split3.apk'],
- allow_cached_props=False),
- ['split2.apk']),
- (mock.call.os.path.exists('base.apk'), True),
- (mock.call.os.path.exists('split2.apk'), False)):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device.InstallSplitApk(DeviceUtilsInstallSplitApkTest.mock_apk,
- ['split1.apk', 'split2.apk', 'split3.apk'], permissions=[],
- retries=0)
-
-
-class DeviceUtilsUninstallTest(DeviceUtilsTest):
-
- def testUninstall_callsThrough(self):
- with self.assertCalls(
- (self.call.device._GetApplicationPathsInternal('test.package'),
- ['/path.apk']),
- self.call.adb.Uninstall('test.package', True)):
- self.device.Uninstall('test.package', True)
-
- def testUninstall_noop(self):
- with self.assertCalls(
- (self.call.device._GetApplicationPathsInternal('test.package'), [])):
- self.device.Uninstall('test.package', True)
-
-
-class DeviceUtilsSuTest(DeviceUtilsTest):
-
- def testSu_preM(self):
- with self.patch_call(
- self.call.device.build_version_sdk,
- return_value=version_codes.LOLLIPOP_MR1):
- self.assertEquals('su -c foo', self.device._Su('foo'))
-
- def testSu_mAndAbove(self):
- with self.patch_call(
- self.call.device.build_version_sdk,
- return_value=version_codes.MARSHMALLOW):
- self.assertEquals('su 0 foo', self.device._Su('foo'))
-
-
-class DeviceUtilsRunShellCommandTest(DeviceUtilsTest):
-
- def setUp(self):
- super(DeviceUtilsRunShellCommandTest, self).setUp()
- self.device.NeedsSU = mock.Mock(return_value=False)
-
- def testRunShellCommand_commandAsList(self):
- with self.assertCall(self.call.adb.Shell('pm list packages'), ''):
- self.device.RunShellCommand(
- ['pm', 'list', 'packages'], check_return=True)
-
- def testRunShellCommand_commandAsListQuoted(self):
- with self.assertCall(self.call.adb.Shell("echo 'hello world' '$10'"), ''):
- self.device.RunShellCommand(
- ['echo', 'hello world', '$10'], check_return=True)
-
- def testRunShellCommand_commandAsString(self):
- with self.assertCall(self.call.adb.Shell('echo "$VAR"'), ''):
- self.device.RunShellCommand(
- 'echo "$VAR"', shell=True, check_return=True)
-
- def testNewRunShellImpl_withEnv(self):
- with self.assertCall(
- self.call.adb.Shell('VAR=some_string echo "$VAR"'), ''):
- self.device.RunShellCommand(
- 'echo "$VAR"', shell=True, check_return=True,
- env={'VAR': 'some_string'})
-
- def testNewRunShellImpl_withEnvQuoted(self):
- with self.assertCall(
- self.call.adb.Shell('PATH="$PATH:/other/path" run_this'), ''):
- self.device.RunShellCommand(
- ['run_this'], check_return=True, env={'PATH': '$PATH:/other/path'})
-
- def testNewRunShellImpl_withEnv_failure(self):
- with self.assertRaises(KeyError):
- self.device.RunShellCommand(
- ['some_cmd'], check_return=True, env={'INVALID NAME': 'value'})
-
- def testNewRunShellImpl_withCwd(self):
- with self.assertCall(self.call.adb.Shell('cd /some/test/path && ls'), ''):
- self.device.RunShellCommand(
- ['ls'], check_return=True, cwd='/some/test/path')
-
- def testNewRunShellImpl_withCwdQuoted(self):
- with self.assertCall(
- self.call.adb.Shell("cd '/some test/path with/spaces' && ls"), ''):
- self.device.RunShellCommand(
- ['ls'], check_return=True, cwd='/some test/path with/spaces')
-
- def testRunShellCommand_withHugeCmd(self):
- payload = 'hi! ' * 1024
- expected_cmd = "echo '%s'" % payload
- with self.assertCalls(
- (mock.call.devil.android.device_temp_file.DeviceTempFile(
- self.adb, suffix='.sh'), MockTempFile('/sdcard/temp-123.sh')),
- self.call.device._WriteFileWithPush('/sdcard/temp-123.sh', expected_cmd),
- (self.call.adb.Shell('sh /sdcard/temp-123.sh'), payload + '\n')):
- self.assertEquals(
- [payload],
- self.device.RunShellCommand(['echo', payload], check_return=True))
-
- def testRunShellCommand_withHugeCmdAndSu(self):
- payload = 'hi! ' * 1024
- expected_cmd_without_su = """sh -c 'echo '"'"'%s'"'"''""" % payload
- expected_cmd = 'su -c %s' % expected_cmd_without_su
- with self.assertCalls(
- (self.call.device.NeedsSU(), True),
- (self.call.device._Su(expected_cmd_without_su), expected_cmd),
- (mock.call.devil.android.device_temp_file.DeviceTempFile(
- self.adb, suffix='.sh'), MockTempFile('/sdcard/temp-123.sh')),
- self.call.device._WriteFileWithPush('/sdcard/temp-123.sh', expected_cmd),
- (self.call.adb.Shell('sh /sdcard/temp-123.sh'), payload + '\n')):
- self.assertEquals(
- [payload],
- self.device.RunShellCommand(
- ['echo', payload], check_return=True, as_root=True))
-
- def testRunShellCommand_withSu(self):
- expected_cmd_without_su = "sh -c 'setprop service.adb.root 0'"
- expected_cmd = 'su -c %s' % expected_cmd_without_su
- with self.assertCalls(
- (self.call.device.NeedsSU(), True),
- (self.call.device._Su(expected_cmd_without_su), expected_cmd),
- (self.call.adb.Shell(expected_cmd), '')):
- self.device.RunShellCommand(
- ['setprop', 'service.adb.root', '0'],
- check_return=True, as_root=True)
-
- def testRunShellCommand_withRunAs(self):
- expected_cmd_without_run_as = "sh -c 'mkdir -p files'"
- expected_cmd = (
- 'run-as org.devil.test_package %s' % expected_cmd_without_run_as)
- with self.assertCall(self.call.adb.Shell(expected_cmd), ''):
- self.device.RunShellCommand(
- ['mkdir', '-p', 'files'],
- check_return=True, run_as='org.devil.test_package')
-
- def testRunShellCommand_withRunAsAndSu(self):
- expected_cmd_with_nothing = "sh -c 'mkdir -p files'"
- expected_cmd_with_run_as = (
- 'run-as org.devil.test_package %s' % expected_cmd_with_nothing)
- expected_cmd_without_su = (
- 'sh -c %s' % cmd_helper.SingleQuote(expected_cmd_with_run_as))
- expected_cmd = 'su -c %s' % expected_cmd_without_su
- with self.assertCalls(
- (self.call.device.NeedsSU(), True),
- (self.call.device._Su(expected_cmd_without_su), expected_cmd),
- (self.call.adb.Shell(expected_cmd), '')):
- self.device.RunShellCommand(
- ['mkdir', '-p', 'files'],
- check_return=True, run_as='org.devil.test_package',
- as_root=True)
-
- def testRunShellCommand_manyLines(self):
- cmd = 'ls /some/path'
- with self.assertCall(self.call.adb.Shell(cmd), 'file1\nfile2\nfile3\n'):
- self.assertEquals(
- ['file1', 'file2', 'file3'],
- self.device.RunShellCommand(cmd.split(), check_return=True))
-
- def testRunShellCommand_manyLinesRawOutput(self):
- cmd = 'ls /some/path'
- with self.assertCall(self.call.adb.Shell(cmd), '\rfile1\nfile2\r\nfile3\n'):
- self.assertEquals(
- '\rfile1\nfile2\r\nfile3\n',
- self.device.RunShellCommand(
- cmd.split(), check_return=True, raw_output=True))
-
- def testRunShellCommand_singleLine_success(self):
- cmd = 'echo $VALUE'
- with self.assertCall(self.call.adb.Shell(cmd), 'some value\n'):
- self.assertEquals(
- 'some value',
- self.device.RunShellCommand(
- cmd, shell=True, check_return=True, single_line=True))
-
- def testRunShellCommand_singleLine_successEmptyLine(self):
- cmd = 'echo $VALUE'
- with self.assertCall(self.call.adb.Shell(cmd), '\n'):
- self.assertEquals(
- '',
- self.device.RunShellCommand(
- cmd, shell=True, check_return=True, single_line=True))
-
- def testRunShellCommand_singleLine_successWithoutEndLine(self):
- cmd = 'echo -n $VALUE'
- with self.assertCall(self.call.adb.Shell(cmd), 'some value'):
- self.assertEquals(
- 'some value',
- self.device.RunShellCommand(
- cmd, shell=True, check_return=True, single_line=True))
-
- def testRunShellCommand_singleLine_successNoOutput(self):
- cmd = 'echo -n $VALUE'
- with self.assertCall(self.call.adb.Shell(cmd), ''):
- self.assertEquals(
- '',
- self.device.RunShellCommand(
- cmd, shell=True, check_return=True, single_line=True))
-
- def testRunShellCommand_singleLine_failTooManyLines(self):
- cmd = 'echo $VALUE'
- with self.assertCall(self.call.adb.Shell(cmd),
- 'some value\nanother value\n'):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device.RunShellCommand(
- cmd, shell=True, check_return=True, single_line=True)
-
- def testRunShellCommand_checkReturn_success(self):
- cmd = 'echo $ANDROID_DATA'
- output = '/data\n'
- with self.assertCall(self.call.adb.Shell(cmd), output):
- self.assertEquals(
- [output.rstrip()],
- self.device.RunShellCommand(cmd, shell=True, check_return=True))
-
- def testRunShellCommand_checkReturn_failure(self):
- cmd = 'ls /root'
- output = 'opendir failed, Permission denied\n'
- with self.assertCall(self.call.adb.Shell(cmd), self.ShellError(output)):
- with self.assertRaises(device_errors.AdbCommandFailedError):
- self.device.RunShellCommand(cmd.split(), check_return=True)
-
- def testRunShellCommand_checkReturn_disabled(self):
- cmd = 'ls /root'
- output = 'opendir failed, Permission denied\n'
- with self.assertCall(self.call.adb.Shell(cmd), self.ShellError(output)):
- self.assertEquals(
- [output.rstrip()],
- self.device.RunShellCommand(cmd.split(), check_return=False))
-
- def testRunShellCommand_largeOutput_enabled(self):
- cmd = 'echo $VALUE'
- temp_file = MockTempFile('/sdcard/temp-123')
- cmd_redirect = '( %s )>%s' % (cmd, temp_file.name)
- with self.assertCalls(
- (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb),
- temp_file),
- (self.call.adb.Shell(cmd_redirect)),
- (self.call.device.ReadFile(temp_file.name, force_pull=True),
- 'something')):
- self.assertEquals(
- ['something'],
- self.device.RunShellCommand(
- cmd, shell=True, large_output=True, check_return=True))
-
- def testRunShellCommand_largeOutput_disabledNoTrigger(self):
- cmd = 'something'
- with self.assertCall(self.call.adb.Shell(cmd), self.ShellError('')):
- with self.assertRaises(device_errors.AdbCommandFailedError):
- self.device.RunShellCommand([cmd], check_return=True)
-
- def testRunShellCommand_largeOutput_disabledTrigger(self):
- cmd = 'echo $VALUE'
- temp_file = MockTempFile('/sdcard/temp-123')
- cmd_redirect = '( %s )>%s' % (cmd, temp_file.name)
- with self.assertCalls(
- (self.call.adb.Shell(cmd), self.ShellError('', None)),
- (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb),
- temp_file),
- (self.call.adb.Shell(cmd_redirect)),
- (self.call.device.ReadFile(mock.ANY, force_pull=True),
- 'something')):
- self.assertEquals(
- ['something'],
- self.device.RunShellCommand(cmd, shell=True, check_return=True))
-
-
-class DeviceUtilsRunPipedShellCommandTest(DeviceUtilsTest):
-
- def testRunPipedShellCommand_success(self):
- with self.assertCall(
- self.call.device.RunShellCommand(
- 'ps | grep foo; echo "PIPESTATUS: ${PIPESTATUS[@]}"',
- shell=True, check_return=True),
- ['This line contains foo', 'PIPESTATUS: 0 0']):
- self.assertEquals(['This line contains foo'],
- self.device._RunPipedShellCommand('ps | grep foo'))
-
- def testRunPipedShellCommand_firstCommandFails(self):
- with self.assertCall(
- self.call.device.RunShellCommand(
- 'ps | grep foo; echo "PIPESTATUS: ${PIPESTATUS[@]}"',
- shell=True, check_return=True),
- ['PIPESTATUS: 1 0']):
- with self.assertRaises(device_errors.AdbShellCommandFailedError) as ec:
- self.device._RunPipedShellCommand('ps | grep foo')
- self.assertEquals([1, 0], ec.exception.status)
-
- def testRunPipedShellCommand_secondCommandFails(self):
- with self.assertCall(
- self.call.device.RunShellCommand(
- 'ps | grep foo; echo "PIPESTATUS: ${PIPESTATUS[@]}"',
- shell=True, check_return=True),
- ['PIPESTATUS: 0 1']):
- with self.assertRaises(device_errors.AdbShellCommandFailedError) as ec:
- self.device._RunPipedShellCommand('ps | grep foo')
- self.assertEquals([0, 1], ec.exception.status)
-
- def testRunPipedShellCommand_outputCutOff(self):
- with self.assertCall(
- self.call.device.RunShellCommand(
- 'ps | grep foo; echo "PIPESTATUS: ${PIPESTATUS[@]}"',
- shell=True, check_return=True),
- ['foo.bar'] * 256 + ['foo.ba']):
- with self.assertRaises(device_errors.AdbShellCommandFailedError) as ec:
- self.device._RunPipedShellCommand('ps | grep foo')
- self.assertIs(None, ec.exception.status)
-
-
-@mock.patch('time.sleep', mock.Mock())
-class DeviceUtilsKillAllTest(DeviceUtilsTest):
-
- def testKillAll_noMatchingProcessesFailure(self):
- with self.assertCall(self.call.device.GetPids('test_process'), {}):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device.KillAll('test_process')
-
- def testKillAll_noMatchingProcessesQuiet(self):
- with self.assertCall(self.call.device.GetPids('test_process'), {}):
- self.assertEqual(0, self.device.KillAll('test_process', quiet=True))
-
- def testKillAll_nonblocking(self):
- with self.assertCalls(
- (self.call.device.GetPids('some.process'),
- {'some.process': ['1234'], 'some.processing.thing': ['5678']}),
- (self.call.adb.Shell('kill -9 1234 5678'), '')):
- self.assertEquals(
- 2, self.device.KillAll('some.process', blocking=False))
-
- def testKillAll_blocking(self):
- with self.assertCalls(
- (self.call.device.GetPids('some.process'),
- {'some.process': ['1234'], 'some.processing.thing': ['5678']}),
- (self.call.adb.Shell('kill -9 1234 5678'), ''),
- (self.call.device.GetPids('some.process'),
- {'some.processing.thing': ['5678']}),
- (self.call.device.GetPids('some.process'),
- {'some.process': ['1111']})): # Other instance with different pid.
- self.assertEquals(
- 2, self.device.KillAll('some.process', blocking=True))
-
- def testKillAll_exactNonblocking(self):
- with self.assertCalls(
- (self.call.device.GetPids('some.process'),
- {'some.process': ['1234'], 'some.processing.thing': ['5678']}),
- (self.call.adb.Shell('kill -9 1234'), '')):
- self.assertEquals(
- 1, self.device.KillAll('some.process', exact=True, blocking=False))
-
- def testKillAll_exactBlocking(self):
- with self.assertCalls(
- (self.call.device.GetPids('some.process'),
- {'some.process': ['1234'], 'some.processing.thing': ['5678']}),
- (self.call.adb.Shell('kill -9 1234'), ''),
- (self.call.device.GetPids('some.process'),
- {'some.process': ['1234'], 'some.processing.thing': ['5678']}),
- (self.call.device.GetPids('some.process'),
- {'some.processing.thing': ['5678']})):
- self.assertEquals(
- 1, self.device.KillAll('some.process', exact=True, blocking=True))
-
- def testKillAll_root(self):
- with self.assertCalls(
- (self.call.device.GetPids('some.process'), {'some.process': ['1234']}),
- (self.call.device.NeedsSU(), True),
- (self.call.device._Su("sh -c 'kill -9 1234'"),
- "su -c sh -c 'kill -9 1234'"),
- (self.call.adb.Shell("su -c sh -c 'kill -9 1234'"), '')):
- self.assertEquals(
- 1, self.device.KillAll('some.process', as_root=True))
-
- def testKillAll_sigterm(self):
- with self.assertCalls(
- (self.call.device.GetPids('some.process'),
- {'some.process': ['1234']}),
- (self.call.adb.Shell('kill -15 1234'), '')):
- self.assertEquals(
- 1, self.device.KillAll('some.process', signum=device_signal.SIGTERM))
-
- def testKillAll_multipleInstances(self):
- with self.assertCalls(
- (self.call.device.GetPids('some.process'),
- {'some.process': ['1234', '4567']}),
- (self.call.adb.Shell('kill -15 1234 4567'), '')):
- self.assertEquals(
- 2, self.device.KillAll('some.process', signum=device_signal.SIGTERM))
-
-
-class DeviceUtilsStartActivityTest(DeviceUtilsTest):
-
- def testStartActivity_actionOnly(self):
- test_intent = intent.Intent(action='android.intent.action.VIEW')
- with self.assertCall(
- self.call.adb.Shell('am start '
- '-a android.intent.action.VIEW'),
- 'Starting: Intent { act=android.intent.action.VIEW }'):
- self.device.StartActivity(test_intent)
-
- def testStartActivity_success(self):
- test_intent = intent.Intent(action='android.intent.action.VIEW',
- package='test.package',
- activity='.Main')
- with self.assertCall(
- self.call.adb.Shell('am start '
- '-a android.intent.action.VIEW '
- '-n test.package/.Main'),
- 'Starting: Intent { act=android.intent.action.VIEW }'):
- self.device.StartActivity(test_intent)
-
- def testStartActivity_failure(self):
- test_intent = intent.Intent(action='android.intent.action.VIEW',
- package='test.package',
- activity='.Main')
- with self.assertCall(
- self.call.adb.Shell('am start '
- '-a android.intent.action.VIEW '
- '-n test.package/.Main'),
- 'Error: Failed to start test activity'):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device.StartActivity(test_intent)
-
- def testStartActivity_blocking(self):
- test_intent = intent.Intent(action='android.intent.action.VIEW',
- package='test.package',
- activity='.Main')
- with self.assertCall(
- self.call.adb.Shell('am start '
- '-W '
- '-a android.intent.action.VIEW '
- '-n test.package/.Main'),
- 'Starting: Intent { act=android.intent.action.VIEW }'):
- self.device.StartActivity(test_intent, blocking=True)
-
- def testStartActivity_withCategory(self):
- test_intent = intent.Intent(action='android.intent.action.VIEW',
- package='test.package',
- activity='.Main',
- category='android.intent.category.HOME')
- with self.assertCall(
- self.call.adb.Shell('am start '
- '-a android.intent.action.VIEW '
- '-c android.intent.category.HOME '
- '-n test.package/.Main'),
- 'Starting: Intent { act=android.intent.action.VIEW }'):
- self.device.StartActivity(test_intent)
-
- def testStartActivity_withMultipleCategories(self):
- test_intent = intent.Intent(action='android.intent.action.VIEW',
- package='test.package',
- activity='.Main',
- category=['android.intent.category.HOME',
- 'android.intent.category.BROWSABLE'])
- with self.assertCall(
- self.call.adb.Shell('am start '
- '-a android.intent.action.VIEW '
- '-c android.intent.category.HOME '
- '-c android.intent.category.BROWSABLE '
- '-n test.package/.Main'),
- 'Starting: Intent { act=android.intent.action.VIEW }'):
- self.device.StartActivity(test_intent)
-
- def testStartActivity_withData(self):
- test_intent = intent.Intent(action='android.intent.action.VIEW',
- package='test.package',
- activity='.Main',
- data='http://www.google.com/')
- with self.assertCall(
- self.call.adb.Shell('am start '
- '-a android.intent.action.VIEW '
- '-d http://www.google.com/ '
- '-n test.package/.Main'),
- 'Starting: Intent { act=android.intent.action.VIEW }'):
- self.device.StartActivity(test_intent)
-
- def testStartActivity_withStringExtra(self):
- test_intent = intent.Intent(action='android.intent.action.VIEW',
- package='test.package',
- activity='.Main',
- extras={'foo': 'test'})
- with self.assertCall(
- self.call.adb.Shell('am start '
- '-a android.intent.action.VIEW '
- '-n test.package/.Main '
- '--es foo test'),
- 'Starting: Intent { act=android.intent.action.VIEW }'):
- self.device.StartActivity(test_intent)
-
- def testStartActivity_withBoolExtra(self):
- test_intent = intent.Intent(action='android.intent.action.VIEW',
- package='test.package',
- activity='.Main',
- extras={'foo': True})
- with self.assertCall(
- self.call.adb.Shell('am start '
- '-a android.intent.action.VIEW '
- '-n test.package/.Main '
- '--ez foo True'),
- 'Starting: Intent { act=android.intent.action.VIEW }'):
- self.device.StartActivity(test_intent)
-
- def testStartActivity_withIntExtra(self):
- test_intent = intent.Intent(action='android.intent.action.VIEW',
- package='test.package',
- activity='.Main',
- extras={'foo': 123})
- with self.assertCall(
- self.call.adb.Shell('am start '
- '-a android.intent.action.VIEW '
- '-n test.package/.Main '
- '--ei foo 123'),
- 'Starting: Intent { act=android.intent.action.VIEW }'):
- self.device.StartActivity(test_intent)
-
- def testStartActivity_withTraceFile(self):
- test_intent = intent.Intent(action='android.intent.action.VIEW',
- package='test.package',
- activity='.Main')
- with self.assertCall(
- self.call.adb.Shell('am start '
- '--start-profiler test_trace_file.out '
- '-a android.intent.action.VIEW '
- '-n test.package/.Main'),
- 'Starting: Intent { act=android.intent.action.VIEW }'):
- self.device.StartActivity(test_intent,
- trace_file_name='test_trace_file.out')
-
- def testStartActivity_withForceStop(self):
- test_intent = intent.Intent(action='android.intent.action.VIEW',
- package='test.package',
- activity='.Main')
- with self.assertCall(
- self.call.adb.Shell('am start '
- '-S '
- '-a android.intent.action.VIEW '
- '-n test.package/.Main'),
- 'Starting: Intent { act=android.intent.action.VIEW }'):
- self.device.StartActivity(test_intent, force_stop=True)
-
- def testStartActivity_withFlags(self):
- test_intent = intent.Intent(action='android.intent.action.VIEW',
- package='test.package',
- activity='.Main',
- flags=[
- intent.FLAG_ACTIVITY_NEW_TASK,
- intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
- ])
- with self.assertCall(
- self.call.adb.Shell('am start '
- '-a android.intent.action.VIEW '
- '-n test.package/.Main '
- '-f 0x10200000'),
- 'Starting: Intent { act=android.intent.action.VIEW }'):
- self.device.StartActivity(test_intent)
-
-
-class DeviceUtilsStartInstrumentationTest(DeviceUtilsTest):
-
- def testStartInstrumentation_nothing(self):
- with self.assertCalls(
- self.call.device.RunShellCommand(
- 'p=test.package;am instrument "$p"/.TestInstrumentation',
- shell=True, check_return=True, large_output=True)):
- self.device.StartInstrumentation(
- 'test.package/.TestInstrumentation',
- finish=False, raw=False, extras=None)
-
- def testStartInstrumentation_finish(self):
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- 'p=test.package;am instrument -w "$p"/.TestInstrumentation',
- shell=True, check_return=True, large_output=True),
- ['OK (1 test)'])):
- output = self.device.StartInstrumentation(
- 'test.package/.TestInstrumentation',
- finish=True, raw=False, extras=None)
- self.assertEquals(['OK (1 test)'], output)
-
- def testStartInstrumentation_raw(self):
- with self.assertCalls(
- self.call.device.RunShellCommand(
- 'p=test.package;am instrument -r "$p"/.TestInstrumentation',
- shell=True, check_return=True, large_output=True)):
- self.device.StartInstrumentation(
- 'test.package/.TestInstrumentation',
- finish=False, raw=True, extras=None)
-
- def testStartInstrumentation_extras(self):
- with self.assertCalls(
- self.call.device.RunShellCommand(
- 'p=test.package;am instrument -e "$p".foo Foo -e bar \'Val \'"$p" '
- '"$p"/.TestInstrumentation',
- shell=True, check_return=True, large_output=True)):
- self.device.StartInstrumentation(
- 'test.package/.TestInstrumentation',
- finish=False, raw=False, extras={'test.package.foo': 'Foo',
- 'bar': 'Val test.package'})
-
-
-class DeviceUtilsBroadcastIntentTest(DeviceUtilsTest):
-
- def testBroadcastIntent_noExtras(self):
- test_intent = intent.Intent(action='test.package.with.an.INTENT')
- with self.assertCall(
- self.call.adb.Shell('am broadcast -a test.package.with.an.INTENT'),
- 'Broadcasting: Intent { act=test.package.with.an.INTENT } '):
- self.device.BroadcastIntent(test_intent)
-
- def testBroadcastIntent_withExtra(self):
- test_intent = intent.Intent(action='test.package.with.an.INTENT',
- extras={'foo': 'bar value'})
- with self.assertCall(
- self.call.adb.Shell(
- "am broadcast -a test.package.with.an.INTENT --es foo 'bar value'"),
- 'Broadcasting: Intent { act=test.package.with.an.INTENT } '):
- self.device.BroadcastIntent(test_intent)
-
- def testBroadcastIntent_withExtra_noValue(self):
- test_intent = intent.Intent(action='test.package.with.an.INTENT',
- extras={'foo': None})
- with self.assertCall(
- self.call.adb.Shell(
- 'am broadcast -a test.package.with.an.INTENT --esn foo'),
- 'Broadcasting: Intent { act=test.package.with.an.INTENT } '):
- self.device.BroadcastIntent(test_intent)
-
-
-class DeviceUtilsGoHomeTest(DeviceUtilsTest):
-
- def testGoHome_popupsExist(self):
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- ['dumpsys', 'window', 'windows'], check_return=True,
- large_output=True), []),
- (self.call.device.RunShellCommand(
- ['am', 'start', '-W', '-a', 'android.intent.action.MAIN',
- '-c', 'android.intent.category.HOME'], check_return=True),
- 'Starting: Intent { act=android.intent.action.MAIN }\r\n'''),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'window', 'windows'], check_return=True,
- large_output=True), []),
- (self.call.device.RunShellCommand(
- ['input', 'keyevent', '66'], check_return=True)),
- (self.call.device.RunShellCommand(
- ['input', 'keyevent', '4'], check_return=True)),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'window', 'windows'], check_return=True,
- large_output=True),
- ['mCurrentFocus Launcher'])):
- self.device.GoHome()
-
- def testGoHome_willRetry(self):
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- ['dumpsys', 'window', 'windows'], check_return=True,
- large_output=True), []),
- (self.call.device.RunShellCommand(
- ['am', 'start', '-W', '-a', 'android.intent.action.MAIN',
- '-c', 'android.intent.category.HOME'], check_return=True),
- 'Starting: Intent { act=android.intent.action.MAIN }\r\n'''),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'window', 'windows'], check_return=True,
- large_output=True), []),
- (self.call.device.RunShellCommand(
- ['input', 'keyevent', '66'], check_return=True,)),
- (self.call.device.RunShellCommand(
- ['input', 'keyevent', '4'], check_return=True)),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'window', 'windows'], check_return=True,
- large_output=True), []),
- (self.call.device.RunShellCommand(
- ['input', 'keyevent', '66'], check_return=True)),
- (self.call.device.RunShellCommand(
- ['input', 'keyevent', '4'], check_return=True)),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'window', 'windows'], check_return=True,
- large_output=True),
- self.TimeoutError())):
- with self.assertRaises(device_errors.CommandTimeoutError):
- self.device.GoHome()
-
- def testGoHome_alreadyFocused(self):
- with self.assertCall(
- self.call.device.RunShellCommand(
- ['dumpsys', 'window', 'windows'], check_return=True,
- large_output=True),
- ['mCurrentFocus Launcher']):
- self.device.GoHome()
-
- def testGoHome_alreadyFocusedAlternateCase(self):
- with self.assertCall(
- self.call.device.RunShellCommand(
- ['dumpsys', 'window', 'windows'], check_return=True,
- large_output=True),
- [' mCurrentFocus .launcher/.']):
- self.device.GoHome()
-
- def testGoHome_obtainsFocusAfterGoingHome(self):
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- ['dumpsys', 'window', 'windows'], check_return=True,
- large_output=True), []),
- (self.call.device.RunShellCommand(
- ['am', 'start', '-W', '-a', 'android.intent.action.MAIN',
- '-c', 'android.intent.category.HOME'], check_return=True),
- 'Starting: Intent { act=android.intent.action.MAIN }\r\n'''),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'window', 'windows'], check_return=True,
- large_output=True),
- ['mCurrentFocus Launcher'])):
- self.device.GoHome()
-
-
-class DeviceUtilsForceStopTest(DeviceUtilsTest):
-
- def testForceStop(self):
- with self.assertCall(
- self.call.adb.Shell('p=test.package;if [[ "$(ps)" = *$p* ]]; then '
- 'am force-stop $p; fi'),
- ''):
- self.device.ForceStop('test.package')
-
-
-class DeviceUtilsClearApplicationStateTest(DeviceUtilsTest):
-
- def testClearApplicationState_setPermissions(self):
- with self.assertCalls(
- (self.call.device.GetProp('ro.build.version.sdk', cache=True), '17'),
- (self.call.device._GetApplicationPathsInternal('this.package.exists'),
- ['/data/app/this.package.exists.apk']),
- (self.call.device.RunShellCommand(
- ['pm', 'clear', 'this.package.exists'],
- check_return=True),
- ['Success']),
- (self.call.device.GrantPermissions(
- 'this.package.exists', ['p1']), [])):
- self.device.ClearApplicationState(
- 'this.package.exists', permissions=['p1'])
-
- def testClearApplicationState_packageDoesntExist(self):
- with self.assertCalls(
- (self.call.device.GetProp('ro.build.version.sdk', cache=True), '11'),
- (self.call.device._GetApplicationPathsInternal('does.not.exist'),
- [])):
- self.device.ClearApplicationState('does.not.exist')
-
- def testClearApplicationState_packageDoesntExistOnAndroidJBMR2OrAbove(self):
- with self.assertCalls(
- (self.call.device.GetProp('ro.build.version.sdk', cache=True), '18'),
- (self.call.device.RunShellCommand(
- ['pm', 'clear', 'this.package.does.not.exist'],
- check_return=True),
- ['Failed'])):
- self.device.ClearApplicationState('this.package.does.not.exist')
-
- def testClearApplicationState_packageExists(self):
- with self.assertCalls(
- (self.call.device.GetProp('ro.build.version.sdk', cache=True), '17'),
- (self.call.device._GetApplicationPathsInternal('this.package.exists'),
- ['/data/app/this.package.exists.apk']),
- (self.call.device.RunShellCommand(
- ['pm', 'clear', 'this.package.exists'],
- check_return=True),
- ['Success'])):
- self.device.ClearApplicationState('this.package.exists')
-
- def testClearApplicationState_packageExistsOnAndroidJBMR2OrAbove(self):
- with self.assertCalls(
- (self.call.device.GetProp('ro.build.version.sdk', cache=True), '18'),
- (self.call.device.RunShellCommand(
- ['pm', 'clear', 'this.package.exists'],
- check_return=True),
- ['Success'])):
- self.device.ClearApplicationState('this.package.exists')
-
-
-class DeviceUtilsSendKeyEventTest(DeviceUtilsTest):
-
- def testSendKeyEvent(self):
- with self.assertCall(self.call.adb.Shell('input keyevent 66'), ''):
- self.device.SendKeyEvent(66)
-
-
-class DeviceUtilsPushChangedFilesIndividuallyTest(DeviceUtilsTest):
-
- def testPushChangedFilesIndividually_empty(self):
- test_files = []
- with self.assertCalls():
- self.device._PushChangedFilesIndividually(test_files)
-
- def testPushChangedFilesIndividually_single(self):
- test_files = [('/test/host/path', '/test/device/path')]
- with self.assertCalls(self.call.adb.Push(*test_files[0])):
- self.device._PushChangedFilesIndividually(test_files)
-
- def testPushChangedFilesIndividually_multiple(self):
- test_files = [
- ('/test/host/path/file1', '/test/device/path/file1'),
- ('/test/host/path/file2', '/test/device/path/file2')]
- with self.assertCalls(
- self.call.adb.Push(*test_files[0]),
- self.call.adb.Push(*test_files[1])):
- self.device._PushChangedFilesIndividually(test_files)
-
-
-class DeviceUtilsPushChangedFilesZippedTest(DeviceUtilsTest):
-
- def testPushChangedFilesZipped_noUnzipCommand(self):
- test_files = [('/test/host/path/file1', '/test/device/path/file1')]
- mock_zip_temp = mock.mock_open()
- mock_zip_temp.return_value.name = '/test/temp/file/tmp.zip'
- with self.assertCalls(
- (mock.call.tempfile.NamedTemporaryFile(suffix='.zip'), mock_zip_temp),
- (mock.call.multiprocessing.Process(
- target=device_utils.DeviceUtils._CreateDeviceZip,
- args=('/test/temp/file/tmp.zip', test_files)), mock.Mock()),
- (self.call.device._MaybeInstallCommands(), False)):
- self.assertFalse(self.device._PushChangedFilesZipped(test_files,
- ['/test/dir']))
-
- def _testPushChangedFilesZipped_spec(self, test_files):
- mock_zip_temp = mock.mock_open()
- mock_zip_temp.return_value.name = '/test/temp/file/tmp.zip'
- with self.assertCalls(
- (mock.call.tempfile.NamedTemporaryFile(suffix='.zip'), mock_zip_temp),
- (mock.call.multiprocessing.Process(
- target=device_utils.DeviceUtils._CreateDeviceZip,
- args=('/test/temp/file/tmp.zip', test_files)), mock.Mock()),
- (self.call.device._MaybeInstallCommands(), True),
- (self.call.device.NeedsSU(), True),
- (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb,
- suffix='.zip'),
- MockTempFile('/test/sdcard/foo123.zip')),
- self.call.adb.Push(
- '/test/temp/file/tmp.zip', '/test/sdcard/foo123.zip'),
- self.call.device.RunShellCommand(
- 'unzip /test/sdcard/foo123.zip&&chmod -R 777 /test/dir',
- shell=True, as_root=True,
- env={'PATH': '/data/local/tmp/bin:$PATH'},
- check_return=True)):
- self.assertTrue(self.device._PushChangedFilesZipped(test_files,
- ['/test/dir']))
-
- def testPushChangedFilesZipped_single(self):
- self._testPushChangedFilesZipped_spec(
- [('/test/host/path/file1', '/test/device/path/file1')])
-
- def testPushChangedFilesZipped_multiple(self):
- self._testPushChangedFilesZipped_spec(
- [('/test/host/path/file1', '/test/device/path/file1'),
- ('/test/host/path/file2', '/test/device/path/file2')])
-
-
-class DeviceUtilsPathExistsTest(DeviceUtilsTest):
-
- def testPathExists_pathExists(self):
- with self.assertCall(
- self.call.device.RunShellCommand(
- ['test', '-e', '/path/file exists'],
- as_root=False, check_return=True, timeout=10, retries=0),
- []):
- self.assertTrue(self.device.PathExists('/path/file exists'))
-
- def testPathExists_multiplePathExists(self):
- with self.assertCall(
- self.call.device.RunShellCommand(
- ['test', '-e', '/path 1', '-a', '-e', '/path2'],
- as_root=False, check_return=True, timeout=10, retries=0),
- []):
- self.assertTrue(self.device.PathExists(('/path 1', '/path2')))
-
- def testPathExists_pathDoesntExist(self):
- with self.assertCall(
- self.call.device.RunShellCommand(
- ['test', '-e', '/path/file.not.exists'],
- as_root=False, check_return=True, timeout=10, retries=0),
- self.ShellError()):
- self.assertFalse(self.device.PathExists('/path/file.not.exists'))
-
- def testPathExists_asRoot(self):
- with self.assertCall(
- self.call.device.RunShellCommand(
- ['test', '-e', '/root/path/exists'],
- as_root=True, check_return=True, timeout=10, retries=0),
- self.ShellError()):
- self.assertFalse(
- self.device.PathExists('/root/path/exists', as_root=True))
-
- def testFileExists_pathDoesntExist(self):
- with self.assertCall(
- self.call.device.RunShellCommand(
- ['test', '-e', '/path/file.not.exists'],
- as_root=False, check_return=True, timeout=10, retries=0),
- self.ShellError()):
- self.assertFalse(self.device.FileExists('/path/file.not.exists'))
-
-
-class DeviceUtilsRemovePathTest(DeviceUtilsTest):
-
- def testRemovePath_regular(self):
- with self.assertCall(
- self.call.device.RunShellCommand(
- ['rm', 'some file'], as_root=False, check_return=True),
- []):
- self.device.RemovePath('some file')
-
- def testRemovePath_withForce(self):
- with self.assertCall(
- self.call.device.RunShellCommand(
- ['rm', '-f', 'some file'], as_root=False, check_return=True),
- []):
- self.device.RemovePath('some file', force=True)
-
- def testRemovePath_recursively(self):
- with self.assertCall(
- self.call.device.RunShellCommand(
- ['rm', '-r', '/remove/this/dir'], as_root=False, check_return=True),
- []):
- self.device.RemovePath('/remove/this/dir', recursive=True)
-
- def testRemovePath_withRoot(self):
- with self.assertCall(
- self.call.device.RunShellCommand(
- ['rm', 'some file'], as_root=True, check_return=True),
- []):
- self.device.RemovePath('some file', as_root=True)
-
- def testRemovePath_manyPaths(self):
- with self.assertCall(
- self.call.device.RunShellCommand(
- ['rm', 'eeny', 'meeny', 'miny', 'moe'],
- as_root=False, check_return=True),
- []):
- self.device.RemovePath(['eeny', 'meeny', 'miny', 'moe'])
-
-
-class DeviceUtilsPullFileTest(DeviceUtilsTest):
-
- def testPullFile_existsOnDevice(self):
- with mock.patch('os.path.exists', return_value=True):
- with self.assertCall(
- self.call.adb.Pull('/data/app/test.file.exists',
- '/test/file/host/path')):
- self.device.PullFile('/data/app/test.file.exists',
- '/test/file/host/path')
-
- def testPullFile_doesntExistOnDevice(self):
- with mock.patch('os.path.exists', return_value=True):
- with self.assertCall(
- self.call.adb.Pull('/data/app/test.file.does.not.exist',
- '/test/file/host/path'),
- self.CommandError('remote object does not exist')):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device.PullFile('/data/app/test.file.does.not.exist',
- '/test/file/host/path')
-
-
-class DeviceUtilsReadFileTest(DeviceUtilsTest):
-
- def testReadFileWithPull_success(self):
- tmp_host_dir = '/tmp/dir/on.host/'
- tmp_host = MockTempFile('/tmp/dir/on.host/tmp_ReadFileWithPull')
- tmp_host.file.read.return_value = 'some interesting contents'
- with self.assertCalls(
- (mock.call.tempfile.mkdtemp(), tmp_host_dir),
- (self.call.adb.Pull('/path/to/device/file', mock.ANY)),
- (mock.call.__builtin__.open(mock.ANY, 'r'), tmp_host),
- (mock.call.os.path.exists(tmp_host_dir), True),
- (mock.call.shutil.rmtree(tmp_host_dir), None)):
- self.assertEquals('some interesting contents',
- self.device._ReadFileWithPull('/path/to/device/file'))
- tmp_host.file.read.assert_called_once_with()
-
- def testReadFileWithPull_rejected(self):
- tmp_host_dir = '/tmp/dir/on.host/'
- with self.assertCalls(
- (mock.call.tempfile.mkdtemp(), tmp_host_dir),
- (self.call.adb.Pull('/path/to/device/file', mock.ANY),
- self.CommandError()),
- (mock.call.os.path.exists(tmp_host_dir), True),
- (mock.call.shutil.rmtree(tmp_host_dir), None)):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device._ReadFileWithPull('/path/to/device/file')
-
- def testReadFile_exists(self):
- with self.assertCalls(
- (self.call.device.FileSize('/read/this/test/file', as_root=False), 256),
- (self.call.device.RunShellCommand(
- ['cat', '/read/this/test/file'],
- as_root=False, check_return=True),
- ['this is a test file'])):
- self.assertEqual('this is a test file\n',
- self.device.ReadFile('/read/this/test/file'))
-
- def testReadFile_exists2(self):
- # Same as testReadFile_exists, but uses Android N ls output.
- with self.assertCalls(
- (self.call.device.FileSize('/read/this/test/file', as_root=False), 256),
- (self.call.device.RunShellCommand(
- ['cat', '/read/this/test/file'],
- as_root=False, check_return=True),
- ['this is a test file'])):
- self.assertEqual('this is a test file\n',
- self.device.ReadFile('/read/this/test/file'))
-
- def testReadFile_doesNotExist(self):
- with self.assertCall(
- self.call.device.FileSize('/this/file/does.not.exist', as_root=False),
- self.CommandError('File does not exist')):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device.ReadFile('/this/file/does.not.exist')
-
- def testReadFile_zeroSize(self):
- with self.assertCalls(
- (self.call.device.FileSize('/this/file/has/zero/size', as_root=False),
- 0),
- (self.call.device._ReadFileWithPull('/this/file/has/zero/size'),
- 'but it has contents\n')):
- self.assertEqual('but it has contents\n',
- self.device.ReadFile('/this/file/has/zero/size'))
-
- def testReadFile_withSU(self):
- with self.assertCalls(
- (self.call.device.FileSize(
- '/this/file/can.be.read.with.su', as_root=True), 256),
- (self.call.device.RunShellCommand(
- ['cat', '/this/file/can.be.read.with.su'],
- as_root=True, check_return=True),
- ['this is a test file', 'read with su'])):
- self.assertEqual(
- 'this is a test file\nread with su\n',
- self.device.ReadFile('/this/file/can.be.read.with.su',
- as_root=True))
-
- def testReadFile_withPull(self):
- contents = 'a' * 123456
- with self.assertCalls(
- (self.call.device.FileSize('/read/this/big/test/file', as_root=False),
- 123456),
- (self.call.device._ReadFileWithPull('/read/this/big/test/file'),
- contents)):
- self.assertEqual(
- contents, self.device.ReadFile('/read/this/big/test/file'))
-
- def testReadFile_withPullAndSU(self):
- contents = 'b' * 123456
- with self.assertCalls(
- (self.call.device.FileSize(
- '/this/big/file/can.be.read.with.su', as_root=True), 123456),
- (self.call.device.NeedsSU(), True),
- (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb),
- MockTempFile('/sdcard/tmp/on.device')),
- self.call.device.RunShellCommand(
- 'SRC=/this/big/file/can.be.read.with.su DEST=/sdcard/tmp/on.device;'
- 'cp "$SRC" "$DEST" && chmod 666 "$DEST"',
- shell=True, as_root=True, check_return=True),
- (self.call.device._ReadFileWithPull('/sdcard/tmp/on.device'),
- contents)):
- self.assertEqual(
- contents,
- self.device.ReadFile('/this/big/file/can.be.read.with.su',
- as_root=True))
-
- def testReadFile_forcePull(self):
- contents = 'a' * 123456
- with self.assertCall(
- self.call.device._ReadFileWithPull('/read/this/big/test/file'),
- contents):
- self.assertEqual(
- contents,
- self.device.ReadFile('/read/this/big/test/file', force_pull=True))
-
-
-class DeviceUtilsWriteFileTest(DeviceUtilsTest):
-
- def testWriteFileWithPush_success(self):
- tmp_host = MockTempFile('/tmp/file/on.host')
- contents = 'some interesting contents'
- with self.assertCalls(
- (mock.call.tempfile.NamedTemporaryFile(), tmp_host),
- self.call.adb.Push('/tmp/file/on.host', '/path/to/device/file')):
- self.device._WriteFileWithPush('/path/to/device/file', contents)
- tmp_host.file.write.assert_called_once_with(contents)
-
- def testWriteFileWithPush_rejected(self):
- tmp_host = MockTempFile('/tmp/file/on.host')
- contents = 'some interesting contents'
- with self.assertCalls(
- (mock.call.tempfile.NamedTemporaryFile(), tmp_host),
- (self.call.adb.Push('/tmp/file/on.host', '/path/to/device/file'),
- self.CommandError())):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device._WriteFileWithPush('/path/to/device/file', contents)
-
- def testWriteFile_withPush(self):
- contents = 'some large contents ' * 26 # 20 * 26 = 520 chars
- with self.assertCalls(
- self.call.device._WriteFileWithPush('/path/to/device/file', contents)):
- self.device.WriteFile('/path/to/device/file', contents)
-
- def testWriteFile_withPushForced(self):
- contents = 'tiny contents'
- with self.assertCalls(
- self.call.device._WriteFileWithPush('/path/to/device/file', contents)):
- self.device.WriteFile('/path/to/device/file', contents, force_push=True)
-
- def testWriteFile_withPushAndSU(self):
- contents = 'some large contents ' * 26 # 20 * 26 = 520 chars
- with self.assertCalls(
- (self.call.device.NeedsSU(), True),
- (mock.call.devil.android.device_temp_file.DeviceTempFile(self.adb),
- MockTempFile('/sdcard/tmp/on.device')),
- self.call.device._WriteFileWithPush('/sdcard/tmp/on.device', contents),
- self.call.device.RunShellCommand(
- ['cp', '/sdcard/tmp/on.device', '/path/to/device/file'],
- as_root=True, check_return=True)):
- self.device.WriteFile('/path/to/device/file', contents, as_root=True)
-
- def testWriteFile_withEcho(self):
- with self.assertCall(self.call.adb.Shell(
- "echo -n the.contents > /test/file/to.write"), ''):
- self.device.WriteFile('/test/file/to.write', 'the.contents')
-
- def testWriteFile_withEchoAndQuotes(self):
- with self.assertCall(self.call.adb.Shell(
- "echo -n 'the contents' > '/test/file/to write'"), ''):
- self.device.WriteFile('/test/file/to write', 'the contents')
-
- def testWriteFile_withEchoAndSU(self):
- expected_cmd_without_su = "sh -c 'echo -n contents > /test/file'"
- expected_cmd = 'su -c %s' % expected_cmd_without_su
- with self.assertCalls(
- (self.call.device.NeedsSU(), True),
- (self.call.device._Su(expected_cmd_without_su), expected_cmd),
- (self.call.adb.Shell(expected_cmd),
- '')):
- self.device.WriteFile('/test/file', 'contents', as_root=True)
-
-
-class DeviceUtilsStatDirectoryTest(DeviceUtilsTest):
- # Note: Also tests ListDirectory in testStatDirectory_fileList.
-
- EXAMPLE_LS_OUTPUT = [
- 'total 12345',
- 'drwxr-xr-x 19 root root 0 1970-04-06 18:03 .',
- 'drwxr-xr-x 19 root root 0 1970-04-06 18:03 ..',
- 'drwxr-xr-x 6 root root 1970-01-01 00:00 some_dir',
- '-rw-r--r-- 1 root root 723 1971-01-01 07:04 some_file',
- '-rw-r----- 1 root root 327 2009-02-13 23:30 My Music File',
- # Older Android versions do not print st_nlink
- 'lrwxrwxrwx root root 1970-01-01 00:00 lnk -> /some/path',
- 'srwxrwx--- system system 2016-05-31 17:25 a_socket1',
- 'drwxrwxrwt system misc 1970-11-23 02:25 tmp',
- 'drwxr-s--- system shell 1970-11-23 02:24 my_cmd',
- 'cr--r----- root system 10, 183 1971-01-01 07:04 random',
- 'brw------- root root 7, 0 1971-01-01 07:04 block_dev',
- '-rwS------ root shell 157404 2015-04-13 15:44 silly',
- ]
-
- FILENAMES = [
- 'some_dir', 'some_file', 'My Music File', 'lnk', 'a_socket1',
- 'tmp', 'my_cmd', 'random', 'block_dev', 'silly']
-
- def getStatEntries(self, path_given='/', path_listed='/'):
- with self.assertCall(
- self.call.device.RunShellCommand(
- ['ls', '-a', '-l', path_listed],
- check_return=True, as_root=False, env={'TZ': 'utc'}),
- self.EXAMPLE_LS_OUTPUT):
- entries = self.device.StatDirectory(path_given)
- return {f['filename']: f for f in entries}
-
- def getListEntries(self):
- with self.assertCall(
- self.call.device.RunShellCommand(
- ['ls', '-a', '-l', '/'],
- check_return=True, as_root=False, env={'TZ': 'utc'}),
- self.EXAMPLE_LS_OUTPUT):
- return self.device.ListDirectory('/')
-
- def testStatDirectory_forceTrailingSlash(self):
- self.getStatEntries(path_given='/foo/bar/', path_listed='/foo/bar/')
- self.getStatEntries(path_given='/foo/bar', path_listed='/foo/bar/')
-
- def testStatDirectory_fileList(self):
- self.assertItemsEqual(self.getStatEntries().keys(), self.FILENAMES)
- self.assertItemsEqual(self.getListEntries(), self.FILENAMES)
-
- def testStatDirectory_fileModes(self):
- expected_modes = (
- ('some_dir', stat.S_ISDIR),
- ('some_file', stat.S_ISREG),
- ('lnk', stat.S_ISLNK),
- ('a_socket1', stat.S_ISSOCK),
- ('block_dev', stat.S_ISBLK),
- ('random', stat.S_ISCHR),
- )
- entries = self.getStatEntries()
- for filename, check in expected_modes:
- self.assertTrue(check(entries[filename]['st_mode']))
-
- def testStatDirectory_filePermissions(self):
- should_have = (
- ('some_file', stat.S_IWUSR), # Owner can write.
- ('tmp', stat.S_IXOTH), # Others can execute.
- ('tmp', stat.S_ISVTX), # Has sticky bit.
- ('my_cmd', stat.S_ISGID), # Has set-group-ID bit.
- ('silly', stat.S_ISUID), # Has set UID bit.
- )
- should_not_have = (
- ('some_file', stat.S_IWOTH), # Others can't write.
- ('block_dev', stat.S_IRGRP), # Group can't read.
- ('silly', stat.S_IXUSR), # Owner can't execute.
- )
- entries = self.getStatEntries()
- for filename, bit in should_have:
- self.assertTrue(entries[filename]['st_mode'] & bit)
- for filename, bit in should_not_have:
- self.assertFalse(entries[filename]['st_mode'] & bit)
-
- def testStatDirectory_numHardLinks(self):
- entries = self.getStatEntries()
- self.assertEqual(entries['some_dir']['st_nlink'], 6)
- self.assertEqual(entries['some_file']['st_nlink'], 1)
- self.assertFalse('st_nlink' in entries['tmp'])
-
- def testStatDirectory_fileOwners(self):
- entries = self.getStatEntries()
- self.assertEqual(entries['some_dir']['st_owner'], 'root')
- self.assertEqual(entries['my_cmd']['st_owner'], 'system')
- self.assertEqual(entries['my_cmd']['st_group'], 'shell')
- self.assertEqual(entries['tmp']['st_group'], 'misc')
-
- def testStatDirectory_fileSize(self):
- entries = self.getStatEntries()
- self.assertEqual(entries['some_file']['st_size'], 723)
- self.assertEqual(entries['My Music File']['st_size'], 327)
- # Sizes are sometimes not reported for non-regular files, don't try to
- # guess the size in those cases.
- self.assertFalse('st_size' in entries['some_dir'])
-
- def testStatDirectory_fileDateTime(self):
- entries = self.getStatEntries()
- self.assertEqual(entries['some_dir']['st_mtime'], 0) # Epoch!
- self.assertEqual(entries['My Music File']['st_mtime'], 1234567800)
-
- def testStatDirectory_deviceType(self):
- entries = self.getStatEntries()
- self.assertEqual(entries['random']['st_rdev_pair'], (10, 183))
- self.assertEqual(entries['block_dev']['st_rdev_pair'], (7, 0))
-
- def testStatDirectory_symbolicLinks(self):
- entries = self.getStatEntries()
- self.assertEqual(entries['lnk']['symbolic_link_to'], '/some/path')
- for d in entries.itervalues():
- self.assertEqual('symbolic_link_to' in d, stat.S_ISLNK(d['st_mode']))
-
-
-class DeviceUtilsStatPathTest(DeviceUtilsTest):
-
- EXAMPLE_DIRECTORY = [
- {'filename': 'foo.txt', 'st_size': 123, 'st_time': 456},
- {'filename': 'some_dir', 'st_time': 0}
- ]
- INDEX = {e['filename']: e for e in EXAMPLE_DIRECTORY}
-
- def testStatPath_file(self):
- with self.assertCall(
- self.call.device.StatDirectory('/data/local/tmp', as_root=False),
- self.EXAMPLE_DIRECTORY):
- self.assertEquals(self.INDEX['foo.txt'],
- self.device.StatPath('/data/local/tmp/foo.txt'))
-
- def testStatPath_directory(self):
- with self.assertCall(
- self.call.device.StatDirectory('/data/local/tmp', as_root=False),
- self.EXAMPLE_DIRECTORY):
- self.assertEquals(self.INDEX['some_dir'],
- self.device.StatPath('/data/local/tmp/some_dir'))
-
- def testStatPath_directoryWithTrailingSlash(self):
- with self.assertCall(
- self.call.device.StatDirectory('/data/local/tmp', as_root=False),
- self.EXAMPLE_DIRECTORY):
- self.assertEquals(self.INDEX['some_dir'],
- self.device.StatPath('/data/local/tmp/some_dir/'))
-
- def testStatPath_doesNotExist(self):
- with self.assertCall(
- self.call.device.StatDirectory('/data/local/tmp', as_root=False),
- self.EXAMPLE_DIRECTORY):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device.StatPath('/data/local/tmp/does.not.exist.txt')
-
-
-class DeviceUtilsFileSizeTest(DeviceUtilsTest):
-
- EXAMPLE_DIRECTORY = [
- {'filename': 'foo.txt', 'st_size': 123, 'st_mtime': 456},
- {'filename': 'some_dir', 'st_mtime': 0}
- ]
-
- def testFileSize_file(self):
- with self.assertCall(
- self.call.device.StatDirectory('/data/local/tmp', as_root=False),
- self.EXAMPLE_DIRECTORY):
- self.assertEquals(123,
- self.device.FileSize('/data/local/tmp/foo.txt'))
-
- def testFileSize_doesNotExist(self):
- with self.assertCall(
- self.call.device.StatDirectory('/data/local/tmp', as_root=False),
- self.EXAMPLE_DIRECTORY):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device.FileSize('/data/local/tmp/does.not.exist.txt')
-
- def testFileSize_directoryWithNoSize(self):
- with self.assertCall(
- self.call.device.StatDirectory('/data/local/tmp', as_root=False),
- self.EXAMPLE_DIRECTORY):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device.FileSize('/data/local/tmp/some_dir')
-
-
-class DeviceUtilsSetJavaAssertsTest(DeviceUtilsTest):
-
- def testSetJavaAsserts_enable(self):
- with self.assertCalls(
- (self.call.device.ReadFile(self.device.LOCAL_PROPERTIES_PATH),
- 'some.example.prop=with an example value\n'
- 'some.other.prop=value_ok\n'),
- self.call.device.WriteFile(
- self.device.LOCAL_PROPERTIES_PATH,
- 'some.example.prop=with an example value\n'
- 'some.other.prop=value_ok\n'
- 'dalvik.vm.enableassertions=all\n'),
- (self.call.device.GetProp('dalvik.vm.enableassertions'), ''),
- self.call.device.SetProp('dalvik.vm.enableassertions', 'all')):
- self.assertTrue(self.device.SetJavaAsserts(True))
-
- def testSetJavaAsserts_disable(self):
- with self.assertCalls(
- (self.call.device.ReadFile(self.device.LOCAL_PROPERTIES_PATH),
- 'some.example.prop=with an example value\n'
- 'dalvik.vm.enableassertions=all\n'
- 'some.other.prop=value_ok\n'),
- self.call.device.WriteFile(
- self.device.LOCAL_PROPERTIES_PATH,
- 'some.example.prop=with an example value\n'
- 'some.other.prop=value_ok\n'),
- (self.call.device.GetProp('dalvik.vm.enableassertions'), 'all'),
- self.call.device.SetProp('dalvik.vm.enableassertions', '')):
- self.assertTrue(self.device.SetJavaAsserts(False))
-
- def testSetJavaAsserts_alreadyEnabled(self):
- with self.assertCalls(
- (self.call.device.ReadFile(self.device.LOCAL_PROPERTIES_PATH),
- 'some.example.prop=with an example value\n'
- 'dalvik.vm.enableassertions=all\n'
- 'some.other.prop=value_ok\n'),
- (self.call.device.GetProp('dalvik.vm.enableassertions'), 'all')):
- self.assertFalse(self.device.SetJavaAsserts(True))
-
- def testSetJavaAsserts_malformedLocalProp(self):
- with self.assertCalls(
- (self.call.device.ReadFile(self.device.LOCAL_PROPERTIES_PATH),
- 'some.example.prop=with an example value\n'
- 'malformed_property\n'
- 'dalvik.vm.enableassertions=all\n'
- 'some.other.prop=value_ok\n'),
- (self.call.device.GetProp('dalvik.vm.enableassertions'), 'all')):
- self.assertFalse(self.device.SetJavaAsserts(True))
-
-
-class DeviceUtilsEnsureCacheInitializedTest(DeviceUtilsTest):
-
- def testEnsureCacheInitialized_noCache_success(self):
- self.assertIsNone(self.device._cache['token'])
- with self.assertCall(
- self.call.device.RunShellCommand(
- AnyStringWith('getprop'),
- shell=True, check_return=True, large_output=True),
- ['/sdcard', 'TOKEN']):
- self.device._EnsureCacheInitialized()
- self.assertIsNotNone(self.device._cache['token'])
-
- def testEnsureCacheInitialized_noCache_failure(self):
- self.assertIsNone(self.device._cache['token'])
- with self.assertCall(
- self.call.device.RunShellCommand(
- AnyStringWith('getprop'),
- shell=True, check_return=True, large_output=True),
- self.TimeoutError()):
- with self.assertRaises(device_errors.CommandTimeoutError):
- self.device._EnsureCacheInitialized()
- self.assertIsNone(self.device._cache['token'])
-
- def testEnsureCacheInitialized_cache(self):
- self.device._cache['token'] = 'TOKEN'
- with self.assertCalls():
- self.device._EnsureCacheInitialized()
- self.assertIsNotNone(self.device._cache['token'])
-
-
-class DeviceUtilsGetPropTest(DeviceUtilsTest):
-
- def testGetProp_exists(self):
- with self.assertCall(
- self.call.device.RunShellCommand(
- ['getprop', 'test.property'], check_return=True, single_line=True,
- timeout=self.device._default_timeout,
- retries=self.device._default_retries),
- 'property_value'):
- self.assertEqual('property_value',
- self.device.GetProp('test.property'))
-
- def testGetProp_doesNotExist(self):
- with self.assertCall(
- self.call.device.RunShellCommand(
- ['getprop', 'property.does.not.exist'],
- check_return=True, single_line=True,
- timeout=self.device._default_timeout,
- retries=self.device._default_retries),
- ''):
- self.assertEqual('', self.device.GetProp('property.does.not.exist'))
-
- def testGetProp_cachedRoProp(self):
- with self.assertCalls(
- self.EnsureCacheInitialized(props=['[ro.build.type]: [userdebug]'])):
- self.assertEqual('userdebug',
- self.device.GetProp('ro.build.type', cache=True))
- self.assertEqual('userdebug',
- self.device.GetProp('ro.build.type', cache=True))
-
-
-class DeviceUtilsSetPropTest(DeviceUtilsTest):
-
- def testSetProp(self):
- with self.assertCall(
- self.call.device.RunShellCommand(
- ['setprop', 'test.property', 'test value'], check_return=True)):
- self.device.SetProp('test.property', 'test value')
-
- def testSetProp_check_succeeds(self):
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- ['setprop', 'test.property', 'new_value'], check_return=True)),
- (self.call.device.GetProp('test.property', cache=False), 'new_value')):
- self.device.SetProp('test.property', 'new_value', check=True)
-
- def testSetProp_check_fails(self):
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- ['setprop', 'test.property', 'new_value'], check_return=True)),
- (self.call.device.GetProp('test.property', cache=False), 'old_value')):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device.SetProp('test.property', 'new_value', check=True)
-
-
-class DeviceUtilsGetPidsTest(DeviceUtilsTest):
- def setUp(self):
- super(DeviceUtilsGetPidsTest, self).setUp()
- self.sample_output = [
- 'USER PID PPID VSIZE RSS WCHAN PC NAME',
- 'user 1001 100 1024 1024 ffffffff 00000000 one.match',
- 'user 1002 100 1024 1024 ffffffff 00000000 two.match',
- 'user 1003 100 1024 1024 ffffffff 00000000 three.match',
- 'user 1234 100 1024 1024 ffffffff 00000000 my$process',
- 'user 1000 100 1024 1024 ffffffff 00000000 foo',
- 'user 1236 100 1024 1024 ffffffff 00000000 foo',
- ]
-
- def _grepOutput(self, substring):
- return [line for line in self.sample_output if substring in line]
-
- def testGetPids_sdkGreaterThanNougatMR1(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=(version_codes.NOUGAT_MR1 + 1)):
- with self.patch_call(self.call.device.build_id,
- return_value='ZZZ99Z'):
- with self.assertCall(
- self.call.device._RunPipedShellCommand(
- 'ps -e | grep -F example.process'), []):
- self.device.GetPids('example.process')
-
- def testGetPids_noMatches(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.LOLLIPOP):
- with self.assertCall(
- self.call.device._RunPipedShellCommand('ps | grep -F does.not.match'),
- self._grepOutput('does.not.match')):
- self.assertEqual({}, self.device.GetPids('does.not.match'))
-
- def testGetPids_oneMatch(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.LOLLIPOP):
- with self.assertCall(
- self.call.device._RunPipedShellCommand('ps | grep -F one.match'),
- self._grepOutput('one.match')):
- self.assertEqual(
- {'one.match': ['1001']},
- self.device.GetPids('one.match'))
-
- def testGetPids_multipleMatches(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.LOLLIPOP):
- with self.assertCall(
- self.call.device._RunPipedShellCommand('ps | grep -F match'),
- self._grepOutput('match')):
- self.assertEqual(
- {'one.match': ['1001'],
- 'two.match': ['1002'],
- 'three.match': ['1003']},
- self.device.GetPids('match'))
-
- def testGetPids_quotable(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.LOLLIPOP):
- with self.assertCall(
- self.call.device._RunPipedShellCommand("ps | grep -F 'my$process'"),
- self._grepOutput('my$process')):
- self.assertEqual(
- {'my$process': ['1234']}, self.device.GetPids('my$process'))
-
- def testGetPids_multipleInstances(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.LOLLIPOP):
- with self.assertCall(
- self.call.device._RunPipedShellCommand('ps | grep -F foo'),
- self._grepOutput('foo')):
- self.assertEqual(
- {'foo': ['1000', '1236']},
- self.device.GetPids('foo'))
-
- def testGetPids_allProcesses(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.LOLLIPOP):
- with self.assertCall(
- self.call.device.RunShellCommand(
- ['ps'], check_return=True, large_output=True),
- self.sample_output):
- self.assertEqual(
- {'one.match': ['1001'],
- 'two.match': ['1002'],
- 'three.match': ['1003'],
- 'my$process': ['1234'],
- 'foo': ['1000', '1236']},
- self.device.GetPids())
-
- def testGetApplicationPids_notFound(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.LOLLIPOP):
- with self.assertCall(
- self.call.device._RunPipedShellCommand('ps | grep -F match'),
- self._grepOutput('match')):
- # No PIDs found, process name should be exact match.
- self.assertEqual([], self.device.GetApplicationPids('match'))
-
- def testGetApplicationPids_foundOne(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.LOLLIPOP):
- with self.assertCall(
- self.call.device._RunPipedShellCommand('ps | grep -F one.match'),
- self._grepOutput('one.match')):
- self.assertEqual(['1001'], self.device.GetApplicationPids('one.match'))
-
- def testGetApplicationPids_foundMany(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.LOLLIPOP):
- with self.assertCall(
- self.call.device._RunPipedShellCommand('ps | grep -F foo'),
- self._grepOutput('foo')):
- self.assertEqual(
- ['1000', '1236'],
- self.device.GetApplicationPids('foo'))
-
- def testGetApplicationPids_atMostOneNotFound(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.LOLLIPOP):
- with self.assertCall(
- self.call.device._RunPipedShellCommand('ps | grep -F match'),
- self._grepOutput('match')):
- # No PIDs found, process name should be exact match.
- self.assertEqual(
- None,
- self.device.GetApplicationPids('match', at_most_one=True))
-
- def testGetApplicationPids_atMostOneFound(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.LOLLIPOP):
- with self.assertCall(
- self.call.device._RunPipedShellCommand('ps | grep -F one.match'),
- self._grepOutput('one.match')):
- self.assertEqual(
- '1001',
- self.device.GetApplicationPids('one.match', at_most_one=True))
-
- def testGetApplicationPids_atMostOneFoundTooMany(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.LOLLIPOP):
- with self.assertRaises(device_errors.CommandFailedError):
- with self.assertCall(
- self.call.device._RunPipedShellCommand('ps | grep -F foo'),
- self._grepOutput('foo')):
- self.device.GetApplicationPids('foo', at_most_one=True)
-
-
-class DeviceUtilsGetSetEnforce(DeviceUtilsTest):
-
- def testGetEnforce_Enforcing(self):
- with self.assertCall(self.call.adb.Shell('getenforce'), 'Enforcing'):
- self.assertEqual(True, self.device.GetEnforce())
-
- def testGetEnforce_Permissive(self):
- with self.assertCall(self.call.adb.Shell('getenforce'), 'Permissive'):
- self.assertEqual(False, self.device.GetEnforce())
-
- def testGetEnforce_Disabled(self):
- with self.assertCall(self.call.adb.Shell('getenforce'), 'Disabled'):
- self.assertEqual(None, self.device.GetEnforce())
-
- def testSetEnforce_Enforcing(self):
- with self.assertCalls(
- (self.call.device.NeedsSU(), False),
- (self.call.adb.Shell('setenforce 1'), '')):
- self.device.SetEnforce(enabled=True)
-
- def testSetEnforce_Permissive(self):
- with self.assertCalls(
- (self.call.device.NeedsSU(), False),
- (self.call.adb.Shell('setenforce 0'), '')):
- self.device.SetEnforce(enabled=False)
-
- def testSetEnforce_EnforcingWithInt(self):
- with self.assertCalls(
- (self.call.device.NeedsSU(), False),
- (self.call.adb.Shell('setenforce 1'), '')):
- self.device.SetEnforce(enabled=1)
-
- def testSetEnforce_PermissiveWithInt(self):
- with self.assertCalls(
- (self.call.device.NeedsSU(), False),
- (self.call.adb.Shell('setenforce 0'), '')):
- self.device.SetEnforce(enabled=0)
-
- def testSetEnforce_EnforcingWithStr(self):
- with self.assertCalls(
- (self.call.device.NeedsSU(), False),
- (self.call.adb.Shell('setenforce 1'), '')):
- self.device.SetEnforce(enabled='1')
-
- def testSetEnforce_PermissiveWithStr(self):
- with self.assertCalls(
- (self.call.device.NeedsSU(), False),
- (self.call.adb.Shell('setenforce 0'), '')):
- self.device.SetEnforce(enabled='0') # Not recommended but it works!
-
-
-class DeviceUtilsTakeScreenshotTest(DeviceUtilsTest):
-
- def testTakeScreenshot_fileNameProvided(self):
- with self.assertCalls(
- (mock.call.devil.android.device_temp_file.DeviceTempFile(
- self.adb, suffix='.png'),
- MockTempFile('/tmp/path/temp-123.png')),
- (self.call.adb.Shell('/system/bin/screencap -p /tmp/path/temp-123.png'),
- ''),
- self.call.device.PullFile('/tmp/path/temp-123.png',
- '/test/host/screenshot.png')):
- self.device.TakeScreenshot('/test/host/screenshot.png')
-
-
-class DeviceUtilsGetMemoryUsageForPidTest(DeviceUtilsTest):
-
- def setUp(self):
- super(DeviceUtilsGetMemoryUsageForPidTest, self).setUp()
-
- def testGetMemoryUsageForPid_validPid(self):
- with self.assertCalls(
- (self.call.device._RunPipedShellCommand(
- 'showmap 1234 | grep TOTAL', as_root=True),
- ['100 101 102 103 104 105 106 107 TOTAL']),
- (self.call.device.ReadFile('/proc/1234/status', as_root=True),
- 'VmHWM: 1024 kB\n')):
- self.assertEqual(
- {
- 'Size': 100,
- 'Rss': 101,
- 'Pss': 102,
- 'Shared_Clean': 103,
- 'Shared_Dirty': 104,
- 'Private_Clean': 105,
- 'Private_Dirty': 106,
- 'VmHWM': 1024
- },
- self.device.GetMemoryUsageForPid(1234))
-
- def testGetMemoryUsageForPid_noSmaps(self):
- with self.assertCalls(
- (self.call.device._RunPipedShellCommand(
- 'showmap 4321 | grep TOTAL', as_root=True),
- ['cannot open /proc/4321/smaps: No such file or directory']),
- (self.call.device.ReadFile('/proc/4321/status', as_root=True),
- 'VmHWM: 1024 kb\n')):
- self.assertEquals({'VmHWM': 1024}, self.device.GetMemoryUsageForPid(4321))
-
- def testGetMemoryUsageForPid_noStatus(self):
- with self.assertCalls(
- (self.call.device._RunPipedShellCommand(
- 'showmap 4321 | grep TOTAL', as_root=True),
- ['100 101 102 103 104 105 106 107 TOTAL']),
- (self.call.device.ReadFile('/proc/4321/status', as_root=True),
- self.CommandError())):
- self.assertEquals(
- {
- 'Size': 100,
- 'Rss': 101,
- 'Pss': 102,
- 'Shared_Clean': 103,
- 'Shared_Dirty': 104,
- 'Private_Clean': 105,
- 'Private_Dirty': 106,
- },
- self.device.GetMemoryUsageForPid(4321))
-
-
-class DeviceUtilsDismissCrashDialogIfNeededTest(DeviceUtilsTest):
-
- def testDismissCrashDialogIfNeeded_crashedPageckageNotFound(self):
- sample_dumpsys_output = '''
-WINDOW MANAGER WINDOWS (dumpsys window windows)
- Window #11 Window{f8b647a u0 SearchPanel}:
- mDisplayId=0 mSession=Session{8 94:122} mClient=android.os.BinderProxy@1ba5
- mOwnerUid=100 mShowToOwnerOnly=false package=com.android.systemui appop=NONE
- mAttrs=WM.LayoutParams{(0,0)(fillxfill) gr=#53 sim=#31 ty=2024 fl=100
- Requested w=1080 h=1920 mLayoutSeq=426
- mBaseLayer=211000 mSubLayer=0 mAnimLayer=211000+0=211000 mLastLayer=211000
-'''
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- ['dumpsys', 'window', 'windows'], check_return=True,
- large_output=True), sample_dumpsys_output.split('\n'))):
- package_name = self.device.DismissCrashDialogIfNeeded()
- self.assertIsNone(package_name)
-
- def testDismissCrashDialogIfNeeded_crashedPageckageFound(self):
- sample_dumpsys_output = '''
-WINDOW MANAGER WINDOWS (dumpsys window windows)
- Window #11 Window{f8b647a u0 SearchPanel}:
- mDisplayId=0 mSession=Session{8 94:122} mClient=android.os.BinderProxy@1ba5
- mOwnerUid=102 mShowToOwnerOnly=false package=com.android.systemui appop=NONE
- mAttrs=WM.LayoutParams{(0,0)(fillxfill) gr=#53 sim=#31 ty=2024 fl=100
- Requested w=1080 h=1920 mLayoutSeq=426
- mBaseLayer=211000 mSubLayer=0 mAnimLayer=211000+0=211000 mLastLayer=211000
- mHasPermanentDpad=false
- mCurrentFocus=Window{3a27740f u0 Application Error: com.android.chrome}
- mFocusedApp=AppWindowToken{470af6f token=Token{272ec24e ActivityRecord{t894}}}
-'''
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- ['dumpsys', 'window', 'windows'], check_return=True,
- large_output=True), sample_dumpsys_output.split('\n')),
- (self.call.device.RunShellCommand(
- ['input', 'keyevent', '22'], check_return=True)),
- (self.call.device.RunShellCommand(
- ['input', 'keyevent', '22'], check_return=True)),
- (self.call.device.RunShellCommand(
- ['input', 'keyevent', '66'], check_return=True)),
- (self.call.device.RunShellCommand(
- ['dumpsys', 'window', 'windows'], check_return=True,
- large_output=True), [])):
- package_name = self.device.DismissCrashDialogIfNeeded()
- self.assertEqual(package_name, 'com.android.chrome')
-
-
-class DeviceUtilsClientCache(DeviceUtilsTest):
-
- def testClientCache_twoCaches(self):
- self.device._cache['test'] = 0
- client_cache_one = self.device.GetClientCache('ClientOne')
- client_cache_one['test'] = 1
- client_cache_two = self.device.GetClientCache('ClientTwo')
- client_cache_two['test'] = 2
- self.assertEqual(self.device._cache['test'], 0)
- self.assertEqual(client_cache_one, {'test': 1})
- self.assertEqual(client_cache_two, {'test': 2})
- self.device._ClearCache()
- self.assertTrue('test' not in self.device._cache)
- self.assertEqual(client_cache_one, {})
- self.assertEqual(client_cache_two, {})
-
- def testClientCache_multipleInstances(self):
- client_cache_one = self.device.GetClientCache('ClientOne')
- client_cache_one['test'] = 1
- client_cache_two = self.device.GetClientCache('ClientOne')
- self.assertEqual(client_cache_one, {'test': 1})
- self.assertEqual(client_cache_two, {'test': 1})
- self.device._ClearCache()
- self.assertEqual(client_cache_one, {})
- self.assertEqual(client_cache_two, {})
-
-
-class DeviceUtilsHealthyDevicesTest(mock_calls.TestCase):
-
- def testHealthyDevices_emptyBlacklist_defaultDeviceArg(self):
- test_serials = ['0123456789abcdef', 'fedcba9876543210']
- with self.assertCalls(
- (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
- [_AdbWrapperMock(s) for s in test_serials])):
- blacklist = mock.NonCallableMock(**{'Read.return_value': []})
- devices = device_utils.DeviceUtils.HealthyDevices(blacklist)
- for serial, device in zip(test_serials, devices):
- self.assertTrue(isinstance(device, device_utils.DeviceUtils))
- self.assertEquals(serial, device.adb.GetDeviceSerial())
-
- def testHealthyDevices_blacklist_defaultDeviceArg(self):
- test_serials = ['0123456789abcdef', 'fedcba9876543210']
- with self.assertCalls(
- (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
- [_AdbWrapperMock(s) for s in test_serials])):
- blacklist = mock.NonCallableMock(
- **{'Read.return_value': ['fedcba9876543210']})
- devices = device_utils.DeviceUtils.HealthyDevices(blacklist)
- self.assertEquals(1, len(devices))
- self.assertTrue(isinstance(devices[0], device_utils.DeviceUtils))
- self.assertEquals('0123456789abcdef', devices[0].adb.GetDeviceSerial())
-
- def testHealthyDevices_noneDeviceArg_multiple_attached(self):
- test_serials = ['0123456789abcdef', 'fedcba9876543210']
- with self.assertCalls(
- (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
- [_AdbWrapperMock(s) for s in test_serials]),
- (mock.call.devil.android.device_errors.MultipleDevicesError(mock.ANY),
- _MockMultipleDevicesError())):
- with self.assertRaises(_MockMultipleDevicesError):
- device_utils.DeviceUtils.HealthyDevices(device_arg=None)
-
- def testHealthyDevices_noneDeviceArg_one_attached(self):
- test_serials = ['0123456789abcdef']
- with self.assertCalls(
- (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
- [_AdbWrapperMock(s) for s in test_serials])):
- devices = device_utils.DeviceUtils.HealthyDevices(device_arg=None)
- self.assertEquals(1, len(devices))
-
- def testHealthyDevices_noneDeviceArg_no_attached(self):
- test_serials = []
- with self.assertCalls(
- (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
- [_AdbWrapperMock(s) for s in test_serials])):
- with self.assertRaises(device_errors.NoDevicesError):
- device_utils.DeviceUtils.HealthyDevices(device_arg=None)
-
- def testHealthyDevices_noneDeviceArg_multiple_attached_ANDROID_SERIAL(self):
- try:
- os.environ['ANDROID_SERIAL'] = '0123456789abcdef'
- with self.assertCalls(): # Should skip adb devices when device is known.
- device_utils.DeviceUtils.HealthyDevices(device_arg=None)
- finally:
- del os.environ['ANDROID_SERIAL']
-
- def testHealthyDevices_stringDeviceArg(self):
- with self.assertCalls(): # Should skip adb devices when device is known.
- devices = device_utils.DeviceUtils.HealthyDevices(
- device_arg='0123456789abcdef')
- self.assertEquals(1, len(devices))
-
- def testHealthyDevices_EmptyListDeviceArg_multiple_attached(self):
- test_serials = ['0123456789abcdef', 'fedcba9876543210']
- with self.assertCalls(
- (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
- [_AdbWrapperMock(s) for s in test_serials])):
- devices = device_utils.DeviceUtils.HealthyDevices(device_arg=())
- self.assertEquals(2, len(devices))
-
- def testHealthyDevices_EmptyListDeviceArg_ANDROID_SERIAL(self):
- try:
- os.environ['ANDROID_SERIAL'] = '0123456789abcdef'
- with self.assertCalls(): # Should skip adb devices when device is known.
- devices = device_utils.DeviceUtils.HealthyDevices(device_arg=())
- finally:
- del os.environ['ANDROID_SERIAL']
- self.assertEquals(1, len(devices))
-
- def testHealthyDevices_EmptyListDeviceArg_no_attached(self):
- test_serials = []
- with self.assertCalls(
- (mock.call.devil.android.sdk.adb_wrapper.AdbWrapper.Devices(),
- [_AdbWrapperMock(s) for s in test_serials])):
- with self.assertRaises(device_errors.NoDevicesError):
- device_utils.DeviceUtils.HealthyDevices(device_arg=[])
-
- def testHealthyDevices_ListDeviceArg(self):
- device_arg = ['0123456789abcdef', 'fedcba9876543210']
- try:
- os.environ['ANDROID_SERIAL'] = 'should-not-apply'
- with self.assertCalls(): # Should skip adb devices when device is known.
- devices = device_utils.DeviceUtils.HealthyDevices(device_arg=device_arg)
- finally:
- del os.environ['ANDROID_SERIAL']
- self.assertEquals(2, len(devices))
-
-
-class DeviceUtilsRestartAdbdTest(DeviceUtilsTest):
-
- def testAdbdRestart(self):
- mock_temp_file = '/sdcard/temp-123.sh'
- with self.assertCalls(
- (mock.call.devil.android.device_temp_file.DeviceTempFile(
- self.adb, suffix='.sh'), MockTempFile(mock_temp_file)),
- self.call.device.WriteFile(mock.ANY, mock.ANY),
- (self.call.device.RunShellCommand(
- ['source', mock_temp_file], check_return=True, as_root=True)),
- self.call.adb.WaitForDevice()):
- self.device.RestartAdbd()
-
-
-class DeviceUtilsGrantPermissionsTest(DeviceUtilsTest):
-
- def testGrantPermissions_none(self):
- self.device.GrantPermissions('package', [])
-
- def testGrantPermissions_underM(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.LOLLIPOP):
- self.device.GrantPermissions('package', ['p1'])
-
- def testGrantPermissions_one(self):
- permissions_cmd = 'pm grant package p1'
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.MARSHMALLOW):
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- permissions_cmd, shell=True, check_return=True), [])):
- self.device.GrantPermissions('package', ['p1'])
-
- def testGrantPermissions_multiple(self):
- permissions_cmd = 'pm grant package p1&&pm grant package p2'
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.MARSHMALLOW):
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- permissions_cmd, shell=True, check_return=True), [])):
- self.device.GrantPermissions('package', ['p1', 'p2'])
-
- def testGrantPermissions_WriteExtrnalStorage(self):
- permissions_cmd = (
- 'pm grant package android.permission.WRITE_EXTERNAL_STORAGE&&'
- 'pm grant package android.permission.READ_EXTERNAL_STORAGE')
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.MARSHMALLOW):
- with self.assertCalls(
- (self.call.device.RunShellCommand(
- permissions_cmd, shell=True, check_return=True), [])):
- self.device.GrantPermissions(
- 'package', ['android.permission.WRITE_EXTERNAL_STORAGE'])
-
- def testGrantPermissions_BlackList(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.MARSHMALLOW):
- self.device.GrantPermissions(
- 'package', ['android.permission.ACCESS_MOCK_LOCATION'])
-
-
-class DeviecUtilsIsScreenOn(DeviceUtilsTest):
-
- _L_SCREEN_ON = ['test=test mInteractive=true']
- _K_SCREEN_ON = ['test=test mScreenOn=true']
- _L_SCREEN_OFF = ['mInteractive=false']
- _K_SCREEN_OFF = ['mScreenOn=false']
-
- def testIsScreenOn_onPreL(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.KITKAT):
- with self.assertCalls(
- (self.call.device._RunPipedShellCommand(
- 'dumpsys input_method | grep mScreenOn'), self._K_SCREEN_ON)):
- self.assertTrue(self.device.IsScreenOn())
-
- def testIsScreenOn_onL(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.LOLLIPOP):
- with self.assertCalls(
- (self.call.device._RunPipedShellCommand(
- 'dumpsys input_method | grep mInteractive'), self._L_SCREEN_ON)):
- self.assertTrue(self.device.IsScreenOn())
-
- def testIsScreenOn_offPreL(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.KITKAT):
- with self.assertCalls(
- (self.call.device._RunPipedShellCommand(
- 'dumpsys input_method | grep mScreenOn'), self._K_SCREEN_OFF)):
- self.assertFalse(self.device.IsScreenOn())
-
- def testIsScreenOn_offL(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.LOLLIPOP):
- with self.assertCalls(
- (self.call.device._RunPipedShellCommand(
- 'dumpsys input_method | grep mInteractive'), self._L_SCREEN_OFF)):
- self.assertFalse(self.device.IsScreenOn())
-
- def testIsScreenOn_noOutput(self):
- with self.patch_call(self.call.device.build_version_sdk,
- return_value=version_codes.LOLLIPOP):
- with self.assertCalls(
- (self.call.device._RunPipedShellCommand(
- 'dumpsys input_method | grep mInteractive'), [])):
- with self.assertRaises(device_errors.CommandFailedError):
- self.device.IsScreenOn()
-
-
-class DeviecUtilsSetScreen(DeviceUtilsTest):
-
- @mock.patch('time.sleep', mock.Mock())
- def testSetScren_alreadySet(self):
- with self.assertCalls(
- (self.call.device.IsScreenOn(), False)):
- self.device.SetScreen(False)
-
- @mock.patch('time.sleep', mock.Mock())
- def testSetScreen_on(self):
- with self.assertCalls(
- (self.call.device.IsScreenOn(), False),
- (self.call.device.SendKeyEvent(keyevent.KEYCODE_POWER), None),
- (self.call.device.IsScreenOn(), True)):
- self.device.SetScreen(True)
-
- @mock.patch('time.sleep', mock.Mock())
- def testSetScreen_off(self):
- with self.assertCalls(
- (self.call.device.IsScreenOn(), True),
- (self.call.device.SendKeyEvent(keyevent.KEYCODE_POWER), None),
- (self.call.device.IsScreenOn(), False)):
- self.device.SetScreen(False)
-
- @mock.patch('time.sleep', mock.Mock())
- def testSetScreen_slow(self):
- with self.assertCalls(
- (self.call.device.IsScreenOn(), True),
- (self.call.device.SendKeyEvent(keyevent.KEYCODE_POWER), None),
- (self.call.device.IsScreenOn(), True),
- (self.call.device.IsScreenOn(), True),
- (self.call.device.IsScreenOn(), False)):
- self.device.SetScreen(False)
-
-class DeviecUtilsLoadCacheData(DeviceUtilsTest):
-
- def testTokenMissing(self):
- with self.assertCalls(
- self.EnsureCacheInitialized()):
- self.assertFalse(self.device.LoadCacheData('{}'))
-
- def testTokenStale(self):
- with self.assertCalls(
- self.EnsureCacheInitialized()):
- self.assertFalse(self.device.LoadCacheData('{"token":"foo"}'))
-
- def testTokenMatches(self):
- with self.assertCalls(
- self.EnsureCacheInitialized()):
- self.assertTrue(self.device.LoadCacheData('{"token":"TOKEN"}'))
-
- def testDumpThenLoad(self):
- with self.assertCalls(
- self.EnsureCacheInitialized()):
- data = json.loads(self.device.DumpCacheData())
- data['token'] = 'TOKEN'
- self.assertTrue(self.device.LoadCacheData(json.dumps(data)))
-
-
-if __name__ == '__main__':
- logging.getLogger().setLevel(logging.DEBUG)
- unittest.main(verbosity=2)
diff --git a/third_party/catapult/devil/devil/android/fastboot_utils.py b/third_party/catapult/devil/devil/android/fastboot_utils.py
deleted file mode 100644
index 3bd3ee8b6e..0000000000
--- a/third_party/catapult/devil/devil/android/fastboot_utils.py
+++ /dev/null
@@ -1,256 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Provides a variety of device interactions based on fastboot."""
-# pylint: disable=unused-argument
-
-import collections
-import contextlib
-import fnmatch
-import logging
-import os
-import re
-
-from devil.android import decorators
-from devil.android import device_errors
-from devil.android.sdk import fastboot
-from devil.utils import timeout_retry
-
-logger = logging.getLogger(__name__)
-
-_DEFAULT_TIMEOUT = 30
-_DEFAULT_RETRIES = 3
-_FASTBOOT_REBOOT_TIMEOUT = 10 * _DEFAULT_TIMEOUT
-_KNOWN_PARTITIONS = collections.OrderedDict([
- ('bootloader', {'image': 'bootloader*.img', 'restart': True}),
- ('radio', {'image': 'radio*.img', 'restart': True}),
- ('boot', {'image': 'boot.img'}),
- ('recovery', {'image': 'recovery.img'}),
- ('system', {'image': 'system.img'}),
- ('userdata', {'image': 'userdata.img', 'wipe_only': True}),
- ('cache', {'image': 'cache.img', 'wipe_only': True}),
- ('vendor', {'image': 'vendor*.img', 'optional': True}),
- ])
-ALL_PARTITIONS = _KNOWN_PARTITIONS.keys()
-
-
-def _FindAndVerifyPartitionsAndImages(partitions, directory):
- """Validate partitions and images.
-
- Validate all partition names and partition directories. Cannot stop mid
- flash so its important to validate everything first.
-
- Args:
- Partitions: partitions to be tested.
- directory: directory containing the images.
-
- Returns:
- Dictionary with exact partition, image name mapping.
- """
-
- files = os.listdir(directory)
- return_dict = collections.OrderedDict()
-
- def find_file(pattern):
- for filename in files:
- if fnmatch.fnmatch(filename, pattern):
- return os.path.join(directory, filename)
- return None
- for partition in partitions:
- partition_info = _KNOWN_PARTITIONS[partition]
- image_file = find_file(partition_info['image'])
- if image_file:
- return_dict[partition] = image_file
- elif not partition_info.get('optional'):
- raise device_errors.FastbootCommandFailedError(
- 'Failed to flash device. Could not find image for %s.',
- partition_info['image'])
- return return_dict
-
-
-class FastbootUtils(object):
-
- _FASTBOOT_WAIT_TIME = 1
- _BOARD_VERIFICATION_FILE = 'android-info.txt'
-
- def __init__(self, device, fastbooter=None, default_timeout=_DEFAULT_TIMEOUT,
- default_retries=_DEFAULT_RETRIES):
- """FastbootUtils constructor.
-
- Example Usage to flash a device:
- fastboot = fastboot_utils.FastbootUtils(device)
- fastboot.FlashDevice('/path/to/build/directory')
-
- Args:
- device: A DeviceUtils instance.
- fastbooter: Optional fastboot object. If none is passed, one will
- be created.
- default_timeout: An integer containing the default number of seconds to
- wait for an operation to complete if no explicit value is provided.
- default_retries: An integer containing the default number or times an
- operation should be retried on failure if no explicit value is provided.
- """
- self._device = device
- self._board = device.product_board
- self._serial = str(device)
- self._default_timeout = default_timeout
- self._default_retries = default_retries
- if fastbooter:
- self.fastboot = fastbooter
- else:
- self.fastboot = fastboot.Fastboot(self._serial)
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def WaitForFastbootMode(self, timeout=None, retries=None):
- """Wait for device to boot into fastboot mode.
-
- This waits for the device serial to show up in fastboot devices output.
- """
- def fastboot_mode():
- return self._serial in self.fastboot.Devices()
-
- timeout_retry.WaitFor(fastboot_mode, wait_period=self._FASTBOOT_WAIT_TIME)
-
- @decorators.WithTimeoutAndRetriesFromInstance(
- min_default_timeout=_FASTBOOT_REBOOT_TIMEOUT)
- def EnableFastbootMode(self, timeout=None, retries=None):
- """Reboots phone into fastboot mode.
-
- Roots phone if needed, then reboots phone into fastboot mode and waits.
- """
- self._device.EnableRoot()
- self._device.adb.Reboot(to_bootloader=True)
- self.WaitForFastbootMode()
-
- @decorators.WithTimeoutAndRetriesFromInstance(
- min_default_timeout=_FASTBOOT_REBOOT_TIMEOUT)
- def Reboot(
- self, bootloader=False, wait_for_reboot=True, timeout=None, retries=None):
- """Reboots out of fastboot mode.
-
- It reboots the phone either back into fastboot, or to a regular boot. It
- then blocks until the device is ready.
-
- Args:
- bootloader: If set to True, reboots back into bootloader.
- """
- if bootloader:
- self.fastboot.RebootBootloader()
- self.WaitForFastbootMode()
- else:
- self.fastboot.Reboot()
- if wait_for_reboot:
- self._device.WaitUntilFullyBooted(timeout=_FASTBOOT_REBOOT_TIMEOUT)
-
- def _VerifyBoard(self, directory):
- """Validate as best as possible that the android build matches the device.
-
- Goes through build files and checks if the board name is mentioned in the
- |self._BOARD_VERIFICATION_FILE| or in the build archive.
-
- Args:
- directory: directory where build files are located.
- """
- files = os.listdir(directory)
- board_regex = re.compile(r'require board=(\w+)')
- if self._BOARD_VERIFICATION_FILE in files:
- with open(os.path.join(directory, self._BOARD_VERIFICATION_FILE)) as f:
- for line in f:
- m = board_regex.match(line)
- if m:
- board_name = m.group(1)
- if board_name == self._board:
- return True
- elif board_name:
- return False
- else:
- logger.warning('No board type found in %s.',
- self._BOARD_VERIFICATION_FILE)
- else:
- logger.warning('%s not found. Unable to use it to verify device.',
- self._BOARD_VERIFICATION_FILE)
-
- zip_regex = re.compile(r'.*%s.*\.zip' % re.escape(self._board))
- for f in files:
- if zip_regex.match(f):
- return True
-
- return False
-
- def _FlashPartitions(self, partitions, directory, wipe=False, force=False):
- """Flashes all given partiitons with all given images.
-
- Args:
- partitions: List of partitions to flash.
- directory: Directory where all partitions can be found.
- wipe: If set to true, will automatically detect if cache and userdata
- partitions are sent, and if so ignore them.
- force: boolean to decide to ignore board name safety checks.
-
- Raises:
- device_errors.CommandFailedError(): If image cannot be found or if bad
- partition name is give.
- """
- if not self._VerifyBoard(directory):
- if force:
- logger.warning('Could not verify build is meant to be installed on '
- 'the current device type, but force flag is set. '
- 'Flashing device. Possibly dangerous operation.')
- else:
- raise device_errors.CommandFailedError(
- 'Could not verify build is meant to be installed on the current '
- 'device type. Run again with force=True to force flashing with an '
- 'unverified board.')
-
- flash_image_files = _FindAndVerifyPartitionsAndImages(partitions, directory)
- partitions = flash_image_files.keys()
- for partition in partitions:
- if _KNOWN_PARTITIONS[partition].get('wipe_only') and not wipe:
- logger.info(
- 'Not flashing in wipe mode. Skipping partition %s.', partition)
- else:
- logger.info(
- 'Flashing %s with %s', partition, flash_image_files[partition])
- self.fastboot.Flash(partition, flash_image_files[partition])
- if _KNOWN_PARTITIONS[partition].get('restart', False):
- self.Reboot(bootloader=True)
-
- @contextlib.contextmanager
- def FastbootMode(self, wait_for_reboot=True, timeout=None, retries=None):
- """Context manager that enables fastboot mode, and reboots after.
-
- Example usage:
- with FastbootMode():
- Flash Device
- # Anything that runs after flashing.
- """
- self.EnableFastbootMode()
- self.fastboot.SetOemOffModeCharge(False)
- try:
- yield self
- finally:
- self.fastboot.SetOemOffModeCharge(True)
- self.Reboot(wait_for_reboot=wait_for_reboot)
-
- def FlashDevice(self, directory, partitions=None, wipe=False):
- """Flash device with build in |directory|.
-
- Directory must contain bootloader, radio, boot, recovery, system, userdata,
- and cache .img files from an android build. This is a dangerous operation so
- use with care.
-
- Args:
- fastboot: A FastbootUtils instance.
- directory: Directory with build files.
- wipe: Wipes cache and userdata if set to true.
- partitions: List of partitions to flash. Defaults to all.
- """
- if partitions is None:
- partitions = ALL_PARTITIONS
- # If a device is wiped, then it will no longer have adb keys so it cannot be
- # communicated with to verify that it is rebooted. It is up to the user of
- # this script to ensure that the adb keys are set on the device after using
- # this to wipe a device.
- with self.FastbootMode(wait_for_reboot=not wipe):
- self._FlashPartitions(partitions, directory, wipe=wipe)
diff --git a/third_party/catapult/devil/devil/android/fastboot_utils_test.py b/third_party/catapult/devil/devil/android/fastboot_utils_test.py
deleted file mode 100755
index 05629746e5..0000000000
--- a/third_party/catapult/devil/devil/android/fastboot_utils_test.py
+++ /dev/null
@@ -1,375 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""
-Unit tests for the contents of fastboot_utils.py
-"""
-
-# pylint: disable=protected-access,unused-argument
-
-import collections
-import io
-import logging
-import unittest
-
-from devil import devil_env
-from devil.android import device_errors
-from devil.android import device_utils
-from devil.android import fastboot_utils
-from devil.android.sdk import fastboot
-from devil.utils import mock_calls
-
-with devil_env.SysPath(devil_env.PYMOCK_PATH):
- import mock # pylint: disable=import-error
-
-_BOARD = 'board_type'
-_SERIAL = '0123456789abcdef'
-_PARTITIONS = [
- 'bootloader', 'radio', 'boot', 'recovery', 'system', 'userdata', 'cache']
-_IMAGES = collections.OrderedDict([
- ('bootloader', 'bootloader.img'),
- ('radio', 'radio.img'),
- ('boot', 'boot.img'),
- ('recovery', 'recovery.img'),
- ('system', 'system.img'),
- ('userdata', 'userdata.img'),
- ('cache', 'cache.img')
-])
-_VALID_FILES = [_BOARD + '.zip', 'android-info.txt']
-_INVALID_FILES = ['test.zip', 'android-info.txt']
-
-
-class MockFile(object):
-
- def __init__(self, name='/tmp/some/file'):
- self.file = mock.MagicMock(spec=file)
- self.file.name = name
-
- def __enter__(self):
- return self.file
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- pass
-
- @property
- def name(self):
- return self.file.name
-
-
-def _FastbootWrapperMock(test_serial):
- fastbooter = mock.Mock(spec=fastboot.Fastboot)
- fastbooter.__str__ = mock.Mock(return_value=test_serial)
- fastbooter.Devices.return_value = [test_serial]
- return fastbooter
-
-
-def _DeviceUtilsMock(test_serial):
- device = mock.Mock(spec=device_utils.DeviceUtils)
- device.__str__ = mock.Mock(return_value=test_serial)
- device.product_board = mock.Mock(return_value=_BOARD)
- device.adb = mock.Mock()
- return device
-
-
-class FastbootUtilsTest(mock_calls.TestCase):
-
- def setUp(self):
- self.device_utils_mock = _DeviceUtilsMock(_SERIAL)
- self.fastboot_wrapper = _FastbootWrapperMock(_SERIAL)
- self.fastboot = fastboot_utils.FastbootUtils(
- self.device_utils_mock, fastbooter=self.fastboot_wrapper,
- default_timeout=2, default_retries=0)
- self.fastboot._board = _BOARD
-
-
-class FastbootUtilsInitTest(FastbootUtilsTest):
-
- def testInitWithDeviceUtil(self):
- f = fastboot_utils.FastbootUtils(self.device_utils_mock)
- self.assertEqual(str(self.device_utils_mock), str(f._device))
-
- def testInitWithMissing_fails(self):
- with self.assertRaises(AttributeError):
- fastboot_utils.FastbootUtils(None)
- with self.assertRaises(AttributeError):
- fastboot_utils.FastbootUtils('')
-
- def testPartitionOrdering(self):
- parts = ['bootloader', 'radio', 'boot', 'recovery', 'system', 'userdata',
- 'cache', 'vendor']
- self.assertListEqual(fastboot_utils.ALL_PARTITIONS, parts)
-
-
-class FastbootUtilsWaitForFastbootMode(FastbootUtilsTest):
-
- # If this test fails by timing out after 1 second.
- @mock.patch('time.sleep', mock.Mock())
- def testWaitForFastbootMode(self):
- self.fastboot.WaitForFastbootMode()
-
-
-class FastbootUtilsEnableFastbootMode(FastbootUtilsTest):
-
- def testEnableFastbootMode(self):
- with self.assertCalls(
- self.call.fastboot._device.EnableRoot(),
- self.call.fastboot._device.adb.Reboot(to_bootloader=True),
- self.call.fastboot.WaitForFastbootMode()):
- self.fastboot.EnableFastbootMode()
-
-
-class FastbootUtilsReboot(FastbootUtilsTest):
-
- def testReboot_bootloader(self):
- with self.assertCalls(
- self.call.fastboot.fastboot.RebootBootloader(),
- self.call.fastboot.WaitForFastbootMode()):
- self.fastboot.Reboot(bootloader=True)
-
- def testReboot_normal(self):
- with self.assertCalls(
- self.call.fastboot.fastboot.Reboot(),
- self.call.fastboot._device.WaitUntilFullyBooted(timeout=mock.ANY)):
- self.fastboot.Reboot()
-
-
-class FastbootUtilsFlashPartitions(FastbootUtilsTest):
-
- def testFlashPartitions_wipe(self):
- with self.assertCalls(
- (self.call.fastboot._VerifyBoard('test'), True),
- (mock.call.devil.android.fastboot_utils.
- _FindAndVerifyPartitionsAndImages(_PARTITIONS, 'test'), _IMAGES),
- (self.call.fastboot.fastboot.Flash('bootloader', 'bootloader.img')),
- (self.call.fastboot.Reboot(bootloader=True)),
- (self.call.fastboot.fastboot.Flash('radio', 'radio.img')),
- (self.call.fastboot.Reboot(bootloader=True)),
- (self.call.fastboot.fastboot.Flash('boot', 'boot.img')),
- (self.call.fastboot.fastboot.Flash('recovery', 'recovery.img')),
- (self.call.fastboot.fastboot.Flash('system', 'system.img')),
- (self.call.fastboot.fastboot.Flash('userdata', 'userdata.img')),
- (self.call.fastboot.fastboot.Flash('cache', 'cache.img'))):
- self.fastboot._FlashPartitions(_PARTITIONS, 'test', wipe=True)
-
- def testFlashPartitions_noWipe(self):
- with self.assertCalls(
- (self.call.fastboot._VerifyBoard('test'), True),
- (mock.call.devil.android.fastboot_utils.
- _FindAndVerifyPartitionsAndImages(_PARTITIONS, 'test'), _IMAGES),
- (self.call.fastboot.fastboot.Flash('bootloader', 'bootloader.img')),
- (self.call.fastboot.Reboot(bootloader=True)),
- (self.call.fastboot.fastboot.Flash('radio', 'radio.img')),
- (self.call.fastboot.Reboot(bootloader=True)),
- (self.call.fastboot.fastboot.Flash('boot', 'boot.img')),
- (self.call.fastboot.fastboot.Flash('recovery', 'recovery.img')),
- (self.call.fastboot.fastboot.Flash('system', 'system.img'))):
- self.fastboot._FlashPartitions(_PARTITIONS, 'test')
-
-
-class FastbootUtilsFastbootMode(FastbootUtilsTest):
-
- def testFastbootMode_goodWait(self):
- with self.assertCalls(
- self.call.fastboot.EnableFastbootMode(),
- self.call.fastboot.fastboot.SetOemOffModeCharge(False),
- self.call.fastboot.fastboot.SetOemOffModeCharge(True),
- self.call.fastboot.Reboot(wait_for_reboot=True)):
- with self.fastboot.FastbootMode() as fbm:
- self.assertEqual(self.fastboot, fbm)
-
- def testFastbootMode_goodNoWait(self):
- with self.assertCalls(
- self.call.fastboot.EnableFastbootMode(),
- self.call.fastboot.fastboot.SetOemOffModeCharge(False),
- self.call.fastboot.fastboot.SetOemOffModeCharge(True),
- self.call.fastboot.Reboot(wait_for_reboot=False)):
- with self.fastboot.FastbootMode(wait_for_reboot=False) as fbm:
- self.assertEqual(self.fastboot, fbm)
-
- def testFastbootMode_exception(self):
- with self.assertCalls(
- self.call.fastboot.EnableFastbootMode(),
- self.call.fastboot.fastboot.SetOemOffModeCharge(False),
- self.call.fastboot.fastboot.SetOemOffModeCharge(True),
- self.call.fastboot.Reboot(wait_for_reboot=True)):
- with self.assertRaises(NotImplementedError):
- with self.fastboot.FastbootMode() as fbm:
- self.assertEqual(self.fastboot, fbm)
- raise NotImplementedError
-
- def testFastbootMode_exceptionInEnableFastboot(self):
- self.fastboot.EnableFastbootMode = mock.Mock()
- self.fastboot.EnableFastbootMode.side_effect = NotImplementedError
- with self.assertRaises(NotImplementedError):
- with self.fastboot.FastbootMode():
- pass
-
-
-class FastbootUtilsVerifyBoard(FastbootUtilsTest):
-
- def testVerifyBoard_bothValid(self):
- mock_file = io.StringIO(u'require board=%s\n' % _BOARD)
- with mock.patch('__builtin__.open', return_value=mock_file, create=True):
- with mock.patch('os.listdir', return_value=_VALID_FILES):
- self.assertTrue(self.fastboot._VerifyBoard('test'))
-
- def testVerifyBoard_BothNotValid(self):
- mock_file = io.StringIO(u'abc')
- with mock.patch('__builtin__.open', return_value=mock_file, create=True):
- with mock.patch('os.listdir', return_value=_INVALID_FILES):
- self.assertFalse(self.assertFalse(self.fastboot._VerifyBoard('test')))
-
- def testVerifyBoard_FileNotFoundZipValid(self):
- with mock.patch('os.listdir', return_value=[_BOARD + '.zip']):
- self.assertTrue(self.fastboot._VerifyBoard('test'))
-
- def testVerifyBoard_ZipNotFoundFileValid(self):
- mock_file = io.StringIO(u'require board=%s\n' % _BOARD)
- with mock.patch('__builtin__.open', return_value=mock_file, create=True):
- with mock.patch('os.listdir', return_value=['android-info.txt']):
- self.assertTrue(self.fastboot._VerifyBoard('test'))
-
- def testVerifyBoard_zipNotValidFileIs(self):
- mock_file = io.StringIO(u'require board=%s\n' % _BOARD)
- with mock.patch('__builtin__.open', return_value=mock_file, create=True):
- with mock.patch('os.listdir', return_value=_INVALID_FILES):
- self.assertTrue(self.fastboot._VerifyBoard('test'))
-
- def testVerifyBoard_fileNotValidZipIs(self):
- mock_file = io.StringIO(u'require board=WrongBoard')
- with mock.patch('__builtin__.open', return_value=mock_file, create=True):
- with mock.patch('os.listdir', return_value=_VALID_FILES):
- self.assertFalse(self.fastboot._VerifyBoard('test'))
-
- def testVerifyBoard_noBoardInFileValidZip(self):
- mock_file = io.StringIO(u'Regex wont match')
- with mock.patch('__builtin__.open', return_value=mock_file, create=True):
- with mock.patch('os.listdir', return_value=_VALID_FILES):
- self.assertTrue(self.fastboot._VerifyBoard('test'))
-
- def testVerifyBoard_noBoardInFileInvalidZip(self):
- mock_file = io.StringIO(u'Regex wont match')
- with mock.patch('__builtin__.open', return_value=mock_file, create=True):
- with mock.patch('os.listdir', return_value=_INVALID_FILES):
- self.assertFalse(self.fastboot._VerifyBoard('test'))
-
-
-class FastbootUtilsFindAndVerifyPartitionsAndImages(FastbootUtilsTest):
-
- def testFindAndVerifyPartitionsAndImages_validNoVendor(self):
- PARTITIONS = [
- 'bootloader', 'radio', 'boot', 'recovery', 'system', 'userdata',
- 'cache', 'vendor'
- ]
- files = [
- 'bootloader-test-.img',
- 'radio123.img',
- 'boot.img',
- 'recovery.img',
- 'system.img',
- 'userdata.img',
- 'cache.img'
- ]
- img_check = collections.OrderedDict([
- ('bootloader', 'test/bootloader-test-.img'),
- ('radio', 'test/radio123.img'),
- ('boot', 'test/boot.img'),
- ('recovery', 'test/recovery.img'),
- ('system', 'test/system.img'),
- ('userdata', 'test/userdata.img'),
- ('cache', 'test/cache.img'),
- ])
- parts_check = [
- 'bootloader', 'radio', 'boot', 'recovery', 'system', 'userdata',
- 'cache'
- ]
- with mock.patch('os.listdir', return_value=files):
- imgs = fastboot_utils._FindAndVerifyPartitionsAndImages(
- PARTITIONS, 'test')
- parts = imgs.keys()
- self.assertDictEqual(imgs, img_check)
- self.assertListEqual(parts, parts_check)
-
- def testFindAndVerifyPartitionsAndImages_validVendor(self):
- PARTITIONS = [
- 'bootloader', 'radio', 'boot', 'recovery', 'system', 'userdata',
- 'cache', 'vendor'
- ]
- files = [
- 'bootloader-test-.img',
- 'radio123.img',
- 'boot.img',
- 'recovery.img',
- 'system.img',
- 'userdata.img',
- 'cache.img',
- 'vendor.img'
- ]
- img_check = {
- 'bootloader': 'test/bootloader-test-.img',
- 'radio': 'test/radio123.img',
- 'boot': 'test/boot.img',
- 'recovery': 'test/recovery.img',
- 'system': 'test/system.img',
- 'userdata': 'test/userdata.img',
- 'cache': 'test/cache.img',
- 'vendor': 'test/vendor.img',
- }
- parts_check = [
- 'bootloader', 'radio', 'boot', 'recovery', 'system', 'userdata',
- 'cache', 'vendor'
- ]
-
- with mock.patch('os.listdir', return_value=files):
- imgs = fastboot_utils._FindAndVerifyPartitionsAndImages(
- PARTITIONS, 'test')
- parts = imgs.keys()
- self.assertDictEqual(imgs, img_check)
- self.assertListEqual(parts, parts_check)
-
- def testFindAndVerifyPartitionsAndImages_badPartition(self):
- with mock.patch('os.listdir', return_value=['test']):
- with self.assertRaises(KeyError):
- fastboot_utils._FindAndVerifyPartitionsAndImages(['test'], 'test')
-
- def testFindAndVerifyPartitionsAndImages_noFile(self):
- with mock.patch('os.listdir', return_value=['test']):
- with self.assertRaises(device_errors.FastbootCommandFailedError):
- fastboot_utils._FindAndVerifyPartitionsAndImages(['cache'], 'test')
-
-
-class FastbootUtilsFlashDevice(FastbootUtilsTest):
-
- def testFlashDevice_wipe(self):
- with self.assertCalls(
- self.call.fastboot.EnableFastbootMode(),
- self.call.fastboot.fastboot.SetOemOffModeCharge(False),
- self.call.fastboot._FlashPartitions(mock.ANY, 'test', wipe=True),
- self.call.fastboot.fastboot.SetOemOffModeCharge(True),
- self.call.fastboot.Reboot(wait_for_reboot=False)):
- self.fastboot.FlashDevice('test', wipe=True)
-
- def testFlashDevice_noWipe(self):
- with self.assertCalls(
- self.call.fastboot.EnableFastbootMode(),
- self.call.fastboot.fastboot.SetOemOffModeCharge(False),
- self.call.fastboot._FlashPartitions(mock.ANY, 'test', wipe=False),
- self.call.fastboot.fastboot.SetOemOffModeCharge(True),
- self.call.fastboot.Reboot(wait_for_reboot=True)):
- self.fastboot.FlashDevice('test', wipe=False)
-
- def testFlashDevice_partitions(self):
- with self.assertCalls(
- self.call.fastboot.EnableFastbootMode(),
- self.call.fastboot.fastboot.SetOemOffModeCharge(False),
- self.call.fastboot._FlashPartitions(['boot'], 'test', wipe=False),
- self.call.fastboot.fastboot.SetOemOffModeCharge(True),
- self.call.fastboot.Reboot(wait_for_reboot=True)):
- self.fastboot.FlashDevice('test', partitions=['boot'], wipe=False)
-
-
-if __name__ == '__main__':
- logging.getLogger().setLevel(logging.DEBUG)
- unittest.main(verbosity=2)
diff --git a/third_party/catapult/devil/devil/android/flag_changer.py b/third_party/catapult/devil/devil/android/flag_changer.py
deleted file mode 100644
index b2ee8b163a..0000000000
--- a/third_party/catapult/devil/devil/android/flag_changer.py
+++ /dev/null
@@ -1,300 +0,0 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import contextlib
-import logging
-import posixpath
-import re
-
-from devil.android.sdk import version_codes
-
-
-logger = logging.getLogger(__name__)
-
-
-_CMDLINE_DIR = '/data/local/tmp'
-_CMDLINE_DIR_LEGACY = '/data/local'
-_RE_NEEDS_QUOTING = re.compile(r'[^\w-]') # Not in: alphanumeric or hyphens.
-_QUOTES = '"\'' # Either a single or a double quote.
-_ESCAPE = '\\' # A backslash.
-
-
-@contextlib.contextmanager
-def CustomCommandLineFlags(device, cmdline_name, flags):
- """Context manager to change Chrome's command line temporarily.
-
- Example:
-
- with flag_changer.TemporaryCommandLineFlags(device, name, flags):
- # Launching Chrome will use the provided flags.
-
- # Previous set of flags on the device is now restored.
-
- Args:
- device: A DeviceUtils instance.
- cmdline_name: Name of the command line file where to store flags.
- flags: A sequence of command line flags to set.
- """
- # On Android N and above, we need to temporarily set SELinux to permissive
- # so that Chrome is allowed to read the command line file.
- # TODO(crbug.com/699082): Remove when a solution to avoid this is implemented.
- needs_permissive = (
- device.build_version_sdk >= version_codes.NOUGAT and
- device.GetEnforce())
- if needs_permissive:
- device.SetEnforce(enabled=False)
- try:
- changer = FlagChanger(device, cmdline_name)
- try:
- changer.ReplaceFlags(flags)
- yield
- finally:
- changer.Restore()
- finally:
- if needs_permissive:
- device.SetEnforce(enabled=True)
-
-
-class FlagChanger(object):
- """Changes the flags Chrome runs with.
-
- Flags can be temporarily set for a particular set of unit tests. These
- tests should call Restore() to revert the flags to their original state
- once the tests have completed.
- """
-
- def __init__(self, device, cmdline_file):
- """Initializes the FlagChanger and records the original arguments.
-
- Args:
- device: A DeviceUtils instance.
- cmdline_file: Name of the command line file where to store flags.
- """
- self._device = device
-
- if posixpath.sep in cmdline_file:
- raise ValueError(
- 'cmdline_file should be a file name only, do not include path'
- ' separators in: %s' % cmdline_file)
- self._cmdline_path = posixpath.join(_CMDLINE_DIR, cmdline_file)
-
- cmdline_path_legacy = posixpath.join(_CMDLINE_DIR_LEGACY, cmdline_file)
- if self._device.PathExists(cmdline_path_legacy):
- logging.warning(
- 'Removing legacy command line file %r.', cmdline_path_legacy)
- self._device.RemovePath(cmdline_path_legacy, as_root=True)
-
- self._state_stack = [None] # Actual state is set by GetCurrentFlags().
- self.GetCurrentFlags()
-
- def GetCurrentFlags(self):
- """Read the current flags currently stored in the device.
-
- Also updates the internal state of the flag_changer.
-
- Returns:
- A list of flags.
- """
- if self._device.PathExists(self._cmdline_path):
- command_line = self._device.ReadFile(self._cmdline_path).strip()
- else:
- command_line = ''
- flags = _ParseFlags(command_line)
-
- # Store the flags as a set to facilitate adding and removing flags.
- self._state_stack[-1] = set(flags)
- return flags
-
- def ReplaceFlags(self, flags):
- """Replaces the flags in the command line with the ones provided.
- Saves the current flags state on the stack, so a call to Restore will
- change the state back to the one preceeding the call to ReplaceFlags.
-
- Args:
- flags: A sequence of command line flags to set, eg. ['--single-process'].
- Note: this should include flags only, not the name of a command
- to run (ie. there is no need to start the sequence with 'chrome').
-
- Returns:
- A list with the flags now stored on the device.
- """
- new_flags = set(flags)
- self._state_stack.append(new_flags)
- return self._UpdateCommandLineFile()
-
- def AddFlags(self, flags):
- """Appends flags to the command line if they aren't already there.
- Saves the current flags state on the stack, so a call to Restore will
- change the state back to the one preceeding the call to AddFlags.
-
- Args:
- flags: A sequence of flags to add on, eg. ['--single-process'].
-
- Returns:
- A list with the flags now stored on the device.
- """
- return self.PushFlags(add=flags)
-
- def RemoveFlags(self, flags):
- """Removes flags from the command line, if they exist.
- Saves the current flags state on the stack, so a call to Restore will
- change the state back to the one preceeding the call to RemoveFlags.
-
- Note that calling RemoveFlags after AddFlags will result in having
- two nested states.
-
- Args:
- flags: A sequence of flags to remove, eg. ['--single-process']. Note
- that we expect a complete match when removing flags; if you want
- to remove a switch with a value, you must use the exact string
- used to add it in the first place.
-
- Returns:
- A list with the flags now stored on the device.
- """
- return self.PushFlags(remove=flags)
-
- def PushFlags(self, add=None, remove=None):
- """Appends and removes flags to/from the command line if they aren't already
- there. Saves the current flags state on the stack, so a call to Restore
- will change the state back to the one preceeding the call to PushFlags.
-
- Args:
- add: A list of flags to add on, eg. ['--single-process'].
- remove: A list of flags to remove, eg. ['--single-process']. Note that we
- expect a complete match when removing flags; if you want to remove
- a switch with a value, you must use the exact string used to add
- it in the first place.
-
- Returns:
- A list with the flags now stored on the device.
- """
- new_flags = self._state_stack[-1].copy()
- if add:
- new_flags.update(add)
- if remove:
- new_flags.difference_update(remove)
- return self.ReplaceFlags(new_flags)
-
- def Restore(self):
- """Restores the flags to their state prior to the last AddFlags or
- RemoveFlags call.
-
- Returns:
- A list with the flags now stored on the device.
- """
- # The initial state must always remain on the stack.
- assert len(self._state_stack) > 1, (
- "Mismatch between calls to Add/RemoveFlags and Restore")
- self._state_stack.pop()
- return self._UpdateCommandLineFile()
-
- def _UpdateCommandLineFile(self):
- """Writes out the command line to the file, or removes it if empty.
-
- Returns:
- A list with the flags now stored on the device.
- """
- command_line = _SerializeFlags(self._state_stack[-1])
- if command_line is not None:
- self._device.WriteFile(self._cmdline_path, command_line)
- else:
- self._device.RemovePath(self._cmdline_path, force=True)
-
- current_flags = self.GetCurrentFlags()
- logger.info('Flags now set on the device: %s', current_flags)
- return current_flags
-
-
-def _ParseFlags(line):
- """Parse the string containing the command line into a list of flags.
-
- It's a direct port of CommandLine.java::tokenizeQuotedArguments.
-
- The first token is assumed to be the (unused) program name and stripped off
- from the list of flags.
-
- Args:
- line: A string containing the entire command line. The first token is
- assumed to be the program name.
-
- Returns:
- A list of flags, with quoting removed.
- """
- flags = []
- current_quote = None
- current_flag = None
-
- for c in line:
- # Detect start or end of quote block.
- if (current_quote is None and c in _QUOTES) or c == current_quote:
- if current_flag is not None and current_flag[-1] == _ESCAPE:
- # Last char was a backslash; pop it, and treat c as a literal.
- current_flag = current_flag[:-1] + c
- else:
- current_quote = c if current_quote is None else None
- elif current_quote is None and c.isspace():
- if current_flag is not None:
- flags.append(current_flag)
- current_flag = None
- else:
- if current_flag is None:
- current_flag = ''
- current_flag += c
-
- if current_flag is not None:
- if current_quote is not None:
- logger.warning('Unterminated quoted argument: ' + current_flag)
- flags.append(current_flag)
-
- # Return everything but the program name.
- return flags[1:]
-
-
-def _SerializeFlags(flags):
- """Serialize a sequence of flags into a command line string.
-
- Args:
- flags: A sequence of strings with individual flags.
-
- Returns:
- A line with the command line contents to save; or None if the sequence of
- flags is empty.
- """
- if flags:
- # The first command line argument doesn't matter as we are not actually
- # launching the chrome executable using this command line.
- args = ['_']
- args.extend(_QuoteFlag(f) for f in flags)
- return ' '.join(args)
- else:
- return None
-
-
-def _QuoteFlag(flag):
- """Validate and quote a single flag.
-
- Args:
- A string with the flag to quote.
-
- Returns:
- A string with the flag quoted so that it can be parsed by the algorithm
- in _ParseFlags; or None if the flag does not appear to be valid.
- """
- if '=' in flag:
- key, value = flag.split('=', 1)
- else:
- key, value = flag, None
-
- if not flag or _RE_NEEDS_QUOTING.search(key):
- # Probably not a valid flag, but quote the whole thing so it can be
- # parsed back correctly.
- return '"%s"' % flag.replace('"', r'\"')
-
- if value is None:
- return key
-
- if _RE_NEEDS_QUOTING.search(value):
- value = '"%s"' % value.replace('"', r'\"')
- return '='.join([key, value])
diff --git a/third_party/catapult/devil/devil/android/flag_changer_devicetest.py b/third_party/catapult/devil/devil/android/flag_changer_devicetest.py
deleted file mode 100644
index b75504b52a..0000000000
--- a/third_party/catapult/devil/devil/android/flag_changer_devicetest.py
+++ /dev/null
@@ -1,88 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-"""
-Unit tests for the contents of flag_changer.py.
-The test will invoke real devices
-"""
-
-import os
-import posixpath
-import sys
-import unittest
-
-if __name__ == '__main__':
- sys.path.append(
- os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', )))
-
-from devil.android import device_test_case
-from devil.android import device_utils
-from devil.android import flag_changer
-from devil.android.sdk import adb_wrapper
-
-
-_CMDLINE_FILE = 'dummy-command-line'
-
-
-class FlagChangerTest(device_test_case.DeviceTestCase):
-
- def setUp(self):
- super(FlagChangerTest, self).setUp()
- self.adb = adb_wrapper.AdbWrapper(self.serial)
- self.adb.WaitForDevice()
- self.device = device_utils.DeviceUtils(
- self.adb, default_timeout=10, default_retries=0)
- # pylint: disable=protected-access
- self.cmdline_path = posixpath.join(flag_changer._CMDLINE_DIR, _CMDLINE_FILE)
- self.cmdline_path_legacy = posixpath.join(
- flag_changer._CMDLINE_DIR_LEGACY, _CMDLINE_FILE)
-
- def tearDown(self):
- super(FlagChangerTest, self).tearDown()
- self.device.RemovePath(
- [self.cmdline_path, self.cmdline_path_legacy], force=True, as_root=True)
-
- def testFlagChanger_restoreFlags(self):
- if not self.device.HasRoot():
- self.skipTest('Test needs a rooted device')
-
- # Write some custom chrome command line flags.
- self.device.WriteFile(
- self.cmdline_path, 'chrome --some --old --flags')
-
- # Write some more flags on a command line file in the legacy location.
- self.device.WriteFile(
- self.cmdline_path_legacy, 'some --stray --flags', as_root=True)
- self.assertTrue(self.device.PathExists(self.cmdline_path_legacy))
-
- changer = flag_changer.FlagChanger(self.device, _CMDLINE_FILE)
-
- # Legacy command line file is removed, ensuring Chrome picks up the
- # right file.
- self.assertFalse(self.device.PathExists(self.cmdline_path_legacy))
-
- # Write some new files, and check they are set.
- new_flags = ['--my', '--new', '--flags=with special value']
- self.assertItemsEqual(
- changer.ReplaceFlags(new_flags),
- new_flags)
-
- # Restore and go back to the old flags.
- self.assertItemsEqual(
- changer.Restore(),
- ['--some', '--old', '--flags'])
-
- def testFlagChanger_removeFlags(self):
- self.device.RemovePath(self.cmdline_path, force=True)
- self.assertFalse(self.device.PathExists(self.cmdline_path))
-
- with flag_changer.CustomCommandLineFlags(
- self.device, _CMDLINE_FILE, ['--some', '--flags']):
- self.assertTrue(self.device.PathExists(self.cmdline_path))
-
- self.assertFalse(self.device.PathExists(self.cmdline_path))
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/third_party/catapult/devil/devil/android/flag_changer_test.py b/third_party/catapult/devil/devil/android/flag_changer_test.py
deleted file mode 100755
index 5342cf44d0..0000000000
--- a/third_party/catapult/devil/devil/android/flag_changer_test.py
+++ /dev/null
@@ -1,135 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import posixpath
-import unittest
-
-from devil.android import flag_changer
-
-
-_CMDLINE_FILE = 'chrome-command-line'
-
-
-class _FakeDevice(object):
- def __init__(self):
- self.build_type = 'user'
- self.has_root = True
- self.file_system = {}
-
- def HasRoot(self):
- return self.has_root
-
- def PathExists(self, filepath):
- return filepath in self.file_system
-
- def RemovePath(self, path, **_kwargs):
- self.file_system.pop(path)
-
- def WriteFile(self, path, contents, **_kwargs):
- self.file_system[path] = contents
-
- def ReadFile(self, path, **_kwargs):
- return self.file_system[path]
-
-
-class FlagChangerTest(unittest.TestCase):
- def setUp(self):
- self.device = _FakeDevice()
- # pylint: disable=protected-access
- self.cmdline_path = posixpath.join(flag_changer._CMDLINE_DIR, _CMDLINE_FILE)
- self.cmdline_path_legacy = posixpath.join(
- flag_changer._CMDLINE_DIR_LEGACY, _CMDLINE_FILE)
-
- def testFlagChanger_removeLegacyCmdLine(self):
- self.device.WriteFile(self.cmdline_path_legacy, 'chrome --old --stuff')
- self.assertTrue(self.device.PathExists(self.cmdline_path_legacy))
-
- changer = flag_changer.FlagChanger(self.device, 'chrome-command-line')
- self.assertEquals(
- changer._cmdline_path, # pylint: disable=protected-access
- self.cmdline_path)
- self.assertFalse(self.device.PathExists(self.cmdline_path_legacy))
-
- def testFlagChanger_mustBeFileName(self):
- with self.assertRaises(ValueError):
- flag_changer.FlagChanger(self.device, '/data/local/chrome-command-line')
-
-
-class ParseSerializeFlagsTest(unittest.TestCase):
- def _testQuoteFlag(self, flag, expected_quoted_flag):
- # Start with an unquoted flag, check that it's quoted as expected.
- # pylint: disable=protected-access
- quoted_flag = flag_changer._QuoteFlag(flag)
- self.assertEqual(quoted_flag, expected_quoted_flag)
- # Check that it survives a round-trip.
- parsed_flags = flag_changer._ParseFlags('_ %s' % quoted_flag)
- self.assertEqual(len(parsed_flags), 1)
- self.assertEqual(flag, parsed_flags[0])
-
- def testQuoteFlag_simple(self):
- self._testQuoteFlag('--simple-flag', '--simple-flag')
-
- def testQuoteFlag_withSimpleValue(self):
- self._testQuoteFlag('--key=value', '--key=value')
-
- def testQuoteFlag_withQuotedValue1(self):
- self._testQuoteFlag('--key=valueA valueB', '--key="valueA valueB"')
-
- def testQuoteFlag_withQuotedValue2(self):
- self._testQuoteFlag(
- '--key=this "should" work', r'--key="this \"should\" work"')
-
- def testQuoteFlag_withQuotedValue3(self):
- self._testQuoteFlag(
- "--key=this is 'fine' too", '''--key="this is 'fine' too"''')
-
- def testQuoteFlag_withQuotedValue4(self):
- self._testQuoteFlag(
- "--key='I really want to keep these quotes'",
- '''--key="'I really want to keep these quotes'"''')
-
- def testQuoteFlag_withQuotedValue5(self):
- self._testQuoteFlag(
- "--this is a strange=flag", '"--this is a strange=flag"')
-
- def testQuoteFlag_withEmptyValue(self):
- self._testQuoteFlag('--some-flag=', '--some-flag=')
-
- def _testParseCmdLine(self, command_line, expected_flags):
- # Start with a command line, check that flags are parsed as expected.
- # pylint: disable=protected-access
- flags = flag_changer._ParseFlags(command_line)
- self.assertItemsEqual(flags, expected_flags)
-
- # Check that flags survive a round-trip.
- # Note: Although new_command_line and command_line may not match, they
- # should describe the same set of flags.
- new_command_line = flag_changer._SerializeFlags(flags)
- new_flags = flag_changer._ParseFlags(new_command_line)
- self.assertItemsEqual(new_flags, expected_flags)
-
- def testParseCmdLine_simple(self):
- self._testParseCmdLine(
- 'chrome --foo --bar="a b" --baz=true --fine="ok"',
- ['--foo', '--bar=a b', '--baz=true', '--fine=ok'])
-
- def testParseCmdLine_withFancyQuotes(self):
- self._testParseCmdLine(
- r'''_ --foo="this 'is' ok"
- --bar='this \'is\' too'
- --baz="this \'is\' tricky"
- ''',
- ["--foo=this 'is' ok",
- "--bar=this 'is' too",
- r"--baz=this \'is\' tricky"])
-
- def testParseCmdLine_withUnterminatedQuote(self):
- self._testParseCmdLine(
- '_ --foo --bar="I forgot something',
- ['--foo', '--bar=I forgot something'])
-
-
-if __name__ == '__main__':
- unittest.main(verbosity=2)
diff --git a/third_party/catapult/devil/devil/android/forwarder.py b/third_party/catapult/devil/devil/android/forwarder.py
deleted file mode 100644
index 244f555af4..0000000000
--- a/third_party/catapult/devil/devil/android/forwarder.py
+++ /dev/null
@@ -1,464 +0,0 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# pylint: disable=W0212
-
-import fcntl
-import logging
-import os
-import psutil
-
-from devil import base_error
-from devil import devil_env
-from devil.android import device_errors
-from devil.android.constants import file_system
-from devil.android.sdk import adb_wrapper
-from devil.android.valgrind_tools import base_tool
-from devil.utils import cmd_helper
-
-logger = logging.getLogger(__name__)
-
-# If passed as the device port, this will tell the forwarder to allocate
-# a dynamic port on the device. The actual port can then be retrieved with
-# Forwarder.DevicePortForHostPort.
-DYNAMIC_DEVICE_PORT = 0
-
-
-def _GetProcessStartTime(pid):
- return psutil.Process(pid).create_time
-
-
-def _LogMapFailureDiagnostics(device):
- # The host forwarder daemon logs to /tmp/host_forwarder_log, so print the end
- # of that.
- try:
- with open('/tmp/host_forwarder_log') as host_forwarder_log:
- logger.info('Last 50 lines of the host forwarder daemon log:')
- for line in host_forwarder_log.read().splitlines()[-50:]:
- logger.info(' %s', line)
- except Exception: # pylint: disable=broad-except
- # Grabbing the host forwarder log is best-effort. Ignore all errors.
- logger.warning('Failed to get the contents of host_forwarder_log.')
-
- # The device forwarder daemon logs to the logcat, so print the end of that.
- try:
- logger.info('Last 50 lines of logcat:')
- for logcat_line in device.adb.Logcat(dump=True)[-50:]:
- logger.info(' %s', logcat_line)
- except device_errors.CommandFailedError:
- # Grabbing the device forwarder log is also best-effort. Ignore all errors.
- logger.warning('Failed to get the contents of the logcat.')
-
- # Log alive device forwarders.
- try:
- ps_out = device.RunShellCommand(['ps'], check_return=True)
- logger.info('Currently running device_forwarders:')
- for line in ps_out:
- if 'device_forwarder' in line:
- logger.info(' %s', line)
- except device_errors.CommandFailedError:
- logger.warning('Failed to list currently running device_forwarder '
- 'instances.')
-
-
-class _FileLock(object):
- """With statement-aware implementation of a file lock.
-
- File locks are needed for cross-process synchronization when the
- multiprocessing Python module is used.
- """
-
- def __init__(self, path):
- self._fd = -1
- self._path = path
-
- def __enter__(self):
- self._fd = os.open(self._path, os.O_RDONLY | os.O_CREAT)
- if self._fd < 0:
- raise Exception('Could not open file %s for reading' % self._path)
- fcntl.flock(self._fd, fcntl.LOCK_EX)
-
- def __exit__(self, _exception_type, _exception_value, traceback):
- fcntl.flock(self._fd, fcntl.LOCK_UN)
- os.close(self._fd)
-
-
-class HostForwarderError(base_error.BaseError):
- """Exception for failures involving host_forwarder."""
-
- def __init__(self, message):
- super(HostForwarderError, self).__init__(message)
-
-
-class Forwarder(object):
- """Thread-safe class to manage port forwards from the device to the host."""
-
- _DEVICE_FORWARDER_FOLDER = (file_system.TEST_EXECUTABLE_DIR +
- '/forwarder/')
- _DEVICE_FORWARDER_PATH = (file_system.TEST_EXECUTABLE_DIR +
- '/forwarder/device_forwarder')
- _LOCK_PATH = '/tmp/chrome.forwarder.lock'
- # Defined in host_forwarder_main.cc
- _HOST_FORWARDER_LOG = '/tmp/host_forwarder_log'
-
- _TIMEOUT = 60 # seconds
-
- _instance = None
-
- @staticmethod
- def Map(port_pairs, device, tool=None):
- """Runs the forwarder.
-
- Args:
- port_pairs: A list of tuples (device_port, host_port) to forward. Note
- that you can specify 0 as a device_port, in which case a
- port will by dynamically assigned on the device. You can
- get the number of the assigned port using the
- DevicePortForHostPort method.
- device: A DeviceUtils instance.
- tool: Tool class to use to get wrapper, if necessary, for executing the
- forwarder (see valgrind_tools.py).
-
- Raises:
- Exception on failure to forward the port.
- """
- if not tool:
- tool = base_tool.BaseTool()
- with _FileLock(Forwarder._LOCK_PATH):
- instance = Forwarder._GetInstanceLocked(tool)
- instance._InitDeviceLocked(device, tool)
-
- device_serial = str(device)
- map_arg_lists = [
- ['--adb=' + adb_wrapper.AdbWrapper.GetAdbPath(),
- '--serial-id=' + device_serial,
- '--map', str(device_port), str(host_port)]
- for device_port, host_port in port_pairs]
- logger.info('Forwarding using commands: %s', map_arg_lists)
-
- for map_arg_list in map_arg_lists:
- try:
- map_cmd = [instance._host_forwarder_path] + map_arg_list
- (exit_code, output) = cmd_helper.GetCmdStatusAndOutputWithTimeout(
- map_cmd, Forwarder._TIMEOUT)
- except cmd_helper.TimeoutError as e:
- raise HostForwarderError(
- '`%s` timed out:\n%s' % (' '.join(map_cmd), e.output))
- except OSError as e:
- if e.errno == 2:
- raise HostForwarderError(
- 'Unable to start host forwarder. '
- 'Make sure you have built host_forwarder.')
- else: raise
- if exit_code != 0:
- try:
- instance._KillDeviceLocked(device, tool)
- except device_errors.CommandFailedError:
- # We don't want the failure to kill the device forwarder to
- # supersede the original failure to map.
- logging.warning(
- 'Failed to kill the device forwarder after map failure: %s',
- str(e))
- _LogMapFailureDiagnostics(device)
- formatted_output = ('\n'.join(output) if isinstance(output, list)
- else output)
- raise HostForwarderError(
- '`%s` exited with %d:\n%s' % (
- ' '.join(map_cmd),
- exit_code,
- formatted_output))
- tokens = output.split(':')
- if len(tokens) != 2:
- raise HostForwarderError(
- 'Unexpected host forwarder output "%s", '
- 'expected "device_port:host_port"' % output)
- device_port = int(tokens[0])
- host_port = int(tokens[1])
- serial_with_port = (device_serial, device_port)
- instance._device_to_host_port_map[serial_with_port] = host_port
- instance._host_to_device_port_map[host_port] = serial_with_port
- logger.info('Forwarding device port: %d to host port: %d.',
- device_port, host_port)
-
- @staticmethod
- def UnmapDevicePort(device_port, device):
- """Unmaps a previously forwarded device port.
-
- Args:
- device: A DeviceUtils instance.
- device_port: A previously forwarded port (through Map()).
- """
- with _FileLock(Forwarder._LOCK_PATH):
- Forwarder._UnmapDevicePortLocked(device_port, device)
-
- @staticmethod
- def UnmapAllDevicePorts(device):
- """Unmaps all the previously forwarded ports for the provided device.
-
- Args:
- device: A DeviceUtils instance.
- port_pairs: A list of tuples (device_port, host_port) to unmap.
- """
- with _FileLock(Forwarder._LOCK_PATH):
- instance = Forwarder._GetInstanceLocked(None)
- unmap_all_cmd = [
- instance._host_forwarder_path,
- '--adb=%s' % adb_wrapper.AdbWrapper.GetAdbPath(),
- '--serial-id=%s' % device.serial,
- '--unmap-all'
- ]
- try:
- exit_code, output = cmd_helper.GetCmdStatusAndOutputWithTimeout(
- unmap_all_cmd, Forwarder._TIMEOUT)
- except cmd_helper.TimeoutError as e:
- raise HostForwarderError(
- '`%s` timed out:\n%s' % (' '.join(unmap_all_cmd), e.output))
- if exit_code != 0:
- error_msg = [
- '`%s` exited with %d' % (' '.join(unmap_all_cmd), exit_code)]
- if isinstance(output, list):
- error_msg += output
- else:
- error_msg += [output]
- raise HostForwarderError('\n'.join(error_msg))
-
- # Clean out any entries from the device & host map.
- device_map = instance._device_to_host_port_map
- host_map = instance._host_to_device_port_map
- for device_serial_and_port, host_port in device_map.items():
- device_serial = device_serial_and_port[0]
- if device_serial == device.serial:
- del device_map[device_serial_and_port]
- del host_map[host_port]
-
- # Kill the device forwarder.
- tool = base_tool.BaseTool()
- instance._KillDeviceLocked(device, tool)
-
- @staticmethod
- def DevicePortForHostPort(host_port):
- """Returns the device port that corresponds to a given host port."""
- with _FileLock(Forwarder._LOCK_PATH):
- serial_and_port = Forwarder._GetInstanceLocked(
- None)._host_to_device_port_map.get(host_port)
- return serial_and_port[1] if serial_and_port else None
-
- @staticmethod
- def RemoveHostLog():
- if os.path.exists(Forwarder._HOST_FORWARDER_LOG):
- os.unlink(Forwarder._HOST_FORWARDER_LOG)
-
- @staticmethod
- def GetHostLog():
- if not os.path.exists(Forwarder._HOST_FORWARDER_LOG):
- return ''
- with file(Forwarder._HOST_FORWARDER_LOG, 'r') as f:
- return f.read()
-
- @staticmethod
- def _GetInstanceLocked(tool):
- """Returns the singleton instance.
-
- Note that the global lock must be acquired before calling this method.
-
- Args:
- tool: Tool class to use to get wrapper, if necessary, for executing the
- forwarder (see valgrind_tools.py).
- """
- if not Forwarder._instance:
- Forwarder._instance = Forwarder(tool)
- return Forwarder._instance
-
- def __init__(self, tool):
- """Constructs a new instance of Forwarder.
-
- Note that Forwarder is a singleton therefore this constructor should be
- called only once.
-
- Args:
- tool: Tool class to use to get wrapper, if necessary, for executing the
- forwarder (see valgrind_tools.py).
- """
- assert not Forwarder._instance
- self._tool = tool
- self._initialized_devices = set()
- self._device_to_host_port_map = dict()
- self._host_to_device_port_map = dict()
- self._host_forwarder_path = devil_env.config.FetchPath('forwarder_host')
- assert os.path.exists(self._host_forwarder_path), 'Please build forwarder2'
- self._InitHostLocked()
-
- @staticmethod
- def _UnmapDevicePortLocked(device_port, device):
- """Internal method used by UnmapDevicePort().
-
- Note that the global lock must be acquired before calling this method.
- """
- instance = Forwarder._GetInstanceLocked(None)
- serial = str(device)
- serial_with_port = (serial, device_port)
- if not serial_with_port in instance._device_to_host_port_map:
- logger.error('Trying to unmap non-forwarded port %d', device_port)
- return
-
- host_port = instance._device_to_host_port_map[serial_with_port]
- del instance._device_to_host_port_map[serial_with_port]
- del instance._host_to_device_port_map[host_port]
-
- unmap_cmd = [
- instance._host_forwarder_path,
- '--adb=%s' % adb_wrapper.AdbWrapper.GetAdbPath(),
- '--serial-id=%s' % serial,
- '--unmap', str(device_port)
- ]
- try:
- (exit_code, output) = cmd_helper.GetCmdStatusAndOutputWithTimeout(
- unmap_cmd, Forwarder._TIMEOUT)
- except cmd_helper.TimeoutError as e:
- raise HostForwarderError(
- '`%s` timed out:\n%s' % (' '.join(unmap_cmd), e.output))
- if exit_code != 0:
- logger.error(
- '`%s` exited with %d:\n%s',
- ' '.join(unmap_cmd),
- exit_code,
- '\n'.join(output) if isinstance(output, list) else output)
-
- @staticmethod
- def _GetPidForLock():
- """Returns the PID used for host_forwarder initialization.
-
- The PID of the "sharder" is used to handle multiprocessing. The "sharder"
- is the initial process that forks that is the parent process.
- """
- return os.getpgrp()
-
- def _InitHostLocked(self):
- """Initializes the host forwarder daemon.
-
- Note that the global lock must be acquired before calling this method. This
- method kills any existing host_forwarder process that could be stale.
- """
- # See if the host_forwarder daemon was already initialized by a concurrent
- # process or thread (in case multi-process sharding is not used).
- pid_for_lock = Forwarder._GetPidForLock()
- fd = os.open(Forwarder._LOCK_PATH, os.O_RDWR | os.O_CREAT)
- with os.fdopen(fd, 'r+') as pid_file:
- pid_with_start_time = pid_file.readline()
- if pid_with_start_time:
- (pid, process_start_time) = pid_with_start_time.split(':')
- if pid == str(pid_for_lock):
- if process_start_time == str(_GetProcessStartTime(pid_for_lock)):
- return
- self._KillHostLocked()
- pid_file.seek(0)
- pid_file.write(
- '%s:%s' % (pid_for_lock, str(_GetProcessStartTime(pid_for_lock))))
- pid_file.truncate()
-
- def _InitDeviceLocked(self, device, tool):
- """Initializes the device_forwarder daemon for a specific device (once).
-
- Note that the global lock must be acquired before calling this method. This
- method kills any existing device_forwarder daemon on the device that could
- be stale, pushes the latest version of the daemon (to the device) and starts
- it.
-
- Args:
- device: A DeviceUtils instance.
- tool: Tool class to use to get wrapper, if necessary, for executing the
- forwarder (see valgrind_tools.py).
- """
- device_serial = str(device)
- if device_serial in self._initialized_devices:
- return
- try:
- self._KillDeviceLocked(device, tool)
- except device_errors.CommandFailedError:
- logger.warning('Failed to kill device forwarder. Rebooting.')
- device.Reboot()
- forwarder_device_path_on_host = devil_env.config.FetchPath(
- 'forwarder_device', device=device)
- forwarder_device_path_on_device = (
- Forwarder._DEVICE_FORWARDER_FOLDER
- if os.path.isdir(forwarder_device_path_on_host)
- else Forwarder._DEVICE_FORWARDER_PATH)
- device.PushChangedFiles([(
- forwarder_device_path_on_host,
- forwarder_device_path_on_device)])
-
- cmd = [Forwarder._DEVICE_FORWARDER_PATH]
- wrapper = tool.GetUtilWrapper()
- if wrapper:
- cmd.insert(0, wrapper)
- device.RunShellCommand(
- cmd, env={'LD_LIBRARY_PATH': Forwarder._DEVICE_FORWARDER_FOLDER},
- check_return=True)
- self._initialized_devices.add(device_serial)
-
- @staticmethod
- def KillHost():
- """Kills the forwarder process running on the host."""
- with _FileLock(Forwarder._LOCK_PATH):
- Forwarder._GetInstanceLocked(None)._KillHostLocked()
-
- def _KillHostLocked(self):
- """Kills the forwarder process running on the host.
-
- Note that the global lock must be acquired before calling this method.
- """
- logger.info('Killing host_forwarder.')
- try:
- kill_cmd = [self._host_forwarder_path, '--kill-server']
- (exit_code, _o) = cmd_helper.GetCmdStatusAndOutputWithTimeout(
- kill_cmd, Forwarder._TIMEOUT)
- if exit_code != 0:
- kill_cmd = ['pkill', '-9', 'host_forwarder']
- (exit_code, output) = cmd_helper.GetCmdStatusAndOutputWithTimeout(
- kill_cmd, Forwarder._TIMEOUT)
- if exit_code != 0:
- raise HostForwarderError(
- '%s exited with %d:\n%s' % (
- self._host_forwarder_path,
- exit_code,
- '\n'.join(output) if isinstance(output, list) else output))
- except cmd_helper.TimeoutError as e:
- raise HostForwarderError(
- '`%s` timed out:\n%s' % (' '.join(kill_cmd), e.output))
-
- @staticmethod
- def KillDevice(device, tool=None):
- """Kills the forwarder process running on the device.
-
- Args:
- device: Instance of DeviceUtils for talking to the device.
- tool: Wrapper tool (e.g. valgrind) that can be used to execute the device
- forwarder (see valgrind_tools.py).
- """
- with _FileLock(Forwarder._LOCK_PATH):
- Forwarder._GetInstanceLocked(None)._KillDeviceLocked(
- device, tool or base_tool.BaseTool())
-
- def _KillDeviceLocked(self, device, tool):
- """Kills the forwarder process running on the device.
-
- Note that the global lock must be acquired before calling this method.
-
- Args:
- device: Instance of DeviceUtils for talking to the device.
- tool: Wrapper tool (e.g. valgrind) that can be used to execute the device
- forwarder (see valgrind_tools.py).
- """
- logger.info('Killing device_forwarder.')
- self._initialized_devices.discard(device.serial)
- if not device.FileExists(Forwarder._DEVICE_FORWARDER_PATH):
- return
-
- cmd = [Forwarder._DEVICE_FORWARDER_PATH, '--kill-server']
- wrapper = tool.GetUtilWrapper()
- if wrapper:
- cmd.insert(0, wrapper)
- device.RunShellCommand(
- cmd, env={'LD_LIBRARY_PATH': Forwarder._DEVICE_FORWARDER_FOLDER},
- check_return=True)
diff --git a/third_party/catapult/devil/devil/android/install_commands.py b/third_party/catapult/devil/devil/android/install_commands.py
deleted file mode 100644
index c8da869602..0000000000
--- a/third_party/catapult/devil/devil/android/install_commands.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import os
-import posixpath
-
-from devil import devil_env
-from devil.android import device_errors
-from devil.android.constants import file_system
-
-BIN_DIR = '%s/bin' % file_system.TEST_EXECUTABLE_DIR
-_FRAMEWORK_DIR = '%s/framework' % file_system.TEST_EXECUTABLE_DIR
-
-_COMMANDS = {
- 'unzip': 'org.chromium.android.commands.unzip.Unzip',
-}
-
-_SHELL_COMMAND_FORMAT = (
-"""#!/system/bin/sh
-base=%s
-export CLASSPATH=$base/framework/chromium_commands.jar
-exec app_process $base/bin %s $@
-""")
-
-
-def Installed(device):
- paths = [posixpath.join(BIN_DIR, c) for c in _COMMANDS]
- paths.append(posixpath.join(_FRAMEWORK_DIR, 'chromium_commands.jar'))
- return device.PathExists(paths)
-
-
-def InstallCommands(device):
- if device.IsUserBuild():
- raise device_errors.CommandFailedError(
- 'chromium_commands currently requires a userdebug build.',
- device_serial=device.adb.GetDeviceSerial())
-
- chromium_commands_jar_path = devil_env.config.FetchPath('chromium_commands')
- if not os.path.exists(chromium_commands_jar_path):
- raise device_errors.CommandFailedError(
- '%s not found. Please build chromium_commands.'
- % chromium_commands_jar_path)
-
- device.RunShellCommand(
- ['mkdir', '-p', BIN_DIR, _FRAMEWORK_DIR], check_return=True)
- for command, main_class in _COMMANDS.iteritems():
- shell_command = _SHELL_COMMAND_FORMAT % (
- file_system.TEST_EXECUTABLE_DIR, main_class)
- shell_file = '%s/%s' % (BIN_DIR, command)
- device.WriteFile(shell_file, shell_command)
- device.RunShellCommand(
- ['chmod', '755', shell_file], check_return=True)
-
- device.adb.Push(
- chromium_commands_jar_path,
- '%s/chromium_commands.jar' % _FRAMEWORK_DIR)
diff --git a/third_party/catapult/devil/devil/android/logcat_monitor.py b/third_party/catapult/devil/devil/android/logcat_monitor.py
deleted file mode 100644
index 0aece87dee..0000000000
--- a/third_party/catapult/devil/devil/android/logcat_monitor.py
+++ /dev/null
@@ -1,255 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# pylint: disable=unused-argument
-
-import errno
-import logging
-import os
-import re
-import shutil
-import tempfile
-import threading
-import time
-
-from devil.android import decorators
-from devil.android import device_errors
-from devil.android.sdk import adb_wrapper
-from devil.utils import reraiser_thread
-
-logger = logging.getLogger(__name__)
-
-
-class LogcatMonitor(object):
-
- _RECORD_ITER_TIMEOUT = 2.0
- _RECORD_THREAD_JOIN_WAIT = 5.0
- _WAIT_TIME = 0.2
- _THREADTIME_RE_FORMAT = (
- r'(?P<date>\S*) +(?P<time>\S*) +(?P<proc_id>%s) +(?P<thread_id>%s) +'
- r'(?P<log_level>%s) +(?P<component>%s) *: +(?P<message>%s)$')
-
- def __init__(self, adb, clear=True, filter_specs=None, output_file=None):
- """Create a LogcatMonitor instance.
-
- Args:
- adb: An instance of adb_wrapper.AdbWrapper.
- clear: If True, clear the logcat when monitoring starts.
- filter_specs: An optional list of '<tag>[:priority]' strings.
- output_file: File path to save recorded logcat.
- """
- if isinstance(adb, adb_wrapper.AdbWrapper):
- self._adb = adb
- else:
- raise ValueError('Unsupported type passed for argument "device"')
- self._clear = clear
- self._filter_specs = filter_specs
- self._output_file = output_file
- self._record_file = None
- self._record_file_lock = threading.Lock()
- self._record_thread = None
- self._stop_recording_event = threading.Event()
-
- @property
- def output_file(self):
- return self._output_file
-
- @decorators.WithTimeoutAndRetriesDefaults(10, 0)
- def WaitFor(self, success_regex, failure_regex=None, timeout=None,
- retries=None):
- """Wait for a matching logcat line or until a timeout occurs.
-
- This will attempt to match lines in the logcat against both |success_regex|
- and |failure_regex| (if provided). Note that this calls re.search on each
- logcat line, not re.match, so the provided regular expressions don't have
- to match an entire line.
-
- Args:
- success_regex: The regular expression to search for.
- failure_regex: An optional regular expression that, if hit, causes this
- to stop looking for a match. Can be None.
- timeout: timeout in seconds
- retries: number of retries
-
- Returns:
- A match object if |success_regex| matches a part of a logcat line, or
- None if |failure_regex| matches a part of a logcat line.
- Raises:
- CommandFailedError on logcat failure (NOT on a |failure_regex| match).
- CommandTimeoutError if no logcat line matching either |success_regex| or
- |failure_regex| is found in |timeout| seconds.
- DeviceUnreachableError if the device becomes unreachable.
- LogcatMonitorCommandError when calling |WaitFor| while not recording
- logcat.
- """
- if self._record_thread is None:
- raise LogcatMonitorCommandError(
- 'Must be recording logcat when calling |WaitFor|',
- device_serial=str(self._adb))
- if isinstance(success_regex, basestring):
- success_regex = re.compile(success_regex)
- if isinstance(failure_regex, basestring):
- failure_regex = re.compile(failure_regex)
-
- logger.debug('Waiting %d seconds for "%s"', timeout, success_regex.pattern)
-
- # NOTE This will continue looping until:
- # - success_regex matches a line, in which case the match object is
- # returned.
- # - failure_regex matches a line, in which case None is returned
- # - the timeout is hit, in which case a CommandTimeoutError is raised.
- with open(self._record_file.name, 'r') as f:
- while True:
- line = f.readline()
- if line:
- m = success_regex.search(line)
- if m:
- return m
- if failure_regex and failure_regex.search(line):
- return None
- else:
- time.sleep(self._WAIT_TIME)
-
- def FindAll(self, message_regex, proc_id=None, thread_id=None, log_level=None,
- component=None):
- """Finds all lines in the logcat that match the provided constraints.
-
- Args:
- message_regex: The regular expression that the <message> section must
- match.
- proc_id: The process ID to match. If None, matches any process ID.
- thread_id: The thread ID to match. If None, matches any thread ID.
- log_level: The log level to match. If None, matches any log level.
- component: The component to match. If None, matches any component.
-
- Raises:
- LogcatMonitorCommandError when calling |FindAll| before recording logcat.
-
- Yields:
- A match object for each matching line in the logcat. The match object
- will always contain, in addition to groups defined in |message_regex|,
- the following named groups: 'date', 'time', 'proc_id', 'thread_id',
- 'log_level', 'component', and 'message'.
- """
- if self._record_file is None:
- raise LogcatMonitorCommandError(
- 'Must have recorded or be recording a logcat to call |FindAll|',
- device_serial=str(self._adb))
- if proc_id is None:
- proc_id = r'\d+'
- if thread_id is None:
- thread_id = r'\d+'
- if log_level is None:
- log_level = r'[VDIWEF]'
- if component is None:
- component = r'[^\s:]+'
- # pylint: disable=protected-access
- threadtime_re = re.compile(
- type(self)._THREADTIME_RE_FORMAT % (
- proc_id, thread_id, log_level, component, message_regex))
-
- with open(self._record_file.name, 'r') as f:
- for line in f:
- m = re.match(threadtime_re, line)
- if m:
- yield m
-
- def _StartRecording(self):
- """Starts recording logcat to file.
-
- Function spawns a thread that records logcat to file and will not die
- until |StopRecording| is called.
- """
- def record_to_file():
- # Write the log with line buffering so the consumer sees each individual
- # line.
- for data in self._adb.Logcat(filter_specs=self._filter_specs,
- logcat_format='threadtime',
- iter_timeout=self._RECORD_ITER_TIMEOUT):
- if self._stop_recording_event.isSet():
- return
-
- if data is None:
- # Logcat can yield None if the iter_timeout is hit.
- continue
-
- with self._record_file_lock:
- if self._record_file and not self._record_file.closed:
- self._record_file.write(data + '\n')
-
- self._stop_recording_event.clear()
- if not self._record_thread:
- self._record_thread = reraiser_thread.ReraiserThread(record_to_file)
- self._record_thread.start()
-
- def _StopRecording(self):
- """Finish recording logcat."""
- if self._record_thread:
- self._stop_recording_event.set()
- self._record_thread.join(timeout=self._RECORD_THREAD_JOIN_WAIT)
- self._record_thread.ReraiseIfException()
- self._record_thread = None
-
- def Start(self):
- """Starts the logcat monitor.
-
- Clears the logcat if |clear| was set in |__init__|.
- """
- if self._clear:
- self._adb.Logcat(clear=True)
- if not self._record_file:
- self._record_file = tempfile.NamedTemporaryFile(mode='a', bufsize=1)
- self._StartRecording()
-
- def Stop(self):
- """Stops the logcat monitor.
-
- Stops recording the logcat. Copies currently recorded logcat to
- |self._output_file|.
- """
- self._StopRecording()
- with self._record_file_lock:
- if self._record_file and self._output_file:
- try:
- os.makedirs(os.path.dirname(self._output_file))
- except OSError as e:
- if e.errno != errno.EEXIST:
- raise
- shutil.copy(self._record_file.name, self._output_file)
-
- def Close(self):
- """Closes logcat recording file.
-
- Should be called when finished using the logcat monitor.
- """
- with self._record_file_lock:
- if self._record_file:
- self._record_file.close()
- self._record_file = None
-
- def __enter__(self):
- """Starts the logcat monitor."""
- self.Start()
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- """Stops the logcat monitor."""
- self.Stop()
-
- def __del__(self):
- """Closes logcat recording file in case |Close| was never called."""
- with self._record_file_lock:
- if self._record_file:
- logger.warning(
- 'Need to call |Close| on the logcat monitor when done!')
- self._record_file.close()
-
- @property
- def adb(self):
- return self._adb
-
-
-class LogcatMonitorCommandError(device_errors.CommandFailedError):
- """Exception for errors with logcat monitor commands."""
- pass
diff --git a/third_party/catapult/devil/devil/android/logcat_monitor_test.py b/third_party/catapult/devil/devil/android/logcat_monitor_test.py
deleted file mode 100755
index 8fb4d74bbc..0000000000
--- a/third_party/catapult/devil/devil/android/logcat_monitor_test.py
+++ /dev/null
@@ -1,230 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# pylint: disable=protected-access
-
-import itertools
-import threading
-import unittest
-
-from devil import devil_env
-from devil.android import logcat_monitor
-from devil.android.sdk import adb_wrapper
-
-with devil_env.SysPath(devil_env.PYMOCK_PATH):
- import mock # pylint: disable=import-error
-
-
-def _CreateTestLog(raw_logcat=None):
- test_adb = adb_wrapper.AdbWrapper('0123456789abcdef')
- test_adb.Logcat = mock.Mock(return_value=(l for l in raw_logcat))
- test_log = logcat_monitor.LogcatMonitor(test_adb, clear=False)
- return test_log
-
-
-class LogcatMonitorTest(unittest.TestCase):
-
- _TEST_THREADTIME_LOGCAT_DATA = [
- '01-01 01:02:03.456 7890 0987 V LogcatMonitorTest: '
- 'verbose logcat monitor test message 1',
- '01-01 01:02:03.457 8901 1098 D LogcatMonitorTest: '
- 'debug logcat monitor test message 2',
- '01-01 01:02:03.458 9012 2109 I LogcatMonitorTest: '
- 'info logcat monitor test message 3',
- '01-01 01:02:03.459 0123 3210 W LogcatMonitorTest: '
- 'warning logcat monitor test message 4',
- '01-01 01:02:03.460 1234 4321 E LogcatMonitorTest: '
- 'error logcat monitor test message 5',
- '01-01 01:02:03.461 2345 5432 F LogcatMonitorTest: '
- 'fatal logcat monitor test message 6',
- '01-01 01:02:03.462 3456 6543 D LogcatMonitorTest: '
- 'last line'
- ]
-
- def assertIterEqual(self, expected_iter, actual_iter):
- for expected, actual in itertools.izip_longest(expected_iter, actual_iter):
- self.assertIsNotNone(
- expected,
- msg='actual has unexpected elements starting with %s' % str(actual))
- self.assertIsNotNone(
- actual,
- msg='actual is missing elements starting with %s' % str(expected))
- self.assertEqual(actual.group('proc_id'), expected[0])
- self.assertEqual(actual.group('thread_id'), expected[1])
- self.assertEqual(actual.group('log_level'), expected[2])
- self.assertEqual(actual.group('component'), expected[3])
- self.assertEqual(actual.group('message'), expected[4])
-
- with self.assertRaises(StopIteration):
- next(actual_iter)
- with self.assertRaises(StopIteration):
- next(expected_iter)
-
- @mock.patch('time.sleep', mock.Mock())
- def testWaitFor_success(self):
- test_log = _CreateTestLog(
- raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
- test_log.Start()
- actual_match = test_log.WaitFor(r'.*(fatal|error) logcat monitor.*', None)
- self.assertTrue(actual_match)
- self.assertEqual(
- '01-01 01:02:03.460 1234 4321 E LogcatMonitorTest: '
- 'error logcat monitor test message 5',
- actual_match.group(0))
- self.assertEqual('error', actual_match.group(1))
- test_log.Stop()
- test_log.Close()
-
- @mock.patch('time.sleep', mock.Mock())
- def testWaitFor_failure(self):
- test_log = _CreateTestLog(
- raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
- test_log.Start()
- actual_match = test_log.WaitFor(
- r'.*My Success Regex.*', r'.*(fatal|error) logcat monitor.*')
- self.assertIsNone(actual_match)
- test_log.Stop()
- test_log.Close()
-
- @mock.patch('time.sleep', mock.Mock())
- def testWaitFor_buffering(self):
- # Simulate an adb log stream which does not complete until the test tells it
- # to. This checks that the log matcher can receive individual lines from the
- # log reader thread even if adb is not producing enough output to fill an
- # entire file io buffer.
- finished_lock = threading.Lock()
- finished_lock.acquire()
-
- def LogGenerator():
- for line in type(self)._TEST_THREADTIME_LOGCAT_DATA:
- yield line
- finished_lock.acquire()
-
- test_adb = adb_wrapper.AdbWrapper('0123456789abcdef')
- test_adb.Logcat = mock.Mock(return_value=LogGenerator())
- test_log = logcat_monitor.LogcatMonitor(test_adb, clear=False)
- test_log.Start()
-
- actual_match = test_log.WaitFor(r'.*last line.*', None)
- finished_lock.release()
- self.assertTrue(actual_match)
- test_log.Stop()
- test_log.Close()
-
- @mock.patch('time.sleep', mock.Mock())
- def testFindAll_defaults(self):
- test_log = _CreateTestLog(
- raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
- test_log.Start()
- test_log.WaitFor(r'.*last line.*', None)
- test_log.Stop()
- expected_results = [
- ('7890', '0987', 'V', 'LogcatMonitorTest',
- 'verbose logcat monitor test message 1'),
- ('8901', '1098', 'D', 'LogcatMonitorTest',
- 'debug logcat monitor test message 2'),
- ('9012', '2109', 'I', 'LogcatMonitorTest',
- 'info logcat monitor test message 3'),
- ('0123', '3210', 'W', 'LogcatMonitorTest',
- 'warning logcat monitor test message 4'),
- ('1234', '4321', 'E', 'LogcatMonitorTest',
- 'error logcat monitor test message 5'),
- ('2345', '5432', 'F', 'LogcatMonitorTest',
- 'fatal logcat monitor test message 6')]
- actual_results = test_log.FindAll(r'\S* logcat monitor test message \d')
- self.assertIterEqual(iter(expected_results), actual_results)
- test_log.Close()
-
- @mock.patch('time.sleep', mock.Mock())
- def testFindAll_defaults_miss(self):
- test_log = _CreateTestLog(
- raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
- test_log.Start()
- test_log.WaitFor(r'.*last line.*', None)
- test_log.Stop()
- expected_results = []
- actual_results = test_log.FindAll(r'\S* nothing should match this \d')
- self.assertIterEqual(iter(expected_results), actual_results)
- test_log.Close()
-
- @mock.patch('time.sleep', mock.Mock())
- def testFindAll_filterProcId(self):
- test_log = _CreateTestLog(
- raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
- test_log.Start()
- test_log.WaitFor(r'.*last line.*', None)
- test_log.Stop()
- actual_results = test_log.FindAll(
- r'\S* logcat monitor test message \d', proc_id=1234)
- expected_results = [
- ('1234', '4321', 'E', 'LogcatMonitorTest',
- 'error logcat monitor test message 5')]
- self.assertIterEqual(iter(expected_results), actual_results)
- test_log.Close()
-
- @mock.patch('time.sleep', mock.Mock())
- def testFindAll_filterThreadId(self):
- test_log = _CreateTestLog(
- raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
- test_log.Start()
- test_log.WaitFor(r'.*last line.*', None)
- test_log.Stop()
- actual_results = test_log.FindAll(
- r'\S* logcat monitor test message \d', thread_id=2109)
- expected_results = [
- ('9012', '2109', 'I', 'LogcatMonitorTest',
- 'info logcat monitor test message 3')]
- self.assertIterEqual(iter(expected_results), actual_results)
- test_log.Close()
-
- @mock.patch('time.sleep', mock.Mock())
- def testFindAll_filterLogLevel(self):
- test_log = _CreateTestLog(
- raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
- test_log.Start()
- test_log.WaitFor(r'.*last line.*', None)
- test_log.Stop()
- actual_results = test_log.FindAll(
- r'\S* logcat monitor test message \d', log_level=r'[DW]')
- expected_results = [
- ('8901', '1098', 'D', 'LogcatMonitorTest',
- 'debug logcat monitor test message 2'),
- ('0123', '3210', 'W', 'LogcatMonitorTest',
- 'warning logcat monitor test message 4')
- ]
- self.assertIterEqual(iter(expected_results), actual_results)
- test_log.Close()
-
- @mock.patch('time.sleep', mock.Mock())
- def testFindAll_filterComponent(self):
- test_log = _CreateTestLog(
- raw_logcat=type(self)._TEST_THREADTIME_LOGCAT_DATA)
- test_log.Start()
- test_log.WaitFor(r'.*last line.*', None)
- test_log.Stop()
- actual_results = test_log.FindAll(r'.*', component='LogcatMonitorTest')
- expected_results = [
- ('7890', '0987', 'V', 'LogcatMonitorTest',
- 'verbose logcat monitor test message 1'),
- ('8901', '1098', 'D', 'LogcatMonitorTest',
- 'debug logcat monitor test message 2'),
- ('9012', '2109', 'I', 'LogcatMonitorTest',
- 'info logcat monitor test message 3'),
- ('0123', '3210', 'W', 'LogcatMonitorTest',
- 'warning logcat monitor test message 4'),
- ('1234', '4321', 'E', 'LogcatMonitorTest',
- 'error logcat monitor test message 5'),
- ('2345', '5432', 'F', 'LogcatMonitorTest',
- 'fatal logcat monitor test message 6'),
- ('3456', '6543', 'D', 'LogcatMonitorTest',
- 'last line')
- ]
- self.assertIterEqual(iter(expected_results), actual_results)
- test_log.Close()
-
-
-if __name__ == '__main__':
- unittest.main(verbosity=2)
-
diff --git a/third_party/catapult/devil/devil/android/md5sum.py b/third_party/catapult/devil/devil/android/md5sum.py
deleted file mode 100644
index 6dece9e8d7..0000000000
--- a/third_party/catapult/devil/devil/android/md5sum.py
+++ /dev/null
@@ -1,120 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import os
-import posixpath
-import re
-
-from devil import devil_env
-from devil.android import device_errors
-from devil.utils import cmd_helper
-
-MD5SUM_DEVICE_LIB_PATH = '/data/local/tmp/md5sum'
-MD5SUM_DEVICE_BIN_PATH = MD5SUM_DEVICE_LIB_PATH + '/md5sum_bin'
-
-_STARTS_WITH_CHECKSUM_RE = re.compile(r'^\s*[0-9a-fA-F]{32}\s+')
-
-
-def CalculateHostMd5Sums(paths):
- """Calculates the MD5 sum value for all items in |paths|.
-
- Directories are traversed recursively and the MD5 sum of each file found is
- reported in the result.
-
- Args:
- paths: A list of host paths to md5sum.
- Returns:
- A dict mapping file paths to their respective md5sum checksums.
- """
- if isinstance(paths, basestring):
- paths = [paths]
-
- md5sum_bin_host_path = devil_env.config.FetchPath('md5sum_host')
- if not os.path.exists(md5sum_bin_host_path):
- raise IOError('File not built: %s' % md5sum_bin_host_path)
- out = cmd_helper.GetCmdOutput(
- [md5sum_bin_host_path] + [os.path.realpath(p) for p in paths])
-
- return _ParseMd5SumOutput(out.splitlines())
-
-
-def CalculateDeviceMd5Sums(paths, device):
- """Calculates the MD5 sum value for all items in |paths|.
-
- Directories are traversed recursively and the MD5 sum of each file found is
- reported in the result.
-
- Args:
- paths: A list of device paths to md5sum.
- Returns:
- A dict mapping file paths to their respective md5sum checksums.
- """
- if not paths:
- return {}
-
- if isinstance(paths, basestring):
- paths = [paths]
- # Allow generators
- paths = list(paths)
-
- md5sum_dist_path = devil_env.config.FetchPath('md5sum_device', device=device)
-
- if os.path.isdir(md5sum_dist_path):
- md5sum_dist_bin_path = os.path.join(md5sum_dist_path, 'md5sum_bin')
- else:
- md5sum_dist_bin_path = md5sum_dist_path
-
- if not os.path.exists(md5sum_dist_path):
- raise IOError('File not built: %s' % md5sum_dist_path)
- md5sum_file_size = os.path.getsize(md5sum_dist_bin_path)
-
- # For better performance, make the script as small as possible to try and
- # avoid needing to write to an intermediary file (which RunShellCommand will
- # do if necessary).
- md5sum_script = 'a=%s;' % MD5SUM_DEVICE_BIN_PATH
- # Check if the binary is missing or has changed (using its file size as an
- # indicator), and trigger a (re-)push via the exit code.
- md5sum_script += '! [[ $(ls -l $a) = *%d* ]]&&exit 2;' % md5sum_file_size
- # Make sure it can find libbase.so
- md5sum_script += 'export LD_LIBRARY_PATH=%s;' % MD5SUM_DEVICE_LIB_PATH
- if len(paths) > 1:
- prefix = posixpath.commonprefix(paths)
- if len(prefix) > 4:
- md5sum_script += 'p="%s";' % prefix
- paths = ['$p"%s"' % p[len(prefix):] for p in paths]
-
- md5sum_script += ';'.join('$a %s' % p for p in paths)
- # Don't fail the script if the last md5sum fails (due to file not found)
- # Note: ":" is equivalent to "true".
- md5sum_script += ';:'
- try:
- out = device.RunShellCommand(md5sum_script, shell=True, check_return=True)
- except device_errors.AdbShellCommandFailedError as e:
- # Push the binary only if it is found to not exist
- # (faster than checking up-front).
- if e.status == 2:
- # If files were previously pushed as root (adbd running as root), trying
- # to re-push as non-root causes the push command to report success, but
- # actually fail. So, wipe the directory first.
- device.RunShellCommand(['rm', '-rf', MD5SUM_DEVICE_LIB_PATH],
- as_root=True, check_return=True)
- if os.path.isdir(md5sum_dist_path):
- device.adb.Push(md5sum_dist_path, MD5SUM_DEVICE_LIB_PATH)
- else:
- mkdir_cmd = 'a=%s;[[ -e $a ]] || mkdir $a' % MD5SUM_DEVICE_LIB_PATH
- device.RunShellCommand(mkdir_cmd, shell=True, check_return=True)
- device.adb.Push(md5sum_dist_bin_path, MD5SUM_DEVICE_BIN_PATH)
-
- out = device.RunShellCommand(md5sum_script, shell=True, check_return=True)
- else:
- raise
-
- return _ParseMd5SumOutput(out)
-
-
-def _ParseMd5SumOutput(out):
- hash_and_path = (l.split(None, 1) for l in out
- if l and _STARTS_WITH_CHECKSUM_RE.match(l))
- return dict((p, h) for h, p in hash_and_path)
-
diff --git a/third_party/catapult/devil/devil/android/md5sum_test.py b/third_party/catapult/devil/devil/android/md5sum_test.py
deleted file mode 100755
index c9b4954540..0000000000
--- a/third_party/catapult/devil/devil/android/md5sum_test.py
+++ /dev/null
@@ -1,237 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import os
-import unittest
-
-from devil import devil_env
-from devil.android import device_errors
-from devil.android import md5sum
-
-with devil_env.SysPath(devil_env.PYMOCK_PATH):
- import mock # pylint: disable=import-error
-
-TEST_OUT_DIR = os.path.join('test', 'out', 'directory')
-HOST_MD5_EXECUTABLE = os.path.join(TEST_OUT_DIR, 'md5sum_bin_host')
-MD5_DIST = os.path.join(TEST_OUT_DIR, 'md5sum_dist')
-
-
-class Md5SumTest(unittest.TestCase):
-
- def setUp(self):
- mocked_attrs = {
- 'md5sum_host': HOST_MD5_EXECUTABLE,
- 'md5sum_device': MD5_DIST,
- }
- self._patchers = [
- mock.patch('devil.devil_env._Environment.FetchPath',
- mock.Mock(side_effect=lambda a, device=None: mocked_attrs[a])),
- mock.patch('os.path.exists',
- new=mock.Mock(return_value=True)),
- ]
- for p in self._patchers:
- p.start()
-
- def tearDown(self):
- for p in self._patchers:
- p.stop()
-
- def testCalculateHostMd5Sums_singlePath(self):
- test_path = '/test/host/file.dat'
- mock_get_cmd_output = mock.Mock(
- return_value='0123456789abcdeffedcba9876543210 /test/host/file.dat')
- with mock.patch('devil.utils.cmd_helper.GetCmdOutput',
- new=mock_get_cmd_output):
- out = md5sum.CalculateHostMd5Sums(test_path)
- self.assertEquals(1, len(out))
- self.assertTrue('/test/host/file.dat' in out)
- self.assertEquals('0123456789abcdeffedcba9876543210',
- out['/test/host/file.dat'])
- mock_get_cmd_output.assert_called_once_with(
- [HOST_MD5_EXECUTABLE, '/test/host/file.dat'])
-
- def testCalculateHostMd5Sums_list(self):
- test_paths = ['/test/host/file0.dat', '/test/host/file1.dat']
- mock_get_cmd_output = mock.Mock(
- return_value='0123456789abcdeffedcba9876543210 /test/host/file0.dat\n'
- '123456789abcdef00fedcba987654321 /test/host/file1.dat\n')
- with mock.patch('devil.utils.cmd_helper.GetCmdOutput',
- new=mock_get_cmd_output):
- out = md5sum.CalculateHostMd5Sums(test_paths)
- self.assertEquals(2, len(out))
- self.assertTrue('/test/host/file0.dat' in out)
- self.assertEquals('0123456789abcdeffedcba9876543210',
- out['/test/host/file0.dat'])
- self.assertTrue('/test/host/file1.dat' in out)
- self.assertEquals('123456789abcdef00fedcba987654321',
- out['/test/host/file1.dat'])
- mock_get_cmd_output.assert_called_once_with(
- [HOST_MD5_EXECUTABLE, '/test/host/file0.dat',
- '/test/host/file1.dat'])
-
- def testCalculateHostMd5Sums_generator(self):
- test_paths = ('/test/host/' + p for p in ['file0.dat', 'file1.dat'])
- mock_get_cmd_output = mock.Mock(
- return_value='0123456789abcdeffedcba9876543210 /test/host/file0.dat\n'
- '123456789abcdef00fedcba987654321 /test/host/file1.dat\n')
- with mock.patch('devil.utils.cmd_helper.GetCmdOutput',
- new=mock_get_cmd_output):
- out = md5sum.CalculateHostMd5Sums(test_paths)
- self.assertEquals(2, len(out))
- self.assertTrue('/test/host/file0.dat' in out)
- self.assertEquals('0123456789abcdeffedcba9876543210',
- out['/test/host/file0.dat'])
- self.assertTrue('/test/host/file1.dat' in out)
- self.assertEquals('123456789abcdef00fedcba987654321',
- out['/test/host/file1.dat'])
- mock_get_cmd_output.assert_called_once_with(
- [HOST_MD5_EXECUTABLE, '/test/host/file0.dat', '/test/host/file1.dat'])
-
- def testCalculateDeviceMd5Sums_noPaths(self):
- device = mock.NonCallableMock()
- device.RunShellCommand = mock.Mock(side_effect=Exception())
-
- out = md5sum.CalculateDeviceMd5Sums([], device)
- self.assertEquals(0, len(out))
-
- def testCalculateDeviceMd5Sums_singlePath(self):
- test_path = '/storage/emulated/legacy/test/file.dat'
-
- device = mock.NonCallableMock()
- device_md5sum_output = [
- '0123456789abcdeffedcba9876543210 '
- '/storage/emulated/legacy/test/file.dat',
- ]
- device.RunShellCommand = mock.Mock(return_value=device_md5sum_output)
-
- with mock.patch('os.path.getsize', return_value=1337):
- out = md5sum.CalculateDeviceMd5Sums(test_path, device)
- self.assertEquals(1, len(out))
- self.assertTrue('/storage/emulated/legacy/test/file.dat' in out)
- self.assertEquals('0123456789abcdeffedcba9876543210',
- out['/storage/emulated/legacy/test/file.dat'])
- self.assertEquals(1, len(device.RunShellCommand.call_args_list))
-
- def testCalculateDeviceMd5Sums_list(self):
- test_path = ['/storage/emulated/legacy/test/file0.dat',
- '/storage/emulated/legacy/test/file1.dat']
- device = mock.NonCallableMock()
- device_md5sum_output = [
- '0123456789abcdeffedcba9876543210 '
- '/storage/emulated/legacy/test/file0.dat',
- '123456789abcdef00fedcba987654321 '
- '/storage/emulated/legacy/test/file1.dat',
- ]
- device.RunShellCommand = mock.Mock(return_value=device_md5sum_output)
-
- with mock.patch('os.path.getsize', return_value=1337):
- out = md5sum.CalculateDeviceMd5Sums(test_path, device)
- self.assertEquals(2, len(out))
- self.assertTrue('/storage/emulated/legacy/test/file0.dat' in out)
- self.assertEquals('0123456789abcdeffedcba9876543210',
- out['/storage/emulated/legacy/test/file0.dat'])
- self.assertTrue('/storage/emulated/legacy/test/file1.dat' in out)
- self.assertEquals('123456789abcdef00fedcba987654321',
- out['/storage/emulated/legacy/test/file1.dat'])
- self.assertEquals(1, len(device.RunShellCommand.call_args_list))
-
- def testCalculateDeviceMd5Sums_generator(self):
- test_path = ('/storage/emulated/legacy/test/file%d.dat' % n
- for n in xrange(0, 2))
-
- device = mock.NonCallableMock()
- device_md5sum_output = [
- '0123456789abcdeffedcba9876543210 '
- '/storage/emulated/legacy/test/file0.dat',
- '123456789abcdef00fedcba987654321 '
- '/storage/emulated/legacy/test/file1.dat',
- ]
- device.RunShellCommand = mock.Mock(return_value=device_md5sum_output)
-
- with mock.patch('os.path.getsize', return_value=1337):
- out = md5sum.CalculateDeviceMd5Sums(test_path, device)
- self.assertEquals(2, len(out))
- self.assertTrue('/storage/emulated/legacy/test/file0.dat' in out)
- self.assertEquals('0123456789abcdeffedcba9876543210',
- out['/storage/emulated/legacy/test/file0.dat'])
- self.assertTrue('/storage/emulated/legacy/test/file1.dat' in out)
- self.assertEquals('123456789abcdef00fedcba987654321',
- out['/storage/emulated/legacy/test/file1.dat'])
- self.assertEquals(1, len(device.RunShellCommand.call_args_list))
-
- def testCalculateDeviceMd5Sums_singlePath_linkerWarning(self):
- # See crbug/479966
- test_path = '/storage/emulated/legacy/test/file.dat'
-
- device = mock.NonCallableMock()
- device_md5sum_output = [
- 'WARNING: linker: /data/local/tmp/md5sum/md5sum_bin: '
- 'unused DT entry: type 0x1d arg 0x15db',
- 'THIS_IS_NOT_A_VALID_CHECKSUM_ZZZ some random text',
- '0123456789abcdeffedcba9876543210 '
- '/storage/emulated/legacy/test/file.dat',
- ]
- device.RunShellCommand = mock.Mock(return_value=device_md5sum_output)
-
- with mock.patch('os.path.getsize', return_value=1337):
- out = md5sum.CalculateDeviceMd5Sums(test_path, device)
- self.assertEquals(1, len(out))
- self.assertTrue('/storage/emulated/legacy/test/file.dat' in out)
- self.assertEquals('0123456789abcdeffedcba9876543210',
- out['/storage/emulated/legacy/test/file.dat'])
- self.assertEquals(1, len(device.RunShellCommand.call_args_list))
-
- def testCalculateDeviceMd5Sums_list_fileMissing(self):
- test_path = ['/storage/emulated/legacy/test/file0.dat',
- '/storage/emulated/legacy/test/file1.dat']
- device = mock.NonCallableMock()
- device_md5sum_output = [
- '0123456789abcdeffedcba9876543210 '
- '/storage/emulated/legacy/test/file0.dat',
- '[0819/203513:ERROR:md5sum.cc(25)] Could not open file asdf',
- '',
- ]
- device.RunShellCommand = mock.Mock(return_value=device_md5sum_output)
-
- with mock.patch('os.path.getsize', return_value=1337):
- out = md5sum.CalculateDeviceMd5Sums(test_path, device)
- self.assertEquals(1, len(out))
- self.assertTrue('/storage/emulated/legacy/test/file0.dat' in out)
- self.assertEquals('0123456789abcdeffedcba9876543210',
- out['/storage/emulated/legacy/test/file0.dat'])
- self.assertEquals(1, len(device.RunShellCommand.call_args_list))
-
- def testCalculateDeviceMd5Sums_requiresBinary(self):
- test_path = '/storage/emulated/legacy/test/file.dat'
-
- device = mock.NonCallableMock()
- device.adb = mock.NonCallableMock()
- device.adb.Push = mock.Mock()
- device_md5sum_output = [
- 'WARNING: linker: /data/local/tmp/md5sum/md5sum_bin: '
- 'unused DT entry: type 0x1d arg 0x15db',
- 'THIS_IS_NOT_A_VALID_CHECKSUM_ZZZ some random text',
- '0123456789abcdeffedcba9876543210 '
- '/storage/emulated/legacy/test/file.dat',
- ]
- error = device_errors.AdbShellCommandFailedError('cmd', 'out', 2)
- device.RunShellCommand = mock.Mock(
- side_effect=(error, '', device_md5sum_output))
-
- with mock.patch('os.path.isdir', return_value=True), (
- mock.patch('os.path.getsize', return_value=1337)):
- out = md5sum.CalculateDeviceMd5Sums(test_path, device)
- self.assertEquals(1, len(out))
- self.assertTrue('/storage/emulated/legacy/test/file.dat' in out)
- self.assertEquals('0123456789abcdeffedcba9876543210',
- out['/storage/emulated/legacy/test/file.dat'])
- self.assertEquals(3, len(device.RunShellCommand.call_args_list))
- device.adb.Push.assert_called_once_with(
- 'test/out/directory/md5sum_dist', '/data/local/tmp/md5sum')
-
-
-if __name__ == '__main__':
- unittest.main(verbosity=2)
-
diff --git a/third_party/catapult/devil/devil/android/perf/__init__.py b/third_party/catapult/devil/devil/android/perf/__init__.py
deleted file mode 100644
index 50b23dff63..0000000000
--- a/third_party/catapult/devil/devil/android/perf/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
diff --git a/third_party/catapult/devil/devil/android/perf/cache_control.py b/third_party/catapult/devil/devil/android/perf/cache_control.py
deleted file mode 100644
index 27782b50b2..0000000000
--- a/third_party/catapult/devil/devil/android/perf/cache_control.py
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-
-class CacheControl(object):
- _DROP_CACHES = '/proc/sys/vm/drop_caches'
-
- def __init__(self, device):
- self._device = device
-
- def DropRamCaches(self):
- """Drops the filesystem ram caches for performance testing."""
- self._device.RunShellCommand(['sync'], check_return=True, as_root=True)
- self._device.WriteFile(CacheControl._DROP_CACHES, '3', as_root=True)
diff --git a/third_party/catapult/devil/devil/android/perf/perf_control.py b/third_party/catapult/devil/devil/android/perf/perf_control.py
deleted file mode 100644
index 06a5db61e5..0000000000
--- a/third_party/catapult/devil/devil/android/perf/perf_control.py
+++ /dev/null
@@ -1,210 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import atexit
-import logging
-import re
-
-from devil.android import device_errors
-
-logger = logging.getLogger(__name__)
-
-
-class PerfControl(object):
- """Provides methods for setting the performance mode of a device."""
-
- _AVAILABLE_GOVERNORS_REL_PATH = 'cpufreq/scaling_available_governors'
- _CPU_FILE_PATTERN = re.compile(r'^cpu\d+$')
- _CPU_PATH = '/sys/devices/system/cpu'
- _KERNEL_MAX = '/sys/devices/system/cpu/kernel_max'
-
- def __init__(self, device):
- self._device = device
- self._cpu_files = [
- filename
- for filename in self._device.ListDirectory(self._CPU_PATH, as_root=True)
- if self._CPU_FILE_PATTERN.match(filename)]
- assert self._cpu_files, 'Failed to detect CPUs.'
- self._cpu_file_list = ' '.join(self._cpu_files)
- logger.info('CPUs found: %s', self._cpu_file_list)
-
- self._have_mpdecision = self._device.FileExists('/system/bin/mpdecision')
-
- raw = self._ReadEachCpuFile(self._AVAILABLE_GOVERNORS_REL_PATH)
- self._available_governors = [
- (cpu, raw_governors.strip().split() if not exit_code else None)
- for cpu, raw_governors, exit_code in raw]
-
- def SetHighPerfMode(self):
- """Sets the highest stable performance mode for the device."""
- try:
- self._device.EnableRoot()
- except device_errors.CommandFailedError:
- message = 'Need root for performance mode. Results may be NOISY!!'
- logger.warning(message)
- # Add an additional warning at exit, such that it's clear that any results
- # may be different/noisy (due to the lack of intended performance mode).
- atexit.register(logger.warning, message)
- return
-
- product_model = self._device.product_model
- # TODO(epenner): Enable on all devices (http://crbug.com/383566)
- if 'Nexus 4' == product_model:
- self._ForceAllCpusOnline(True)
- if not self._AllCpusAreOnline():
- logger.warning('Failed to force CPUs online. Results may be NOISY!')
- self.SetScalingGovernor('performance')
- elif 'Nexus 5' == product_model:
- self._ForceAllCpusOnline(True)
- if not self._AllCpusAreOnline():
- logger.warning('Failed to force CPUs online. Results may be NOISY!')
- self.SetScalingGovernor('performance')
- self._SetScalingMaxFreq(1190400)
- self._SetMaxGpuClock(200000000)
- else:
- self.SetScalingGovernor('performance')
-
- def SetPerfProfilingMode(self):
- """Enables all cores for reliable perf profiling."""
- self._ForceAllCpusOnline(True)
- self.SetScalingGovernor('performance')
- if not self._AllCpusAreOnline():
- if not self._device.HasRoot():
- raise RuntimeError('Need root to force CPUs online.')
- raise RuntimeError('Failed to force CPUs online.')
-
- def SetDefaultPerfMode(self):
- """Sets the performance mode for the device to its default mode."""
- if not self._device.HasRoot():
- return
- product_model = self._device.product_model
- if 'Nexus 5' == product_model:
- if self._AllCpusAreOnline():
- self._SetScalingMaxFreq(2265600)
- self._SetMaxGpuClock(450000000)
-
- governor_mode = {
- 'GT-I9300': 'pegasusq',
- 'Galaxy Nexus': 'interactive',
- 'Nexus 4': 'ondemand',
- 'Nexus 5': 'ondemand',
- 'Nexus 7': 'interactive',
- 'Nexus 10': 'interactive'
- }.get(product_model, 'ondemand')
- self.SetScalingGovernor(governor_mode)
- self._ForceAllCpusOnline(False)
-
- def GetCpuInfo(self):
- online = (output.rstrip() == '1' and status == 0
- for (_, output, status) in self._ForEachCpu('cat "$CPU/online"'))
- governor = (output.rstrip() if status == 0 else None
- for (_, output, status)
- in self._ForEachCpu('cat "$CPU/cpufreq/scaling_governor"'))
- return zip(self._cpu_files, online, governor)
-
- def _ForEachCpu(self, cmd):
- script = '; '.join([
- 'for CPU in %s' % self._cpu_file_list,
- 'do %s' % cmd,
- 'echo -n "%~%$?%~%"',
- 'done'
- ])
- output = self._device.RunShellCommand(
- script, cwd=self._CPU_PATH, check_return=True, as_root=True, shell=True)
- output = '\n'.join(output).split('%~%')
- return zip(self._cpu_files, output[0::2], (int(c) for c in output[1::2]))
-
- def _WriteEachCpuFile(self, path, value):
- self._ConditionallyWriteEachCpuFile(path, value, condition='true')
-
- def _ConditionallyWriteEachCpuFile(self, path, value, condition):
- template = (
- '{condition} && test -e "$CPU/{path}" && echo {value} > "$CPU/{path}"')
- results = self._ForEachCpu(
- template.format(path=path, value=value, condition=condition))
- cpus = ' '.join(cpu for (cpu, _, status) in results if status == 0)
- if cpus:
- logger.info('Successfully set %s to %r on: %s', path, value, cpus)
- else:
- logger.warning('Failed to set %s to %r on any cpus', path, value)
-
- def _ReadEachCpuFile(self, path):
- return self._ForEachCpu(
- 'cat "$CPU/{path}"'.format(path=path))
-
- def SetScalingGovernor(self, value):
- """Sets the scaling governor to the given value on all possible CPUs.
-
- This does not attempt to set a governor to a value not reported as available
- on the corresponding CPU.
-
- Args:
- value: [string] The new governor value.
- """
- condition = 'test -e "{path}" && grep -q {value} {path}'.format(
- path=('${CPU}/%s' % self._AVAILABLE_GOVERNORS_REL_PATH),
- value=value)
- self._ConditionallyWriteEachCpuFile(
- 'cpufreq/scaling_governor', value, condition)
-
- def GetScalingGovernor(self):
- """Gets the currently set governor for each CPU.
-
- Returns:
- An iterable of 2-tuples, each containing the cpu and the current
- governor.
- """
- raw = self._ReadEachCpuFile('cpufreq/scaling_governor')
- return [
- (cpu, raw_governor.strip() if not exit_code else None)
- for cpu, raw_governor, exit_code in raw]
-
- def ListAvailableGovernors(self):
- """Returns the list of available governors for each CPU.
-
- Returns:
- An iterable of 2-tuples, each containing the cpu and a list of available
- governors for that cpu.
- """
- return self._available_governors
-
- def _SetScalingMaxFreq(self, value):
- self._WriteEachCpuFile('cpufreq/scaling_max_freq', '%d' % value)
-
- def _SetMaxGpuClock(self, value):
- self._device.WriteFile('/sys/class/kgsl/kgsl-3d0/max_gpuclk',
- str(value),
- as_root=True)
-
- def _AllCpusAreOnline(self):
- results = self._ForEachCpu('cat "$CPU/online"')
- # TODO(epenner): Investigate why file may be missing
- # (http://crbug.com/397118)
- return all(output.rstrip() == '1' and status == 0
- for (cpu, output, status) in results
- if cpu != 'cpu0')
-
- def _ForceAllCpusOnline(self, force_online):
- """Enable all CPUs on a device.
-
- Some vendors (or only Qualcomm?) hot-plug their CPUs, which can add noise
- to measurements:
- - In perf, samples are only taken for the CPUs that are online when the
- measurement is started.
- - The scaling governor can't be set for an offline CPU and frequency scaling
- on newly enabled CPUs adds noise to both perf and tracing measurements.
-
- It appears Qualcomm is the only vendor that hot-plugs CPUs, and on Qualcomm
- this is done by "mpdecision".
-
- """
- if self._have_mpdecision:
- cmd = ['stop', 'mpdecision'] if force_online else ['start', 'mpdecision']
- self._device.RunShellCommand(cmd, check_return=True, as_root=True)
-
- if not self._have_mpdecision and not self._AllCpusAreOnline():
- logger.warning('Unexpected cpu hot plugging detected.')
-
- if force_online:
- self._ForEachCpu('echo 1 > "$CPU/online"')
diff --git a/third_party/catapult/devil/devil/android/perf/perf_control_devicetest.py b/third_party/catapult/devil/devil/android/perf/perf_control_devicetest.py
deleted file mode 100644
index b64580306b..0000000000
--- a/third_party/catapult/devil/devil/android/perf/perf_control_devicetest.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-# pylint: disable=W0212
-
-import os
-import sys
-import unittest
-
-sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))
-
-from devil.android import device_test_case
-from devil.android import device_utils
-from devil.android.perf import perf_control
-
-
-class TestPerfControl(device_test_case.DeviceTestCase):
-
- def setUp(self):
- super(TestPerfControl, self).setUp()
- if not os.getenv('BUILDTYPE'):
- os.environ['BUILDTYPE'] = 'Debug'
- self._device = device_utils.DeviceUtils(self.serial)
-
- def testHighPerfMode(self):
- perf = perf_control.PerfControl(self._device)
- try:
- perf.SetPerfProfilingMode()
- cpu_info = perf.GetCpuInfo()
- self.assertEquals(len(perf._cpu_files), len(cpu_info))
- for _, online, governor in cpu_info:
- self.assertTrue(online)
- self.assertEquals('performance', governor)
- finally:
- perf.SetDefaultPerfMode()
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/third_party/catapult/devil/devil/android/perf/surface_stats_collector.py b/third_party/catapult/devil/devil/android/perf/surface_stats_collector.py
deleted file mode 100644
index 25079f310e..0000000000
--- a/third_party/catapult/devil/devil/android/perf/surface_stats_collector.py
+++ /dev/null
@@ -1,186 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import Queue
-import threading
-
-
-# Log marker containing SurfaceTexture timestamps.
-_SURFACE_TEXTURE_TIMESTAMPS_MESSAGE = 'SurfaceTexture update timestamps'
-_SURFACE_TEXTURE_TIMESTAMP_RE = r'\d+'
-
-
-class SurfaceStatsCollector(object):
- """Collects surface stats for a SurfaceView from the output of SurfaceFlinger.
-
- Args:
- device: A DeviceUtils instance.
- """
-
- def __init__(self, device):
- self._device = device
- self._collector_thread = None
- self._surface_before = None
- self._get_data_event = None
- self._data_queue = None
- self._stop_event = None
- self._warn_about_empty_data = True
-
- def DisableWarningAboutEmptyData(self):
- self._warn_about_empty_data = False
-
- def Start(self):
- assert not self._collector_thread
-
- if self._ClearSurfaceFlingerLatencyData():
- self._get_data_event = threading.Event()
- self._stop_event = threading.Event()
- self._data_queue = Queue.Queue()
- self._collector_thread = threading.Thread(target=self._CollectorThread)
- self._collector_thread.start()
- else:
- raise Exception('SurfaceFlinger not supported on this device.')
-
- def Stop(self):
- assert self._collector_thread
- (refresh_period, timestamps) = self._GetDataFromThread()
- if self._collector_thread:
- self._stop_event.set()
- self._collector_thread.join()
- self._collector_thread = None
- return (refresh_period, timestamps)
-
- def _CollectorThread(self):
- last_timestamp = 0
- timestamps = []
- retries = 0
-
- while not self._stop_event.is_set():
- self._get_data_event.wait(1)
- try:
- refresh_period, new_timestamps = self._GetSurfaceFlingerFrameData()
- if refresh_period is None or timestamps is None:
- retries += 1
- if retries < 3:
- continue
- if last_timestamp:
- # Some data has already been collected, but either the app
- # was closed or there's no new data. Signal the main thread and
- # wait.
- self._data_queue.put((None, None))
- self._stop_event.wait()
- break
- raise Exception('Unable to get surface flinger latency data')
-
- timestamps += [timestamp for timestamp in new_timestamps
- if timestamp > last_timestamp]
- if len(timestamps):
- last_timestamp = timestamps[-1]
-
- if self._get_data_event.is_set():
- self._get_data_event.clear()
- self._data_queue.put((refresh_period, timestamps))
- timestamps = []
- except Exception as e:
- # On any error, before aborting, put the exception into _data_queue to
- # prevent the main thread from waiting at _data_queue.get() infinitely.
- self._data_queue.put(e)
- raise
-
- def _GetDataFromThread(self):
- self._get_data_event.set()
- ret = self._data_queue.get()
- if isinstance(ret, Exception):
- raise ret
- return ret
-
- def _ClearSurfaceFlingerLatencyData(self):
- """Clears the SurfaceFlinger latency data.
-
- Returns:
- True if SurfaceFlinger latency is supported by the device, otherwise
- False.
- """
- # The command returns nothing if it is supported, otherwise returns many
- # lines of result just like 'dumpsys SurfaceFlinger'.
- results = self._device.RunShellCommand(
- ['dumpsys', 'SurfaceFlinger', '--latency-clear', 'SurfaceView'],
- check_return=True)
- return not len(results)
-
- def GetSurfaceFlingerPid(self):
- pids_dict = self._device.GetPids('surfaceflinger')
- if not pids_dict:
- raise Exception('Unable to get surface flinger process id')
- # TODO(cataput:#3378): Do more strict checks in GetPids when possible.
- # For now it just returns the first pid found of some matching process.
- return pids_dict.popitem()[1][0]
-
- def _GetSurfaceFlingerFrameData(self):
- """Returns collected SurfaceFlinger frame timing data.
-
- Returns:
- A tuple containing:
- - The display's nominal refresh period in milliseconds.
- - A list of timestamps signifying frame presentation times in
- milliseconds.
- The return value may be (None, None) if there was no data collected (for
- example, if the app was closed before the collector thread has finished).
- """
- # adb shell dumpsys SurfaceFlinger --latency <window name>
- # prints some information about the last 128 frames displayed in
- # that window.
- # The data returned looks like this:
- # 16954612
- # 7657467895508 7657482691352 7657493499756
- # 7657484466553 7657499645964 7657511077881
- # 7657500793457 7657516600576 7657527404785
- # (...)
- #
- # The first line is the refresh period (here 16.95 ms), it is followed
- # by 128 lines w/ 3 timestamps in nanosecond each:
- # A) when the app started to draw
- # B) the vsync immediately preceding SF submitting the frame to the h/w
- # C) timestamp immediately after SF submitted that frame to the h/w
- #
- # The difference between the 1st and 3rd timestamp is the frame-latency.
- # An interesting data is when the frame latency crosses a refresh period
- # boundary, this can be calculated this way:
- #
- # ceil((C - A) / refresh-period)
- #
- # (each time the number above changes, we have a "jank").
- # If this happens a lot during an animation, the animation appears
- # janky, even if it runs at 60 fps in average.
- #
- # We use the special "SurfaceView" window name because the statistics for
- # the activity's main window are not updated when the main web content is
- # composited into a SurfaceView.
- results = self._device.RunShellCommand(
- ['dumpsys', 'SurfaceFlinger', '--latency', 'SurfaceView'],
- check_return=True)
- if not len(results):
- return (None, None)
-
- timestamps = []
- nanoseconds_per_millisecond = 1e6
- refresh_period = long(results[0]) / nanoseconds_per_millisecond
-
- # If a fence associated with a frame is still pending when we query the
- # latency data, SurfaceFlinger gives the frame a timestamp of INT64_MAX.
- # Since we only care about completed frames, we will ignore any timestamps
- # with this value.
- pending_fence_timestamp = (1 << 63) - 1
-
- for line in results[1:]:
- fields = line.split()
- if len(fields) != 3:
- continue
- timestamp = long(fields[1])
- if timestamp == pending_fence_timestamp:
- continue
- timestamp /= nanoseconds_per_millisecond
- timestamps.append(timestamp)
-
- return (refresh_period, timestamps)
diff --git a/third_party/catapult/devil/devil/android/perf/thermal_throttle.py b/third_party/catapult/devil/devil/android/perf/thermal_throttle.py
deleted file mode 100644
index 546a92e092..0000000000
--- a/third_party/catapult/devil/devil/android/perf/thermal_throttle.py
+++ /dev/null
@@ -1,135 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import logging
-
-logger = logging.getLogger(__name__)
-
-
-class OmapThrottlingDetector(object):
- """Class to detect and track thermal throttling on an OMAP 4."""
- OMAP_TEMP_FILE = ('/sys/devices/platform/omap/omap_temp_sensor.0/'
- 'temperature')
-
- @staticmethod
- def IsSupported(device):
- return device.FileExists(OmapThrottlingDetector.OMAP_TEMP_FILE)
-
- def __init__(self, device):
- self._device = device
-
- @staticmethod
- def BecameThrottled(log_line):
- return 'omap_thermal_throttle' in log_line
-
- @staticmethod
- def BecameUnthrottled(log_line):
- return 'omap_thermal_unthrottle' in log_line
-
- @staticmethod
- def GetThrottlingTemperature(log_line):
- if 'throttle_delayed_work_fn' in log_line:
- return float([s for s in log_line.split() if s.isdigit()][0]) / 1000.0
-
- def GetCurrentTemperature(self):
- tempdata = self._device.ReadFile(OmapThrottlingDetector.OMAP_TEMP_FILE)
- return float(tempdata) / 1000.0
-
-
-class ExynosThrottlingDetector(object):
- """Class to detect and track thermal throttling on an Exynos 5."""
- @staticmethod
- def IsSupported(device):
- return device.FileExists('/sys/bus/exynos5-core')
-
- def __init__(self, device):
- pass
-
- @staticmethod
- def BecameThrottled(log_line):
- return 'exynos_tmu: Throttling interrupt' in log_line
-
- @staticmethod
- def BecameUnthrottled(log_line):
- return 'exynos_thermal_unthrottle: not throttling' in log_line
-
- @staticmethod
- def GetThrottlingTemperature(_log_line):
- return None
-
- @staticmethod
- def GetCurrentTemperature():
- return None
-
-
-class ThermalThrottle(object):
- """Class to detect and track thermal throttling.
-
- Usage:
- Wait for IsThrottled() to be False before running test
- After running test call HasBeenThrottled() to find out if the
- test run was affected by thermal throttling.
- """
-
- def __init__(self, device):
- self._device = device
- self._throttled = False
- self._detector = None
- if OmapThrottlingDetector.IsSupported(device):
- self._detector = OmapThrottlingDetector(device)
- elif ExynosThrottlingDetector.IsSupported(device):
- self._detector = ExynosThrottlingDetector(device)
-
- def HasBeenThrottled(self):
- """True if there has been any throttling since the last call to
- HasBeenThrottled or IsThrottled.
- """
- return self._ReadLog()
-
- def IsThrottled(self):
- """True if currently throttled."""
- self._ReadLog()
- return self._throttled
-
- def _ReadLog(self):
- if not self._detector:
- return False
- has_been_throttled = False
- serial_number = str(self._device)
- log = self._device.RunShellCommand(
- ['dmesg', '-c'], large_output=True, check_return=True)
- degree_symbol = unichr(0x00B0)
- for line in log:
- if self._detector.BecameThrottled(line):
- if not self._throttled:
- logger.warning('>>> Device %s thermally throttled', serial_number)
- self._throttled = True
- has_been_throttled = True
- elif self._detector.BecameUnthrottled(line):
- if self._throttled:
- logger.warning('>>> Device %s thermally unthrottled', serial_number)
- self._throttled = False
- has_been_throttled = True
- temperature = self._detector.GetThrottlingTemperature(line)
- if temperature is not None:
- logger.info(u'Device %s thermally throttled at %3.1f%sC',
- serial_number, temperature, degree_symbol)
-
- if logger.isEnabledFor(logging.DEBUG):
- # Print current temperature of CPU SoC.
- temperature = self._detector.GetCurrentTemperature()
- if temperature is not None:
- logger.debug(u'Current SoC temperature of %s = %3.1f%sC',
- serial_number, temperature, degree_symbol)
-
- # Print temperature of battery, to give a system temperature
- dumpsys_log = self._device.RunShellCommand(
- ['dumpsys', 'battery'], check_return=True)
- for line in dumpsys_log:
- if 'temperature' in line:
- btemp = float([s for s in line.split() if s.isdigit()][0]) / 10.0
- logger.debug(u'Current battery temperature of %s = %3.1f%sC',
- serial_number, btemp, degree_symbol)
-
- return has_been_throttled
diff --git a/third_party/catapult/devil/devil/android/ports.py b/third_party/catapult/devil/devil/android/ports.py
deleted file mode 100644
index 1d4e5f21fe..0000000000
--- a/third_party/catapult/devil/devil/android/ports.py
+++ /dev/null
@@ -1,178 +0,0 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Functions that deal with local and device ports."""
-
-import contextlib
-import fcntl
-import httplib
-import logging
-import os
-import socket
-import traceback
-
-logger = logging.getLogger(__name__)
-
-# The net test server is started from port 10201.
-_TEST_SERVER_PORT_FIRST = 10201
-_TEST_SERVER_PORT_LAST = 30000
-# A file to record next valid port of test server.
-_TEST_SERVER_PORT_FILE = '/tmp/test_server_port'
-_TEST_SERVER_PORT_LOCKFILE = '/tmp/test_server_port.lock'
-
-
-# The following two methods are used to allocate the port source for various
-# types of test servers. Because some net-related tests can be run on shards at
-# same time, it's important to have a mechanism to allocate the port
-# process-safe. In here, we implement the safe port allocation by leveraging
-# flock.
-def ResetTestServerPortAllocation():
- """Resets the port allocation to start from TEST_SERVER_PORT_FIRST.
-
- Returns:
- Returns True if reset successes. Otherwise returns False.
- """
- try:
- with open(_TEST_SERVER_PORT_FILE, 'w') as fp:
- fp.write('%d' % _TEST_SERVER_PORT_FIRST)
- return True
- except Exception: # pylint: disable=broad-except
- logger.exception('Error while resetting port allocation')
- return False
-
-
-def AllocateTestServerPort():
- """Allocates a port incrementally.
-
- Returns:
- Returns a valid port which should be in between TEST_SERVER_PORT_FIRST and
- TEST_SERVER_PORT_LAST. Returning 0 means no more valid port can be used.
- """
- port = 0
- ports_tried = []
- try:
- fp_lock = open(_TEST_SERVER_PORT_LOCKFILE, 'w')
- fcntl.flock(fp_lock, fcntl.LOCK_EX)
- # Get current valid port and calculate next valid port.
- if not os.path.exists(_TEST_SERVER_PORT_FILE):
- ResetTestServerPortAllocation()
- with open(_TEST_SERVER_PORT_FILE, 'r+') as fp:
- port = int(fp.read())
- ports_tried.append(port)
- while not IsHostPortAvailable(port):
- port += 1
- ports_tried.append(port)
- if (port > _TEST_SERVER_PORT_LAST or
- port < _TEST_SERVER_PORT_FIRST):
- port = 0
- else:
- fp.seek(0, os.SEEK_SET)
- fp.write('%d' % (port + 1))
- except Exception: # pylint: disable=broad-except
- logger.exception('Error while allocating port')
- finally:
- if fp_lock:
- fcntl.flock(fp_lock, fcntl.LOCK_UN)
- fp_lock.close()
- if port:
- logger.info('Allocate port %d for test server.', port)
- else:
- logger.error('Could not allocate port for test server. '
- 'List of ports tried: %s', str(ports_tried))
- return port
-
-
-def IsHostPortAvailable(host_port):
- """Checks whether the specified host port is available.
-
- Args:
- host_port: Port on host to check.
-
- Returns:
- True if the port on host is available, otherwise returns False.
- """
- s = socket.socket()
- try:
- s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- s.bind(('', host_port))
- s.close()
- return True
- except socket.error:
- return False
-
-
-def IsDevicePortUsed(device, device_port, state=''):
- """Checks whether the specified device port is used or not.
-
- Args:
- device: A DeviceUtils instance.
- device_port: Port on device we want to check.
- state: String of the specified state. Default is empty string, which
- means any state.
-
- Returns:
- True if the port on device is already used, otherwise returns False.
- """
- base_urls = ('127.0.0.1:%d' % device_port, 'localhost:%d' % device_port)
- netstat_results = device.RunShellCommand(
- ['netstat', '-a'], check_return=True, large_output=True)
- for single_connect in netstat_results:
- # Column 3 is the local address which we want to check with.
- connect_results = single_connect.split()
- if connect_results[0] != 'tcp':
- continue
- if len(connect_results) < 6:
- raise Exception('Unexpected format while parsing netstat line: ' +
- single_connect)
- is_state_match = connect_results[5] == state if state else True
- if connect_results[3] in base_urls and is_state_match:
- return True
- return False
-
-
-def IsHttpServerConnectable(host, port, tries=3, command='GET', path='/',
- expected_read='', timeout=2):
- """Checks whether the specified http server is ready to serve request or not.
-
- Args:
- host: Host name of the HTTP server.
- port: Port number of the HTTP server.
- tries: How many times we want to test the connection. The default value is
- 3.
- command: The http command we use to connect to HTTP server. The default
- command is 'GET'.
- path: The path we use when connecting to HTTP server. The default path is
- '/'.
- expected_read: The content we expect to read from the response. The default
- value is ''.
- timeout: Timeout (in seconds) for each http connection. The default is 2s.
-
- Returns:
- Tuple of (connect status, client error). connect status is a boolean value
- to indicate whether the server is connectable. client_error is the error
- message the server returns when connect status is false.
- """
- assert tries >= 1
- for i in xrange(0, tries):
- client_error = None
- try:
- with contextlib.closing(httplib.HTTPConnection(
- host, port, timeout=timeout)) as http:
- # Output some debug information when we have tried more than 2 times.
- http.set_debuglevel(i >= 2)
- http.request(command, path)
- r = http.getresponse()
- content = r.read()
- if r.status == 200 and r.reason == 'OK' and content == expected_read:
- return (True, '')
- client_error = ('Bad response: %s %s version %s\n ' %
- (r.status, r.reason, r.version) +
- '\n '.join([': '.join(h) for h in r.getheaders()]))
- except (httplib.HTTPException, socket.error) as e:
- # Probably too quick connecting: try again.
- exception_error_msgs = traceback.format_exception_only(type(e), e)
- if exception_error_msgs:
- client_error = ''.join(exception_error_msgs)
- # Only returns last client_error.
- return (False, client_error or 'Timeout')
diff --git a/third_party/catapult/devil/devil/android/sdk/__init__.py b/third_party/catapult/devil/devil/android/sdk/__init__.py
deleted file mode 100644
index f95d3b27b4..0000000000
--- a/third_party/catapult/devil/devil/android/sdk/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This package is intended for modules that are very tightly coupled to
-# tools or APIs from the Android SDK.
diff --git a/third_party/catapult/devil/devil/android/sdk/aapt.py b/third_party/catapult/devil/devil/android/sdk/aapt.py
deleted file mode 100644
index 7ae3a9380a..0000000000
--- a/third_party/catapult/devil/devil/android/sdk/aapt.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""This module wraps the Android Asset Packaging Tool."""
-
-from devil.android.sdk import build_tools
-from devil.utils import cmd_helper
-from devil.utils import lazy
-
-
-_aapt_path = lazy.WeakConstant(lambda: build_tools.GetPath('aapt'))
-
-
-def _RunAaptCmd(args):
- """Runs an aapt command.
-
- Args:
- args: A list of arguments for aapt.
-
- Returns:
- The output of the command.
- """
- cmd = [_aapt_path.read()] + args
- status, output = cmd_helper.GetCmdStatusAndOutput(cmd)
- if status != 0:
- raise Exception('Failed running aapt command: "%s" with output "%s".' %
- (' '.join(cmd), output))
- return output
-
-
-def Dump(what, apk, assets=None):
- """Returns the output of the aapt dump command.
-
- Args:
- what: What you want to dump.
- apk: Path to apk you want to dump information for.
- assets: List of assets in apk you want to dump information for.
- """
- assets = assets or []
- if isinstance(assets, basestring):
- assets = [assets]
- return _RunAaptCmd(['dump', what, apk] + assets).splitlines()
diff --git a/third_party/catapult/devil/devil/android/sdk/adb_compatibility_devicetest.py b/third_party/catapult/devil/devil/android/sdk/adb_compatibility_devicetest.py
deleted file mode 100644
index cbe2a1b6a0..0000000000
--- a/third_party/catapult/devil/devil/android/sdk/adb_compatibility_devicetest.py
+++ /dev/null
@@ -1,230 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import contextlib
-import os
-import posixpath
-import random
-import signal
-import sys
-import unittest
-
-_CATAPULT_BASE_DIR = os.path.abspath(os.path.join(
- os.path.dirname(__file__), '..', '..', '..', '..'))
-
-sys.path.append(os.path.join(_CATAPULT_BASE_DIR, 'devil'))
-from devil import devil_env
-from devil.android import device_errors
-from devil.android import device_test_case
-from devil.android.sdk import adb_wrapper
-from devil.utils import cmd_helper
-from devil.utils import timeout_retry
-
-
-_TEST_DATA_DIR = os.path.abspath(os.path.join(
- os.path.dirname(__file__), 'test', 'data'))
-
-
-def _hostAdbPids():
- ps_status, ps_output = cmd_helper.GetCmdStatusAndOutput(
- ['pgrep', '-l', 'adb'])
- if ps_status != 0:
- return []
-
- pids_and_names = (line.split() for line in ps_output.splitlines())
- return [int(pid) for pid, name in pids_and_names
- if name == 'adb']
-
-
-class AdbCompatibilityTest(device_test_case.DeviceTestCase):
-
- @classmethod
- def setUpClass(cls):
- custom_adb_path = os.environ.get('ADB_PATH')
- custom_deps = {
- 'config_type': 'BaseConfig',
- 'dependencies': {},
- }
- if custom_adb_path:
- custom_deps['dependencies']['adb'] = {
- 'file_info': {
- devil_env.GetPlatform(): {
- 'local_paths': [custom_adb_path],
- },
- },
- }
- devil_env.config.Initialize(configs=[custom_deps])
-
- def testStartServer(self):
- # Manually kill off any instances of adb.
- adb_pids = _hostAdbPids()
- for p in adb_pids:
- os.kill(p, signal.SIGKILL)
-
- self.assertIsNotNone(
- timeout_retry.WaitFor(
- lambda: not _hostAdbPids(), wait_period=0.1, max_tries=10))
-
- # start the adb server
- start_server_status, _ = cmd_helper.GetCmdStatusAndOutput(
- [adb_wrapper.AdbWrapper.GetAdbPath(), 'start-server'])
-
- # verify that the server is now online
- self.assertEquals(0, start_server_status)
- self.assertIsNotNone(
- timeout_retry.WaitFor(
- lambda: bool(_hostAdbPids()), wait_period=0.1, max_tries=10))
-
- def testKillServer(self):
- adb_pids = _hostAdbPids()
- if not adb_pids:
- adb_wrapper.AdbWrapper.StartServer()
-
- adb_pids = _hostAdbPids()
- self.assertGreaterEqual(len(adb_pids), 1)
-
- kill_server_status, _ = cmd_helper.GetCmdStatusAndOutput(
- [adb_wrapper.AdbWrapper.GetAdbPath(), 'kill-server'])
- self.assertEqual(0, kill_server_status)
-
- adb_pids = _hostAdbPids()
- self.assertEqual(0, len(adb_pids))
-
- def testDevices(self):
- devices = adb_wrapper.AdbWrapper.Devices()
- self.assertNotEqual(0, len(devices), 'No devices found.')
-
- def getTestInstance(self):
- """Creates a real AdbWrapper instance for testing."""
- return adb_wrapper.AdbWrapper(self.serial)
-
- def testShell(self):
- under_test = self.getTestInstance()
- shell_ls_result = under_test.Shell('ls')
- self.assertIsInstance(shell_ls_result, str)
- self.assertTrue(bool(shell_ls_result))
-
- def testShell_failed(self):
- under_test = self.getTestInstance()
- with self.assertRaises(device_errors.AdbShellCommandFailedError):
- under_test.Shell('ls /foo/bar/baz')
-
- def testShell_externalStorageDefined(self):
- under_test = self.getTestInstance()
- external_storage = under_test.Shell('echo $EXTERNAL_STORAGE')
- self.assertIsInstance(external_storage, str)
- self.assertTrue(posixpath.isabs(external_storage))
-
- @contextlib.contextmanager
- def getTestPushDestination(self, under_test):
- """Creates a temporary directory suitable for pushing to."""
- external_storage = under_test.Shell('echo $EXTERNAL_STORAGE').strip()
- if not external_storage:
- self.skipTest('External storage not available.')
- while True:
- random_hex = hex(random.randint(0, 2 ** 52))[2:]
- name = 'tmp_push_test%s' % random_hex
- path = posixpath.join(external_storage, name)
- try:
- under_test.Shell('ls %s' % path)
- except device_errors.AdbShellCommandFailedError:
- break
- under_test.Shell('mkdir %s' % path)
- try:
- yield path
- finally:
- under_test.Shell('rm -rf %s' % path)
-
- def testPush_fileToFile(self):
- under_test = self.getTestInstance()
- with self.getTestPushDestination(under_test) as push_target_directory:
- src = os.path.join(_TEST_DATA_DIR, 'push_file.txt')
- dest = posixpath.join(push_target_directory, 'push_file.txt')
- with self.assertRaises(device_errors.AdbShellCommandFailedError):
- under_test.Shell('ls %s' % dest)
- under_test.Push(src, dest)
- self.assertEquals(dest, under_test.Shell('ls %s' % dest).strip())
-
- def testPush_fileToDirectory(self):
- under_test = self.getTestInstance()
- with self.getTestPushDestination(under_test) as push_target_directory:
- src = os.path.join(_TEST_DATA_DIR, 'push_file.txt')
- dest = push_target_directory
- resulting_file = posixpath.join(dest, 'push_file.txt')
- with self.assertRaises(device_errors.AdbShellCommandFailedError):
- under_test.Shell('ls %s' % resulting_file)
- under_test.Push(src, dest)
- self.assertEquals(
- resulting_file,
- under_test.Shell('ls %s' % resulting_file).strip())
-
- def testPush_directoryToDirectory(self):
- under_test = self.getTestInstance()
- with self.getTestPushDestination(under_test) as push_target_directory:
- src = os.path.join(_TEST_DATA_DIR, 'push_directory')
- dest = posixpath.join(push_target_directory, 'push_directory')
- with self.assertRaises(device_errors.AdbShellCommandFailedError):
- under_test.Shell('ls %s' % dest)
- under_test.Push(src, dest)
- self.assertEquals(
- sorted(os.listdir(src)),
- sorted(under_test.Shell('ls %s' % dest).strip().split()))
-
- def testPush_directoryToExistingDirectory(self):
- under_test = self.getTestInstance()
- with self.getTestPushDestination(under_test) as push_target_directory:
- src = os.path.join(_TEST_DATA_DIR, 'push_directory')
- dest = push_target_directory
- resulting_directory = posixpath.join(dest, 'push_directory')
- with self.assertRaises(device_errors.AdbShellCommandFailedError):
- under_test.Shell('ls %s' % resulting_directory)
- under_test.Shell('mkdir %s' % resulting_directory)
- under_test.Push(src, dest)
- self.assertEquals(
- sorted(os.listdir(src)),
- sorted(under_test.Shell('ls %s' % resulting_directory).split()))
-
- # TODO(jbudorick): Implement tests for the following:
- # taskset -c
- # devices [-l]
- # pull
- # shell
- # ls
- # logcat [-c] [-d] [-v] [-b]
- # forward [--remove] [--list]
- # jdwp
- # install [-l] [-r] [-s] [-d]
- # install-multiple [-l] [-r] [-s] [-d] [-p]
- # uninstall [-k]
- # backup -f [-apk] [-shared] [-nosystem] [-all]
- # restore
- # wait-for-device
- # get-state (BROKEN IN THE M SDK)
- # get-devpath
- # remount
- # reboot
- # reboot-bootloader
- # root
- # emu
-
- @classmethod
- def tearDownClass(cls):
- print
- print
- print 'tested %s' % adb_wrapper.AdbWrapper.GetAdbPath()
- print ' %s' % adb_wrapper.AdbWrapper.Version()
- print 'connected devices:'
- try:
- for d in adb_wrapper.AdbWrapper.Devices():
- print ' %s' % d
- except device_errors.AdbCommandFailedError:
- print ' <failed to list devices>'
- raise
- finally:
- print
-
-
-if __name__ == '__main__':
- sys.exit(unittest.main())
diff --git a/third_party/catapult/devil/devil/android/sdk/adb_wrapper.py b/third_party/catapult/devil/devil/android/sdk/adb_wrapper.py
deleted file mode 100644
index 7f6b8d952b..0000000000
--- a/third_party/catapult/devil/devil/android/sdk/adb_wrapper.py
+++ /dev/null
@@ -1,917 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""This module wraps Android's adb tool.
-
-This is a thin wrapper around the adb interface. Any additional complexity
-should be delegated to a higher level (ex. DeviceUtils).
-"""
-
-import collections
-import distutils.version
-import errno
-import logging
-import os
-import posixpath
-import re
-import subprocess
-
-from devil import devil_env
-from devil.android import decorators
-from devil.android import device_errors
-from devil.utils import cmd_helper
-from devil.utils import lazy
-from devil.utils import timeout_retry
-
-with devil_env.SysPath(devil_env.DEPENDENCY_MANAGER_PATH):
- import dependency_manager # pylint: disable=import-error
-
-logger = logging.getLogger(__name__)
-
-
-ADB_KEYS_FILE = '/data/misc/adb/adb_keys'
-
-DEFAULT_TIMEOUT = 30
-DEFAULT_RETRIES = 2
-
-_ADB_VERSION_RE = re.compile(r'Android Debug Bridge version (\d+\.\d+\.\d+)')
-_EMULATOR_RE = re.compile(r'^emulator-[0-9]+$')
-_READY_STATE = 'device'
-_VERITY_DISABLE_RE = re.compile(r'Verity (already )?disabled')
-_VERITY_ENABLE_RE = re.compile(r'Verity (already )?enabled')
-
-
-def VerifyLocalFileExists(path):
- """Verifies a local file exists.
-
- Args:
- path: Path to the local file.
-
- Raises:
- IOError: If the file doesn't exist.
- """
- if not os.path.exists(path):
- raise IOError(errno.ENOENT, os.strerror(errno.ENOENT), path)
-
-
-def _FindAdb():
- try:
- return devil_env.config.LocalPath('adb')
- except dependency_manager.NoPathFoundError:
- pass
-
- try:
- return os.path.join(devil_env.config.LocalPath('android_sdk'),
- 'platform-tools', 'adb')
- except dependency_manager.NoPathFoundError:
- pass
-
- try:
- return devil_env.config.FetchPath('adb')
- except dependency_manager.NoPathFoundError:
- raise device_errors.NoAdbError()
-
-
-def _GetVersion():
- # pylint: disable=protected-access
- raw_version = AdbWrapper._RunAdbCmd(['version'], timeout=2, retries=0)
- for l in raw_version.splitlines():
- m = _ADB_VERSION_RE.search(l)
- if m:
- return m.group(1)
- return None
-
-
-def _ShouldRetryAdbCmd(exc):
- return not isinstance(exc, device_errors.NoAdbError)
-
-
-DeviceStat = collections.namedtuple('DeviceStat',
- ['st_mode', 'st_size', 'st_time'])
-
-
-def _IsExtraneousLine(line, send_cmd):
- """Determine if a line read from stdout in persistent shell is extraneous.
-
- The results output to stdout by the persistent shell process
- (in PersistentShell below) often include "extraneous" lines that are
- not part of the output of the shell command. These "extraneous" lines
- do not always appear and are of two forms: shell prompt lines and lines
- that just duplicate what the input command was. This function
- detects these extraneous lines. Since all these lines have the
- original command in them, that is what it detects ror.
-
- Args:
- line: Output line to check.
- send_cmd: Command that was sent to adb persistent shell.
- """
- return send_cmd.rstrip() in line
-
-
-class AdbWrapper(object):
- """A wrapper around a local Android Debug Bridge executable."""
-
- _adb_path = lazy.WeakConstant(_FindAdb)
- _adb_version = lazy.WeakConstant(_GetVersion)
-
- def __init__(self, device_serial):
- """Initializes the AdbWrapper.
-
- Args:
- device_serial: The device serial number as a string.
- """
- if not device_serial:
- raise ValueError('A device serial must be specified')
- self._device_serial = str(device_serial)
-
- class PersistentShell(object):
- '''Class to use persistent shell for ADB.
-
- This class allows a persistent ADB shell to be created, where multiple
- commands can be passed into it. This avoids the overhead of starting
- up a new ADB shell for each command.
-
- Example of use:
- with PersistentShell('123456789') as pshell:
- pshell.RunCommand('which ls')
- pshell.RunCommandAndClose('echo TEST')
- '''
- def __init__(self, serial):
- """Initialization function:
-
- Args:
- serial: Serial number of device.
- """
- self._cmd = [AdbWrapper.GetAdbPath(), '-s', serial, 'shell']
- self._process = None
-
- def __enter__(self):
- self.Start()
- self.WaitForReady()
- return self
-
- def __exit__(self, exc_type, exc_value, tb):
- self.Stop()
-
- def Start(self):
- """Start the shell."""
- if self._process is not None:
- raise RuntimeError('Persistent shell already running.')
- self._process = subprocess.Popen(self._cmd,
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- shell=False)
-
- def WaitForReady(self):
- """Wait for the shell to be ready after starting.
-
- Sends an echo command, then waits until it gets a response.
- """
- self._process.stdin.write('echo\n')
- output_line = self._process.stdout.readline()
- while output_line.rstrip() != '':
- output_line = self._process.stdout.readline()
-
- def RunCommand(self, command, close=False):
- """Runs an ADB command and returns the output.
-
- Note that there can be approximately 40 ms of additional latency
- between sending the command and receiving the results if close=False
- due to the use of Nagle's algorithm in the TCP socket between the
- adb server and client. To avoid this extra latency, set close=True.
-
- Args:
- command: Command to send.
- Returns:
- The command output, given as a list of lines, and the exit code
- """
-
- if close:
- def run_cmd(cmd):
- send_cmd = '( %s ); echo $?; exit;\n' % cmd.rstrip()
- (output, _) = self._process.communicate(send_cmd)
- self._process = None
- for x in output.splitlines():
- yield x
-
- else:
- def run_cmd(cmd):
- send_cmd = '( %s ); echo DONE:$?;\n' % cmd.rstrip()
- self._process.stdin.write(send_cmd)
- while True:
- output_line = self._process.stdout.readline().rstrip()
- if output_line[:5] == 'DONE:':
- yield output_line[5:]
- break
- yield output_line
-
- result = [line for line in run_cmd(command)
- if not _IsExtraneousLine(line, command)]
-
- return (result[:-1], int(result[-1]))
-
- def Stop(self):
- """Stops the ADB process if it is still running."""
- if self._process is not None:
- self._process.stdin.write('exit\n')
- self._process = None
-
- @classmethod
- def GetAdbPath(cls):
- return cls._adb_path.read()
-
- @classmethod
- def Version(cls):
- return cls._adb_version.read()
-
- @classmethod
- def _BuildAdbCmd(cls, args, device_serial, cpu_affinity=None):
- if cpu_affinity is not None:
- cmd = ['taskset', '-c', str(cpu_affinity)]
- else:
- cmd = []
- cmd.append(cls.GetAdbPath())
- if device_serial is not None:
- cmd.extend(['-s', device_serial])
- cmd.extend(args)
- return cmd
-
- # pylint: disable=unused-argument
- @classmethod
- @decorators.WithTimeoutAndConditionalRetries(_ShouldRetryAdbCmd)
- def _RunAdbCmd(cls, args, timeout=None, retries=None, device_serial=None,
- check_error=True, cpu_affinity=None):
- # pylint: disable=no-member
- try:
- status, output = cmd_helper.GetCmdStatusAndOutputWithTimeout(
- cls._BuildAdbCmd(args, device_serial, cpu_affinity=cpu_affinity),
- timeout_retry.CurrentTimeoutThreadGroup().GetRemainingTime())
- except OSError as e:
- if e.errno in (errno.ENOENT, errno.ENOEXEC):
- raise device_errors.NoAdbError(msg=str(e))
- else:
- raise
-
- if status != 0:
- raise device_errors.AdbCommandFailedError(
- args, output, status, device_serial)
- # This catches some errors, including when the device drops offline;
- # unfortunately adb is very inconsistent with error reporting so many
- # command failures present differently.
- if check_error and output.startswith('error:'):
- raise device_errors.AdbCommandFailedError(args, output)
- return output
- # pylint: enable=unused-argument
-
- def _RunDeviceAdbCmd(self, args, timeout, retries, check_error=True):
- """Runs an adb command on the device associated with this object.
-
- Args:
- args: A list of arguments to adb.
- timeout: Timeout in seconds.
- retries: Number of retries.
- check_error: Check that the command doesn't return an error message. This
- does NOT check the exit status of shell commands.
-
- Returns:
- The output of the command.
- """
- return self._RunAdbCmd(args, timeout=timeout, retries=retries,
- device_serial=self._device_serial,
- check_error=check_error)
-
- def _IterRunDeviceAdbCmd(self, args, iter_timeout, timeout):
- """Runs an adb command and returns an iterator over its output lines.
-
- Args:
- args: A list of arguments to adb.
- iter_timeout: Timeout for each iteration in seconds.
- timeout: Timeout for the entire command in seconds.
-
- Yields:
- The output of the command line by line.
- """
- return cmd_helper.IterCmdOutputLines(
- self._BuildAdbCmd(args, self._device_serial),
- iter_timeout=iter_timeout,
- timeout=timeout)
-
- def __eq__(self, other):
- """Consider instances equal if they refer to the same device.
-
- Args:
- other: The instance to compare equality with.
-
- Returns:
- True if the instances are considered equal, false otherwise.
- """
- return self._device_serial == str(other)
-
- def __str__(self):
- """The string representation of an instance.
-
- Returns:
- The device serial number as a string.
- """
- return self._device_serial
-
- def __repr__(self):
- return '%s(\'%s\')' % (self.__class__.__name__, self)
-
- # pylint: disable=unused-argument
- @classmethod
- def IsServerOnline(cls):
- status, output = cmd_helper.GetCmdStatusAndOutput(['pgrep', 'adb'])
- output = [int(x) for x in output.split()]
- logger.info('PIDs for adb found: %r', output)
- return status == 0
- # pylint: enable=unused-argument
-
- @classmethod
- def KillServer(cls, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
- cls._RunAdbCmd(['kill-server'], timeout=timeout, retries=retries)
-
- @classmethod
- def StartServer(cls, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
- # CPU affinity is used to reduce adb instability http://crbug.com/268450
- cls._RunAdbCmd(['start-server'], timeout=timeout, retries=retries,
- cpu_affinity=0)
-
- @classmethod
- def GetDevices(cls, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
- """DEPRECATED. Refer to Devices(...) below."""
- # TODO(jbudorick): Remove this function once no more clients are using it.
- return cls.Devices(timeout=timeout, retries=retries)
-
- @classmethod
- def Devices(cls, desired_state=_READY_STATE, long_list=False,
- timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
- """Get the list of active attached devices.
-
- Args:
- desired_state: If not None, limit the devices returned to only those
- in the given state.
- long_list: Whether to use the long listing format.
- timeout: (optional) Timeout per try in seconds.
- retries: (optional) Number of retries to attempt.
-
- Yields:
- AdbWrapper instances.
- """
- lines = cls._RawDevices(long_list=long_list, timeout=timeout,
- retries=retries)
- if long_list:
- return [
- [AdbWrapper(line[0])] + line[1:]
- for line in lines
- if (len(line) >= 2 and (not desired_state or line[1] == desired_state))
- ]
- else:
- return [
- AdbWrapper(line[0])
- for line in lines
- if (len(line) == 2 and (not desired_state or line[1] == desired_state))
- ]
-
- @classmethod
- def _RawDevices(cls, long_list=False, timeout=DEFAULT_TIMEOUT,
- retries=DEFAULT_RETRIES):
- cmd = ['devices']
- if long_list:
- cmd.append('-l')
- output = cls._RunAdbCmd(cmd, timeout=timeout, retries=retries)
- return [line.split() for line in output.splitlines()[1:]]
-
- def GetDeviceSerial(self):
- """Gets the device serial number associated with this object.
-
- Returns:
- Device serial number as a string.
- """
- return self._device_serial
-
- def Push(self, local, remote, timeout=60 * 5, retries=DEFAULT_RETRIES):
- """Pushes a file from the host to the device.
-
- Args:
- local: Path on the host filesystem.
- remote: Path on the device filesystem.
- timeout: (optional) Timeout per try in seconds.
- retries: (optional) Number of retries to attempt.
- """
- VerifyLocalFileExists(local)
-
- if (distutils.version.LooseVersion(self.Version()) <
- distutils.version.LooseVersion('1.0.36')):
-
- # Different versions of adb handle pushing a directory to an existing
- # directory differently.
-
- # In the version packaged with the M SDK, 1.0.32, the following push:
- # foo/bar -> /sdcard/foo/bar
- # where bar is an existing directory both on the host and the device
- # results in the contents of bar/ on the host being pushed to bar/ on
- # the device, i.e.
- # foo/bar/A -> /sdcard/foo/bar/A
- # foo/bar/B -> /sdcard/foo/bar/B
- # ... etc.
-
- # In the version packaged with the N SDK, 1.0.36, the same push under
- # the same conditions results in a second bar/ directory being created
- # underneath the first bar/ directory on the device, i.e.
- # foo/bar/A -> /sdcard/foo/bar/bar/A
- # foo/bar/B -> /sdcard/foo/bar/bar/B
- # ... etc.
-
- # In order to provide a consistent interface to clients, we check whether
- # the target is an existing directory on the device and, if so, modifies
- # the target passed to adb to emulate the behavior on 1.0.36 and above.
-
- # Note that this behavior may have started before 1.0.36; that's simply
- # the earliest version we've confirmed thus far.
-
- try:
- self.Shell('test -d %s' % remote, timeout=timeout, retries=retries)
- remote = posixpath.join(remote, posixpath.basename(local))
- except device_errors.AdbShellCommandFailedError:
- # The target directory doesn't exist on the device, so we can use it
- # without modification.
- pass
-
- self._RunDeviceAdbCmd(['push', local, remote], timeout, retries)
-
- def Pull(self, remote, local, timeout=60 * 5, retries=DEFAULT_RETRIES):
- """Pulls a file from the device to the host.
-
- Args:
- remote: Path on the device filesystem.
- local: Path on the host filesystem.
- timeout: (optional) Timeout per try in seconds.
- retries: (optional) Number of retries to attempt.
- """
- cmd = ['pull', remote, local]
- self._RunDeviceAdbCmd(cmd, timeout, retries)
- try:
- VerifyLocalFileExists(local)
- except IOError:
- raise device_errors.AdbCommandFailedError(
- cmd,
- 'File pulled from the device did not arrive on the host: %s' % local,
- device_serial=str(self))
-
- def Shell(self, command, expect_status=0, timeout=DEFAULT_TIMEOUT,
- retries=DEFAULT_RETRIES):
- """Runs a shell command on the device.
-
- Args:
- command: A string with the shell command to run.
- expect_status: (optional) Check that the command's exit status matches
- this value. Default is 0. If set to None the test is skipped.
- timeout: (optional) Timeout per try in seconds.
- retries: (optional) Number of retries to attempt.
-
- Returns:
- The output of the shell command as a string.
-
- Raises:
- device_errors.AdbCommandFailedError: If the exit status doesn't match
- |expect_status|.
- """
- if expect_status is None:
- args = ['shell', command]
- else:
- args = ['shell', '( %s );echo %%$?' % command.rstrip()]
- output = self._RunDeviceAdbCmd(args, timeout, retries, check_error=False)
- if expect_status is not None:
- output_end = output.rfind('%')
- if output_end < 0:
- # causes the status string to become empty and raise a ValueError
- output_end = len(output)
-
- try:
- status = int(output[output_end + 1:])
- except ValueError:
- logger.warning('exit status of shell command %r missing.', command)
- raise device_errors.AdbShellCommandFailedError(
- command, output, status=None, device_serial=self._device_serial)
- output = output[:output_end]
- if status != expect_status:
- raise device_errors.AdbShellCommandFailedError(
- command, output, status=status, device_serial=self._device_serial)
- return output
-
- def IterShell(self, command, timeout):
- """Runs a shell command and returns an iterator over its output lines.
-
- Args:
- command: A string with the shell command to run.
- timeout: Timeout in seconds.
-
- Yields:
- The output of the command line by line.
- """
- args = ['shell', command]
- return cmd_helper.IterCmdOutputLines(
- self._BuildAdbCmd(args, self._device_serial), timeout=timeout)
-
- def Ls(self, path, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
- """List the contents of a directory on the device.
-
- Args:
- path: Path on the device filesystem.
- timeout: (optional) Timeout per try in seconds.
- retries: (optional) Number of retries to attempt.
-
- Returns:
- A list of pairs (filename, stat) for each file found in the directory,
- where the stat object has the properties: st_mode, st_size, and st_time.
-
- Raises:
- AdbCommandFailedError if |path| does not specify a valid and accessible
- directory in the device, or the output of "adb ls" command is less
- than four columns
- """
- def ParseLine(line, cmd):
- cols = line.split(None, 3)
- if len(cols) < 4:
- raise device_errors.AdbCommandFailedError(
- cmd, line, "the output should be 4 columns, but is only %d columns"
- % len(cols), device_serial=self._device_serial)
- filename = cols.pop()
- stat = DeviceStat(*[int(num, base=16) for num in cols])
- return (filename, stat)
-
- cmd = ['ls', path]
- lines = self._RunDeviceAdbCmd(
- cmd, timeout=timeout, retries=retries).splitlines()
- if lines:
- return [ParseLine(line, cmd) for line in lines]
- else:
- raise device_errors.AdbCommandFailedError(
- cmd, 'path does not specify an accessible directory in the device',
- device_serial=self._device_serial)
-
- def Logcat(self, clear=False, dump=False, filter_specs=None,
- logcat_format=None, ring_buffer=None, iter_timeout=None,
- timeout=None, retries=DEFAULT_RETRIES):
- """Get an iterable over the logcat output.
-
- Args:
- clear: If true, clear the logcat.
- dump: If true, dump the current logcat contents.
- filter_specs: If set, a list of specs to filter the logcat.
- logcat_format: If set, the format in which the logcat should be output.
- Options include "brief", "process", "tag", "thread", "raw", "time",
- "threadtime", and "long"
- ring_buffer: If set, a list of alternate ring buffers to request.
- Options include "main", "system", "radio", "events", "crash" or "all".
- The default is equivalent to ["main", "system", "crash"].
- iter_timeout: If set and neither clear nor dump is set, the number of
- seconds to wait between iterations. If no line is found before the
- given number of seconds elapses, the iterable will yield None.
- timeout: (optional) If set, timeout per try in seconds. If clear or dump
- is set, defaults to DEFAULT_TIMEOUT.
- retries: (optional) If clear or dump is set, the number of retries to
- attempt. Otherwise, does nothing.
-
- Yields:
- logcat output line by line.
- """
- cmd = ['logcat']
- use_iter = True
- if clear:
- cmd.append('-c')
- use_iter = False
- if dump:
- cmd.append('-d')
- use_iter = False
- if logcat_format:
- cmd.extend(['-v', logcat_format])
- if ring_buffer:
- for buffer_name in ring_buffer:
- cmd.extend(['-b', buffer_name])
- if filter_specs:
- cmd.extend(filter_specs)
-
- if use_iter:
- return self._IterRunDeviceAdbCmd(cmd, iter_timeout, timeout)
- else:
- timeout = timeout if timeout is not None else DEFAULT_TIMEOUT
- return self._RunDeviceAdbCmd(cmd, timeout, retries).splitlines()
-
- def Forward(self, local, remote, allow_rebind=False,
- timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
- """Forward socket connections from the local socket to the remote socket.
-
- Sockets are specified by 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)
-
- Args:
- local: The host socket.
- remote: The device socket.
- allow_rebind: A boolean indicating whether adb may rebind a local socket;
- otherwise, the default, an exception is raised if the local socket is
- already being forwarded.
- timeout: (optional) Timeout per try in seconds.
- retries: (optional) Number of retries to attempt.
- """
- cmd = ['forward']
- if not allow_rebind:
- cmd.append('--no-rebind')
- cmd.extend([str(local), str(remote)])
- self._RunDeviceAdbCmd(cmd, timeout, retries)
-
- def ForwardRemove(self, local, timeout=DEFAULT_TIMEOUT,
- retries=DEFAULT_RETRIES):
- """Remove a forward socket connection.
-
- Args:
- local: The host socket.
- timeout: (optional) Timeout per try in seconds.
- retries: (optional) Number of retries to attempt.
- """
- self._RunDeviceAdbCmd(['forward', '--remove', str(local)], timeout,
- retries)
-
- def ForwardList(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
- """List all currently forwarded socket connections.
-
- Args:
- timeout: (optional) Timeout per try in seconds.
- retries: (optional) Number of retries to attempt.
- Returns:
- The output of adb forward --list as a string.
- """
- if (distutils.version.LooseVersion(self.Version()) >=
- distutils.version.LooseVersion('1.0.36')):
- # Starting in 1.0.36, this can occasionally fail with a protocol fault.
- # As this interrupts all connections with all devices, we instead just
- # return an empty list. This may give clients an inaccurate result, but
- # that's usually better than crashing the adb server.
-
- # TODO(jbudorick): Determine an appropriate upper version bound for this
- # once b/31811775 is fixed.
- return ''
-
- return self._RunDeviceAdbCmd(['forward', '--list'], timeout, retries)
-
- def JDWP(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
- """List of PIDs of processes hosting a JDWP transport.
-
- Args:
- timeout: (optional) Timeout per try in seconds.
- retries: (optional) Number of retries to attempt.
-
- Returns:
- A list of PIDs as strings.
- """
- return [a.strip() for a in
- self._RunDeviceAdbCmd(['jdwp'], timeout, retries).split('\n')]
-
- def Install(self, apk_path, forward_lock=False, allow_downgrade=False,
- reinstall=False, sd_card=False, timeout=60 * 2,
- retries=DEFAULT_RETRIES):
- """Install an apk on the device.
-
- Args:
- apk_path: Host path to the APK file.
- forward_lock: (optional) If set forward-locks the app.
- allow_downgrade: (optional) If set, allows for downgrades.
- reinstall: (optional) If set reinstalls the app, keeping its data.
- sd_card: (optional) If set installs on the SD card.
- timeout: (optional) Timeout per try in seconds.
- retries: (optional) Number of retries to attempt.
- """
- VerifyLocalFileExists(apk_path)
- cmd = ['install']
- if forward_lock:
- cmd.append('-l')
- if reinstall:
- cmd.append('-r')
- if sd_card:
- cmd.append('-s')
- if allow_downgrade:
- cmd.append('-d')
- cmd.append(apk_path)
- output = self._RunDeviceAdbCmd(cmd, timeout, retries)
- if 'Success' not in output:
- raise device_errors.AdbCommandFailedError(
- cmd, output, device_serial=self._device_serial)
-
- def InstallMultiple(self, apk_paths, forward_lock=False, reinstall=False,
- sd_card=False, allow_downgrade=False, partial=False,
- timeout=60 * 2, retries=DEFAULT_RETRIES):
- """Install an apk with splits on the device.
-
- Args:
- apk_paths: Host path to the APK file.
- forward_lock: (optional) If set forward-locks the app.
- reinstall: (optional) If set reinstalls the app, keeping its data.
- sd_card: (optional) If set installs on the SD card.
- allow_downgrade: (optional) Allow versionCode downgrade.
- partial: (optional) Package ID if apk_paths doesn't include all .apks.
- timeout: (optional) Timeout per try in seconds.
- retries: (optional) Number of retries to attempt.
- """
- for path in apk_paths:
- VerifyLocalFileExists(path)
- cmd = ['install-multiple']
- if forward_lock:
- cmd.append('-l')
- if reinstall:
- cmd.append('-r')
- if sd_card:
- cmd.append('-s')
- if allow_downgrade:
- cmd.append('-d')
- if partial:
- cmd.extend(('-p', partial))
- cmd.extend(apk_paths)
- output = self._RunDeviceAdbCmd(cmd, timeout, retries)
- if 'Success' not in output:
- raise device_errors.AdbCommandFailedError(
- cmd, output, device_serial=self._device_serial)
-
- def Uninstall(self, package, keep_data=False, timeout=DEFAULT_TIMEOUT,
- retries=DEFAULT_RETRIES):
- """Remove the app |package| from the device.
-
- Args:
- package: The package to uninstall.
- keep_data: (optional) If set keep the data and cache directories.
- timeout: (optional) Timeout per try in seconds.
- retries: (optional) Number of retries to attempt.
- """
- cmd = ['uninstall']
- if keep_data:
- cmd.append('-k')
- cmd.append(package)
- output = self._RunDeviceAdbCmd(cmd, timeout, retries)
- if 'Failure' in output or 'Exception' in output:
- raise device_errors.AdbCommandFailedError(
- cmd, output, device_serial=self._device_serial)
-
- def Backup(self, path, packages=None, apk=False, shared=False,
- nosystem=True, include_all=False, timeout=DEFAULT_TIMEOUT,
- retries=DEFAULT_RETRIES):
- """Write an archive of the device's data to |path|.
-
- Args:
- path: Local path to store the backup file.
- packages: List of to packages to be backed up.
- apk: (optional) If set include the .apk files in the archive.
- shared: (optional) If set buckup the device's SD card.
- nosystem: (optional) If set exclude system applications.
- include_all: (optional) If set back up all installed applications and
- |packages| is optional.
- timeout: (optional) Timeout per try in seconds.
- retries: (optional) Number of retries to attempt.
- """
- cmd = ['backup', '-f', path]
- if apk:
- cmd.append('-apk')
- if shared:
- cmd.append('-shared')
- if nosystem:
- cmd.append('-nosystem')
- if include_all:
- cmd.append('-all')
- if packages:
- cmd.extend(packages)
- assert bool(packages) ^ bool(include_all), (
- 'Provide \'packages\' or set \'include_all\' but not both.')
- ret = self._RunDeviceAdbCmd(cmd, timeout, retries)
- VerifyLocalFileExists(path)
- return ret
-
- def Restore(self, path, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
- """Restore device contents from the backup archive.
-
- Args:
- path: Host path to the backup archive.
- timeout: (optional) Timeout per try in seconds.
- retries: (optional) Number of retries to attempt.
- """
- VerifyLocalFileExists(path)
- self._RunDeviceAdbCmd(['restore'] + [path], timeout, retries)
-
- def WaitForDevice(self, timeout=60 * 5, retries=DEFAULT_RETRIES):
- """Block until the device is online.
-
- Args:
- timeout: (optional) Timeout per try in seconds.
- retries: (optional) Number of retries to attempt.
- """
- self._RunDeviceAdbCmd(['wait-for-device'], timeout, retries)
-
- def GetState(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
- """Get device state.
-
- Args:
- timeout: (optional) Timeout per try in seconds.
- retries: (optional) Number of retries to attempt.
-
- Returns:
- One of 'offline', 'bootloader', or 'device'.
- """
- # TODO(jbudorick): Revert to using get-state once it doesn't cause a
- # a protocol fault.
- # return self._RunDeviceAdbCmd(['get-state'], timeout, retries).strip()
-
- lines = self._RawDevices(timeout=timeout, retries=retries)
- for line in lines:
- if len(line) >= 2 and line[0] == self._device_serial:
- return line[1]
- return 'offline'
-
- def GetDevPath(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
- """Gets the device path.
-
- Args:
- timeout: (optional) Timeout per try in seconds.
- retries: (optional) Number of retries to attempt.
-
- Returns:
- The device path (e.g. usb:3-4)
- """
- return self._RunDeviceAdbCmd(['get-devpath'], timeout, retries)
-
- def Remount(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
- """Remounts the /system partition on the device read-write."""
- self._RunDeviceAdbCmd(['remount'], timeout, retries)
-
- def Reboot(self, to_bootloader=False, timeout=60 * 5,
- retries=DEFAULT_RETRIES):
- """Reboots the device.
-
- Args:
- to_bootloader: (optional) If set reboots to the bootloader.
- timeout: (optional) Timeout per try in seconds.
- retries: (optional) Number of retries to attempt.
- """
- if to_bootloader:
- cmd = ['reboot-bootloader']
- else:
- cmd = ['reboot']
- self._RunDeviceAdbCmd(cmd, timeout, retries)
-
- def Root(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
- """Restarts the adbd daemon with root permissions, if possible.
-
- Args:
- timeout: (optional) Timeout per try in seconds.
- retries: (optional) Number of retries to attempt.
- """
- output = self._RunDeviceAdbCmd(['root'], timeout, retries)
- if 'cannot' in output:
- raise device_errors.AdbCommandFailedError(
- ['root'], output, device_serial=self._device_serial)
-
- def Emu(self, cmd, timeout=DEFAULT_TIMEOUT,
- retries=DEFAULT_RETRIES):
- """Runs an emulator console command.
-
- See http://developer.android.com/tools/devices/emulator.html#console
-
- Args:
- cmd: The command to run on the emulator console.
- timeout: (optional) Timeout per try in seconds.
- retries: (optional) Number of retries to attempt.
-
- Returns:
- The output of the emulator console command.
- """
- if isinstance(cmd, basestring):
- cmd = [cmd]
- return self._RunDeviceAdbCmd(['emu'] + cmd, timeout, retries)
-
- def DisableVerity(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
- """Disable Marshmallow's Verity security feature"""
- output = self._RunDeviceAdbCmd(['disable-verity'], timeout, retries)
- if output and not _VERITY_DISABLE_RE.search(output):
- raise device_errors.AdbCommandFailedError(
- ['disable-verity'], output, device_serial=self._device_serial)
-
- def EnableVerity(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES):
- """Enable Marshmallow's Verity security feature"""
- output = self._RunDeviceAdbCmd(['enable-verity'], timeout, retries)
- if output and not _VERITY_ENABLE_RE.search(output):
- raise device_errors.AdbCommandFailedError(
- ['enable-verity'], output, device_serial=self._device_serial)
-
- @property
- def is_emulator(self):
- return _EMULATOR_RE.match(self._device_serial)
-
- @property
- def is_ready(self):
- try:
- return self.GetState() == _READY_STATE
- except device_errors.CommandFailedError:
- return False
diff --git a/third_party/catapult/devil/devil/android/sdk/adb_wrapper_devicetest.py b/third_party/catapult/devil/devil/android/sdk/adb_wrapper_devicetest.py
deleted file mode 100755
index d97d56a1a2..0000000000
--- a/third_party/catapult/devil/devil/android/sdk/adb_wrapper_devicetest.py
+++ /dev/null
@@ -1,118 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Tests for the AdbWrapper class."""
-
-import os
-import tempfile
-import time
-import unittest
-
-from devil.android import device_test_case
-from devil.android import device_errors
-from devil.android.sdk import adb_wrapper
-
-
-class TestAdbWrapper(device_test_case.DeviceTestCase):
-
- def setUp(self):
- super(TestAdbWrapper, self).setUp()
- self._adb = adb_wrapper.AdbWrapper(self.serial)
- self._adb.WaitForDevice()
-
- @staticmethod
- def _MakeTempFile(contents):
- """Make a temporary file with the given contents.
-
- Args:
- contents: string to write to the temporary file.
-
- Returns:
- The absolute path to the file.
- """
- fi, path = tempfile.mkstemp()
- with os.fdopen(fi, 'wb') as f:
- f.write(contents)
- return path
-
- def testShell(self):
- output = self._adb.Shell('echo test', expect_status=0)
- self.assertEqual(output.strip(), 'test')
- output = self._adb.Shell('echo test')
- self.assertEqual(output.strip(), 'test')
- with self.assertRaises(device_errors.AdbCommandFailedError):
- self._adb.Shell('echo test', expect_status=1)
-
- @unittest.skip("https://github.com/catapult-project/catapult/issues/2574")
- def testPersistentShell(self):
- # We need to access the device serial number here in order
- # to create the persistent shell.
- serial = self._adb.GetDeviceSerial() # pylint: disable=protected-access
- with self._adb.PersistentShell(serial) as pshell:
- (res1, code1) = pshell.RunCommand('echo TEST')
- (res2, code2) = pshell.RunCommand('echo TEST2')
- self.assertEqual(len(res1), 1)
- self.assertEqual(res1[0], 'TEST')
- self.assertEqual(res2[-1], 'TEST2')
- self.assertEqual(code1, 0)
- self.assertEqual(code2, 0)
-
- def testPushLsPull(self):
- path = self._MakeTempFile('foo')
- device_path = '/data/local/tmp/testfile.txt'
- local_tmpdir = os.path.dirname(path)
- self._adb.Push(path, device_path)
- files = dict(self._adb.Ls('/data/local/tmp'))
- self.assertTrue('testfile.txt' in files)
- self.assertEquals(3, files['testfile.txt'].st_size)
- self.assertEqual(self._adb.Shell('cat %s' % device_path), 'foo')
- self._adb.Pull(device_path, local_tmpdir)
- with open(os.path.join(local_tmpdir, 'testfile.txt'), 'r') as f:
- self.assertEqual(f.read(), 'foo')
-
- def testInstall(self):
- path = self._MakeTempFile('foo')
- with self.assertRaises(device_errors.AdbCommandFailedError):
- self._adb.Install(path)
-
- def testForward(self):
- with self.assertRaises(device_errors.AdbCommandFailedError):
- self._adb.Forward(0, 0)
-
- def testUninstall(self):
- with self.assertRaises(device_errors.AdbCommandFailedError):
- self._adb.Uninstall('some.nonexistant.package')
-
- def testRebootWaitForDevice(self):
- self._adb.Reboot()
- print 'waiting for device to reboot...'
- while self._adb.GetState() == 'device':
- time.sleep(1)
- self._adb.WaitForDevice()
- self.assertEqual(self._adb.GetState(), 'device')
- print 'waiting for package manager...'
- while True:
- try:
- android_path = self._adb.Shell('pm path android')
- except device_errors.AdbShellCommandFailedError:
- android_path = None
- if android_path and 'package:' in android_path:
- break
- time.sleep(1)
-
- def testRootRemount(self):
- self._adb.Root()
- while True:
- try:
- self._adb.Shell('start')
- break
- except device_errors.AdbCommandFailedError:
- time.sleep(1)
- self._adb.Remount()
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/third_party/catapult/devil/devil/android/sdk/adb_wrapper_test.py b/third_party/catapult/devil/devil/android/sdk/adb_wrapper_test.py
deleted file mode 100755
index ef08661208..0000000000
--- a/third_party/catapult/devil/devil/android/sdk/adb_wrapper_test.py
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""
-Unit tests for some APIs with conditional logic in adb_wrapper.py
-"""
-
-import unittest
-
-from devil import devil_env
-from devil.android import device_errors
-from devil.android.sdk import adb_wrapper
-
-with devil_env.SysPath(devil_env.PYMOCK_PATH):
- import mock # pylint: disable=import-error
-
-
-class AdbWrapperTest(unittest.TestCase):
- def setUp(self):
- self.adb = adb_wrapper.AdbWrapper('ABC12345678')
-
- def _MockRunDeviceAdbCmd(self, return_value):
- return mock.patch.object(
- self.adb,
- '_RunDeviceAdbCmd',
- mock.Mock(side_effect=None, return_value=return_value))
-
- def testDisableVerityWhenDisabled(self):
- with self._MockRunDeviceAdbCmd('Verity already disabled on /system'):
- self.adb.DisableVerity()
-
- def testDisableVerityWhenEnabled(self):
- with self._MockRunDeviceAdbCmd(
- 'Verity disabled on /system\nNow reboot your device for settings to '
- 'take effect'):
- self.adb.DisableVerity()
-
- def testEnableVerityWhenEnabled(self):
- with self._MockRunDeviceAdbCmd('Verity already enabled on /system'):
- self.adb.EnableVerity()
-
- def testEnableVerityWhenDisabled(self):
- with self._MockRunDeviceAdbCmd(
- 'Verity enabled on /system\nNow reboot your device for settings to '
- 'take effect'):
- self.adb.EnableVerity()
-
- def testFailEnableVerity(self):
- with self._MockRunDeviceAdbCmd('error: closed'):
- self.assertRaises(
- device_errors.AdbCommandFailedError, self.adb.EnableVerity)
-
- def testFailDisableVerity(self):
- with self._MockRunDeviceAdbCmd('error: closed'):
- self.assertRaises(
- device_errors.AdbCommandFailedError, self.adb.DisableVerity)
-
diff --git a/third_party/catapult/devil/devil/android/sdk/build_tools.py b/third_party/catapult/devil/devil/android/sdk/build_tools.py
deleted file mode 100644
index 99083d9904..0000000000
--- a/third_party/catapult/devil/devil/android/sdk/build_tools.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import os
-
-from devil import devil_env
-from devil.utils import lazy
-
-with devil_env.SysPath(devil_env.DEPENDENCY_MANAGER_PATH):
- import dependency_manager # pylint: disable=import-error
-
-
-def GetPath(build_tool):
- try:
- return devil_env.config.LocalPath(build_tool)
- except dependency_manager.NoPathFoundError:
- pass
-
- try:
- return _PathInLocalSdk(build_tool)
- except dependency_manager.NoPathFoundError:
- pass
-
- return devil_env.config.FetchPath(build_tool)
-
-
-def _PathInLocalSdk(build_tool):
- build_tools_path = _build_tools_path.read()
- return (os.path.join(build_tools_path, build_tool) if build_tools_path
- else None)
-
-
-def _FindBuildTools():
- android_sdk_path = devil_env.config.LocalPath('android_sdk')
- if not android_sdk_path:
- return None
-
- build_tools_contents = os.listdir(
- os.path.join(android_sdk_path, 'build-tools'))
-
- if not build_tools_contents:
- return None
- else:
- if len(build_tools_contents) > 1:
- build_tools_contents.sort()
- return os.path.join(android_sdk_path, 'build-tools',
- build_tools_contents[-1])
-
-
-_build_tools_path = lazy.WeakConstant(_FindBuildTools)
diff --git a/third_party/catapult/devil/devil/android/sdk/dexdump.py b/third_party/catapult/devil/devil/android/sdk/dexdump.py
deleted file mode 100644
index 992366e84a..0000000000
--- a/third_party/catapult/devil/devil/android/sdk/dexdump.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-from devil.android.sdk import build_tools
-from devil.utils import cmd_helper
-from devil.utils import lazy
-
-
-_dexdump_path = lazy.WeakConstant(lambda: build_tools.GetPath('dexdump'))
-
-
-def DexDump(dexfiles, file_summary=False):
- """A wrapper around the Android SDK's dexdump tool.
-
- Args:
- dexfiles: The dexfile or list of dex files to dump.
- file_summary: Display summary information from the file header. (-f)
-
- Returns:
- An iterable over the output lines.
- """
- # TODO(jbudorick): Add support for more options as necessary.
- if isinstance(dexfiles, basestring):
- dexfiles = [dexfiles]
- args = [_dexdump_path.read()] + dexfiles
- if file_summary:
- args.append('-f')
-
- return cmd_helper.IterCmdOutputLines(args)
-
diff --git a/third_party/catapult/devil/devil/android/sdk/fastboot.py b/third_party/catapult/devil/devil/android/sdk/fastboot.py
deleted file mode 100644
index d7f9f624bb..0000000000
--- a/third_party/catapult/devil/devil/android/sdk/fastboot.py
+++ /dev/null
@@ -1,98 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""This module wraps Android's fastboot tool.
-
-This is a thin wrapper around the fastboot interface. Any additional complexity
-should be delegated to a higher level (ex. FastbootUtils).
-"""
-# pylint: disable=unused-argument
-
-from devil import devil_env
-from devil.android import decorators
-from devil.android import device_errors
-from devil.utils import cmd_helper
-from devil.utils import lazy
-
-_DEFAULT_TIMEOUT = 30
-_DEFAULT_RETRIES = 3
-_FLASH_TIMEOUT = _DEFAULT_TIMEOUT * 10
-
-
-class Fastboot(object):
-
- _fastboot_path = lazy.WeakConstant(
- lambda: devil_env.config.FetchPath('fastboot'))
-
- def __init__(self, device_serial, default_timeout=_DEFAULT_TIMEOUT,
- default_retries=_DEFAULT_RETRIES):
- """Initializes the FastbootWrapper.
-
- Args:
- device_serial: The device serial number as a string.
- """
- if not device_serial:
- raise ValueError('A device serial must be specified')
- self._device_serial = str(device_serial)
- self._default_timeout = default_timeout
- self._default_retries = default_retries
-
- def _RunFastbootCommand(self, cmd):
- """Run a command line command using the fastboot android tool.
-
- Args:
- cmd: Command to run. Must be list of args, the first one being the command
-
- Returns:
- output of command.
-
- Raises:
- TypeError: If cmd is not of type list.
- """
- if type(cmd) == list:
- cmd = [self._fastboot_path.read(), '-s', self._device_serial] + cmd
- else:
- raise TypeError(
- 'Command for _RunFastbootCommand must be a list.')
- status, output = cmd_helper.GetCmdStatusAndOutput(cmd)
- if int(status) != 0:
- raise device_errors.FastbootCommandFailedError(
- cmd, output, status, self._device_serial)
- return output
-
- @decorators.WithTimeoutAndRetriesDefaults(_FLASH_TIMEOUT, 0)
- def Flash(self, partition, image, timeout=None, retries=None):
- """Flash partition with img.
-
- Args:
- partition: Partition to be flashed.
- image: location of image to flash with.
- """
- self._RunFastbootCommand(['flash', partition, image])
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def Devices(self, timeout=None, retries=None):
- """Outputs list of devices in fastboot mode."""
- output = self._RunFastbootCommand(['devices'])
- return [line.split()[0] for line in output.splitlines()]
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def RebootBootloader(self, timeout=None, retries=None):
- """Reboot from fastboot, into fastboot."""
- self._RunFastbootCommand(['reboot-bootloader'])
-
- @decorators.WithTimeoutAndRetriesDefaults(_FLASH_TIMEOUT, 0)
- def Reboot(self, timeout=None, retries=None):
- """Reboot from fastboot to normal usage"""
- self._RunFastbootCommand(['reboot'])
-
- @decorators.WithTimeoutAndRetriesFromInstance()
- def SetOemOffModeCharge(self, value, timeout=None, retries=None):
- """Sets off mode charging
-
- Args:
- value: boolean value to set off-mode-charging on or off.
- """
- self._RunFastbootCommand(
- ['oem', 'off-mode-charge', str(int(value))])
diff --git a/third_party/catapult/devil/devil/android/sdk/gce_adb_wrapper.py b/third_party/catapult/devil/devil/android/sdk/gce_adb_wrapper.py
deleted file mode 100644
index 71600f40a6..0000000000
--- a/third_party/catapult/devil/devil/android/sdk/gce_adb_wrapper.py
+++ /dev/null
@@ -1,154 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Provides a work around for various adb commands on android gce instances.
-
-Some adb commands don't work well when the device is a cloud vm, namely
-'push' and 'pull'. With gce instances, moving files through adb can be
-painfully slow and hit timeouts, so the methods here just use scp instead.
-"""
-# pylint: disable=unused-argument
-
-import logging
-import os
-import subprocess
-
-from devil.android import device_errors
-from devil.android.sdk import adb_wrapper
-from devil.utils import cmd_helper
-
-logger = logging.getLogger(__name__)
-
-
-class GceAdbWrapper(adb_wrapper.AdbWrapper):
-
- def __init__(self, device_serial):
- super(GceAdbWrapper, self).__init__(device_serial)
- self._Connect()
- self.Root()
- self._instance_ip = self.Shell('getprop net.gce.ip').strip()
-
- def _Connect(self, timeout=adb_wrapper.DEFAULT_TIMEOUT,
- retries=adb_wrapper.DEFAULT_RETRIES):
- """Connects ADB to the android gce instance."""
- cmd = ['connect', self._device_serial]
- output = self._RunAdbCmd(cmd, timeout=timeout, retries=retries)
- if 'unable to connect' in output:
- raise device_errors.AdbCommandFailedError(cmd, output)
- self.WaitForDevice()
-
- # override
- def Root(self, **kwargs):
- super(GceAdbWrapper, self).Root()
- self._Connect()
-
- # override
- def Push(self, local, remote, **kwargs):
- """Pushes an object from the host to the gce instance.
-
- Args:
- local: Path on the host filesystem.
- remote: Path on the instance filesystem.
- """
- adb_wrapper.VerifyLocalFileExists(local)
- if os.path.isdir(local):
- self.Shell('mkdir -p %s' % cmd_helper.SingleQuote(remote))
-
- # When the object to be pushed is a directory, adb merges the source dir
- # with the destination dir. So if local is a dir, just scp its contents.
- for f in os.listdir(local):
- self._PushObject(os.path.join(local, f), os.path.join(remote, f))
- self.Shell('chmod 777 %s' %
- cmd_helper.SingleQuote(os.path.join(remote, f)))
- else:
- parent_dir = remote[0:remote.rfind('/')]
- if parent_dir:
- self.Shell('mkdir -p %s' % cmd_helper.SingleQuote(parent_dir))
- self._PushObject(local, remote)
- self.Shell('chmod 777 %s' % cmd_helper.SingleQuote(remote))
-
- def _PushObject(self, local, remote):
- """Copies an object from the host to the gce instance using scp.
-
- Args:
- local: Path on the host filesystem.
- remote: Path on the instance filesystem.
- """
- cmd = [
- 'scp',
- '-r',
- '-o', 'UserKnownHostsFile=/dev/null',
- '-o', 'StrictHostKeyChecking=no',
- local,
- 'root@%s:%s' % (self._instance_ip, remote)
- ]
- status, _ = cmd_helper.GetCmdStatusAndOutput(cmd)
- if status:
- raise device_errors.AdbCommandFailedError(
- cmd, 'File not reachable on host: %s' % local,
- device_serial=str(self))
-
- # override
- def Pull(self, remote, local, **kwargs):
- """Pulls a file from the gce instance to the host.
-
- Args:
- remote: Path on the instance filesystem.
- local: Path on the host filesystem.
- """
- cmd = [
- 'scp',
- '-p',
- '-r',
- '-o', 'UserKnownHostsFile=/dev/null',
- '-o', 'StrictHostKeyChecking=no',
- 'root@%s:%s' % (self._instance_ip, remote),
- local,
- ]
- status, _ = cmd_helper.GetCmdStatusAndOutput(cmd)
- if status:
- raise device_errors.AdbCommandFailedError(
- cmd, 'File not reachable on host: %s' % local,
- device_serial=str(self))
-
- try:
- adb_wrapper.VerifyLocalFileExists(local)
- except (subprocess.CalledProcessError, IOError):
- logger.exception('Error when pulling files from android instance.')
- raise device_errors.AdbCommandFailedError(
- cmd, 'File not reachable on host: %s' % local,
- device_serial=str(self))
-
- # override
- def Install(self, apk_path, forward_lock=False, reinstall=False,
- sd_card=False, **kwargs):
- """Installs an apk on the gce instance
-
- Args:
- apk_path: Host path to the APK file.
- forward_lock: (optional) If set forward-locks the app.
- reinstall: (optional) If set reinstalls the app, keeping its data.
- sd_card: (optional) If set installs on the SD card.
- """
- adb_wrapper.VerifyLocalFileExists(apk_path)
- cmd = ['install']
- if forward_lock:
- cmd.append('-l')
- if reinstall:
- cmd.append('-r')
- if sd_card:
- cmd.append('-s')
- self.Push(apk_path, '/data/local/tmp/tmp.apk')
- cmd = ['pm'] + cmd
- cmd.append('/data/local/tmp/tmp.apk')
- output = self.Shell(' '.join(cmd))
- self.Shell('rm /data/local/tmp/tmp.apk')
- if 'Success' not in output:
- raise device_errors.AdbCommandFailedError(
- cmd, output, device_serial=self._device_serial)
-
- # override
- @property
- def is_emulator(self):
- return True
diff --git a/third_party/catapult/devil/devil/android/sdk/intent.py b/third_party/catapult/devil/devil/android/sdk/intent.py
deleted file mode 100644
index cdefb4632f..0000000000
--- a/third_party/catapult/devil/devil/android/sdk/intent.py
+++ /dev/null
@@ -1,129 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Manages intents and associated information.
-
-This is generally intended to be used with functions that calls Android's
-Am command.
-"""
-
-# Some common flag constants that can be used to construct intents.
-# Full list: http://developer.android.com/reference/android/content/Intent.html
-FLAG_ACTIVITY_CLEAR_TASK = 0x00008000
-FLAG_ACTIVITY_CLEAR_TOP = 0x04000000
-FLAG_ACTIVITY_NEW_TASK = 0x10000000
-FLAG_ACTIVITY_REORDER_TO_FRONT = 0x00020000
-FLAG_ACTIVITY_RESET_TASK_IF_NEEDED = 0x00200000
-
-
-def _bitwise_or(flags):
- result = 0
- for flag in flags:
- result |= flag
- return result
-
-
-class Intent(object):
-
- def __init__(self, action='android.intent.action.VIEW', activity=None,
- category=None, component=None, data=None, extras=None,
- flags=None, package=None):
- """Creates an Intent.
-
- Args:
- action: A string containing the action.
- activity: A string that, with |package|, can be used to specify the
- component.
- category: A string or list containing any categories.
- component: A string that specifies the component to send the intent to.
- data: A string containing a data URI.
- extras: A dict containing extra parameters to be passed along with the
- intent.
- flags: A sequence of flag constants to be passed with the intent.
- package: A string that, with activity, can be used to specify the
- component.
- """
- self._action = action
- self._activity = activity
- if isinstance(category, list) or category is None:
- self._category = category
- else:
- self._category = [category]
- self._component = component
- self._data = data
- self._extras = extras
- self._flags = '0x%0.8x' % _bitwise_or(flags) if flags else None
- self._package = package
-
- if self._component and '/' in component:
- self._package, self._activity = component.split('/', 1)
- elif self._package and self._activity:
- self._component = '%s/%s' % (package, activity)
-
- @property
- def action(self):
- return self._action
-
- @property
- def activity(self):
- return self._activity
-
- @property
- def category(self):
- return self._category
-
- @property
- def component(self):
- return self._component
-
- @property
- def data(self):
- return self._data
-
- @property
- def extras(self):
- return self._extras
-
- @property
- def flags(self):
- return self._flags
-
- @property
- def package(self):
- return self._package
-
- @property
- def am_args(self):
- """Returns the intent as a list of arguments for the activity manager.
-
- For details refer to the specification at:
- - http://developer.android.com/tools/help/adb.html#IntentSpec
- """
- args = []
- if self.action:
- args.extend(['-a', self.action])
- if self.data:
- args.extend(['-d', self.data])
- if self.category:
- args.extend(arg for cat in self.category for arg in ('-c', cat))
- if self.component:
- args.extend(['-n', self.component])
- if self.flags:
- args.extend(['-f', self.flags])
- if self.extras:
- for key, value in self.extras.iteritems():
- if value is None:
- args.extend(['--esn', key])
- elif isinstance(value, str):
- args.extend(['--es', key, value])
- elif isinstance(value, bool):
- args.extend(['--ez', key, str(value)])
- elif isinstance(value, int):
- args.extend(['--ei', key, str(value)])
- elif isinstance(value, float):
- args.extend(['--ef', key, str(value)])
- else:
- raise NotImplementedError(
- 'Intent does not know how to pass %s extras' % type(value))
- return args
diff --git a/third_party/catapult/devil/devil/android/sdk/keyevent.py b/third_party/catapult/devil/devil/android/sdk/keyevent.py
deleted file mode 100644
index 657dc963b9..0000000000
--- a/third_party/catapult/devil/devil/android/sdk/keyevent.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Android KeyEvent constants.
-
-http://developer.android.com/reference/android/view/KeyEvent.html
-"""
-
-KEYCODE_BACK = 4
-
-KEYCODE_0 = 7
-KEYCODE_1 = 8
-KEYCODE_2 = 9
-KEYCODE_3 = 10
-KEYCODE_4 = 11
-KEYCODE_5 = 12
-KEYCODE_6 = 13
-KEYCODE_7 = 14
-KEYCODE_8 = 15
-KEYCODE_9 = 16
-
-KEYCODE_DPAD_RIGHT = 22
-
-KEYCODE_POWER = 26
-
-KEYCODE_A = 29
-KEYCODE_B = 30
-KEYCODE_C = 31
-KEYCODE_D = 32
-KEYCODE_E = 33
-KEYCODE_F = 34
-KEYCODE_G = 35
-KEYCODE_H = 36
-KEYCODE_I = 37
-KEYCODE_J = 38
-KEYCODE_K = 39
-KEYCODE_L = 40
-KEYCODE_M = 41
-KEYCODE_N = 42
-KEYCODE_O = 43
-KEYCODE_P = 44
-KEYCODE_Q = 45
-KEYCODE_R = 46
-KEYCODE_S = 47
-KEYCODE_T = 48
-KEYCODE_U = 49
-KEYCODE_V = 50
-KEYCODE_W = 51
-KEYCODE_X = 52
-KEYCODE_Y = 53
-KEYCODE_Z = 54
-
-KEYCODE_PERIOD = 56
-
-KEYCODE_SPACE = 62
-
-KEYCODE_ENTER = 66
-KEYCODE_DEL = 67
-
-KEYCODE_MENU = 82
-
-KEYCODE_APP_SWITCH = 187
diff --git a/third_party/catapult/devil/devil/android/sdk/shared_prefs.py b/third_party/catapult/devil/devil/android/sdk/shared_prefs.py
deleted file mode 100644
index 2fa2e6a186..0000000000
--- a/third_party/catapult/devil/devil/android/sdk/shared_prefs.py
+++ /dev/null
@@ -1,420 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Helper object to read and modify Shared Preferences from Android apps.
-
-See e.g.:
- http://developer.android.com/reference/android/content/SharedPreferences.html
-"""
-
-import logging
-import posixpath
-
-from devil.android import device_errors
-from devil.android.sdk import version_codes
-from xml.etree import ElementTree
-
-logger = logging.getLogger(__name__)
-
-
-_XML_DECLARATION = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
-
-
-class BasePref(object):
- """Base class for getting/setting the value of a specific preference type.
-
- Should not be instantiated directly. The SharedPrefs collection will
- instantiate the appropriate subclasses, which directly manipulate the
- underlying xml document, to parse and serialize values according to their
- type.
-
- Args:
- elem: An xml ElementTree object holding the preference data.
-
- Properties:
- tag_name: A string with the tag that must be used for this preference type.
- """
- tag_name = None
-
- def __init__(self, elem):
- if elem.tag != type(self).tag_name:
- raise TypeError('Property %r has type %r, but trying to access as %r' %
- (elem.get('name'), elem.tag, type(self).tag_name))
- self._elem = elem
-
- def __str__(self):
- """Get the underlying xml element as a string."""
- return ElementTree.tostring(self._elem)
-
- def get(self):
- """Get the value of this preference."""
- return self._elem.get('value')
-
- def set(self, value):
- """Set from a value casted as a string."""
- self._elem.set('value', str(value))
-
- @property
- def has_value(self):
- """Check whether the element has a value."""
- return self._elem.get('value') is not None
-
-
-class BooleanPref(BasePref):
- """Class for getting/setting a preference with a boolean value.
-
- The underlying xml element has the form, e.g.:
- <boolean name="featureEnabled" value="false" />
- """
- tag_name = 'boolean'
- VALUES = {'true': True, 'false': False}
-
- def get(self):
- """Get the value as a Python bool."""
- return type(self).VALUES[super(BooleanPref, self).get()]
-
- def set(self, value):
- """Set from a value casted as a bool."""
- super(BooleanPref, self).set('true' if value else 'false')
-
-
-class FloatPref(BasePref):
- """Class for getting/setting a preference with a float value.
-
- The underlying xml element has the form, e.g.:
- <float name="someMetric" value="4.7" />
- """
- tag_name = 'float'
-
- def get(self):
- """Get the value as a Python float."""
- return float(super(FloatPref, self).get())
-
-
-class IntPref(BasePref):
- """Class for getting/setting a preference with an int value.
-
- The underlying xml element has the form, e.g.:
- <int name="aCounter" value="1234" />
- """
- tag_name = 'int'
-
- def get(self):
- """Get the value as a Python int."""
- return int(super(IntPref, self).get())
-
-
-class LongPref(IntPref):
- """Class for getting/setting a preference with a long value.
-
- The underlying xml element has the form, e.g.:
- <long name="aLongCounter" value="1234" />
-
- We use the same implementation from IntPref.
- """
- tag_name = 'long'
-
-
-class StringPref(BasePref):
- """Class for getting/setting a preference with a string value.
-
- The underlying xml element has the form, e.g.:
- <string name="someHashValue">249b3e5af13d4db2</string>
- """
- tag_name = 'string'
-
- def get(self):
- """Get the value as a Python string."""
- return self._elem.text
-
- def set(self, value):
- """Set from a value casted as a string."""
- self._elem.text = str(value)
-
-
-class StringSetPref(StringPref):
- """Class for getting/setting a preference with a set of string values.
-
- The underlying xml element has the form, e.g.:
- <set name="managed_apps">
- <string>com.mine.app1</string>
- <string>com.mine.app2</string>
- <string>com.mine.app3</string>
- </set>
- """
- tag_name = 'set'
-
- def get(self):
- """Get a list with the string values contained."""
- value = []
- for child in self._elem:
- assert child.tag == 'string'
- value.append(child.text)
- return value
-
- def set(self, value):
- """Set from a sequence of values, each casted as a string."""
- for child in list(self._elem):
- self._elem.remove(child)
- for item in value:
- ElementTree.SubElement(self._elem, 'string').text = str(item)
-
-
-_PREF_TYPES = {c.tag_name: c for c in [BooleanPref, FloatPref, IntPref,
- LongPref, StringPref, StringSetPref]}
-
-
-class SharedPrefs(object):
-
- def __init__(self, device, package, filename):
- """Helper object to read and update "Shared Prefs" of Android apps.
-
- Such files typically look like, e.g.:
-
- <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
- <map>
- <int name="databaseVersion" value="107" />
- <boolean name="featureEnabled" value="false" />
- <string name="someHashValue">249b3e5af13d4db2</string>
- </map>
-
- Example usage:
-
- prefs = shared_prefs.SharedPrefs(device, 'com.my.app', 'my_prefs.xml')
- prefs.Load()
- prefs.GetString('someHashValue') # => '249b3e5af13d4db2'
- prefs.SetInt('databaseVersion', 42)
- prefs.Remove('featureEnabled')
- prefs.Commit()
-
- The object may also be used as a context manager to automatically load and
- commit, respectively, upon entering and leaving the context.
-
- Args:
- device: A DeviceUtils object.
- package: A string with the package name of the app that owns the shared
- preferences file.
- filename: A string with the name of the preferences file to read/write.
- """
- self._device = device
- self._xml = None
- self._package = package
- self._filename = filename
- self._path = '/data/data/%s/shared_prefs/%s' % (package, filename)
- self._changed = False
-
- def __repr__(self):
- """Get a useful printable representation of the object."""
- return '<{cls} file {filename} for {package} on {device}>'.format(
- cls=type(self).__name__, filename=self.filename, package=self.package,
- device=str(self._device))
-
- def __str__(self):
- """Get the underlying xml document as a string."""
- return _XML_DECLARATION + ElementTree.tostring(self.xml)
-
- @property
- def package(self):
- """Get the package name of the app that owns the shared preferences."""
- return self._package
-
- @property
- def filename(self):
- """Get the filename of the shared preferences file."""
- return self._filename
-
- @property
- def path(self):
- """Get the full path to the shared preferences file on the device."""
- return self._path
-
- @property
- def changed(self):
- """True if properties have changed and a commit would be needed."""
- return self._changed
-
- @property
- def xml(self):
- """Get the underlying xml document as an ElementTree object."""
- if self._xml is None:
- self._xml = ElementTree.Element('map')
- return self._xml
-
- def Load(self):
- """Load the shared preferences file from the device.
-
- A empty xml document, which may be modified and saved on |commit|, is
- created if the file does not already exist.
- """
- if self._device.FileExists(self.path):
- self._xml = ElementTree.fromstring(
- self._device.ReadFile(self.path, as_root=True))
- assert self._xml.tag == 'map'
- else:
- self._xml = None
- self._changed = False
-
- def Clear(self):
- """Clear all of the preferences contained in this object."""
- if self._xml is not None and len(self): # only clear if not already empty
- self._xml = None
- self._changed = True
-
- def Commit(self):
- """Save the current set of preferences to the device.
-
- Only actually saves if some preferences have been modified.
- """
- if not self.changed:
- return
- self._device.RunShellCommand(
- ['mkdir', '-p', posixpath.dirname(self.path)],
- as_root=True, check_return=True)
- self._device.WriteFile(self.path, str(self), as_root=True)
- # Creating the directory/file can cause issues with SELinux if they did
- # not already exist. As a workaround, apply the package's security context
- # to the shared_prefs directory, which mimics the behavior of a file
- # created by the app itself
- if self._device.build_version_sdk >= version_codes.MARSHMALLOW:
- security_context = self._GetSecurityContext(self.package)
- if security_context == None:
- raise device_errors.CommandFailedError(
- 'Failed to get security context for %s' % self.package)
- self._device.RunShellCommand(
- ['chcon', '-R', security_context,
- '/data/data/%s/shared_prefs' % self.package],
- as_root=True, check_return=True)
- self._device.KillAll(self.package, exact=True, as_root=True, quiet=True)
- self._changed = False
-
- def __len__(self):
- """Get the number of preferences in this collection."""
- return len(self.xml)
-
- def PropertyType(self, key):
- """Get the type (i.e. tag name) of a property in the collection."""
- return self._GetChild(key).tag
-
- def HasProperty(self, key):
- try:
- self._GetChild(key)
- return True
- except KeyError:
- return False
-
- def GetBoolean(self, key):
- """Get a boolean property."""
- return BooleanPref(self._GetChild(key)).get()
-
- def SetBoolean(self, key, value):
- """Set a boolean property."""
- self._SetPrefValue(key, value, BooleanPref)
-
- def GetFloat(self, key):
- """Get a float property."""
- return FloatPref(self._GetChild(key)).get()
-
- def SetFloat(self, key, value):
- """Set a float property."""
- self._SetPrefValue(key, value, FloatPref)
-
- def GetInt(self, key):
- """Get an int property."""
- return IntPref(self._GetChild(key)).get()
-
- def SetInt(self, key, value):
- """Set an int property."""
- self._SetPrefValue(key, value, IntPref)
-
- def GetLong(self, key):
- """Get a long property."""
- return LongPref(self._GetChild(key)).get()
-
- def SetLong(self, key, value):
- """Set a long property."""
- self._SetPrefValue(key, value, LongPref)
-
- def GetString(self, key):
- """Get a string property."""
- return StringPref(self._GetChild(key)).get()
-
- def SetString(self, key, value):
- """Set a string property."""
- self._SetPrefValue(key, value, StringPref)
-
- def GetStringSet(self, key):
- """Get a string set property."""
- return StringSetPref(self._GetChild(key)).get()
-
- def SetStringSet(self, key, value):
- """Set a string set property."""
- self._SetPrefValue(key, value, StringSetPref)
-
- def Remove(self, key):
- """Remove a preference from the collection."""
- self.xml.remove(self._GetChild(key))
-
- def AsDict(self):
- """Return the properties and their values as a dictionary."""
- d = {}
- for child in self.xml:
- pref = _PREF_TYPES[child.tag](child)
- d[child.get('name')] = pref.get()
- return d
-
- def __enter__(self):
- """Load preferences file from the device when entering a context."""
- self.Load()
- return self
-
- def __exit__(self, exc_type, _exc_value, _traceback):
- """Save preferences file to the device when leaving a context."""
- if not exc_type:
- self.Commit()
-
- def _GetChild(self, key):
- """Get the underlying xml node that holds the property of a given key.
-
- Raises:
- KeyError when the key is not found in the collection.
- """
- for child in self.xml:
- if child.get('name') == key:
- return child
- raise KeyError(key)
-
- def _SetPrefValue(self, key, value, pref_cls):
- """Set the value of a property.
-
- Args:
- key: The key of the property to set.
- value: The new value of the property.
- pref_cls: A subclass of BasePref used to access the property.
-
- Raises:
- TypeError when the key already exists but with a different type.
- """
- try:
- pref = pref_cls(self._GetChild(key))
- old_value = pref.get()
- except KeyError:
- pref = pref_cls(ElementTree.SubElement(
- self.xml, pref_cls.tag_name, {'name': key}))
- old_value = None
- if old_value != value:
- pref.set(value)
- self._changed = True
- logger.info('Setting property: %s', pref)
-
- def _GetSecurityContext(self, package):
- for line in self._device.RunShellCommand(['ls', '-Z', '/data/data/'],
- as_root=True, check_return=True):
- split_line = line.split()
- # ls -Z output differs between Android versions, but the package is
- # always last and the context always starts with "u:object"
- if split_line[-1] == package:
- for column in split_line:
- if column.startswith('u:object'):
- return column
- return None
diff --git a/third_party/catapult/devil/devil/android/sdk/shared_prefs_test.py b/third_party/catapult/devil/devil/android/sdk/shared_prefs_test.py
deleted file mode 100755
index 4c31c569fd..0000000000
--- a/third_party/catapult/devil/devil/android/sdk/shared_prefs_test.py
+++ /dev/null
@@ -1,171 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""
-Unit tests for the contents of shared_prefs.py (mostly SharedPrefs).
-"""
-
-import logging
-import unittest
-
-from devil import devil_env
-from devil.android import device_utils
-from devil.android.sdk import shared_prefs
-from devil.android.sdk import version_codes
-
-with devil_env.SysPath(devil_env.PYMOCK_PATH):
- import mock # pylint: disable=import-error
-
-
-def MockDeviceWithFiles(files=None):
- if files is None:
- files = {}
-
- def file_exists(path):
- return path in files
-
- def write_file(path, contents, **_kwargs):
- files[path] = contents
-
- def read_file(path, **_kwargs):
- return files[path]
-
- device = mock.MagicMock(spec=device_utils.DeviceUtils)
- device.FileExists = mock.Mock(side_effect=file_exists)
- device.WriteFile = mock.Mock(side_effect=write_file)
- device.ReadFile = mock.Mock(side_effect=read_file)
- return device
-
-
-class SharedPrefsTest(unittest.TestCase):
-
- def setUp(self):
- self.device = MockDeviceWithFiles({
- '/data/data/com.some.package/shared_prefs/prefs.xml':
- "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
- '<map>\n'
- ' <int name="databaseVersion" value="107" />\n'
- ' <boolean name="featureEnabled" value="false" />\n'
- ' <string name="someHashValue">249b3e5af13d4db2</string>\n'
- '</map>'})
- self.expected_data = {'databaseVersion': 107,
- 'featureEnabled': False,
- 'someHashValue': '249b3e5af13d4db2'}
-
- def testPropertyLifetime(self):
- prefs = shared_prefs.SharedPrefs(
- self.device, 'com.some.package', 'prefs.xml')
- self.assertEquals(len(prefs), 0) # collection is empty before loading
- prefs.SetInt('myValue', 444)
- self.assertEquals(len(prefs), 1)
- self.assertEquals(prefs.GetInt('myValue'), 444)
- self.assertTrue(prefs.HasProperty('myValue'))
- prefs.Remove('myValue')
- self.assertEquals(len(prefs), 0)
- self.assertFalse(prefs.HasProperty('myValue'))
- with self.assertRaises(KeyError):
- prefs.GetInt('myValue')
-
- def testPropertyType(self):
- prefs = shared_prefs.SharedPrefs(
- self.device, 'com.some.package', 'prefs.xml')
- prefs.SetInt('myValue', 444)
- self.assertEquals(prefs.PropertyType('myValue'), 'int')
- with self.assertRaises(TypeError):
- prefs.GetString('myValue')
- with self.assertRaises(TypeError):
- prefs.SetString('myValue', 'hello')
-
- def testLoad(self):
- prefs = shared_prefs.SharedPrefs(
- self.device, 'com.some.package', 'prefs.xml')
- self.assertEquals(len(prefs), 0) # collection is empty before loading
- prefs.Load()
- self.assertEquals(len(prefs), len(self.expected_data))
- self.assertEquals(prefs.AsDict(), self.expected_data)
- self.assertFalse(prefs.changed)
-
- def testClear(self):
- prefs = shared_prefs.SharedPrefs(
- self.device, 'com.some.package', 'prefs.xml')
- prefs.Load()
- self.assertEquals(prefs.AsDict(), self.expected_data)
- self.assertFalse(prefs.changed)
- prefs.Clear()
- self.assertEquals(len(prefs), 0) # collection is empty now
- self.assertTrue(prefs.changed)
-
- def testCommit(self):
- type(self.device).build_version_sdk = mock.PropertyMock(
- return_value=version_codes.LOLLIPOP_MR1)
- prefs = shared_prefs.SharedPrefs(
- self.device, 'com.some.package', 'other_prefs.xml')
- self.assertFalse(self.device.FileExists(prefs.path)) # file does not exist
- prefs.Load()
- self.assertEquals(len(prefs), 0) # file did not exist, collection is empty
- prefs.SetInt('magicNumber', 42)
- prefs.SetFloat('myMetric', 3.14)
- prefs.SetLong('bigNumner', 6000000000)
- prefs.SetStringSet('apps', ['gmail', 'chrome', 'music'])
- self.assertFalse(self.device.FileExists(prefs.path)) # still does not exist
- self.assertTrue(prefs.changed)
- prefs.Commit()
- self.assertTrue(self.device.FileExists(prefs.path)) # should exist now
- self.device.KillAll.assert_called_once_with(prefs.package, exact=True,
- as_root=True, quiet=True)
- self.assertFalse(prefs.changed)
-
- prefs = shared_prefs.SharedPrefs(
- self.device, 'com.some.package', 'other_prefs.xml')
- self.assertEquals(len(prefs), 0) # collection is empty before loading
- prefs.Load()
- self.assertEquals(prefs.AsDict(), {
- 'magicNumber': 42,
- 'myMetric': 3.14,
- 'bigNumner': 6000000000,
- 'apps': ['gmail', 'chrome', 'music']}) # data survived roundtrip
-
- def testAsContextManager_onlyReads(self):
- with shared_prefs.SharedPrefs(
- self.device, 'com.some.package', 'prefs.xml') as prefs:
- self.assertEquals(prefs.AsDict(), self.expected_data) # loaded and ready
- self.assertEquals(self.device.WriteFile.call_args_list, []) # did not write
-
- def testAsContextManager_readAndWrite(self):
- type(self.device).build_version_sdk = mock.PropertyMock(
- return_value=version_codes.LOLLIPOP_MR1)
- with shared_prefs.SharedPrefs(
- self.device, 'com.some.package', 'prefs.xml') as prefs:
- prefs.SetBoolean('featureEnabled', True)
- prefs.Remove('someHashValue')
- prefs.SetString('newString', 'hello')
-
- self.assertTrue(self.device.WriteFile.called) # did write
- with shared_prefs.SharedPrefs(
- self.device, 'com.some.package', 'prefs.xml') as prefs:
- # changes persisted
- self.assertTrue(prefs.GetBoolean('featureEnabled'))
- self.assertFalse(prefs.HasProperty('someHashValue'))
- self.assertEquals(prefs.GetString('newString'), 'hello')
- self.assertTrue(prefs.HasProperty('databaseVersion')) # still there
-
- def testAsContextManager_commitAborted(self):
- with self.assertRaises(TypeError):
- with shared_prefs.SharedPrefs(
- self.device, 'com.some.package', 'prefs.xml') as prefs:
- prefs.SetBoolean('featureEnabled', True)
- prefs.Remove('someHashValue')
- prefs.SetString('newString', 'hello')
- prefs.SetInt('newString', 123) # oops!
-
- self.assertEquals(self.device.WriteFile.call_args_list, []) # did not write
- with shared_prefs.SharedPrefs(
- self.device, 'com.some.package', 'prefs.xml') as prefs:
- # contents were not modified
- self.assertEquals(prefs.AsDict(), self.expected_data)
-
-if __name__ == '__main__':
- logging.getLogger().setLevel(logging.DEBUG)
- unittest.main(verbosity=2)
diff --git a/third_party/catapult/devil/devil/android/sdk/split_select.py b/third_party/catapult/devil/devil/android/sdk/split_select.py
deleted file mode 100644
index 6c3d231a77..0000000000
--- a/third_party/catapult/devil/devil/android/sdk/split_select.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""This module wraps Android's split-select tool."""
-
-from devil.android.sdk import build_tools
-from devil.utils import cmd_helper
-from devil.utils import lazy
-
-
-_split_select_path = lazy.WeakConstant(
- lambda: build_tools.GetPath('split-select'))
-
-
-def _RunSplitSelectCmd(args):
- """Runs a split-select command.
-
- Args:
- args: A list of arguments for split-select.
-
- Returns:
- The output of the command.
- """
- cmd = [_split_select_path.read()] + args
- status, output = cmd_helper.GetCmdStatusAndOutput(cmd)
- if status != 0:
- raise Exception('Failed running command "%s" with output "%s".' %
- (' '.join(cmd), output))
- return output
-
-
-def _SplitConfig(device, allow_cached_props=False):
- """Returns a config specifying which APK splits are required by the device.
-
- Args:
- device: A DeviceUtils object.
- allow_cached_props: Whether to use cached values for device properties.
- """
- return ('%s-r%s-%s:%s' %
- (device.GetLanguage(cache=allow_cached_props),
- device.GetCountry(cache=allow_cached_props),
- device.screen_density,
- device.product_cpu_abi))
-
-
-def SelectSplits(device, base_apk, split_apks, allow_cached_props=False):
- """Determines which APK splits the device requires.
-
- Args:
- device: A DeviceUtils object.
- base_apk: The path of the base APK.
- split_apks: A list of paths of APK splits.
- allow_cached_props: Whether to use cached values for device properties.
-
- Returns:
- The list of APK splits that the device requires.
- """
- config = _SplitConfig(device, allow_cached_props=allow_cached_props)
- args = ['--target', config, '--base', base_apk]
- for split in split_apks:
- args.extend(['--split', split])
- return _RunSplitSelectCmd(args).splitlines()
diff --git a/third_party/catapult/devil/devil/android/sdk/test/data/push_directory/push_directory_contents.txt b/third_party/catapult/devil/devil/android/sdk/test/data/push_directory/push_directory_contents.txt
deleted file mode 100644
index 573df2e9b2..0000000000
--- a/third_party/catapult/devil/devil/android/sdk/test/data/push_directory/push_directory_contents.txt
+++ /dev/null
@@ -1 +0,0 @@
-Goodnight, moon.
diff --git a/third_party/catapult/devil/devil/android/sdk/test/data/push_file.txt b/third_party/catapult/devil/devil/android/sdk/test/data/push_file.txt
deleted file mode 100644
index af5626b4a1..0000000000
--- a/third_party/catapult/devil/devil/android/sdk/test/data/push_file.txt
+++ /dev/null
@@ -1 +0,0 @@
-Hello, world!
diff --git a/third_party/catapult/devil/devil/android/sdk/version_codes.py b/third_party/catapult/devil/devil/android/sdk/version_codes.py
deleted file mode 100644
index 3f03cbac6c..0000000000
--- a/third_party/catapult/devil/devil/android/sdk/version_codes.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Android SDK version codes.
-
-http://developer.android.com/reference/android/os/Build.VERSION_CODES.html
-"""
-
-JELLY_BEAN = 16
-JELLY_BEAN_MR1 = 17
-JELLY_BEAN_MR2 = 18
-KITKAT = 19
-KITKAT_WATCH = 20
-LOLLIPOP = 21
-LOLLIPOP_MR1 = 22
-MARSHMALLOW = 23
-NOUGAT = 24
-NOUGAT_MR1 = 25
-
diff --git a/third_party/catapult/devil/devil/android/settings.py b/third_party/catapult/devil/devil/android/settings.py
deleted file mode 100644
index 886b2661d3..0000000000
--- a/third_party/catapult/devil/devil/android/settings.py
+++ /dev/null
@@ -1,273 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import logging
-
-logger = logging.getLogger(__name__)
-
-_LOCK_SCREEN_SETTINGS_PATH = '/data/system/locksettings.db'
-_ALTERNATE_LOCK_SCREEN_SETTINGS_PATH = (
- '/data/data/com.android.providers.settings/databases/settings.db')
-PASSWORD_QUALITY_UNSPECIFIED = '0'
-_COMPATIBLE_BUILD_TYPES = ['userdebug', 'eng']
-
-
-ENABLE_LOCATION_SETTINGS = [
- # Note that setting these in this order is required in order for all of
- # them to take and stick through a reboot.
- ('com.google.settings/partner', [
- ('use_location_for_services', 1),
- ]),
- ('settings/secure', [
- # Ensure Geolocation is enabled and allowed for tests.
- ('location_providers_allowed', 'gps,network'),
- ]),
- ('com.google.settings/partner', [
- ('network_location_opt_in', 1),
- ])
-]
-
-DISABLE_LOCATION_SETTINGS = [
- ('com.google.settings/partner', [
- ('use_location_for_services', 0),
- ]),
- ('settings/secure', [
- # Ensure Geolocation is disabled.
- ('location_providers_allowed', ''),
- ]),
-]
-
-ENABLE_MOCK_LOCATION_SETTINGS = [
- ('settings/secure', [
- ('mock_location', 1),
- ]),
-]
-
-DISABLE_MOCK_LOCATION_SETTINGS = [
- ('settings/secure', [
- ('mock_location', 0),
- ]),
-]
-
-DETERMINISTIC_DEVICE_SETTINGS = [
- ('settings/global', [
- ('assisted_gps_enabled', 0),
-
- # Disable "auto time" and "auto time zone" to avoid network-provided time
- # to overwrite the device's datetime and timezone synchronized from host
- # when running tests later. See b/6569849.
- ('auto_time', 0),
- ('auto_time_zone', 0),
-
- ('development_settings_enabled', 1),
-
- # Flag for allowing ActivityManagerService to send ACTION_APP_ERROR intents
- # on application crashes and ANRs. If this is disabled, the crash/ANR dialog
- # will never display the "Report" button.
- # Type: int ( 0 = disallow, 1 = allow )
- ('send_action_app_error', 0),
-
- ('stay_on_while_plugged_in', 3),
-
- ('verifier_verify_adb_installs', 0),
- ]),
- ('settings/secure', [
- ('allowed_geolocation_origins',
- 'http://www.google.co.uk http://www.google.com'),
-
- # Ensure that we never get random dialogs like "Unfortunately the process
- # android.process.acore has stopped", which steal the focus, and make our
- # automation fail (because the dialog steals the focus then mistakenly
- # receives the injected user input events).
- ('anr_show_background', 0),
-
- ('lockscreen.disabled', 1),
-
- ('screensaver_enabled', 0),
-
- ('skip_first_use_hints', 1),
- ]),
- ('settings/system', [
- # Don't want devices to accidentally rotate the screen as that could
- # affect performance measurements.
- ('accelerometer_rotation', 0),
-
- ('lockscreen.disabled', 1),
-
- # Turn down brightness and disable auto-adjust so that devices run cooler.
- ('screen_brightness', 5),
- ('screen_brightness_mode', 0),
-
- ('user_rotation', 0),
- ]),
-]
-
-NETWORK_DISABLED_SETTINGS = [
- ('settings/global', [
- ('airplane_mode_on', 1),
- ('wifi_on', 0),
- ]),
-]
-
-
-class ContentSettings(dict):
-
- """A dict interface to interact with device content settings.
-
- System properties are key/value pairs as exposed by adb shell content.
- """
-
- def __init__(self, table, device):
- super(ContentSettings, self).__init__()
- self._table = table
- self._device = device
-
- @staticmethod
- def _GetTypeBinding(value):
- if isinstance(value, bool):
- return 'b'
- if isinstance(value, float):
- return 'f'
- if isinstance(value, int):
- return 'i'
- if isinstance(value, long):
- return 'l'
- if isinstance(value, str):
- return 's'
- raise ValueError('Unsupported type %s' % type(value))
-
- def iteritems(self):
- # Example row:
- # 'Row: 0 _id=13, name=logging_id2, value=-1fccbaa546705b05'
- for row in self._device.RunShellCommand(
- ['content', 'query', '--uri', 'content://%s' % self._table],
- check_return=True, as_root=True):
- fields = row.split(', ')
- key = None
- value = None
- for field in fields:
- k, _, v = field.partition('=')
- if k == 'name':
- key = v
- elif k == 'value':
- value = v
- if not key:
- continue
- if not value:
- value = ''
- yield key, value
-
- def __getitem__(self, key):
- return self._device.RunShellCommand(
- ['content', 'query', '--uri', 'content://%s' % self._table,
- '--where', "name='%s'" % key],
- check_return=True, as_root=True).strip()
-
- def __setitem__(self, key, value):
- if key in self:
- self._device.RunShellCommand(
- ['content', 'update', '--uri', 'content://%s' % self._table,
- '--bind', 'value:%s:%s' % (self._GetTypeBinding(value), value),
- '--where', "name='%s'" % key],
- check_return=True, as_root=True)
- else:
- self._device.RunShellCommand(
- ['content', 'insert', '--uri', 'content://%s' % self._table,
- '--bind', 'name:%s:%s' % (self._GetTypeBinding(key), key),
- '--bind', 'value:%s:%s' % (self._GetTypeBinding(value), value)],
- check_return=True, as_root=True)
-
- def __delitem__(self, key):
- self._device.RunShellCommand(
- ['content', 'delete', '--uri', 'content://%s' % self._table,
- '--bind', 'name:%s:%s' % (self._GetTypeBinding(key), key)],
- check_return=True, as_root=True)
-
-
-def ConfigureContentSettings(device, desired_settings):
- """Configures device content setings from a list.
-
- Many settings are documented at:
- http://developer.android.com/reference/android/provider/Settings.Global.html
- http://developer.android.com/reference/android/provider/Settings.Secure.html
- http://developer.android.com/reference/android/provider/Settings.System.html
-
- Many others are undocumented.
-
- Args:
- device: A DeviceUtils instance for the device to configure.
- desired_settings: A list of (table, [(key: value), ...]) for all
- settings to configure.
- """
- for table, key_value in desired_settings:
- settings = ContentSettings(table, device)
- for key, value in key_value:
- settings[key] = value
- logger.info('\n%s %s', table, (80 - len(table)) * '-')
- for key, value in sorted(settings.iteritems()):
- logger.info('\t%s: %s', key, value)
-
-
-def SetLockScreenSettings(device):
- """Sets lock screen settings on the device.
-
- On certain device/Android configurations we need to disable the lock screen in
- a different database. Additionally, the password type must be set to
- DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED.
- Lock screen settings are stored in sqlite on the device in:
- /data/system/locksettings.db
-
- IMPORTANT: The first column is used as a primary key so that all rows with the
- same value for that column are removed from the table prior to inserting the
- new values.
-
- Args:
- device: A DeviceUtils instance for the device to configure.
-
- Raises:
- Exception if the setting was not properly set.
- """
- if device.build_type not in _COMPATIBLE_BUILD_TYPES:
- logger.warning('Unable to disable lockscreen on %s builds.',
- device.build_type)
- return
-
- def get_lock_settings(table):
- return [(table, 'lockscreen.disabled', '1'),
- (table, 'lockscreen.password_type', PASSWORD_QUALITY_UNSPECIFIED),
- (table, 'lockscreen.password_type_alternate',
- PASSWORD_QUALITY_UNSPECIFIED)]
-
- if device.FileExists(_LOCK_SCREEN_SETTINGS_PATH):
- db = _LOCK_SCREEN_SETTINGS_PATH
- locksettings = get_lock_settings('locksettings')
- columns = ['name', 'user', 'value']
- generate_values = lambda k, v: [k, '0', v]
- elif device.FileExists(_ALTERNATE_LOCK_SCREEN_SETTINGS_PATH):
- db = _ALTERNATE_LOCK_SCREEN_SETTINGS_PATH
- locksettings = get_lock_settings('secure') + get_lock_settings('system')
- columns = ['name', 'value']
- generate_values = lambda k, v: [k, v]
- else:
- logger.warning('Unable to find database file to set lock screen settings.')
- return
-
- for table, key, value in locksettings:
- # Set the lockscreen setting for default user '0'
- values = generate_values(key, value)
-
- cmd = """begin transaction;
-delete from '%(table)s' where %(primary_key)s='%(primary_value)s';
-insert into '%(table)s' (%(columns)s) values (%(values)s);
-commit transaction;""" % {
- 'table': table,
- 'primary_key': columns[0],
- 'primary_value': values[0],
- 'columns': ', '.join(columns),
- 'values': ', '.join(["'%s'" % value for value in values])
- }
- output_msg = device.RunShellCommand(
- ['sqlite3', db, cmd], check_return=True, as_root=True)
- if output_msg:
- logger.info(' '.join(output_msg))
diff --git a/third_party/catapult/devil/devil/android/tools/__init__.py b/third_party/catapult/devil/devil/android/tools/__init__.py
deleted file mode 100644
index 50b23dff63..0000000000
--- a/third_party/catapult/devil/devil/android/tools/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
diff --git a/third_party/catapult/devil/devil/android/tools/adb_run_shell_cmd.py b/third_party/catapult/devil/devil/android/tools/adb_run_shell_cmd.py
deleted file mode 100755
index 77b67e8446..0000000000
--- a/third_party/catapult/devil/devil/android/tools/adb_run_shell_cmd.py
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import argparse
-import json
-import os
-import sys
-
-if __name__ == '__main__':
- sys.path.append(
- os.path.abspath(os.path.join(os.path.dirname(__file__),
- '..', '..', '..')))
-
-from devil.android import device_blacklist
-from devil.android import device_utils
-from devil.utils import run_tests_helper
-
-
-def main():
- parser = argparse.ArgumentParser(
- 'Run an adb shell command on selected devices')
- parser.add_argument('cmd', help='Adb shell command to run.', nargs="+")
- parser.add_argument('-d', '--device', action='append', dest='devices',
- default=[],
- help='Device to run cmd on. Runs on all devices if not '
- 'specified. Set multiple times for multiple devices')
- parser.add_argument('-v', '--verbose', default=0, action='count',
- help='Verbose level (multiple times for more)')
- parser.add_argument('--blacklist-file', help='Device blacklist file.')
- parser.add_argument('--as-root', action='store_true', help='Run as root.')
- parser.add_argument('--json-output',
- help='File to dump json output to.')
- args = parser.parse_args()
- run_tests_helper.SetLogLevel(args.verbose)
-
- args.blacklist_file = device_blacklist.Blacklist(
- args.blacklist_file) if args.blacklist_file else None
- devices = device_utils.DeviceUtils.HealthyDevices(
- blacklist=args.blacklist_file, device_arg=args.devices)
-
- p_out = (device_utils.DeviceUtils.parallel(devices).RunShellCommand(
- args.cmd, large_output=True, as_root=args.as_root, check_return=True)
- .pGet(None))
-
- data = {}
- for device, output in zip(devices, p_out):
- for line in output:
- print '%s: %s' % (device, line)
- data[str(device)] = output
-
- if args.json_output:
- with open(args.json_output, 'w') as f:
- json.dump(data, f)
-
- return 0
-
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/third_party/catapult/devil/devil/android/tools/cpufreq.py b/third_party/catapult/devil/devil/android/tools/cpufreq.py
deleted file mode 100755
index 97deaf042c..0000000000
--- a/third_party/catapult/devil/devil/android/tools/cpufreq.py
+++ /dev/null
@@ -1,87 +0,0 @@
-#! /usr/bin/env python
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""A script to manipulate device CPU frequency."""
-
-import argparse
-import os
-import pprint
-import sys
-
-if __name__ == '__main__':
- sys.path.append(
- os.path.abspath(os.path.join(os.path.dirname(__file__),
- '..', '..', '..')))
-
-from devil import devil_env
-from devil.android import device_utils
-from devil.android.perf import perf_control
-from devil.utils import run_tests_helper
-
-
-def SetScalingGovernor(device, args):
- p = perf_control.PerfControl(device)
- p.SetScalingGovernor(args.governor)
-
-
-def GetScalingGovernor(device, _args):
- p = perf_control.PerfControl(device)
- for cpu, governor in p.GetScalingGovernor():
- print '%s %s: %s' % (str(device), cpu, governor)
-
-
-def ListAvailableGovernors(device, _args):
- p = perf_control.PerfControl(device)
- for cpu, governors in p.ListAvailableGovernors():
- print '%s %s: %s' % (str(device), cpu, pprint.pformat(governors))
-
-
-def main(raw_args):
- parser = argparse.ArgumentParser()
- parser.add_argument(
- '--adb-path',
- help='ADB binary path.')
- parser.add_argument(
- '--device', dest='devices', action='append', default=[],
- help='Devices for which the governor should be set. Defaults to all.')
- parser.add_argument(
- '-v', '--verbose', action='count',
- help='Log more.')
-
- subparsers = parser.add_subparsers()
-
- set_governor = subparsers.add_parser('set-governor')
- set_governor.add_argument(
- 'governor',
- help='Desired CPU governor.')
- set_governor.set_defaults(func=SetScalingGovernor)
-
- get_governor = subparsers.add_parser('get-governor')
- get_governor.set_defaults(func=GetScalingGovernor)
-
- list_governors = subparsers.add_parser('list-governors')
- list_governors.set_defaults(func=ListAvailableGovernors)
-
- args = parser.parse_args(raw_args)
-
- run_tests_helper.SetLogLevel(args.verbose)
-
- devil_dynamic_config = devil_env.EmptyConfig()
- if args.adb_path:
- devil_dynamic_config['dependencies'].update(
- devil_env.LocalConfigItem(
- 'adb', devil_env.GetPlatform(), args.adb_path))
- devil_env.config.Initialize(configs=[devil_dynamic_config])
-
- devices = device_utils.DeviceUtils.HealthyDevices(device_arg=args.devices)
-
- parallel_devices = device_utils.DeviceUtils.parallel(devices)
- parallel_devices.pMap(args.func, args)
-
- return 0
-
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv[1:]))
diff --git a/third_party/catapult/devil/devil/android/tools/device_monitor.py b/third_party/catapult/devil/devil/android/tools/device_monitor.py
deleted file mode 100755
index 49214a9282..0000000000
--- a/third_party/catapult/devil/devil/android/tools/device_monitor.py
+++ /dev/null
@@ -1,231 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Launches a daemon to monitor android device temperatures & status.
-
-This script will repeatedly poll the given devices for their temperatures and
-status every 60 seconds and dump the stats to file on the host.
-"""
-
-import argparse
-import collections
-import json
-import logging
-import logging.handlers
-import os
-import re
-import socket
-import sys
-import time
-
-if __name__ == '__main__':
- sys.path.append(
- os.path.abspath(os.path.join(os.path.dirname(__file__),
- '..', '..', '..')))
-
-from devil import devil_env
-from devil.android import battery_utils
-from devil.android import device_blacklist
-from devil.android import device_errors
-from devil.android import device_utils
-
-
-# Various names of sensors used to measure cpu temp
-CPU_TEMP_SENSORS = [
- # most nexus devices
- 'tsens_tz_sensor0',
- # android one
- 'mtktscpu',
- # nexus 9
- 'CPU-therm',
-]
-
-DEVICE_FILE_VERSION = 1
-# TODO(bpastene): Remove the old file once sysmon has been updated to read the
-# new status file.
-DEVICE_FILES = [
- os.path.join(os.path.expanduser('~'), 'android_device_status.json'),
- os.path.join(
- os.path.expanduser('~'), '.android',
- '%s__android_device_status.json' % socket.gethostname().split('.')[0]
- ),
-]
-
-MEM_INFO_REGEX = re.compile(r'.*?\:\s*(\d+)\s*kB') # ex: 'MemTotal: 185735 kB'
-
-
-def get_device_status(device):
- """Polls the given device for various info.
-
- Returns: A dict of the following format:
- {
- 'battery': {
- 'level': 100,
- 'temperature': 123
- },
- 'build': {
- 'build.id': 'ABC12D',
- 'product.device': 'chickenofthesea'
- },
- 'mem': {
- 'avail': 1000000,
- 'total': 1234567,
- },
- 'processes': 123,
- 'state': 'good',
- 'temp': {
- 'some_sensor': 30
- },
- 'uptime': 1234.56,
- }
- """
- status = collections.defaultdict(dict)
-
- # Battery
- battery = battery_utils.BatteryUtils(device)
- battery_info = battery.GetBatteryInfo()
- try:
- level = int(battery_info.get('level'))
- except (KeyError, TypeError, ValueError):
- level = None
- if level and level >= 0 and level <= 100:
- status['battery']['level'] = level
- try:
- temperature = int(battery_info.get('temperature'))
- except (KeyError, TypeError, ValueError):
- temperature = None
- if temperature:
- status['battery']['temperature'] = temperature
-
- # Build
- status['build']['build.id'] = device.build_id
- status['build']['product.device'] = device.build_product
-
- # Memory
- mem_info = ''
- try:
- mem_info = device.ReadFile('/proc/meminfo')
- except device_errors.AdbShellCommandFailedError:
- logging.exception('Unable to read /proc/meminfo')
- for line in mem_info.splitlines():
- match = MEM_INFO_REGEX.match(line)
- if match:
- try:
- value = int(match.group(1))
- except ValueError:
- continue
- key = line.split(':')[0].strip()
- if 'MemTotal' == key:
- status['mem']['total'] = value
- elif 'MemFree' == key:
- status['mem']['free'] = value
-
- # Process
- try:
- # TODO(catapult:#3215): Migrate to device.GetPids()
- lines = device.RunShellCommand(['ps'], check_return=True)
- status['processes'] = len(lines) - 1 # Ignore the header row.
- except device_errors.AdbShellCommandFailedError:
- logging.exception('Unable to count process list.')
-
- # CPU Temps
- # Find a thermal sensor that matches one in CPU_TEMP_SENSORS and read its
- # temperature.
- files = []
- try:
- files = device.RunShellCommand(
- 'grep -lE "%s" /sys/class/thermal/thermal_zone*/type' % '|'.join(
- CPU_TEMP_SENSORS), shell=True, check_return=True)
- except device_errors.AdbShellCommandFailedError:
- logging.exception('Unable to list thermal sensors.')
- for f in files:
- try:
- sensor_name = device.ReadFile(f).strip()
- temp = float(device.ReadFile(f[:-4] + 'temp').strip()) # s/type^/temp
- status['temp'][sensor_name] = temp
- except (device_errors.AdbShellCommandFailedError, ValueError):
- logging.exception('Unable to read thermal sensor %s', f)
-
- # Uptime
- try:
- uptimes = device.ReadFile('/proc/uptime').split()
- status['uptime'] = float(uptimes[0]) # Take the first field (actual uptime)
- except (device_errors.AdbShellCommandFailedError, ValueError):
- logging.exception('Unable to read /proc/uptime')
-
- status['state'] = 'available'
- return status
-
-
-def get_all_status(blacklist):
- status_dict = {
- 'version': DEVICE_FILE_VERSION,
- 'devices': {},
- }
-
- healthy_devices = device_utils.DeviceUtils.HealthyDevices(blacklist)
- parallel_devices = device_utils.DeviceUtils.parallel(healthy_devices)
- results = parallel_devices.pMap(get_device_status).pGet(None)
-
- status_dict['devices'] = {
- device.serial: result for device, result in zip(healthy_devices, results)
- }
-
- if blacklist:
- for device, reason in blacklist.Read().iteritems():
- status_dict['devices'][device] = {
- 'state': reason.get('reason', 'blacklisted')}
-
- status_dict['timestamp'] = time.time()
- return status_dict
-
-
-def main(argv):
- """Launches the device monitor.
-
- Polls the devices for their battery and cpu temperatures and scans the
- blacklist file every 60 seconds and dumps the data to DEVICE_FILE.
- """
-
- parser = argparse.ArgumentParser(
- description='Launches the device monitor.')
- parser.add_argument('--adb-path', help='Path to adb binary.')
- parser.add_argument('--blacklist-file', help='Path to device blacklist file.')
- args = parser.parse_args(argv)
-
- logger = logging.getLogger()
- logger.setLevel(logging.DEBUG)
- handler = logging.handlers.RotatingFileHandler(
- '/tmp/device_monitor.log', maxBytes=10 * 1024 * 1024, backupCount=5)
- fmt = logging.Formatter('%(asctime)s %(levelname)s %(message)s',
- datefmt='%y%m%d %H:%M:%S')
- handler.setFormatter(fmt)
- logger.addHandler(handler)
-
- devil_dynamic_config = devil_env.EmptyConfig()
- if args.adb_path:
- devil_dynamic_config['dependencies'].update(
- devil_env.LocalConfigItem(
- 'adb', devil_env.GetPlatform(), args.adb_path))
-
- devil_env.config.Initialize(configs=[devil_dynamic_config])
-
- blacklist = (device_blacklist.Blacklist(args.blacklist_file)
- if args.blacklist_file else None)
-
- logging.info('Device monitor running with pid %d, adb: %s, blacklist: %s',
- os.getpid(), args.adb_path, args.blacklist_file)
- while True:
- start = time.time()
- status_dict = get_all_status(blacklist)
- for device_file in DEVICE_FILES:
- with open(device_file, 'wb') as f:
- json.dump(status_dict, f, indent=2, sort_keys=True)
- logging.info('Got status of all devices in %.2fs.', time.time() - start)
- time.sleep(60)
-
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv[1:]))
diff --git a/third_party/catapult/devil/devil/android/tools/device_monitor_test.py b/third_party/catapult/devil/devil/android/tools/device_monitor_test.py
deleted file mode 100755
index e39e324b36..0000000000
--- a/third_party/catapult/devil/devil/android/tools/device_monitor_test.py
+++ /dev/null
@@ -1,168 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import os
-import sys
-import unittest
-
-if __name__ == '__main__':
- sys.path.append(
- os.path.abspath(os.path.join(os.path.dirname(__file__),
- '..', '..', '..')))
-
-from devil import devil_env
-from devil.android import device_errors
-from devil.android import device_utils
-from devil.android.tools import device_monitor
-
-with devil_env.SysPath(devil_env.PYMOCK_PATH):
- import mock # pylint: disable=import-error
-
-
-class DeviceMonitorTest(unittest.TestCase):
-
- def setUp(self):
- self.device = mock.Mock(spec=device_utils.DeviceUtils,
- serial='device_cereal', build_id='abc123', build_product='clownfish')
- self.file_contents = {
- '/proc/meminfo': """
- MemTotal: 1234567 kB
- MemFree: 1000000 kB
- MemUsed: 234567 kB
- """,
- '/sys/class/thermal/thermal_zone0/type': 'CPU-therm',
- '/sys/class/thermal/thermal_zone0/temp': '30',
- '/proc/uptime': '12345 99999',
- }
- self.device.ReadFile = mock.MagicMock(
- side_effect=lambda file_name: self.file_contents[file_name])
-
- self.cmd_outputs = {
- 'ps': ['headers', 'p1', 'p2', 'p3', 'p4', 'p5'],
- 'grep': ['/sys/class/thermal/thermal_zone0/type'],
- }
-
- def mock_run_shell(cmd, **_kwargs):
- args = cmd.split() if isinstance(cmd, basestring) else cmd
- try:
- return self.cmd_outputs[args[0]]
- except KeyError:
- raise device_errors.AdbShellCommandFailedError(cmd, None, None)
-
- self.device.RunShellCommand = mock.MagicMock(side_effect=mock_run_shell)
-
- self.battery = mock.Mock()
- self.battery.GetBatteryInfo = mock.MagicMock(
- return_value={'level': '80', 'temperature': '123'})
-
- self.expected_status = {
- 'device_cereal': {
- 'processes': 5,
- 'temp': {
- 'CPU-therm': 30.0
- },
- 'battery': {
- 'temperature': 123,
- 'level': 80
- },
- 'uptime': 12345.0,
- 'mem': {
- 'total': 1234567,
- 'free': 1000000
- },
- 'build': {
- 'build.id': 'abc123',
- 'product.device': 'clownfish',
- },
- 'state': 'available',
- }
- }
-
- @mock.patch('devil.android.battery_utils.BatteryUtils')
- @mock.patch('devil.android.device_utils.DeviceUtils.HealthyDevices')
- def test_getStats(self, get_devices, get_battery):
- get_devices.return_value = [self.device]
- get_battery.return_value = self.battery
-
- status = device_monitor.get_all_status(None)
- self.assertEquals(self.expected_status, status['devices'])
-
- @mock.patch('devil.android.battery_utils.BatteryUtils')
- @mock.patch('devil.android.device_utils.DeviceUtils.HealthyDevices')
- def test_getStatsNoBattery(self, get_devices, get_battery):
- get_devices.return_value = [self.device]
- get_battery.return_value = self.battery
- broken_battery_info = mock.Mock()
- broken_battery_info.GetBatteryInfo = mock.MagicMock(
- return_value={'level': '-1', 'temperature': 'not_a_number'})
- get_battery.return_value = broken_battery_info
-
- # Should be same status dict but without battery stats.
- expected_status_no_battery = self.expected_status.copy()
- expected_status_no_battery['device_cereal'].pop('battery')
-
- status = device_monitor.get_all_status(None)
- self.assertEquals(expected_status_no_battery, status['devices'])
-
- @mock.patch('devil.android.battery_utils.BatteryUtils')
- @mock.patch('devil.android.device_utils.DeviceUtils.HealthyDevices')
- def test_getStatsNoPs(self, get_devices, get_battery):
- get_devices.return_value = [self.device]
- get_battery.return_value = self.battery
- del self.cmd_outputs['ps'] # Throw exception on run shell ps command.
-
- # Should be same status dict but without process stats.
- expected_status_no_ps = self.expected_status.copy()
- expected_status_no_ps['device_cereal'].pop('processes')
-
- status = device_monitor.get_all_status(None)
- self.assertEquals(expected_status_no_ps, status['devices'])
-
- @mock.patch('devil.android.battery_utils.BatteryUtils')
- @mock.patch('devil.android.device_utils.DeviceUtils.HealthyDevices')
- def test_getStatsNoSensors(self, get_devices, get_battery):
- get_devices.return_value = [self.device]
- get_battery.return_value = self.battery
- del self.cmd_outputs['grep'] # Throw exception on run shell grep command.
-
- # Should be same status dict but without temp stats.
- expected_status_no_temp = self.expected_status.copy()
- expected_status_no_temp['device_cereal'].pop('temp')
-
- status = device_monitor.get_all_status(None)
- self.assertEquals(expected_status_no_temp, status['devices'])
-
- @mock.patch('devil.android.battery_utils.BatteryUtils')
- @mock.patch('devil.android.device_utils.DeviceUtils.HealthyDevices')
- def test_getStatsWithBlacklist(self, get_devices, get_battery):
- get_devices.return_value = [self.device]
- get_battery.return_value = self.battery
- blacklist = mock.Mock()
- blacklist.Read = mock.MagicMock(
- return_value={'bad_device': {'reason': 'offline'}})
-
- # Should be same status dict but with extra blacklisted device.
- expected_status = self.expected_status.copy()
- expected_status['bad_device'] = {'state': 'offline'}
-
- status = device_monitor.get_all_status(blacklist)
- self.assertEquals(expected_status, status['devices'])
-
- @mock.patch('devil.android.battery_utils.BatteryUtils')
- @mock.patch('devil.android.device_utils.DeviceUtils.HealthyDevices')
- def test_brokenTempValue(self, get_devices, get_battery):
- self.file_contents['/sys/class/thermal/thermal_zone0/temp'] = 'n0t a numb3r'
- get_devices.return_value = [self.device]
- get_battery.return_value = self.battery
-
- expected_status_no_temp = self.expected_status.copy()
- expected_status_no_temp['device_cereal'].pop('temp')
-
- status = device_monitor.get_all_status(None)
- self.assertEquals(self.expected_status, status['devices'])
-
-
-if __name__ == '__main__':
- sys.exit(unittest.main())
diff --git a/third_party/catapult/devil/devil/android/tools/device_recovery.py b/third_party/catapult/devil/devil/android/tools/device_recovery.py
deleted file mode 100755
index 57857b1ed1..0000000000
--- a/third_party/catapult/devil/devil/android/tools/device_recovery.py
+++ /dev/null
@@ -1,208 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""A script to recover devices in a known bad state."""
-
-import argparse
-import logging
-import os
-import psutil
-import signal
-import sys
-
-if __name__ == '__main__':
- sys.path.append(
- os.path.abspath(os.path.join(os.path.dirname(__file__),
- '..', '..', '..')))
-from devil import devil_env
-from devil.android import device_blacklist
-from devil.android import device_errors
-from devil.android import device_utils
-from devil.android.tools import device_status
-from devil.utils import lsusb
-# TODO(jbudorick): Resolve this after experimenting w/ disabling the USB reset.
-from devil.utils import reset_usb # pylint: disable=unused-import
-from devil.utils import run_tests_helper
-
-logger = logging.getLogger(__name__)
-
-
-def KillAllAdb():
- def get_all_adb():
- for p in psutil.process_iter():
- try:
- if 'adb' in p.name:
- yield p
- except (psutil.NoSuchProcess, psutil.AccessDenied):
- pass
-
- for sig in [signal.SIGTERM, signal.SIGQUIT, signal.SIGKILL]:
- for p in get_all_adb():
- try:
- logger.info('kill %d %d (%s [%s])', sig, p.pid, p.name,
- ' '.join(p.cmdline))
- p.send_signal(sig)
- except (psutil.NoSuchProcess, psutil.AccessDenied):
- pass
- for p in get_all_adb():
- try:
- logger.error('Unable to kill %d (%s [%s])', p.pid, p.name,
- ' '.join(p.cmdline))
- except (psutil.NoSuchProcess, psutil.AccessDenied):
- pass
-
-
-def RecoverDevice(device, blacklist, should_reboot=lambda device: True):
- if device_status.IsBlacklisted(device.adb.GetDeviceSerial(),
- blacklist):
- logger.debug('%s is blacklisted, skipping recovery.', str(device))
- return
-
- if should_reboot(device):
- try:
- device.WaitUntilFullyBooted(retries=0)
- except (device_errors.CommandTimeoutError,
- device_errors.CommandFailedError):
- logger.exception('Failure while waiting for %s. '
- 'Attempting to recover.', str(device))
- try:
- try:
- device.Reboot(block=False, timeout=5, retries=0)
- except device_errors.CommandTimeoutError:
- logger.warning('Timed out while attempting to reboot %s normally.'
- 'Attempting alternative reboot.', str(device))
- # The device drops offline before we can grab the exit code, so
- # we don't check for status.
- try:
- device.adb.Root()
- finally:
- # We are already in a failure mode, attempt to reboot regardless of
- # what device.adb.Root() returns. If the sysrq reboot fails an
- # exception willbe thrown at that level.
- device.adb.Shell('echo b > /proc/sysrq-trigger', expect_status=None,
- timeout=5, retries=0)
- except device_errors.CommandFailedError:
- logger.exception('Failed to reboot %s.', str(device))
- if blacklist:
- blacklist.Extend([device.adb.GetDeviceSerial()],
- reason='reboot_failure')
- except device_errors.CommandTimeoutError:
- logger.exception('Timed out while rebooting %s.', str(device))
- if blacklist:
- blacklist.Extend([device.adb.GetDeviceSerial()],
- reason='reboot_timeout')
-
- try:
- device.WaitUntilFullyBooted(
- retries=0, timeout=device.REBOOT_DEFAULT_TIMEOUT)
- except device_errors.CommandFailedError:
- logger.exception('Failure while waiting for %s.', str(device))
- if blacklist:
- blacklist.Extend([device.adb.GetDeviceSerial()],
- reason='reboot_failure')
- except device_errors.CommandTimeoutError:
- logger.exception('Timed out while waiting for %s.', str(device))
- if blacklist:
- blacklist.Extend([device.adb.GetDeviceSerial()],
- reason='reboot_timeout')
-
-
-def RecoverDevices(devices, blacklist, enable_usb_reset=False):
- """Attempts to recover any inoperable devices in the provided list.
-
- Args:
- devices: The list of devices to attempt to recover.
- blacklist: The current device blacklist, which will be used then
- reset.
- """
-
- statuses = device_status.DeviceStatus(devices, blacklist)
-
- should_restart_usb = set(
- status['serial'] for status in statuses
- if (not status['usb_status']
- or status['adb_status'] in ('offline', 'missing')))
- should_restart_adb = should_restart_usb.union(set(
- status['serial'] for status in statuses
- if status['adb_status'] == 'unauthorized'))
- should_reboot_device = should_restart_adb.union(set(
- status['serial'] for status in statuses
- if status['blacklisted']))
-
- logger.debug('Should restart USB for:')
- for d in should_restart_usb:
- logger.debug(' %s', d)
- logger.debug('Should restart ADB for:')
- for d in should_restart_adb:
- logger.debug(' %s', d)
- logger.debug('Should reboot:')
- for d in should_reboot_device:
- logger.debug(' %s', d)
-
- if blacklist:
- blacklist.Reset()
-
- if should_restart_adb:
- KillAllAdb()
- for serial in should_restart_usb:
- try:
- # TODO(crbug.com/642194): Resetting may be causing more harm
- # (specifically, kernel panics) than it does good.
- if enable_usb_reset:
- reset_usb.reset_android_usb(serial)
- else:
- logger.warning('USB reset disabled for %s (crbug.com/642914)',
- serial)
- except IOError:
- logger.exception('Unable to reset USB for %s.', serial)
- if blacklist:
- blacklist.Extend([serial], reason='USB failure')
- except device_errors.DeviceUnreachableError:
- logger.exception('Unable to reset USB for %s.', serial)
- if blacklist:
- blacklist.Extend([serial], reason='offline')
-
- device_utils.DeviceUtils.parallel(devices).pMap(
- RecoverDevice, blacklist,
- should_reboot=lambda device: device.serial in should_reboot_device)
-
-
-def main():
- parser = argparse.ArgumentParser()
- parser.add_argument('--adb-path',
- help='Absolute path to the adb binary to use.')
- parser.add_argument('--blacklist-file', help='Device blacklist JSON file.')
- parser.add_argument('--known-devices-file', action='append', default=[],
- dest='known_devices_files',
- help='Path to known device lists.')
- parser.add_argument('--enable-usb-reset', action='store_true',
- help='Reset USB if necessary.')
- parser.add_argument('-v', '--verbose', action='count', default=1,
- help='Log more information.')
-
- args = parser.parse_args()
- run_tests_helper.SetLogLevel(args.verbose)
-
- devil_dynamic_config = devil_env.EmptyConfig()
- if args.adb_path:
- devil_dynamic_config['dependencies'].update(
- devil_env.LocalConfigItem(
- 'adb', devil_env.GetPlatform(), args.adb_path))
- devil_env.config.Initialize(configs=[devil_dynamic_config])
-
- blacklist = (device_blacklist.Blacklist(args.blacklist_file)
- if args.blacklist_file
- else None)
-
- expected_devices = device_status.GetExpectedDevices(args.known_devices_files)
- usb_devices = set(lsusb.get_android_devices())
- devices = [device_utils.DeviceUtils(s)
- for s in expected_devices.union(usb_devices)]
-
- RecoverDevices(devices, blacklist, enable_usb_reset=args.enable_usb_reset)
-
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/third_party/catapult/devil/devil/android/tools/device_status.py b/third_party/catapult/devil/devil/android/tools/device_status.py
deleted file mode 100755
index 167d66c4b5..0000000000
--- a/third_party/catapult/devil/devil/android/tools/device_status.py
+++ /dev/null
@@ -1,313 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""A script to keep track of devices across builds and report state."""
-
-import argparse
-import json
-import logging
-import os
-import re
-import sys
-
-if __name__ == '__main__':
- sys.path.append(
- os.path.abspath(os.path.join(os.path.dirname(__file__),
- '..', '..', '..')))
-from devil import devil_env
-from devil.android import battery_utils
-from devil.android import device_blacklist
-from devil.android import device_errors
-from devil.android import device_list
-from devil.android import device_utils
-from devil.android.sdk import adb_wrapper
-from devil.constants import exit_codes
-from devil.utils import lsusb
-from devil.utils import run_tests_helper
-
-logger = logging.getLogger(__name__)
-
-_RE_DEVICE_ID = re.compile(r'Device ID = (\d+)')
-
-
-def IsBlacklisted(serial, blacklist):
- return blacklist and serial in blacklist.Read()
-
-
-def _BatteryStatus(device, blacklist):
- battery_info = {}
- try:
- battery = battery_utils.BatteryUtils(device)
- battery_info = battery.GetBatteryInfo(timeout=5)
- battery_level = int(battery_info.get('level', 100))
-
- if battery_level < 15:
- logger.error('Critically low battery level (%d)', battery_level)
- battery = battery_utils.BatteryUtils(device)
- if not battery.GetCharging():
- battery.SetCharging(True)
- if blacklist:
- blacklist.Extend([device.adb.GetDeviceSerial()], reason='low_battery')
-
- except device_errors.CommandFailedError:
- logger.exception('Failed to get battery information for %s',
- str(device))
-
- return battery_info
-
-
-def _IMEISlice(device):
- imei_slice = ''
- try:
- for l in device.RunShellCommand(['dumpsys', 'iphonesubinfo'],
- check_return=True, timeout=5):
- m = _RE_DEVICE_ID.match(l)
- if m:
- imei_slice = m.group(1)[-6:]
- except device_errors.CommandFailedError:
- logger.exception('Failed to get IMEI slice for %s', str(device))
-
- return imei_slice
-
-
-def DeviceStatus(devices, blacklist):
- """Generates status information for the given devices.
-
- Args:
- devices: The devices to generate status for.
- blacklist: The current device blacklist.
- Returns:
- A dict of the following form:
- {
- '<serial>': {
- 'serial': '<serial>',
- 'adb_status': str,
- 'usb_status': bool,
- 'blacklisted': bool,
- # only if the device is connected and not blacklisted
- 'type': ro.build.product,
- 'build': ro.build.id,
- 'build_detail': ro.build.fingerprint,
- 'battery': {
- ...
- },
- 'imei_slice': str,
- 'wifi_ip': str,
- },
- ...
- }
- """
- adb_devices = {
- a[0].GetDeviceSerial(): a
- for a in adb_wrapper.AdbWrapper.Devices(desired_state=None, long_list=True)
- }
- usb_devices = set(lsusb.get_android_devices())
-
- def blacklisting_device_status(device):
- serial = device.adb.GetDeviceSerial()
- adb_status = (
- adb_devices[serial][1] if serial in adb_devices
- else 'missing')
- usb_status = bool(serial in usb_devices)
-
- device_status = {
- 'serial': serial,
- 'adb_status': adb_status,
- 'usb_status': usb_status,
- }
-
- if not IsBlacklisted(serial, blacklist):
- if adb_status == 'device':
- try:
- build_product = device.build_product
- build_id = device.build_id
- build_fingerprint = device.build_fingerprint
- build_description = device.build_description
- wifi_ip = device.GetProp('dhcp.wlan0.ipaddress')
- battery_info = _BatteryStatus(device, blacklist)
- imei_slice = _IMEISlice(device)
-
- if (device.product_name == 'mantaray' and
- battery_info.get('AC powered', None) != 'true'):
- logger.error('Mantaray device not connected to AC power.')
-
- device_status.update({
- 'ro.build.product': build_product,
- 'ro.build.id': build_id,
- 'ro.build.fingerprint': build_fingerprint,
- 'ro.build.description': build_description,
- 'battery': battery_info,
- 'imei_slice': imei_slice,
- 'wifi_ip': wifi_ip,
- })
-
- except device_errors.CommandFailedError:
- logger.exception('Failure while getting device status for %s.',
- str(device))
- if blacklist:
- blacklist.Extend([serial], reason='status_check_failure')
-
- except device_errors.CommandTimeoutError:
- logger.exception('Timeout while getting device status for %s.',
- str(device))
- if blacklist:
- blacklist.Extend([serial], reason='status_check_timeout')
-
- elif blacklist:
- blacklist.Extend([serial],
- reason=adb_status if usb_status else 'offline')
-
- device_status['blacklisted'] = IsBlacklisted(serial, blacklist)
-
- return device_status
-
- parallel_devices = device_utils.DeviceUtils.parallel(devices)
- statuses = parallel_devices.pMap(blacklisting_device_status).pGet(None)
- return statuses
-
-
-def _LogStatuses(statuses):
- # Log the state of all devices.
- for status in statuses:
- logger.info(status['serial'])
- adb_status = status.get('adb_status')
- blacklisted = status.get('blacklisted')
- logger.info(' USB status: %s',
- 'online' if status.get('usb_status') else 'offline')
- logger.info(' ADB status: %s', adb_status)
- logger.info(' Blacklisted: %s', str(blacklisted))
- if adb_status == 'device' and not blacklisted:
- logger.info(' Device type: %s', status.get('ro.build.product'))
- logger.info(' OS build: %s', status.get('ro.build.id'))
- logger.info(' OS build fingerprint: %s',
- status.get('ro.build.fingerprint'))
- logger.info(' Battery state:')
- for k, v in status.get('battery', {}).iteritems():
- logger.info(' %s: %s', k, v)
- logger.info(' IMEI slice: %s', status.get('imei_slice'))
- logger.info(' WiFi IP: %s', status.get('wifi_ip'))
-
-
-def _WriteBuildbotFile(file_path, statuses):
- buildbot_path, _ = os.path.split(file_path)
- if os.path.exists(buildbot_path):
- with open(file_path, 'w') as f:
- for status in statuses:
- try:
- if status['adb_status'] == 'device':
- f.write('{serial} {adb_status} {build_product} {build_id} '
- '{temperature:.1f}C {level}%\n'.format(
- serial=status['serial'],
- adb_status=status['adb_status'],
- build_product=status['type'],
- build_id=status['build'],
- temperature=float(status['battery']['temperature']) / 10,
- level=status['battery']['level']
- ))
- elif status.get('usb_status', False):
- f.write('{serial} {adb_status}\n'.format(
- serial=status['serial'],
- adb_status=status['adb_status']
- ))
- else:
- f.write('{serial} offline\n'.format(
- serial=status['serial']
- ))
- except Exception: # pylint: disable=broad-except
- pass
-
-
-def GetExpectedDevices(known_devices_files):
- expected_devices = set()
- try:
- for path in known_devices_files:
- if os.path.exists(path):
- expected_devices.update(device_list.GetPersistentDeviceList(path))
- else:
- logger.warning('Could not find known devices file: %s', path)
- except IOError:
- logger.warning('Problem reading %s, skipping.', path)
-
- logger.info('Expected devices:')
- for device in expected_devices:
- logger.info(' %s', device)
- return expected_devices
-
-
-def AddArguments(parser):
- parser.add_argument('--json-output',
- help='Output JSON information into a specified file.')
- parser.add_argument('--adb-path',
- help='Absolute path to the adb binary to use.')
- parser.add_argument('--blacklist-file', help='Device blacklist JSON file.')
- parser.add_argument('--known-devices-file', action='append', default=[],
- dest='known_devices_files',
- help='Path to known device lists.')
- parser.add_argument('--buildbot-path', '-b',
- default='/home/chrome-bot/.adb_device_info',
- help='Absolute path to buildbot file location')
- parser.add_argument('-v', '--verbose', action='count', default=1,
- help='Log more information.')
- parser.add_argument('-w', '--overwrite-known-devices-files',
- action='store_true',
- help='If set, overwrites known devices files wiht new '
- 'values.')
-
-def main():
- parser = argparse.ArgumentParser()
- AddArguments(parser)
- args = parser.parse_args()
-
- run_tests_helper.SetLogLevel(args.verbose)
-
- devil_dynamic_config = devil_env.EmptyConfig()
-
- if args.adb_path:
- devil_dynamic_config['dependencies'].update(
- devil_env.LocalConfigItem(
- 'adb', devil_env.GetPlatform(), args.adb_path))
- devil_env.config.Initialize(configs=[devil_dynamic_config])
-
- blacklist = (device_blacklist.Blacklist(args.blacklist_file)
- if args.blacklist_file
- else None)
-
- expected_devices = GetExpectedDevices(args.known_devices_files)
- usb_devices = set(lsusb.get_android_devices())
- devices = [device_utils.DeviceUtils(s)
- for s in expected_devices.union(usb_devices)]
-
- statuses = DeviceStatus(devices, blacklist)
-
- # Log the state of all devices.
- _LogStatuses(statuses)
-
- # Update the last devices file(s).
- if args.overwrite_known_devices_files:
- for path in args.known_devices_files:
- device_list.WritePersistentDeviceList(
- path, [status['serial'] for status in statuses])
-
- # Write device info to file for buildbot info display.
- _WriteBuildbotFile(args.buildbot_path, statuses)
-
- # Dump the device statuses to JSON.
- if args.json_output:
- with open(args.json_output, 'wb') as f:
- f.write(json.dumps(
- statuses, indent=4, sort_keys=True, separators=(',', ': ')))
-
- live_devices = [status['serial'] for status in statuses
- if (status['adb_status'] == 'device'
- and not IsBlacklisted(status['serial'], blacklist))]
-
- # If all devices failed, or if there are no devices, it's an infra error.
- if not live_devices:
- logger.error('No available devices.')
- return 0 if live_devices else exit_codes.INFRA
-
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/third_party/catapult/devil/devil/android/tools/flash_device.py b/third_party/catapult/devil/devil/android/tools/flash_device.py
deleted file mode 100755
index d13c1df72c..0000000000
--- a/third_party/catapult/devil/devil/android/tools/flash_device.py
+++ /dev/null
@@ -1,70 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import argparse
-import logging
-import os
-import sys
-
-if __name__ == '__main__':
- sys.path.append(os.path.abspath(os.path.join(
- os.path.dirname(__file__), '..', '..', '..')))
-from devil.android import device_blacklist
-from devil.android import device_utils
-from devil.android import fastboot_utils
-from devil.android.tools import script_common
-from devil.constants import exit_codes
-from devil.utils import run_tests_helper
-
-logger = logging.getLogger(__name__)
-
-
-def main():
- parser = argparse.ArgumentParser()
- parser.add_argument('build_path', help='Path to android build.')
- parser.add_argument('-d', '--device', dest='devices', action='append',
- help='Device(s) to flash.')
- parser.add_argument('-v', '--verbose', default=0, action='count',
- help='Verbose level (multiple times for more)')
- parser.add_argument('-w', '--wipe', action='store_true',
- help='If set, wipes user data')
- parser.add_argument('--blacklist-file', help='Device blacklist file.')
- args = parser.parse_args()
- run_tests_helper.SetLogLevel(args.verbose)
-
- if args.blacklist_file:
- blacklist = device_blacklist.Blacklist(args.blacklist_file).Read()
- if blacklist:
- logger.critical('Device(s) in blacklist, not flashing devices:')
- for key in blacklist:
- logger.critical(' %s', key)
- return exit_codes.INFRA
-
- flashed_devices = []
- failed_devices = []
-
- def flash(device):
- fastboot = fastboot_utils.FastbootUtils(device)
- try:
- fastboot.FlashDevice(args.build_path, wipe=args.wipe)
- flashed_devices.append(device)
- except Exception: # pylint: disable=broad-except
- logger.exception('Device %s failed to flash.', str(device))
- failed_devices.append(device)
-
- devices = script_common.GetDevices(args.devices, args.blacklist_file)
- device_utils.DeviceUtils.parallel(devices).pMap(flash)
-
- if flashed_devices:
- logger.info('The following devices were flashed:')
- logger.info(' %s', ' '.join(str(d) for d in flashed_devices))
- if failed_devices:
- logger.critical('The following devices failed to flash:')
- logger.critical(' %s', ' '.join(str(d) for d in failed_devices))
- return exit_codes.INFRA
- return 0
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/third_party/catapult/devil/devil/android/tools/keyboard.py b/third_party/catapult/devil/devil/android/tools/keyboard.py
deleted file mode 100755
index 31daf59edb..0000000000
--- a/third_party/catapult/devil/devil/android/tools/keyboard.py
+++ /dev/null
@@ -1,129 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Use your keyboard as your phone's keyboard. Experimental."""
-
-import argparse
-import copy
-import os
-import sys
-import termios
-import tty
-
-if __name__ == '__main__':
- sys.path.append(
- os.path.abspath(os.path.join(os.path.dirname(__file__),
- '..', '..', '..')))
-from devil import base_error
-from devil.android.sdk import keyevent
-from devil.android.tools import script_common
-from devil.utils import run_tests_helper
-
-
-_KEY_MAPPING = {
- '\x08': keyevent.KEYCODE_DEL,
- '\x0a': keyevent.KEYCODE_ENTER,
- ' ': keyevent.KEYCODE_SPACE,
- '.': keyevent.KEYCODE_PERIOD,
- '0': keyevent.KEYCODE_0,
- '1': keyevent.KEYCODE_1,
- '2': keyevent.KEYCODE_2,
- '3': keyevent.KEYCODE_3,
- '4': keyevent.KEYCODE_4,
- '5': keyevent.KEYCODE_5,
- '6': keyevent.KEYCODE_6,
- '7': keyevent.KEYCODE_7,
- '8': keyevent.KEYCODE_8,
- '9': keyevent.KEYCODE_9,
- 'a': keyevent.KEYCODE_A,
- 'b': keyevent.KEYCODE_B,
- 'c': keyevent.KEYCODE_C,
- 'd': keyevent.KEYCODE_D,
- 'e': keyevent.KEYCODE_E,
- 'f': keyevent.KEYCODE_F,
- 'g': keyevent.KEYCODE_G,
- 'h': keyevent.KEYCODE_H,
- 'i': keyevent.KEYCODE_I,
- 'j': keyevent.KEYCODE_J,
- 'k': keyevent.KEYCODE_K,
- 'l': keyevent.KEYCODE_L,
- 'm': keyevent.KEYCODE_M,
- 'n': keyevent.KEYCODE_N,
- 'o': keyevent.KEYCODE_O,
- 'p': keyevent.KEYCODE_P,
- 'q': keyevent.KEYCODE_Q,
- 'r': keyevent.KEYCODE_R,
- 's': keyevent.KEYCODE_S,
- 't': keyevent.KEYCODE_T,
- 'u': keyevent.KEYCODE_U,
- 'v': keyevent.KEYCODE_V,
- 'w': keyevent.KEYCODE_W,
- 'x': keyevent.KEYCODE_X,
- 'y': keyevent.KEYCODE_Y,
- 'z': keyevent.KEYCODE_Z,
- '\x7f': keyevent.KEYCODE_DEL,
-}
-
-
-def Keyboard(device, stream_itr):
- try:
- for c in stream_itr:
- k = _KEY_MAPPING.get(c)
- if k:
- device.SendKeyEvent(k)
- else:
- print
- print '(No mapping for character 0x%x)' % ord(c)
- except KeyboardInterrupt:
- pass
-
-
-def AddArguments(parser):
- parser.add_argument('-d', '--device', action='append', dest='devices',
- metavar='DEVICE', help='device serial')
- parser.add_argument('-v', '--verbose', action='count', help='print more')
-
-
-class MultipleDevicesError(base_error.BaseError):
- def __init__(self, devices):
- super(MultipleDevicesError, self).__init__(
- 'More than one device found: %s' % ', '.join(str(d) for d in devices))
-
-
-def main(raw_args):
- parser = argparse.ArgumentParser(
- description="Use your keyboard as your phone's keyboard.")
- AddArguments(parser)
- args = parser.parse_args(raw_args)
-
- run_tests_helper.SetLogLevel(args.verbose)
-
- devices = script_common.GetDevices(args.devices, None)
- if len(devices) > 1:
- raise MultipleDevicesError(devices)
-
- def next_char():
- while True:
- yield sys.stdin.read(1)
-
- try:
- fd = sys.stdin.fileno()
-
- # See man 3 termios for more info on what this is doing.
- old_attrs = termios.tcgetattr(fd)
- new_attrs = copy.deepcopy(old_attrs)
- new_attrs[tty.LFLAG] = new_attrs[tty.LFLAG] & ~(termios.ICANON)
- new_attrs[tty.CC][tty.VMIN] = 1
- new_attrs[tty.CC][tty.VTIME] = 0
- termios.tcsetattr(fd, termios.TCSAFLUSH, new_attrs)
-
- Keyboard(devices[0], next_char())
- finally:
- termios.tcsetattr(fd, termios.TCSAFLUSH, old_attrs)
- return 0
-
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv[1:]))
diff --git a/third_party/catapult/devil/devil/android/tools/provision_devices.py b/third_party/catapult/devil/devil/android/tools/provision_devices.py
deleted file mode 100755
index 7374290c79..0000000000
--- a/third_party/catapult/devil/devil/android/tools/provision_devices.py
+++ /dev/null
@@ -1,637 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright (c) 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Provisions Android devices with settings required for bots.
-
-Usage:
- ./provision_devices.py [-d <device serial number>]
-"""
-
-import argparse
-import datetime
-import json
-import logging
-import os
-import posixpath
-import re
-import sys
-import time
-
-# Import _strptime before threaded code. datetime.datetime.strptime is
-# threadsafe except for the initial import of the _strptime module.
-# See crbug.com/584730 and https://bugs.python.org/issue7980.
-import _strptime # pylint: disable=unused-import
-
-if __name__ == '__main__':
- sys.path.append(
- os.path.abspath(os.path.join(os.path.dirname(__file__),
- '..', '..', '..')))
-
-from devil import devil_env
-from devil.android import battery_utils
-from devil.android import device_blacklist
-from devil.android import device_errors
-from devil.android import device_temp_file
-from devil.android import device_utils
-from devil.android import settings
-from devil.android.constants import chrome
-from devil.android.sdk import adb_wrapper
-from devil.android.sdk import intent
-from devil.android.sdk import keyevent
-from devil.android.sdk import version_codes
-from devil.android.tools import script_common
-from devil.constants import exit_codes
-from devil.utils import run_tests_helper
-from devil.utils import timeout_retry
-
-logger = logging.getLogger(__name__)
-
-_SYSTEM_APP_DIRECTORIES = ['/system/app/', '/system/priv-app/']
-_SYSTEM_WEBVIEW_NAMES = ['webview', 'WebViewGoogle']
-_CHROME_PACKAGE_REGEX = re.compile('.*chrom.*')
-_TOMBSTONE_REGEX = re.compile('tombstone.*')
-
-
-class _DEFAULT_TIMEOUTS(object):
- # L can take a while to reboot after a wipe.
- LOLLIPOP = 600
- PRE_LOLLIPOP = 180
-
- HELP_TEXT = '{}s on L, {}s on pre-L'.format(LOLLIPOP, PRE_LOLLIPOP)
-
-
-class ProvisionStep(object):
-
- def __init__(self, cmd, reboot=False):
- self.cmd = cmd
- self.reboot = reboot
-
-
-def ProvisionDevices(
- devices,
- blacklist_file,
- adb_key_files=None,
- disable_location=False,
- disable_mock_location=False,
- disable_network=False,
- disable_system_chrome=False,
- emulators=False,
- enable_java_debug=False,
- max_battery_temp=None,
- min_battery_level=None,
- output_device_blacklist=None,
- reboot_timeout=None,
- remove_system_webview=False,
- system_app_remove_list=None,
- wipe=True):
- blacklist = (device_blacklist.Blacklist(blacklist_file)
- if blacklist_file
- else None)
- system_app_remove_list = system_app_remove_list or []
- try:
- devices = script_common.GetDevices(devices, blacklist)
- except device_errors.NoDevicesError:
- logging.error('No available devices to provision.')
- if blacklist:
- logging.error('Local device blacklist: %s', blacklist.Read())
- raise
- devices = [d for d in devices
- if not emulators or d.adb.is_emulator]
- parallel_devices = device_utils.DeviceUtils.parallel(devices)
-
- steps = []
- if wipe:
- steps += [ProvisionStep(lambda d: Wipe(d, adb_key_files), reboot=True)]
- steps += [ProvisionStep(
- lambda d: SetProperties(d, enable_java_debug, disable_location,
- disable_mock_location),
- reboot=not emulators)]
-
- if disable_network:
- steps.append(ProvisionStep(DisableNetwork))
-
- if disable_system_chrome:
- steps.append(ProvisionStep(DisableSystemChrome))
-
- if max_battery_temp:
- steps.append(ProvisionStep(
- lambda d: WaitForTemperature(d, max_battery_temp)))
-
- if min_battery_level:
- steps.append(ProvisionStep(
- lambda d: WaitForCharge(d, min_battery_level)))
-
- if remove_system_webview:
- system_app_remove_list.extend(_SYSTEM_WEBVIEW_NAMES)
-
- if system_app_remove_list:
- steps.append(ProvisionStep(
- lambda d: RemoveSystemApps(d, system_app_remove_list)))
-
- steps.append(ProvisionStep(SetDate))
- steps.append(ProvisionStep(CheckExternalStorage))
-
- parallel_devices.pMap(ProvisionDevice, steps, blacklist, reboot_timeout)
-
- blacklisted_devices = blacklist.Read() if blacklist else []
- if output_device_blacklist:
- with open(output_device_blacklist, 'w') as f:
- json.dump(blacklisted_devices, f)
- if all(d in blacklisted_devices for d in devices):
- raise device_errors.NoDevicesError
- return 0
-
-
-def ProvisionDevice(device, steps, blacklist, reboot_timeout=None):
- try:
- if not reboot_timeout:
- if device.build_version_sdk >= version_codes.LOLLIPOP:
- reboot_timeout = _DEFAULT_TIMEOUTS.LOLLIPOP
- else:
- reboot_timeout = _DEFAULT_TIMEOUTS.PRE_LOLLIPOP
-
- for step in steps:
- try:
- device.WaitUntilFullyBooted(timeout=reboot_timeout, retries=0)
- except device_errors.CommandTimeoutError:
- logger.error('Device did not finish booting. Will try to reboot.')
- device.Reboot(timeout=reboot_timeout)
- step.cmd(device)
- if step.reboot:
- device.Reboot(False, retries=0)
- device.adb.WaitForDevice()
-
- except device_errors.CommandTimeoutError:
- logger.exception('Timed out waiting for device %s. Adding to blacklist.',
- str(device))
- if blacklist:
- blacklist.Extend([str(device)], reason='provision_timeout')
-
- except device_errors.CommandFailedError:
- logger.exception('Failed to provision device %s. Adding to blacklist.',
- str(device))
- if blacklist:
- blacklist.Extend([str(device)], reason='provision_failure')
-
-
-def Wipe(device, adb_key_files=None):
- if (device.IsUserBuild() or
- device.build_version_sdk >= version_codes.MARSHMALLOW):
- WipeChromeData(device)
-
- package = "com.google.android.gms"
- version_name = device.GetApplicationVersion(package)
- logger.info("Version name for %s is %s", package, version_name)
- else:
- WipeDevice(device, adb_key_files)
-
-
-def WipeChromeData(device):
- """Wipes chrome specific data from device
-
- (1) uninstall any app whose name matches *chrom*, except
- com.android.chrome, which is the chrome stable package. Doing so also
- removes the corresponding dirs under /data/data/ and /data/app/
- (2) remove any dir under /data/app-lib/ whose name matches *chrom*
- (3) remove any files under /data/tombstones/ whose name matches "tombstone*"
- (4) remove /data/local.prop if there is any
- (5) remove /data/local/chrome-command-line if there is any
- (6) remove anything under /data/local/.config/ if the dir exists
- (this is telemetry related)
- (7) remove anything under /data/local/tmp/
-
- Arguments:
- device: the device to wipe
- """
- try:
- if device.IsUserBuild():
- _UninstallIfMatch(device, _CHROME_PACKAGE_REGEX,
- chrome.PACKAGE_INFO['chrome_stable'].package)
- device.RunShellCommand('rm -rf %s/*' % device.GetExternalStoragePath(),
- shell=True, check_return=True)
- device.RunShellCommand('rm -rf /data/local/tmp/*',
- shell=True, check_return=True)
- else:
- device.EnableRoot()
- _UninstallIfMatch(device, _CHROME_PACKAGE_REGEX,
- chrome.PACKAGE_INFO['chrome_stable'].package)
- _WipeUnderDirIfMatch(device, '/data/app-lib/', _CHROME_PACKAGE_REGEX)
- _WipeUnderDirIfMatch(device, '/data/tombstones/', _TOMBSTONE_REGEX)
-
- _WipeFileOrDir(device, '/data/local.prop')
- _WipeFileOrDir(device, '/data/local/chrome-command-line')
- _WipeFileOrDir(device, '/data/local/.config/')
- _WipeFileOrDir(device, '/data/local/tmp/')
- device.RunShellCommand('rm -rf %s/*' % device.GetExternalStoragePath(),
- shell=True, check_return=True)
- except device_errors.CommandFailedError:
- logger.exception('Possible failure while wiping the device. '
- 'Attempting to continue.')
-
-
-def _UninstallIfMatch(device, pattern, app_to_keep):
- installed_packages = device.RunShellCommand(
- ['pm', 'list', 'packages'], check_return=True)
- installed_system_packages = [
- pkg.split(':')[1] for pkg in device.RunShellCommand(
- ['pm', 'list', 'packages', '-s'], check_return=True)]
- for package_output in installed_packages:
- package = package_output.split(":")[1]
- if pattern.match(package) and not package == app_to_keep:
- if not device.IsUserBuild() or package not in installed_system_packages:
- device.Uninstall(package)
-
-
-def _WipeUnderDirIfMatch(device, path, pattern):
- for filename in device.ListDirectory(path):
- if pattern.match(filename):
- _WipeFileOrDir(device, posixpath.join(path, filename))
-
-
-def _WipeFileOrDir(device, path):
- if device.PathExists(path):
- device.RunShellCommand(['rm', '-rf', path], check_return=True)
-
-
-def WipeDevice(device, adb_key_files):
- """Wipes data from device, keeping only the adb_keys for authorization.
-
- After wiping data on a device that has been authorized, adb can still
- communicate with the device, but after reboot the device will need to be
- re-authorized because the adb keys file is stored in /data/misc/adb/.
- Thus, adb_keys file is rewritten so the device does not need to be
- re-authorized.
-
- Arguments:
- device: the device to wipe
- """
- try:
- device.EnableRoot()
- device_authorized = device.FileExists(adb_wrapper.ADB_KEYS_FILE)
- if device_authorized:
- adb_keys = device.ReadFile(adb_wrapper.ADB_KEYS_FILE,
- as_root=True).splitlines()
- device.RunShellCommand(['wipe', 'data'],
- as_root=True, check_return=True)
- device.adb.WaitForDevice()
-
- if device_authorized:
- adb_keys_set = set(adb_keys)
- for adb_key_file in adb_key_files or []:
- try:
- with open(adb_key_file, 'r') as f:
- adb_public_keys = f.readlines()
- adb_keys_set.update(adb_public_keys)
- except IOError:
- logger.warning('Unable to find adb keys file %s.', adb_key_file)
- _WriteAdbKeysFile(device, '\n'.join(adb_keys_set))
- except device_errors.CommandFailedError:
- logger.exception('Possible failure while wiping the device. '
- 'Attempting to continue.')
-
-
-def _WriteAdbKeysFile(device, adb_keys_string):
- dir_path = posixpath.dirname(adb_wrapper.ADB_KEYS_FILE)
- device.RunShellCommand(['mkdir', '-p', dir_path],
- as_root=True, check_return=True)
- device.RunShellCommand(['restorecon', dir_path],
- as_root=True, check_return=True)
- device.WriteFile(adb_wrapper.ADB_KEYS_FILE, adb_keys_string, as_root=True)
- device.RunShellCommand(['restorecon', adb_wrapper.ADB_KEYS_FILE],
- as_root=True, check_return=True)
-
-
-def SetProperties(device, enable_java_debug, disable_location,
- disable_mock_location):
- try:
- device.EnableRoot()
- except device_errors.CommandFailedError as e:
- logger.warning(str(e))
-
- if not device.IsUserBuild():
- _ConfigureLocalProperties(device, enable_java_debug)
- else:
- logger.warning('Cannot configure properties in user builds.')
- settings.ConfigureContentSettings(
- device, settings.DETERMINISTIC_DEVICE_SETTINGS)
- if disable_location:
- settings.ConfigureContentSettings(
- device, settings.DISABLE_LOCATION_SETTINGS)
- else:
- settings.ConfigureContentSettings(
- device, settings.ENABLE_LOCATION_SETTINGS)
-
- if disable_mock_location:
- settings.ConfigureContentSettings(
- device, settings.DISABLE_MOCK_LOCATION_SETTINGS)
- else:
- settings.ConfigureContentSettings(
- device, settings.ENABLE_MOCK_LOCATION_SETTINGS)
-
- settings.SetLockScreenSettings(device)
-
- # Some device types can momentarily disappear after setting properties.
- device.adb.WaitForDevice()
-
-
-def DisableNetwork(device):
- settings.ConfigureContentSettings(
- device, settings.NETWORK_DISABLED_SETTINGS)
- if device.build_version_sdk >= version_codes.MARSHMALLOW:
- # Ensure that NFC is also switched off.
- device.RunShellCommand(['svc', 'nfc', 'disable'],
- as_root=True, check_return=True)
-
-
-def DisableSystemChrome(device):
- # The system chrome version on the device interferes with some tests.
- device.RunShellCommand(['pm', 'disable', 'com.android.chrome'],
- check_return=True)
-
-
-def _RemoveSystemApp(device, system_app):
- found_paths = []
- for directory in _SYSTEM_APP_DIRECTORIES:
- path = os.path.join(directory, system_app)
- if device.PathExists(path):
- found_paths.append(path)
- if not found_paths:
- logger.warning('Could not find install location for system app %s',
- system_app)
- device.RemovePath(found_paths, force=True, recursive=True)
-
-def RemoveSystemApps(device, system_app_remove_list):
- """Attempts to remove the provided system apps from the given device.
-
- Arguments:
- device: The device to remove the system apps from.
- system_app_remove_list: A list of app names to remove, e.g.
- ['WebViewGoogle', 'GoogleVrCore']
- """
- device.EnableRoot()
- if device.HasRoot():
- # Disable Marshmallow's Verity security feature
- if device.build_version_sdk >= version_codes.MARSHMALLOW:
- logger.info('Disabling Verity on %s', device.serial)
- device.adb.DisableVerity()
- device.Reboot()
- device.WaitUntilFullyBooted()
- device.EnableRoot()
-
- device.adb.Remount()
- device.RunShellCommand(['stop'], check_return=True)
- for system_app in system_app_remove_list:
- _RemoveSystemApp(device, system_app)
- device.RunShellCommand(['start'], check_return=True)
- else:
- raise device_errors.CommandFailedError(
- 'Failed to remove system apps from non-rooted device', str(device))
-
-
-def _ConfigureLocalProperties(device, java_debug=True):
- """Set standard readonly testing device properties prior to reboot."""
- local_props = [
- 'persist.sys.usb.config=adb',
- 'ro.monkey=1',
- 'ro.test_harness=1',
- 'ro.audio.silent=1',
- 'ro.setupwizard.mode=DISABLED',
- ]
- if java_debug:
- local_props.append(
- '%s=all' % device_utils.DeviceUtils.JAVA_ASSERT_PROPERTY)
- local_props.append('debug.checkjni=1')
- try:
- device.WriteFile(
- device.LOCAL_PROPERTIES_PATH,
- '\n'.join(local_props), as_root=True)
- # Android will not respect the local props file if it is world writable.
- device.RunShellCommand(
- ['chmod', '644', device.LOCAL_PROPERTIES_PATH],
- as_root=True, check_return=True)
- except device_errors.CommandFailedError:
- logger.exception('Failed to configure local properties.')
-
-
-def FinishProvisioning(device):
- # The lockscreen can't be disabled on user builds, so send a keyevent
- # to unlock it.
- if device.IsUserBuild():
- device.SendKeyEvent(keyevent.KEYCODE_MENU)
-
-
-def WaitForCharge(device, min_battery_level):
- battery = battery_utils.BatteryUtils(device)
- try:
- battery.ChargeDeviceToLevel(min_battery_level)
- except device_errors.DeviceChargingError:
- device.Reboot()
- battery.ChargeDeviceToLevel(min_battery_level)
-
-
-def WaitForTemperature(device, max_battery_temp):
- try:
- battery = battery_utils.BatteryUtils(device)
- battery.LetBatteryCoolToTemperature(max_battery_temp)
- except device_errors.CommandFailedError:
- logger.exception('Unable to let battery cool to specified temperature.')
-
-
-def SetDate(device):
- def _set_and_verify_date():
- if device.build_version_sdk >= version_codes.MARSHMALLOW:
- date_format = '%m%d%H%M%Y.%S'
- set_date_command = ['date', '-u']
- get_date_command = ['date', '-u']
- else:
- date_format = '%Y%m%d.%H%M%S'
- set_date_command = ['date', '-s']
- get_date_command = ['date']
-
- # TODO(jbudorick): This is wrong on pre-M devices -- get/set are
- # dealing in local time, but we're setting based on GMT.
- strgmtime = time.strftime(date_format, time.gmtime())
- set_date_command.append(strgmtime)
- device.RunShellCommand(set_date_command, as_root=True, check_return=True)
-
- get_date_command.append('+"%Y%m%d.%H%M%S"')
- device_time = device.RunShellCommand(
- get_date_command, check_return=True,
- as_root=True, single_line=True).replace('"', '')
- device_time = datetime.datetime.strptime(device_time, "%Y%m%d.%H%M%S")
- correct_time = datetime.datetime.strptime(strgmtime, date_format)
- tdelta = (correct_time - device_time).seconds
- if tdelta <= 1:
- logger.info('Date/time successfully set on %s', device)
- return True
- else:
- logger.error('Date mismatch. Device: %s Correct: %s',
- device_time.isoformat(), correct_time.isoformat())
- return False
-
- # Sometimes the date is not set correctly on the devices. Retry on failure.
- if device.IsUserBuild():
- # TODO(bpastene): Figure out how to set the date & time on user builds.
- pass
- else:
- if not timeout_retry.WaitFor(
- _set_and_verify_date, wait_period=1, max_tries=2):
- raise device_errors.CommandFailedError(
- 'Failed to set date & time.', device_serial=str(device))
- device.EnableRoot()
- device.BroadcastIntent(
- intent.Intent(action='android.intent.action.TIME_SET'))
-
-
-def LogDeviceProperties(device):
- props = device.RunShellCommand(['getprop'], check_return=True)
- for prop in props:
- logger.info(' %s', prop)
-
-
-def CheckExternalStorage(device):
- """Checks that storage is writable and if not makes it writable.
-
- Arguments:
- device: The device to check.
- """
- try:
- with device_temp_file.DeviceTempFile(
- device.adb, suffix='.sh', dir=device.GetExternalStoragePath()) as f:
- device.WriteFile(f.name, 'test')
- except device_errors.CommandFailedError:
- logger.info('External storage not writable. Remounting / as RW')
- device.RunShellCommand(['mount', '-o', 'remount,rw', '/'],
- check_return=True, as_root=True)
- device.EnableRoot()
- with device_temp_file.DeviceTempFile(
- device.adb, suffix='.sh', dir=device.GetExternalStoragePath()) as f:
- device.WriteFile(f.name, 'test')
-
-
-def main(raw_args):
- # Recommended options on perf bots:
- # --disable-network
- # TODO(tonyg): We eventually want network on. However, currently radios
- # can cause perfbots to drain faster than they charge.
- # --min-battery-level 95
- # Some perf bots run benchmarks with USB charging disabled which leads
- # to gradual draining of the battery. We must wait for a full charge
- # before starting a run in order to keep the devices online.
-
- parser = argparse.ArgumentParser(
- description='Provision Android devices with settings required for bots.')
- parser.add_argument(
- '--adb-key-files', type=str, nargs='+',
- help='list of adb keys to push to device')
- parser.add_argument(
- '--adb-path',
- help='Absolute path to the adb binary to use.')
- parser.add_argument('--blacklist-file', help='Device blacklist JSON file.')
- parser.add_argument(
- '-d', '--device', metavar='SERIAL', action='append', dest='devices',
- help='the serial number of the device to be provisioned '
- '(the default is to provision all devices attached)')
- parser.add_argument(
- '--disable-location', action='store_true',
- help='disable Google location services on devices')
- parser.add_argument(
- '--disable-mock-location', action='store_true', default=False,
- help='Set ALLOW_MOCK_LOCATION to false')
- parser.add_argument(
- '--disable-network', action='store_true',
- help='disable network access on devices')
- parser.add_argument(
- '--disable-java-debug', action='store_false',
- dest='enable_java_debug', default=True,
- help='disable Java property asserts and JNI checking')
- parser.add_argument(
- '--disable-system-chrome', action='store_true',
- help='Disable the system chrome from devices.')
- parser.add_argument(
- '--emulators', action='store_true',
- help='provision only emulators and ignore usb devices '
- '(this will not wipe emulators)')
- parser.add_argument(
- '--max-battery-temp', type=int, metavar='NUM',
- help='Wait for the battery to have this temp or lower.')
- parser.add_argument(
- '--min-battery-level', type=int, metavar='NUM',
- help='wait for the device to reach this minimum battery'
- ' level before trying to continue')
- parser.add_argument(
- '--output-device-blacklist',
- help='Json file to output the device blacklist.')
- parser.add_argument(
- '--reboot-timeout', metavar='SECS', type=int,
- help='when wiping the device, max number of seconds to'
- ' wait after each reboot '
- '(default: %s)' % _DEFAULT_TIMEOUTS.HELP_TEXT)
- parser.add_argument(
- '--remove-system-apps', nargs='*', dest='system_app_remove_list',
- help='the names of system apps to remove')
- parser.add_argument(
- '--remove-system-webview', action='store_true',
- help='Remove the system webview from devices.')
- parser.add_argument(
- '--skip-wipe', action='store_true', default=False,
- help='do not wipe device data during provisioning')
- parser.add_argument(
- '-v', '--verbose', action='count', default=1,
- help='Log more information.')
-
- # No-op arguments for compatibility with build/android/provision_devices.py.
- # TODO(jbudorick): Remove these once all callers have stopped using them.
- parser.add_argument(
- '--chrome-specific-wipe', action='store_true',
- help=argparse.SUPPRESS)
- parser.add_argument(
- '--phase', action='append',
- help=argparse.SUPPRESS)
- parser.add_argument(
- '-r', '--auto-reconnect', action='store_true',
- help=argparse.SUPPRESS)
- parser.add_argument(
- '-t', '--target',
- help=argparse.SUPPRESS)
-
- args = parser.parse_args(raw_args)
-
- run_tests_helper.SetLogLevel(args.verbose)
-
- devil_dynamic_config = devil_env.EmptyConfig()
- if args.adb_path:
- devil_dynamic_config['dependencies'].update(
- devil_env.LocalConfigItem(
- 'adb', devil_env.GetPlatform(), args.adb_path))
-
- devil_env.config.Initialize(configs=[devil_dynamic_config])
-
- try:
- return ProvisionDevices(
- args.devices,
- args.blacklist_file,
- adb_key_files=args.adb_key_files,
- disable_location=args.disable_location,
- disable_mock_location=args.disable_mock_location,
- disable_network=args.disable_network,
- disable_system_chrome=args.disable_system_chrome,
- emulators=args.emulators,
- enable_java_debug=args.enable_java_debug,
- max_battery_temp=args.max_battery_temp,
- min_battery_level=args.min_battery_level,
- output_device_blacklist=args.output_device_blacklist,
- reboot_timeout=args.reboot_timeout,
- remove_system_webview=args.remove_system_webview,
- system_app_remove_list=args.system_app_remove_list,
- wipe=not args.skip_wipe and not args.emulators)
- except (device_errors.DeviceUnreachableError, device_errors.NoDevicesError):
- logging.exception('Unable to provision local devices.')
- return exit_codes.INFRA
-
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv[1:]))
diff --git a/third_party/catapult/devil/devil/android/tools/screenshot.py b/third_party/catapult/devil/devil/android/tools/screenshot.py
deleted file mode 100755
index a264c4f3d4..0000000000
--- a/third_party/catapult/devil/devil/android/tools/screenshot.py
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Takes a screenshot from an Android device."""
-
-import argparse
-import logging
-import os
-import sys
-
-if __name__ == '__main__':
- sys.path.append(os.path.abspath(os.path.join(
- os.path.dirname(__file__), '..', '..', '..')))
-from devil.android import device_utils
-from devil.android.tools import script_common
-
-logger = logging.getLogger(__name__)
-
-
-def main():
- # Parse options.
- parser = argparse.ArgumentParser(description=__doc__)
- parser.add_argument('-d', '--device', dest='devices', action='append',
- help='Serial number of Android device to use.')
- parser.add_argument('--blacklist-file', help='Device blacklist JSON file.')
- parser.add_argument('-f', '--file', metavar='FILE',
- help='Save result to file instead of generating a '
- 'timestamped file name.')
- parser.add_argument('-v', '--verbose', action='store_true',
- help='Verbose logging.')
- parser.add_argument('host_file', nargs='?',
- help='File to which the screenshot will be saved.')
-
- args = parser.parse_args()
-
- host_file = args.host_file or args.file
-
- if args.verbose:
- logging.getLogger().setLevel(logging.DEBUG)
-
- devices = script_common.GetDevices(args.devices, args.blacklist_file)
-
- def screenshot(device):
- f = None
- if host_file:
- root, ext = os.path.splitext(host_file)
- f = '%s_%s%s' % (root, str(device), ext)
- f = device.TakeScreenshot(f)
- print 'Screenshot for device %s written to %s' % (
- str(device), os.path.abspath(f))
-
- device_utils.DeviceUtils.parallel(devices).pMap(screenshot)
- return 0
-
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/third_party/catapult/devil/devil/android/tools/script_common.py b/third_party/catapult/devil/devil/android/tools/script_common.py
deleted file mode 100644
index f91ad5eea0..0000000000
--- a/third_party/catapult/devil/devil/android/tools/script_common.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-from devil.android import device_blacklist
-from devil.android import device_errors
-from devil.android import device_utils
-
-
-def GetDevices(requested_devices, blacklist_file):
- if not isinstance(blacklist_file, device_blacklist.Blacklist):
- blacklist_file = (device_blacklist.Blacklist(blacklist_file)
- if blacklist_file
- else None)
-
- devices = device_utils.DeviceUtils.HealthyDevices(blacklist_file)
- if not devices:
- raise device_errors.NoDevicesError()
- elif requested_devices:
- requested = set(requested_devices)
- available = set(str(d) for d in devices)
- missing = requested.difference(available)
- if missing:
- raise device_errors.DeviceUnreachableError(next(iter(missing)))
- return sorted(device_utils.DeviceUtils(d)
- for d in available.intersection(requested))
- else:
- return devices
-
diff --git a/third_party/catapult/devil/devil/android/tools/script_common_test.py b/third_party/catapult/devil/devil/android/tools/script_common_test.py
deleted file mode 100755
index a226764557..0000000000
--- a/third_party/catapult/devil/devil/android/tools/script_common_test.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-
-import sys
-import unittest
-
-from devil import devil_env
-from devil.android import device_errors
-from devil.android import device_utils
-from devil.android.tools import script_common
-
-with devil_env.SysPath(devil_env.PYMOCK_PATH):
- import mock # pylint: disable=import-error
-
-
-class ScriptCommonTest(unittest.TestCase):
-
- def testGetDevices_noSpecs(self):
- devices = [
- device_utils.DeviceUtils('123'),
- device_utils.DeviceUtils('456'),
- ]
- with mock.patch('devil.android.device_utils.DeviceUtils.HealthyDevices',
- return_value=devices):
- self.assertEquals(
- devices,
- script_common.GetDevices(None, None))
-
- def testGetDevices_withDevices(self):
- devices = [
- device_utils.DeviceUtils('123'),
- device_utils.DeviceUtils('456'),
- ]
- with mock.patch('devil.android.device_utils.DeviceUtils.HealthyDevices',
- return_value=devices):
- self.assertEquals(
- [device_utils.DeviceUtils('456')],
- script_common.GetDevices(['456'], None))
-
- def testGetDevices_missingDevice(self):
- with mock.patch('devil.android.device_utils.DeviceUtils.HealthyDevices',
- return_value=[device_utils.DeviceUtils('123')]):
- with self.assertRaises(device_errors.DeviceUnreachableError):
- script_common.GetDevices(['456'], None)
-
- def testGetDevices_noDevices(self):
- with mock.patch('devil.android.device_utils.DeviceUtils.HealthyDevices',
- return_value=[]):
- with self.assertRaises(device_errors.NoDevicesError):
- script_common.GetDevices(None, None)
-
-
-if __name__ == '__main__':
- sys.exit(unittest.main())
-
diff --git a/third_party/catapult/devil/devil/android/tools/video_recorder.py b/third_party/catapult/devil/devil/android/tools/video_recorder.py
deleted file mode 100755
index a91e649699..0000000000
--- a/third_party/catapult/devil/devil/android/tools/video_recorder.py
+++ /dev/null
@@ -1,175 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Captures a video from an Android device."""
-
-import argparse
-import logging
-import os
-import threading
-import time
-import sys
-
-if __name__ == '__main__':
- sys.path.append(os.path.abspath(os.path.join(
- os.path.dirname(__file__), '..', '..', '..')))
-from devil.android import device_signal
-from devil.android import device_utils
-from devil.android.tools import script_common
-from devil.utils import cmd_helper
-from devil.utils import reraiser_thread
-from devil.utils import timeout_retry
-
-logger = logging.getLogger(__name__)
-
-
-class VideoRecorder(object):
- """Records a screen capture video from an Android Device (KitKat or newer)."""
-
- def __init__(self, device, megabits_per_second=4, size=None,
- rotate=False):
- """Creates a VideoRecorder instance.
-
- Args:
- device: DeviceUtils instance.
- host_file: Path to the video file to store on the host.
- megabits_per_second: Video bitrate in megabits per second. Allowed range
- from 0.1 to 100 mbps.
- size: Video frame size tuple (width, height) or None to use the device
- default.
- rotate: If True, the video will be rotated 90 degrees.
- """
- self._bit_rate = megabits_per_second * 1000 * 1000
- self._device = device
- self._device_file = (
- '%s/screen-recording.mp4' % device.GetExternalStoragePath())
- self._recorder_thread = None
- self._rotate = rotate
- self._size = size
- self._started = threading.Event()
-
- def __enter__(self):
- self.Start()
-
- def Start(self, timeout=None):
- """Start recording video."""
- def screenrecord_started():
- return bool(self._device.GetPids('screenrecord'))
-
- if screenrecord_started():
- raise Exception("Can't run multiple concurrent video captures.")
-
- self._started.clear()
- self._recorder_thread = reraiser_thread.ReraiserThread(self._Record)
- self._recorder_thread.start()
- timeout_retry.WaitFor(
- screenrecord_started, wait_period=1, max_tries=timeout)
- self._started.wait(timeout)
-
- def _Record(self):
- cmd = ['screenrecord', '--verbose', '--bit-rate', str(self._bit_rate)]
- if self._rotate:
- cmd += ['--rotate']
- if self._size:
- cmd += ['--size', '%dx%d' % self._size]
- cmd += [self._device_file]
- for line in self._device.adb.IterShell(
- ' '.join(cmd_helper.SingleQuote(i) for i in cmd), None):
- if line.startswith('Content area is '):
- self._started.set()
-
- def __exit__(self, _exc_type, _exc_value, _traceback):
- self.Stop()
-
- def Stop(self):
- """Stop recording video."""
- if not self._device.KillAll('screenrecord', signum=device_signal.SIGINT,
- quiet=True):
- logger.warning('Nothing to kill: screenrecord was not running')
- self._recorder_thread.join()
-
- def Pull(self, host_file=None):
- """Pull resulting video file from the device.
-
- Args:
- host_file: Path to the video file to store on the host.
- Returns:
- Output video file name on the host.
- """
- # TODO(jbudorick): Merge filename generation with the logic for doing so in
- # DeviceUtils.
- host_file_name = (
- host_file
- or 'screen-recording-%s-%s.mp4' % (
- str(self._device),
- time.strftime('%Y%m%dT%H%M%S', time.localtime())))
- host_file_name = os.path.abspath(host_file_name)
- self._device.PullFile(self._device_file, host_file_name)
- self._device.RemovePath(self._device_file, force=True)
- return host_file_name
-
-
-def main():
- # Parse options.
- parser = argparse.ArgumentParser(description=__doc__)
- parser.add_argument('-d', '--device', dest='devices', action='append',
- help='Serial number of Android device to use.')
- parser.add_argument('--blacklist-file', help='Device blacklist JSON file.')
- parser.add_argument('-f', '--file', metavar='FILE',
- help='Save result to file instead of generating a '
- 'timestamped file name.')
- parser.add_argument('-v', '--verbose', action='store_true',
- help='Verbose logging.')
- parser.add_argument('-b', '--bitrate', default=4, type=float,
- help='Bitrate in megabits/s, from 0.1 to 100 mbps, '
- '%default mbps by default.')
- parser.add_argument('-r', '--rotate', action='store_true',
- help='Rotate video by 90 degrees.')
- parser.add_argument('-s', '--size', metavar='WIDTHxHEIGHT',
- help='Frame size to use instead of the device '
- 'screen size.')
- parser.add_argument('host_file', nargs='?',
- help='File to which the video capture will be written.')
-
- args = parser.parse_args()
-
- host_file = args.host_file or args.file
-
- if args.verbose:
- logging.getLogger().setLevel(logging.DEBUG)
-
- size = (tuple(int(i) for i in args.size.split('x'))
- if args.size
- else None)
-
- def record_video(device, stop_recording):
- recorder = VideoRecorder(
- device, megabits_per_second=args.bitrate, size=size, rotate=args.rotate)
- with recorder:
- stop_recording.wait()
-
- f = None
- if host_file:
- root, ext = os.path.splitext(host_file)
- f = '%s_%s%s' % (root, str(device), ext)
- f = recorder.Pull(f)
- print 'Video written to %s' % os.path.abspath(f)
-
- parallel_devices = device_utils.DeviceUtils.parallel(
- script_common.GetDevices(args.devices, args.blacklist_file),
- async=True)
- stop_recording = threading.Event()
- running_recording = parallel_devices.pMap(record_video, stop_recording)
- print 'Recording. Press Enter to stop.',
- sys.stdout.flush()
- raw_input()
- stop_recording.set()
-
- running_recording.pGet(None)
- return 0
-
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/third_party/catapult/devil/devil/android/tools/wait_for_devices.py b/third_party/catapult/devil/devil/android/tools/wait_for_devices.py
deleted file mode 100755
index 4bde2cd4b0..0000000000
--- a/third_party/catapult/devil/devil/android/tools/wait_for_devices.py
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Waits for the given devices to be available."""
-
-import argparse
-import os
-import sys
-
-if __name__ == '__main__':
- sys.path.append(
- os.path.abspath(os.path.join(os.path.dirname(__file__),
- '..', '..', '..')))
-
-from devil import devil_env
-from devil.android import device_utils
-from devil.utils import run_tests_helper
-
-
-def main(raw_args):
- parser = argparse.ArgumentParser()
- parser.add_argument('-v', '--verbose', action='count', help='Log more.')
- parser.add_argument('-t', '--timeout', default=30, type=int,
- help='Seconds to wait for the devices.')
- parser.add_argument('--adb-path', help='ADB binary to use.')
- parser.add_argument('device_serials', nargs='*', metavar='SERIAL',
- help='Serials of the devices to wait for.')
-
- args = parser.parse_args(raw_args)
-
- run_tests_helper.SetLogLevel(args.verbose)
-
- devil_dynamic_config = devil_env.EmptyConfig()
- if args.adb_path:
- devil_dynamic_config['dependencies'].update(
- devil_env.LocalConfigItem(
- 'adb', devil_env.GetPlatform(), args.adb_path))
- devil_env.config.Initialize(configs=[devil_dynamic_config])
-
- devices = device_utils.DeviceUtils.HealthyDevices(
- device_arg=args.device_serials)
- parallel_devices = device_utils.DeviceUtils.parallel(devices)
- parallel_devices.WaitUntilFullyBooted(timeout=args.timeout)
- return 0
-
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv[1:]))
diff --git a/third_party/catapult/devil/devil/android/valgrind_tools/__init__.py b/third_party/catapult/devil/devil/android/valgrind_tools/__init__.py
deleted file mode 100644
index 0182d4c176..0000000000
--- a/third_party/catapult/devil/devil/android/valgrind_tools/__init__.py
+++ /dev/null
@@ -1,21 +0,0 @@
-# Copyright (c) 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-"""
-Classes in this package define additional actions that need to be taken to run a
-test under some kind of runtime error detection tool.
-
-The interface is intended to be used as follows.
-
-1. For tests that simply run a native process (i.e. no activity is spawned):
-
-Call tool.CopyFiles(device).
-Prepend test command line with tool.GetTestWrapper().
-
-2. For tests that spawn an activity:
-
-Call tool.CopyFiles(device).
-Call tool.SetupEnvironment().
-Run the test as usual.
-Call tool.CleanUpEnvironment().
-"""
diff --git a/third_party/catapult/devil/devil/android/valgrind_tools/base_tool.py b/third_party/catapult/devil/devil/android/valgrind_tools/base_tool.py
deleted file mode 100644
index 2e6e9af3d3..0000000000
--- a/third_party/catapult/devil/devil/android/valgrind_tools/base_tool.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# Copyright (c) 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-
-class BaseTool(object):
- """A tool that does nothing."""
- # pylint: disable=R0201
-
- def __init__(self):
- """Does nothing."""
- pass
-
- def GetTestWrapper(self):
- """Returns a string that is to be prepended to the test command line."""
- return ''
-
- def GetUtilWrapper(self):
- """Returns the wrapper name for the utilities.
-
- Returns:
- A string that is to be prepended to the command line of utility
- processes (forwarder, etc.).
- """
- return ''
-
- @classmethod
- def CopyFiles(cls, device):
- """Copies tool-specific files to the device, create directories, etc."""
- pass
-
- def SetupEnvironment(self):
- """Sets up the system environment for a test.
-
- This is a good place to set system properties.
- """
- pass
-
- def CleanUpEnvironment(self):
- """Cleans up environment."""
- pass
-
- def GetTimeoutScale(self):
- """Returns a multiplier that should be applied to timeout values."""
- return 1.0
-
- def NeedsDebugInfo(self):
- """Whether this tool requires debug info.
-
- Returns:
- True if this tool can not work with stripped binaries.
- """
- return False
diff --git a/third_party/catapult/devil/devil/base_error.py b/third_party/catapult/devil/devil/base_error.py
deleted file mode 100644
index 4b896613dc..0000000000
--- a/third_party/catapult/devil/devil/base_error.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-
-class BaseError(Exception):
- """Base error for all test runner errors."""
-
- def __init__(self, message, is_infra_error=False):
- super(BaseError, self).__init__(message)
- self._is_infra_error = is_infra_error
-
- def __eq__(self, other):
- return (self.message == other.message
- and self.is_infra_error == other.is_infra_error)
-
- def __ne__(self, other):
- return not self == other
-
- @property
- def is_infra_error(self):
- """Property to indicate if error was caused by an infrastructure issue."""
- return self._is_infra_error
-
diff --git a/third_party/catapult/devil/devil/constants/__init__.py b/third_party/catapult/devil/devil/constants/__init__.py
deleted file mode 100644
index 50b23dff63..0000000000
--- a/third_party/catapult/devil/devil/constants/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
diff --git a/third_party/catapult/devil/devil/constants/exit_codes.py b/third_party/catapult/devil/devil/constants/exit_codes.py
deleted file mode 100644
index aaeca4a871..0000000000
--- a/third_party/catapult/devil/devil/constants/exit_codes.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Common exit codes used by devil."""
-
-ERROR = 1
-INFRA = 87
-WARNING = 88
diff --git a/third_party/catapult/devil/devil/devil_dependencies.json b/third_party/catapult/devil/devil/devil_dependencies.json
deleted file mode 100644
index bed6fe10a2..0000000000
--- a/third_party/catapult/devil/devil/devil_dependencies.json
+++ /dev/null
@@ -1,127 +0,0 @@
-{
- "config_type": "BaseConfig",
- "dependencies": {
- "aapt": {
- "cloud_storage_base_folder": "binary_dependencies",
- "cloud_storage_bucket": "chromium-telemetry",
- "file_info": {
- "linux2_x86_64": {
- "cloud_storage_hash": "16ba3180141a2489d7ec99b39fd6e3434a9a373f",
- "download_path": "../bin/deps/linux2/x86_64/bin/aapt"
- }
- }
- },
- "adb": {
- "cloud_storage_base_folder": "binary_dependencies",
- "cloud_storage_bucket": "chromium-telemetry",
- "file_info": {
- "linux2_x86_64": {
- "cloud_storage_hash": "8bd43e3930f6eec643d5dc64cab9e5bb4ddf4909",
- "download_path": "../bin/deps/linux2/x86_64/bin/adb"
- }
- }
- },
- "android_build_tools_libc++": {
- "cloud_storage_base_folder": "binary_dependencies",
- "cloud_storage_bucket": "chromium-telemetry",
- "file_info": {
- "linux2_x86_64": {
- "cloud_storage_hash": "91cdce1e3bd81b2ac1fd380013896d0e2cdb40a0",
- "download_path": "../bin/deps/linux2/x86_64/lib/libc++.so"
- }
- }
- },
- "chromium_commands": {
- "cloud_storage_base_folder": "binary_dependencies",
- "cloud_storage_bucket": "chromium-telemetry",
- "file_info": {
- "linux2_x86_64": {
- "cloud_storage_hash": "4e22f641e4757309510e8d9f933f5aa504574ab6",
- "download_path": "../bin/deps/linux2/x86_64/lib.java/chromium_commands.dex.jar"
- }
- }
- },
- "dexdump": {
- "cloud_storage_base_folder": "binary_dependencies",
- "cloud_storage_bucket": "chromium-telemetry",
- "file_info": {
- "linux2_x86_64": {
- "cloud_storage_hash": "acfb10f7a868baf9bcf446a2d9f8ed6b5d52c3c6",
- "download_path": "../bin/deps/linux2/x86_64/bin/dexdump"
- }
- }
- },
- "fastboot": {
- "cloud_storage_base_folder": "binary_dependencies",
- "cloud_storage_bucket": "chromium-telemetry",
- "file_info": {
- "linux2_x86_64": {
- "cloud_storage_hash": "db9728166f182800eb9d09e9f036d56e105e8235",
- "download_path": "../bin/deps/linux2/x86_64/bin/fastboot"
- }
- }
- },
- "forwarder_device": {
- "cloud_storage_base_folder": "binary_dependencies",
- "cloud_storage_bucket": "chromium-telemetry",
- "file_info": {
- "android_arm64-v8a": {
- "cloud_storage_hash": "f222268d8442979240d1b18de00911a49e548daa",
- "download_path": "../bin/deps/android/arm64-v8a/bin/forwarder_device"
- },
- "android_armeabi-v7a": {
- "cloud_storage_hash": "c15267bf01c26eb0aea4f61c780bbba460c5c981",
- "download_path": "../bin/deps/android/armeabi-v7a/bin/forwarder_device"
- }
- }
- },
- "forwarder_host": {
- "cloud_storage_base_folder": "binary_dependencies",
- "cloud_storage_bucket": "chromium-telemetry",
- "file_info": {
- "linux2_x86_64": {
- "cloud_storage_hash": "8fe69994b670f028484eed475dbffc838c8a57f7",
- "download_path": "../bin/deps/linux2/x86_64/forwarder_host"
- }
- }
- },
- "md5sum_device": {
- "cloud_storage_base_folder": "binary_dependencies",
- "cloud_storage_bucket": "chromium-telemetry",
- "file_info": {
- "android_arm64-v8a": {
- "cloud_storage_hash": "4e7d2dedd9c6321fdc152b06869e09a3c5817904",
- "download_path": "../bin/deps/android/arm64-v8a/bin/md5sum_device"
- },
- "android_armeabi-v7a": {
- "cloud_storage_hash": "39fd90af0f8828202b687f7128393759181c5e2e",
- "download_path": "../bin/deps/android/armeabi-v7a/bin/md5sum_device"
- },
- "android_x86": {
- "cloud_storage_hash": "d5cf42ab5986a69c31c0177b0df499d6bf708df6",
- "download_path": "../bin/deps/android/x86/bin/md5sum_device"
- }
- }
- },
- "md5sum_host": {
- "cloud_storage_base_folder": "binary_dependencies",
- "cloud_storage_bucket": "chromium-telemetry",
- "file_info": {
- "linux2_x86_64": {
- "cloud_storage_hash": "4db5bd5e9bea8880d8bf2caa59d0efb0acc19f74",
- "download_path": "../bin/deps/linux2/x86_64/bin/md5sum_host"
- }
- }
- },
- "split-select": {
- "cloud_storage_base_folder": "binary_dependencies",
- "cloud_storage_bucket": "chromium-telemetry",
- "file_info": {
- "linux2_x86_64": {
- "cloud_storage_hash": "abb9753a8d3efeea4144e328933931729e01571c",
- "download_path": "../bin/deps/linux2/x86_64/bin/split-select"
- }
- }
- }
- }
-} \ No newline at end of file
diff --git a/third_party/catapult/devil/devil/devil_env.py b/third_party/catapult/devil/devil/devil_env.py
deleted file mode 100644
index aa4fe1ee6d..0000000000
--- a/third_party/catapult/devil/devil/devil_env.py
+++ /dev/null
@@ -1,194 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import contextlib
-import json
-import logging
-import os
-import platform
-import sys
-import tempfile
-import threading
-
-CATAPULT_ROOT_PATH = os.path.abspath(os.path.join(
- os.path.dirname(__file__), '..', '..'))
-DEPENDENCY_MANAGER_PATH = os.path.join(
- CATAPULT_ROOT_PATH, 'dependency_manager')
-PYMOCK_PATH = os.path.join(
- CATAPULT_ROOT_PATH, 'third_party', 'mock')
-
-
-@contextlib.contextmanager
-def SysPath(path):
- sys.path.append(path)
- yield
- if sys.path[-1] != path:
- sys.path.remove(path)
- else:
- sys.path.pop()
-
-with SysPath(DEPENDENCY_MANAGER_PATH):
- import dependency_manager # pylint: disable=import-error
-
-_ANDROID_BUILD_TOOLS = {'aapt', 'dexdump', 'split-select'}
-
-_DEVIL_DEFAULT_CONFIG = os.path.abspath(os.path.join(
- os.path.dirname(__file__), 'devil_dependencies.json'))
-
-_LEGACY_ENVIRONMENT_VARIABLES = {
- 'ADB_PATH': {
- 'dependency_name': 'adb',
- 'platform': 'linux2_x86_64',
- },
- 'ANDROID_SDK_ROOT': {
- 'dependency_name': 'android_sdk',
- 'platform': 'linux2_x86_64',
- },
-}
-
-
-def EmptyConfig():
- return {
- 'config_type': 'BaseConfig',
- 'dependencies': {}
- }
-
-
-def LocalConfigItem(dependency_name, dependency_platform, dependency_path):
- if isinstance(dependency_path, basestring):
- dependency_path = [dependency_path]
- return {
- dependency_name: {
- 'file_info': {
- dependency_platform: {
- 'local_paths': dependency_path
- },
- },
- },
- }
-
-
-def _GetEnvironmentVariableConfig():
- env_config = EmptyConfig()
- path_config = (
- (os.environ.get(k), v)
- for k, v in _LEGACY_ENVIRONMENT_VARIABLES.iteritems())
- path_config = ((p, c) for p, c in path_config if p)
- for p, c in path_config:
- env_config['dependencies'].update(
- LocalConfigItem(c['dependency_name'], c['platform'], p))
- return env_config
-
-
-class _Environment(object):
-
- def __init__(self):
- self._dm_init_lock = threading.Lock()
- self._dm = None
- self._logging_init_lock = threading.Lock()
- self._logging_initialized = False
-
- def Initialize(self, configs=None, config_files=None):
- """Initialize devil's environment from configuration files.
-
- This uses all configurations provided via |configs| and |config_files|
- to determine the locations of devil's dependencies. Configurations should
- all take the form described by py_utils.dependency_manager.BaseConfig.
- If no configurations are provided, a default one will be used if available.
-
- Args:
- configs: An optional list of dict configurations.
- config_files: An optional list of files to load
- """
-
- # Make sure we only initialize self._dm once.
- with self._dm_init_lock:
- if self._dm is None:
- if configs is None:
- configs = []
-
- env_config = _GetEnvironmentVariableConfig()
- if env_config:
- configs.insert(0, env_config)
- self._InitializeRecursive(
- configs=configs,
- config_files=config_files)
- assert self._dm is not None, 'Failed to create dependency manager.'
-
- def _InitializeRecursive(self, configs=None, config_files=None):
- # This recurses through configs to create temporary files for each and
- # take advantage of context managers to appropriately close those files.
- # TODO(jbudorick): Remove this recursion if/when dependency_manager
- # supports loading configurations directly from a dict.
- if configs:
- with tempfile.NamedTemporaryFile(delete=False) as next_config_file:
- try:
- next_config_file.write(json.dumps(configs[0]))
- next_config_file.close()
- self._InitializeRecursive(
- configs=configs[1:],
- config_files=[next_config_file.name] + (config_files or []))
- finally:
- if os.path.exists(next_config_file.name):
- os.remove(next_config_file.name)
- else:
- config_files = config_files or []
- if 'DEVIL_ENV_CONFIG' in os.environ:
- config_files.append(os.environ.get('DEVIL_ENV_CONFIG'))
- config_files.append(_DEVIL_DEFAULT_CONFIG)
-
- self._dm = dependency_manager.DependencyManager(
- [dependency_manager.BaseConfig(c) for c in config_files])
-
- def InitializeLogging(self, log_level, formatter=None, handler=None):
- if self._logging_initialized:
- return
-
- with self._logging_init_lock:
- if self._logging_initialized:
- return
-
- formatter = formatter or logging.Formatter(
- '%(threadName)-4s %(message)s')
- handler = handler or logging.StreamHandler(sys.stdout)
- handler.setFormatter(formatter)
-
- devil_logger = logging.getLogger('devil')
- devil_logger.setLevel(log_level)
- devil_logger.propagate = False
- devil_logger.addHandler(handler)
-
- import py_utils.cloud_storage
- lock_logger = py_utils.cloud_storage.logger
- lock_logger.setLevel(log_level)
- lock_logger.propagate = False
- lock_logger.addHandler(handler)
-
- self._logging_initialized = True
-
- def FetchPath(self, dependency, arch=None, device=None):
- if self._dm is None:
- self.Initialize()
- if dependency in _ANDROID_BUILD_TOOLS:
- self.FetchPath('android_build_tools_libc++', arch=arch, device=device)
- return self._dm.FetchPath(dependency, GetPlatform(arch, device))
-
- def LocalPath(self, dependency, arch=None, device=None):
- if self._dm is None:
- self.Initialize()
- return self._dm.LocalPath(dependency, GetPlatform(arch, device))
-
- def PrefetchPaths(self, dependencies=None, arch=None, device=None):
- return self._dm.PrefetchPaths(
- GetPlatform(arch, device), dependencies=dependencies)
-
-
-def GetPlatform(arch=None, device=None):
- if arch or device:
- return 'android_%s' % (arch or device.product_cpu_abi)
- return '%s_%s' % (sys.platform, platform.machine())
-
-
-config = _Environment()
-
diff --git a/third_party/catapult/devil/devil/devil_env_test.py b/third_party/catapult/devil/devil/devil_env_test.py
deleted file mode 100755
index e78221a070..0000000000
--- a/third_party/catapult/devil/devil/devil_env_test.py
+++ /dev/null
@@ -1,63 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# pylint: disable=protected-access
-
-import logging
-import sys
-import unittest
-
-from devil import devil_env
-
-_sys_path_before = list(sys.path)
-with devil_env.SysPath(devil_env.PYMOCK_PATH):
- _sys_path_with_pymock = list(sys.path)
- import mock # pylint: disable=import-error
-_sys_path_after = list(sys.path)
-
-
-class DevilEnvTest(unittest.TestCase):
-
- def testSysPath(self):
- self.assertEquals(_sys_path_before, _sys_path_after)
- self.assertEquals(
- _sys_path_before + [devil_env.PYMOCK_PATH],
- _sys_path_with_pymock)
-
- def testGetEnvironmentVariableConfig_configType(self):
- with mock.patch('os.environ.get',
- mock.Mock(side_effect=lambda _env_var: None)):
- env_config = devil_env._GetEnvironmentVariableConfig()
- self.assertEquals('BaseConfig', env_config.get('config_type'))
-
- def testGetEnvironmentVariableConfig_noEnv(self):
- with mock.patch('os.environ.get',
- mock.Mock(side_effect=lambda _env_var: None)):
- env_config = devil_env._GetEnvironmentVariableConfig()
- self.assertEquals({}, env_config.get('dependencies'))
-
- def testGetEnvironmentVariableConfig_adbPath(self):
- def mock_environment(env_var):
- return '/my/fake/adb/path' if env_var == 'ADB_PATH' else None
-
- with mock.patch('os.environ.get',
- mock.Mock(side_effect=mock_environment)):
- env_config = devil_env._GetEnvironmentVariableConfig()
- self.assertEquals(
- {
- 'adb': {
- 'file_info': {
- 'linux2_x86_64': {
- 'local_paths': ['/my/fake/adb/path'],
- },
- },
- },
- },
- env_config.get('dependencies'))
-
-
-if __name__ == '__main__':
- logging.getLogger().setLevel(logging.DEBUG)
- unittest.main(verbosity=2)
diff --git a/third_party/catapult/devil/devil/utils/__init__.py b/third_party/catapult/devil/devil/utils/__init__.py
deleted file mode 100644
index ff84988dbd..0000000000
--- a/third_party/catapult/devil/devil/utils/__init__.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import os
-import sys
-
-def _JoinPath(*path_parts):
- return os.path.abspath(os.path.join(*path_parts))
-
-
-def _AddDirToPythonPath(*path_parts):
- path = _JoinPath(*path_parts)
- if os.path.isdir(path) and path not in sys.path:
- # Some call sites that use Telemetry assume that sys.path[0] is the
- # directory containing the script, so we add these extra paths to right
- # after sys.path[0].
- sys.path.insert(1, path)
-
-_CATAPULT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)),
- os.path.pardir, os.path.pardir, os.path.pardir)
-
-_AddDirToPythonPath(_CATAPULT_DIR, 'common', 'battor')
diff --git a/third_party/catapult/devil/devil/utils/battor_device_mapping.py b/third_party/catapult/devil/devil/utils/battor_device_mapping.py
deleted file mode 100755
index 8cabb8304e..0000000000
--- a/third_party/catapult/devil/devil/utils/battor_device_mapping.py
+++ /dev/null
@@ -1,309 +0,0 @@
-#!/usr/bin/python
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-
-'''
-This script provides tools to map BattOrs to phones.
-
-Phones are identified by the following string:
-
-"Phone serial number" - Serial number of the phone. This can be
-obtained via 'adb devices' or 'usb-devices', and is not expected
-to change for a given phone.
-
-BattOrs are identified by the following two strings:
-
-"BattOr serial number" - Serial number of the BattOr. This can be
-obtained via 'usb-devices', and is not expected to change for
-a given BattOr.
-
-"BattOr path" - The path of the form '/dev/ttyUSB*' that is used
-to communicate with the BattOr (the battor_agent binary takes
-this BattOr path as a parameter). The BattOr path is frequently
-reassigned by the OS, most often when the device is disconnected
-and then reconnected. Thus, the BattOr path cannot be expected
-to be stable.
-
-In a typical application, the user will require the BattOr path
-for the BattOr that is plugged into a given phone. For instance,
-the user will be running tracing on a particular phone, and will
-need to know which BattOr path to use to communicate with the BattOr
-to get the corresponding power trace.
-
-Getting this mapping requires two steps: (1) determining the
-mapping between phone serial numbers and BattOr serial numbers, and
-(2) getting the BattOr path corresponding to a given BattOr serial
-number.
-
-For step (1), we generate a JSON file giving this mapping. This
-JSON file consists of a list of items of the following form:
-[{'phone': <phone serial 1>, 'battor': <battor serial 1>},
-{'phone': <phone serial 2>, 'battor': <battor serial 2>}, ...]
-
-The default way to generate this JSON file is using the function
-GenerateSerialMapFile, which generates a mapping based on assuming
-that the system has two identical USB hubs connected to it, and
-the phone plugged into physical port number 1 on one hub corresponds
-to the BattOr plugged into physical port number 1 on the other hub,
-and similarly with physical port numbers 2, 3, etc. This generates
-the map file based on the structure at the time GenerateSerialMapFile called.
-Note that after the map file is generated, port numbers are no longer used;
-the user could move around the devices in the ports without affecting
-which phone goes with which BattOr. (Thus, if the user wanted to update the
-mapping to match the new port connections, the user would have to
-re-generate this file.)
-
-The script update_mapping.py will do this updating from the command line.
-
-If the user wanted to specify a custom mapping, the user could instead
-create the JSON file manually. (In this case, hubs would not be necessary
-and the physical ports connected would be irrelevant.)
-
-Step (2) is conducted through the function GetBattOrPathFromPhoneSerial,
-which takes a serial number mapping generated via step (1) and a phone
-serial number, then gets the corresponding BattOr serial number from the
-map and determines its BattOr path (e.g. /dev/ttyUSB0). Since BattOr paths
-can change if devices are connected and disconnected (even if connected
-or disconnected via the same port) this function should be called to
-determine the BattOr path every time before connecting to the BattOr.
-
-Note that if there is only one BattOr connected to the system, then
-GetBattOrPathFromPhoneSerial will always return that BattOr and will ignore
-the mapping file. Thus, if the user never has more than one BattOr connected
-to the system, the user will not need to generate mapping files.
-'''
-
-
-import json
-import collections
-
-from battor import battor_error
-from devil.utils import find_usb_devices
-from devil.utils import usb_hubs
-
-
-def GetBattOrList(device_tree_map):
- return [x for x in find_usb_devices.GetTTYList()
- if IsBattOr(x, device_tree_map)]
-
-
-def IsBattOr(tty_string, device_tree_map):
- (bus, device) = find_usb_devices.GetBusDeviceFromTTY(tty_string)
- node = device_tree_map[bus].FindDeviceNumber(device)
- return '0403:6001' in node.desc
-
-
-def GetBattOrSerialNumbers(device_tree_map):
- for x in find_usb_devices.GetTTYList():
- if IsBattOr(x, device_tree_map):
- (bus, device) = find_usb_devices.GetBusDeviceFromTTY(x)
- devnode = device_tree_map[bus].FindDeviceNumber(device)
- yield devnode.serial
-
-
-def ReadSerialMapFile(filename):
- """Reads JSON file giving phone-to-battor serial number map.
-
- Parses a JSON file consisting of a list of items of the following form:
- [{'phone': <phone serial 1>, 'battor': <battor serial 1>},
- {'phone': <phone serial 2>, 'battor': <battor serial 2>}, ...]
-
- indicating which phone serial numbers should be matched with
- which BattOr serial numbers. Returns dictionary of the form:
-
- {<phone serial 1>: <BattOr serial 1>,
- <phone serial 2>: <BattOr serial 2>}
-
- Args:
- filename: Name of file to read.
- """
- result = {}
- with open(filename, 'r') as infile:
- in_dict = json.load(infile)
- for x in in_dict:
- result[x['phone']] = x['battor']
- return result
-
-def WriteSerialMapFile(filename, serial_map):
- """Writes a map of phone serial numbers to BattOr serial numbers to file.
-
- Writes a JSON file consisting of a list of items of the following form:
- [{'phone': <phone serial 1>, 'battor': <battor serial 1>},
- {'phone': <phone serial 2>, 'battor': <battor serial 2>}, ...]
-
- indicating which phone serial numbers should be matched with
- which BattOr serial numbers. Mapping is based on the physical port numbers
- of the hubs that the BattOrs and phones are connected to.
-
- Args:
- filename: Name of file to write.
- serial_map: Serial map {phone: battor}
- """
- result = []
- for (phone, battor) in serial_map.iteritems():
- result.append({'phone': phone, 'battor': battor})
- with open(filename, 'w') as outfile:
- json.dump(result, outfile)
-
-def GenerateSerialMap(hub_types=None):
- """Generates a map of phone serial numbers to BattOr serial numbers.
-
- Generates a dict of:
- {<phone serial 1>: <battor serial 1>,
- <phone serial 2>: <battor serial 2>}
- indicating which phone serial numbers should be matched with
- which BattOr serial numbers. Mapping is based on the physical port numbers
- of the hubs that the BattOrs and phones are connected to.
-
- Args:
- hub_types: List of hub types to check for. If not specified, checks
- for all defined hub types. (see usb_hubs.py for details)
- """
- if hub_types:
- hub_types = [usb_hubs.GetHubType(x) for x in hub_types]
- else:
- hub_types = usb_hubs.ALL_HUBS
-
- devtree = find_usb_devices.GetBusNumberToDeviceTreeMap()
-
- # List of serial numbers in the system that represent BattOrs.
- battor_serials = list(GetBattOrSerialNumbers(devtree))
-
- # If there's only one BattOr in the system, then a serial number ma
- # is not necessary.
- if len(battor_serials) == 1:
- return {}
-
- # List of dictionaries, one for each hub, that maps the physical
- # port number to the serial number of that hub. For instance, in a 2
- # hub system, this could return [{1:'ab', 2:'cd'}, {1:'jkl', 2:'xyz'}]
- # where 'ab' and 'cd' are the phone serial numbers and 'jkl' and 'xyz'
- # are the BattOr serial numbers.
- port_to_serial = find_usb_devices.GetAllPhysicalPortToSerialMaps(
- hub_types, device_tree_map=devtree)
-
- class serials(object):
- def __init__(self):
- self.phone = None
- self.battor = None
-
- # Map of {physical port number: [phone serial #, BattOr serial #]. This
- # map is populated by executing the code below. For instance, in the above
- # example, after the code below is executed, port_to_devices would equal
- # {1: ['ab', 'jkl'], 2: ['cd', 'xyz']}
- port_to_devices = collections.defaultdict(serials)
- for hub in port_to_serial:
- for (port, serial) in hub.iteritems():
- if serial in battor_serials:
- if port_to_devices[port].battor is not None:
- raise battor_error.BattOrError('Multiple BattOrs on same port number')
- else:
- port_to_devices[port].battor = serial
- else:
- if port_to_devices[port].phone is not None:
- raise battor_error.BattOrError('Multiple phones on same port number')
- else:
- port_to_devices[port].phone = serial
-
- # Turn the port_to_devices map into a map of the form
- # {phone serial number: BattOr serial number}.
- result = {}
- for pair in port_to_devices.values():
- if pair.phone is None:
- continue
- if pair.battor is None:
- raise battor_error.BattOrError(
- 'Phone detected with no corresponding BattOr')
- result[pair.phone] = pair.battor
- return result
-
-def GenerateSerialMapFile(filename, hub_types=None):
- """Generates a serial map file and writes it."""
- WriteSerialMapFile(filename, GenerateSerialMap(hub_types))
-
-def _PhoneToPathMap(serial, serial_map, devtree):
- """Maps phone serial number to TTY path, assuming serial map is provided."""
- try:
- battor_serial = serial_map[serial]
- except KeyError:
- raise battor_error.BattOrError('Serial number not found in serial map.')
- for tree in devtree.values():
- for node in tree.AllNodes():
- if isinstance(node, find_usb_devices.USBDeviceNode):
- if node.serial == battor_serial:
- bus_device_to_tty = find_usb_devices.GetBusDeviceToTTYMap()
- bus_device = (node.bus_num, node.device_num)
- try:
- return bus_device_to_tty[bus_device]
- except KeyError:
- raise battor_error.BattOrError(
- 'Device with given serial number not a BattOr '
- '(does not have TTY path)')
-
-
-def GetBattOrPathFromPhoneSerial(serial, serial_map=None,
- serial_map_file=None):
- """Gets the TTY path (e.g. '/dev/ttyUSB0') to communicate with the BattOr.
-
- (1) If serial_map is given, it is treated as a dictionary mapping
- phone serial numbers to BattOr serial numbers. This function will get the
- TTY path for the given BattOr serial number.
-
- (2) If serial_map_file is given, it is treated as the name of a
- phone-to-BattOr mapping file (generated with GenerateSerialMapFile)
- and this will be loaded and used as the dict to map port numbers to
- BattOr serial numbers.
-
- You can only give one of serial_map and serial_map_file.
-
- Args:
- serial: Serial number of phone connected on the same physical port that
- the BattOr is connected to.
- serial_map: Map of phone serial numbers to BattOr serial numbers, given
- as a dictionary.
- serial_map_file: Map of phone serial numbers to BattOr serial numbers,
- given as a file.
- hub_types: List of hub types to check for. Used only if serial_map_file
- is None.
-
- Returns:
- Device string used to communicate with device.
-
- Raises:
- ValueError: If serial number is not given.
- BattOrError: If BattOr not found or unexpected USB topology.
- """
- # If there's only one BattOr connected to the system, just use that one.
- # This allows for use on, e.g., a developer's workstation with no hubs.
- devtree = find_usb_devices.GetBusNumberToDeviceTreeMap()
- all_battors = GetBattOrList(devtree)
- if len(all_battors) == 1:
- return '/dev/' + all_battors[0]
-
- if not serial:
- raise battor_error.BattOrError(
- 'Two or more BattOrs connected, no serial provided')
-
- if serial_map and serial_map_file:
- raise ValueError('Cannot specify both serial_map and serial_map_file')
-
- if serial_map_file:
- serial_map = ReadSerialMapFile(serial_map_file)
-
- tty_string = _PhoneToPathMap(serial, serial_map, devtree)
-
- if not tty_string:
- raise battor_error.BattOrError(
- 'No device with given serial number detected.')
-
- if IsBattOr(tty_string, devtree):
- return '/dev/' + tty_string
- else:
- raise battor_error.BattOrError(
- 'Device with given serial number is not a BattOr.')
-
-if __name__ == '__main__':
- # Main function for testing purposes
- print GenerateSerialMap()
diff --git a/third_party/catapult/devil/devil/utils/cmd_helper.py b/third_party/catapult/devil/devil/utils/cmd_helper.py
deleted file mode 100644
index 06c105fcc5..0000000000
--- a/third_party/catapult/devil/devil/utils/cmd_helper.py
+++ /dev/null
@@ -1,394 +0,0 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""A wrapper for subprocess to make calling shell commands easier."""
-
-import logging
-import os
-import pipes
-import select
-import signal
-import string
-import StringIO
-import subprocess
-import sys
-import time
-
-# fcntl is not available on Windows.
-try:
- import fcntl
-except ImportError:
- fcntl = None
-
-logger = logging.getLogger(__name__)
-
-_SafeShellChars = frozenset(string.ascii_letters + string.digits + '@%_-+=:,./')
-
-
-def SingleQuote(s):
- """Return an shell-escaped version of the string using single quotes.
-
- Reliably quote a string which may contain unsafe characters (e.g. space,
- quote, or other special characters such as '$').
-
- The returned value can be used in a shell command line as one token that gets
- to be interpreted literally.
-
- Args:
- s: The string to quote.
-
- Return:
- The string quoted using single quotes.
- """
- return pipes.quote(s)
-
-
-def DoubleQuote(s):
- """Return an shell-escaped version of the string using double quotes.
-
- Reliably quote a string which may contain unsafe characters (e.g. space
- or quote characters), while retaining some shell features such as variable
- interpolation.
-
- The returned value can be used in a shell command line as one token that gets
- to be further interpreted by the shell.
-
- The set of characters that retain their special meaning may depend on the
- shell implementation. This set usually includes: '$', '`', '\', '!', '*',
- and '@'.
-
- Args:
- s: The string to quote.
-
- Return:
- The string quoted using double quotes.
- """
- if not s:
- return '""'
- elif all(c in _SafeShellChars for c in s):
- return s
- else:
- return '"' + s.replace('"', '\\"') + '"'
-
-
-def ShrinkToSnippet(cmd_parts, var_name, var_value):
- """Constructs a shell snippet for a command using a variable to shrink it.
-
- Takes into account all quoting that needs to happen.
-
- Args:
- cmd_parts: A list of command arguments.
- var_name: The variable that holds var_value.
- var_value: The string to replace in cmd_parts with $var_name
-
- Returns:
- A shell snippet that does not include setting the variable.
- """
- def shrink(value):
- parts = (x and SingleQuote(x) for x in value.split(var_value))
- with_substitutions = ('"$%s"' % var_name).join(parts)
- return with_substitutions or "''"
-
- return ' '.join(shrink(part) for part in cmd_parts)
-
-
-def Popen(args, stdout=None, stderr=None, shell=None, cwd=None, env=None):
- # preexec_fn isn't supported on windows.
- if sys.platform == 'win32':
- preexec_fn = None
- else:
- preexec_fn = lambda: signal.signal(signal.SIGPIPE, signal.SIG_DFL)
-
- return subprocess.Popen(
- args=args, cwd=cwd, stdout=stdout, stderr=stderr,
- shell=shell, close_fds=True, env=env, preexec_fn=preexec_fn)
-
-
-def Call(args, stdout=None, stderr=None, shell=None, cwd=None, env=None):
- pipe = Popen(args, stdout=stdout, stderr=stderr, shell=shell, cwd=cwd,
- env=env)
- pipe.communicate()
- return pipe.wait()
-
-
-def RunCmd(args, cwd=None):
- """Opens a subprocess to execute a program and returns its return value.
-
- Args:
- args: A string or a sequence of program arguments. The program to execute is
- the string or the first item in the args sequence.
- cwd: If not None, the subprocess's current directory will be changed to
- |cwd| before it's executed.
-
- Returns:
- Return code from the command execution.
- """
- logger.info(str(args) + ' ' + (cwd or ''))
- return Call(args, cwd=cwd)
-
-
-def GetCmdOutput(args, cwd=None, shell=False):
- """Open a subprocess to execute a program and returns its output.
-
- Args:
- args: A string or a sequence of program arguments. The program to execute is
- the string or the first item in the args sequence.
- cwd: If not None, the subprocess's current directory will be changed to
- |cwd| before it's executed.
- shell: Whether to execute args as a shell command.
-
- Returns:
- Captures and returns the command's stdout.
- Prints the command's stderr to logger (which defaults to stdout).
- """
- (_, output) = GetCmdStatusAndOutput(args, cwd, shell)
- return output
-
-
-def _ValidateAndLogCommand(args, cwd, shell):
- if isinstance(args, basestring):
- if not shell:
- raise Exception('string args must be run with shell=True')
- else:
- if shell:
- raise Exception('array args must be run with shell=False')
- args = ' '.join(SingleQuote(c) for c in args)
- if cwd is None:
- cwd = ''
- else:
- cwd = ':' + cwd
- logger.info('[host]%s> %s', cwd, args)
- return args
-
-
-def GetCmdStatusAndOutput(args, cwd=None, shell=False):
- """Executes a subprocess and returns its exit code and output.
-
- Args:
- args: A string or a sequence of program arguments. The program to execute is
- the string or the first item in the args sequence.
- cwd: If not None, the subprocess's current directory will be changed to
- |cwd| before it's executed.
- shell: Whether to execute args as a shell command. Must be True if args
- is a string and False if args is a sequence.
-
- Returns:
- The 2-tuple (exit code, output).
- """
- status, stdout, stderr = GetCmdStatusOutputAndError(
- args, cwd=cwd, shell=shell)
-
- if stderr:
- logger.critical('STDERR: %s', stderr)
- logger.debug('STDOUT: %s%s', stdout[:4096].rstrip(),
- '<truncated>' if len(stdout) > 4096 else '')
- return (status, stdout)
-
-
-def GetCmdStatusOutputAndError(args, cwd=None, shell=False):
- """Executes a subprocess and returns its exit code, output, and errors.
-
- Args:
- args: A string or a sequence of program arguments. The program to execute is
- the string or the first item in the args sequence.
- cwd: If not None, the subprocess's current directory will be changed to
- |cwd| before it's executed.
- shell: Whether to execute args as a shell command. Must be True if args
- is a string and False if args is a sequence.
-
- Returns:
- The 2-tuple (exit code, output).
- """
- _ValidateAndLogCommand(args, cwd, shell)
- pipe = Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
- shell=shell, cwd=cwd)
- stdout, stderr = pipe.communicate()
- return (pipe.returncode, stdout, stderr)
-
-
-class TimeoutError(Exception):
- """Module-specific timeout exception."""
-
- def __init__(self, output=None):
- super(TimeoutError, self).__init__()
- self._output = output
-
- @property
- def output(self):
- return self._output
-
-
-def _IterProcessStdout(process, iter_timeout=None, timeout=None,
- buffer_size=4096, poll_interval=1):
- """Iterate over a process's stdout.
-
- This is intentionally not public.
-
- Args:
- process: The process in question.
- iter_timeout: An optional length of time, in seconds, to wait in
- between each iteration. If no output is received in the given
- time, this generator will yield None.
- timeout: An optional length of time, in seconds, during which
- the process must finish. If it fails to do so, a TimeoutError
- will be raised.
- buffer_size: The maximum number of bytes to read (and thus yield) at once.
- poll_interval: The length of time to wait in calls to `select.select`.
- If iter_timeout is set, the remaining length of time in the iteration
- may take precedence.
- Raises:
- TimeoutError: if timeout is set and the process does not complete.
- Yields:
- basestrings of data or None.
- """
-
- assert fcntl, 'fcntl module is required'
- try:
- # Enable non-blocking reads from the child's stdout.
- child_fd = process.stdout.fileno()
- fl = fcntl.fcntl(child_fd, fcntl.F_GETFL)
- fcntl.fcntl(child_fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
-
- end_time = (time.time() + timeout) if timeout else None
- iter_end_time = (time.time() + iter_timeout) if iter_timeout else None
-
- while True:
- if end_time and time.time() > end_time:
- raise TimeoutError()
- if iter_end_time and time.time() > iter_end_time:
- yield None
- iter_end_time = time.time() + iter_timeout
-
- if iter_end_time:
- iter_aware_poll_interval = min(
- poll_interval,
- max(0, iter_end_time - time.time()))
- else:
- iter_aware_poll_interval = poll_interval
-
- read_fds, _, _ = select.select(
- [child_fd], [], [], iter_aware_poll_interval)
- if child_fd in read_fds:
- data = os.read(child_fd, buffer_size)
- if not data:
- break
- yield data
- if process.poll() is not None:
- break
- finally:
- try:
- if process.returncode is None:
- # Make sure the process doesn't stick around if we fail with an
- # exception.
- process.kill()
- except OSError:
- pass
- process.wait()
-
-
-def GetCmdStatusAndOutputWithTimeout(args, timeout, cwd=None, shell=False,
- logfile=None):
- """Executes a subprocess with a timeout.
-
- Args:
- args: List of arguments to the program, the program to execute is the first
- element.
- timeout: the timeout in seconds or None to wait forever.
- cwd: If not None, the subprocess's current directory will be changed to
- |cwd| before it's executed.
- shell: Whether to execute args as a shell command. Must be True if args
- is a string and False if args is a sequence.
- logfile: Optional file-like object that will receive output from the
- command as it is running.
-
- Returns:
- The 2-tuple (exit code, output).
- Raises:
- TimeoutError on timeout.
- """
- _ValidateAndLogCommand(args, cwd, shell)
- output = StringIO.StringIO()
- process = Popen(args, cwd=cwd, shell=shell, stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
- try:
- for data in _IterProcessStdout(process, timeout=timeout):
- if logfile:
- logfile.write(data)
- output.write(data)
- except TimeoutError:
- raise TimeoutError(output.getvalue())
-
- str_output = output.getvalue()
- logger.debug('STDOUT+STDERR: %s%s', str_output[:4096].rstrip(),
- '<truncated>' if len(str_output) > 4096 else '')
- return process.returncode, str_output
-
-
-def IterCmdOutputLines(args, iter_timeout=None, timeout=None, cwd=None,
- shell=False, check_status=True):
- """Executes a subprocess and continuously yields lines from its output.
-
- Args:
- args: List of arguments to the program, the program to execute is the first
- element.
- iter_timeout: Timeout for each iteration, in seconds.
- timeout: Timeout for the entire command, in seconds.
- cwd: If not None, the subprocess's current directory will be changed to
- |cwd| before it's executed.
- shell: Whether to execute args as a shell command. Must be True if args
- is a string and False if args is a sequence.
- check_status: A boolean indicating whether to check the exit status of the
- process after all output has been read.
- Yields:
- The output of the subprocess, line by line.
-
- Raises:
- CalledProcessError if check_status is True and the process exited with a
- non-zero exit status.
- """
- cmd = _ValidateAndLogCommand(args, cwd, shell)
- process = Popen(args, cwd=cwd, shell=shell, stdout=subprocess.PIPE,
- stderr=subprocess.STDOUT)
- return _IterCmdOutputLines(
- process, cmd, iter_timeout=iter_timeout, timeout=timeout,
- check_status=check_status)
-
-def _IterCmdOutputLines(process, cmd, iter_timeout=None, timeout=None,
- check_status=True):
- buffer_output = ''
-
- iter_end = None
- cur_iter_timeout = None
- if iter_timeout:
- iter_end = time.time() + iter_timeout
- cur_iter_timeout = iter_timeout
-
- for data in _IterProcessStdout(process, iter_timeout=cur_iter_timeout,
- timeout=timeout):
- if iter_timeout:
- # Check whether the current iteration has timed out.
- cur_iter_timeout = iter_end - time.time()
- if data is None or cur_iter_timeout < 0:
- yield None
- iter_end = time.time() + iter_timeout
- continue
- else:
- assert data is not None, (
- 'Iteration received no data despite no iter_timeout being set. '
- 'cmd: %s' % cmd)
-
- # Construct lines to yield from raw data.
- buffer_output += data
- has_incomplete_line = buffer_output[-1] not in '\r\n'
- lines = buffer_output.splitlines()
- buffer_output = lines.pop() if has_incomplete_line else ''
- for line in lines:
- yield line
- if iter_timeout:
- iter_end = time.time() + iter_timeout
-
- if buffer_output:
- yield buffer_output
- if check_status and process.returncode:
- raise subprocess.CalledProcessError(process.returncode, cmd)
diff --git a/third_party/catapult/devil/devil/utils/cmd_helper_test.py b/third_party/catapult/devil/devil/utils/cmd_helper_test.py
deleted file mode 100755
index 783c4137c8..0000000000
--- a/third_party/catapult/devil/devil/utils/cmd_helper_test.py
+++ /dev/null
@@ -1,262 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Tests for the cmd_helper module."""
-
-import unittest
-import subprocess
-import time
-
-from devil import devil_env
-from devil.utils import cmd_helper
-
-with devil_env.SysPath(devil_env.PYMOCK_PATH):
- import mock # pylint: disable=import-error
-
-
-class CmdHelperSingleQuoteTest(unittest.TestCase):
-
- def testSingleQuote_basic(self):
- self.assertEquals('hello',
- cmd_helper.SingleQuote('hello'))
-
- def testSingleQuote_withSpaces(self):
- self.assertEquals("'hello world'",
- cmd_helper.SingleQuote('hello world'))
-
- def testSingleQuote_withUnsafeChars(self):
- self.assertEquals("""'hello'"'"'; rm -rf /'""",
- cmd_helper.SingleQuote("hello'; rm -rf /"))
-
- def testSingleQuote_dontExpand(self):
- test_string = 'hello $TEST_VAR'
- cmd = 'TEST_VAR=world; echo %s' % cmd_helper.SingleQuote(test_string)
- self.assertEquals(test_string,
- cmd_helper.GetCmdOutput(cmd, shell=True).rstrip())
-
-
-class CmdHelperDoubleQuoteTest(unittest.TestCase):
-
- def testDoubleQuote_basic(self):
- self.assertEquals('hello',
- cmd_helper.DoubleQuote('hello'))
-
- def testDoubleQuote_withSpaces(self):
- self.assertEquals('"hello world"',
- cmd_helper.DoubleQuote('hello world'))
-
- def testDoubleQuote_withUnsafeChars(self):
- self.assertEquals('''"hello\\"; rm -rf /"''',
- cmd_helper.DoubleQuote('hello"; rm -rf /'))
-
- def testSingleQuote_doExpand(self):
- test_string = 'hello $TEST_VAR'
- cmd = 'TEST_VAR=world; echo %s' % cmd_helper.DoubleQuote(test_string)
- self.assertEquals('hello world',
- cmd_helper.GetCmdOutput(cmd, shell=True).rstrip())
-
-
-class CmdHelperShinkToSnippetTest(unittest.TestCase):
-
- def testShrinkToSnippet_noArgs(self):
- self.assertEquals('foo',
- cmd_helper.ShrinkToSnippet(['foo'], 'a', 'bar'))
- self.assertEquals("'foo foo'",
- cmd_helper.ShrinkToSnippet(['foo foo'], 'a', 'bar'))
- self.assertEquals('"$a"\' bar\'',
- cmd_helper.ShrinkToSnippet(['foo bar'], 'a', 'foo'))
- self.assertEquals('\'foo \'"$a"',
- cmd_helper.ShrinkToSnippet(['foo bar'], 'a', 'bar'))
- self.assertEquals('foo"$a"',
- cmd_helper.ShrinkToSnippet(['foobar'], 'a', 'bar'))
-
- def testShrinkToSnippet_singleArg(self):
- self.assertEquals("foo ''",
- cmd_helper.ShrinkToSnippet(['foo', ''], 'a', 'bar'))
- self.assertEquals("foo foo",
- cmd_helper.ShrinkToSnippet(['foo', 'foo'], 'a', 'bar'))
- self.assertEquals('"$a" "$a"',
- cmd_helper.ShrinkToSnippet(['foo', 'foo'], 'a', 'foo'))
- self.assertEquals('foo "$a""$a"',
- cmd_helper.ShrinkToSnippet(['foo', 'barbar'], 'a', 'bar'))
- self.assertEquals('foo "$a"\' \'"$a"',
- cmd_helper.ShrinkToSnippet(['foo', 'bar bar'], 'a', 'bar'))
- self.assertEquals('foo "$a""$a"\' \'',
- cmd_helper.ShrinkToSnippet(['foo', 'barbar '], 'a', 'bar'))
- self.assertEquals('foo \' \'"$a""$a"\' \'',
- cmd_helper.ShrinkToSnippet(['foo', ' barbar '], 'a', 'bar'))
-
-
-_DEFAULT = 'DEFAULT'
-
-
-class _ProcessOutputEvent(object):
-
- def __init__(self, select_fds=_DEFAULT, read_contents=None, ts=_DEFAULT):
- self.select_fds = select_fds
- self.read_contents = read_contents
- self.ts = ts
-
-
-class _MockProcess(object):
-
- def __init__(self, output_sequence=None, return_value=0):
-
- # Arbitrary.
- fake_stdout_fileno = 25
-
- self.mock_proc = mock.MagicMock(spec=subprocess.Popen)
- self.mock_proc.stdout = mock.MagicMock()
- self.mock_proc.stdout.fileno = mock.MagicMock(
- return_value=fake_stdout_fileno)
- self.mock_proc.returncode = None
-
- self._return_value = return_value
-
- # This links the behavior of os.read, select.select, time.time, and
- # <process>.poll. The output sequence can be thought of as a list of
- # return values for select.select with corresponding return values for
- # the other calls at any time between that select call and the following
- # one. We iterate through the sequence only on calls to select.select.
- #
- # os.read is a special case, though, where we only return a given chunk
- # of data *once* after a given call to select.
-
- if not output_sequence:
- output_sequence = []
-
- # Use an leading element to make the iteration logic work.
- initial_seq_element = _ProcessOutputEvent(
- _DEFAULT, '',
- output_sequence[0].ts if output_sequence else _DEFAULT)
- output_sequence.insert(0, initial_seq_element)
-
- for o in output_sequence:
- if o.select_fds == _DEFAULT:
- if o.read_contents is None:
- o.select_fds = []
- else:
- o.select_fds = [fake_stdout_fileno]
- if o.ts == _DEFAULT:
- o.ts = time.time()
- self._output_sequence = output_sequence
-
- self._output_seq_index = 0
- self._read_flags = [False] * len(output_sequence)
-
- def read_side_effect(*_args, **_kwargs):
- if self._read_flags[self._output_seq_index]:
- return None
- self._read_flags[self._output_seq_index] = True
- return self._output_sequence[self._output_seq_index].read_contents
-
- def select_side_effect(*_args, **_kwargs):
- if self._output_seq_index is None:
- self._output_seq_index = 0
- else:
- self._output_seq_index += 1
- return (self._output_sequence[self._output_seq_index].select_fds,
- None, None)
-
- def time_side_effect(*_args, **_kwargs):
- return self._output_sequence[self._output_seq_index].ts
-
- def poll_side_effect(*_args, **_kwargs):
- if self._output_seq_index >= len(self._output_sequence) - 1:
- self.mock_proc.returncode = self._return_value
- return self.mock_proc.returncode
-
- mock_read = mock.MagicMock(side_effect=read_side_effect)
- mock_select = mock.MagicMock(side_effect=select_side_effect)
- mock_time = mock.MagicMock(side_effect=time_side_effect)
- self.mock_proc.poll = mock.MagicMock(side_effect=poll_side_effect)
-
- # Set up but *do not start* the mocks.
- self._mocks = [
- mock.patch('fcntl.fcntl'),
- mock.patch('os.read', new=mock_read),
- mock.patch('select.select', new=mock_select),
- mock.patch('time.time', new=mock_time),
- ]
-
- def __enter__(self):
- for m in self._mocks:
- m.__enter__()
- return self.mock_proc
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- for m in reversed(self._mocks):
- m.__exit__(exc_type, exc_val, exc_tb)
-
-
-class CmdHelperIterCmdOutputLinesTest(unittest.TestCase):
- """Test IterCmdOutputLines with some calls to the unix 'seq' command."""
-
- # This calls _IterCmdOutputLines rather than IterCmdOutputLines s.t. it
- # can mock the process.
- # pylint: disable=protected-access
-
- _SIMPLE_OUTPUT_SEQUENCE = [
- _ProcessOutputEvent(read_contents='1\n2\n'),
- ]
-
- def testIterCmdOutputLines_success(self):
- with _MockProcess(
- output_sequence=self._SIMPLE_OUTPUT_SEQUENCE) as mock_proc:
- for num, line in enumerate(
- cmd_helper._IterCmdOutputLines(mock_proc, 'mock_proc'), 1):
- self.assertEquals(num, int(line))
-
- def testIterCmdOutputLines_exitStatusFail(self):
- with self.assertRaises(subprocess.CalledProcessError):
- with _MockProcess(output_sequence=self._SIMPLE_OUTPUT_SEQUENCE,
- return_value=1) as mock_proc:
- for num, line in enumerate(
- cmd_helper._IterCmdOutputLines(mock_proc, 'mock_proc'), 1):
- self.assertEquals(num, int(line))
- # after reading all the output we get an exit status of 1
-
- def testIterCmdOutputLines_exitStatusIgnored(self):
- with _MockProcess(output_sequence=self._SIMPLE_OUTPUT_SEQUENCE,
- return_value=1) as mock_proc:
- for num, line in enumerate(
- cmd_helper._IterCmdOutputLines(
- mock_proc, 'mock_proc', check_status=False),
- 1):
- self.assertEquals(num, int(line))
-
- def testIterCmdOutputLines_exitStatusSkipped(self):
- with _MockProcess(output_sequence=self._SIMPLE_OUTPUT_SEQUENCE,
- return_value=1) as mock_proc:
- for num, line in enumerate(
- cmd_helper._IterCmdOutputLines(mock_proc, 'mock_proc'), 1):
- self.assertEquals(num, int(line))
- # no exception will be raised because we don't attempt to read past
- # the end of the output and, thus, the status never gets checked
- if num == 2:
- break
-
- def testIterCmdOutputLines_delay(self):
- output_sequence = [
- _ProcessOutputEvent(read_contents='1\n2\n', ts=1),
- _ProcessOutputEvent(read_contents=None, ts=2),
- _ProcessOutputEvent(read_contents='Awake', ts=10),
- ]
- with _MockProcess(output_sequence=output_sequence) as mock_proc:
- for num, line in enumerate(
- cmd_helper._IterCmdOutputLines(mock_proc, 'mock_proc',
- iter_timeout=5), 1):
- if num <= 2:
- self.assertEquals(num, int(line))
- elif num == 3:
- self.assertEquals(None, line)
- elif num == 4:
- self.assertEquals('Awake', line)
- else:
- self.fail()
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/third_party/catapult/devil/devil/utils/file_utils.py b/third_party/catapult/devil/devil/utils/file_utils.py
deleted file mode 100644
index dc5a9efc94..0000000000
--- a/third_party/catapult/devil/devil/utils/file_utils.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import os
-
-
-def MergeFiles(dest_file, source_files):
- """Merge list of files into single destination file.
-
- Args:
- dest_file: File to be written to.
- source_files: List of files to be merged. Will be merged in the order they
- appear in the list.
- """
- if not os.path.exists(os.path.dirname(dest_file)):
- os.makedirs(os.path.dirname(dest_file))
- try:
- with open(dest_file, 'w') as dest_f:
- for source_file in source_files:
- with open(source_file, 'r') as source_f:
- dest_f.write(source_f.read())
- except Exception as e: # pylint: disable=broad-except
- # Something went wrong when creating dest_file. Cleaning up.
- try:
- os.remove(dest_file)
- except OSError:
- pass
- raise e
-
-
diff --git a/third_party/catapult/devil/devil/utils/find_usb_devices.py b/third_party/catapult/devil/devil/utils/find_usb_devices.py
deleted file mode 100755
index 0e0f4d5666..0000000000
--- a/third_party/catapult/devil/devil/utils/find_usb_devices.py
+++ /dev/null
@@ -1,532 +0,0 @@
-#!/usr/bin/python
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import re
-import sys
-import argparse
-
-from devil.utils import cmd_helper
-from devil.utils import usb_hubs
-from devil.utils import lsusb
-
-# Note: In the documentation below, "virtual port" refers to the port number
-# as observed by the system (e.g. by usb-devices) and "physical port" refers
-# to the physical numerical label on the physical port e.g. on a USB hub.
-# The mapping between virtual and physical ports is not always the identity
-# (e.g. the port labeled "1" on a USB hub does not always show up as "port 1"
-# when you plug something into it) but, as far as we are aware, the mapping
-# between virtual and physical ports is always the same for a given
-# model of USB hub. When "port number" is referenced without specifying, it
-# means the virtual port number.
-
-
-# Wrapper functions for system commands to get output. These are in wrapper
-# functions so that they can be more easily mocked-out for tests.
-def _GetParsedLSUSBOutput():
- return lsusb.lsusb()
-
-
-def _GetUSBDevicesOutput():
- return cmd_helper.GetCmdOutput(['usb-devices'])
-
-
-def _GetTtyUSBInfo(tty_string):
- cmd = ['udevadm', 'info', '--name=/dev/' + tty_string, '--attribute-walk']
- return cmd_helper.GetCmdOutput(cmd)
-
-
-def _GetCommList():
- return cmd_helper.GetCmdOutput('ls /dev', shell=True)
-
-
-def GetTTYList():
- return [x for x in _GetCommList().splitlines() if 'ttyUSB' in x]
-
-
-# Class to identify nodes in the USB topology. USB topology is organized as
-# a tree.
-class USBNode(object):
- def __init__(self):
- self._port_to_node = {}
-
- @property
- def desc(self):
- raise NotImplementedError
-
- @property
- def info(self):
- raise NotImplementedError
-
- @property
- def device_num(self):
- raise NotImplementedError
-
- @property
- def bus_num(self):
- raise NotImplementedError
-
- def HasPort(self, port):
- """Determines if this device has a device connected to the given port."""
- return port in self._port_to_node
-
- def PortToDevice(self, port):
- """Gets the device connected to the given port on this device."""
- return self._port_to_node[port]
-
- def Display(self, port_chain='', info=False):
- """Displays information about this node and its descendants.
-
- Output format is, e.g. 1:3:3:Device 42 (ID 1234:5678 Some Device)
- meaning that from the bus, if you look at the device connected
- to port 1, then the device connected to port 3 of that,
- then the device connected to port 3 of that, you get the device
- assigned device number 42, which is Some Device. Note that device
- numbers will be reassigned whenever a connected device is powercycled
- or reinserted, but port numbers stay the same as long as the device
- is reinserted back into the same physical port.
-
- Args:
- port_chain: [string] Chain of ports from bus to this node (e.g. '2:4:')
- info: [bool] Whether to display detailed info as well.
- """
- raise NotImplementedError
-
- def AddChild(self, port, device):
- """Adds child to the device tree.
-
- Args:
- port: [int] Port number of the device.
- device: [USBDeviceNode] Device to add.
-
- Raises:
- ValueError: If device already has a child at the given port.
- """
- if self.HasPort(port):
- raise ValueError('Duplicate port number')
- else:
- self._port_to_node[port] = device
-
- def AllNodes(self):
- """Generator that yields this node and all of its descendants.
-
- Yields:
- [USBNode] First this node, then each of its descendants (recursively)
- """
- yield self
- for child_node in self._port_to_node.values():
- for descendant_node in child_node.AllNodes():
- yield descendant_node
-
- def FindDeviceNumber(self, findnum):
- """Find device with given number in tree
-
- Searches the portion of the device tree rooted at this node for
- a device with the given device number.
-
- Args:
- findnum: [int] Device number to search for.
-
- Returns:
- [USBDeviceNode] Node that is found.
- """
- for node in self.AllNodes():
- if node.device_num == findnum:
- return node
- return None
-
-
-class USBDeviceNode(USBNode):
- def __init__(self, bus_num=0, device_num=0, serial=None, info=None):
- """Class that represents a device in USB tree.
-
- Args:
- bus_num: [int] Bus number that this node is attached to.
- device_num: [int] Device number of this device (or 0, if this is a bus)
- serial: [string] Serial number.
- info: [dict] Map giving detailed device info.
- """
- super(USBDeviceNode, self).__init__()
- self._bus_num = bus_num
- self._device_num = device_num
- self._serial = serial
- self._info = {} if info is None else info
-
- #override
- @property
- def desc(self):
- return self._info.get('desc')
-
- #override
- @property
- def info(self):
- return self._info
-
- #override
- @property
- def device_num(self):
- return self._device_num
-
- #override
- @property
- def bus_num(self):
- return self._bus_num
-
- @property
- def serial(self):
- return self._serial
-
- @serial.setter
- def serial(self, serial):
- self._serial = serial
-
- #override
- def Display(self, port_chain='', info=False):
- print '%s Device %d (%s)' % (port_chain, self.device_num, self.desc)
- if info:
- print self.info
- for (port, device) in self._port_to_node.iteritems():
- device.Display('%s%d:' % (port_chain, port), info=info)
-
-
-class USBBusNode(USBNode):
- def __init__(self, bus_num=0):
- """Class that represents a node (either a bus or device) in USB tree.
-
- Args:
- is_bus: [bool] If true, node is bus; if not, node is device.
- bus_num: [int] Bus number that this node is attached to.
- device_num: [int] Device number of this device (or 0, if this is a bus)
- desc: [string] Short description of device.
- serial: [string] Serial number.
- info: [dict] Map giving detailed device info.
- port_to_dev: [dict(int:USBDeviceNode)]
- Maps port # to device connected to port.
- """
- super(USBBusNode, self).__init__()
- self._bus_num = bus_num
-
- #override
- @property
- def desc(self):
- return 'BUS %d' % self._bus_num
-
- #override
- @property
- def info(self):
- return {}
-
- #override
- @property
- def device_num(self):
- return -1
-
- #override
- @property
- def bus_num(self):
- return self._bus_num
-
- #override
- def Display(self, port_chain='', info=False):
- print "=== %s ===" % self.desc
- for (port, device) in self._port_to_node.iteritems():
- device.Display('%s%d:' % (port_chain, port), info=info)
-
-
-_T_LINE_REGEX = re.compile(r'T: Bus=(?P<bus>\d{2}) Lev=(?P<lev>\d{2}) '
- r'Prnt=(?P<prnt>\d{2,3}) Port=(?P<port>\d{2}) '
- r'Cnt=(?P<cnt>\d{2}) Dev#=(?P<dev>.{3}) .*')
-
-_S_LINE_REGEX = re.compile(r'S: SerialNumber=(?P<serial>.*)')
-_LSUSB_BUS_DEVICE_RE = re.compile(r'^Bus (\d{3}) Device (\d{3}): (.*)')
-
-
-def GetBusNumberToDeviceTreeMap(fast=True):
- """Gets devices currently attached.
-
- Args:
- fast [bool]: whether to do it fast (only get description, not
- the whole dictionary, from lsusb)
-
- Returns:
- map of {bus number: bus object}
- where the bus object has all the devices attached to it in a tree.
- """
- if fast:
- info_map = {}
- for line in lsusb.raw_lsusb().splitlines():
- match = _LSUSB_BUS_DEVICE_RE.match(line)
- if match:
- info_map[(int(match.group(1)), int(match.group(2)))] = (
- {'desc':match.group(3)})
- else:
- info_map = {((int(line['bus']), int(line['device']))): line
- for line in _GetParsedLSUSBOutput()}
-
-
- tree = {}
- bus_num = -1
- for line in _GetUSBDevicesOutput().splitlines():
- match = _T_LINE_REGEX.match(line)
- if match:
- bus_num = int(match.group('bus'))
- parent_num = int(match.group('prnt'))
- # usb-devices starts counting ports from 0, so add 1
- port_num = int(match.group('port')) + 1
- device_num = int(match.group('dev'))
-
- # create new bus if necessary
- if bus_num not in tree:
- tree[bus_num] = USBBusNode(bus_num=bus_num)
-
- # create the new device
- new_device = USBDeviceNode(bus_num=bus_num,
- device_num=device_num,
- info=info_map.get((bus_num, device_num),
- {'desc': 'NOT AVAILABLE'}))
-
- # add device to bus
- if parent_num != 0:
- tree[bus_num].FindDeviceNumber(parent_num).AddChild(
- port_num, new_device)
- else:
- tree[bus_num].AddChild(port_num, new_device)
-
- match = _S_LINE_REGEX.match(line)
- if match:
- if bus_num == -1:
- raise ValueError('S line appears before T line in input file')
- # put the serial number in the device
- tree[bus_num].FindDeviceNumber(device_num).serial = match.group('serial')
-
- return tree
-
-
-def GetHubsOnBus(bus, hub_types):
- """Scans for all hubs on a bus of given hub types.
-
- Args:
- bus: [USBNode] Bus object.
- hub_types: [iterable(usb_hubs.HubType)] Possible types of hubs.
-
- Yields:
- Sequence of tuples representing (hub, type of hub)
- """
- for device in bus.AllNodes():
- for hub_type in hub_types:
- if hub_type.IsType(device):
- yield (device, hub_type)
-
-
-def GetPhysicalPortToNodeMap(hub, hub_type):
- """Gets physical-port:node mapping for a given hub.
- Args:
- hub: [USBNode] Hub to get map for.
- hub_type: [usb_hubs.HubType] Which type of hub it is.
-
- Returns:
- Dict of {physical port: node}
- """
- port_device = hub_type.GetPhysicalPortToNodeTuples(hub)
- return {port: device for (port, device) in port_device}
-
-
-def GetPhysicalPortToBusDeviceMap(hub, hub_type):
- """Gets physical-port:(bus#, device#) mapping for a given hub.
- Args:
- hub: [USBNode] Hub to get map for.
- hub_type: [usb_hubs.HubType] Which type of hub it is.
-
- Returns:
- Dict of {physical port: (bus number, device number)}
- """
- port_device = hub_type.GetPhysicalPortToNodeTuples(hub)
- return {port: (device.bus_num, device.device_num)
- for (port, device) in port_device}
-
-
-def GetPhysicalPortToSerialMap(hub, hub_type):
- """Gets physical-port:serial# mapping for a given hub.
-
- Args:
- hub: [USBNode] Hub to get map for.
- hub_type: [usb_hubs.HubType] Which type of hub it is.
-
- Returns:
- Dict of {physical port: serial number)}
- """
- port_device = hub_type.GetPhysicalPortToNodeTuples(hub)
- return {port: device.serial
- for (port, device) in port_device
- if device.serial}
-
-
-def GetPhysicalPortToTTYMap(device, hub_type):
- """Gets physical-port:tty-string mapping for a given hub.
- Args:
- hub: [USBNode] Hub to get map for.
- hub_type: [usb_hubs.HubType] Which type of hub it is.
-
- Returns:
- Dict of {physical port: tty-string)}
- """
- port_device = hub_type.GetPhysicalPortToNodeTuples(device)
- bus_device_to_tty = GetBusDeviceToTTYMap()
- return {port: bus_device_to_tty[(device.bus_num, device.device_num)]
- for (port, device) in port_device
- if (device.bus_num, device.device_num) in bus_device_to_tty}
-
-
-def CollectHubMaps(hub_types, map_func, device_tree_map=None, fast=False):
- """Runs a function on all hubs in the system and collects their output.
-
- Args:
- hub_types: [usb_hubs.HubType] List of possible hub types.
- map_func: [string] Function to run on each hub.
- device_tree: Previously constructed device tree map, if any.
- fast: Whether to construct device tree fast, if not already provided
-
- Yields:
- Sequence of dicts of {physical port: device} where the type of
- device depends on the ident keyword. Each dict is a separate hub.
- """
- if device_tree_map is None:
- device_tree_map = GetBusNumberToDeviceTreeMap(fast=fast)
- for bus in device_tree_map.values():
- for (hub, hub_type) in GetHubsOnBus(bus, hub_types):
- yield map_func(hub, hub_type)
-
-
-def GetAllPhysicalPortToNodeMaps(hub_types, **kwargs):
- return CollectHubMaps(hub_types, GetPhysicalPortToNodeMap, **kwargs)
-
-
-def GetAllPhysicalPortToBusDeviceMaps(hub_types, **kwargs):
- return CollectHubMaps(hub_types, GetPhysicalPortToBusDeviceMap, **kwargs)
-
-
-def GetAllPhysicalPortToSerialMaps(hub_types, **kwargs):
- return CollectHubMaps(hub_types, GetPhysicalPortToSerialMap, **kwargs)
-
-
-def GetAllPhysicalPortToTTYMaps(hub_types, **kwargs):
- return CollectHubMaps(hub_types, GetPhysicalPortToTTYMap, **kwargs)
-
-
-_BUS_NUM_REGEX = re.compile(r'.*ATTRS{busnum}=="(\d*)".*')
-_DEVICE_NUM_REGEX = re.compile(r'.*ATTRS{devnum}=="(\d*)".*')
-
-
-def GetBusDeviceFromTTY(tty_string):
- """Gets bus and device number connected to a ttyUSB port.
-
- Args:
- tty_string: [String] Identifier for ttyUSB (e.g. 'ttyUSB0')
-
- Returns:
- Tuple (bus, device) giving device connected to that ttyUSB.
-
- Raises:
- ValueError: If bus and device information could not be found.
- """
- bus_num = None
- device_num = None
- # Expected output of GetCmdOutput should be something like:
- # looking at device /devices/something/.../.../...
- # KERNELS="ttyUSB0"
- # SUBSYSTEMS=...
- # DRIVERS=...
- # ATTRS{foo}=...
- # ATTRS{bar}=...
- # ...
- for line in _GetTtyUSBInfo(tty_string).splitlines():
- bus_match = _BUS_NUM_REGEX.match(line)
- device_match = _DEVICE_NUM_REGEX.match(line)
- if bus_match and bus_num == None:
- bus_num = int(bus_match.group(1))
- if device_match and device_num == None:
- device_num = int(device_match.group(1))
- if bus_num is None or device_num is None:
- raise ValueError('Info not found')
- return (bus_num, device_num)
-
-
-def GetBusDeviceToTTYMap():
- """Gets all mappings from (bus, device) to ttyUSB string.
-
- Gets mapping from (bus, device) to ttyUSB string (e.g. 'ttyUSB0'),
- for all ttyUSB strings currently active.
-
- Returns:
- [dict] Dict that maps (bus, device) to ttyUSB string
- """
- result = {}
- for tty in GetTTYList():
- result[GetBusDeviceFromTTY(tty)] = tty
- return result
-
-
-# This dictionary described the mapping between physical and
-# virtual ports on a Plugable 7-Port Hub (model USB2-HUB7BC).
-# Keys are the virtual ports, values are the physical port.
-# The entry 4:{1:4, 2:3, 3:2, 4:1} indicates that virtual port
-# 4 connects to another 'virtual' hub that itself has the
-# virtual-to-physical port mapping {1:4, 2:3, 3:2, 4:1}.
-
-
-def TestUSBTopologyScript():
- """Test display and hub identification."""
- # Identification criteria for Plugable 7-Port Hub
- print '==== USB TOPOLOGY SCRIPT TEST ===='
-
- # Display devices
- print '==== DEVICE DISPLAY ===='
- device_trees = GetBusNumberToDeviceTreeMap()
- for device_tree in device_trees.values():
- device_tree.Display()
- print
-
- # Display TTY information about devices plugged into hubs.
- print '==== TTY INFORMATION ===='
- for port_map in GetAllPhysicalPortToTTYMaps(
- usb_hubs.ALL_HUBS, device_tree_map=device_trees):
- print port_map
- print
-
- # Display serial number information about devices plugged into hubs.
- print '==== SERIAL NUMBER INFORMATION ===='
- for port_map in GetAllPhysicalPortToSerialMaps(
- usb_hubs.ALL_HUBS, device_tree_map=device_trees):
- print port_map
-
-
- return 0
-
-
-def parse_options(argv):
- """Parses and checks the command-line options.
-
- Returns:
- A tuple containing the options structure and a list of categories to
- be traced.
- """
- USAGE = '''./find_usb_devices [--help]
- This script shows the mapping between USB devices and port numbers.
- Clients are not intended to call this script from the command line.
- Clients are intended to call the functions in this script directly.
- For instance, GetAllPhysicalPortToSerialMaps(...)
- Running this script with --help will display this message.
- Running this script without --help will display information about
- devices attached, TTY mapping, and serial number mapping,
- for testing purposes. See design document for API documentation.
- '''
- parser = argparse.ArgumentParser(usage=USAGE)
- return parser.parse_args(argv[1:])
-
-def main():
- parse_options(sys.argv)
- TestUSBTopologyScript()
-
-if __name__ == "__main__":
- sys.exit(main())
diff --git a/third_party/catapult/devil/devil/utils/find_usb_devices_test.py b/third_party/catapult/devil/devil/utils/find_usb_devices_test.py
deleted file mode 100755
index e8b00c85ee..0000000000
--- a/third_party/catapult/devil/devil/utils/find_usb_devices_test.py
+++ /dev/null
@@ -1,379 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# pylint: disable=protected-access
-
-"""
-Unit tests for the contents of find_usb_devices.py.
-
-Device tree for these tests is as follows:
-Bus 001:
-1: Device 011 "foo"
-2: Device 012 "bar"
-3: Device 013 "baz"
-
-Bus 002:
-1: Device 011 "quux"
-2: Device 020 "My Test HUB" #hub 1
-2:1: Device 021 "battor_p7_h1_t0" #physical port 7 on hub 1, on ttyUSB0
-2:3: Device 022 "battor_p5_h1_t1" #physical port 5 on hub 1, on ttyUSB1
-2:4: Device 023 "My Test Internal HUB" #internal section of hub 1
-2:4:2: Device 024 "battor_p3_h1_t2" #physical port 3 on hub 1, on ttyUSB2
-2:4:3: Device 026 "Not a Battery Monitor" #physical port 1 on hub 1, on ttyUSB3
-2:4:4: Device 025 "battor_p1_h1_t3" #physical port 1 on hub 1, on ttyUSB3
-3: Device 100 "My Test HUB" #hub 2
-3:4: Device 101 "My Test Internal HUB" #internal section of hub 2
-3:4:4: Device 102 "battor_p1_h2_t4" #physical port 1 on hub 2, on ttyusb4
-"""
-
-import logging
-import os
-import unittest
-
-from devil import devil_env
-from devil.utils import battor_device_mapping
-from devil.utils import find_usb_devices
-from devil.utils import lsusb
-from devil.utils import usb_hubs
-
-with devil_env.SysPath(devil_env.PYMOCK_PATH):
- import mock # pylint: disable=import-error
-
-# Output of lsusb.lsusb().
-# We just test that the dictionary is working by creating an
-# "ID number" equal to (bus_num*1000)+device_num and seeing if
-# it is picked up correctly. Also we test the description
-
-DEVLIST = [(1, 11, 'foo'),
- (1, 12, 'bar'),
- (1, 13, 'baz'),
- (2, 11, 'quux'),
- (2, 20, 'My Test HUB'),
- (2, 21, 'ID 0403:6001 battor_p7_h1_t0'),
- (2, 22, 'ID 0403:6001 battor_p5_h1_t1'),
- (2, 23, 'My Test Internal HUB'),
- (2, 24, 'ID 0403:6001 battor_p3_h1_t2'),
- (2, 25, 'ID 0403:6001 battor_p1_h1_t3'),
- (2, 26, 'Not a Battery Monitor'),
- (2, 100, 'My Test HUB'),
- (2, 101, 'My Test Internal HUB'),
- (2, 102, 'ID 0403:6001 battor_p1_h1_t4')]
-
-LSUSB_OUTPUT = [
- {'bus': b, 'device': d, 'desc': t, 'id': (1000*b)+d}
- for (b, d, t) in DEVLIST]
-
-
-# Note: "Lev", "Cnt", "Spd", and "MxCh" are not used by parser,
-# so we just leave them as zeros here. Also note that the port
-# numbers reported here start at 0, so they're 1 less than the
-# port numbers reported elsewhere.
-USB_DEVICES_OUTPUT = '''
-T: Bus=01 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 11 Spd=000 MxCh=00
-S: SerialNumber=FooSerial
-T: Bus=01 Lev=00 Prnt=00 Port=01 Cnt=00 Dev#= 12 Spd=000 MxCh=00
-S: SerialNumber=BarSerial
-T: Bus=01 Lev=00 Prnt=00 Port=02 Cnt=00 Dev#= 13 Spd=000 MxCh=00
-S: SerialNumber=BazSerial
-
-T: Bus=02 Lev=00 Prnt=00 Port=00 Cnt=00 Dev#= 11 Spd=000 MxCh=00
-
-T: Bus=02 Lev=00 Prnt=00 Port=01 Cnt=00 Dev#= 20 Spd=000 MxCh=00
-T: Bus=02 Lev=00 Prnt=20 Port=00 Cnt=00 Dev#= 21 Spd=000 MxCh=00
-S: SerialNumber=BattOr0
-T: Bus=02 Lev=00 Prnt=20 Port=02 Cnt=00 Dev#= 22 Spd=000 MxCh=00
-S: SerialNumber=BattOr1
-T: Bus=02 Lev=00 Prnt=20 Port=03 Cnt=00 Dev#= 23 Spd=000 MxCh=00
-T: Bus=02 Lev=00 Prnt=23 Port=01 Cnt=00 Dev#= 24 Spd=000 MxCh=00
-S: SerialNumber=BattOr2
-T: Bus=02 Lev=00 Prnt=23 Port=03 Cnt=00 Dev#= 25 Spd=000 MxCh=00
-S: SerialNumber=BattOr3
-T: Bus=02 Lev=00 Prnt=23 Port=02 Cnt=00 Dev#= 26 Spd=000 MxCh=00
-
-T: Bus=02 Lev=00 Prnt=00 Port=02 Cnt=00 Dev#=100 Spd=000 MxCh=00
-T: Bus=02 Lev=00 Prnt=100 Port=03 Cnt=00 Dev#=101 Spd=000 MxCh=00
-T: Bus=02 Lev=00 Prnt=101 Port=03 Cnt=00 Dev#=102 Spd=000 MxCh=00
-'''
-
-RAW_LSUSB_OUTPUT = '''
-Bus 001 Device 011: FAST foo
-Bus 001 Device 012: FAST bar
-Bus 001 Device 013: baz
-Bus 002 Device 011: quux
-Bus 002 Device 020: My Test HUB
-Bus 002 Device 021: ID 0403:6001 battor_p7_h1_t0
-Bus 002 Device 022: ID 0403:6001 battor_p5_h1_t1
-Bus 002 Device 023: My Test Internal HUB
-Bus 002 Device 024: ID 0403:6001 battor_p3_h1_t2
-Bus 002 Device 025: ID 0403:6001 battor_p1_h1_t3
-Bus 002 Device 026: Not a Battery Monitor
-Bus 002 Device 100: My Test HUB
-Bus 002 Device 101: My Test Internal HUB
-Bus 002 Device 102: ID 0403:6001 battor_p1_h1_t4
-'''
-
-LIST_TTY_OUTPUT = '''
-ttyUSB0
-Something-else-0
-ttyUSB1
-ttyUSB2
-Something-else-1
-ttyUSB3
-ttyUSB4
-Something-else-2
-ttyUSB5
-'''
-
-# Note: The real output will have multiple lines with
-# ATTRS{busnum} and ATTRS{devnum}, but only the first
-# one counts. Thus the test output duplicates this.
-UDEVADM_USBTTY0_OUTPUT = '''
-ATTRS{busnum}=="2"
-ATTRS{devnum}=="21"
-ATTRS{busnum}=="0"
-ATTRS{devnum}=="0"
-'''
-
-UDEVADM_USBTTY1_OUTPUT = '''
-ATTRS{busnum}=="2"
-ATTRS{devnum}=="22"
-ATTRS{busnum}=="0"
-ATTRS{devnum}=="0"
-'''
-
-UDEVADM_USBTTY2_OUTPUT = '''
-ATTRS{busnum}=="2"
-ATTRS{devnum}=="24"
-ATTRS{busnum}=="0"
-ATTRS{devnum}=="0"
-'''
-
-UDEVADM_USBTTY3_OUTPUT = '''
-ATTRS{busnum}=="2"
-ATTRS{devnum}=="25"
-ATTRS{busnum}=="0"
-ATTRS{devnum}=="0"
-'''
-
-UDEVADM_USBTTY4_OUTPUT = '''
-ATTRS{busnum}=="2"
-ATTRS{devnum}=="102"
-ATTRS{busnum}=="0"
-ATTRS{devnum}=="0"
-'''
-
-UDEVADM_USBTTY5_OUTPUT = '''
-ATTRS{busnum}=="2"
-ATTRS{devnum}=="26"
-ATTRS{busnum}=="0"
-ATTRS{devnum}=="0"
-'''
-
-UDEVADM_OUTPUT_DICT = {
- 'ttyUSB0': UDEVADM_USBTTY0_OUTPUT,
- 'ttyUSB1': UDEVADM_USBTTY1_OUTPUT,
- 'ttyUSB2': UDEVADM_USBTTY2_OUTPUT,
- 'ttyUSB3': UDEVADM_USBTTY3_OUTPUT,
- 'ttyUSB4': UDEVADM_USBTTY4_OUTPUT,
- 'ttyUSB5': UDEVADM_USBTTY5_OUTPUT}
-
-# Identification criteria for Plugable 7-Port Hub
-def isTestHub(node):
- """Check if a node is a Plugable 7-Port Hub
- (Model USB2-HUB7BC)
- The topology of this device is a 4-port hub,
- with another 4-port hub connected on port 4.
- """
- if not isinstance(node, find_usb_devices.USBDeviceNode):
- return False
- if 'Test HUB' not in node.desc:
- return False
- if not node.HasPort(4):
- return False
- return 'Test Internal HUB' in node.PortToDevice(4).desc
-
-TEST_HUB = usb_hubs.HubType(isTestHub,
- {1:7,
- 2:6,
- 3:5,
- 4:{1:4, 2:3, 3:2, 4:1}})
-
-class USBScriptTest(unittest.TestCase):
- def setUp(self):
- find_usb_devices._GetTtyUSBInfo = mock.Mock(
- side_effect=lambda x: UDEVADM_OUTPUT_DICT[x])
- find_usb_devices._GetParsedLSUSBOutput = mock.Mock(
- return_value=LSUSB_OUTPUT)
- find_usb_devices._GetUSBDevicesOutput = mock.Mock(
- return_value=USB_DEVICES_OUTPUT)
- find_usb_devices._GetCommList = mock.Mock(
- return_value=LIST_TTY_OUTPUT)
- lsusb.raw_lsusb = mock.Mock(
- return_value=RAW_LSUSB_OUTPUT)
-
- def testIsBattOr(self):
- bd = find_usb_devices.GetBusNumberToDeviceTreeMap()
- self.assertTrue(battor_device_mapping.IsBattOr('ttyUSB3', bd))
- self.assertFalse(battor_device_mapping.IsBattOr('ttyUSB5', bd))
-
- def testGetBattOrs(self):
- bd = find_usb_devices.GetBusNumberToDeviceTreeMap()
- self.assertEquals(battor_device_mapping.GetBattOrList(bd),
- ['ttyUSB0', 'ttyUSB1', 'ttyUSB2',
- 'ttyUSB3', 'ttyUSB4'])
-
- def testGetTTYDevices(self):
- pp = find_usb_devices.GetAllPhysicalPortToTTYMaps([TEST_HUB])
- result = list(pp)
- self.assertEquals(result[0], {7:'ttyUSB0',
- 5:'ttyUSB1',
- 3:'ttyUSB2',
- 2:'ttyUSB5',
- 1:'ttyUSB3'})
- self.assertEquals(result[1], {1:'ttyUSB4'})
-
- def testGetPortDeviceMapping(self):
- pp = find_usb_devices.GetAllPhysicalPortToBusDeviceMaps([TEST_HUB])
- result = list(pp)
- self.assertEquals(result[0], {7:(2, 21),
- 5:(2, 22),
- 3:(2, 24),
- 2:(2, 26),
- 1:(2, 25)})
- self.assertEquals(result[1], {1:(2, 102)})
-
- def testGetSerialMapping(self):
- pp = find_usb_devices.GetAllPhysicalPortToSerialMaps([TEST_HUB])
- result = list(pp)
- self.assertEquals(result[0], {7:'BattOr0',
- 5:'BattOr1',
- 3:'BattOr2',
- 1:'BattOr3'})
- self.assertEquals(result[1], {})
-
- def testFastDeviceDescriptions(self):
- bd = find_usb_devices.GetBusNumberToDeviceTreeMap()
- dev_foo = bd[1].FindDeviceNumber(11)
- dev_bar = bd[1].FindDeviceNumber(12)
- dev_battor_p7_h1_t0 = bd[2].FindDeviceNumber(21)
- self.assertEquals(dev_foo.desc, 'FAST foo')
- self.assertEquals(dev_bar.desc, 'FAST bar')
- self.assertEquals(dev_battor_p7_h1_t0.desc,
- 'ID 0403:6001 battor_p7_h1_t0')
-
- def testDeviceDescriptions(self):
- bd = find_usb_devices.GetBusNumberToDeviceTreeMap(fast=False)
- dev_foo = bd[1].FindDeviceNumber(11)
- dev_bar = bd[1].FindDeviceNumber(12)
- dev_battor_p7_h1_t0 = bd[2].FindDeviceNumber(21)
- self.assertEquals(dev_foo.desc, 'foo')
- self.assertEquals(dev_bar.desc, 'bar')
- self.assertEquals(dev_battor_p7_h1_t0.desc,
- 'ID 0403:6001 battor_p7_h1_t0')
-
- def testDeviceInformation(self):
- bd = find_usb_devices.GetBusNumberToDeviceTreeMap(fast=False)
- dev_foo = bd[1].FindDeviceNumber(11)
- dev_bar = bd[1].FindDeviceNumber(12)
- dev_battor_p7_h1_t0 = bd[2].FindDeviceNumber(21)
- self.assertEquals(dev_foo.info['id'], 1011)
- self.assertEquals(dev_bar.info['id'], 1012)
- self.assertEquals(dev_battor_p7_h1_t0.info['id'], 2021)
-
- def testSerialNumber(self):
- bd = find_usb_devices.GetBusNumberToDeviceTreeMap(fast=False)
- dev_foo = bd[1].FindDeviceNumber(11)
- dev_bar = bd[1].FindDeviceNumber(12)
- dev_battor_p7_h1_t0 = bd[2].FindDeviceNumber(21)
- self.assertEquals(dev_foo.serial, 'FooSerial')
- self.assertEquals(dev_bar.serial, 'BarSerial')
- self.assertEquals(dev_battor_p7_h1_t0.serial, 'BattOr0')
-
- def testBattOrDictMapping(self):
- map_dict = {'Phone1':'BattOr1', 'Phone2':'BattOr2', 'Phone3':'BattOr3'}
- a1 = battor_device_mapping.GetBattOrPathFromPhoneSerial(
- 'Phone1', serial_map=map_dict)
- a2 = battor_device_mapping.GetBattOrPathFromPhoneSerial(
- 'Phone2', serial_map=map_dict)
- a3 = battor_device_mapping.GetBattOrPathFromPhoneSerial(
- 'Phone3', serial_map=map_dict)
- self.assertEquals(a1, '/dev/ttyUSB1')
- self.assertEquals(a2, '/dev/ttyUSB2')
- self.assertEquals(a3, '/dev/ttyUSB3')
-
- def testBattOrDictFromFileMapping(self):
- try:
- map_dict = {'Phone1':'BattOr1', 'Phone2':'BattOr2', 'Phone3':'BattOr3'}
- curr_dir = os.path.dirname(os.path.realpath(__file__))
- filename = os.path.join(curr_dir, 'test', 'data', 'test_write_map.json')
- battor_device_mapping.WriteSerialMapFile(filename, map_dict)
- a1 = battor_device_mapping.GetBattOrPathFromPhoneSerial(
- 'Phone1', serial_map_file=filename)
- a2 = battor_device_mapping.GetBattOrPathFromPhoneSerial(
- 'Phone2', serial_map_file=filename)
- a3 = battor_device_mapping.GetBattOrPathFromPhoneSerial(
- 'Phone3', serial_map_file=filename)
- finally:
- os.remove(filename)
- self.assertEquals(a1, '/dev/ttyUSB1')
- self.assertEquals(a2, '/dev/ttyUSB2')
- self.assertEquals(a3, '/dev/ttyUSB3')
-
- def testReadSerialMapFile(self):
- curr_dir = os.path.dirname(os.path.realpath(__file__))
- map_dict = battor_device_mapping.ReadSerialMapFile(
- os.path.join(curr_dir, 'test', 'data', 'test_serial_map.json'))
- self.assertEquals(len(map_dict.keys()), 3)
- self.assertEquals(map_dict['Phone1'], 'BattOr1')
- self.assertEquals(map_dict['Phone2'], 'BattOr2')
- self.assertEquals(map_dict['Phone3'], 'BattOr3')
-
-original_PPTSM = find_usb_devices.GetAllPhysicalPortToSerialMaps
-original_PPTTM = find_usb_devices.GetAllPhysicalPortToTTYMaps
-original_GBL = battor_device_mapping.GetBattOrList
-original_GBNDM = find_usb_devices.GetBusNumberToDeviceTreeMap
-original_IB = battor_device_mapping.IsBattOr
-original_GBSM = battor_device_mapping.GetBattOrSerialNumbers
-
-def setup_battor_test(serial, tty, battor, bser=None):
- serial_mapper = mock.Mock(return_value=serial)
- tty_mapper = mock.Mock(return_value=tty)
- battor_lister = mock.Mock(return_value=battor)
- devtree = mock.Mock(return_value=None)
- is_battor = mock.Mock(side_effect=lambda x, y: x in battor)
- battor_serials = mock.Mock(return_value=bser)
- find_usb_devices.GetAllPhysicalPortToSerialMaps = serial_mapper
- find_usb_devices.GetAllPhysicalPortToTTYMaps = tty_mapper
- battor_device_mapping.GetBattOrList = battor_lister
- find_usb_devices.GetBusNumberToDeviceTreeMap = devtree
- battor_device_mapping.IsBattOr = is_battor
- battor_device_mapping.GetBattOrSerialNumbers = battor_serials
-
-class BattOrMappingTest(unittest.TestCase):
- def tearDown(self):
- find_usb_devices.GetAllPhysicalPortToSerialMaps = original_PPTSM
- find_usb_devices.GetAllPhysicalPortToTTYMaps = original_PPTTM
- battor_device_mapping.GetBattOrList = original_GBL
- find_usb_devices.GetBusNumberToDeviceTreeMap = original_GBNDM
- battor_device_mapping.IsBattOr = original_IB
- battor_device_mapping.GetBattOrSerialNumbers = original_GBSM
-
- def test_generate_serial_map(self):
- setup_battor_test([{1:'Phn1', 2:'Phn2', 3:'Phn3'},
- {1:'Bat1', 2:'Bat2', 3:'Bat3'}],
- [{},
- {1:'ttyUSB0', 2:'ttyUSB1', 3:'ttyUSB2'}],
- ['ttyUSB0', 'ttyUSB1', 'ttyUSB2'],
- ['Bat1', 'Bat2', 'Bat3'])
- result = battor_device_mapping.GenerateSerialMap()
- self.assertEqual(len(result), 3)
- self.assertEqual(result['Phn1'], 'Bat1')
- self.assertEqual(result['Phn2'], 'Bat2')
- self.assertEqual(result['Phn3'], 'Bat3')
-
-
-if __name__ == "__main__":
- logging.getLogger().setLevel(logging.DEBUG)
- unittest.main(verbosity=2)
diff --git a/third_party/catapult/devil/devil/utils/geometry.py b/third_party/catapult/devil/devil/utils/geometry.py
deleted file mode 100644
index da21770b3e..0000000000
--- a/third_party/catapult/devil/devil/utils/geometry.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Objects for convenient manipulation of points and other surface areas."""
-
-import collections
-
-
-class Point(collections.namedtuple('Point', ['x', 'y'])):
- """Object to represent an (x, y) point on a surface.
-
- Args:
- x, y: Two numeric coordinates that define the point.
- """
- __slots__ = ()
-
- def __str__(self):
- """Get a useful string representation of the object."""
- return '(%s, %s)' % (self.x, self.y)
-
- def __add__(self, other):
- """Sum of two points, e.g. p + q."""
- if isinstance(other, Point):
- return Point(self.x + other.x, self.y + other.y)
- else:
- return NotImplemented
-
- def __mul__(self, factor):
- """Multiplication on the right is not implemented."""
- # This overrides the default behaviour of a tuple multiplied by a constant
- # on the right, which does not make sense for a Point.
- return NotImplemented
-
- def __rmul__(self, factor):
- """Multiply a point by a scalar factor on the left, e.g. 2 * p."""
- return Point(factor * self.x, factor * self.y)
-
-
-class Rectangle(
- collections.namedtuple('Rectangle', ['top_left', 'bottom_right'])):
- """Object to represent a rectangle on a surface.
-
- Args:
- top_left: A pair of (left, top) coordinates. Might be given as a Point
- or as a two-element sequence (list, tuple, etc.).
- bottom_right: A pair (right, bottom) coordinates.
- """
- __slots__ = ()
-
- def __new__(cls, top_left, bottom_right):
- if not isinstance(top_left, Point):
- top_left = Point(*top_left)
- if not isinstance(bottom_right, Point):
- bottom_right = Point(*bottom_right)
- return super(Rectangle, cls).__new__(cls, top_left, bottom_right)
-
- def __str__(self):
- """Get a useful string representation of the object."""
- return '[%s, %s]' % (self.top_left, self.bottom_right)
-
- @property
- def center(self):
- """Get the point at the center of the rectangle."""
- return 0.5 * (self.top_left + self.bottom_right)
-
- @classmethod
- def FromDict(cls, d):
- """Create a rectangle object from a dictionary.
-
- Args:
- d: A dictionary (or mapping) of the form, e.g., {'top': 0, 'left': 0,
- 'bottom': 1, 'right': 1}.
- """
- return cls(Point(d['left'], d['top']), Point(d['right'], d['bottom']))
diff --git a/third_party/catapult/devil/devil/utils/geometry_test.py b/third_party/catapult/devil/devil/utils/geometry_test.py
deleted file mode 100644
index af69442930..0000000000
--- a/third_party/catapult/devil/devil/utils/geometry_test.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Tests for the geometry module."""
-
-import unittest
-
-from devil.utils import geometry as g
-
-
-class PointTest(unittest.TestCase):
-
- def testStr(self):
- p = g.Point(1, 2)
- self.assertEquals(str(p), '(1, 2)')
-
- def testAdd(self):
- p = g.Point(1, 2)
- q = g.Point(3, 4)
- r = g.Point(4, 6)
- self.assertEquals(p + q, r)
-
- def testAdd_TypeErrorWithInvalidOperands(self):
- # pylint: disable=pointless-statement
- p = g.Point(1, 2)
- with self.assertRaises(TypeError):
- p + 4 # Can't add point and scalar.
- with self.assertRaises(TypeError):
- 4 + p # Can't add scalar and point.
-
- def testMult(self):
- p = g.Point(1, 2)
- r = g.Point(2, 4)
- self.assertEquals(2 * p, r) # Multiply by scalar on the left.
-
- def testMult_TypeErrorWithInvalidOperands(self):
- # pylint: disable=pointless-statement
- p = g.Point(1, 2)
- q = g.Point(2, 4)
- with self.assertRaises(TypeError):
- p * q # Can't multiply points.
- with self.assertRaises(TypeError):
- p * 4 # Can't multiply by a scalar on the right.
-
-
-class RectangleTest(unittest.TestCase):
-
- def testStr(self):
- r = g.Rectangle(g.Point(0, 1), g.Point(2, 3))
- self.assertEquals(str(r), '[(0, 1), (2, 3)]')
-
- def testCenter(self):
- r = g.Rectangle(g.Point(0, 1), g.Point(2, 3))
- c = g.Point(1, 2)
- self.assertEquals(r.center, c)
-
- def testFromJson(self):
- r1 = g.Rectangle(g.Point(0, 1), g.Point(2, 3))
- r2 = g.Rectangle.FromDict({'top': 1, 'left': 0, 'bottom': 3, 'right': 2})
- self.assertEquals(r1, r2)
diff --git a/third_party/catapult/devil/devil/utils/host_utils.py b/third_party/catapult/devil/devil/utils/host_utils.py
deleted file mode 100644
index 580721f127..0000000000
--- a/third_party/catapult/devil/devil/utils/host_utils.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import os
-
-
-def GetRecursiveDiskUsage(path):
- """Returns the disk usage in bytes of |path|. Similar to `du -sb |path|`."""
- running_size = os.path.getsize(path)
- if os.path.isdir(path):
- for root, dirs, files in os.walk(path):
- running_size += sum([os.path.getsize(os.path.join(root, f))
- for f in files + dirs])
- return running_size
-
diff --git a/third_party/catapult/devil/devil/utils/lazy/__init__.py b/third_party/catapult/devil/devil/utils/lazy/__init__.py
deleted file mode 100644
index 3cc56c0acf..0000000000
--- a/third_party/catapult/devil/devil/utils/lazy/__init__.py
+++ /dev/null
@@ -1,5 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-from devil.utils.lazy.weak_constant import WeakConstant
diff --git a/third_party/catapult/devil/devil/utils/lazy/weak_constant.py b/third_party/catapult/devil/devil/utils/lazy/weak_constant.py
deleted file mode 100644
index 3558f29ac6..0000000000
--- a/third_party/catapult/devil/devil/utils/lazy/weak_constant.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import threading
-
-
-class WeakConstant(object):
- """A thread-safe, lazily initialized object.
-
- This does not support modification after initialization. The intended
- constant nature of the object is not enforced, though, hence the "weak".
- """
-
- def __init__(self, initializer):
- self._initialized = False
- self._initializer = initializer
- self._lock = threading.Lock()
- self._val = None
-
- def read(self):
- """Get the object, creating it if necessary."""
- if self._initialized:
- return self._val
- with self._lock:
- if not self._initialized:
- self._val = self._initializer()
- self._initialized = True
- return self._val
diff --git a/third_party/catapult/devil/devil/utils/lsusb.py b/third_party/catapult/devil/devil/utils/lsusb.py
deleted file mode 100644
index 6cbf2567b9..0000000000
--- a/third_party/catapult/devil/devil/utils/lsusb.py
+++ /dev/null
@@ -1,174 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import logging
-import re
-
-from devil.utils import cmd_helper
-
-logger = logging.getLogger(__name__)
-
-_COULDNT_OPEN_ERROR_RE = re.compile(r'Couldn\'t open device.*')
-_INDENTATION_RE = re.compile(r'^( *)')
-_LSUSB_BUS_DEVICE_RE = re.compile(r'^Bus (\d{3}) Device (\d{3}): (.*)')
-_LSUSB_ENTRY_RE = re.compile(r'^ *([^ ]+) +([^ ]+) *([^ ].*)?$')
-_LSUSB_GROUP_RE = re.compile(r'^ *([^ ]+.*):$')
-
-
-def _lsusbv_on_device(bus_id, dev_id):
- """Calls lsusb -v on device."""
- _, raw_output = cmd_helper.GetCmdStatusAndOutputWithTimeout(
- ['lsusb', '-v', '-s', '%s:%s' % (bus_id, dev_id)], timeout=10)
-
- device = {'bus': bus_id, 'device': dev_id}
- depth_stack = [device]
-
- # This builds a nested dict -- a tree, basically -- that corresponds
- # to the lsusb output. It looks first for a line containing
- #
- # "Bus <bus number> Device <device number>: ..."
- #
- # and uses that to create the root node. It then parses all remaining
- # lines as a tree, with the indentation level determining the
- # depth of the new node.
- #
- # This expects two kinds of lines:
- # - "groups", which take the form
- # "<Group name>:"
- # and typically have children, and
- # - "entries", which take the form
- # "<entry name> <entry value> <possible entry description>"
- # and typically do not have children (but can).
- #
- # This maintains a stack containing all current ancestor nodes in
- # order to add new nodes to the proper place in the tree.
- # The stack is added to when a new node is parsed. Nodes are removed
- # from the stack when they are either at the same indentation level as
- # or a deeper indentation level than the current line.
- #
- # e.g. the following lsusb output:
- #
- # Bus 123 Device 456: School bus
- # Device Descriptor:
- # bDeviceClass 5 Actual School Bus
- # Configuration Descriptor:
- # bLength 20 Rows
- #
- # would produce the following dict:
- #
- # {
- # 'bus': 123,
- # 'device': 456,
- # 'desc': 'School bus',
- # 'Device Descriptor': {
- # 'bDeviceClass': {
- # '_value': '5',
- # '_desc': 'Actual School Bus',
- # },
- # 'Configuration Descriptor': {
- # 'bLength': {
- # '_value': '20',
- # '_desc': 'Rows',
- # },
- # },
- # }
- # }
- for line in raw_output.splitlines():
- # Ignore blank lines.
- if not line:
- continue
- # Filter out error mesage about opening device.
- if _COULDNT_OPEN_ERROR_RE.match(line):
- continue
- # Find start of device information.
- m = _LSUSB_BUS_DEVICE_RE.match(line)
- if m:
- if m.group(1) != bus_id:
- logger.warning(
- 'Expected bus_id value: %r, seen %r', bus_id, m.group(1))
- if m.group(2) != dev_id:
- logger.warning(
- 'Expected dev_id value: %r, seen %r', dev_id, m.group(2))
- device['desc'] = m.group(3)
- continue
-
- # Skip any lines that aren't indented, as they're not part of the
- # device descriptor.
- indent_match = _INDENTATION_RE.match(line)
- if not indent_match:
- continue
-
- # Determine the indentation depth.
- depth = 1 + len(indent_match.group(1)) / 2
- if depth > len(depth_stack):
- logger.error(
- 'lsusb parsing error: unexpected indentation: "%s"', line)
- continue
-
- # Pop everything off the depth stack that isn't a parent of
- # this element.
- while depth < len(depth_stack):
- depth_stack.pop()
-
- cur = depth_stack[-1]
-
- m = _LSUSB_GROUP_RE.match(line)
- if m:
- new_group = {}
- cur[m.group(1)] = new_group
- depth_stack.append(new_group)
- continue
-
- m = _LSUSB_ENTRY_RE.match(line)
- if m:
- new_entry = {
- '_value': m.group(2),
- '_desc': m.group(3),
- }
- cur[m.group(1)] = new_entry
- depth_stack.append(new_entry)
- continue
-
- logger.error('lsusb parsing error: unrecognized line: "%s"', line)
-
- return device
-
-def lsusb():
- """Call lsusb and return the parsed output."""
- _, lsusb_list_output = cmd_helper.GetCmdStatusAndOutputWithTimeout(
- ['lsusb'], timeout=10)
- devices = []
- for line in lsusb_list_output.splitlines():
- m = _LSUSB_BUS_DEVICE_RE.match(line)
- if m:
- bus_num = m.group(1)
- dev_num = m.group(2)
- try:
- devices.append(_lsusbv_on_device(bus_num, dev_num))
- except cmd_helper.TimeoutError:
- # Will be blacklisted if it is in expected device file, but times out.
- logger.info('lsusb -v %s:%s timed out.', bus_num, dev_num)
- return devices
-
-def raw_lsusb():
- return cmd_helper.GetCmdOutput(['lsusb'])
-
-def get_lsusb_serial(device):
- try:
- return device['Device Descriptor']['iSerial']['_desc']
- except KeyError:
- return None
-
-def _is_android_device(device):
- try:
- # Hubs are not android devices.
- if device['Device Descriptor']['bDeviceClass']['_value'] == '9':
- return False
- except KeyError:
- pass
- return get_lsusb_serial(device) is not None
-
-def get_android_devices():
- android_devices = (d for d in lsusb() if _is_android_device(d))
- return [get_lsusb_serial(d) for d in android_devices]
diff --git a/third_party/catapult/devil/devil/utils/lsusb_test.py b/third_party/catapult/devil/devil/utils/lsusb_test.py
deleted file mode 100755
index f381e72f10..0000000000
--- a/third_party/catapult/devil/devil/utils/lsusb_test.py
+++ /dev/null
@@ -1,250 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Tests for the cmd_helper module."""
-
-import unittest
-
-from devil import devil_env
-from devil.utils import lsusb
-from devil.utils import mock_calls
-
-with devil_env.SysPath(devil_env.PYMOCK_PATH):
- import mock # pylint: disable=import-error
-
-RAW_OUTPUT = """
-Bus 003 Device 007: ID 18d1:4ee2 Google Inc. Nexus 4 (debug)
-Device Descriptor:
- bLength 18
- bDescriptorType 1
- bcdUSB 2.00
- bDeviceClass 0 (Defined at Interface level)
- bDeviceSubClass 0
- bDeviceProtocol 0
- bMaxPacketSize0 64
- idVendor 0x18d1 Google Inc.
- idProduct 0x4ee2 Nexus 4 (debug)
- bcdDevice 2.28
- iManufacturer 1 LGE
- iProduct 2 Nexus 4
- iSerial 3 01d2450ea194a93b
- bNumConfigurations 1
- Configuration Descriptor:
- bLength 9
- bDescriptorType 2
- wTotalLength 62
- bNumInterfaces 2
- bConfigurationValue 1
- iConfiguration 0
- bmAttributes 0x80
- (Bus Powered)
- MaxPower 500mA
- Interface Descriptor:
- bLength 9
- bDescriptorType 4
- bInterfaceNumber 0
- bAlternateSetting 0
- bNumEndpoints 3
- bInterfaceClass 255 Vendor Specific Class
- bInterfaceSubClass 255 Vendor Specific Subclass
- bInterfaceProtocol 0
- iInterface 4 MTP
- Endpoint Descriptor:
- bLength 7
- bDescriptorType 5
- bEndpointAddress 0x81 EP 1 IN
- bmAttributes 2
- Transfer Type Bulk
- Synch Type None
- Usage Type Data
- wMaxPacketSize 0x0040 1x 64 bytes
- bInterval 0
- Endpoint Descriptor:
- bLength 7
- bDescriptorType 5
- bEndpointAddress 0x01 EP 1 OUT
- bmAttributes 2
- Transfer Type Bulk
- Synch Type None
- Usage Type Data
- wMaxPacketSize 0x0040 1x 64 bytes
- bInterval 0
- Endpoint Descriptor:
- bLength 7
- bDescriptorType 5
- bEndpointAddress 0x82 EP 2 IN
- bmAttributes 3
- Transfer Type Interrupt
- Synch Type None
- Usage Type Data
- wMaxPacketSize 0x001c 1x 28 bytes
- bInterval 6
- Interface Descriptor:
- bLength 9
- bDescriptorType 4
- bInterfaceNumber 1
- bAlternateSetting 0
- bNumEndpoints 2
- bInterfaceClass 255 Vendor Specific Class
- bInterfaceSubClass 66
- bInterfaceProtocol 1
- iInterface 0
- Endpoint Descriptor:
- bLength 7
- bDescriptorType 5
- bEndpointAddress 0x83 EP 3 IN
- bmAttributes 2
- Transfer Type Bulk
- Synch Type None
- Usage Type Data
- wMaxPacketSize 0x0040 1x 64 bytes
- bInterval 0
- Endpoint Descriptor:
- bLength 7
- bDescriptorType 5
- bEndpointAddress 0x02 EP 2 OUT
- bmAttributes 2
- Transfer Type Bulk
- Synch Type None
- Usage Type Data
- wMaxPacketSize 0x0040 1x 64 bytes
- bInterval 0
-Device Qualifier (for other device speed):
- bLength 10
- bDescriptorType 6
- bcdUSB 2.00
- bDeviceClass 0 (Defined at Interface level)
- bDeviceSubClass 0
- bDeviceProtocol 0
- bMaxPacketSize0 64
- bNumConfigurations 1
-Device Status: 0x0000
- (Bus Powered)
-"""
-DEVICE_LIST = 'Bus 003 Device 007: ID 18d1:4ee2 Google Inc. Nexus 4 (debug)'
-
-EXPECTED_RESULT = {
- 'device': '007',
- 'bus': '003',
- 'desc': 'ID 18d1:4ee2 Google Inc. Nexus 4 (debug)',
- 'Device': {
- '_value': 'Status:',
- '_desc': '0x0000',
- '(Bus': {
- '_value': 'Powered)',
- '_desc': None
- }
- },
- 'Device Descriptor': {
- 'bLength': {'_value': '18', '_desc': None},
- 'bcdDevice': {'_value': '2.28', '_desc': None},
- 'bDeviceSubClass': {'_value': '0', '_desc': None},
- 'idVendor': {'_value': '0x18d1', '_desc': 'Google Inc.'},
- 'bcdUSB': {'_value': '2.00', '_desc': None},
- 'bDeviceProtocol': {'_value': '0', '_desc': None},
- 'bDescriptorType': {'_value': '1', '_desc': None},
- 'Configuration Descriptor': {
- 'bLength': {'_value': '9', '_desc': None},
- 'wTotalLength': {'_value': '62', '_desc': None},
- 'bConfigurationValue': {'_value': '1', '_desc': None},
- 'Interface Descriptor': {
- 'bLength': {'_value': '9', '_desc': None},
- 'bAlternateSetting': {'_value': '0', '_desc': None},
- 'bInterfaceNumber': {'_value': '1', '_desc': None},
- 'bNumEndpoints': {'_value': '2', '_desc': None},
- 'bDescriptorType': {'_value': '4', '_desc': None},
- 'bInterfaceSubClass': {'_value': '66', '_desc': None},
- 'bInterfaceClass': {
- '_value': '255',
- '_desc': 'Vendor Specific Class'
- },
- 'bInterfaceProtocol': {'_value': '1', '_desc': None},
- 'Endpoint Descriptor': {
- 'bLength': {'_value': '7', '_desc': None},
- 'bEndpointAddress': {'_value': '0x02', '_desc': 'EP 2 OUT'},
- 'bInterval': {'_value': '0', '_desc': None},
- 'bDescriptorType': {'_value': '5', '_desc': None},
- 'bmAttributes': {
- '_value': '2',
- 'Transfer': {'_value': 'Type', '_desc': 'Bulk'},
- 'Usage': {'_value': 'Type', '_desc': 'Data'},
- '_desc': None,
- 'Synch': {'_value': 'Type', '_desc': 'None'}
- },
- 'wMaxPacketSize': {
- '_value': '0x0040',
- '_desc': '1x 64 bytes'
- }
- },
- 'iInterface': {'_value': '0', '_desc': None}
- },
- 'bDescriptorType': {'_value': '2', '_desc': None},
- 'iConfiguration': {'_value': '0', '_desc': None},
- 'bmAttributes': {
- '_value': '0x80',
- '_desc': None,
- '(Bus': {'_value': 'Powered)', '_desc': None}
- },
- 'bNumInterfaces': {'_value': '2', '_desc': None},
- 'MaxPower': {'_value': '500mA', '_desc': None}
- },
- 'iSerial': {'_value': '3', '_desc': '01d2450ea194a93b'},
- 'idProduct': {'_value': '0x4ee2', '_desc': 'Nexus 4 (debug)'},
- 'iManufacturer': {'_value': '1', '_desc': 'LGE'},
- 'bDeviceClass': {
- '_value': '0',
- '_desc': '(Defined at Interface level)'
- },
- 'iProduct': {'_value': '2', '_desc': 'Nexus 4'},
- 'bMaxPacketSize0': {'_value': '64', '_desc': None},
- 'bNumConfigurations': {'_value': '1', '_desc': None}
- },
- 'Device Qualifier (for other device speed)': {
- 'bLength': {'_value': '10', '_desc': None},
- 'bNumConfigurations': {'_value': '1', '_desc': None},
- 'bDeviceSubClass': {'_value': '0', '_desc': None},
- 'bcdUSB': {'_value': '2.00', '_desc': None},
- 'bDeviceProtocol': {'_value': '0', '_desc': None},
- 'bDescriptorType': {'_value': '6', '_desc': None},
- 'bDeviceClass': {
- '_value': '0',
- '_desc': '(Defined at Interface level)'
- },
- 'bMaxPacketSize0': {'_value': '64', '_desc': None}
- }
-}
-
-
-class LsusbTest(mock_calls.TestCase):
- """Test Lsusb parsing."""
-
- def testLsusb(self):
- with self.assertCalls(
- (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutputWithTimeout(
- ['lsusb'], timeout=10), (None, DEVICE_LIST)),
- (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutputWithTimeout(
- ['lsusb', '-v', '-s', '003:007'], timeout=10), (None, RAW_OUTPUT))):
- self.assertDictEqual(lsusb.lsusb().pop(), EXPECTED_RESULT)
-
- def testGetSerial(self):
- with self.assertCalls(
- (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutputWithTimeout(
- ['lsusb'], timeout=10), (None, DEVICE_LIST)),
- (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutputWithTimeout(
- ['lsusb', '-v', '-s', '003:007'], timeout=10), (None, RAW_OUTPUT))):
- self.assertEqual(lsusb.get_android_devices(), ['01d2450ea194a93b'])
-
- def testGetLsusbSerial(self):
- with self.assertCalls(
- (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutputWithTimeout(
- ['lsusb'], timeout=10), (None, DEVICE_LIST)),
- (mock.call.devil.utils.cmd_helper.GetCmdStatusAndOutputWithTimeout(
- ['lsusb', '-v', '-s', '003:007'], timeout=10), (None, RAW_OUTPUT))):
- out = lsusb.lsusb().pop()
- self.assertEqual(lsusb.get_lsusb_serial(out), '01d2450ea194a93b')
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/third_party/catapult/devil/devil/utils/markdown.py b/third_party/catapult/devil/devil/utils/markdown.py
deleted file mode 100755
index 54e7ed5629..0000000000
--- a/third_party/catapult/devil/devil/utils/markdown.py
+++ /dev/null
@@ -1,320 +0,0 @@
-#! /usr/bin/env python
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import argparse
-import imp
-import os
-import re
-import sys
-import textwrap
-import types
-
-# A markdown code block template: https://goo.gl/9EsyRi
-_CODE_BLOCK_FORMAT = '''```{language}
-{code}
-```
-'''
-
-_DEVIL_ROOT = os.path.abspath(os.path.join(
- os.path.dirname(__file__), '..', '..'))
-
-
-def md_bold(raw_text):
- """Returns markdown-formatted bold text."""
- return '**%s**' % md_escape(raw_text, characters='*')
-
-
-def md_code(raw_text, language):
- """Returns a markdown-formatted code block in the given language."""
- return _CODE_BLOCK_FORMAT.format(
- language=language or '',
- code=md_escape(raw_text, characters='`'))
-
-
-def md_escape(raw_text, characters='*_'):
- """Escapes * and _."""
- def escape_char(m):
- return '\\%s' % m.group(0)
- pattern = '[%s]' % re.escape(characters)
- return re.sub(pattern, escape_char, raw_text)
-
-
-def md_heading(raw_text, level):
- """Returns markdown-formatted heading."""
- adjusted_level = min(max(level, 0), 6)
- return '%s%s%s' % (
- '#' * adjusted_level, ' ' if adjusted_level > 0 else '', raw_text)
-
-
-def md_inline_code(raw_text):
- """Returns markdown-formatted inline code."""
- return '`%s`' % md_escape(raw_text, characters='`')
-
-
-def md_italic(raw_text):
- """Returns markdown-formatted italic text."""
- return '*%s*' % md_escape(raw_text, characters='*')
-
-
-def md_link(link_text, link_target):
- """returns a markdown-formatted link."""
- return '[%s](%s)' % (
- md_escape(link_text, characters=']'),
- md_escape(link_target, characters=')'))
-
-
-class MarkdownHelpFormatter(argparse.HelpFormatter):
- """A really bare-bones argparse help formatter that generates valid markdown.
-
- This will generate something like:
-
- usage
-
- # **section heading**:
-
- ## **--argument-one**
-
- ```
- argument-one help text
- ```
-
- """
-
- #override
- def _format_usage(self, usage, actions, groups, prefix):
- usage_text = super(MarkdownHelpFormatter, self)._format_usage(
- usage, actions, groups, prefix)
- return md_code(usage_text, language=None)
-
- #override
- def format_help(self):
- self._root_section.heading = md_heading(self._prog, level=1)
- return super(MarkdownHelpFormatter, self).format_help()
-
- #override
- def start_section(self, heading):
- super(MarkdownHelpFormatter, self).start_section(
- md_heading(heading, level=2))
-
- #override
- def _format_action(self, action):
- lines = []
- action_header = self._format_action_invocation(action)
- lines.append(md_heading(action_header, level=3))
- if action.help:
- lines.append(md_code(self._expand_help(action), language=None))
- lines.extend(['', ''])
- return '\n'.join(lines)
-
-
-class MarkdownHelpAction(argparse.Action):
- def __init__(self, option_strings,
- dest=argparse.SUPPRESS, default=argparse.SUPPRESS,
- **kwargs):
- super(MarkdownHelpAction, self).__init__(
- option_strings=option_strings,
- dest=dest,
- default=default,
- nargs=0,
- **kwargs)
-
- def __call__(self, parser, namespace, values, option_string=None):
- parser.formatter_class = MarkdownHelpFormatter
- parser.print_help()
- parser.exit()
-
-
-def add_md_help_argument(parser):
- """Adds --md-help to the given argparse.ArgumentParser.
-
- Running a script with --md-help will print the help text for that script
- as valid markdown.
-
- Args:
- parser: The ArgumentParser to which --md-help should be added.
- """
- parser.add_argument('--md-help', action=MarkdownHelpAction,
- help='print Markdown-formatted help text and exit.')
-
-
-def load_module_from_path(module_path):
- """Load a module given only the path name.
-
- Also loads package modules as necessary.
-
- Args:
- module_path: An absolute path to a python module.
- Returns:
- The module object for the given path.
- """
- module_names = [os.path.splitext(os.path.basename(module_path))[0]]
- d = os.path.dirname(module_path)
-
- while os.path.exists(os.path.join(d, '__init__.py')):
- module_names.append(os.path.basename(d))
- d = os.path.dirname(d)
-
- d = [d]
-
- module = None
- full_module_name = ''
- for package_name in reversed(module_names):
- if module:
- d = module.__path__
- full_module_name += '.'
- r = imp.find_module(package_name, d)
- full_module_name += package_name
- module = imp.load_module(full_module_name, *r)
- return module
-
-
-def md_module(module_obj, module_path=None, module_link=None):
- """Write markdown documentation for a class.
-
- Documents public classes and functions.
-
- Args:
- class_obj: a types.TypeType object for the class that should be
- documented.
- Returns:
- A list of markdown-formatted lines.
- """
- def should_doc(name):
- return (type(module_obj.__dict__[name]) != types.ModuleType
- and not name.startswith('_'))
-
- stuff_to_doc = sorted(
- obj for name, obj in module_obj.__dict__.iteritems()
- if should_doc(name))
-
- classes_to_doc = []
- functions_to_doc = []
-
- for s in stuff_to_doc:
- if type(s) == types.TypeType:
- classes_to_doc.append(s)
- elif type(s) == types.FunctionType:
- functions_to_doc.append(s)
-
- command = ['devil/utils/markdown.py']
- if module_link:
- command.extend(['--module-link', module_link])
- if module_path:
- command.append(os.path.relpath(module_path, _DEVIL_ROOT))
-
- heading_text = module_obj.__name__
- if module_link:
- heading_text = md_link(heading_text, module_link)
-
- content = [
- md_heading(heading_text, level=1),
- '',
- md_italic('This page was autogenerated by %s'
- % md_inline_code(' '.join(command))),
- '',
- ]
-
- for c in classes_to_doc:
- content += md_class(c)
- for f in functions_to_doc:
- content += md_function(f)
-
- print '\n'.join(content)
-
- return 0
-
-
-def md_class(class_obj):
- """Write markdown documentation for a class.
-
- Documents public methods. Does not currently document subclasses.
-
- Args:
- class_obj: a types.TypeType object for the class that should be
- documented.
- Returns:
- A list of markdown-formatted lines.
- """
- content = [md_heading(md_escape(class_obj.__name__), level=2)]
- content.append('')
- if class_obj.__doc__:
- content.extend(md_docstring(class_obj.__doc__))
-
- def should_doc(name, obj):
- return (type(obj) == types.FunctionType
- and (name.startswith('__') or not name.startswith('_')))
-
- methods_to_doc = sorted(
- obj for name, obj in class_obj.__dict__.iteritems()
- if should_doc(name, obj))
-
- for m in methods_to_doc:
- content.extend(md_function(m, class_obj=class_obj))
-
- return content
-
-
-def md_docstring(docstring):
- """Write a markdown-formatted docstring.
-
- Returns:
- A list of markdown-formatted lines.
- """
- content = []
- lines = textwrap.dedent(docstring).splitlines()
- content.append(md_escape(lines[0]))
- lines = lines[1:]
- while lines and (not lines[0] or lines[0].isspace()):
- lines = lines[1:]
-
- if not all(l.isspace() for l in lines):
- content.append(md_code('\n'.join(lines), language=None))
- content.append('')
- return content
-
-
-def md_function(func_obj, class_obj=None):
- """Write markdown documentation for a function.
-
- Args:
- func_obj: a types.FunctionType object for the function that should be
- documented.
- Returns:
- A list of markdown-formatted lines.
- """
- if class_obj:
- heading_text = '%s.%s' % (class_obj.__name__, func_obj.__name__)
- else:
- heading_text = func_obj.__name__
- content = [md_heading(md_escape(heading_text), level=3)]
- content.append('')
-
- if func_obj.__doc__:
- content.extend(md_docstring(func_obj.__doc__))
-
- return content
-
-
-def main(raw_args):
- """Write markdown documentation for the module at the provided path.
-
- Args:
- raw_args: the raw command-line args. Usually sys.argv[1:].
- Returns:
- An integer exit code. 0 for success, non-zero for failure.
- """
- parser = argparse.ArgumentParser()
- parser.add_argument('--module-link')
- parser.add_argument('module_path', type=os.path.realpath)
- args = parser.parse_args(raw_args)
-
- return md_module(
- load_module_from_path(args.module_path),
- module_link=args.module_link)
-
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv[1:]))
-
diff --git a/third_party/catapult/devil/devil/utils/markdown_test.py b/third_party/catapult/devil/devil/utils/markdown_test.py
deleted file mode 100755
index 323776ca1a..0000000000
--- a/third_party/catapult/devil/devil/utils/markdown_test.py
+++ /dev/null
@@ -1,121 +0,0 @@
-#! /usr/bin/env python
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import os
-import sys
-import textwrap
-import unittest
-
-if __name__ == '__main__':
- sys.path.append(
- os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')))
-
-from devil.utils import markdown
-
-
-class MarkdownTest(unittest.TestCase):
-
- def testBold(self):
- raw = 'foo'
- self.assertEquals('**foo**', markdown.md_bold(raw))
-
- def testBoldContainsStars(self):
- raw = '*foo*'
- self.assertEquals('**\\*foo\\***', markdown.md_bold(raw))
-
- def testCode(self):
- raw = textwrap.dedent("""\
- class MarkdownTest(unittest.TestCase):
- def testCode(self):
- pass""")
-
- expected = textwrap.dedent("""\
- ```python
- class MarkdownTest(unittest.TestCase):
- def testCode(self):
- pass
- ```
- """)
- actual = markdown.md_code(raw, language='python')
- self.assertEquals(expected, actual)
-
- def testCodeContainsTicks(self):
- raw = textwrap.dedent("""\
- This is sample markdown.
- ```c
- // This is a sample code block.
- int main(int argc, char** argv) {
- return 0;
- }
- ```""")
-
- expected = textwrap.dedent("""\
- ```
- This is sample markdown.
- \\`\\`\\`c
- // This is a sample code block.
- int main(int argc, char** argv) {
- return 0;
- }
- \\`\\`\\`
- ```
- """)
- actual = markdown.md_code(raw, language=None)
- self.assertEquals(expected, actual)
-
- def testEscape(self):
- raw = 'text_with_underscores *and stars*'
- expected = 'text\\_with\\_underscores \\*and stars\\*'
- actual = markdown.md_escape(raw)
- self.assertEquals(expected, actual)
-
- def testHeading1(self):
- raw = 'Heading 1'
- self.assertEquals('# Heading 1', markdown.md_heading(raw, level=1))
-
- def testHeading5(self):
- raw = 'Heading 5'
- self.assertEquals('##### Heading 5', markdown.md_heading(raw, level=5))
-
- def testHeading10(self):
- raw = 'Heading 10'
- self.assertEquals('###### Heading 10', markdown.md_heading(raw, level=10))
-
- def testInlineCode(self):
- raw = 'devil.utils.markdown_test'
- self.assertEquals(
- '`devil.utils.markdown_test`', markdown.md_inline_code(raw))
-
- def testInlineCodeContainsTicks(self):
- raw = 'this contains `backticks`'
- self.assertEquals(
- '`this contains \\`backticks\\``', markdown.md_inline_code(raw))
-
- def testItalic(self):
- raw = 'bar'
- self.assertEquals('*bar*', markdown.md_italic(raw))
-
- def testItalicContainsStars(self):
- raw = '*bar*'
- self.assertEquals('*\\*bar\\**', markdown.md_italic(raw))
-
- def testLink(self):
- link_text = 'Devil home'
- link_target = (
- 'https://github.com/catapult-project/catapult/tree/master/devil')
- expected = (
- '[Devil home]'
- '(https://github.com/catapult-project/catapult/tree/master/devil)')
- self.assertEquals(expected, markdown.md_link(link_text, link_target))
-
- def testLinkTextContainsBracket(self):
- link_text = 'foo [] bar'
- link_target = 'https://www.google.com'
- expected = '[foo [\\] bar](https://www.google.com)'
- self.assertEquals(expected, markdown.md_link(link_text, link_target))
-
-
-if __name__ == '__main__':
- unittest.main(verbosity=2)
diff --git a/third_party/catapult/devil/devil/utils/mock_calls.py b/third_party/catapult/devil/devil/utils/mock_calls.py
deleted file mode 100644
index 5ae951e37d..0000000000
--- a/third_party/catapult/devil/devil/utils/mock_calls.py
+++ /dev/null
@@ -1,180 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""
-A test facility to assert call sequences while mocking their behavior.
-"""
-
-import unittest
-
-from devil import devil_env
-
-with devil_env.SysPath(devil_env.PYMOCK_PATH):
- import mock # pylint: disable=import-error
-
-
-class TestCase(unittest.TestCase):
- """Adds assertCalls to TestCase objects."""
- class _AssertCalls(object):
-
- def __init__(self, test_case, expected_calls, watched):
- def call_action(pair):
- if isinstance(pair, type(mock.call)):
- return (pair, None)
- else:
- return pair
-
- def do_check(call):
- def side_effect(*args, **kwargs):
- received_call = call(*args, **kwargs)
- self._test_case.assertTrue(
- self._expected_calls,
- msg=('Unexpected call: %s' % str(received_call)))
- expected_call, action = self._expected_calls.pop(0)
- self._test_case.assertTrue(
- received_call == expected_call,
- msg=('Expected call mismatch:\n'
- ' expected: %s\n'
- ' received: %s\n'
- % (str(expected_call), str(received_call))))
- if callable(action):
- return action(*args, **kwargs)
- else:
- return action
- return side_effect
-
- self._test_case = test_case
- self._expected_calls = [call_action(pair) for pair in expected_calls]
- watched = watched.copy() # do not pollute the caller's dict
- watched.update((call.parent.name, call.parent)
- for call, _ in self._expected_calls)
- self._patched = [test_case.patch_call(call, side_effect=do_check(call))
- for call in watched.itervalues()]
-
- def __enter__(self):
- for patch in self._patched:
- patch.__enter__()
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- for patch in self._patched:
- patch.__exit__(exc_type, exc_val, exc_tb)
- if exc_type is None:
- missing = ''.join(' expected: %s\n' % str(call)
- for call, _ in self._expected_calls)
- self._test_case.assertFalse(
- missing,
- msg='Expected calls not found:\n' + missing)
-
- def __init__(self, *args, **kwargs):
- super(TestCase, self).__init__(*args, **kwargs)
- self.call = mock.call.self
- self._watched = {}
-
- def call_target(self, call):
- """Resolve a self.call instance to the target it represents.
-
- Args:
- call: a self.call instance, e.g. self.call.adb.Shell
-
- Returns:
- The target object represented by the call, e.g. self.adb.Shell
-
- Raises:
- ValueError if the path of the call does not start with "self", i.e. the
- target of the call is external to the self object.
- AttributeError if the path of the call does not specify a valid
- chain of attributes (without any calls) starting from "self".
- """
- path = call.name.split('.')
- if path.pop(0) != 'self':
- raise ValueError("Target %r outside of 'self' object" % call.name)
- target = self
- for attr in path:
- target = getattr(target, attr)
- return target
-
- def patch_call(self, call, **kwargs):
- """Patch the target of a mock.call instance.
-
- Args:
- call: a mock.call instance identifying a target to patch
- Extra keyword arguments are processed by mock.patch
-
- Returns:
- A context manager to mock/unmock the target of the call
- """
- if call.name.startswith('self.'):
- target = self.call_target(call.parent)
- _, attribute = call.name.rsplit('.', 1)
- if (hasattr(type(target), attribute)
- and isinstance(getattr(type(target), attribute), property)):
- return mock.patch.object(
- type(target), attribute, new_callable=mock.PropertyMock, **kwargs)
- else:
- return mock.patch.object(target, attribute, **kwargs)
- else:
- return mock.patch(call.name, **kwargs)
-
- def watchCalls(self, calls):
- """Add calls to the set of watched calls.
-
- Args:
- calls: a sequence of mock.call instances identifying targets to watch
- """
- self._watched.update((call.name, call) for call in calls)
-
- def watchMethodCalls(self, call, ignore=None):
- """Watch all public methods of the target identified by a self.call.
-
- Args:
- call: a self.call instance indetifying an object
- ignore: a list of public methods to ignore when watching for calls
- """
- target = self.call_target(call)
- if ignore is None:
- ignore = []
- self.watchCalls(getattr(call, method)
- for method in dir(target.__class__)
- if not method.startswith('_') and not method in ignore)
-
- def clearWatched(self):
- """Clear the set of watched calls."""
- self._watched = {}
-
- def assertCalls(self, *calls):
- """A context manager to assert that a sequence of calls is made.
-
- During the assertion, a number of functions and methods will be "watched",
- and any calls made to them is expected to appear---in the exact same order,
- and with the exact same arguments---as specified by the argument |calls|.
-
- By default, the targets of all expected calls are watched. Further targets
- to watch may be added using watchCalls and watchMethodCalls.
-
- Optionaly, each call may be accompanied by an action. If the action is a
- (non-callable) value, this value will be used as the return value given to
- the caller when the matching call is found. Alternatively, if the action is
- a callable, the action will be then called with the same arguments as the
- intercepted call, so that it can provide a return value or perform other
- side effects. If the action is missing, a return value of None is assumed.
-
- Note that mock.Mock objects are often convenient to use as a callable
- action, e.g. to raise exceptions or return other objects which are
- themselves callable.
-
- Args:
- calls: each argument is either a pair (expected_call, action) or just an
- expected_call, where expected_call is a mock.call instance.
-
- Raises:
- AssertionError if the watched targets do not receive the exact sequence
- of calls specified. Missing calls, extra calls, and calls with
- mismatching arguments, all cause the assertion to fail.
- """
- return self._AssertCalls(self, calls, self._watched)
-
- def assertCall(self, call, action=None):
- return self.assertCalls((call, action))
-
diff --git a/third_party/catapult/devil/devil/utils/mock_calls_test.py b/third_party/catapult/devil/devil/utils/mock_calls_test.py
deleted file mode 100755
index 8eb4fc9da4..0000000000
--- a/third_party/catapult/devil/devil/utils/mock_calls_test.py
+++ /dev/null
@@ -1,173 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""
-Unit tests for the contents of mock_calls.py.
-"""
-
-import logging
-import os
-import unittest
-
-from devil import devil_env
-from devil.android.sdk import version_codes
-from devil.utils import mock_calls
-
-with devil_env.SysPath(devil_env.PYMOCK_PATH):
- import mock # pylint: disable=import-error
-
-
-class _DummyAdb(object):
-
- def __str__(self):
- return '0123456789abcdef'
-
- def Push(self, host_path, device_path):
- logging.debug('(device %s) pushing %r to %r', self, host_path, device_path)
-
- def IsOnline(self):
- logging.debug('(device %s) checking device online', self)
- return True
-
- def Shell(self, cmd):
- logging.debug('(device %s) running command %r', self, cmd)
- return "nice output\n"
-
- def Reboot(self):
- logging.debug('(device %s) rebooted!', self)
-
- @property
- def build_version_sdk(self):
- logging.debug('(device %s) getting build_version_sdk', self)
- return version_codes.LOLLIPOP
-
-
-class TestCaseWithAssertCallsTest(mock_calls.TestCase):
-
- def setUp(self):
- self.adb = _DummyAdb()
-
- def ShellError(self):
- def action(cmd):
- raise ValueError('(device %s) command %r is not nice' % (self.adb, cmd))
- return action
-
- def get_answer(self):
- logging.debug("called 'get_answer' of %r object", self)
- return 42
-
- def echo(self, thing):
- logging.debug("called 'echo' of %r object", self)
- return thing
-
- def testCallTarget_succeds(self):
- self.assertEquals(self.adb.Shell,
- self.call_target(self.call.adb.Shell))
-
- def testCallTarget_failsExternal(self):
- with self.assertRaises(ValueError):
- self.call_target(mock.call.sys.getcwd)
-
- def testCallTarget_failsUnknownAttribute(self):
- with self.assertRaises(AttributeError):
- self.call_target(self.call.adb.Run)
-
- def testCallTarget_failsIntermediateCalls(self):
- with self.assertRaises(AttributeError):
- self.call_target(self.call.adb.RunShell('cmd').append)
-
- def testPatchCall_method(self):
- self.assertEquals(42, self.get_answer())
- with self.patch_call(self.call.get_answer, return_value=123):
- self.assertEquals(123, self.get_answer())
- self.assertEquals(42, self.get_answer())
-
- def testPatchCall_attribute_method(self):
- with self.patch_call(self.call.adb.Shell, return_value='hello'):
- self.assertEquals('hello', self.adb.Shell('echo hello'))
-
- def testPatchCall_global(self):
- with self.patch_call(mock.call.os.getcwd, return_value='/some/path'):
- self.assertEquals('/some/path', os.getcwd())
-
- def testPatchCall_withSideEffect(self):
- with self.patch_call(self.call.adb.Shell, side_effect=ValueError):
- with self.assertRaises(ValueError):
- self.adb.Shell('echo hello')
-
- def testPatchCall_property(self):
- self.assertEquals(version_codes.LOLLIPOP, self.adb.build_version_sdk)
- with self.patch_call(
- self.call.adb.build_version_sdk,
- return_value=version_codes.KITKAT):
- self.assertEquals(version_codes.KITKAT, self.adb.build_version_sdk)
- self.assertEquals(version_codes.LOLLIPOP, self.adb.build_version_sdk)
-
- def testAssertCalls_succeeds_simple(self):
- self.assertEquals(42, self.get_answer())
- with self.assertCall(self.call.get_answer(), 123):
- self.assertEquals(123, self.get_answer())
- self.assertEquals(42, self.get_answer())
-
- def testAssertCalls_succeeds_multiple(self):
- with self.assertCalls(
- (mock.call.os.getcwd(), '/some/path'),
- (self.call.echo('hello'), 'hello'),
- (self.call.get_answer(), 11),
- self.call.adb.Push('this_file', 'that_file'),
- (self.call.get_answer(), 12)):
- self.assertEquals(os.getcwd(), '/some/path')
- self.assertEquals('hello', self.echo('hello'))
- self.assertEquals(11, self.get_answer())
- self.adb.Push('this_file', 'that_file')
- self.assertEquals(12, self.get_answer())
-
- def testAsserCalls_succeeds_withAction(self):
- with self.assertCall(
- self.call.adb.Shell('echo hello'), self.ShellError()):
- with self.assertRaises(ValueError):
- self.adb.Shell('echo hello')
-
- def testAssertCalls_fails_tooManyCalls(self):
- with self.assertRaises(AssertionError):
- with self.assertCalls(self.call.adb.IsOnline()):
- self.adb.IsOnline()
- self.adb.IsOnline()
-
- def testAssertCalls_fails_tooFewCalls(self):
- with self.assertRaises(AssertionError):
- with self.assertCalls(self.call.adb.IsOnline()):
- pass
-
- def testAssertCalls_succeeds_extraCalls(self):
- # we are not watching Reboot, so the assertion succeeds
- with self.assertCalls(self.call.adb.IsOnline()):
- self.adb.IsOnline()
- self.adb.Reboot()
-
- def testAssertCalls_fails_extraCalls(self):
- self.watchCalls([self.call.adb.Reboot])
- # this time we are also watching Reboot, so the assertion fails
- with self.assertRaises(AssertionError):
- with self.assertCalls(self.call.adb.IsOnline()):
- self.adb.IsOnline()
- self.adb.Reboot()
-
- def testAssertCalls_succeeds_NoCalls(self):
- self.watchMethodCalls(self.call.adb) # we are watching all adb methods
- with self.assertCalls():
- pass
-
- def testAssertCalls_fails_NoCalls(self):
- self.watchMethodCalls(self.call.adb)
- with self.assertRaises(AssertionError):
- with self.assertCalls():
- self.adb.IsOnline()
-
-
-if __name__ == '__main__':
- logging.getLogger().setLevel(logging.DEBUG)
- unittest.main(verbosity=2)
-
diff --git a/third_party/catapult/devil/devil/utils/parallelizer.py b/third_party/catapult/devil/devil/utils/parallelizer.py
deleted file mode 100644
index 35995251c8..0000000000
--- a/third_party/catapult/devil/devil/utils/parallelizer.py
+++ /dev/null
@@ -1,238 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-""" Wrapper that allows method execution in parallel.
-
-This class wraps a list of objects of the same type, emulates their
-interface, and executes any functions called on the objects in parallel
-in ReraiserThreads.
-
-This means that, given a list of objects:
-
- class Foo:
- def __init__(self):
- self.baz = Baz()
-
- def bar(self, my_param):
- // do something
-
- list_of_foos = [Foo(1), Foo(2), Foo(3)]
-
-we can take a sequential operation on that list of objects:
-
- for f in list_of_foos:
- f.bar('Hello')
-
-and run it in parallel across all of the objects:
-
- Parallelizer(list_of_foos).bar('Hello')
-
-It can also handle (non-method) attributes of objects, so that this:
-
- for f in list_of_foos:
- f.baz.myBazMethod()
-
-can be run in parallel with:
-
- Parallelizer(list_of_foos).baz.myBazMethod()
-
-Because it emulates the interface of the wrapped objects, a Parallelizer
-can be passed to a method or function that takes objects of that type:
-
- def DoesSomethingWithFoo(the_foo):
- the_foo.bar('Hello')
- the_foo.bar('world')
- the_foo.baz.myBazMethod
-
- DoesSomethingWithFoo(Parallelizer(list_of_foos))
-
-Note that this class spins up a thread for each object. Using this class
-to parallelize operations that are already fast will incur a net performance
-penalty.
-
-"""
-# pylint: disable=protected-access
-
-from devil.utils import reraiser_thread
-from devil.utils import watchdog_timer
-
-_DEFAULT_TIMEOUT = 30
-_DEFAULT_RETRIES = 3
-
-
-class Parallelizer(object):
- """Allows parallel execution of method calls across a group of objects."""
-
- def __init__(self, objs):
- self._orig_objs = objs
- self._objs = objs
-
- def __getattr__(self, name):
- """Emulate getting the |name| attribute of |self|.
-
- Args:
- name: The name of the attribute to retrieve.
- Returns:
- A Parallelizer emulating the |name| attribute of |self|.
- """
- self.pGet(None)
-
- r = type(self)(self._orig_objs)
- r._objs = [getattr(o, name) for o in self._objs]
- return r
-
- def __getitem__(self, index):
- """Emulate getting the value of |self| at |index|.
-
- Returns:
- A Parallelizer emulating the value of |self| at |index|.
- """
- self.pGet(None)
-
- r = type(self)(self._orig_objs)
- r._objs = [o[index] for o in self._objs]
- return r
-
- def __call__(self, *args, **kwargs):
- """Emulate calling |self| with |args| and |kwargs|.
-
- Note that this call is asynchronous. Call pFinish on the return value to
- block until the call finishes.
-
- Returns:
- A Parallelizer wrapping the ReraiserThreadGroup running the call in
- parallel.
- Raises:
- AttributeError if the wrapped objects aren't callable.
- """
- self.pGet(None)
-
- for o in self._objs:
- if not callable(o):
- raise AttributeError("'%s' is not callable" % o.__name__)
-
- r = type(self)(self._orig_objs)
- r._objs = reraiser_thread.ReraiserThreadGroup(
- [reraiser_thread.ReraiserThread(
- o, args=args, kwargs=kwargs,
- name='%s.%s' % (str(d), o.__name__))
- for d, o in zip(self._orig_objs, self._objs)])
- r._objs.StartAll() # pylint: disable=W0212
- return r
-
- def pFinish(self, timeout):
- """Finish any outstanding asynchronous operations.
-
- Args:
- timeout: The maximum number of seconds to wait for an individual
- result to return, or None to wait forever.
- Returns:
- self, now emulating the return values.
- """
- self._assertNoShadow('pFinish')
- if isinstance(self._objs, reraiser_thread.ReraiserThreadGroup):
- self._objs.JoinAll()
- self._objs = self._objs.GetAllReturnValues(
- watchdog_timer.WatchdogTimer(timeout))
- return self
-
- def pGet(self, timeout):
- """Get the current wrapped objects.
-
- Args:
- timeout: Same as |pFinish|.
- Returns:
- A list of the results, in order of the provided devices.
- Raises:
- Any exception raised by any of the called functions.
- """
- self._assertNoShadow('pGet')
- self.pFinish(timeout)
- return self._objs
-
- def pMap(self, f, *args, **kwargs):
- """Map a function across the current wrapped objects in parallel.
-
- This calls f(o, *args, **kwargs) for each o in the set of wrapped objects.
-
- Note that this call is asynchronous. Call pFinish on the return value to
- block until the call finishes.
-
- Args:
- f: The function to call.
- args: The positional args to pass to f.
- kwargs: The keyword args to pass to f.
- Returns:
- A Parallelizer wrapping the ReraiserThreadGroup running the map in
- parallel.
- """
- self._assertNoShadow('pMap')
- r = type(self)(self._orig_objs)
- r._objs = reraiser_thread.ReraiserThreadGroup(
- [reraiser_thread.ReraiserThread(
- f, args=tuple([o] + list(args)), kwargs=kwargs,
- name='%s(%s)' % (f.__name__, d))
- for d, o in zip(self._orig_objs, self._objs)])
- r._objs.StartAll() # pylint: disable=W0212
- return r
-
- def _assertNoShadow(self, attr_name):
- """Ensures that |attr_name| isn't shadowing part of the wrapped obejcts.
-
- If the wrapped objects _do_ have an |attr_name| attribute, it will be
- inaccessible to clients.
-
- Args:
- attr_name: The attribute to check.
- Raises:
- AssertionError if the wrapped objects have an attribute named 'attr_name'
- or '_assertNoShadow'.
- """
- if isinstance(self._objs, reraiser_thread.ReraiserThreadGroup):
- assert not hasattr(self._objs, '_assertNoShadow')
- assert not hasattr(self._objs, attr_name)
- else:
- assert not any(hasattr(o, '_assertNoShadow') for o in self._objs)
- assert not any(hasattr(o, attr_name) for o in self._objs)
-
-
-class SyncParallelizer(Parallelizer):
- """A Parallelizer that blocks on function calls."""
-
- # override
- def __call__(self, *args, **kwargs):
- """Emulate calling |self| with |args| and |kwargs|.
-
- Note that this call is synchronous.
-
- Returns:
- A Parallelizer emulating the value returned from calling |self| with
- |args| and |kwargs|.
- Raises:
- AttributeError if the wrapped objects aren't callable.
- """
- r = super(SyncParallelizer, self).__call__(*args, **kwargs)
- r.pFinish(None)
- return r
-
- # override
- def pMap(self, f, *args, **kwargs):
- """Map a function across the current wrapped objects in parallel.
-
- This calls f(o, *args, **kwargs) for each o in the set of wrapped objects.
-
- Note that this call is synchronous.
-
- Args:
- f: The function to call.
- args: The positional args to pass to f.
- kwargs: The keyword args to pass to f.
- Returns:
- A Parallelizer wrapping the ReraiserThreadGroup running the map in
- parallel.
- """
- r = super(SyncParallelizer, self).pMap(f, *args, **kwargs)
- r.pFinish(None)
- return r
-
diff --git a/third_party/catapult/devil/devil/utils/parallelizer_test.py b/third_party/catapult/devil/devil/utils/parallelizer_test.py
deleted file mode 100644
index 32ff7ec547..0000000000
--- a/third_party/catapult/devil/devil/utils/parallelizer_test.py
+++ /dev/null
@@ -1,162 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Unit tests for the contents of parallelizer.py."""
-
-# pylint: disable=W0212
-# pylint: disable=W0613
-
-import os
-import tempfile
-import time
-import unittest
-
-from devil.utils import parallelizer
-
-
-class ParallelizerTestObject(object):
- """Class used to test parallelizer.Parallelizer."""
-
- parallel = parallelizer.Parallelizer
-
- def __init__(self, thing, completion_file_name=None):
- self._thing = thing
- self._completion_file_name = completion_file_name
- self.helper = ParallelizerTestObjectHelper(thing)
-
- @staticmethod
- def doReturn(what):
- return what
-
- @classmethod
- def doRaise(cls, what):
- raise what
-
- def doSetTheThing(self, new_thing):
- self._thing = new_thing
-
- def doReturnTheThing(self):
- return self._thing
-
- def doRaiseTheThing(self):
- raise self._thing
-
- def doRaiseIfExceptionElseSleepFor(self, sleep_duration):
- if isinstance(self._thing, Exception):
- raise self._thing
- time.sleep(sleep_duration)
- self._write_completion_file()
- return self._thing
-
- def _write_completion_file(self):
- if self._completion_file_name and len(self._completion_file_name):
- with open(self._completion_file_name, 'w+b') as completion_file:
- completion_file.write('complete')
-
- def __getitem__(self, index):
- return self._thing[index]
-
- def __str__(self):
- return type(self).__name__
-
-
-class ParallelizerTestObjectHelper(object):
-
- def __init__(self, thing):
- self._thing = thing
-
- def doReturnStringThing(self):
- return str(self._thing)
-
-
-class ParallelizerTest(unittest.TestCase):
-
- def testInitEmptyList(self):
- r = parallelizer.Parallelizer([]).replace('a', 'b').pGet(0.1)
- self.assertEquals([], r)
-
- def testMethodCall(self):
- test_data = ['abc_foo', 'def_foo', 'ghi_foo']
- expected = ['abc_bar', 'def_bar', 'ghi_bar']
- r = parallelizer.Parallelizer(test_data).replace('_foo', '_bar').pGet(0.1)
- self.assertEquals(expected, r)
-
- def testMutate(self):
- devices = [ParallelizerTestObject(True) for _ in xrange(0, 10)]
- self.assertTrue(all(d.doReturnTheThing() for d in devices))
- ParallelizerTestObject.parallel(devices).doSetTheThing(False).pFinish(1)
- self.assertTrue(not any(d.doReturnTheThing() for d in devices))
-
- def testAllReturn(self):
- devices = [ParallelizerTestObject(True) for _ in xrange(0, 10)]
- results = ParallelizerTestObject.parallel(
- devices).doReturnTheThing().pGet(1)
- self.assertTrue(isinstance(results, list))
- self.assertEquals(10, len(results))
- self.assertTrue(all(results))
-
- def testAllRaise(self):
- devices = [ParallelizerTestObject(Exception('thing %d' % i))
- for i in xrange(0, 10)]
- p = ParallelizerTestObject.parallel(devices).doRaiseTheThing()
- with self.assertRaises(Exception):
- p.pGet(1)
-
- def testOneFailOthersComplete(self):
- parallel_device_count = 10
- exception_index = 7
- exception_msg = 'thing %d' % exception_index
-
- try:
- completion_files = [tempfile.NamedTemporaryFile(delete=False)
- for _ in xrange(0, parallel_device_count)]
- devices = [
- ParallelizerTestObject(
- i if i != exception_index else Exception(exception_msg),
- completion_files[i].name)
- for i in xrange(0, parallel_device_count)]
- for f in completion_files:
- f.close()
- p = ParallelizerTestObject.parallel(devices)
- with self.assertRaises(Exception) as e:
- p.doRaiseIfExceptionElseSleepFor(2).pGet(3)
- self.assertTrue(exception_msg in str(e.exception))
- for i in xrange(0, parallel_device_count):
- with open(completion_files[i].name) as f:
- if i == exception_index:
- self.assertEquals('', f.read())
- else:
- self.assertEquals('complete', f.read())
- finally:
- for f in completion_files:
- os.remove(f.name)
-
- def testReusable(self):
- devices = [ParallelizerTestObject(True) for _ in xrange(0, 10)]
- p = ParallelizerTestObject.parallel(devices)
- results = p.doReturn(True).pGet(1)
- self.assertTrue(all(results))
- results = p.doReturn(True).pGet(1)
- self.assertTrue(all(results))
- with self.assertRaises(Exception):
- results = p.doRaise(Exception('reusableTest')).pGet(1)
-
- def testContained(self):
- devices = [ParallelizerTestObject(i) for i in xrange(0, 10)]
- results = (ParallelizerTestObject.parallel(devices).helper
- .doReturnStringThing().pGet(1))
- self.assertTrue(isinstance(results, list))
- self.assertEquals(10, len(results))
- for i in xrange(0, 10):
- self.assertEquals(str(i), results[i])
-
- def testGetItem(self):
- devices = [ParallelizerTestObject(range(i, i + 10)) for i in xrange(0, 10)]
- results = ParallelizerTestObject.parallel(devices)[9].pGet(1)
- self.assertEquals(range(9, 19), results)
-
-
-if __name__ == '__main__':
- unittest.main(verbosity=2)
-
diff --git a/third_party/catapult/devil/devil/utils/reraiser_thread.py b/third_party/catapult/devil/devil/utils/reraiser_thread.py
deleted file mode 100644
index 56d95f3937..0000000000
--- a/third_party/catapult/devil/devil/utils/reraiser_thread.py
+++ /dev/null
@@ -1,228 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Thread and ThreadGroup that reraise exceptions on the main thread."""
-# pylint: disable=W0212
-
-import logging
-import sys
-import threading
-import time
-import traceback
-
-from devil.utils import watchdog_timer
-
-
-class TimeoutError(Exception):
- """Module-specific timeout exception."""
- pass
-
-
-def LogThreadStack(thread, error_log_func=logging.critical):
- """Log the stack for the given thread.
-
- Args:
- thread: a threading.Thread instance.
- error_log_func: Logging function when logging errors.
- """
- stack = sys._current_frames()[thread.ident]
- error_log_func('*' * 80)
- error_log_func('Stack dump for thread %r', thread.name)
- error_log_func('*' * 80)
- for filename, lineno, name, line in traceback.extract_stack(stack):
- error_log_func('File: "%s", line %d, in %s', filename, lineno, name)
- if line:
- error_log_func(' %s', line.strip())
- error_log_func('*' * 80)
-
-
-class ReraiserThread(threading.Thread):
- """Thread class that can reraise exceptions."""
-
- def __init__(self, func, args=None, kwargs=None, name=None):
- """Initialize thread.
-
- Args:
- func: callable to call on a new thread.
- args: list of positional arguments for callable, defaults to empty.
- kwargs: dictionary of keyword arguments for callable, defaults to empty.
- name: thread name, defaults to Thread-N.
- """
- if not name and func.__name__ != '<lambda>':
- name = func.__name__
- super(ReraiserThread, self).__init__(name=name)
- if not args:
- args = []
- if not kwargs:
- kwargs = {}
- self.daemon = True
- self._func = func
- self._args = args
- self._kwargs = kwargs
- self._ret = None
- self._exc_info = None
- self._thread_group = None
-
- def ReraiseIfException(self):
- """Reraise exception if an exception was raised in the thread."""
- if self._exc_info:
- raise self._exc_info[0], self._exc_info[1], self._exc_info[2]
-
- def GetReturnValue(self):
- """Reraise exception if present, otherwise get the return value."""
- self.ReraiseIfException()
- return self._ret
-
- # override
- def run(self):
- """Overrides Thread.run() to add support for reraising exceptions."""
- try:
- self._ret = self._func(*self._args, **self._kwargs)
- except: # pylint: disable=W0702
- self._exc_info = sys.exc_info()
-
-
-class ReraiserThreadGroup(object):
- """A group of ReraiserThread objects."""
-
- def __init__(self, threads=None):
- """Initialize thread group.
-
- Args:
- threads: a list of ReraiserThread objects; defaults to empty.
- """
- self._threads = []
- # Set when a thread from one group has called JoinAll on another. It is used
- # to detect when a there is a TimeoutRetryThread active that links to the
- # current thread.
- self.blocked_parent_thread_group = None
- if threads:
- for thread in threads:
- self.Add(thread)
-
- def Add(self, thread):
- """Add a thread to the group.
-
- Args:
- thread: a ReraiserThread object.
- """
- assert thread._thread_group is None
- thread._thread_group = self
- self._threads.append(thread)
-
- def StartAll(self, will_block=False):
- """Start all threads.
-
- Args:
- will_block: Whether the calling thread will subsequently block on this
- thread group. Causes the active ReraiserThreadGroup (if there is one)
- to be marked as blocking on this thread group.
- """
- if will_block:
- # Multiple threads blocking on the same outer thread should not happen in
- # practice.
- assert not self.blocked_parent_thread_group
- self.blocked_parent_thread_group = CurrentThreadGroup()
- for thread in self._threads:
- thread.start()
-
- def _JoinAll(self, watcher=None, timeout=None):
- """Join all threads without stack dumps.
-
- Reraises exceptions raised by the child threads and supports breaking
- immediately on exceptions raised on the main thread.
-
- Args:
- watcher: Watchdog object providing the thread timeout. If none is
- provided, the thread will never be timed out.
- timeout: An optional number of seconds to wait before timing out the join
- operation. This will not time out the threads.
- """
- if watcher is None:
- watcher = watchdog_timer.WatchdogTimer(None)
- alive_threads = self._threads[:]
- end_time = (time.time() + timeout) if timeout else None
- try:
- while alive_threads and (end_time is None or end_time > time.time()):
- for thread in alive_threads[:]:
- if watcher.IsTimedOut():
- raise TimeoutError('Timed out waiting for %d of %d threads.' %
- (len(alive_threads), len(self._threads)))
- # Allow the main thread to periodically check for interrupts.
- thread.join(0.1)
- if not thread.isAlive():
- alive_threads.remove(thread)
- # All threads are allowed to complete before reraising exceptions.
- for thread in self._threads:
- thread.ReraiseIfException()
- finally:
- self.blocked_parent_thread_group = None
-
- def IsAlive(self):
- """Check whether any of the threads are still alive.
-
- Returns:
- Whether any of the threads are still alive.
- """
- return any(t.isAlive() for t in self._threads)
-
- def JoinAll(self, watcher=None, timeout=None,
- error_log_func=logging.critical):
- """Join all threads.
-
- Reraises exceptions raised by the child threads and supports breaking
- immediately on exceptions raised on the main thread. Unfinished threads'
- stacks will be logged on watchdog timeout.
-
- Args:
- watcher: Watchdog object providing the thread timeout. If none is
- provided, the thread will never be timed out.
- timeout: An optional number of seconds to wait before timing out the join
- operation. This will not time out the threads.
- error_log_func: Logging function when logging errors.
- """
- try:
- self._JoinAll(watcher, timeout)
- except TimeoutError:
- error_log_func('Timed out. Dumping threads.')
- for thread in (t for t in self._threads if t.isAlive()):
- LogThreadStack(thread, error_log_func=error_log_func)
- raise
-
- def GetAllReturnValues(self, watcher=None):
- """Get all return values, joining all threads if necessary.
-
- Args:
- watcher: same as in |JoinAll|. Only used if threads are alive.
- """
- if any([t.isAlive() for t in self._threads]):
- self.JoinAll(watcher)
- return [t.GetReturnValue() for t in self._threads]
-
-
-def CurrentThreadGroup():
- """Returns the ReraiserThreadGroup that owns the running thread.
-
- Returns:
- The current thread group, otherwise None.
- """
- current_thread = threading.current_thread()
- if isinstance(current_thread, ReraiserThread):
- return current_thread._thread_group # pylint: disable=no-member
- return None
-
-
-def RunAsync(funcs, watcher=None):
- """Executes the given functions in parallel and returns their results.
-
- Args:
- funcs: List of functions to perform on their own threads.
- watcher: Watchdog object providing timeout, by default waits forever.
-
- Returns:
- A list of return values in the order of the given functions.
- """
- thread_group = ReraiserThreadGroup(ReraiserThread(f) for f in funcs)
- thread_group.StartAll(will_block=True)
- return thread_group.GetAllReturnValues(watcher=watcher)
diff --git a/third_party/catapult/devil/devil/utils/reraiser_thread_unittest.py b/third_party/catapult/devil/devil/utils/reraiser_thread_unittest.py
deleted file mode 100644
index e3c4e6bee8..0000000000
--- a/third_party/catapult/devil/devil/utils/reraiser_thread_unittest.py
+++ /dev/null
@@ -1,117 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Unittests for reraiser_thread.py."""
-
-import threading
-import unittest
-
-from devil.utils import reraiser_thread
-from devil.utils import watchdog_timer
-
-
-class TestException(Exception):
- pass
-
-
-class TestReraiserThread(unittest.TestCase):
- """Tests for reraiser_thread.ReraiserThread."""
-
- def testNominal(self):
- result = [None, None]
-
- def f(a, b=None):
- result[0] = a
- result[1] = b
-
- thread = reraiser_thread.ReraiserThread(f, [1], {'b': 2})
- thread.start()
- thread.join()
- self.assertEqual(result[0], 1)
- self.assertEqual(result[1], 2)
-
- def testRaise(self):
- def f():
- raise TestException
-
- thread = reraiser_thread.ReraiserThread(f)
- thread.start()
- thread.join()
- with self.assertRaises(TestException):
- thread.ReraiseIfException()
-
-
-class TestReraiserThreadGroup(unittest.TestCase):
- """Tests for reraiser_thread.ReraiserThreadGroup."""
-
- def testInit(self):
- ran = [False] * 5
-
- def f(i):
- ran[i] = True
-
- group = reraiser_thread.ReraiserThreadGroup(
- [reraiser_thread.ReraiserThread(f, args=[i]) for i in range(5)])
- group.StartAll()
- group.JoinAll()
- for v in ran:
- self.assertTrue(v)
-
- def testAdd(self):
- ran = [False] * 5
-
- def f(i):
- ran[i] = True
-
- group = reraiser_thread.ReraiserThreadGroup()
- for i in xrange(5):
- group.Add(reraiser_thread.ReraiserThread(f, args=[i]))
- group.StartAll()
- group.JoinAll()
- for v in ran:
- self.assertTrue(v)
-
- def testJoinRaise(self):
- def f():
- raise TestException
- group = reraiser_thread.ReraiserThreadGroup(
- [reraiser_thread.ReraiserThread(f) for _ in xrange(5)])
- group.StartAll()
- with self.assertRaises(TestException):
- group.JoinAll()
-
- def testJoinTimeout(self):
- def f():
- pass
- event = threading.Event()
-
- def g():
- event.wait()
- group = reraiser_thread.ReraiserThreadGroup(
- [reraiser_thread.ReraiserThread(g),
- reraiser_thread.ReraiserThread(f)])
- group.StartAll()
- with self.assertRaises(reraiser_thread.TimeoutError):
- group.JoinAll(watchdog_timer.WatchdogTimer(0.01))
- event.set()
-
-
-class TestRunAsync(unittest.TestCase):
- """Tests for reraiser_thread.RunAsync."""
-
- def testNoArgs(self):
- results = reraiser_thread.RunAsync([])
- self.assertEqual([], results)
-
- def testOneArg(self):
- results = reraiser_thread.RunAsync([lambda: 1])
- self.assertEqual([1], results)
-
- def testTwoArgs(self):
- a, b = reraiser_thread.RunAsync((lambda: 1, lambda: 2))
- self.assertEqual(1, a)
- self.assertEqual(2, b)
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/third_party/catapult/devil/devil/utils/reset_usb.py b/third_party/catapult/devil/devil/utils/reset_usb.py
deleted file mode 100755
index 0335227dca..0000000000
--- a/third_party/catapult/devil/devil/utils/reset_usb.py
+++ /dev/null
@@ -1,111 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import argparse
-import fcntl
-import logging
-import os
-import re
-import sys
-
-if __name__ == '__main__':
- sys.path.append(
- os.path.abspath(os.path.join(os.path.dirname(__file__),
- '..', '..')))
-
-from devil.android import device_errors
-from devil.utils import lsusb
-from devil.utils import run_tests_helper
-
-logger = logging.getLogger(__name__)
-
-_INDENTATION_RE = re.compile(r'^( *)')
-_LSUSB_BUS_DEVICE_RE = re.compile(r'^Bus (\d{3}) Device (\d{3}):')
-_LSUSB_ENTRY_RE = re.compile(r'^ *([^ ]+) +([^ ]+) *([^ ].*)?$')
-_LSUSB_GROUP_RE = re.compile(r'^ *([^ ]+.*):$')
-
-_USBDEVFS_RESET = ord('U') << 8 | 20
-
-
-def reset_usb(bus, device):
- """Reset the USB device with the given bus and device."""
- usb_file_path = '/dev/bus/usb/%03d/%03d' % (bus, device)
- with open(usb_file_path, 'w') as usb_file:
- logger.debug('fcntl.ioctl(%s, %d)', usb_file_path, _USBDEVFS_RESET)
- fcntl.ioctl(usb_file, _USBDEVFS_RESET)
-
-
-def reset_android_usb(serial):
- """Reset the USB device for the given Android device."""
- lsusb_info = lsusb.lsusb()
-
- bus = None
- device = None
- for device_info in lsusb_info:
- device_serial = lsusb.get_lsusb_serial(device_info)
- if device_serial == serial:
- bus = int(device_info.get('bus'))
- device = int(device_info.get('device'))
-
- if bus and device:
- reset_usb(bus, device)
- else:
- raise device_errors.DeviceUnreachableError(
- 'Unable to determine bus(%s) or device(%s) for device %s'
- % (bus, device, serial))
-
-
-def reset_all_android_devices():
- """Reset all USB devices that look like an Android device."""
- _reset_all_matching(lambda i: bool(lsusb.get_lsusb_serial(i)))
-
-
-def _reset_all_matching(condition):
- lsusb_info = lsusb.lsusb()
- for device_info in lsusb_info:
- if int(device_info.get('device')) != 1 and condition(device_info):
- bus = int(device_info.get('bus'))
- device = int(device_info.get('device'))
- try:
- reset_usb(bus, device)
- serial = lsusb.get_lsusb_serial(device_info)
- if serial:
- logger.info(
- 'Reset USB device (bus: %03d, device: %03d, serial: %s)',
- bus, device, serial)
- else:
- logger.info(
- 'Reset USB device (bus: %03d, device: %03d)',
- bus, device)
- except IOError:
- logger.error(
- 'Failed to reset USB device (bus: %03d, device: %03d)',
- bus, device)
-
-
-def main():
- parser = argparse.ArgumentParser()
- parser.add_argument('-v', '--verbose', action='count')
- parser.add_argument('-s', '--serial')
- parser.add_argument('--bus', type=int)
- parser.add_argument('--device', type=int)
- args = parser.parse_args()
-
- run_tests_helper.SetLogLevel(args.verbose)
-
- if args.serial:
- reset_android_usb(args.serial)
- elif args.bus and args.device:
- reset_usb(args.bus, args.device)
- else:
- parser.error('Unable to determine target. '
- 'Specify --serial or BOTH --bus and --device.')
-
- return 0
-
-
-if __name__ == '__main__':
- sys.exit(main())
-
diff --git a/third_party/catapult/devil/devil/utils/run_tests_helper.py b/third_party/catapult/devil/devil/utils/run_tests_helper.py
deleted file mode 100644
index 7df2da6585..0000000000
--- a/third_party/catapult/devil/devil/utils/run_tests_helper.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Helper functions common to native, java and host-driven test runners."""
-
-import logging
-import sys
-import time
-
-
-class CustomFormatter(logging.Formatter):
- """Custom log formatter."""
-
- # override
- def __init__(self, fmt='%(threadName)-4s %(message)s'):
- # Can't use super() because in older Python versions logging.Formatter does
- # not inherit from object.
- logging.Formatter.__init__(self, fmt=fmt)
- self._creation_time = time.time()
-
- # override
- def format(self, record):
- # Can't use super() because in older Python versions logging.Formatter does
- # not inherit from object.
- msg = logging.Formatter.format(self, record)
- if 'MainThread' in msg[:19]:
- msg = msg.replace('MainThread', 'Main', 1)
- timediff = time.time() - self._creation_time
- return '%s %8.3fs %s' % (record.levelname[0], timediff, msg)
-
-
-def SetLogLevel(verbose_count):
- """Sets log level as |verbose_count|."""
- log_level = logging.WARNING # Default.
- if verbose_count == 1:
- log_level = logging.INFO
- elif verbose_count >= 2:
- log_level = logging.DEBUG
- logger = logging.getLogger()
- logger.setLevel(log_level)
- custom_handler = logging.StreamHandler(sys.stdout)
- custom_handler.setFormatter(CustomFormatter())
- logging.getLogger().addHandler(custom_handler)
diff --git a/third_party/catapult/devil/devil/utils/signal_handler.py b/third_party/catapult/devil/devil/utils/signal_handler.py
deleted file mode 100644
index 1230f8df5f..0000000000
--- a/third_party/catapult/devil/devil/utils/signal_handler.py
+++ /dev/null
@@ -1,48 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import contextlib
-import signal
-
-
-@contextlib.contextmanager
-def SignalHandler(signalnum, handler):
- """Sets the signal handler for the given signal in the wrapped context.
-
- Args:
- signum: The signal for which a handler should be added.
- additional_handler: The handler to add.
- """
- existing_handler = signal.getsignal(signalnum)
-
- try:
- signal.signal(signalnum, handler)
- yield
- finally:
- signal.signal(signalnum, existing_handler)
-
-
-@contextlib.contextmanager
-def AddSignalHandler(signalnum, additional_handler):
- """Adds a signal handler for the given signal in the wrapped context.
-
- This runs the new handler after any existing handler rather than
- replacing the existing handler.
-
- Args:
- signum: The signal for which a handler should be added.
- additional_handler: The handler to add.
- """
- existing_handler = signal.getsignal(signalnum)
-
- def handler(signum, frame):
- if callable(existing_handler):
- existing_handler(signum, frame)
- additional_handler(signum, frame)
-
- try:
- signal.signal(signalnum, handler)
- yield
- finally:
- signal.signal(signalnum, existing_handler)
diff --git a/third_party/catapult/devil/devil/utils/test/data/test_serial_map.json b/third_party/catapult/devil/devil/utils/test/data/test_serial_map.json
deleted file mode 100644
index f0682816a0..0000000000
--- a/third_party/catapult/devil/devil/utils/test/data/test_serial_map.json
+++ /dev/null
@@ -1 +0,0 @@
-[{"phone": "Phone1", "battor": "BattOr1"}, {"phone": "Phone2", "battor": "BattOr2"}, {"phone": "Phone3", "battor": "BattOr3"}]
diff --git a/third_party/catapult/devil/devil/utils/timeout_retry.py b/third_party/catapult/devil/devil/utils/timeout_retry.py
deleted file mode 100644
index d2304629e9..0000000000
--- a/third_party/catapult/devil/devil/utils/timeout_retry.py
+++ /dev/null
@@ -1,175 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""A utility to run functions with timeouts and retries."""
-# pylint: disable=W0702
-
-import logging
-import threading
-import time
-
-from devil.utils import reraiser_thread
-from devil.utils import watchdog_timer
-
-logger = logging.getLogger(__name__)
-
-
-class TimeoutRetryThreadGroup(reraiser_thread.ReraiserThreadGroup):
-
- def __init__(self, timeout, threads=None):
- super(TimeoutRetryThreadGroup, self).__init__(threads)
- self._watcher = watchdog_timer.WatchdogTimer(timeout)
-
- def GetWatcher(self):
- """Returns the watchdog keeping track of this thread's time."""
- return self._watcher
-
- def GetElapsedTime(self):
- return self._watcher.GetElapsed()
-
- def GetRemainingTime(self, required=0, msg=None):
- """Get the remaining time before the thread times out.
-
- Useful to send as the |timeout| parameter of async IO operations.
-
- Args:
- required: minimum amount of time that will be required to complete, e.g.,
- some sleep or IO operation.
- msg: error message to show if timing out.
-
- Returns:
- The number of seconds remaining before the thread times out, or None
- if the thread never times out.
-
- Raises:
- reraiser_thread.TimeoutError if the remaining time is less than the
- required time.
- """
- remaining = self._watcher.GetRemaining()
- if remaining is not None and remaining < required:
- if msg is None:
- msg = 'Timeout expired'
- if remaining > 0:
- msg += (', wait of %.1f secs required but only %.1f secs left'
- % (required, remaining))
- raise reraiser_thread.TimeoutError(msg)
- return remaining
-
-
-def CurrentTimeoutThreadGroup():
- """Returns the thread group that owns or is blocked on the active thread.
-
- Returns:
- Returns None if no TimeoutRetryThreadGroup is tracking the current thread.
- """
- thread_group = reraiser_thread.CurrentThreadGroup()
- while thread_group:
- if isinstance(thread_group, TimeoutRetryThreadGroup):
- return thread_group
- thread_group = thread_group.blocked_parent_thread_group
- return None
-
-
-def WaitFor(condition, wait_period=5, max_tries=None):
- """Wait for a condition to become true.
-
- Repeatedly call the function condition(), with no arguments, until it returns
- a true value.
-
- If called within a TimeoutRetryThreadGroup, it cooperates nicely with it.
-
- Args:
- condition: function with the condition to check
- wait_period: number of seconds to wait before retrying to check the
- condition
- max_tries: maximum number of checks to make, the default tries forever
- or until the TimeoutRetryThreadGroup expires.
-
- Returns:
- The true value returned by the condition, or None if the condition was
- not met after max_tries.
-
- Raises:
- reraiser_thread.TimeoutError: if the current thread is a
- TimeoutRetryThreadGroup and the timeout expires.
- """
- condition_name = condition.__name__
- timeout_thread_group = CurrentTimeoutThreadGroup()
- while max_tries is None or max_tries > 0:
- result = condition()
- if max_tries is not None:
- max_tries -= 1
- msg = ['condition', repr(condition_name), 'met' if result else 'not met']
- if timeout_thread_group:
- # pylint: disable=no-member
- msg.append('(%.1fs)' % timeout_thread_group.GetElapsedTime())
- logger.info(' '.join(msg))
- if result:
- return result
- if timeout_thread_group:
- # pylint: disable=no-member
- timeout_thread_group.GetRemainingTime(wait_period,
- msg='Timed out waiting for %r' % condition_name)
- time.sleep(wait_period)
- return None
-
-
-def AlwaysRetry(_exception):
- return True
-
-
-def Run(func, timeout, retries, args=None, kwargs=None, desc=None,
- error_log_func=logging.critical, retry_if_func=AlwaysRetry):
- """Runs the passed function in a separate thread with timeouts and retries.
-
- Args:
- func: the function to be wrapped.
- timeout: the timeout in seconds for each try.
- retries: the number of retries.
- args: list of positional args to pass to |func|.
- kwargs: dictionary of keyword args to pass to |func|.
- desc: An optional description of |func| used in logging. If omitted,
- |func.__name__| will be used.
- error_log_func: Logging function when logging errors.
- retry_if_func: Unary callable that takes an exception and returns
- whether |func| should be retried. Defaults to always retrying.
-
- Returns:
- The return value of func(*args, **kwargs).
- """
- if not args:
- args = []
- if not kwargs:
- kwargs = {}
- if not desc:
- desc = func.__name__
-
- num_try = 1
- while True:
- thread_name = 'TimeoutThread-%d-for-%s' % (num_try,
- threading.current_thread().name)
- child_thread = reraiser_thread.ReraiserThread(lambda: func(*args, **kwargs),
- name=thread_name)
- try:
- thread_group = TimeoutRetryThreadGroup(timeout, threads=[child_thread])
- thread_group.StartAll(will_block=True)
- while True:
- thread_group.JoinAll(watcher=thread_group.GetWatcher(), timeout=60,
- error_log_func=error_log_func)
- if thread_group.IsAlive():
- logger.info('Still working on %s', desc)
- else:
- return thread_group.GetAllReturnValues()[0]
- except reraiser_thread.TimeoutError as e:
- # Timeouts already get their stacks logged.
- if num_try > retries or not retry_if_func(e):
- raise
- # Do not catch KeyboardInterrupt.
- except Exception as e: # pylint: disable=broad-except
- if num_try > retries or not retry_if_func(e):
- raise
- error_log_func(
- '(%s) Exception on %s, attempt %d of %d: %r',
- thread_name, desc, num_try, retries + 1, e)
- num_try += 1
diff --git a/third_party/catapult/devil/devil/utils/timeout_retry_unittest.py b/third_party/catapult/devil/devil/utils/timeout_retry_unittest.py
deleted file mode 100755
index 0eeb31a4f1..0000000000
--- a/third_party/catapult/devil/devil/utils/timeout_retry_unittest.py
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/usr/bin/python
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Unittests for timeout_and_retry.py."""
-
-import logging
-import time
-import unittest
-
-from devil.utils import reraiser_thread
-from devil.utils import timeout_retry
-
-
-_DEFAULT_TIMEOUT = .1
-
-
-class TestException(Exception):
- pass
-
-
-def _CountTries(tries):
- tries[0] += 1
- raise TestException
-
-
-class TestRun(unittest.TestCase):
- """Tests for timeout_retry.Run."""
-
- def testRun(self):
- self.assertTrue(timeout_retry.Run(
- lambda x: x, 30, 3, [True], {}))
-
- def testTimeout(self):
- tries = [0]
-
- def _sleep():
- tries[0] += 1
- time.sleep(1)
-
- self.assertRaises(
- reraiser_thread.TimeoutError, timeout_retry.Run, _sleep, .01, 1,
- error_log_func=logging.debug)
- self.assertEqual(tries[0], 2)
-
- def testRetries(self):
- tries = [0]
- self.assertRaises(
- TestException, timeout_retry.Run, lambda: _CountTries(tries),
- _DEFAULT_TIMEOUT, 3, error_log_func=logging.debug)
- self.assertEqual(tries[0], 4)
-
- def testNoRetries(self):
- tries = [0]
- self.assertRaises(
- TestException, timeout_retry.Run, lambda: _CountTries(tries),
- _DEFAULT_TIMEOUT, 0, error_log_func=logging.debug)
- self.assertEqual(tries[0], 1)
-
- def testReturnValue(self):
- self.assertTrue(timeout_retry.Run(lambda: True, _DEFAULT_TIMEOUT, 3))
-
- def testCurrentTimeoutThreadGroup(self):
- def InnerFunc():
- current_thread_group = timeout_retry.CurrentTimeoutThreadGroup()
- self.assertIsNotNone(current_thread_group)
-
- def InnerInnerFunc():
- self.assertEqual(current_thread_group,
- timeout_retry.CurrentTimeoutThreadGroup())
- return True
- return reraiser_thread.RunAsync((InnerInnerFunc,))[0]
-
- self.assertTrue(timeout_retry.Run(InnerFunc, _DEFAULT_TIMEOUT, 3))
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/third_party/catapult/devil/devil/utils/update_mapping.py b/third_party/catapult/devil/devil/utils/update_mapping.py
deleted file mode 100755
index 6666b9b084..0000000000
--- a/third_party/catapult/devil/devil/utils/update_mapping.py
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import argparse
-import sys
-
-from devil.utils import battor_device_mapping
-
-def parse_options():
- """Parses and checks the command-line options.
-
- Returns:
- A tuple containing the options structure.
- """
- usage = 'Usage: ./update_mapping.py [options]'
- desc = ('Example: ./update_mapping.py -o mapping.json.\n'
- 'This script generates and stores a file that gives the\n'
- 'mapping between phone serial numbers and BattOr serial numbers\n'
- 'Mapping is based on which physical ports on the USB hubs the\n'
- 'devices are plugged in to. For instance, if there are two hubs,\n'
- 'the phone connected to port N on the first hub is mapped to the\n'
- 'BattOr connected to port N on the second hub, for each N.')
- parser = argparse.ArgumentParser(usage=usage, description=desc)
- parser.add_argument('-o', '--output', dest='out_file',
- default='mapping.json', type=str,
- action='store', help='mapping file name')
- parser.add_argument('-u', '--hub', dest='hub_types',
- action='append', choices=['plugable_7port',
- 'plugable_7port_usb3_part2',
- 'plugable_7port_usb3_part3'],
- help='USB hub types.')
- options = parser.parse_args()
- if not options.hub_types:
- options.hub_types = ['plugable_7port', 'plugable_7port_usb3_part2',
- 'plugable_7port_usb3_part3']
- return options
-
-def main():
- options = parse_options()
- battor_device_mapping.GenerateSerialMapFile(options.out_file,
- options.hub_types)
-
-if __name__ == "__main__":
- sys.exit(main())
diff --git a/third_party/catapult/devil/devil/utils/usb_hubs.py b/third_party/catapult/devil/devil/utils/usb_hubs.py
deleted file mode 100644
index 1b9566a356..0000000000
--- a/third_party/catapult/devil/devil/utils/usb_hubs.py
+++ /dev/null
@@ -1,165 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-PLUGABLE_7PORT_LAYOUT = {1:7,
- 2:6,
- 3:5,
- 4:{1:4, 2:3, 3:2, 4:1}}
-
-PLUGABLE_7PORT_USB3_LAYOUT = {1:{1:1, 2:2, 3:3, 4:4},
- 2:5,
- 3:6,
- 4:7}
-
-KEEDOX_LAYOUT = {1:1,
- 2:2,
- 3:3,
- 4:{1:4, 2:5, 3:6, 4:7}}
-
-class HubType(object):
- def __init__(self, id_func, port_mapping):
- """Defines a type of hub.
-
- Args:
- id_func: [USBNode -> bool] is a function that can be run on a node
- to determine if the node represents this type of hub.
- port_mapping: [dict(int:(int|dict))] maps virtual to physical port
- numbers. For instance, {3:1, 1:2, 2:3} means that virtual port 3
- corresponds to physical port 1, virtual port 1 corresponds to physical
- port 2, and virtual port 2 corresponds to physical port 3. In the
- case of hubs with "internal" topology, this is represented by nested
- maps. For instance, {1:{1:1,2:2},2:{1:3,2:4}} means, e.g. that the
- device plugged into physical port 3 will show up as being connected
- to port 1, on a device which is connected to port 2 on the hub.
- """
- self._id_func = id_func
- # v2p = "virtual to physical" ports
- self._v2p_port = port_mapping
-
- def IsType(self, node):
- """Determines if the given Node is a hub of this type.
-
- Args:
- node: [USBNode] Node to check.
- """
- return self._id_func(node)
-
- def GetPhysicalPortToNodeTuples(self, node):
- """Gets devices connected to the physical ports on a hub of this type.
-
- Args:
- node: [USBNode] Node representing a hub of this type.
-
- Yields:
- A series of (int, USBNode) tuples giving a physical port
- and the USBNode connected to it.
-
- Raises:
- ValueError: If the given node isn't a hub of this type.
- """
- if self.IsType(node):
- for res in self._GppHelper(node, self._v2p_port):
- yield res
- else:
- raise ValueError('Node must be a hub of this type')
-
- def _GppHelper(self, node, mapping):
- """Helper function for GetPhysicalPortToNodeMap.
-
- Gets devices connected to physical ports, based on device tree
- rooted at the given node and the mapping between virtual and physical
- ports.
-
- Args:
- node: [USBNode] Root of tree to search for devices.
- mapping: [dict] Mapping between virtual and physical ports.
-
- Yields:
- A series of (int, USBNode) tuples giving a physical port
- and the Node connected to it.
- """
- for (virtual, physical) in mapping.iteritems():
- if node.HasPort(virtual):
- if isinstance(physical, dict):
- for res in self._GppHelper(node.PortToDevice(virtual), physical):
- yield res
- else:
- yield (physical, node.PortToDevice(virtual))
-
-def _is_plugable_7port_hub(node):
- """Check if a node is a Plugable 7-Port Hub
- (Model USB2-HUB7BC)
- The topology of this device is a 4-port hub,
- with another 4-port hub connected on port 4.
- """
- if '1a40:0101' not in node.desc:
- return False
- if not node.HasPort(4):
- return False
- return '1a40:0101' in node.PortToDevice(4).desc
-
-# Plugable 7-Port USB-3 Hubs show up twice in the USB devices list; they have
-# two different "branches", one which has USB2 devices and one which has
-# USB3 devices. The "part2" is the "USB-2" branch of the hub, the
-# "part3" is the "USB-3" branch of the hub.
-
-def _is_plugable_7port_usb3_part2_hub(node):
- """Check if a node is the "USB2 branch" of
- a Plugable 7-Port USB-3 Hub (Model USB3-HUB7BC)
- The topology of this device is a 4-port hub,
- with another 4-port hub connected on port 1.
- """
- if '2109:2811' not in node.desc:
- return False
- if not node.HasPort(1):
- return False
- return '2109:2811' in node.PortToDevice(1).desc
-
-def _is_plugable_7port_usb3_part3_hub(node):
- """Check if a node is the "USB3 branch" of
- a Plugable 7-Port USB-3 Hub (Model USB3-HUB7BC)
- The topology of this device is a 4-port hub,
- with another 4-port hub connected on port 1.
- """
- if '2109:8110' not in node.desc:
- return False
- if not node.HasPort(1):
- return False
- return '2109:8110' in node.PortToDevice(1).desc
-
-def _is_keedox_hub(node):
- """Check if a node is a Keedox hub.
- The topology of this device is a 4-port hub,
- with another 4-port hub connected on port 4.
- """
- if '0bda:5411' not in node.desc:
- return False
- if not node.HasPort(4):
- return False
- return '0bda:5411' in node.PortToDevice(4).desc
-
-
-PLUGABLE_7PORT = HubType(_is_plugable_7port_hub, PLUGABLE_7PORT_LAYOUT)
-PLUGABLE_7PORT_USB3_PART2 = HubType(_is_plugable_7port_usb3_part2_hub,
- PLUGABLE_7PORT_USB3_LAYOUT)
-PLUGABLE_7PORT_USB3_PART3 = HubType(_is_plugable_7port_usb3_part3_hub,
- PLUGABLE_7PORT_USB3_LAYOUT)
-KEEDOX = HubType(_is_keedox_hub, KEEDOX_LAYOUT)
-
-ALL_HUBS = [PLUGABLE_7PORT,
- PLUGABLE_7PORT_USB3_PART2,
- PLUGABLE_7PORT_USB3_PART3,
- KEEDOX]
-
-def GetHubType(type_name):
- if type_name == 'plugable_7port':
- return PLUGABLE_7PORT
- if type_name == 'plugable_7port_usb3_part2':
- return PLUGABLE_7PORT_USB3_PART2
- if type_name == 'plugable_7port_usb3_part3':
- return PLUGABLE_7PORT_USB3_PART3
- if type_name == 'keedox':
- return KEEDOX
- else:
- raise ValueError('Invalid hub type')
diff --git a/third_party/catapult/devil/devil/utils/watchdog_timer.py b/third_party/catapult/devil/devil/utils/watchdog_timer.py
deleted file mode 100644
index 2f4c46455b..0000000000
--- a/third_party/catapult/devil/devil/utils/watchdog_timer.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""WatchdogTimer timeout objects."""
-
-import time
-
-
-class WatchdogTimer(object):
- """A resetable timeout-based watchdog.
-
- This object is threadsafe.
- """
-
- def __init__(self, timeout):
- """Initializes the watchdog.
-
- Args:
- timeout: The timeout in seconds. If timeout is None it will never timeout.
- """
- self._start_time = time.time()
- self._timeout = timeout
-
- def Reset(self):
- """Resets the timeout countdown."""
- self._start_time = time.time()
-
- def GetElapsed(self):
- """Returns the elapsed time of the watchdog."""
- return time.time() - self._start_time
-
- def GetRemaining(self):
- """Returns the remaining time of the watchdog."""
- if self._timeout:
- return self._timeout - self.GetElapsed()
- else:
- return None
-
- def IsTimedOut(self):
- """Whether the watchdog has timed out.
-
- Returns:
- True if the watchdog has timed out, False otherwise.
- """
- remaining = self.GetRemaining()
- return remaining is not None and remaining < 0
diff --git a/third_party/catapult/devil/devil/utils/zip_utils.py b/third_party/catapult/devil/devil/utils/zip_utils.py
deleted file mode 100644
index eaa6a2df01..0000000000
--- a/third_party/catapult/devil/devil/utils/zip_utils.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import logging
-import os
-import zipfile
-
-logger = logging.getLogger(__name__)
-
-
-def WriteToZipFile(zip_file, path, arc_path):
- """Recursively write |path| to |zip_file| as |arc_path|.
-
- zip_file: An open instance of zipfile.ZipFile.
- path: An absolute path to the file or directory to be zipped.
- arc_path: A relative path within the zip file to which the file or directory
- located at |path| should be written.
- """
- if os.path.isdir(path):
- for dir_path, _, file_names in os.walk(path):
- dir_arc_path = os.path.join(arc_path, os.path.relpath(dir_path, path))
- logger.debug('dir: %s -> %s', dir_path, dir_arc_path)
- zip_file.write(dir_path, dir_arc_path, zipfile.ZIP_STORED)
- for f in file_names:
- file_path = os.path.join(dir_path, f)
- file_arc_path = os.path.join(dir_arc_path, f)
- logger.debug('file: %s -> %s', file_path, file_arc_path)
- zip_file.write(file_path, file_arc_path, zipfile.ZIP_DEFLATED)
- else:
- logger.debug('file: %s -> %s', path, arc_path)
- zip_file.write(path, arc_path, zipfile.ZIP_DEFLATED)
-