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 554 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
565 if not output: | 565 if not output: |
566 return '' | 566 return '' |
567 elif len(output) == 1: | 567 elif len(output) == 1: |
568 return output[0] | 568 return output[0] |
569 else: | 569 else: |
570 msg = 'one line of output was expected, but got: %s' | 570 msg = 'one line of output was expected, but got: %s' |
571 raise device_errors.CommandFailedError(msg % output, str(self)) | 571 raise device_errors.CommandFailedError(msg % output, str(self)) |
572 else: | 572 else: |
573 return output | 573 return output |
574 | 574 |
575 def _RunPipedShellCommand(self, script, **kwargs): | |
576 PIPESTATUS_LEADER = 'PIPESTATUS: ' | |
577 | |
578 if not isinstance(script, basestring): | |
579 script = ' '.join(script) | |
perezju
2015/04/14 10:17:29
I'm not sure I link this. The caller should be res
jbudorick
2015/04/14 13:42:46
I wasn't sure about this. Removed.
| |
580 | |
581 script += '; echo "%s${PIPESTATUS[@]}"' % PIPESTATUS_LEADER | |
582 output = self.RunShellCommand(script, **kwargs) | |
583 pipestatus_line = output[-1] | |
584 output = output[:-1] | |
585 | |
586 if not pipestatus_line.startswith(PIPESTATUS_LEADER): | |
587 logging.error('exit statuses of shell script %r missing.', script) | |
perezju
2015/04/14 10:17:29
RunShellCommand should have already logged the scr
jbudorick
2015/04/14 13:42:46
Done.
| |
588 raise device_errors.AdbShellCommandFailedError( | |
589 script, output, status=None, | |
perezju
2015/04/14 10:17:29
if the PIPESTATUS_LEADER is missing, maybe we want
jbudorick
2015/04/14 13:42:46
moved output = output[:-1] below this check
| |
590 device_serial=self.adb.GetDeviceSerial()) | |
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 | |
575 @decorators.WithTimeoutAndRetriesFromInstance() | 599 @decorators.WithTimeoutAndRetriesFromInstance() |
576 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, |
577 timeout=None, retries=None): | 601 timeout=None, retries=None): |
578 """Kill all processes with the given name on the device. | 602 """Kill all processes with the given name on the device. |
579 | 603 |
580 Args: | 604 Args: |
581 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. |
582 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 |
583 to 9 (SIGKILL). | 607 to 9 (SIGKILL). |
584 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 |
585 root privileges. | 609 root privileges. |
586 blocking: A boolean indicating whether we should wait until all processes | 610 blocking: A boolean indicating whether we should wait until all processes |
587 with the given |process_name| are dead. | 611 with the given |process_name| are dead. |
588 timeout: timeout in seconds | 612 timeout: timeout in seconds |
589 retries: number of retries | 613 retries: number of retries |
590 | 614 |
591 Raises: | 615 Raises: |
592 CommandFailedError if no process was killed. | 616 CommandFailedError if no process was killed. |
593 CommandTimeoutError on timeout. | 617 CommandTimeoutError on timeout. |
594 DeviceUnreachableError on missing device. | 618 DeviceUnreachableError on missing device. |
595 """ | 619 """ |
596 pids = self._GetPidsImpl(process_name) | 620 pids = self.GetPids(process_name) |
597 if not pids: | 621 if not pids: |
598 raise device_errors.CommandFailedError( | 622 raise device_errors.CommandFailedError( |
599 'No process "%s"' % process_name, str(self)) | 623 'No process "%s"' % process_name, str(self)) |
600 | 624 |
601 cmd = ['kill', '-%d' % signum] + pids.values() | 625 cmd = ['kill', '-%d' % signum] + pids.values() |
602 self.RunShellCommand(cmd, as_root=as_root, check_return=True) | 626 self.RunShellCommand(cmd, as_root=as_root, check_return=True) |
603 | 627 |
604 if blocking: | 628 if blocking: |
605 wait_period = 0.1 | 629 wait_period = 0.1 |
606 while self._GetPidsImpl(process_name): | 630 while self.GetPids(process_name): |
607 time.sleep(wait_period) | 631 time.sleep(wait_period) |
608 | 632 |
609 return len(pids) | 633 return len(pids) |
610 | 634 |
611 @decorators.WithTimeoutAndRetriesFromInstance() | 635 @decorators.WithTimeoutAndRetriesFromInstance() |
612 def StartActivity(self, intent_obj, blocking=False, trace_file_name=None, | 636 def StartActivity(self, intent_obj, blocking=False, trace_file_name=None, |
613 force_stop=False, timeout=None, retries=None): | 637 force_stop=False, timeout=None, retries=None): |
614 """Start package's activity on the device. | 638 """Start package's activity on the device. |
615 | 639 |
616 Args: | 640 Args: |
(...skipping 394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1011 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, |
1012 check_return=True) | 1036 check_return=True) |
1013 for line in ls_out: | 1037 for line in ls_out: |
1014 m = self._LS_RE.match(line) | 1038 m = self._LS_RE.match(line) |
1015 if m and m.group('name') == posixpath.basename(device_path): | 1039 if m and m.group('name') == posixpath.basename(device_path): |
1016 size = int(m.group('size')) | 1040 size = int(m.group('size')) |
1017 break | 1041 break |
1018 else: | 1042 else: |
1019 logging.warning('Could not determine size of %s.', device_path) | 1043 logging.warning('Could not determine size of %s.', device_path) |
1020 | 1044 |
1021 if size is None or size <= self._MAX_ADB_OUTPUT_LENGTH: | 1045 if size > 0 and size <= self._MAX_ADB_OUTPUT_LENGTH: |
perezju
2015/04/14 10:17:29
I think you can write this as: 0 < size <= self._M
jbudorick
2015/04/14 13:42:46
this is sorcery
done
| |
1022 return _JoinLines(self.RunShellCommand( | 1046 return _JoinLines(self.RunShellCommand( |
1023 ['cat', device_path], as_root=as_root, check_return=True)) | 1047 ['cat', device_path], as_root=as_root, check_return=True)) |
1024 elif as_root and self.NeedsSU(): | 1048 elif as_root and self.NeedsSU(): |
1025 with device_temp_file.DeviceTempFile(self.adb) as device_temp: | 1049 with device_temp_file.DeviceTempFile(self.adb) as device_temp: |
1026 self.RunShellCommand(['cp', device_path, device_temp.name], | 1050 self.RunShellCommand(['cp', device_path, device_temp.name], |
1027 as_root=True, check_return=True) | 1051 as_root=True, check_return=True) |
1028 return self._ReadFileWithPull(device_temp.name) | 1052 return self._ReadFileWithPull(device_temp.name) |
1029 else: | 1053 else: |
1030 return self._ReadFileWithPull(device_path) | 1054 return self._ReadFileWithPull(device_path) |
1031 | 1055 |
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1346 retries: number of retries | 1370 retries: number of retries |
1347 | 1371 |
1348 Returns: | 1372 Returns: |
1349 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 |
1350 provided |process_name|. | 1374 provided |process_name|. |
1351 | 1375 |
1352 Raises: | 1376 Raises: |
1353 CommandTimeoutError on timeout. | 1377 CommandTimeoutError on timeout. |
1354 DeviceUnreachableError on missing device. | 1378 DeviceUnreachableError on missing device. |
1355 """ | 1379 """ |
1356 return self._GetPidsImpl(process_name) | 1380 procs_pids = {} |
1381 try: | |
1382 ps_output = self._RunPipedShellCommand( | |
1383 'ps | grep -F %s' % process_name, check_return=True) | |
perezju
2015/04/14 10:17:29
use cmd_helper.SingleQuote(process_name)
jbudorick
2015/04/14 13:42:46
Done.
| |
1384 except device_errors.AdbShellCommandFailedError as e: | |
perezju
2015/04/14 10:17:29
just to clarify, what is the relationship between
jbudorick
2015/04/14 13:42:46
I'm not sure whether $? is the same as the last it
| |
1385 if e.status and not e.status[0]: | |
1386 # If ps succeeded but grep failed, there were no processes with the | |
1387 # given name. | |
1388 return procs_pids | |
1389 else: | |
1390 raise | |
1357 | 1391 |
1358 def _GetPidsImpl(self, process_name): | 1392 for line in ps_output: |
1359 procs_pids = {} | |
1360 for line in self.RunShellCommand('ps', check_return=True): | |
1361 try: | 1393 try: |
1362 ps_data = line.split() | 1394 ps_data = line.split() |
1363 if process_name in ps_data[-1]: | 1395 if process_name in ps_data[-1]: |
1364 procs_pids[ps_data[-1]] = ps_data[1] | 1396 procs_pids[ps_data[-1]] = ps_data[1] |
1365 except IndexError: | 1397 except IndexError: |
1366 pass | 1398 pass |
1367 return procs_pids | 1399 return procs_pids |
1368 | 1400 |
1369 @decorators.WithTimeoutAndRetriesFromInstance() | 1401 @decorators.WithTimeoutAndRetriesFromInstance() |
1370 def TakeScreenshot(self, host_path=None, timeout=None, retries=None): | 1402 def TakeScreenshot(self, host_path=None, timeout=None, retries=None): |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1422 except device_errors.CommandFailedError: | 1454 except device_errors.CommandFailedError: |
1423 logging.exception('Error getting memory usage from status') | 1455 logging.exception('Error getting memory usage from status') |
1424 | 1456 |
1425 return result | 1457 return result |
1426 | 1458 |
1427 def _GetMemoryUsageForPidFromSmaps(self, pid): | 1459 def _GetMemoryUsageForPidFromSmaps(self, pid): |
1428 SMAPS_COLUMNS = ( | 1460 SMAPS_COLUMNS = ( |
1429 'Size', 'Rss', 'Pss', 'Shared_Clean', 'Shared_Dirty', 'Private_Clean', | 1461 'Size', 'Rss', 'Pss', 'Shared_Clean', 'Shared_Dirty', 'Private_Clean', |
1430 'Private_Dirty') | 1462 'Private_Dirty') |
1431 | 1463 |
1432 showmap_out = self.RunShellCommand( | 1464 showmap_out = self._RunPipedShellCommand( |
1433 ['showmap', str(pid)], as_root=True, check_return=True) | 1465 'showmap %s | grep TOTAL' % str(pid), as_root=True, check_return=True) |
perezju
2015/04/14 10:17:29
maybe rewrite as: 'showmap %d | grep TOTAL' % pid
perezju
2015/04/14 10:49:19
actually, maybe: 'showmap %d | grep TOTAL' % int(p
jbudorick
2015/04/14 13:42:46
Done.
| |
1434 if not showmap_out: | |
1435 raise device_errors.CommandFailedError('No output from showmap') | |
1436 | 1466 |
1437 split_totals = showmap_out[-1].split() | 1467 split_totals = showmap_out[-1].split() |
1438 if (not split_totals | 1468 if (not split_totals |
1439 or len(split_totals) != 9 | 1469 or len(split_totals) != 9 |
1440 or split_totals[-1] != 'TOTAL'): | 1470 or split_totals[-1] != 'TOTAL'): |
1441 raise device_errors.CommandFailedError( | 1471 raise device_errors.CommandFailedError( |
1442 'Invalid output from showmap: %s' % '\n'.join(showmap_out)) | 1472 'Invalid output from showmap: %s' % '\n'.join(showmap_out)) |
1443 | 1473 |
1444 return dict(itertools.izip(SMAPS_COLUMNS, (int(n) for n in split_totals))) | 1474 return dict(itertools.izip(SMAPS_COLUMNS, (int(n) for n in split_totals))) |
1445 | 1475 |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1531 """Returns client cache.""" | 1561 """Returns client cache.""" |
1532 if client_name not in self._client_caches: | 1562 if client_name not in self._client_caches: |
1533 self._client_caches[client_name] = {} | 1563 self._client_caches[client_name] = {} |
1534 return self._client_caches[client_name] | 1564 return self._client_caches[client_name] |
1535 | 1565 |
1536 def _ClearCache(self): | 1566 def _ClearCache(self): |
1537 """Clears all caches.""" | 1567 """Clears all caches.""" |
1538 for client in self._client_caches: | 1568 for client in self._client_caches: |
1539 self._client_caches[client].clear() | 1569 self._client_caches[client].clear() |
1540 self._cache.clear() | 1570 self._cache.clear() |
OLD | NEW |