1424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# found in the LICENSE file.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import logging
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import os
71320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciimport pipes
8f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import re
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import subprocess
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import sys
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import time
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from telemetry.core import exceptions
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from telemetry.core import forwarders
157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochfrom telemetry.core import util
16424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)from telemetry.core.backends import adb_commands
17a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)from telemetry.core.backends import browser_backend
18a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)from telemetry.core.backends.chrome import chrome_browser_backend
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from telemetry.core.forwarders import android_forwarder
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
21116680a4aac90f2aa7413d9095a592090648e557Ben Murdochutil.AddDirToPythonPath(util.GetChromiumSrcDir(), 'build', 'android')
22116680a4aac90f2aa7413d9095a592090648e557Ben Murdochfrom pylib.device import device_errors  # pylint: disable=F0401
23116680a4aac90f2aa7413d9095a592090648e557Ben Murdochfrom pylib.device import intent  # pylint: disable=F0401
24116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
25a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
26a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)class AndroidBrowserBackendSettings(object):
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def __init__(self, activity, cmdline_file, package, pseudo_exec_name,
296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)               supports_tab_control, relax_ssl_check=False):
30a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.activity = activity
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self._cmdline_file = cmdline_file
32a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.package = package
33a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.pseudo_exec_name = pseudo_exec_name
341e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.supports_tab_control = supports_tab_control
356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    self.relax_ssl_check = relax_ssl_check
36a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def GetCommandLineFile(self, is_user_debug_build):  # pylint: disable=W0613
381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return self._cmdline_file
391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def GetDevtoolsRemotePort(self, adb):
41a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    raise NotImplementedError()
42a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def RemoveProfile(self, adb):
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    files = adb.device().RunShellCommand(
45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        'ls "%s"' % self.profile_dir, as_root=True)
46f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    # Don't delete lib, since it is created by the installer.
47a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    paths = ['"%s/%s"' % (self.profile_dir, f) for f in files if f != 'lib']
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    adb.device().RunShellCommand('rm -r %s' % ' '.join(paths), as_root=True)
49a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def PushProfile(self, _new_profile_dir, _adb):
51a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    logging.critical('Profiles cannot be overriden with current configuration')
52a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    sys.exit(1)
53a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
54a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  @property
55bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  def profile_dir(self):
56f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return '/data/data/%s/' % self.package
57a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
58a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
59a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)class ChromeBackendSettings(AndroidBrowserBackendSettings):
60a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # Stores a default Preferences file, re-used to speed up "--page-repeat".
61a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  _default_preferences_file = None
62a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def GetCommandLineFile(self, is_user_debug_build):
641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if is_user_debug_build:
65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return '/data/local/tmp/chrome-command-line'
66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    else:
67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return '/data/local/chrome-command-line'
68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def __init__(self, package):
70a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    super(ChromeBackendSettings, self).__init__(
71a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        activity='com.google.android.apps.chrome.Main',
721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        cmdline_file=None,
73a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        package=package,
741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        pseudo_exec_name='chrome',
751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        supports_tab_control=True)
76a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def GetDevtoolsRemotePort(self, adb):
78a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return 'localabstract:chrome_devtools_remote'
79a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def PushProfile(self, new_profile_dir, adb):
81f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    # Pushing the profile is slow, so we don't want to do it every time.
82116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    # Avoid this by pushing to a safe location using PushChangedFiles, and
83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    # then copying into the correct location on each test run.
84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    (profile_parent, profile_base) = os.path.split(new_profile_dir)
86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    # If the path ends with a '/' python split will return an empty string for
87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    # the base name; so we now need to get the base name from the directory.
88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if not profile_base:
89f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      profile_base = os.path.basename(profile_parent)
90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    saved_profile_location = '/sdcard/profile/%s' % profile_base
921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    adb.device().PushChangedFiles(new_profile_dir, saved_profile_location)
93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    adb.device().old_interface.EfficientDeviceDirectoryCopy(
955c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        saved_profile_location, self.profile_dir)
961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    dumpsys = adb.device().RunShellCommand(
97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        'dumpsys package %s' % self.package)
98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    id_line = next(line for line in dumpsys if 'userId=' in line)
99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    uid = re.search('\d+', id_line).group()
1001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    files = adb.device().RunShellCommand(
101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        'ls "%s"' % self.profile_dir, as_root=True)
102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    files.remove('lib')
103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    paths = ['%s/%s' % (self.profile_dir, f) for f in files]
104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    for path in paths:
105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      extended_path = '%s %s/* %s/*/* %s/*/*/*' % (path, path, path, path)
1061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      adb.device().RunShellCommand(
107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          'chown %s.%s %s' % (uid, uid, extended_path))
108a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
109a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)class ContentShellBackendSettings(AndroidBrowserBackendSettings):
1101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def __init__(self, package):
111a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    super(ContentShellBackendSettings, self).__init__(
112a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        activity='org.chromium.content_shell_apk.ContentShellActivity',
113a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        cmdline_file='/data/local/tmp/content-shell-command-line',
114a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        package=package,
1151e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        pseudo_exec_name='content_shell',
1161e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        supports_tab_control=False)
117a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def GetDevtoolsRemotePort(self, adb):
119a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return 'localabstract:content_shell_devtools_remote'
120a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
121a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
122a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class ChromeShellBackendSettings(AndroidBrowserBackendSettings):
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def __init__(self, package):
124a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    super(ChromeShellBackendSettings, self).__init__(
125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          activity='org.chromium.chrome.shell.ChromeShellActivity',
126a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          cmdline_file='/data/local/tmp/chrome-shell-command-line',
12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          package=package,
128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          pseudo_exec_name='chrome_shell',
1291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          supports_tab_control=False)
13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def GetDevtoolsRemotePort(self, adb):
132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return 'localabstract:chrome_shell_devtools_remote'
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
134a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)class WebviewBackendSettings(AndroidBrowserBackendSettings):
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def __init__(self, package,
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci               activity='org.chromium.telemetry_shell.TelemetryActivity'):
137a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    super(WebviewBackendSettings, self).__init__(
1381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        activity=activity,
139a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        cmdline_file='/data/local/tmp/webview-command-line',
140a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        package=package,
1411e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        pseudo_exec_name='webview',
1421e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        supports_tab_control=False)
143a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
1441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def GetDevtoolsRemotePort(self, adb):
145a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    # The DevTools socket name for WebView depends on the activity PID's.
146a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    retries = 0
147a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    timeout = 1
148a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    pid = None
149a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    while True:
1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      pids = adb.ExtractPid(self.package)
151a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      if (len(pids) > 0):
152a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        pid = pids[-1]
153a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        break
154a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      time.sleep(timeout)
155a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      retries += 1
156a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      timeout *= 2
157a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      if retries == 4:
158a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        logging.critical('android_browser_backend: Timeout while waiting for '
159a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                         'activity %s:%s to come up',
160a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                         self.package,
161a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                         self.activity)
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        raise exceptions.BrowserGoneException(self.browser,
163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                                              'Timeout waiting for PID.')
164a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return 'localabstract:webview_devtools_remote_%s' % str(pid)
165a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
1661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass WebviewShellBackendSettings(WebviewBackendSettings):
1671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def __init__(self, package):
1681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    super(WebviewShellBackendSettings, self).__init__(
1691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        activity='org.chromium.android_webview.shell.AwShellActivity',
1701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        package=package)
171a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
172a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)class AndroidBrowserBackend(chrome_browser_backend.ChromeBrowserBackend):
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  """The backend for controlling a browser instance running on Android."""
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def __init__(self, browser_options, backend_settings, use_rndis_forwarder,
1751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci               output_profile_path, extensions_to_load, target_arch,
1761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci               android_platform_backend):
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    super(AndroidBrowserBackend, self).__init__(
178116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        supports_tab_control=backend_settings.supports_tab_control,
17958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        supports_extensions=False, browser_options=browser_options,
18058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        output_profile_path=output_profile_path,
18158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        extensions_to_load=extensions_to_load)
18258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if len(extensions_to_load) > 0:
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      raise browser_backend.ExtensionsNotSupportedException(
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          'Android browser does not support extensions.')
18568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Initialize fields so that an explosion during init doesn't break in Close.
1871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self._android_platform_backend = android_platform_backend
188a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self._backend_settings = backend_settings
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._saved_cmdline = ''
1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    self._target_arch = target_arch
1916e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    self._saved_sslflag = ''
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # TODO(tonyg): This is flaky because it doesn't reserve the port that it
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # allocates. Need to fix this.
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._port = adb_commands.AllocateTestServerPort()
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    # Disables android.net SSL certificate check.  This is necessary for
1981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    # applications using the android.net stack to work with proxy HTTPS server
1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    # created by telemetry
2001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if self._backend_settings.relax_ssl_check:
2011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      self._saved_sslflag = self._adb.device().GetProp('socket.relaxsslcheck')
2021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      self._adb.device().SetProp('socket.relaxsslcheck', 'yes')
2031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Kill old browser.
2051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self._KillBrowser()
2067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2075c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if self._adb.device().old_interface.CanAccessProtectedFileContents():
20858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if self.browser_options.profile_dir:
2091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        self._backend_settings.PushProfile(self.browser_options.profile_dir,
2101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                           self._adb)
211a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      elif not self.browser_options.dont_override_profile:
2121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        self._backend_settings.RemoveProfile(self._adb)
2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._forwarder_factory = android_forwarder.AndroidForwarderFactory(
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        self._adb, use_rndis_forwarder)
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if self.browser_options.netsim or use_rndis_forwarder:
2186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      assert use_rndis_forwarder, 'Netsim requires RNDIS forwarding.'
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self.wpr_port_pairs = forwarders.PortPairs(
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          http=forwarders.PortPair(0, 80),
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          https=forwarders.PortPair(0, 443),
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          dns=forwarders.PortPair(0, 53))
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Set the debug app if needed.
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self._adb.IsUserBuild():
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      logging.debug('User build device, setting debug app')
227f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      self._adb.device().RunShellCommand(
228f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          'am set-debug-app --persistent %s' % self._backend_settings.package)
22958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
2301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  @property
2311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def _adb(self):
2321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    return self._android_platform_backend.adb
2331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def _KillBrowser(self):
2351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    # We use KillAll rather than ForceStop for efficiency reasons.
2361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    try:
2371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      self._adb.device().KillAll(self._backend_settings.package, retries=0)
2381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    except device_errors.CommandFailedError:
2391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      pass
2401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
24158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  def _SetUpCommandLine(self):
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    def QuoteIfNeeded(arg):
2431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      # Properly escape "key=valueA valueB" to "key='valueA valueB'"
2441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      # Values without spaces, or that seem to be quoted are left untouched.
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # This is required so CommandLine.java can parse valueB correctly rather
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # than as a separate switch.
247f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      params = arg.split('=', 1)
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if len(params) != 2:
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return arg
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      key, values = params
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if ' ' not in values:
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return arg
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if values[0] in '"\'' and values[-1] == values[0]:
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return arg
2551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      return '%s=%s' % (key, pipes.quote(values))
25658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    args = [self._backend_settings.pseudo_exec_name]
25758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    args.extend(self.GetBrowserStartupArgs())
2581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    content = ' '.join(QuoteIfNeeded(arg) for arg in args)
2591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    cmdline_file = self._backend_settings.GetCommandLineFile(
2601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        self._adb.IsUserBuild())
2611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    as_root = self._adb.device().old_interface.CanAccessProtectedFileContents()
2621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
263116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    try:
2641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      # Save the current command line to restore later, except if it appears to
2651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      # be a  Telemetry created one. This is to prevent a common bug where
2661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      # --host-resolver-rules borks people's browsers if something goes wrong
2671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      # with Telemetry.
2681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      self._saved_cmdline = ''.join(self._adb.device().ReadFile(cmdline_file))
2691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if '--host-resolver-rules' in self._saved_cmdline:
2701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        self._saved_cmdline = ''
2711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      self._adb.device().WriteTextFile(cmdline_file, content, as_root=as_root)
272116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    except device_errors.CommandFailedError:
273116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      logging.critical('Cannot set Chrome command line. '
274116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                       'Fix this by flashing to a userdebug build.')
275116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      sys.exit(1)
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def _RestoreCommandLine(self):
2781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    cmdline_file = self._backend_settings.GetCommandLineFile(
2791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        self._adb.IsUserBuild())
2801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    as_root = self._adb.device().old_interface.CanAccessProtectedFileContents()
2811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self._adb.device().WriteTextFile(cmdline_file, self._saved_cmdline,
2821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                     as_root=as_root)
2831320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
284a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  def Start(self):
285f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self._SetUpCommandLine()
2866e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
287f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    self._adb.device().RunShellCommand('logcat -c')
2881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if self.browser_options.startup_url:
2891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      url = self.browser_options.startup_url
290f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    elif self.browser_options.profile_dir:
291f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      url = None
2921e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    else:
293f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      # If we have no existing tabs start with a blank page since default
294f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      # startup with the NTP can lead to race conditions with Telemetry
2951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      url = 'about:blank'
2965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    # Dismiss any error dialogs. Limit the number in case we have an error loop
2975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    # or we are failing to dismiss.
2985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    for _ in xrange(10):
2995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if not self._adb.device().old_interface.DismissCrashDialogIfNeeded():
3005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        break
301116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    self._adb.device().StartActivity(
302116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        intent.Intent(package=self._backend_settings.package,
303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                      activity=self._backend_settings.activity,
304116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                      action=None, data=url, category=None),
305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        blocking=True)
306a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
307a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self._adb.Forward('tcp:%d' % self._port,
3081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                      self._backend_settings.GetDevtoolsRemotePort(self._adb))
309a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    try:
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      self._WaitForBrowserToComeUp()
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    except exceptions.BrowserGoneException:
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      logging.critical('Failed to connect to browser.')
3145c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      if not self._adb.device().old_interface.CanAccessProtectedFileContents():
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        logging.critical(
3162385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch          'Resolve this by either: '
3172385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch          '(1) Flashing to a userdebug build OR '
3182385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch          '(2) Manually enabling web debugging in Chrome at '
3192385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch          'Settings > Developer tools > Enable USB Web debugging.')
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      sys.exit(1)
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    except:
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      import traceback
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      traceback.print_exc()
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      self.Close()
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      raise
3260f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    finally:
3271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      self._RestoreCommandLine()
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def GetBrowserStartupArgs(self):
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    args = super(AndroidBrowserBackend, self).GetBrowserStartupArgs()
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.forwarder_factory.does_forwarder_override_dns:
33258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      args = [arg for arg in args
33358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)              if not arg.startswith('--host-resolver-rules')]
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    args.append('--enable-remote-debugging')
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    args.append('--disable-fre')
336f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    args.append('--disable-external-intent-requests')
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return args
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @property
3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def forwarder_factory(self):
3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return self._forwarder_factory
3425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  @property
34490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  def adb(self):
34590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return self._adb
34690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
34790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  @property
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def pid(self):
34968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    pids = self._adb.ExtractPid(self._backend_settings.package)
35068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if not pids:
351cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      raise exceptions.BrowserGoneException(self.browser)
35268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return int(pids[0])
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
354bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  @property
355bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  def browser_directory(self):
356bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    return None
357bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
358bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  @property
359bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  def profile_directory(self):
360bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    return self._backend_settings.profile_dir
361bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
362424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  @property
363424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  def package(self):
364424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return self._backend_settings.package
365424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
3664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  @property
3674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def activity(self):
3684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return self._backend_settings.activity
3694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def __del__(self):
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self.Close()
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def Close(self):
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    super(AndroidBrowserBackend, self).Close()
3751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self._KillBrowser()
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3776e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    # Restore android.net SSL check
3786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    if self._backend_settings.relax_ssl_check:
3796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      self._adb.device().SetProp('socket.relaxsslcheck', self._saved_sslflag)
3806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
38158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if self._output_profile_path:
38258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      logging.info("Pulling profile directory from device: '%s'->'%s'.",
38358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                   self._backend_settings.profile_dir,
38458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                   self._output_profile_path)
385424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      # To minimize bandwidth it might be good to look at whether all the data
386424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      # pulled down is really needed e.g. .pak files.
387f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if not os.path.exists(self._output_profile_path):
388f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        os.makedirs(self._output_profile_pathame)
389f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      files = self.adb.device().RunShellCommand(
390a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          'ls "%s"' % self._backend_settings.profile_dir)
391f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      for f in files:
392f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        # Don't pull lib, since it is created by the installer.
393f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if f != 'lib':
394f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          source = '%s%s' % (self._backend_settings.profile_dir, f)
395f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          dest = os.path.join(self._output_profile_path, f)
396f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          # self._adb.Pull(source, dest) doesn't work because its timeout
397f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          # is fixed in android's adb_interface at 60 seconds, which may
398f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          # be too short to pull the cache.
399f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          cmd = 'pull %s %s' % (source, dest)
4005c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          self._adb.device().old_interface.Adb().SendCommand(
4015c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu              cmd, timeout_time=240)
402424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def IsBrowserRunning(self):
404a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    pids = self._adb.ExtractPid(self._backend_settings.package)
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return len(pids) != 0
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def GetRemotePort(self, local_port):
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return local_port
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def GetStandardOutput(self):
411f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return '\n'.join(self._adb.device().RunShellCommand('logcat -d -t 500'))
4127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def GetStackTrace(self):
4147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    def Decorate(title, content):
4157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      return title + '\n' + content + '\n' + '*' * 80 + '\n'
4167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    # Get the last lines of logcat (large enough to contain stacktrace)
4177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    logcat = self.GetStandardOutput()
4187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ret = Decorate('Logcat', logcat)
4197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    stack = os.path.join(util.GetChromiumSrcDir(), 'third_party',
4207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                         'android_platform', 'development', 'scripts', 'stack')
4217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    # Try to symbolize logcat.
4227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if os.path.exists(stack):
4235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      cmd = [stack]
4245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if self._target_arch:
4255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        cmd.append('--arch=%s' % self._target_arch)
4265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
4277dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      ret += Decorate('Stack from Logcat', p.communicate(input=logcat)[0])
4287dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    # Try to get tombstones.
4307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    tombstones = os.path.join(util.GetChromiumSrcDir(), 'build', 'android',
4317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                              'tombstones.py')
4327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if os.path.exists(tombstones):
4337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      ret += Decorate('Tombstones',
4347dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                      subprocess.Popen([tombstones, '-w', '--device',
4355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                        self._adb.device_serial()],
4367dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                       stdout=subprocess.PIPE).communicate()[0])
4377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return ret
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
43958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  def AddReplayServerOptions(self, extra_wpr_args):
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if not self.forwarder_factory.does_forwarder_override_dns:
44158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      extra_wpr_args.append('--no-dns_forwarding')
442f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if self.browser_options.netsim:
443f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      extra_wpr_args.append('--net=%s' % self.browser_options.netsim)
444