| 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 1421 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1432 | 1432 |
| 1433 Parameters passed to this function are passed directly to | 1433 Parameters passed to this function are passed directly to |
| 1434 |logcat_monitor.LogcatMonitor| and are documented there. | 1434 |logcat_monitor.LogcatMonitor| and are documented there. |
| 1435 | 1435 |
| 1436 Args: | 1436 Args: |
| 1437 timeout: timeout in seconds | 1437 timeout: timeout in seconds |
| 1438 retries: number of retries | 1438 retries: number of retries |
| 1439 """ | 1439 """ |
| 1440 return logcat_monitor.LogcatMonitor(self.adb, *args, **kwargs) | 1440 return logcat_monitor.LogcatMonitor(self.adb, *args, **kwargs) |
| 1441 | 1441 |
| 1442 # TODO(rnephew): Remove when battery_utils is switched to. | |
| 1443 @decorators.WithTimeoutAndRetriesFromInstance() | |
| 1444 def GetBatteryInfo(self, timeout=None, retries=None): | |
| 1445 """Gets battery info for the device. | |
| 1446 | |
| 1447 Args: | |
| 1448 timeout: timeout in seconds | |
| 1449 retries: number of retries | |
| 1450 Returns: | |
| 1451 A dict containing various battery information as reported by dumpsys | |
| 1452 battery. | |
| 1453 """ | |
| 1454 result = {} | |
| 1455 # Skip the first line, which is just a header. | |
| 1456 for line in self.RunShellCommand( | |
| 1457 ['dumpsys', 'battery'], check_return=True)[1:]: | |
| 1458 # If usb charging has been disabled, an extra line of header exists. | |
| 1459 if 'UPDATES STOPPED' in line: | |
| 1460 logging.warning('Dumpsys battery not receiving updates. ' | |
| 1461 'Run dumpsys battery reset if this is in error.') | |
| 1462 elif ':' not in line: | |
| 1463 logging.warning('Unknown line found in dumpsys battery.') | |
| 1464 logging.warning(line) | |
| 1465 else: | |
| 1466 k, v = line.split(': ', 1) | |
| 1467 result[k.strip()] = v.strip() | |
| 1468 return result | |
| 1469 | |
| 1470 # TODO(rnephew): Remove when battery_utils is switched to. | |
| 1471 @decorators.WithTimeoutAndRetriesFromInstance() | |
| 1472 def GetCharging(self, timeout=None, retries=None): | |
| 1473 """Gets the charging state of the device. | |
| 1474 | |
| 1475 Args: | |
| 1476 timeout: timeout in seconds | |
| 1477 retries: number of retries | |
| 1478 Returns: | |
| 1479 True if the device is charging, false otherwise. | |
| 1480 """ | |
| 1481 battery_info = self.GetBatteryInfo() | |
| 1482 for k in ('AC powered', 'USB powered', 'Wireless powered'): | |
| 1483 if (k in battery_info and | |
| 1484 battery_info[k].lower() in ('true', '1', 'yes')): | |
| 1485 return True | |
| 1486 return False | |
| 1487 | |
| 1488 # TODO(rnephew): Remove when battery_utils is switched to. | |
| 1489 @decorators.WithTimeoutAndRetriesFromInstance() | |
| 1490 def SetCharging(self, enabled, timeout=None, retries=None): | |
| 1491 """Enables or disables charging on the device. | |
| 1492 | |
| 1493 Args: | |
| 1494 enabled: A boolean indicating whether charging should be enabled or | |
| 1495 disabled. | |
| 1496 timeout: timeout in seconds | |
| 1497 retries: number of retries | |
| 1498 """ | |
| 1499 if 'charging_config' not in self._cache: | |
| 1500 for c in _CONTROL_CHARGING_COMMANDS: | |
| 1501 if self.FileExists(c['witness_file']): | |
| 1502 self._cache['charging_config'] = c | |
| 1503 break | |
| 1504 else: | |
| 1505 raise device_errors.CommandFailedError( | |
| 1506 'Unable to find charging commands.') | |
| 1507 | |
| 1508 if enabled: | |
| 1509 command = self._cache['charging_config']['enable_command'] | |
| 1510 else: | |
| 1511 command = self._cache['charging_config']['disable_command'] | |
| 1512 | |
| 1513 def set_and_verify_charging(): | |
| 1514 self.RunShellCommand(command, check_return=True) | |
| 1515 return self.GetCharging() == enabled | |
| 1516 | |
| 1517 timeout_retry.WaitFor(set_and_verify_charging, wait_period=1) | |
| 1518 | |
| 1519 # TODO(rnephew): Remove when battery_utils is switched to. | |
| 1520 @decorators.WithTimeoutAndRetriesFromInstance() | |
| 1521 def DisableBatteryUpdates(self, timeout=None, retries=None): | |
| 1522 """ Resets battery data and makes device appear like it is not | |
| 1523 charging so that it will collect power data since last charge. | |
| 1524 | |
| 1525 Args: | |
| 1526 timeout: timeout in seconds | |
| 1527 retries: number of retries | |
| 1528 """ | |
| 1529 def battery_updates_disabled(): | |
| 1530 return self.GetCharging() is False | |
| 1531 | |
| 1532 self.RunShellCommand( | |
| 1533 ['dumpsys', 'batterystats', '--reset'], check_return=True) | |
| 1534 battery_data = self.RunShellCommand( | |
| 1535 ['dumpsys', 'batterystats', '--charged', '--checkin'], | |
| 1536 check_return=True) | |
| 1537 ROW_TYPE_INDEX = 3 | |
| 1538 PWI_POWER_INDEX = 5 | |
| 1539 for line in battery_data: | |
| 1540 l = line.split(',') | |
| 1541 if (len(l) > PWI_POWER_INDEX and l[ROW_TYPE_INDEX] == 'pwi' | |
| 1542 and l[PWI_POWER_INDEX] != 0): | |
| 1543 raise device_errors.CommandFailedError( | |
| 1544 'Non-zero pmi value found after reset.') | |
| 1545 self.RunShellCommand(['dumpsys', 'battery', 'set', 'usb', '0'], | |
| 1546 check_return=True) | |
| 1547 timeout_retry.WaitFor(battery_updates_disabled, wait_period=1) | |
| 1548 | |
| 1549 # TODO(rnephew): Remove when battery_utils is switched to. | |
| 1550 @decorators.WithTimeoutAndRetriesFromInstance() | |
| 1551 def EnableBatteryUpdates(self, timeout=None, retries=None): | |
| 1552 """ Restarts device charging so that dumpsys no longer collects power data. | |
| 1553 | |
| 1554 Args: | |
| 1555 timeout: timeout in seconds | |
| 1556 retries: number of retries | |
| 1557 """ | |
| 1558 def battery_updates_enabled(): | |
| 1559 return self.GetCharging() is True | |
| 1560 | |
| 1561 self.RunShellCommand(['dumpsys', 'battery', 'set', 'usb', '1'], | |
| 1562 check_return=True) | |
| 1563 self.RunShellCommand(['dumpsys', 'battery', 'reset'], check_return=True) | |
| 1564 timeout_retry.WaitFor(battery_updates_enabled, wait_period=1) | |
| 1565 | |
| 1566 # TODO(rnephew): Remove when battery_utils is switched to. | |
| 1567 @contextlib.contextmanager | |
| 1568 def BatteryMeasurement(self, timeout=None, retries=None): | |
| 1569 """Context manager that enables battery data collection. It makes | |
| 1570 the device appear to stop charging so that dumpsys will start collecting | |
| 1571 power data since last charge. Once the with block is exited, charging is | |
| 1572 resumed and power data since last charge is no longer collected. | |
| 1573 | |
| 1574 Only for devices L and higher. | |
| 1575 | |
| 1576 Example usage: | |
| 1577 with BatteryMeasurement(): | |
| 1578 browser_actions() | |
| 1579 get_power_data() # report usage within this block | |
| 1580 after_measurements() # Anything that runs after power | |
| 1581 # measurements are collected | |
| 1582 | |
| 1583 Args: | |
| 1584 timeout: timeout in seconds | |
| 1585 retries: number of retries | |
| 1586 """ | |
| 1587 if self.build_version_sdk < constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP: | |
| 1588 raise device_errors.CommandFailedError('Device must be L or higher.') | |
| 1589 try: | |
| 1590 self.DisableBatteryUpdates(timeout=timeout, retries=retries) | |
| 1591 yield | |
| 1592 finally: | |
| 1593 self.EnableBatteryUpdates(timeout=timeout, retries=retries) | |
| 1594 | |
| 1595 @decorators.WithTimeoutAndRetriesFromInstance() | 1442 @decorators.WithTimeoutAndRetriesFromInstance() |
| 1596 def GetDevicePieWrapper(self, timeout=None, retries=None): | 1443 def GetDevicePieWrapper(self, timeout=None, retries=None): |
| 1597 """Gets the absolute path to the run_pie wrapper on the device. | 1444 """Gets the absolute path to the run_pie wrapper on the device. |
| 1598 | 1445 |
| 1599 We have to build our device executables to be PIE, but they need to be able | 1446 We have to build our device executables to be PIE, but they need to be able |
| 1600 to run on versions of android that don't support PIE (i.e. ICS and below). | 1447 to run on versions of android that don't support PIE (i.e. ICS and below). |
| 1601 To do so, we push a wrapper to the device that lets older android versions | 1448 To do so, we push a wrapper to the device that lets older android versions |
| 1602 run PIE executables. This method pushes that wrapper to the device if | 1449 run PIE executables. This method pushes that wrapper to the device if |
| 1603 necessary and returns the path to it. | 1450 necessary and returns the path to it. |
| 1604 | 1451 |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1658 """Returns client cache.""" | 1505 """Returns client cache.""" |
| 1659 if client_name not in self._client_caches: | 1506 if client_name not in self._client_caches: |
| 1660 self._client_caches[client_name] = {} | 1507 self._client_caches[client_name] = {} |
| 1661 return self._client_caches[client_name] | 1508 return self._client_caches[client_name] |
| 1662 | 1509 |
| 1663 def _ClearCache(self): | 1510 def _ClearCache(self): |
| 1664 """Clears all caches.""" | 1511 """Clears all caches.""" |
| 1665 for client in self._client_caches: | 1512 for client in self._client_caches: |
| 1666 self._client_caches[client].clear() | 1513 self._client_caches[client].clear() |
| 1667 self._cache.clear() | 1514 self._cache.clear() |
| OLD | NEW |