1# Copyright 2015 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 optparse 6import os 7import py_utils 8import re 9 10from devil.android import flag_changer 11from devil.android.perf import cache_control 12from devil.android.sdk import intent 13 14from systrace import trace_result 15from systrace import tracing_agents 16 17 18class ChromeStartupTracingAgent(tracing_agents.TracingAgent): 19 def __init__(self, device, package_info, cold, url): 20 tracing_agents.TracingAgent.__init__(self) 21 self._device = device 22 self._package_info = package_info 23 self._cold = cold 24 self._logcat_monitor = self._device.GetLogcatMonitor() 25 self._url = url 26 self._trace_file = None 27 self._trace_finish_re = re.compile(r' Completed startup tracing to (.*)') 28 self._flag_changer = flag_changer.FlagChanger( 29 self._device, self._package_info.cmdline_file) 30 31 def __repr__(self): 32 return 'Browser Startup Trace' 33 34 def _SetupTracing(self): 35 # TODO(lizeb): Figure out how to clean up the command-line file when 36 # _TearDownTracing() is not executed in StopTracing(). 37 self._flag_changer.AddFlags(['--trace-startup']) 38 self._device.ForceStop(self._package_info.package) 39 if self._cold: 40 self._device.EnableRoot() 41 cache_control.CacheControl(self._device).DropRamCaches() 42 launch_intent = None 43 if self._url == '': 44 launch_intent = intent.Intent( 45 action='android.intent.action.MAIN', 46 package=self._package_info.package, 47 activity=self._package_info.activity) 48 else: 49 launch_intent = intent.Intent( 50 package=self._package_info.package, 51 activity=self._package_info.activity, 52 data=self._url, 53 extras={'create_new_tab': True}) 54 self._device.StartActivity(launch_intent, blocking=True) 55 56 def _TearDownTracing(self): 57 self._flag_changer.Restore() 58 59 @py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT) 60 def StartAgentTracing(self, config, timeout=None): 61 self._SetupTracing() 62 self._logcat_monitor.Start() 63 return True 64 65 @py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT) 66 def StopAgentTracing(self, timeout=None): 67 try: 68 self._trace_file = self._logcat_monitor.WaitFor( 69 self._trace_finish_re).group(1) 70 finally: 71 self._TearDownTracing() 72 return True 73 74 @py_utils.Timeout(tracing_agents.GET_RESULTS_TIMEOUT) 75 def GetResults(self, timeout=None): 76 with open(self._PullTrace(), 'r') as f: 77 trace_data = f.read() 78 return trace_result.TraceResult('traceEvents', trace_data) 79 80 def _PullTrace(self): 81 trace_file = self._trace_file.replace('/storage/emulated/0/', '/sdcard/') 82 host_file = os.path.join(os.path.curdir, os.path.basename(trace_file)) 83 self._device.PullFile(trace_file, host_file) 84 return host_file 85 86 def SupportsExplicitClockSync(self): 87 return False 88 89 def RecordClockSyncMarker(self, sync_id, did_record_sync_marker_callback): 90 # pylint: disable=unused-argument 91 assert self.SupportsExplicitClockSync(), ('Clock sync marker cannot be ' 92 'recorded since explicit clock sync is not supported.') 93 94 95class ChromeStartupConfig(tracing_agents.TracingConfig): 96 def __init__(self, device, package_info, cold, url, chrome_categories): 97 tracing_agents.TracingConfig.__init__(self) 98 self.device = device 99 self.package_info = package_info 100 self.cold = cold 101 self.url = url 102 self.chrome_categories = chrome_categories 103 104 105def try_create_agent(config): 106 return ChromeStartupTracingAgent(config.device, config.package_info, 107 config.cold, config.url) 108 109def add_options(parser): 110 options = optparse.OptionGroup(parser, 'Chrome startup tracing') 111 options.add_option('--url', help='URL to visit on startup. Default: ' 112 'https://www.google.com. An empty URL launches Chrome ' 113 'with a MAIN action instead of VIEW.', 114 default='https://www.google.com', metavar='URL') 115 options.add_option('--cold', help='Flush the OS page cache before starting ' 116 'the browser. Note that this require a device with root ' 117 'access.', default=False, action='store_true') 118 return options 119 120def get_config(options): 121 return ChromeStartupConfig(options.device, options.package_info, 122 options.cold, options.url, 123 options.chrome_categories) 124