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