• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2013 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import logging
6
7from telemetry import decorators
8from telemetry.core import cros_interface
9from telemetry.core import platform
10from telemetry.core import util
11from telemetry.internal.forwarders import cros_forwarder
12from telemetry.internal.platform import cros_device
13from telemetry.internal.platform import linux_based_platform_backend
14from telemetry.internal.platform.power_monitor import cros_power_monitor
15from telemetry.internal.util import ps_util
16
17
18class CrosPlatformBackend(
19    linux_based_platform_backend.LinuxBasedPlatformBackend):
20  def __init__(self, device=None):
21    super(CrosPlatformBackend, self).__init__(device)
22    if device and not device.is_local:
23      self._cri = cros_interface.CrOSInterface(
24          device.host_name, device.ssh_port, device.ssh_identity)
25      self._cri.TryLogin()
26    else:
27      self._cri = cros_interface.CrOSInterface()
28    self._powermonitor = cros_power_monitor.CrosPowerMonitor(self)
29
30  @classmethod
31  def IsPlatformBackendForHost(cls):
32    return util.IsRunningOnCrosDevice()
33
34  @classmethod
35  def SupportsDevice(cls, device):
36    return isinstance(device, cros_device.CrOSDevice)
37
38  @classmethod
39  def CreatePlatformForDevice(cls, device, finder_options):
40    assert cls.SupportsDevice(device)
41    return platform.Platform(CrosPlatformBackend(device))
42
43  @property
44  def cri(self):
45    return self._cri
46
47  @property
48  def forwarder_factory(self):
49    if not self._forwarder_factory:
50      self._forwarder_factory = cros_forwarder.CrOsForwarderFactory(self._cri)
51    return self._forwarder_factory
52
53  def GetRemotePort(self, port):
54    if self._cri.local:
55      return port
56    return self._cri.GetRemotePort()
57
58  def IsThermallyThrottled(self):
59    raise NotImplementedError()
60
61  def HasBeenThermallyThrottled(self):
62    raise NotImplementedError()
63
64  def RunCommand(self, args):
65    if not isinstance(args, list):
66      args = [args]
67    stdout, stderr = self._cri.RunCmdOnDevice(args)
68    if stderr:
69      raise IOError('Failed to run: cmd = %s, stderr = %s' %
70                    (str(args), stderr))
71    return stdout
72
73  def GetFileContents(self, filename):
74    try:
75      return self.RunCommand(['cat', filename])
76    except AssertionError:
77      return ''
78
79  def GetPsOutput(self, columns, pid=None):
80    return ps_util.GetPsOutputWithPlatformBackend(self, columns, pid)
81
82  @staticmethod
83  def ParseCStateSample(sample):
84    sample_stats = {}
85    for cpu in sample:
86      values = sample[cpu].splitlines()
87      # There are three values per state after excluding the single time value.
88      num_states = (len(values) - 1) / 3
89      names = values[:num_states]
90      times = values[num_states:2 * num_states]
91      latencies = values[2 * num_states:]
92      # The last line in the sample contains the time.
93      cstates = {'C0': int(values[-1]) * 10 ** 6}
94      for i, state in enumerate(names):
95        if names[i] == 'POLL' and not int(latencies[i]):
96          # C0 state. Kernel stats aren't right, so calculate by
97          # subtracting all other states from total time (using epoch
98          # timer since we calculate differences in the end anyway).
99          # NOTE: Only x86 lists C0 under cpuidle, ARM does not.
100          continue
101        cstates['C0'] -= int(times[i])
102        if names[i] == '<null>':
103          # Kernel race condition that can happen while a new C-state gets
104          # added (e.g. AC->battery). Don't know the 'name' of the state
105          # yet, but its 'time' would be 0 anyway.
106          continue
107        cstates[state] = int(times[i])
108      sample_stats[cpu] = cstates
109    return sample_stats
110
111  def GetDeviceTypeName(self):
112    return self._cri.GetDeviceTypeName()
113
114  @decorators.Cache
115  def GetArchName(self):
116    return self._cri.GetArchName()
117
118  def GetOSName(self):
119    return 'chromeos'
120
121  def GetOSVersionName(self):
122    return ''  # TODO: Implement this.
123
124  def GetChildPids(self, pid):
125    """Returns a list of child pids of |pid|."""
126    all_process_info = self._cri.ListProcesses()
127    processes = [(curr_pid, curr_ppid, curr_state)
128                 for curr_pid, _, curr_ppid, curr_state in all_process_info]
129    return ps_util.GetChildPids(processes, pid)
130
131  def GetCommandLine(self, pid):
132    procs = self._cri.ListProcesses()
133    return next((proc[1] for proc in procs if proc[0] == pid), None)
134
135  def CanFlushIndividualFilesFromSystemCache(self):
136    return True
137
138  def FlushEntireSystemCache(self):
139    raise NotImplementedError()
140
141  def FlushSystemCacheForDirectory(self, directory):
142    flush_command = (
143        '/usr/local/telemetry/src/src/out/Release/clear_system_cache')
144    self.RunCommand(['chmod', '+x', flush_command])
145    self.RunCommand([flush_command, '--recurse', directory])
146
147  def CanMonitorPower(self):
148    return self._powermonitor.CanMonitorPower()
149
150  def StartMonitoringPower(self, browser):
151    self._powermonitor.StartMonitoringPower(browser)
152
153  def StopMonitoringPower(self):
154    return self._powermonitor.StopMonitoringPower()
155
156  def PathExists(self, path, timeout=None, retries=None):
157    if timeout or retries:
158      logging.warning(
159          'PathExists: params timeout and retries are not support on CrOS.')
160    return self._cri.FileExistsOnDevice(path)
161
162  def CanTakeScreenshot(self):
163    # crbug.com/609001: screenshots don't work on VMs.
164    return not self.cri.IsRunningOnVM()
165
166  def TakeScreenshot(self, file_path):
167    return self._cri.TakeScreenshot(file_path)
168