Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """Provides an interface to communicate with the device via the adb command. | 5 """Provides an interface to communicate with the device via the adb command. |
| 6 | 6 |
| 7 Assumes adb binary is currently on system path. | 7 Assumes adb binary is currently on system path. |
| 8 """ | 8 """ |
| 9 | 9 |
| 10 import collections | 10 import collections |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 54 | 54 |
| 55 # Keycode "enum" suitable for passing to AndroidCommands.SendKey(). | 55 # Keycode "enum" suitable for passing to AndroidCommands.SendKey(). |
| 56 KEYCODE_HOME = 3 | 56 KEYCODE_HOME = 3 |
| 57 KEYCODE_BACK = 4 | 57 KEYCODE_BACK = 4 |
| 58 KEYCODE_DPAD_UP = 19 | 58 KEYCODE_DPAD_UP = 19 |
| 59 KEYCODE_DPAD_DOWN = 20 | 59 KEYCODE_DPAD_DOWN = 20 |
| 60 KEYCODE_DPAD_RIGHT = 22 | 60 KEYCODE_DPAD_RIGHT = 22 |
| 61 KEYCODE_ENTER = 66 | 61 KEYCODE_ENTER = 66 |
| 62 KEYCODE_MENU = 82 | 62 KEYCODE_MENU = 82 |
| 63 | 63 |
| 64 MD5SUM_DEVICE_FOLDER = constants.TEST_EXECUTABLE_DIR + '/md5sum/' | 64 TIMEMODIFIED_DEVICE_FOLDER = constants.TEST_EXECUTABLE_DIR + '/timemodified/' |
|
frankf
2013/06/20 22:52:38
If these are only used in one function, let's move
frankf
2013/06/20 22:52:38
FOLDER -> DIRECTORY
craigdh
2013/07/02 17:26:12
Done.
craigdh
2013/07/02 17:26:12
Done.
| |
| 65 MD5SUM_DEVICE_PATH = MD5SUM_DEVICE_FOLDER + 'md5sum_bin' | 65 TIMEMODIFIED_DEVICE_PATH = TIMEMODIFIED_DEVICE_FOLDER + 'timemodified_bin' |
| 66 MD5SUM_LD_LIBRARY_PATH = 'LD_LIBRARY_PATH=%s' % MD5SUM_DEVICE_FOLDER | 66 TIMEMODIFIED_LD_LIBRARY_PATH = 'LD_LIBRARY_PATH=%s' % TIMEMODIFIED_DEVICE_FOLDER |
| 67 | 67 |
| 68 def GetEmulators(): | 68 def GetEmulators(): |
| 69 """Returns a list of emulators. Does not filter by status (e.g. offline). | 69 """Returns a list of emulators. Does not filter by status (e.g. offline). |
| 70 | 70 |
| 71 Both devices starting with 'emulator' will be returned in below output: | 71 Both devices starting with 'emulator' will be returned in below output: |
| 72 | 72 |
| 73 * daemon not running. starting it now on port 5037 * | 73 * daemon not running. starting it now on port 5037 * |
| 74 * daemon started successfully * | 74 * daemon started successfully * |
| 75 List of devices attached | 75 List of devices attached |
| 76 027c10494100b4d7 device | 76 027c10494100b4d7 device |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 164 if isinstance(utc_offset, str) and len(utc_offset) == 5: | 164 if isinstance(utc_offset, str) and len(utc_offset) == 5: |
| 165 utc_delta = datetime.timedelta(hours=int(utc_offset[1:3]), | 165 utc_delta = datetime.timedelta(hours=int(utc_offset[1:3]), |
| 166 minutes=int(utc_offset[3:5])) | 166 minutes=int(utc_offset[3:5])) |
| 167 if utc_offset[0:1] == '-': | 167 if utc_offset[0:1] == '-': |
| 168 utc_delta = -utc_delta | 168 utc_delta = -utc_delta |
| 169 lastmod -= utc_delta | 169 lastmod -= utc_delta |
| 170 files[filename] = (int(file_match.group('size')), lastmod) | 170 files[filename] = (int(file_match.group('size')), lastmod) |
| 171 return files | 171 return files |
| 172 | 172 |
| 173 | 173 |
| 174 def _ComputeFileListHash(md5sum_output): | 174 def _ComputeFileListTimesModified(timemodified_output): |
| 175 """Returns a list of MD5 strings from the provided md5sum output.""" | 175 """Returns a list of time strings from the provided timemodified output.""" |
| 176 return [line.split(' ')[0] for line in md5sum_output] | 176 return [line.split(' ')[0] for line in timemodified_output] |
| 177 | 177 |
| 178 | 178 |
| 179 def _HasAdbPushSucceeded(command_output): | 179 def _HasAdbPushSucceeded(command_output): |
| 180 """Returns whether adb push has succeeded from the provided output.""" | 180 """Returns whether adb push has succeeded from the provided output.""" |
| 181 if not command_output: | 181 if not command_output: |
| 182 return False | 182 return False |
| 183 # Success looks like this: "3035 KB/s (12512056 bytes in 4.025s)" | 183 # Success looks like this: "3035 KB/s (12512056 bytes in 4.025s)" |
| 184 # Errors look like this: "failed to copy ... " | 184 # Errors look like this: "failed to copy ... " |
| 185 if not re.search('^[0-9]', command_output.splitlines()[-1]): | 185 if not re.search('^[0-9]', command_output.splitlines()[-1]): |
| 186 logging.critical('PUSH FAILED: ' + command_output) | 186 logging.critical('PUSH FAILED: ' + command_output) |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 213 os.environ['PATH'] += os.pathsep + adb_dir | 213 os.environ['PATH'] += os.pathsep + adb_dir |
| 214 self._adb = adb_interface.AdbInterface() | 214 self._adb = adb_interface.AdbInterface() |
| 215 if device: | 215 if device: |
| 216 self._adb.SetTargetSerial(device) | 216 self._adb.SetTargetSerial(device) |
| 217 self._device = device | 217 self._device = device |
| 218 self._logcat = None | 218 self._logcat = None |
| 219 self.logcat_process = None | 219 self.logcat_process = None |
| 220 self._logcat_tmpoutfile = None | 220 self._logcat_tmpoutfile = None |
| 221 self._pushed_files = [] | 221 self._pushed_files = [] |
| 222 self._device_utc_offset = self.RunShellCommand('date +%z')[0] | 222 self._device_utc_offset = self.RunShellCommand('date +%z')[0] |
| 223 self._md5sum_build_dir = '' | 223 self._timemodified_build_dir = '' |
| 224 self._external_storage = '' | 224 self._external_storage = '' |
| 225 self._util_wrapper = '' | 225 self._util_wrapper = '' |
| 226 | 226 |
| 227 def _LogShell(self, cmd): | 227 def _LogShell(self, cmd): |
| 228 """Logs the adb shell command.""" | 228 """Logs the adb shell command.""" |
| 229 if self._device: | 229 if self._device: |
| 230 device_repr = self._device[-4:] | 230 device_repr = self._device[-4:] |
| 231 else: | 231 else: |
| 232 device_repr = '????' | 232 device_repr = '????' |
| 233 logging.info('[%s]> %s', device_repr, cmd) | 233 logging.info('[%s]> %s', device_repr, cmd) |
| (...skipping 455 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 689 self.RunShellCommand('pm clear ' + package) | 689 self.RunShellCommand('pm clear ' + package) |
| 690 | 690 |
| 691 def SendKeyEvent(self, keycode): | 691 def SendKeyEvent(self, keycode): |
| 692 """Sends keycode to the device. | 692 """Sends keycode to the device. |
| 693 | 693 |
| 694 Args: | 694 Args: |
| 695 keycode: Numeric keycode to send (see "enum" at top of file). | 695 keycode: Numeric keycode to send (see "enum" at top of file). |
| 696 """ | 696 """ |
| 697 self.RunShellCommand('input keyevent %d' % keycode) | 697 self.RunShellCommand('input keyevent %d' % keycode) |
| 698 | 698 |
| 699 def CheckMd5Sum(self, local_path, device_path, ignore_paths=False): | 699 def CheckTimesModified(self, local_path, device_path, ignore_paths=False): |
|
frankf
2013/06/20 22:52:38
I would rename this to something like FileOutOfSyn
craigdh
2013/07/02 17:26:12
Done.
craigdh
2013/07/02 17:26:12
Done.
| |
| 700 """Compares the md5sum of a local path against a device path. | 700 """Compares the time modified of a local path against a device path. |
| 701 | 701 |
| 702 Args: | 702 Args: |
| 703 local_path: Path (file or directory) on the host. | 703 local_path: Path (file or directory) on the host. |
| 704 device_path: Path on the device. | 704 device_path: Path on the device. |
| 705 ignore_paths: If False, both the md5sum and the relative paths/names of | 705 ignore_paths: If False, both the time modified and the relative |
| 706 files must match. If True, only the md5sum must match. | 706 paths/names of files must match. If True, only the time modified |
| 707 must match. | |
| 707 | 708 |
| 708 Returns: | 709 Returns: |
| 709 True if the md5sums match. | 710 True if the time the files were modified match or are more recent. |
| 710 """ | 711 """ |
| 711 assert os.path.exists(local_path), 'Local path not found %s' % local_path | 712 assert os.path.exists(local_path), 'Local path not found %s' % local_path |
| 712 | 713 |
| 713 if not self._md5sum_build_dir: | 714 if not self._timemodified_build_dir: |
| 714 default_build_type = os.environ.get('BUILD_TYPE', 'Debug') | 715 default_build_type = os.environ.get('BUILD_TYPE', 'Debug') |
| 715 build_dir = '%s/%s/' % ( | 716 build_dir = '%s/%s/' % ( |
| 716 cmd_helper.OutDirectory().get(), default_build_type) | 717 cmd_helper.OutDirectory().get(), default_build_type) |
|
frankf
2013/06/20 22:52:38
We should really set the out directory once instea
craigdh
2013/07/02 17:26:12
Why? It's not a very heavy call.
| |
| 717 md5sum_dist_path = '%s/md5sum_dist' % build_dir | 718 timemodified_dist_path = '%s/timemodified_dist' % build_dir |
|
frankf
2013/06/20 22:52:38
let's have 'host'/'device' in the variable names t
craigdh
2013/07/02 17:26:12
Done.
| |
| 718 if not os.path.exists(md5sum_dist_path): | 719 if not os.path.exists(timemodified_dist_path): |
| 719 build_dir = '%s/Release/' % cmd_helper.OutDirectory().get() | 720 build_dir = '%s/Release/' % cmd_helper.OutDirectory().get() |
| 720 md5sum_dist_path = '%s/md5sum_dist' % build_dir | 721 timemodified_dist_path = '%s/timemodified_dist' % build_dir |
| 721 assert os.path.exists(md5sum_dist_path), 'Please build md5sum.' | 722 assert os.path.exists(timemodified_dist_path), 'Build timemodified.' |
| 722 command = 'push %s %s' % (md5sum_dist_path, MD5SUM_DEVICE_FOLDER) | 723 command = 'push %s %s' % (timemodified_dist_path, |
| 724 TIMEMODIFIED_DEVICE_FOLDER) | |
| 723 assert _HasAdbPushSucceeded(self._adb.SendCommand(command)) | 725 assert _HasAdbPushSucceeded(self._adb.SendCommand(command)) |
| 724 self._md5sum_build_dir = build_dir | 726 self._timemodified_build_dir = build_dir |
| 725 | 727 |
| 726 self._pushed_files.append(device_path) | 728 self._pushed_files.append(device_path) |
| 727 hashes_on_device = _ComputeFileListHash( | 729 hashes_on_device = _ComputeFileListTimesModified( |
| 728 self.RunShellCommand(MD5SUM_LD_LIBRARY_PATH + ' ' + self._util_wrapper + | 730 self.RunShellCommand(TIMEMODIFIED_LD_LIBRARY_PATH + ' ' + |
| 729 ' ' + MD5SUM_DEVICE_PATH + ' ' + device_path)) | 731 self._util_wrapper + ' ' + TIMEMODIFIED_DEVICE_PATH + ' ' + |
| 732 device_path)) | |
| 730 assert os.path.exists(local_path), 'Local path not found %s' % local_path | 733 assert os.path.exists(local_path), 'Local path not found %s' % local_path |
| 731 md5sum_output = cmd_helper.GetCmdOutput( | 734 timemodified_output = cmd_helper.GetCmdOutput( |
| 732 ['%s/md5sum_bin_host' % self._md5sum_build_dir, local_path]) | 735 ['%s/timemodified_bin_host' % self._timemodified_build_dir, local_path]) |
| 733 hashes_on_host = _ComputeFileListHash(md5sum_output.splitlines()) | 736 hashes_on_host = _ComputeFileListTimesModified( |
| 737 timemodified_output.splitlines()) | |
| 734 | 738 |
| 739 #TODO(craigdh): This doesn't appear to have any effect. | |
|
frankf
2013/06/20 22:52:38
What's the deal here? If not used, can we remove i
craigdh
2013/07/02 17:26:12
Done.
| |
| 735 if ignore_paths: | 740 if ignore_paths: |
| 736 hashes_on_device = [h.split()[0] for h in hashes_on_device] | 741 hashes_on_device = [h.split()[0] for h in hashes_on_device] |
| 737 hashes_on_host = [h.split()[0] for h in hashes_on_host] | 742 hashes_on_host = [h.split()[0] for h in hashes_on_host] |
| 738 | 743 |
| 739 return hashes_on_device == hashes_on_host | 744 if len(hashes_on_device) != len(hashes_on_host): |
| 745 return False | |
| 746 hashes_on_device.sort() | |
| 747 hashes_on_host.sort() | |
| 748 return all(int(dtime) >= int(htime) for dtime, htime in | |
| 749 zip(hashes_on_device, hashes_on_host)) | |
| 740 | 750 |
| 741 def PushIfNeeded(self, local_path, device_path): | 751 def PushIfNeeded(self, local_path, device_path): |
| 742 """Pushes |local_path| to |device_path|. | 752 """Pushes |local_path| to |device_path|. |
| 743 | 753 |
| 744 Works for files and directories. This method skips copying any paths in | 754 Works for files and directories. This method skips copying any paths in |
| 745 |test_data_paths| that already exist on the device with the same hash. | 755 |test_data_paths| that already exist on the device with the same modified |
| 756 time. | |
| 746 | 757 |
| 747 All pushed files can be removed by calling RemovePushedFiles(). | 758 All pushed files can be removed by calling RemovePushedFiles(). |
| 748 """ | 759 """ |
| 749 if self.CheckMd5Sum(local_path, device_path): | 760 if self.CheckTimesModified(local_path, device_path): |
| 750 return | 761 return |
| 751 | 762 |
| 752 # They don't match, so remove everything first and then create it. | 763 # They don't match, so remove everything first and then create it. |
| 753 if os.path.isdir(local_path): | 764 if os.path.isdir(local_path): |
| 754 self.RunShellCommand('rm -r %s' % device_path, timeout_time=2 * 60) | 765 self.RunShellCommand('rm -r %s' % device_path, timeout_time=2 * 60) |
| 755 self.RunShellCommand('mkdir -p %s' % device_path) | 766 self.RunShellCommand('mkdir -p %s' % device_path) |
| 756 | 767 |
| 757 # NOTE: We can't use adb_interface.Push() because it hardcodes a timeout of | 768 # NOTE: We can't use adb_interface.Push() because it hardcodes a timeout of |
| 758 # 60 seconds which isn't sufficient for a lot of users of this method. | 769 # 60 seconds which isn't sufficient for a lot of users of this method. |
| 759 push_command = 'push %s %s' % (local_path, device_path) | 770 push_command = 'push %s %s' % (local_path, device_path) |
| (...skipping 507 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1267 host_dir = os.path.dirname(host_file) | 1278 host_dir = os.path.dirname(host_file) |
| 1268 if not os.path.exists(host_dir): | 1279 if not os.path.exists(host_dir): |
| 1269 os.makedirs(host_dir) | 1280 os.makedirs(host_dir) |
| 1270 device_file = '%s/screenshot.png' % self.GetExternalStorage() | 1281 device_file = '%s/screenshot.png' % self.GetExternalStorage() |
| 1271 self.RunShellCommand('/system/bin/screencap -p %s' % device_file) | 1282 self.RunShellCommand('/system/bin/screencap -p %s' % device_file) |
| 1272 assert self._adb.Pull(device_file, host_file) | 1283 assert self._adb.Pull(device_file, host_file) |
| 1273 assert os.path.exists(host_file) | 1284 assert os.path.exists(host_file) |
| 1274 | 1285 |
| 1275 def SetUtilWrapper(self, util_wrapper): | 1286 def SetUtilWrapper(self, util_wrapper): |
| 1276 """Sets a wrapper prefix to be used when running a locally-built | 1287 """Sets a wrapper prefix to be used when running a locally-built |
| 1277 binary on the device (ex.: md5sum_bin). | 1288 binary on the device (ex.: timemodified_bin). |
| 1278 """ | 1289 """ |
| 1279 self._util_wrapper = util_wrapper | 1290 self._util_wrapper = util_wrapper |
| 1280 | 1291 |
| 1281 def RunInstrumentationTest(self, test, test_package, instr_args, timeout): | 1292 def RunInstrumentationTest(self, test, test_package, instr_args, timeout): |
| 1282 """Runs a single instrumentation test. | 1293 """Runs a single instrumentation test. |
| 1283 | 1294 |
| 1284 Args: | 1295 Args: |
| 1285 test: Test class/method. | 1296 test: Test class/method. |
| 1286 test_package: Package name of test apk. | 1297 test_package: Package name of test apk. |
| 1287 instr_args: Extra key/value to pass to am instrument. | 1298 instr_args: Extra key/value to pass to am instrument. |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1337 """ | 1348 """ |
| 1338 def __init__(self, output): | 1349 def __init__(self, output): |
| 1339 self._output = output | 1350 self._output = output |
| 1340 | 1351 |
| 1341 def write(self, data): | 1352 def write(self, data): |
| 1342 data = data.replace('\r\r\n', '\n') | 1353 data = data.replace('\r\r\n', '\n') |
| 1343 self._output.write(data) | 1354 self._output.write(data) |
| 1344 | 1355 |
| 1345 def flush(self): | 1356 def flush(self): |
| 1346 self._output.flush() | 1357 self._output.flush() |
| OLD | NEW |