xref: /aosp_15_r20/external/autotest/client/common_lib/cros/chrome.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li# Lint as: python2, python3
2*9c5db199SXin Li# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
3*9c5db199SXin Li# Use of this source code is governed by a BSD-style license that can be
4*9c5db199SXin Li# found in the LICENSE file.
5*9c5db199SXin Li
6*9c5db199SXin Lifrom __future__ import absolute_import
7*9c5db199SXin Lifrom __future__ import division
8*9c5db199SXin Lifrom __future__ import print_function
9*9c5db199SXin Li
10*9c5db199SXin Liimport logging
11*9c5db199SXin Liimport os
12*9c5db199SXin Liimport re
13*9c5db199SXin Li
14*9c5db199SXin Lifrom autotest_lib.client.common_lib.cros import arc_common
15*9c5db199SXin Lifrom autotest_lib.client.common_lib.cros import arc_util
16*9c5db199SXin Lifrom autotest_lib.client.common_lib.cros import assistant_util
17*9c5db199SXin Lifrom autotest_lib.client.cros import constants
18*9c5db199SXin Lifrom autotest_lib.client.bin import utils
19*9c5db199SXin Lifrom six.moves import range
20*9c5db199SXin Lifrom telemetry.core import cros_interface, exceptions
21*9c5db199SXin Lifrom telemetry.internal.browser import browser_finder, browser_options
22*9c5db199SXin Lifrom telemetry.internal.browser import extension_to_load
23*9c5db199SXin Li
24*9c5db199SXin Liimport py_utils
25*9c5db199SXin Li
26*9c5db199SXin LiError = exceptions.Error
27*9c5db199SXin Li
28*9c5db199SXin Li
29*9c5db199SXin Lidef NormalizeEmail(username):
30*9c5db199SXin Li    """Remove dots from username. Add @gmail.com if necessary.
31*9c5db199SXin Li
32*9c5db199SXin Li    TODO(achuith): Get rid of this when crbug.com/358427 is fixed.
33*9c5db199SXin Li
34*9c5db199SXin Li    @param username: username/email to be scrubbed.
35*9c5db199SXin Li    """
36*9c5db199SXin Li    parts = re.split('@', username)
37*9c5db199SXin Li    parts[0] = re.sub('\.', '', parts[0])
38*9c5db199SXin Li
39*9c5db199SXin Li    if len(parts) == 1:
40*9c5db199SXin Li        parts.append('gmail.com')
41*9c5db199SXin Li    return '@'.join(parts)
42*9c5db199SXin Li
43*9c5db199SXin Li
44*9c5db199SXin Liclass Chrome(object):
45*9c5db199SXin Li    """Wrapper for creating a telemetry browser instance with extensions.
46*9c5db199SXin Li
47*9c5db199SXin Li    The recommended way to use this class is to create the instance using the
48*9c5db199SXin Li    with statement:
49*9c5db199SXin Li
50*9c5db199SXin Li    >>> with chrome.Chrome(...) as cr:
51*9c5db199SXin Li    >>>     # Do whatever you need with cr.
52*9c5db199SXin Li    >>>     pass
53*9c5db199SXin Li
54*9c5db199SXin Li    This will make sure all the clean-up functions are called.  If you really
55*9c5db199SXin Li    need to use this class without the with statement, make sure to call the
56*9c5db199SXin Li    close() method once you're done with the Chrome instance.
57*9c5db199SXin Li    """
58*9c5db199SXin Li
59*9c5db199SXin Li    BROWSER_TYPE_LOGIN = 'system'
60*9c5db199SXin Li    BROWSER_TYPE_GUEST = 'system-guest'
61*9c5db199SXin Li    AUTOTEST_EXT_ID = 'behllobkkfkfnphdnhnkndlbkcpglgmj'
62*9c5db199SXin Li
63*9c5db199SXin Li    def __init__(self,
64*9c5db199SXin Li                 logged_in=True,
65*9c5db199SXin Li                 extension_paths=None,
66*9c5db199SXin Li                 autotest_ext=False,
67*9c5db199SXin Li                 num_tries=3,
68*9c5db199SXin Li                 extra_browser_args=None,
69*9c5db199SXin Li                 clear_enterprise_policy=True,
70*9c5db199SXin Li                 expect_policy_fetch=False,
71*9c5db199SXin Li                 dont_override_profile=False,
72*9c5db199SXin Li                 disable_gaia_services=True,
73*9c5db199SXin Li                 disable_default_apps=True,
74*9c5db199SXin Li                 auto_login=True,
75*9c5db199SXin Li                 gaia_login=False,
76*9c5db199SXin Li                 username=None,
77*9c5db199SXin Li                 password=None,
78*9c5db199SXin Li                 gaia_id=None,
79*9c5db199SXin Li                 arc_mode=None,
80*9c5db199SXin Li                 arc_timeout=None,
81*9c5db199SXin Li                 enable_web_app_auto_install=False,
82*9c5db199SXin Li                 disable_arc_opt_in=True,
83*9c5db199SXin Li                 disable_arc_opt_in_verification=True,
84*9c5db199SXin Li                 disable_arc_cpu_restriction=True,
85*9c5db199SXin Li                 disable_app_sync=False,
86*9c5db199SXin Li                 disable_play_auto_install=False,
87*9c5db199SXin Li                 disable_locale_sync=True,
88*9c5db199SXin Li                 disable_play_store_auto_update=True,
89*9c5db199SXin Li                 enable_assistant=False,
90*9c5db199SXin Li                 enterprise_arc_test=False,
91*9c5db199SXin Li                 init_network_controller=False,
92*9c5db199SXin Li                 mute_audio=False,
93*9c5db199SXin Li                 proxy_server=None,
94*9c5db199SXin Li                 login_delay=0,
95*9c5db199SXin Li                 enable_features=None):
96*9c5db199SXin Li        """
97*9c5db199SXin Li        Constructor of telemetry wrapper.
98*9c5db199SXin Li
99*9c5db199SXin Li        @param logged_in: Regular user (True) or guest user (False).
100*9c5db199SXin Li        @param extension_paths: path of unpacked extension to install.
101*9c5db199SXin Li        @param autotest_ext: Load a component extension with privileges to
102*9c5db199SXin Li                             invoke chrome.autotestPrivate.
103*9c5db199SXin Li        @param num_tries: Number of attempts to log in.
104*9c5db199SXin Li        @param extra_browser_args: Additional argument(s) to pass to the
105*9c5db199SXin Li                                   browser. It can be a string or a list.
106*9c5db199SXin Li        @param clear_enterprise_policy: Clear enterprise policy before
107*9c5db199SXin Li                                        logging in.
108*9c5db199SXin Li        @param expect_policy_fetch: Expect that chrome can reach the device
109*9c5db199SXin Li                                    management server and download policy.
110*9c5db199SXin Li        @param dont_override_profile: Don't delete cryptohome before login.
111*9c5db199SXin Li                                      Telemetry will output a warning with this
112*9c5db199SXin Li                                      option.
113*9c5db199SXin Li        @param disable_gaia_services: For enterprise autotests, this option may
114*9c5db199SXin Li                                      be used to enable policy fetch.
115*9c5db199SXin Li        @param disable_default_apps: For tests that exercise default apps.
116*9c5db199SXin Li        @param auto_login: Does not login automatically if this is False.
117*9c5db199SXin Li                           Useful if you need to examine oobe.
118*9c5db199SXin Li        @param gaia_login: Logs in to real gaia.
119*9c5db199SXin Li        @param username: Log in using this username instead of the default.
120*9c5db199SXin Li        @param password: Log in using this password instead of the default.
121*9c5db199SXin Li        @param gaia_id: Log in using this gaia_id instead of the default.
122*9c5db199SXin Li        @param arc_mode: How ARC instance should be started.  Default is to not
123*9c5db199SXin Li                         start.
124*9c5db199SXin Li        @param arc_timeout: Timeout to wait for ARC to boot.
125*9c5db199SXin Li        @param enable_web_app_auto_install: For tests that require to auto download and install default web applications. By default it is disabled.
126*9c5db199SXin Li        @param disable_arc_opt_in: For opt in flow autotest. This option is used
127*9c5db199SXin Li                                   to disable the arc opt in flow.
128*9c5db199SXin Li        @param disable_arc_opt_in_verification:
129*9c5db199SXin Li             Adds --disable-arc-opt-in-verification to browser args. This should
130*9c5db199SXin Li             generally be enabled when disable_arc_opt_in is enabled. However,
131*9c5db199SXin Li             for data migration tests where user's home data is already set up
132*9c5db199SXin Li             with opted-in state before login, this option needs to be set to
133*9c5db199SXin Li             False with disable_arc_opt_in=True to make ARC container work.
134*9c5db199SXin Li        @param disable_arc_cpu_restriction:
135*9c5db199SXin Li             Adds --disable-arc-cpu-restriction to browser args. This is enabled
136*9c5db199SXin Li             by default and will make tests run faster and is generally
137*9c5db199SXin Li             desirable unless a test is actually trying to test performance
138*9c5db199SXin Li             where ARC is running in the background for some porition of the
139*9c5db199SXin Li             test.
140*9c5db199SXin Li        @param disable_app_sync:
141*9c5db199SXin Li            Adds --arc-disable-app-sync to browser args and this disables ARC
142*9c5db199SXin Li            app sync flow. By default it is enabled.
143*9c5db199SXin Li        @param disable_play_auto_install:
144*9c5db199SXin Li            Adds --arc-disable-play-auto-install to browser args and this
145*9c5db199SXin Li            disables ARC Play Auto Install flow. By default it is enabled.
146*9c5db199SXin Li        @param enable_assistant: For tests that require to enable Google
147*9c5db199SXin Li                                  Assistant service. Default is False.
148*9c5db199SXin Li        @param enterprise_arc_test: Skips opt_in causing enterprise tests to fail
149*9c5db199SXin Li        @param disable_locale_sync:
150*9c5db199SXin Li            Adds --arc-disable-locale-sync to browser args and this
151*9c5db199SXin Li            disables locale sync between Chrome and Android container. In case
152*9c5db199SXin Li            of disabling sync, Android container is started with language and
153*9c5db199SXin Li            preference language list as it was set on the moment of starting
154*9c5db199SXin Li            full instance. Used to prevent random app restarts caused by racy
155*9c5db199SXin Li            locale change, coming from profile sync. By default locale sync is
156*9c5db199SXin Li            disabled.
157*9c5db199SXin Li        @param disable_play_store_auto_update:
158*9c5db199SXin Li            Adds --arc-play-store-auto-update=off to browser args and this
159*9c5db199SXin Li            disables Play Store, GMS Core and third-party apps auto-update.
160*9c5db199SXin Li            By default auto-update is off to have stable autotest environment.
161*9c5db199SXin Li        @param mute_audio: Mute audio.
162*9c5db199SXin Li        @param proxy_server: To launch the chrome with --proxy-server
163*9c5db199SXin Li            Adds '--proxy-server="http://$HTTP_PROXY:PORT"' to browser args. By
164*9c5db199SXin Li            default proxy-server is disabled
165*9c5db199SXin Li        @param login_delay: Time for idle in login screen to simulate the time
166*9c5db199SXin Li                            required for password typing.
167*9c5db199SXin Li        @param enable_features: Comma separated list of features to enable.
168*9c5db199SXin Li        """
169*9c5db199SXin Li        self._autotest_ext_path = None
170*9c5db199SXin Li
171*9c5db199SXin Li        # Force autotest extension if we need enable Play Store.
172*9c5db199SXin Li        if (utils.is_arc_available() and (arc_util.should_start_arc(arc_mode)
173*9c5db199SXin Li                                          or not disable_arc_opt_in)):
174*9c5db199SXin Li            autotest_ext = True
175*9c5db199SXin Li
176*9c5db199SXin Li        if extension_paths is None:
177*9c5db199SXin Li            extension_paths = []
178*9c5db199SXin Li
179*9c5db199SXin Li        finder_options = browser_options.BrowserFinderOptions()
180*9c5db199SXin Li        if proxy_server:
181*9c5db199SXin Li            finder_options.browser_options.AppendExtraBrowserArgs(
182*9c5db199SXin Li                ['--proxy-server="%s"' % proxy_server])
183*9c5db199SXin Li        if utils.is_arc_available() and arc_util.should_start_arc(arc_mode):
184*9c5db199SXin Li            if disable_arc_opt_in and disable_arc_opt_in_verification:
185*9c5db199SXin Li                finder_options.browser_options.AppendExtraBrowserArgs(
186*9c5db199SXin Li                    ['--disable-arc-opt-in-verification'])
187*9c5db199SXin Li            if disable_arc_cpu_restriction:
188*9c5db199SXin Li                finder_options.browser_options.AppendExtraBrowserArgs(
189*9c5db199SXin Li                    ['--disable-arc-cpu-restriction'])
190*9c5db199SXin Li            if disable_app_sync:
191*9c5db199SXin Li                finder_options.browser_options.AppendExtraBrowserArgs(
192*9c5db199SXin Li                    ['--arc-disable-app-sync'])
193*9c5db199SXin Li            if disable_play_auto_install:
194*9c5db199SXin Li                finder_options.browser_options.AppendExtraBrowserArgs(
195*9c5db199SXin Li                    ['--arc-disable-play-auto-install'])
196*9c5db199SXin Li            if disable_locale_sync:
197*9c5db199SXin Li                finder_options.browser_options.AppendExtraBrowserArgs(
198*9c5db199SXin Li                    ['--arc-disable-locale-sync'])
199*9c5db199SXin Li            if disable_play_store_auto_update:
200*9c5db199SXin Li                finder_options.browser_options.AppendExtraBrowserArgs(
201*9c5db199SXin Li                    ['--arc-play-store-auto-update=off'])
202*9c5db199SXin Li            logged_in = True
203*9c5db199SXin Li
204*9c5db199SXin Li        if autotest_ext:
205*9c5db199SXin Li            self._autotest_ext_path = os.path.join(os.path.dirname(__file__),
206*9c5db199SXin Li                                                   'autotest_private_ext')
207*9c5db199SXin Li            extension_paths.append(self._autotest_ext_path)
208*9c5db199SXin Li            finder_options.browser_options.AppendExtraBrowserArgs(
209*9c5db199SXin Li                    ['--allowlisted-extension-id=%s' % self.AUTOTEST_EXT_ID])
210*9c5db199SXin Li
211*9c5db199SXin Li        self._browser_type = (self.BROWSER_TYPE_LOGIN
212*9c5db199SXin Li                              if logged_in else self.BROWSER_TYPE_GUEST)
213*9c5db199SXin Li        finder_options.browser_type = self.browser_type
214*9c5db199SXin Li
215*9c5db199SXin Li        if not enable_web_app_auto_install:
216*9c5db199SXin Li            finder_options.browser_options.AppendExtraBrowserArgs(
217*9c5db199SXin Li                    ['--disable-features=DefaultWebAppInstallation'])
218*9c5db199SXin Li
219*9c5db199SXin Li        if not auto_login:
220*9c5db199SXin Li            finder_options.browser_options.AppendExtraBrowserArgs(
221*9c5db199SXin Li                    ['--enable-oobe-test-api'])
222*9c5db199SXin Li
223*9c5db199SXin Li        if extra_browser_args:
224*9c5db199SXin Li            finder_options.browser_options.AppendExtraBrowserArgs(
225*9c5db199SXin Li                extra_browser_args)
226*9c5db199SXin Li
227*9c5db199SXin Li        if enable_features:
228*9c5db199SXin Li            finder_options.browser_options.AppendExtraBrowserArgs(
229*9c5db199SXin Li                    ['--enable-features=%s' % enable_features])
230*9c5db199SXin Li
231*9c5db199SXin Li        # finder options must be set before parse_args(), browser options must
232*9c5db199SXin Li        # be set before Create().
233*9c5db199SXin Li        # TODO(crbug.com/360890) Below MUST be '2' so that it doesn't inhibit
234*9c5db199SXin Li        # autotest debug logs
235*9c5db199SXin Li        finder_options.verbosity = 2
236*9c5db199SXin Li        finder_options.CreateParser().parse_args(args=[])
237*9c5db199SXin Li        b_options = finder_options.browser_options
238*9c5db199SXin Li        b_options.disable_component_extensions_with_background_pages = False
239*9c5db199SXin Li        b_options.create_browser_with_oobe = True
240*9c5db199SXin Li        b_options.clear_enterprise_policy = clear_enterprise_policy
241*9c5db199SXin Li        b_options.dont_override_profile = dont_override_profile
242*9c5db199SXin Li        b_options.disable_gaia_services = disable_gaia_services
243*9c5db199SXin Li        b_options.disable_default_apps = disable_default_apps
244*9c5db199SXin Li        b_options.disable_component_extensions_with_background_pages = disable_default_apps
245*9c5db199SXin Li        b_options.disable_background_networking = False
246*9c5db199SXin Li        b_options.expect_policy_fetch = expect_policy_fetch
247*9c5db199SXin Li        b_options.auto_login = auto_login
248*9c5db199SXin Li        b_options.gaia_login = gaia_login
249*9c5db199SXin Li        b_options.mute_audio = mute_audio
250*9c5db199SXin Li        b_options.login_delay = login_delay
251*9c5db199SXin Li
252*9c5db199SXin Li        if utils.is_arc_available() and not disable_arc_opt_in:
253*9c5db199SXin Li            arc_util.set_browser_options_for_opt_in(b_options)
254*9c5db199SXin Li
255*9c5db199SXin Li        self.username = b_options.username if username is None else username
256*9c5db199SXin Li        self.password = b_options.password if password is None else password
257*9c5db199SXin Li        self.username = NormalizeEmail(self.username)
258*9c5db199SXin Li        b_options.username = self.username
259*9c5db199SXin Li        b_options.password = self.password
260*9c5db199SXin Li        self.gaia_id = b_options.gaia_id if gaia_id is None else gaia_id
261*9c5db199SXin Li        b_options.gaia_id = self.gaia_id
262*9c5db199SXin Li
263*9c5db199SXin Li        self.arc_mode = arc_mode
264*9c5db199SXin Li
265*9c5db199SXin Li        if logged_in:
266*9c5db199SXin Li            extensions_to_load = b_options.extensions_to_load
267*9c5db199SXin Li            for path in extension_paths:
268*9c5db199SXin Li                extension = extension_to_load.ExtensionToLoad(
269*9c5db199SXin Li                    path, self.browser_type)
270*9c5db199SXin Li                extensions_to_load.append(extension)
271*9c5db199SXin Li            self._extensions_to_load = extensions_to_load
272*9c5db199SXin Li
273*9c5db199SXin Li        # Turn on collection of Chrome coredumps via creation of a magic file.
274*9c5db199SXin Li        # (Without this, Chrome coredumps are trashed.)
275*9c5db199SXin Li        open(constants.CHROME_CORE_MAGIC_FILE, 'w').close()
276*9c5db199SXin Li
277*9c5db199SXin Li        self._browser_to_create = browser_finder.FindBrowser(
278*9c5db199SXin Li            finder_options)
279*9c5db199SXin Li        self._browser_to_create.SetUpEnvironment(b_options)
280*9c5db199SXin Li        for i in range(num_tries):
281*9c5db199SXin Li            try:
282*9c5db199SXin Li                self._browser = self._browser_to_create.Create()
283*9c5db199SXin Li                self._browser_pid = \
284*9c5db199SXin Li                    cros_interface.CrOSInterface().GetChromePid()
285*9c5db199SXin Li                if utils.is_arc_available():
286*9c5db199SXin Li                    if disable_arc_opt_in:
287*9c5db199SXin Li                        if arc_util.should_start_arc(arc_mode):
288*9c5db199SXin Li                            arc_util.enable_play_store(self.autotest_ext, True)
289*9c5db199SXin Li                    else:
290*9c5db199SXin Li                        if not enterprise_arc_test:
291*9c5db199SXin Li                            wait_for_provisioning = \
292*9c5db199SXin Li                                arc_mode != arc_common.ARC_MODE_ENABLED_ASYNC
293*9c5db199SXin Li                            arc_util.opt_in(
294*9c5db199SXin Li                                browser=self.browser,
295*9c5db199SXin Li                                autotest_ext=self.autotest_ext,
296*9c5db199SXin Li                                wait_for_provisioning=wait_for_provisioning)
297*9c5db199SXin Li                    arc_util.post_processing_after_browser(self, arc_timeout)
298*9c5db199SXin Li                if enable_assistant:
299*9c5db199SXin Li                    assistant_util.enable_assistant(self.autotest_ext)
300*9c5db199SXin Li                break
301*9c5db199SXin Li            except exceptions.LoginException as e:
302*9c5db199SXin Li                logging.error('Timed out logging in, tries=%d, error=%s',
303*9c5db199SXin Li                              i, repr(e))
304*9c5db199SXin Li                if i == num_tries-1:
305*9c5db199SXin Li                    raise
306*9c5db199SXin Li        if init_network_controller:
307*9c5db199SXin Li            self._browser.platform.network_controller.Open()
308*9c5db199SXin Li
309*9c5db199SXin Li    def __enter__(self):
310*9c5db199SXin Li        return self
311*9c5db199SXin Li
312*9c5db199SXin Li    def __exit__(self, *args):
313*9c5db199SXin Li        # Turn off collection of Chrome coredumps turned on in init.
314*9c5db199SXin Li        if os.path.exists(constants.CHROME_CORE_MAGIC_FILE):
315*9c5db199SXin Li            os.remove(constants.CHROME_CORE_MAGIC_FILE)
316*9c5db199SXin Li        self.close()
317*9c5db199SXin Li
318*9c5db199SXin Li    @property
319*9c5db199SXin Li    def browser(self):
320*9c5db199SXin Li        """Returns a telemetry browser instance."""
321*9c5db199SXin Li        return self._browser
322*9c5db199SXin Li
323*9c5db199SXin Li    def get_extension(self, extension_path, retry=5):
324*9c5db199SXin Li        """Fetches a telemetry extension instance given the extension path."""
325*9c5db199SXin Li        def _has_ext(ext):
326*9c5db199SXin Li            """
327*9c5db199SXin Li            Return True if the extension is fully loaded.
328*9c5db199SXin Li
329*9c5db199SXin Li            Sometimes an extension will be in the _extensions_to_load, but not
330*9c5db199SXin Li            be fully loaded, and will error when trying to fetch from
331*9c5db199SXin Li            self.browser.extensions. Happens most common when ARC is enabled.
332*9c5db199SXin Li            This will add a wait/retry.
333*9c5db199SXin Li
334*9c5db199SXin Li            @param ext: the extension to look for
335*9c5db199SXin Li            @returns True if found, False if not.
336*9c5db199SXin Li            """
337*9c5db199SXin Li            try:
338*9c5db199SXin Li                return bool(self.browser.extensions[ext])
339*9c5db199SXin Li            except KeyError:
340*9c5db199SXin Li                return False
341*9c5db199SXin Li
342*9c5db199SXin Li        for ext in self._extensions_to_load:
343*9c5db199SXin Li            if extension_path == ext.path:
344*9c5db199SXin Li                utils.poll_for_condition(lambda: _has_ext(ext),
345*9c5db199SXin Li                                         timeout=retry)
346*9c5db199SXin Li                return self.browser.extensions[ext]
347*9c5db199SXin Li        return None
348*9c5db199SXin Li
349*9c5db199SXin Li    @property
350*9c5db199SXin Li    def autotest_ext(self):
351*9c5db199SXin Li        """Returns the autotest extension."""
352*9c5db199SXin Li        return self.get_extension(self._autotest_ext_path)
353*9c5db199SXin Li
354*9c5db199SXin Li    @property
355*9c5db199SXin Li    def login_status(self):
356*9c5db199SXin Li        """Returns login status."""
357*9c5db199SXin Li        ext = self.autotest_ext
358*9c5db199SXin Li        if not ext:
359*9c5db199SXin Li            return None
360*9c5db199SXin Li
361*9c5db199SXin Li        ext.ExecuteJavaScript('''
362*9c5db199SXin Li            window.__login_status = null;
363*9c5db199SXin Li            chrome.autotestPrivate.loginStatus(function(s) {
364*9c5db199SXin Li              window.__login_status = s;
365*9c5db199SXin Li            });
366*9c5db199SXin Li        ''')
367*9c5db199SXin Li        return utils.poll_for_condition(
368*9c5db199SXin Li            lambda: ext.EvaluateJavaScript('window.__login_status'),
369*9c5db199SXin Li            timeout=10)
370*9c5db199SXin Li
371*9c5db199SXin Li    def disable_dim_display(self):
372*9c5db199SXin Li        """Avoid dim display.
373*9c5db199SXin Li
374*9c5db199SXin Li        @returns True if success otherwise False.
375*9c5db199SXin Li        """
376*9c5db199SXin Li        ext = self.autotest_ext
377*9c5db199SXin Li        if not ext:
378*9c5db199SXin Li            return False
379*9c5db199SXin Li        try:
380*9c5db199SXin Li            ext.ExecuteJavaScript(
381*9c5db199SXin Li                    '''chrome.power.requestKeepAwake("display")''')
382*9c5db199SXin Li        except:
383*9c5db199SXin Li            logging.error("failed to disable dim display")
384*9c5db199SXin Li            return False
385*9c5db199SXin Li        return True
386*9c5db199SXin Li
387*9c5db199SXin Li    def get_visible_notifications(self):
388*9c5db199SXin Li        """Returns an array of visible notifications of Chrome.
389*9c5db199SXin Li
390*9c5db199SXin Li        For specific type of each notification, please refer to Chromium's
391*9c5db199SXin Li        chrome/common/extensions/api/autotest_private.idl.
392*9c5db199SXin Li        """
393*9c5db199SXin Li        ext = self.autotest_ext
394*9c5db199SXin Li        if not ext:
395*9c5db199SXin Li            return None
396*9c5db199SXin Li
397*9c5db199SXin Li        ext.ExecuteJavaScript('''
398*9c5db199SXin Li            window.__items = null;
399*9c5db199SXin Li            chrome.autotestPrivate.getVisibleNotifications(function(items) {
400*9c5db199SXin Li              window.__items  = items;
401*9c5db199SXin Li            });
402*9c5db199SXin Li        ''')
403*9c5db199SXin Li        if ext.EvaluateJavaScript('window.__items') is None:
404*9c5db199SXin Li            return None
405*9c5db199SXin Li        return ext.EvaluateJavaScript('window.__items')
406*9c5db199SXin Li
407*9c5db199SXin Li    @property
408*9c5db199SXin Li    def browser_type(self):
409*9c5db199SXin Li        """Returns the browser_type."""
410*9c5db199SXin Li        return self._browser_type
411*9c5db199SXin Li
412*9c5db199SXin Li    @staticmethod
413*9c5db199SXin Li    def did_browser_crash(func):
414*9c5db199SXin Li        """Runs func, returns True if the browser crashed, False otherwise.
415*9c5db199SXin Li
416*9c5db199SXin Li        @param func: function to run.
417*9c5db199SXin Li
418*9c5db199SXin Li        """
419*9c5db199SXin Li        try:
420*9c5db199SXin Li            func()
421*9c5db199SXin Li        except Error:
422*9c5db199SXin Li            return True
423*9c5db199SXin Li        return False
424*9c5db199SXin Li
425*9c5db199SXin Li    @staticmethod
426*9c5db199SXin Li    def wait_for_browser_restart(func, browser):
427*9c5db199SXin Li        """Runs func, and waits for a browser restart.
428*9c5db199SXin Li
429*9c5db199SXin Li        @param func: function to run.
430*9c5db199SXin Li
431*9c5db199SXin Li        """
432*9c5db199SXin Li        _cri = cros_interface.CrOSInterface()
433*9c5db199SXin Li        pid = _cri.GetChromePid()
434*9c5db199SXin Li        Chrome.did_browser_crash(func)
435*9c5db199SXin Li        utils.poll_for_condition(
436*9c5db199SXin Li            lambda: pid != _cri.GetChromePid(), timeout=60)
437*9c5db199SXin Li        browser.WaitForBrowserToComeUp()
438*9c5db199SXin Li
439*9c5db199SXin Li    def wait_for_browser_to_come_up(self):
440*9c5db199SXin Li        """Waits for the browser to come up. This should only be called after a
441*9c5db199SXin Li        browser crash.
442*9c5db199SXin Li        """
443*9c5db199SXin Li        def _BrowserReady(cr):
444*9c5db199SXin Li            tabs = []  # Wrapper for pass by reference.
445*9c5db199SXin Li            if self.did_browser_crash(
446*9c5db199SXin Li                    lambda: tabs.append(cr.browser.tabs.New())):
447*9c5db199SXin Li                return False
448*9c5db199SXin Li            try:
449*9c5db199SXin Li                tabs[0].Close()
450*9c5db199SXin Li            except:
451*9c5db199SXin Li                # crbug.com/350941
452*9c5db199SXin Li                logging.error('Timed out closing tab')
453*9c5db199SXin Li            return True
454*9c5db199SXin Li        py_utils.WaitFor(lambda: _BrowserReady(self), timeout=10)
455*9c5db199SXin Li
456*9c5db199SXin Li    def close(self):
457*9c5db199SXin Li        """Closes the browser.
458*9c5db199SXin Li        """
459*9c5db199SXin Li        try:
460*9c5db199SXin Li            if utils.is_arc_available():
461*9c5db199SXin Li                arc_util.pre_processing_before_close(self)
462*9c5db199SXin Li        finally:
463*9c5db199SXin Li            # Calling platform.StopAllLocalServers() to tear down the telemetry
464*9c5db199SXin Li            # server processes such as the one started by
465*9c5db199SXin Li            # platform.SetHTTPServerDirectories().  Not calling this function
466*9c5db199SXin Li            # will leak the process and may affect test results.
467*9c5db199SXin Li            # (crbug.com/663387)
468*9c5db199SXin Li            self._browser.platform.StopAllLocalServers()
469*9c5db199SXin Li            self._browser.Close()
470*9c5db199SXin Li            self._browser_to_create.CleanUpEnvironment()
471*9c5db199SXin Li            self._browser.platform.network_controller.Close()
472