Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / tools / telemetry / telemetry / core / backends / chrome / cros_browser_backend.py
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 import os
7
8 from telemetry import decorators
9
10 from telemetry.core import exceptions
11 from telemetry.core import forwarders
12 from telemetry.core import util
13 from telemetry.core.backends.chrome import chrome_browser_backend
14 from telemetry.core.backends.chrome import misc_web_contents_backend
15 from telemetry.core.forwarders import cros_forwarder
16
17
18 class CrOSBrowserBackend(chrome_browser_backend.ChromeBrowserBackend):
19   def __init__(self, browser_type, browser_options, cri, is_guest,
20                extensions_to_load):
21     super(CrOSBrowserBackend, self).__init__(
22         is_content_shell=False, supports_extensions=not is_guest,
23         browser_options=browser_options,
24         output_profile_path=None, extensions_to_load=extensions_to_load)
25
26     # Initialize fields so that an explosion during init doesn't break in Close.
27     self._browser_type = browser_type
28     self._cri = cri
29     self._is_guest = is_guest
30     self._forwarder = None
31
32     from telemetry.core.backends.chrome import chrome_browser_options
33     assert isinstance(browser_options,
34                       chrome_browser_options.CrosBrowserOptions)
35
36     self.wpr_port_pairs = forwarders.PortPairs(
37         http=forwarders.PortPair(self.wpr_port_pairs.http.local_port,
38                                  self._cri.GetRemotePort()),
39         https=forwarders.PortPair(self.wpr_port_pairs.https.local_port,
40                                   self._cri.GetRemotePort()),
41         dns=None)
42     self._remote_debugging_port = self._cri.GetRemotePort()
43     self._port = self._remote_debugging_port
44
45     # Copy extensions to temp directories on the device.
46     # Note that we also perform this copy locally to ensure that
47     # the owner of the extensions is set to chronos.
48     for e in extensions_to_load:
49       output = cri.RunCmdOnDevice(['mktemp', '-d', '/tmp/extension_XXXXX'])
50       extension_dir = output[0].rstrip()
51       cri.PushFile(e.path, extension_dir)
52       cri.Chown(extension_dir)
53       e.local_path = os.path.join(extension_dir, os.path.basename(e.path))
54
55     self._cri.RestartUI(self.browser_options.clear_enterprise_policy)
56     util.WaitFor(self.IsBrowserRunning, 20)
57
58     # Delete test user's cryptohome vault (user data directory).
59     if not self.browser_options.dont_override_profile:
60       self._cri.RunCmdOnDevice(['cryptohome', '--action=remove', '--force',
61                                 '--user=%s' % self._username])
62     if self.browser_options.profile_dir:
63       cri.RmRF(self.profile_directory)
64       cri.PushFile(self.browser_options.profile_dir + '/Default',
65                    self.profile_directory)
66       cri.Chown(self.profile_directory)
67
68     self._SetBranchNumber(self._GetChromeVersion())
69
70   def GetBrowserStartupArgs(self):
71     args = super(CrOSBrowserBackend, self).GetBrowserStartupArgs()
72     args.extend([
73             '--enable-smooth-scrolling',
74             '--enable-threaded-compositing',
75             '--enable-per-tile-painting',
76             '--force-compositing-mode',
77             # Disables the start page, as well as other external apps that can
78             # steal focus or make measurements inconsistent.
79             '--disable-default-apps',
80             # Skip user image selection screen, and post login screens.
81             '--oobe-skip-postlogin',
82             # Allow devtools to connect to chrome.
83             '--remote-debugging-port=%i' % self._remote_debugging_port,
84             # Open a maximized window.
85             '--start-maximized',
86             # Debug logging.
87             '--vmodule=*/chromeos/net/*=2,*/chromeos/login/*=2'])
88
89     return args
90
91   def _GetChromeVersion(self):
92     result = util.WaitFor(self._cri.GetChromeProcess, timeout=30)
93     assert result and result['path']
94     (version, _) = self._cri.RunCmdOnDevice([result['path'], '--version'])
95     assert version
96     return version
97
98   @property
99   def pid(self):
100     return self._cri.GetChromePid()
101
102   @property
103   def browser_directory(self):
104     result = self._cri.GetChromeProcess()
105     if result and 'path' in result:
106       return os.path.dirname(result['path'])
107     return None
108
109   @property
110   def profile_directory(self):
111     return '/home/chronos/Default'
112
113   def GetRemotePort(self, port):
114     if self._cri.local:
115       return port
116     return self._cri.GetRemotePort()
117
118   def __del__(self):
119     self.Close()
120
121   def Start(self):
122     # Escape all commas in the startup arguments we pass to Chrome
123     # because dbus-send delimits array elements by commas
124     startup_args = [a.replace(',', '\\,') for a in self.GetBrowserStartupArgs()]
125
126     # Restart Chrome with the login extension and remote debugging.
127     logging.info('Restarting Chrome with flags and login')
128     args = ['dbus-send', '--system', '--type=method_call',
129             '--dest=org.chromium.SessionManager',
130             '/org/chromium/SessionManager',
131             'org.chromium.SessionManagerInterface.EnableChromeTesting',
132             'boolean:true',
133             'array:string:"%s"' % ','.join(startup_args)]
134     self._cri.RunCmdOnDevice(args)
135
136     if not self._cri.local:
137       self._port = util.GetUnreservedAvailableLocalPort()
138       self._forwarder = self.forwarder_factory.Create(
139           forwarders.PortPairs(
140               http=forwarders.PortPair(self._port, self._remote_debugging_port),
141               https=None,
142               dns=None), forwarding_flag='L')
143
144     try:
145       self._WaitForBrowserToComeUp(wait_for_extensions=False)
146       self._PostBrowserStartupInitialization()
147     except:
148       import traceback
149       traceback.print_exc()
150       self.Close()
151       raise
152
153     util.WaitFor(lambda: self.oobe_exists, 10)
154
155     if self.browser_options.auto_login:
156       if self._is_guest:
157         pid = self.pid
158         self.oobe.NavigateGuestLogin()
159         # Guest browsing shuts down the current browser and launches an
160         # incognito browser in a separate process, which we need to wait for.
161         util.WaitFor(lambda: pid != self.pid, 10)
162       elif self.browser_options.gaia_login:
163         try:
164           self.oobe.NavigateGaiaLogin(self._username, self._password)
165         except util.TimeoutException:
166           self._cri.TakeScreenShot('gaia-login')
167           raise
168       else:
169         self.oobe.NavigateFakeLogin(self._username, self._password)
170       self._WaitForLogin()
171
172     logging.info('Browser is up!')
173
174   def Close(self):
175     super(CrOSBrowserBackend, self).Close()
176
177     if self._cri:
178       self._cri.RestartUI(False) # Logs out.
179
180     util.WaitFor(lambda: not self._IsCryptohomeMounted(), 30)
181
182     if self._forwarder:
183       self._forwarder.Close()
184       self._forwarder = None
185
186     if self._cri:
187       for e in self._extensions_to_load:
188         self._cri.RmRF(os.path.dirname(e.local_path))
189
190     self._cri = None
191
192   @property
193   @decorators.Cache
194   def forwarder_factory(self):
195     return cros_forwarder.CrOsForwarderFactory(self._cri)
196
197   def IsBrowserRunning(self):
198     return bool(self.pid)
199
200   def GetStandardOutput(self):
201     return 'Cannot get standard output on CrOS'
202
203   def GetStackTrace(self):
204     return 'Cannot get stack trace on CrOS'
205
206   @property
207   @decorators.Cache
208   def misc_web_contents_backend(self):
209     """Access to chrome://oobe/login page."""
210     return misc_web_contents_backend.MiscWebContentsBackend(self)
211
212   @property
213   def oobe(self):
214     return self.misc_web_contents_backend.GetOobe()
215
216   @property
217   def oobe_exists(self):
218     return self.misc_web_contents_backend.oobe_exists
219
220   @property
221   def _username(self):
222     return self.browser_options.username
223
224   @property
225   def _password(self):
226     return self.browser_options.password
227
228   def _IsCryptohomeMounted(self):
229     username = '$guest' if self._is_guest else self._username
230     return self._cri.IsCryptohomeMounted(username, self._is_guest)
231
232   def _IsLoggedIn(self):
233     """Returns True if cryptohome has mounted, the browser is
234     responsive to devtools requests, and the oobe has been dismissed."""
235     return (self._IsCryptohomeMounted() and
236             self.HasBrowserFinishedLaunching() and
237             not self.oobe_exists)
238
239   def _WaitForLogin(self):
240     if self._is_guest:
241       self._WaitForBrowserToComeUp()
242       util.WaitFor(self._IsCryptohomeMounted, 30)
243       return
244
245     try:
246       util.WaitFor(self._IsLoggedIn, 60)
247     except util.TimeoutException:
248       self._cri.TakeScreenShot('login-screen')
249       raise exceptions.LoginException('Timed out going through login screen')
250
251     # Wait for extensions to load.
252     try:
253       self._WaitForBrowserToComeUp()
254     except util.TimeoutException:
255       logging.error('Chrome args: %s' % self._cri.GetChromeProcess()['args'])
256       self._cri.TakeScreenShot('extension-timeout')
257       raise
258
259     # Workaround for crbug.com/329271, crbug.com/334726.
260     retries = 3
261     while True:
262       try:
263         # Open a new window/tab.
264         tab = self.tab_list_backend.New(timeout=30)
265         tab.Navigate('about:blank', timeout=10)
266         break
267       except (exceptions.TabCrashException, util.TimeoutException,
268               IndexError):
269         retries -= 1
270         logging.warn('TabCrashException/TimeoutException in '
271                      'new tab creation/navigation, '
272                      'remaining retries %d' % retries)
273         if not retries:
274           raise