Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(466)

Side by Side Diff: tools/telemetry/telemetry/core/backends/chrome/android_browser_backend.py

Issue 811703007: Create AndroidCommandLineBackend to handle setting up cmdline args (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright 2013 The Chromium Authors. All rights reserved. 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 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import logging 5 import logging
6 import pipes 6 import pipes
7 import sys 7 import sys
8 import time 8 import time
9 9
10 from telemetry.core import exceptions 10 from telemetry.core import exceptions
11 from telemetry.core import forwarders 11 from telemetry.core import forwarders
12 from telemetry.core import util 12 from telemetry.core import util
13 from telemetry.core.backends import adb_commands 13 from telemetry.core.backends import adb_commands
14 from telemetry.core.backends import android_command_line_backend
14 from telemetry.core.backends import browser_backend 15 from telemetry.core.backends import browser_backend
15 from telemetry.core.backends.chrome import chrome_browser_backend 16 from telemetry.core.backends.chrome import chrome_browser_backend
16 from telemetry.core.platform import android_platform_backend as \ 17 from telemetry.core.platform import android_platform_backend as \
17 android_platform_backend_module 18 android_platform_backend_module
18 from telemetry.core.forwarders import android_forwarder 19 from telemetry.core.forwarders import android_forwarder
19 20
20 util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'build', 'android') 21 util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'build', 'android')
21 from pylib.device import device_errors # pylint: disable=F0401 22 from pylib.device import device_errors # pylint: disable=F0401
22 from pylib.device import intent # pylint: disable=F0401 23 from pylib.device import intent # pylint: disable=F0401
23 24
24 25
25 class AndroidBrowserBackendSettings(object):
26
27 def __init__(self, activity, cmdline_file, package, pseudo_exec_name,
28 supports_tab_control):
29 self.activity = activity
30 self._cmdline_file = cmdline_file
31 self.package = package
32 self.pseudo_exec_name = pseudo_exec_name
33 self.supports_tab_control = supports_tab_control
34
35 def GetCommandLineFile(self, is_user_debug_build): # pylint: disable=W0613
36 return self._cmdline_file
37
38 def GetDevtoolsRemotePort(self, adb):
39 raise NotImplementedError()
40
41 @property
42 def profile_ignore_list(self):
43 # Don't delete lib, since it is created by the installer.
44 return ['lib']
45
46
47 class ChromeBackendSettings(AndroidBrowserBackendSettings):
48 # Stores a default Preferences file, re-used to speed up "--page-repeat".
49 _default_preferences_file = None
50
51 def GetCommandLineFile(self, is_user_debug_build):
52 if is_user_debug_build:
53 return '/data/local/tmp/chrome-command-line'
54 else:
55 return '/data/local/chrome-command-line'
56
57 def __init__(self, package):
58 super(ChromeBackendSettings, self).__init__(
59 activity='com.google.android.apps.chrome.Main',
60 cmdline_file=None,
61 package=package,
62 pseudo_exec_name='chrome',
63 supports_tab_control=True)
64
65 def GetDevtoolsRemotePort(self, adb):
66 return 'localabstract:chrome_devtools_remote'
67
68
69 class ContentShellBackendSettings(AndroidBrowserBackendSettings):
70 def __init__(self, package):
71 super(ContentShellBackendSettings, self).__init__(
72 activity='org.chromium.content_shell_apk.ContentShellActivity',
73 cmdline_file='/data/local/tmp/content-shell-command-line',
74 package=package,
75 pseudo_exec_name='content_shell',
76 supports_tab_control=False)
77
78 def GetDevtoolsRemotePort(self, adb):
79 return 'localabstract:content_shell_devtools_remote'
80
81
82 class ChromeShellBackendSettings(AndroidBrowserBackendSettings):
83 def __init__(self, package):
84 super(ChromeShellBackendSettings, self).__init__(
85 activity='org.chromium.chrome.shell.ChromeShellActivity',
86 cmdline_file='/data/local/tmp/chrome-shell-command-line',
87 package=package,
88 pseudo_exec_name='chrome_shell',
89 supports_tab_control=False)
90
91 def GetDevtoolsRemotePort(self, adb):
92 return 'localabstract:chrome_shell_devtools_remote'
93
94
95 class WebviewBackendSettings(AndroidBrowserBackendSettings):
96 def __init__(self, package,
97 activity='org.chromium.telemetry_shell.TelemetryActivity',
98 cmdline_file='/data/local/tmp/webview-command-line'):
99 super(WebviewBackendSettings, self).__init__(
100 activity=activity,
101 cmdline_file=cmdline_file,
102 package=package,
103 pseudo_exec_name='webview',
104 supports_tab_control=False)
105
106 def GetDevtoolsRemotePort(self, adb):
107 # The DevTools socket name for WebView depends on the activity PID's.
108 retries = 0
109 timeout = 1
110 pid = None
111 while True:
112 pids = adb.ExtractPid(self.package)
113 if len(pids) > 0:
114 pid = pids[-1]
115 break
116 time.sleep(timeout)
117 retries += 1
118 timeout *= 2
119 if retries == 4:
120 logging.critical('android_browser_backend: Timeout while waiting for '
121 'activity %s:%s to come up',
122 self.package,
123 self.activity)
124 raise exceptions.BrowserGoneException(self.browser,
125 'Timeout waiting for PID.')
126 return 'localabstract:webview_devtools_remote_%s' % str(pid)
127
128
129 class WebviewShellBackendSettings(WebviewBackendSettings):
130 def __init__(self, package):
131 super(WebviewShellBackendSettings, self).__init__(
132 activity='org.chromium.android_webview.shell.AwShellActivity',
133 cmdline_file='/data/local/tmp/android-webview-command-line',
134 package=package)
135
136
137 class AndroidBrowserBackend(chrome_browser_backend.ChromeBrowserBackend): 26 class AndroidBrowserBackend(chrome_browser_backend.ChromeBrowserBackend):
138 """The backend for controlling a browser instance running on Android.""" 27 """The backend for controlling a browser instance running on Android."""
139 def __init__(self, android_platform_backend, browser_options, 28 def __init__(self, android_platform_backend, browser_options,
140 backend_settings, use_rndis_forwarder, output_profile_path, 29 backend_settings, use_rndis_forwarder, output_profile_path,
141 extensions_to_load, target_arch): 30 extensions_to_load, target_arch):
142 assert isinstance(android_platform_backend, 31 assert isinstance(android_platform_backend,
143 android_platform_backend_module.AndroidPlatformBackend) 32 android_platform_backend_module.AndroidPlatformBackend)
144 super(AndroidBrowserBackend, self).__init__( 33 super(AndroidBrowserBackend, self).__init__(
145 android_platform_backend, 34 android_platform_backend,
146 supports_tab_control=backend_settings.supports_tab_control, 35 supports_tab_control=backend_settings.supports_tab_control,
147 supports_extensions=False, browser_options=browser_options, 36 supports_extensions=False, browser_options=browser_options,
148 output_profile_path=output_profile_path, 37 output_profile_path=output_profile_path,
149 extensions_to_load=extensions_to_load) 38 extensions_to_load=extensions_to_load)
150 if len(extensions_to_load) > 0: 39 if len(extensions_to_load) > 0:
151 raise browser_backend.ExtensionsNotSupportedException( 40 raise browser_backend.ExtensionsNotSupportedException(
152 'Android browser does not support extensions.') 41 'Android browser does not support extensions.')
153 42
154 # Initialize fields so that an explosion during init doesn't break in Close. 43 # Initialize fields so that an explosion during init doesn't break in Close.
155 self._backend_settings = backend_settings 44 self._backend_settings = backend_settings
156 self._saved_cmdline = ''
157 self._target_arch = target_arch 45 self._target_arch = target_arch
158 self._saved_sslflag = '' 46 self._saved_sslflag = ''
159 47
160 # TODO(tonyg): This is flaky because it doesn't reserve the port that it 48 # TODO(tonyg): This is flaky because it doesn't reserve the port that it
161 # allocates. Need to fix this. 49 # allocates. Need to fix this.
162 self._port = adb_commands.AllocateTestServerPort() 50 self._port = adb_commands.AllocateTestServerPort()
163 51
164 # TODO(wuhu): Move to network controller backend. 52 # TODO(wuhu): Move to network controller backend.
165 self.platform_backend.InstallTestCa() 53 self.platform_backend.InstallTestCa()
166 54
(...skipping 23 matching lines...) Expand all
190 # Set the debug app if needed. 78 # Set the debug app if needed.
191 self.platform_backend.SetDebugApp(self._backend_settings.package) 79 self.platform_backend.SetDebugApp(self._backend_settings.package)
192 80
193 @property 81 @property
194 def _adb(self): 82 def _adb(self):
195 return self.platform_backend.adb 83 return self.platform_backend.adb
196 84
197 def _KillBrowser(self): 85 def _KillBrowser(self):
198 self.platform_backend.KillApplication(self._backend_settings.package) 86 self.platform_backend.KillApplication(self._backend_settings.package)
199 87
200 def _SetUpCommandLine(self): 88 def Start(self):
201 def QuoteIfNeeded(arg): 89 browser_startup_args = self.GetBrowserStartupArgs()
202 # Properly escape "key=valueA valueB" to "key='valueA valueB'" 90 with android_command_line_backend.AndroidCommandLineBackend(
203 # Values without spaces, or that seem to be quoted are left untouched. 91 self._adb, self._backend_settings, browser_startup_args):
nednguyen 2015/01/14 17:05:58 I think we can move this to right before we start
ariblue 2015/01/14 21:19:26 Shouldn't we wait until after _WaitForBrowserToCom
204 # This is required so CommandLine.java can parse valueB correctly rather 92 self._adb.device().RunShellCommand('logcat -c')
205 # than as a separate switch. 93 if self.browser_options.startup_url:
206 params = arg.split('=', 1) 94 url = self.browser_options.startup_url
207 if len(params) != 2: 95 elif self.browser_options.profile_dir:
208 return arg 96 url = None
209 key, values = params 97 else:
210 if ' ' not in values: 98 # If we have no existing tabs start with a blank page since default
211 return arg 99 # startup with the NTP can lead to race conditions with Telemetry
212 if values[0] in '"\'' and values[-1] == values[0]: 100 url = 'about:blank'
213 return arg
214 return '%s=%s' % (key, pipes.quote(values))
215 args = [self._backend_settings.pseudo_exec_name]
216 args.extend(self.GetBrowserStartupArgs())
217 content = ' '.join(QuoteIfNeeded(arg) for arg in args)
218 cmdline_file = self._backend_settings.GetCommandLineFile(
219 self._adb.IsUserBuild())
220 101
221 try: 102 self.platform_backend.DismissCrashDialogIfNeeded()
222 # Save the current command line to restore later, except if it appears to
223 # be a Telemetry created one. This is to prevent a common bug where
224 # --host-resolver-rules borks people's browsers if something goes wrong
225 # with Telemetry.
226 self._saved_cmdline = ''.join(self._adb.device().ReadFile(cmdline_file))
227 if '--host-resolver-rules' in self._saved_cmdline:
228 self._saved_cmdline = ''
229 self._adb.device().WriteFile(cmdline_file, content, as_root=True)
230 except device_errors.CommandFailedError:
231 logging.critical('Cannot set Chrome command line. '
232 'Fix this by flashing to a userdebug build.')
233 sys.exit(1)
234 103
235 def _RestoreCommandLine(self): 104 self._adb.device().StartActivity(
236 cmdline_file = self._backend_settings.GetCommandLineFile( 105 intent.Intent(package=self._backend_settings.package,
237 self._adb.IsUserBuild()) 106 activity=self._backend_settings.activity,
238 self._adb.device().WriteFile(cmdline_file, self._saved_cmdline, 107 action=None, data=url, category=None),
239 as_root=True) 108 blocking=True)
240 109
241 def Start(self): 110 remote_devtools_port = self._backend_settings.GetDevtoolsRemotePort(
242 self._SetUpCommandLine() 111 self._adb)
112 self.platform_backend.ForwardHostToDevice(
113 self._port, remote_devtools_port)
243 114
244 self._adb.device().RunShellCommand('logcat -c') 115 try:
245 if self.browser_options.startup_url: 116 self._WaitForBrowserToComeUp(remote_devtools_port=remote_devtools_port)
246 url = self.browser_options.startup_url 117 except exceptions.BrowserGoneException:
247 elif self.browser_options.profile_dir: 118 logging.critical('Failed to connect to browser.')
248 url = None 119 device = self._adb.device()
249 else: 120 if not device.old_interface.CanAccessProtectedFileContents():
250 # If we have no existing tabs start with a blank page since default 121 logging.critical(
251 # startup with the NTP can lead to race conditions with Telemetry 122 'Resolve this by either: '
252 url = 'about:blank' 123 '(1) Flashing to a userdebug build OR '
253 124 '(2) Manually enabling web debugging in Chrome at '
254 self.platform_backend.DismissCrashDialogIfNeeded() 125 'Settings > Developer tools > Enable USB Web debugging.')
255 126 sys.exit(1)
256 self._adb.device().StartActivity( 127 except:
257 intent.Intent(package=self._backend_settings.package, 128 import traceback
258 activity=self._backend_settings.activity, 129 traceback.print_exc()
259 action=None, data=url, category=None), 130 self.Close()
260 blocking=True) 131 raise
261
262 remote_devtools_port = self._backend_settings.GetDevtoolsRemotePort(
263 self._adb)
264 self.platform_backend.ForwardHostToDevice(self._port, remote_devtools_port)
265
266 try:
267 self._WaitForBrowserToComeUp(remote_devtools_port=remote_devtools_port)
268 except exceptions.BrowserGoneException:
269 logging.critical('Failed to connect to browser.')
270 if not self._adb.device().old_interface.CanAccessProtectedFileContents():
271 logging.critical(
272 'Resolve this by either: '
273 '(1) Flashing to a userdebug build OR '
274 '(2) Manually enabling web debugging in Chrome at '
275 'Settings > Developer tools > Enable USB Web debugging.')
276 sys.exit(1)
277 except:
278 import traceback
279 traceback.print_exc()
280 self.Close()
281 raise
282 finally:
283 self._RestoreCommandLine()
284 132
285 def GetBrowserStartupArgs(self): 133 def GetBrowserStartupArgs(self):
286 args = super(AndroidBrowserBackend, self).GetBrowserStartupArgs() 134 args = super(AndroidBrowserBackend, self).GetBrowserStartupArgs()
287 args.append('--enable-remote-debugging') 135 args.append('--enable-remote-debugging')
288 args.append('--disable-fre') 136 args.append('--disable-fre')
289 args.append('--disable-external-intent-requests') 137 args.append('--disable-external-intent-requests')
290 return args 138 return args
291 139
292 @property 140 @property
293 def forwarder_factory(self): 141 def forwarder_factory(self):
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 190
343 def GetStandardOutput(self): 191 def GetStandardOutput(self):
344 return self.platform_backend.GetStandardOutput() 192 return self.platform_backend.GetStandardOutput()
345 193
346 def GetStackTrace(self): 194 def GetStackTrace(self):
347 return self.platform_backend.GetStackTrace(self._target_arch) 195 return self.platform_backend.GetStackTrace(self._target_arch)
348 196
349 @property 197 @property
350 def should_ignore_certificate_errors(self): 198 def should_ignore_certificate_errors(self):
351 return not self.platform_backend.is_test_ca_installed 199 return not self.platform_backend.is_test_ca_installed
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698