android_platform_backend.py revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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 6import tempfile 7 8from telemetry import decorators 9from telemetry.core import exceptions 10from telemetry.core import platform 11from telemetry.core import util 12from telemetry.core import video 13from telemetry.core.platform import proc_supporting_platform_backend 14from telemetry.core.platform.power_monitor import android_ds2784_power_monitor 15from telemetry.core.platform.power_monitor import android_dumpsys_power_monitor 16from telemetry.core.platform.power_monitor import android_temperature_monitor 17from telemetry.core.platform.power_monitor import monsoon_power_monitor 18from telemetry.core.platform.power_monitor import power_monitor_controller 19from telemetry.core.platform.profiler import android_prebuilt_profiler_helper 20 21# Get build/android scripts into our path. 22util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'build', 'android') 23from pylib import screenshot # pylint: disable=F0401 24from pylib.perf import cache_control # pylint: disable=F0401 25from pylib.perf import perf_control # pylint: disable=F0401 26from pylib.perf import thermal_throttle # pylint: disable=F0401 27 28try: 29 from pylib.perf import surface_stats_collector # pylint: disable=F0401 30except Exception: 31 surface_stats_collector = None 32 33 34_HOST_APPLICATIONS = [ 35 'avconv', 36 'ipfw', 37 'perfhost', 38 ] 39 40 41class AndroidPlatformBackend( 42 proc_supporting_platform_backend.ProcSupportingPlatformBackend): 43 def __init__(self, device, no_performance_mode): 44 super(AndroidPlatformBackend, self).__init__() 45 self._device = device 46 self._surface_stats_collector = None 47 self._perf_tests_setup = perf_control.PerfControl(self._device) 48 self._thermal_throttle = thermal_throttle.ThermalThrottle(self._device) 49 self._no_performance_mode = no_performance_mode 50 self._raw_display_frame_rate_measurements = [] 51 self._can_access_protected_file_contents = \ 52 self._device.old_interface.CanAccessProtectedFileContents() 53 power_controller = power_monitor_controller.PowerMonitorController([ 54 monsoon_power_monitor.MonsoonPowerMonitor(device), 55 android_ds2784_power_monitor.DS2784PowerMonitor(device), 56 android_dumpsys_power_monitor.DumpsysPowerMonitor(device), 57 ]) 58 self._power_monitor = android_temperature_monitor.AndroidTemperatureMonitor( 59 power_controller, device) 60 self._video_recorder = None 61 if self._no_performance_mode: 62 logging.warning('CPU governor will not be set!') 63 64 def IsRawDisplayFrameRateSupported(self): 65 return True 66 67 def StartRawDisplayFrameRateMeasurement(self): 68 assert not self._surface_stats_collector 69 # Clear any leftover data from previous timed out tests 70 self._raw_display_frame_rate_measurements = [] 71 self._surface_stats_collector = \ 72 surface_stats_collector.SurfaceStatsCollector(self._device) 73 self._surface_stats_collector.Start() 74 75 def StopRawDisplayFrameRateMeasurement(self): 76 if not self._surface_stats_collector: 77 return 78 79 self._surface_stats_collector.Stop() 80 for r in self._surface_stats_collector.GetResults(): 81 self._raw_display_frame_rate_measurements.append( 82 platform.Platform.RawDisplayFrameRateMeasurement( 83 r.name, r.value, r.unit)) 84 85 self._surface_stats_collector = None 86 87 def GetRawDisplayFrameRateMeasurements(self): 88 ret = self._raw_display_frame_rate_measurements 89 self._raw_display_frame_rate_measurements = [] 90 return ret 91 92 def SetFullPerformanceModeEnabled(self, enabled): 93 if self._no_performance_mode: 94 return 95 if enabled: 96 self._perf_tests_setup.SetHighPerfMode() 97 else: 98 self._perf_tests_setup.SetDefaultPerfMode() 99 100 def CanMonitorThermalThrottling(self): 101 return True 102 103 def IsThermallyThrottled(self): 104 return self._thermal_throttle.IsThrottled() 105 106 def HasBeenThermallyThrottled(self): 107 return self._thermal_throttle.HasBeenThrottled() 108 109 def GetCpuStats(self, pid): 110 if not self._can_access_protected_file_contents: 111 logging.warning('CPU stats cannot be retrieved on non-rooted device.') 112 return {} 113 return super(AndroidPlatformBackend, self).GetCpuStats(pid) 114 115 def GetCpuTimestamp(self): 116 if not self._can_access_protected_file_contents: 117 logging.warning('CPU timestamp cannot be retrieved on non-rooted device.') 118 return {} 119 return super(AndroidPlatformBackend, self).GetCpuTimestamp() 120 121 def PurgeUnpinnedMemory(self): 122 """Purges the unpinned ashmem memory for the whole system. 123 124 This can be used to make memory measurements more stable. Requires root. 125 """ 126 if not self._can_access_protected_file_contents: 127 logging.warning('Cannot run purge_ashmem. Requires a rooted device.') 128 return 129 130 if not android_prebuilt_profiler_helper.InstallOnDevice( 131 self._device, 'purge_ashmem'): 132 raise Exception('Error installing purge_ashmem.') 133 (status, output) = self._device.old_interface.GetAndroidToolStatusAndOutput( 134 android_prebuilt_profiler_helper.GetDevicePath('purge_ashmem'), 135 log_result=True) 136 if status != 0: 137 raise Exception('Error while purging ashmem: ' + '\n'.join(output)) 138 139 def GetMemoryStats(self, pid): 140 memory_usage = self._device.GetMemoryUsageForPid(pid) 141 if not memory_usage: 142 return {} 143 return {'ProportionalSetSize': memory_usage['Pss'] * 1024, 144 'SharedDirty': memory_usage['Shared_Dirty'] * 1024, 145 'PrivateDirty': memory_usage['Private_Dirty'] * 1024, 146 'VMPeak': memory_usage['VmHWM'] * 1024} 147 148 def GetIOStats(self, pid): 149 return {} 150 151 def GetChildPids(self, pid): 152 child_pids = [] 153 ps = self._GetPsOutput(['pid', 'name']) 154 for curr_pid, curr_name in ps: 155 if int(curr_pid) == pid: 156 name = curr_name 157 for curr_pid, curr_name in ps: 158 if curr_name.startswith(name) and curr_name != name: 159 child_pids.append(int(curr_pid)) 160 break 161 return child_pids 162 163 @decorators.Cache 164 def GetCommandLine(self, pid): 165 ps = self._GetPsOutput(['pid', 'name'], pid) 166 if not ps: 167 raise exceptions.ProcessGoneException() 168 return ps[0][1] 169 170 def GetOSName(self): 171 return 'android' 172 173 @decorators.Cache 174 def GetOSVersionName(self): 175 return self._device.GetProp('ro.build.id')[0] 176 177 def CanFlushIndividualFilesFromSystemCache(self): 178 return False 179 180 def FlushEntireSystemCache(self): 181 cache = cache_control.CacheControl(self._device) 182 cache.DropRamCaches() 183 184 def FlushSystemCacheForDirectory(self, directory, ignoring=None): 185 raise NotImplementedError() 186 187 def FlushDnsCache(self): 188 self._device.RunShellCommand('ndc resolver flushdefaultif', as_root=True) 189 190 def LaunchApplication( 191 self, application, parameters=None, elevate_privilege=False): 192 if application in _HOST_APPLICATIONS: 193 platform.GetHostPlatform().LaunchApplication( 194 application, parameters, elevate_privilege=elevate_privilege) 195 return 196 if elevate_privilege: 197 raise NotImplementedError("elevate_privilege isn't supported on android.") 198 if not parameters: 199 parameters = '' 200 self._device.RunShellCommand('am start ' + parameters + ' ' + application) 201 202 def IsApplicationRunning(self, application): 203 if application in _HOST_APPLICATIONS: 204 return platform.GetHostPlatform().IsApplicationRunning(application) 205 return len(self._device.GetPids(application)) > 0 206 207 def CanLaunchApplication(self, application): 208 if application in _HOST_APPLICATIONS: 209 return platform.GetHostPlatform().CanLaunchApplication(application) 210 return True 211 212 def InstallApplication(self, application): 213 if application in _HOST_APPLICATIONS: 214 platform.GetHostPlatform().InstallApplication(application) 215 return 216 raise NotImplementedError( 217 'Please teach Telemetry how to install ' + application) 218 219 @decorators.Cache 220 def CanCaptureVideo(self): 221 return self.GetOSVersionName() >= 'K' 222 223 def StartVideoCapture(self, min_bitrate_mbps): 224 """Starts the video capture at specified bitrate.""" 225 min_bitrate_mbps = max(min_bitrate_mbps, 0.1) 226 if min_bitrate_mbps > 100: 227 raise ValueError('Android video capture cannot capture at %dmbps. ' 228 'Max capture rate is 100mbps.' % min_bitrate_mbps) 229 if self.is_video_capture_running: 230 self._video_recorder.Stop() 231 self._video_recorder = screenshot.VideoRecorder( 232 self._device, megabits_per_second=min_bitrate_mbps) 233 self._video_recorder.Start() 234 util.WaitFor(self._video_recorder.IsStarted, 5) 235 236 @property 237 def is_video_capture_running(self): 238 return self._video_recorder is not None 239 240 def StopVideoCapture(self): 241 assert self.is_video_capture_running, 'Must start video capture first' 242 self._video_recorder.Stop() 243 video_file_obj = tempfile.NamedTemporaryFile() 244 self._video_recorder.Pull(video_file_obj.name) 245 self._video_recorder = None 246 247 return video.Video(video_file_obj) 248 249 def CanMonitorPower(self): 250 return self._power_monitor.CanMonitorPower() 251 252 def StartMonitoringPower(self, browser): 253 self._power_monitor.StartMonitoringPower(browser) 254 255 def StopMonitoringPower(self): 256 return self._power_monitor.StopMonitoringPower() 257 258 def _GetFileContents(self, fname): 259 if not self._can_access_protected_file_contents: 260 logging.warning('%s cannot be retrieved on non-rooted device.' % fname) 261 return '' 262 return '\n'.join(self._device.ReadFile(fname, as_root=True)) 263 264 def _GetPsOutput(self, columns, pid=None): 265 assert columns == ['pid', 'name'] or columns == ['pid'], \ 266 'Only know how to return pid and name. Requested: ' + columns 267 command = 'ps' 268 if pid: 269 command += ' -p %d' % pid 270 ps = self._device.RunShellCommand(command)[1:] 271 output = [] 272 for line in ps: 273 data = line.split() 274 curr_pid = data[1] 275 curr_name = data[-1] 276 if columns == ['pid', 'name']: 277 output.append([curr_pid, curr_name]) 278 else: 279 output.append([curr_pid]) 280 return output 281