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 |