Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(173)

Side by Side Diff: build/android/pylib/device/device_utils.py

Issue 1077173002: [Android] Tune DeviceUtils commands that are prone to large outputs. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: PIPESTATUS Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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()
OLDNEW
« no previous file with comments | « build/android/pylib/device/device_errors.py ('k') | build/android/pylib/device/device_utils_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698