Home | History | Annotate | Download | only in platform
      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 
      5 import logging
      6 
      7 from telemetry import decorators
      8 from telemetry.core import cros_interface
      9 from telemetry.core import platform
     10 from telemetry.core import util
     11 from telemetry.internal.forwarders import cros_forwarder
     12 from telemetry.internal.platform import cros_device
     13 from telemetry.internal.platform import linux_based_platform_backend
     14 from telemetry.internal.platform.power_monitor import cros_power_monitor
     15 from telemetry.internal.util import ps_util
     16 
     17 
     18 class 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