Update sdk/platform-tools to version 26.0.0.
[android_tools.git] / sdk / platform-tools / systrace / catapult / telemetry / telemetry / internal / backends / chrome / android_browser_finder.py
blob188a3e38a6f5ad8d4bf0bc6e3625a593db0e0140
1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Finds android browsers that can be controlled by telemetry."""
7 import logging
8 import os
9 import subprocess
10 import sys
12 from py_utils import dependency_util
13 from devil import base_error
14 from devil.android import apk_helper
16 from telemetry.core import exceptions
17 from telemetry.core import platform
18 from telemetry.core import util
19 from telemetry import decorators
20 from telemetry.internal.backends import android_browser_backend_settings
21 from telemetry.internal.backends.chrome import android_browser_backend
22 from telemetry.internal.browser import browser
23 from telemetry.internal.browser import possible_browser
24 from telemetry.internal.platform import android_device
25 from telemetry.internal.util import binary_manager
28 CHROME_PACKAGE_NAMES = {
29 'android-content-shell':
30 ['org.chromium.content_shell_apk',
31 android_browser_backend_settings.ContentShellBackendSettings,
32 'ContentShell.apk'],
33 'android-webview':
34 ['org.chromium.webview_shell',
35 android_browser_backend_settings.WebviewBackendSettings,
36 None],
37 'android-webview-shell':
38 ['org.chromium.android_webview.shell',
39 android_browser_backend_settings.WebviewShellBackendSettings,
40 'AndroidWebView.apk'],
41 'android-chromium':
42 ['org.chromium.chrome',
43 android_browser_backend_settings.ChromeBackendSettings,
44 'ChromePublic.apk'],
45 'android-chrome':
46 ['com.google.android.apps.chrome',
47 android_browser_backend_settings.ChromeBackendSettings,
48 'Chrome.apk'],
49 'android-chrome-work':
50 ['com.chrome.work',
51 android_browser_backend_settings.ChromeBackendSettings,
52 None],
53 'android-chrome-beta':
54 ['com.chrome.beta',
55 android_browser_backend_settings.ChromeBackendSettings,
56 None],
57 'android-chrome-dev':
58 ['com.chrome.dev',
59 android_browser_backend_settings.ChromeBackendSettings,
60 None],
61 'android-chrome-canary':
62 ['com.chrome.canary',
63 android_browser_backend_settings.ChromeBackendSettings,
64 None],
65 'android-system-chrome':
66 ['com.android.chrome',
67 android_browser_backend_settings.ChromeBackendSettings,
68 None],
72 class PossibleAndroidBrowser(possible_browser.PossibleBrowser):
73 """A launchable android browser instance."""
74 def __init__(self, browser_type, finder_options, android_platform,
75 backend_settings, apk_name):
76 super(PossibleAndroidBrowser, self).__init__(
77 browser_type, 'android', backend_settings.supports_tab_control)
78 assert browser_type in FindAllBrowserTypes(finder_options), (
79 'Please add %s to android_browser_finder.FindAllBrowserTypes' %
80 browser_type)
81 self._platform = android_platform
82 self._platform_backend = (
83 android_platform._platform_backend) # pylint: disable=protected-access
84 self._backend_settings = backend_settings
85 self._local_apk = None
87 if browser_type == 'exact':
88 if not os.path.exists(apk_name):
89 raise exceptions.PathMissingError(
90 'Unable to find exact apk %s specified by --browser-executable' %
91 apk_name)
92 self._local_apk = apk_name
93 elif browser_type == 'reference':
94 if not os.path.exists(apk_name):
95 raise exceptions.PathMissingError(
96 'Unable to find reference apk at expected location %s.' % apk_name)
97 self._local_apk = apk_name
98 elif apk_name:
99 assert finder_options.chrome_root, (
100 'Must specify Chromium source to use apk_name')
101 chrome_root = finder_options.chrome_root
102 candidate_apks = []
103 for build_path in util.GetBuildDirectories(chrome_root):
104 apk_full_name = os.path.join(build_path, 'apks', apk_name)
105 if os.path.exists(apk_full_name):
106 last_changed = os.path.getmtime(apk_full_name)
107 candidate_apks.append((last_changed, apk_full_name))
109 if candidate_apks:
110 # Find the candidate .apk with the latest modification time.
111 newest_apk_path = sorted(candidate_apks)[-1][1]
112 self._local_apk = newest_apk_path
114 def __repr__(self):
115 return 'PossibleAndroidBrowser(browser_type=%s)' % self.browser_type
117 def _InitPlatformIfNeeded(self):
118 pass
120 def Create(self, finder_options):
121 self._InitPlatformIfNeeded()
122 browser_backend = android_browser_backend.AndroidBrowserBackend(
123 self._platform_backend,
124 finder_options.browser_options, self._backend_settings)
125 try:
126 return browser.Browser(
127 browser_backend, self._platform_backend, self._credentials_path)
128 except Exception:
129 logging.exception('Failure while creating Android browser.')
130 original_exception = sys.exc_info()
131 try:
132 browser_backend.Close()
133 except Exception:
134 logging.exception('Secondary failure while closing browser backend.')
136 raise original_exception[0], original_exception[1], original_exception[2]
138 def SupportsOptions(self, browser_options):
139 if len(browser_options.extensions_to_load) != 0:
140 return False
141 return True
143 def HaveLocalAPK(self):
144 return self._local_apk and os.path.exists(self._local_apk)
146 @decorators.Cache
147 def UpdateExecutableIfNeeded(self):
148 if self.HaveLocalAPK():
149 logging.warn('Installing %s on device if needed.' % self._local_apk)
150 self.platform.InstallApplication(self._local_apk)
152 def last_modification_time(self):
153 if self.HaveLocalAPK():
154 return os.path.getmtime(self._local_apk)
155 return -1
158 def SelectDefaultBrowser(possible_browsers):
159 """Return the newest possible browser."""
160 if not possible_browsers:
161 return None
162 return max(possible_browsers, key=lambda b: b.last_modification_time())
165 def CanFindAvailableBrowsers():
166 return android_device.CanDiscoverDevices()
169 def CanPossiblyHandlePath(target_path):
170 return os.path.splitext(target_path.lower())[1] == '.apk'
173 def FindAllBrowserTypes(options):
174 del options # unused
175 return CHROME_PACKAGE_NAMES.keys() + ['exact', 'reference']
178 def _FindAllPossibleBrowsers(finder_options, android_platform):
179 """Testable version of FindAllAvailableBrowsers."""
180 if not android_platform:
181 return []
182 possible_browsers = []
184 # Add the exact APK if given.
185 if (finder_options.browser_executable and
186 CanPossiblyHandlePath(finder_options.browser_executable)):
187 apk_name = os.path.basename(finder_options.browser_executable)
188 normalized_path = os.path.expanduser(finder_options.browser_executable)
189 exact_package = apk_helper.GetPackageName(normalized_path)
190 package_info = next(
191 (info for info in CHROME_PACKAGE_NAMES.itervalues()
192 if info[0] == exact_package or info[2] == apk_name), None)
194 # It is okay if the APK name or package doesn't match any of known chrome
195 # browser APKs, since it may be of a different browser.
196 if package_info:
197 if not exact_package:
198 raise exceptions.PackageDetectionError(
199 'Unable to find package for %s specified by --browser-executable' %
200 normalized_path)
202 [package, backend_settings, _] = package_info
203 if package == exact_package:
204 possible_browsers.append(PossibleAndroidBrowser(
205 'exact',
206 finder_options,
207 android_platform,
208 backend_settings(package),
209 normalized_path))
210 else:
211 raise exceptions.UnknownPackageError(
212 '%s specified by --browser-executable has an unknown package: %s' %
213 (normalized_path, exact_package))
215 # Add the reference build if found.
216 os_version = dependency_util.GetChromeApkOsVersion(
217 android_platform.GetOSVersionName())
218 arch = android_platform.GetArchName()
219 try:
220 reference_build = binary_manager.FetchPath(
221 'chrome_stable', arch, 'android', os_version)
222 except (binary_manager.NoPathFoundError,
223 binary_manager.CloudStorageError):
224 reference_build = None
226 if reference_build and os.path.exists(reference_build):
227 # TODO(aiolos): how do we stably map the android chrome_stable apk to the
228 # correct package name?
229 package, backend_settings, _ = CHROME_PACKAGE_NAMES['android-chrome']
230 possible_browsers.append(PossibleAndroidBrowser(
231 'reference',
232 finder_options,
233 android_platform,
234 backend_settings(package),
235 reference_build))
237 # Add any known local versions.
238 for name, package_info in CHROME_PACKAGE_NAMES.iteritems():
239 package, backend_settings, apk_name = package_info
240 if apk_name and not finder_options.chrome_root:
241 continue
242 b = PossibleAndroidBrowser(name,
243 finder_options,
244 android_platform,
245 backend_settings(package),
246 apk_name)
247 if b.platform.CanLaunchApplication(package) or b.HaveLocalAPK():
248 possible_browsers.append(b)
249 return possible_browsers
252 def FindAllAvailableBrowsers(finder_options, device):
253 """Finds all the possible browsers on one device.
255 The device is either the only device on the host platform,
256 or |finder_options| specifies a particular device.
258 if not isinstance(device, android_device.AndroidDevice):
259 return []
261 try:
262 android_platform = platform.GetPlatformForDevice(device, finder_options)
263 return _FindAllPossibleBrowsers(finder_options, android_platform)
264 except base_error.BaseError as e:
265 logging.error('Unable to find browsers on %s: %s', device.device_id, str(e))
266 ps_output = subprocess.check_output(['ps', '-ef'])
267 logging.error('Ongoing processes:\n%s', ps_output)
268 return []