Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 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 a variety of device interactions based on adb. | 5 """Provides a variety of device interactions based on adb. |
| 6 | 6 |
| 7 Eventually, this will be based on adb_wrapper. | 7 Eventually, this will be based on adb_wrapper. |
| 8 """ | 8 """ |
| 9 # pylint: disable=unused-argument | 9 # pylint: disable=unused-argument |
| 10 | 10 |
| (...skipping 556 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 567 if not output: | 567 if not output: |
| 568 return '' | 568 return '' |
| 569 elif len(output) == 1: | 569 elif len(output) == 1: |
| 570 return output[0] | 570 return output[0] |
| 571 else: | 571 else: |
| 572 msg = 'one line of output was expected, but got: %s' | 572 msg = 'one line of output was expected, but got: %s' |
| 573 raise device_errors.CommandFailedError(msg % output, str(self)) | 573 raise device_errors.CommandFailedError(msg % output, str(self)) |
| 574 else: | 574 else: |
| 575 return output | 575 return output |
| 576 | 576 |
| 577 def _RunPipedShellCommand(self, script, **kwargs): | |
| 578 PIPESTATUS_LEADER = 'PIPESTATUS: ' | |
| 579 | |
| 580 script += '; echo "%s${PIPESTATUS[@]}"' % PIPESTATUS_LEADER | |
| 581 output = self.RunShellCommand(script, **kwargs) | |
| 582 pipestatus_line = output[-1] | |
| 583 | |
| 584 if not pipestatus_line.startswith(PIPESTATUS_LEADER): | |
| 585 logging.error('Pipe exit statuses of shell script missing.') | |
| 586 raise device_errors.AdbShellCommandFailedError( | |
| 587 script, output, status=None, | |
| 588 device_serial=self.adb.GetDeviceSerial()) | |
| 589 | |
| 590 output = output[:-1] | |
| 591 statuses = [ | |
| 592 int(s) for s in pipestatus_line[len(PIPESTATUS_LEADER):].split()] | |
| 593 if any(statuses): | |
| 594 raise device_errors.AdbShellCommandFailedError( | |
| 595 script, output, status=statuses, | |
| 596 device_serial=self.adb.GetDeviceSerial()) | |
| 597 return output | |
| 598 | |
| 577 @decorators.WithTimeoutAndRetriesFromInstance() | 599 @decorators.WithTimeoutAndRetriesFromInstance() |
| 578 def KillAll(self, process_name, signum=9, as_root=False, blocking=False, | 600 def KillAll(self, process_name, signum=9, as_root=False, blocking=False, |
| 579 timeout=None, retries=None): | 601 timeout=None, retries=None): |
| 580 """Kill all processes with the given name on the device. | 602 """Kill all processes with the given name on the device. |
| 581 | 603 |
| 582 Args: | 604 Args: |
| 583 process_name: A string containing the name of the process to kill. | 605 process_name: A string containing the name of the process to kill. |
| 584 signum: An integer containing the signal number to send to kill. Defaults | 606 signum: An integer containing the signal number to send to kill. Defaults |
| 585 to 9 (SIGKILL). | 607 to 9 (SIGKILL). |
| 586 as_root: A boolean indicating whether the kill should be executed with | 608 as_root: A boolean indicating whether the kill should be executed with |
| 587 root privileges. | 609 root privileges. |
| 588 blocking: A boolean indicating whether we should wait until all processes | 610 blocking: A boolean indicating whether we should wait until all processes |
| 589 with the given |process_name| are dead. | 611 with the given |process_name| are dead. |
| 590 timeout: timeout in seconds | 612 timeout: timeout in seconds |
| 591 retries: number of retries | 613 retries: number of retries |
| 592 | 614 |
| 593 Raises: | 615 Raises: |
| 594 CommandFailedError if no process was killed. | 616 CommandFailedError if no process was killed. |
| 595 CommandTimeoutError on timeout. | 617 CommandTimeoutError on timeout. |
| 596 DeviceUnreachableError on missing device. | 618 DeviceUnreachableError on missing device. |
| 597 """ | 619 """ |
| 598 pids = self._GetPidsImpl(process_name) | 620 pids = self.GetPids(process_name) |
| 599 if not pids: | 621 if not pids: |
| 600 raise device_errors.CommandFailedError( | 622 raise device_errors.CommandFailedError( |
| 601 'No process "%s"' % process_name, str(self)) | 623 'No process "%s"' % process_name, str(self)) |
| 602 | 624 |
| 603 cmd = ['kill', '-%d' % signum] + pids.values() | 625 cmd = ['kill', '-%d' % signum] + pids.values() |
| 604 self.RunShellCommand(cmd, as_root=as_root, check_return=True) | 626 self.RunShellCommand(cmd, as_root=as_root, check_return=True) |
| 605 | 627 |
| 606 if blocking: | 628 if blocking: |
| 607 wait_period = 0.1 | 629 wait_period = 0.1 |
| 608 while self._GetPidsImpl(process_name): | 630 while self.GetPids(process_name): |
| 609 time.sleep(wait_period) | 631 time.sleep(wait_period) |
| 610 | 632 |
| 611 return len(pids) | 633 return len(pids) |
| 612 | 634 |
| 613 @decorators.WithTimeoutAndRetriesFromInstance() | 635 @decorators.WithTimeoutAndRetriesFromInstance() |
| 614 def StartActivity(self, intent_obj, blocking=False, trace_file_name=None, | 636 def StartActivity(self, intent_obj, blocking=False, trace_file_name=None, |
| 615 force_stop=False, timeout=None, retries=None): | 637 force_stop=False, timeout=None, retries=None): |
| 616 """Start package's activity on the device. | 638 """Start package's activity on the device. |
| 617 | 639 |
| 618 Args: | 640 Args: |
| (...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1013 ls_out = self.RunShellCommand(['ls', '-l', device_path], as_root=as_root, | 1035 ls_out = self.RunShellCommand(['ls', '-l', device_path], as_root=as_root, |
| 1014 check_return=True) | 1036 check_return=True) |
| 1015 for line in ls_out: | 1037 for line in ls_out: |
| 1016 m = self._LS_RE.match(line) | 1038 m = self._LS_RE.match(line) |
| 1017 if m and m.group('name') == posixpath.basename(device_path): | 1039 if m and m.group('name') == posixpath.basename(device_path): |
| 1018 size = int(m.group('size')) | 1040 size = int(m.group('size')) |
| 1019 break | 1041 break |
| 1020 else: | 1042 else: |
| 1021 logging.warning('Could not determine size of %s.', device_path) | 1043 logging.warning('Could not determine size of %s.', device_path) |
| 1022 | 1044 |
| 1023 if size is None or size <= self._MAX_ADB_OUTPUT_LENGTH: | 1045 if 0 < size <= self._MAX_ADB_OUTPUT_LENGTH: |
| 1024 return _JoinLines(self.RunShellCommand( | 1046 return _JoinLines(self.RunShellCommand( |
| 1025 ['cat', device_path], as_root=as_root, check_return=True)) | 1047 ['cat', device_path], as_root=as_root, check_return=True)) |
| 1026 elif as_root and self.NeedsSU(): | 1048 elif as_root and self.NeedsSU(): |
| 1027 with device_temp_file.DeviceTempFile(self.adb) as device_temp: | 1049 with device_temp_file.DeviceTempFile(self.adb) as device_temp: |
| 1028 self.RunShellCommand(['cp', device_path, device_temp.name], | 1050 self.RunShellCommand(['cp', device_path, device_temp.name], |
| 1029 as_root=True, check_return=True) | 1051 as_root=True, check_return=True) |
| 1030 return self._ReadFileWithPull(device_temp.name) | 1052 return self._ReadFileWithPull(device_temp.name) |
| 1031 else: | 1053 else: |
| 1032 return self._ReadFileWithPull(device_path) | 1054 return self._ReadFileWithPull(device_path) |
| 1033 | 1055 |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1348 retries: number of retries | 1370 retries: number of retries |
| 1349 | 1371 |
| 1350 Returns: | 1372 Returns: |
| 1351 A dict mapping process name to PID for each process that contained the | 1373 A dict mapping process name to PID for each process that contained the |
| 1352 provided |process_name|. | 1374 provided |process_name|. |
| 1353 | 1375 |
| 1354 Raises: | 1376 Raises: |
| 1355 CommandTimeoutError on timeout. | 1377 CommandTimeoutError on timeout. |
| 1356 DeviceUnreachableError on missing device. | 1378 DeviceUnreachableError on missing device. |
| 1357 """ | 1379 """ |
| 1358 return self._GetPidsImpl(process_name) | 1380 procs_pids = {} |
| 1381 try: | |
| 1382 ps_output = self._RunPipedShellCommand( | |
| 1383 cmd_helper.SingleQuote('ps | grep -F %s' % process_name), | |
| 1384 check_return=False) | |
|
perezju
2015/04/14 14:13:35
nit: I'm ok with this, but maybe _RunPipedShellCom
jbudorick
2015/04/14 16:56:13
After our offline discussion, I realized that chec
| |
| 1385 except device_errors.AdbShellCommandFailedError as e: | |
| 1386 if e.status and not e.status[0]: | |
| 1387 # If ps succeeded but grep failed, there were no processes with the | |
| 1388 # given name. | |
| 1389 return procs_pids | |
| 1390 else: | |
| 1391 raise | |
| 1359 | 1392 |
| 1360 def _GetPidsImpl(self, process_name): | 1393 for line in ps_output: |
| 1361 procs_pids = {} | |
| 1362 for line in self.RunShellCommand('ps', check_return=True): | |
| 1363 try: | 1394 try: |
| 1364 ps_data = line.split() | 1395 ps_data = line.split() |
| 1365 if process_name in ps_data[-1]: | 1396 if process_name in ps_data[-1]: |
| 1366 procs_pids[ps_data[-1]] = ps_data[1] | 1397 procs_pids[ps_data[-1]] = ps_data[1] |
| 1367 except IndexError: | 1398 except IndexError: |
| 1368 pass | 1399 pass |
| 1369 return procs_pids | 1400 return procs_pids |
| 1370 | 1401 |
| 1371 @decorators.WithTimeoutAndRetriesFromInstance() | 1402 @decorators.WithTimeoutAndRetriesFromInstance() |
| 1372 def TakeScreenshot(self, host_path=None, timeout=None, retries=None): | 1403 def TakeScreenshot(self, host_path=None, timeout=None, retries=None): |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1424 except device_errors.CommandFailedError: | 1455 except device_errors.CommandFailedError: |
| 1425 logging.exception('Error getting memory usage from status') | 1456 logging.exception('Error getting memory usage from status') |
| 1426 | 1457 |
| 1427 return result | 1458 return result |
| 1428 | 1459 |
| 1429 def _GetMemoryUsageForPidFromSmaps(self, pid): | 1460 def _GetMemoryUsageForPidFromSmaps(self, pid): |
| 1430 SMAPS_COLUMNS = ( | 1461 SMAPS_COLUMNS = ( |
| 1431 'Size', 'Rss', 'Pss', 'Shared_Clean', 'Shared_Dirty', 'Private_Clean', | 1462 'Size', 'Rss', 'Pss', 'Shared_Clean', 'Shared_Dirty', 'Private_Clean', |
| 1432 'Private_Dirty') | 1463 'Private_Dirty') |
| 1433 | 1464 |
| 1434 showmap_out = self.RunShellCommand( | 1465 showmap_out = self._RunPipedShellCommand( |
| 1435 ['showmap', str(pid)], as_root=True, check_return=True) | 1466 'showmap %d | grep TOTAL' % int(pid), |
| 1436 if not showmap_out: | 1467 as_root=True, check_return=False) |
| 1437 raise device_errors.CommandFailedError('No output from showmap') | |
| 1438 | 1468 |
| 1439 split_totals = showmap_out[-1].split() | 1469 split_totals = showmap_out[-1].split() |
| 1440 if (not split_totals | 1470 if (not split_totals |
| 1441 or len(split_totals) != 9 | 1471 or len(split_totals) != 9 |
| 1442 or split_totals[-1] != 'TOTAL'): | 1472 or split_totals[-1] != 'TOTAL'): |
| 1443 raise device_errors.CommandFailedError( | 1473 raise device_errors.CommandFailedError( |
| 1444 'Invalid output from showmap: %s' % '\n'.join(showmap_out)) | 1474 'Invalid output from showmap: %s' % '\n'.join(showmap_out)) |
| 1445 | 1475 |
| 1446 return dict(itertools.izip(SMAPS_COLUMNS, (int(n) for n in split_totals))) | 1476 return dict(itertools.izip(SMAPS_COLUMNS, (int(n) for n in split_totals))) |
| 1447 | 1477 |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1515 all attached devices will be used. | 1545 all attached devices will be used. |
| 1516 async: If true, returns a Parallelizer that runs operations | 1546 async: If true, returns a Parallelizer that runs operations |
| 1517 asynchronously. | 1547 asynchronously. |
| 1518 | 1548 |
| 1519 Returns: | 1549 Returns: |
| 1520 A Parallelizer operating over |devices|. | 1550 A Parallelizer operating over |devices|. |
| 1521 """ | 1551 """ |
| 1522 if not devices: | 1552 if not devices: |
| 1523 blacklist = device_blacklist.ReadBlacklist() | 1553 blacklist = device_blacklist.ReadBlacklist() |
| 1524 devices = [d for d in adb_wrapper.AdbWrapper.GetDevices() | 1554 devices = [d for d in adb_wrapper.AdbWrapper.GetDevices() |
| 1525 if d.GetDeviceSerial() not in blacklist] | 1555 if d.GetDeviceSerial() not in blacklist] |
|
perezju
2015/04/14 14:13:35
what's this? merged from another CL?
jbudorick
2015/04/14 16:56:12
You're looking at the 2-3 diff, I take it?
perezju
2015/04/15 09:40:43
I guess that was it.
| |
| 1526 if not devices: | 1556 if not devices: |
| 1527 raise device_errors.NoDevicesError() | 1557 raise device_errors.NoDevicesError() |
| 1528 | 1558 |
| 1529 devices = [d if isinstance(d, cls) else cls(d) for d in devices] | 1559 devices = [d if isinstance(d, cls) else cls(d) for d in devices] |
| 1530 if async: | 1560 if async: |
| 1531 return parallelizer.Parallelizer(devices) | 1561 return parallelizer.Parallelizer(devices) |
| 1532 else: | 1562 else: |
| 1533 return parallelizer.SyncParallelizer(devices) | 1563 return parallelizer.SyncParallelizer(devices) |
| 1534 | 1564 |
| 1535 def GetClientCache(self, client_name): | 1565 def GetClientCache(self, client_name): |
| 1536 """Returns client cache.""" | 1566 """Returns client cache.""" |
| 1537 if client_name not in self._client_caches: | 1567 if client_name not in self._client_caches: |
| 1538 self._client_caches[client_name] = {} | 1568 self._client_caches[client_name] = {} |
| 1539 return self._client_caches[client_name] | 1569 return self._client_caches[client_name] |
| 1540 | 1570 |
| 1541 def _ClearCache(self): | 1571 def _ClearCache(self): |
| 1542 """Clears all caches.""" | 1572 """Clears all caches.""" |
| 1543 for client in self._client_caches: | 1573 for client in self._client_caches: |
| 1544 self._client_caches[client].clear() | 1574 self._client_caches[client].clear() |
| 1545 self._cache.clear() | 1575 self._cache.clear() |
| OLD | NEW |