android_browser_backend.py revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
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
7f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import re
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import subprocess
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import sys
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import time
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from telemetry.core import exceptions
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from telemetry.core import forwarders
147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochfrom telemetry.core import util
15424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)from telemetry.core.backends import adb_commands
16a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)from telemetry.core.backends import browser_backend
17a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)from telemetry.core.backends.chrome import chrome_browser_backend
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from telemetry.core.forwarders import android_forwarder
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
20a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
21a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)class AndroidBrowserBackendSettings(object):
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
231e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  def __init__(self, adb, activity, cmdline_file, package, pseudo_exec_name,
241e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)               supports_tab_control):
25a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.adb = adb
26a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.activity = activity
27a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.cmdline_file = cmdline_file
28a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.package = package
29a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self.pseudo_exec_name = pseudo_exec_name
301e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    self.supports_tab_control = supports_tab_control
31a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
32a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  def GetDevtoolsRemotePort(self):
33a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    raise NotImplementedError()
34a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
35a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  def RemoveProfile(self):
36a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    files = self.adb.RunShellCommandWithSU('ls "%s"' % self.profile_dir)
37f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    # Don't delete lib, since it is created by the installer.
38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    paths = ['"%s/%s"' % (self.profile_dir, f) for f in files if f != 'lib']
39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    self.adb.RunShellCommandWithSU('rm -r %s' % ' '.join(paths))
40a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
41a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  def PushProfile(self, _):
42a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    logging.critical('Profiles cannot be overriden with current configuration')
43a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    sys.exit(1)
44a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
45a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  @property
46a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  def is_content_shell(self):
47a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return False
48a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
49a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  @property
50bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  def profile_dir(self):
51f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return '/data/data/%s/' % self.package
52a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
53a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
54a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)class ChromeBackendSettings(AndroidBrowserBackendSettings):
55a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  # Stores a default Preferences file, re-used to speed up "--page-repeat".
56a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  _default_preferences_file = None
57a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  @staticmethod
59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  def _GetCommandLineFile(adb):
60a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    if adb.IsUserBuild():
61a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return '/data/local/tmp/chrome-command-line'
62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    else:
63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return '/data/local/chrome-command-line'
64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
65a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  def __init__(self, adb, package):
66a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    super(ChromeBackendSettings, self).__init__(
67a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        adb=adb,
68a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        activity='com.google.android.apps.chrome.Main',
69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        cmdline_file=ChromeBackendSettings._GetCommandLineFile(adb),
70a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        package=package,
711e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        pseudo_exec_name='chrome',
721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        supports_tab_control=True)
73a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
74a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  def GetDevtoolsRemotePort(self):
75a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return 'localabstract:chrome_devtools_remote'
76a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
77a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  def PushProfile(self, new_profile_dir):
78f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    # Pushing the profile is slow, so we don't want to do it every time.
79f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    # Avoid this by pushing to a safe location using PushIfNeeded, and
80f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    # then copying into the correct location on each test run.
81f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
82f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    (profile_parent, profile_base) = os.path.split(new_profile_dir)
83f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    # If the path ends with a '/' python split will return an empty string for
84f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    # the base name; so we now need to get the base name from the directory.
85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if not profile_base:
86f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      profile_base = os.path.basename(profile_parent)
87f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
88f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    saved_profile_location = '/sdcard/profile/%s' % profile_base
895c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    self.adb.device().old_interface.PushIfNeeded(
905c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        new_profile_dir, saved_profile_location)
91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    self.adb.device().old_interface.EfficientDeviceDirectoryCopy(
935c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        saved_profile_location, self.profile_dir)
94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    dumpsys = self.adb.RunShellCommand('dumpsys package %s' % self.package)
95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    id_line = next(line for line in dumpsys if 'userId=' in line)
96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    uid = re.search('\d+', id_line).group()
97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    files = self.adb.RunShellCommandWithSU('ls "%s"' % self.profile_dir)
98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    files.remove('lib')
99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    paths = ['%s/%s' % (self.profile_dir, f) for f in files]
100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    for path in paths:
101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      extended_path = '%s %s/* %s/*/* %s/*/*/*' % (path, path, path, path)
102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      self.adb.RunShellCommand('chown %s.%s %s' %
103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                             (uid, uid, extended_path))
104a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
105a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)class ContentShellBackendSettings(AndroidBrowserBackendSettings):
106a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  def __init__(self, adb, package):
107a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    super(ContentShellBackendSettings, self).__init__(
108a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        adb=adb,
109a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        activity='org.chromium.content_shell_apk.ContentShellActivity',
110a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        cmdline_file='/data/local/tmp/content-shell-command-line',
111a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        package=package,
1121e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        pseudo_exec_name='content_shell',
1131e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        supports_tab_control=False)
114a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
115a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  def GetDevtoolsRemotePort(self):
116a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return 'localabstract:content_shell_devtools_remote'
117a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
118a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  @property
119a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  def is_content_shell(self):
120a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return True
121a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
122a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
123a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class ChromeShellBackendSettings(AndroidBrowserBackendSettings):
12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  def __init__(self, adb, package):
125a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    super(ChromeShellBackendSettings, self).__init__(
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          adb=adb,
127a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          activity='org.chromium.chrome.shell.ChromeShellActivity',
128a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          cmdline_file='/data/local/tmp/chrome-shell-command-line',
12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)          package=package,
130a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)          pseudo_exec_name='chrome_shell',
1311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)          supports_tab_control=False)
13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  def GetDevtoolsRemotePort(self):
134a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return 'localabstract:chrome_shell_devtools_remote'
13590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
13690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  @property
13790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  def is_content_shell(self):
13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return True
13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
141a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)class WebviewBackendSettings(AndroidBrowserBackendSettings):
142a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  def __init__(self, adb, package):
143a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    super(WebviewBackendSettings, self).__init__(
144a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        adb=adb,
145a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        activity='com.android.webview.chromium.shell.TelemetryActivity',
146a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        cmdline_file='/data/local/tmp/webview-command-line',
147a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        package=package,
1481e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        pseudo_exec_name='webview',
1491e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        supports_tab_control=False)
150a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
151a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  def GetDevtoolsRemotePort(self):
152a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    # The DevTools socket name for WebView depends on the activity PID's.
153a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    retries = 0
154a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    timeout = 1
155a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    pid = None
156a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    while True:
157a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      pids = self.adb.ExtractPid(self.package)
158a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      if (len(pids) > 0):
159a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        pid = pids[-1]
160a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        break
161a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      time.sleep(timeout)
162a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      retries += 1
163a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      timeout *= 2
164a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      if retries == 4:
165a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        logging.critical('android_browser_backend: Timeout while waiting for '
166a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                         'activity %s:%s to come up',
167a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                         self.package,
168a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                         self.activity)
169a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        raise exceptions.BrowserGoneException('Timeout waiting for PID.')
170a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return 'localabstract:webview_devtools_remote_%s' % str(pid)
171a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
172a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
173a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)class AndroidBrowserBackend(chrome_browser_backend.ChromeBrowserBackend):
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  """The backend for controlling a browser instance running on Android."""
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def __init__(self, browser_options, backend_settings, use_rndis_forwarder,
17658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)               output_profile_path, extensions_to_load):
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    super(AndroidBrowserBackend, self).__init__(
178a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        is_content_shell=backend_settings.is_content_shell,
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.
187a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self._adb = backend_settings.adb
188a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self._backend_settings = backend_settings
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._saved_cmdline = ''
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # TODO(tonyg): This is flaky because it doesn't reserve the port that it
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # allocates. Need to fix this.
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._port = adb_commands.AllocateTestServerPort()
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    # Kill old browser.
196a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self._adb.CloseApplication(self._backend_settings.package)
1977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1985c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    if self._adb.device().old_interface.CanAccessProtectedFileContents():
19958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if self.browser_options.profile_dir:
20058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        self._backend_settings.PushProfile(self.browser_options.profile_dir)
201a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      elif not self.browser_options.dont_override_profile:
202a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        self._backend_settings.RemoveProfile()
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._forwarder_factory = android_forwarder.AndroidForwarderFactory(
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        self._adb, use_rndis_forwarder)
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.browser_options.netsim:
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      assert use_rndis_forwarder, 'Netsim requires RNDIS forwarding.'
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self.wpr_port_pairs = forwarders.PortPairs(
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          http=forwarders.PortPair(0, 80),
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          https=forwarders.PortPair(0, 443),
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          dns=forwarders.PortPair(0, 53))
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    # Set the debug app if needed.
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self._adb.IsUserBuild():
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      logging.debug('User build device, setting debug app')
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self._adb.RunShellCommand('am set-debug-app --persistent %s' %
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                self._backend_settings.package)
21958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
22058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  def _SetUpCommandLine(self):
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    def QuoteIfNeeded(arg):
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # Escape 'key=valueA valueB' to 'key="valueA valueB"'
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # Already quoted values, or values without space are left untouched.
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # This is required so CommandLine.java can parse valueB correctly rather
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      # than as a separate switch.
226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      params = arg.split('=', 1)
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if len(params) != 2:
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return arg
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      key, values = params
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if ' ' not in values:
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return arg
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if values[0] in '"\'' and values[-1] == values[0]:
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return arg
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return '%s="%s"' % (key, values)
23558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    args = [self._backend_settings.pseudo_exec_name]
23658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    args.extend(self.GetBrowserStartupArgs())
23758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    args = ' '.join(map(QuoteIfNeeded, args))
23858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
23958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    self._SetCommandLineFile(args)
24058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
24158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  def _SetCommandLineFile(self, file_contents):
242f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    logging.debug('Using command line: ' + file_contents)
24358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    def IsProtectedFile(name):
2445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      if self._adb.device().old_interface.FileExistsOnDevice(name):
2455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu        return not self._adb.device().old_interface.IsFileWritableOnDevice(name)
24658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      else:
24758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        parent_name = os.path.dirname(name)
24858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        if parent_name != '':
24958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          return IsProtectedFile(parent_name)
25058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        else:
25158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          return True
25258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
25358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if IsProtectedFile(self._backend_settings.cmdline_file):
2545c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      if not self._adb.device().old_interface.CanAccessProtectedFileContents():
25558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        logging.critical('Cannot set Chrome command line. '
25658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                         'Fix this by flashing to a userdebug build.')
25758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        sys.exit(1)
2585c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      self._saved_cmdline = ''.join(
2595c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          self._adb.device().old_interface.GetProtectedFileContents(
2605c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu              self._backend_settings.cmdline_file)
2615c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          or [])
2625c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      self._adb.device().old_interface.SetProtectedFileContents(
26358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)          self._backend_settings.cmdline_file, file_contents)
26458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    else:
2655c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      self._saved_cmdline = ''.join(
2665c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          self._adb.device().old_interface.GetFileContents(
2675c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu              self._backend_settings.cmdline_file)
2685c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          or [])
2695c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      self._adb.device().old_interface.SetFileContents(
2705c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          self._backend_settings.cmdline_file, file_contents)
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
272a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  def Start(self):
273f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    self._SetUpCommandLine()
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._adb.RunShellCommand('logcat -c')
2751e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    if self.browser_options.startup_url:
2761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      url = self.browser_options.startup_url
277f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    elif self.browser_options.profile_dir:
278f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      url = None
2791e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    else:
280f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      # If we have no existing tabs start with a blank page since default
281f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      # startup with the NTP can lead to race conditions with Telemetry
2821e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)      url = 'about:blank'
2835c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    self._adb.device().old_interface.DismissCrashDialogIfNeeded()
284a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self._adb.StartActivity(self._backend_settings.package,
285a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)                            self._backend_settings.activity,
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            True,
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            None,
28858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            None,
2891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                            url)
290a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
291a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self._adb.Forward('tcp:%d' % self._port,
292a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)                      self._backend_settings.GetDevtoolsRemotePort())
293a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    try:
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      self._WaitForBrowserToComeUp()
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      self._PostBrowserStartupInitialization()
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    except exceptions.BrowserGoneException:
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      logging.critical('Failed to connect to browser.')
2995c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      if not self._adb.device().old_interface.CanAccessProtectedFileContents():
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        logging.critical(
3012385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch          'Resolve this by either: '
3022385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch          '(1) Flashing to a userdebug build OR '
3032385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch          '(2) Manually enabling web debugging in Chrome at '
3042385ea399aae016c0806a4f9ef3c9cfe3d2a39dfBen Murdoch          'Settings > Developer tools > Enable USB Web debugging.')
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      sys.exit(1)
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    except:
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      import traceback
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      traceback.print_exc()
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      self.Close()
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      raise
3110f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    finally:
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      # Restore the saved command line if it appears to have come from a user.
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      # If it appears to be a Telemetry created command line, then don't restore
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      # it. This is to prevent a common bug where --host-resolver-rules borks
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      # people's browsers if something goes wrong with Telemetry.
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self._SetCommandLineFile(
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          self._saved_cmdline
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          if '--host-resolver-rules' not in self._saved_cmdline else '')
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def GetBrowserStartupArgs(self):
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    args = super(AndroidBrowserBackend, self).GetBrowserStartupArgs()
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.forwarder_factory.does_forwarder_override_dns:
32358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      args = [arg for arg in args
32458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)              if not arg.startswith('--host-resolver-rules')]
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    args.append('--enable-remote-debugging')
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    args.append('--disable-fre')
327f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    args.append('--disable-external-intent-requests')
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return args
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @property
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def forwarder_factory(self):
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return self._forwarder_factory
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  @property
33590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  def adb(self):
33690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return self._adb
33790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
33890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  @property
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def pid(self):
34068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    pids = self._adb.ExtractPid(self._backend_settings.package)
34168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    if not pids:
34268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      raise exceptions.BrowserGoneException(self.GetStackTrace())
34368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    return int(pids[0])
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
345bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  @property
346bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  def browser_directory(self):
347bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    return None
348bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
349bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  @property
350bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch  def profile_directory(self):
351bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    return self._backend_settings.profile_dir
352bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch
353424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  @property
354424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  def package(self):
355424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    return self._backend_settings.package
356424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
3574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  @property
3584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  def activity(self):
3594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return self._backend_settings.activity
3604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
3611e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  @property
3621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)  def supports_tab_control(self):
3631e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    return self._backend_settings.supports_tab_control
3641e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def __del__(self):
3662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self.Close()
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def Close(self):
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    super(AndroidBrowserBackend, self).Close()
370a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    self._adb.CloseApplication(self._backend_settings.package)
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
37258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    if self._output_profile_path:
37358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      logging.info("Pulling profile directory from device: '%s'->'%s'.",
37458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                   self._backend_settings.profile_dir,
37558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                   self._output_profile_path)
376424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      # To minimize bandwidth it might be good to look at whether all the data
377424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      # pulled down is really needed e.g. .pak files.
378f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      if not os.path.exists(self._output_profile_path):
379f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        os.makedirs(self._output_profile_pathame)
380a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      files = self.adb.RunShellCommandWithSU(
381a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          'ls "%s"' % self._backend_settings.profile_dir)
382f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      for f in files:
383f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        # Don't pull lib, since it is created by the installer.
384f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if f != 'lib':
385f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          source = '%s%s' % (self._backend_settings.profile_dir, f)
386f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          dest = os.path.join(self._output_profile_path, f)
387f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          # self._adb.Pull(source, dest) doesn't work because its timeout
388f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          # is fixed in android's adb_interface at 60 seconds, which may
389f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          # be too short to pull the cache.
390f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)          cmd = 'pull %s %s' % (source, dest)
3915c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu          self._adb.device().old_interface.Adb().SendCommand(
3925c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu              cmd, timeout_time=240)
393424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def IsBrowserRunning(self):
395a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    pids = self._adb.ExtractPid(self._backend_settings.package)
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return len(pids) != 0
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def GetRemotePort(self, local_port):
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return local_port
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def GetStandardOutput(self):
4027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return '\n'.join(self._adb.RunShellCommand('logcat -d -t 500'))
4037dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4047dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def GetStackTrace(self):
4057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    def Decorate(title, content):
4067dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      return title + '\n' + content + '\n' + '*' * 80 + '\n'
4077dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    # Get the last lines of logcat (large enough to contain stacktrace)
4087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    logcat = self.GetStandardOutput()
4097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    ret = Decorate('Logcat', logcat)
4107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    stack = os.path.join(util.GetChromiumSrcDir(), 'third_party',
4117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                         'android_platform', 'development', 'scripts', 'stack')
4127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    # Try to symbolize logcat.
4137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if os.path.exists(stack):
4147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      p = subprocess.Popen([stack], stdin=subprocess.PIPE,
4157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                           stdout=subprocess.PIPE)
4167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      ret += Decorate('Stack from Logcat', p.communicate(input=logcat)[0])
4177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    # Try to get tombstones.
4197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    tombstones = os.path.join(util.GetChromiumSrcDir(), 'build', 'android',
4207dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                              'tombstones.py')
4217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if os.path.exists(tombstones):
4227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      ret += Decorate('Tombstones',
4237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                      subprocess.Popen([tombstones, '-w', '--device',
4245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu                                        self._adb.device_serial()],
4257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                       stdout=subprocess.PIPE).communicate()[0])
4267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return ret
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
42858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  def AddReplayServerOptions(self, extra_wpr_args):
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if not self.forwarder_factory.does_forwarder_override_dns:
43058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      extra_wpr_args.append('--no-dns_forwarding')
431f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    if self.browser_options.netsim:
432f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      extra_wpr_args.append('--net=%s' % self.browser_options.netsim)
433