from telemetry.core.backends.chrome import chrome_browser_backend
from telemetry.core.forwarders import android_forwarder
+util.AddDirToPythonPath(util.GetChromiumSrcDir(), 'build', 'android')
+from pylib.device import device_errors # pylint: disable=F0401
+from pylib.device import intent # pylint: disable=F0401
+
class AndroidBrowserBackendSettings(object):
def __init__(self, adb, activity, cmdline_file, package, pseudo_exec_name,
- supports_tab_control):
+ supports_tab_control, relax_ssl_check=False):
self.adb = adb
self.activity = activity
self.cmdline_file = cmdline_file
self.package = package
self.pseudo_exec_name = pseudo_exec_name
self.supports_tab_control = supports_tab_control
+ self.relax_ssl_check = relax_ssl_check
def GetDevtoolsRemotePort(self):
raise NotImplementedError()
def RemoveProfile(self):
- files = self.adb.RunShellCommandWithSU('ls "%s"' % self.profile_dir)
+ files = self.adb.device().RunShellCommand(
+ 'ls "%s"' % self.profile_dir, as_root=True)
# Don't delete lib, since it is created by the installer.
paths = ['"%s/%s"' % (self.profile_dir, f) for f in files if f != 'lib']
- self.adb.RunShellCommandWithSU('rm -r %s' % ' '.join(paths))
+ self.adb.device().RunShellCommand('rm -r %s' % ' '.join(paths),
+ as_root=True)
def PushProfile(self, _):
logging.critical('Profiles cannot be overriden with current configuration')
sys.exit(1)
@property
- def is_content_shell(self):
- return False
-
- @property
def profile_dir(self):
return '/data/data/%s/' % self.package
return 'localabstract:chrome_devtools_remote'
def PushProfile(self, new_profile_dir):
- # Clear the old profile first, since copying won't delete files.
- self.RemoveProfile()
-
# Pushing the profile is slow, so we don't want to do it every time.
- # Avoid this by pushing to a safe location using PushIfNeeded, and
+ # Avoid this by pushing to a safe location using PushChangedFiles, and
# then copying into the correct location on each test run.
(profile_parent, profile_base) = os.path.split(new_profile_dir)
profile_base = os.path.basename(profile_parent)
saved_profile_location = '/sdcard/profile/%s' % profile_base
- self.adb.Adb().PushIfNeeded(new_profile_dir, saved_profile_location)
- self.adb.RunShellCommand('cp -r %s/* %s' % (saved_profile_location,
- self.profile_dir),
- timeout_time = 60)
+ self.adb.device().PushChangedFiles(new_profile_dir, saved_profile_location)
- # We now need to give the ownership back to the browser UID
- dumpsys = self.adb.RunShellCommand('dumpsys package %s' % self.package)
+ self.adb.device().old_interface.EfficientDeviceDirectoryCopy(
+ saved_profile_location, self.profile_dir)
+ dumpsys = self.adb.device().RunShellCommand(
+ 'dumpsys package %s' % self.package)
id_line = next(line for line in dumpsys if 'userId=' in line)
uid = re.search('\d+', id_line).group()
- files = self.adb.RunShellCommandWithSU('ls "%s"' % self.profile_dir)
+ files = self.adb.device().RunShellCommand(
+ 'ls "%s"' % self.profile_dir, as_root=True)
files.remove('lib')
paths = ['%s/%s' % (self.profile_dir, f) for f in files]
for path in paths:
extended_path = '%s %s/* %s/*/* %s/*/*/*' % (path, path, path, path)
- self.adb.RunShellCommand('chown %s.%s %s' %
- (uid, uid, extended_path))
-
+ self.adb.device().RunShellCommand(
+ 'chown %s.%s %s' % (uid, uid, extended_path))
class ContentShellBackendSettings(AndroidBrowserBackendSettings):
def __init__(self, adb, package):
def GetDevtoolsRemotePort(self):
return 'localabstract:content_shell_devtools_remote'
- @property
- def is_content_shell(self):
- return True
-
-class ChromiumTestShellBackendSettings(AndroidBrowserBackendSettings):
+class ChromeShellBackendSettings(AndroidBrowserBackendSettings):
def __init__(self, adb, package):
- super(ChromiumTestShellBackendSettings, self).__init__(
+ super(ChromeShellBackendSettings, self).__init__(
adb=adb,
- activity='org.chromium.chrome.testshell.ChromiumTestShellActivity',
- cmdline_file='/data/local/tmp/chromium-testshell-command-line',
+ activity='org.chromium.chrome.shell.ChromeShellActivity',
+ cmdline_file='/data/local/tmp/chrome-shell-command-line',
package=package,
- pseudo_exec_name='chromium_testshell',
+ pseudo_exec_name='chrome_shell',
supports_tab_control=False)
def GetDevtoolsRemotePort(self):
- return 'localabstract:chromium_testshell_devtools_remote'
-
- @property
- def is_content_shell(self):
- return True
+ return 'localabstract:chrome_shell_devtools_remote'
class WebviewBackendSettings(AndroidBrowserBackendSettings):
def __init__(self, adb, package):
super(WebviewBackendSettings, self).__init__(
adb=adb,
- activity='com.android.webview.chromium.shell.TelemetryActivity',
+ activity='org.chromium.telemetry_shell.TelemetryActivity',
cmdline_file='/data/local/tmp/webview-command-line',
package=package,
pseudo_exec_name='webview',
'activity %s:%s to come up',
self.package,
self.activity)
- raise exceptions.BrowserGoneException('Timeout waiting for PID.')
+ raise exceptions.BrowserGoneException(self.browser,
+ 'Timeout waiting for PID.')
return 'localabstract:webview_devtools_remote_%s' % str(pid)
class AndroidBrowserBackend(chrome_browser_backend.ChromeBrowserBackend):
"""The backend for controlling a browser instance running on Android."""
def __init__(self, browser_options, backend_settings, use_rndis_forwarder,
- output_profile_path, extensions_to_load):
+ output_profile_path, extensions_to_load, target_arch):
super(AndroidBrowserBackend, self).__init__(
- is_content_shell=backend_settings.is_content_shell,
+ supports_tab_control=backend_settings.supports_tab_control,
supports_extensions=False, browser_options=browser_options,
output_profile_path=output_profile_path,
extensions_to_load=extensions_to_load)
self._adb = backend_settings.adb
self._backend_settings = backend_settings
self._saved_cmdline = ''
+ self._target_arch = target_arch
+ self._saved_sslflag = ''
# TODO(tonyg): This is flaky because it doesn't reserve the port that it
# allocates. Need to fix this.
self._port = adb_commands.AllocateTestServerPort()
# Kill old browser.
- self._adb.CloseApplication(self._backend_settings.package)
+ self._adb.device().ForceStop(self._backend_settings.package)
- if self._adb.Adb().CanAccessProtectedFileContents():
- if not self.browser_options.dont_override_profile:
- self._backend_settings.RemoveProfile()
+ if self._adb.device().old_interface.CanAccessProtectedFileContents():
if self.browser_options.profile_dir:
self._backend_settings.PushProfile(self.browser_options.profile_dir)
+ elif not self.browser_options.dont_override_profile:
+ self._backend_settings.RemoveProfile()
self._forwarder_factory = android_forwarder.AndroidForwarderFactory(
self._adb, use_rndis_forwarder)
- if self.browser_options.netsim:
+ if self.browser_options.netsim or use_rndis_forwarder:
assert use_rndis_forwarder, 'Netsim requires RNDIS forwarding.'
self.wpr_port_pairs = forwarders.PortPairs(
http=forwarders.PortPair(0, 80),
# Set the debug app if needed.
if self._adb.IsUserBuild():
logging.debug('User build device, setting debug app')
- self._adb.RunShellCommand('am set-debug-app --persistent %s' %
- self._backend_settings.package)
+ self._adb.device().RunShellCommand(
+ 'am set-debug-app --persistent %s' % self._backend_settings.package)
def _SetUpCommandLine(self):
def QuoteIfNeeded(arg):
def _SetCommandLineFile(self, file_contents):
logging.debug('Using command line: ' + file_contents)
def IsProtectedFile(name):
- if self._adb.Adb().FileExistsOnDevice(name):
- return not self._adb.Adb().IsFileWritableOnDevice(name)
+ if self._adb.device().old_interface.FileExistsOnDevice(name):
+ return not self._adb.device().old_interface.IsFileWritableOnDevice(name)
else:
parent_name = os.path.dirname(name)
if parent_name != '':
else:
return True
- if IsProtectedFile(self._backend_settings.cmdline_file):
- if not self._adb.Adb().CanAccessProtectedFileContents():
- logging.critical('Cannot set Chrome command line. '
- 'Fix this by flashing to a userdebug build.')
- sys.exit(1)
- self._saved_cmdline = ''.join(self._adb.Adb().GetProtectedFileContents(
- self._backend_settings.cmdline_file) or [])
- self._adb.Adb().SetProtectedFileContents(
- self._backend_settings.cmdline_file, file_contents)
- else:
- self._saved_cmdline = ''.join(self._adb.Adb().GetFileContents(
- self._backend_settings.cmdline_file) or [])
- self._adb.Adb().SetFileContents(self._backend_settings.cmdline_file,
- file_contents)
+ protected = IsProtectedFile(self._backend_settings.cmdline_file)
+ try:
+ self._saved_cmdline = ''.join(
+ self._adb.device().ReadFile(
+ self._backend_settings.cmdline_file, as_root=protected)
+ or [])
+ self._adb.device().WriteFile(
+ self._backend_settings.cmdline_file, file_contents,
+ as_root=protected)
+ except device_errors.CommandFailedError:
+ logging.critical('Cannot set Chrome command line. '
+ 'Fix this by flashing to a userdebug build.')
+ sys.exit(1)
def Start(self):
self._SetUpCommandLine()
- self._adb.RunShellCommand('logcat -c')
+
+ # Disables android.net SSL certificate check. This is necessary for
+ # applications using the android.net stack to work with proxy HTTPS server
+ # created by telemetry
+ if self._backend_settings.relax_ssl_check:
+ self._saved_sslflag = self._adb.device().GetProp('socket.relaxsslcheck')
+ self._adb.device().SetProp('socket.relaxsslcheck', 'yes')
+
+ self._adb.device().RunShellCommand('logcat -c')
if self.browser_options.startup_url:
url = self.browser_options.startup_url
elif self.browser_options.profile_dir:
# If we have no existing tabs start with a blank page since default
# startup with the NTP can lead to race conditions with Telemetry
url = 'about:blank'
- self._adb.Adb().DismissCrashDialogIfNeeded()
- self._adb.StartActivity(self._backend_settings.package,
- self._backend_settings.activity,
- True,
- None,
- None,
- url)
+ # Dismiss any error dialogs. Limit the number in case we have an error loop
+ # or we are failing to dismiss.
+ for _ in xrange(10):
+ if not self._adb.device().old_interface.DismissCrashDialogIfNeeded():
+ break
+ self._adb.device().StartActivity(
+ intent.Intent(package=self._backend_settings.package,
+ activity=self._backend_settings.activity,
+ action=None, data=url, category=None),
+ blocking=True)
self._adb.Forward('tcp:%d' % self._port,
self._backend_settings.GetDevtoolsRemotePort())
try:
self._WaitForBrowserToComeUp()
- self._PostBrowserStartupInitialization()
except exceptions.BrowserGoneException:
logging.critical('Failed to connect to browser.')
- if not self._adb.Adb().CanAccessProtectedFileContents():
+ if not self._adb.device().old_interface.CanAccessProtectedFileContents():
logging.critical(
'Resolve this by either: '
'(1) Flashing to a userdebug build OR '
def pid(self):
pids = self._adb.ExtractPid(self._backend_settings.package)
if not pids:
- raise exceptions.BrowserGoneException(self.GetStackTrace())
+ raise exceptions.BrowserGoneException(self.browser)
return int(pids[0])
@property
def activity(self):
return self._backend_settings.activity
- @property
- def supports_tab_control(self):
- return self._backend_settings.supports_tab_control
-
def __del__(self):
self.Close()
def Close(self):
super(AndroidBrowserBackend, self).Close()
- self._adb.CloseApplication(self._backend_settings.package)
+ self._adb.device().ForceStop(self._backend_settings.package)
+
+ # Restore android.net SSL check
+ if self._backend_settings.relax_ssl_check:
+ self._adb.device().SetProp('socket.relaxsslcheck', self._saved_sslflag)
if self._output_profile_path:
logging.info("Pulling profile directory from device: '%s'->'%s'.",
# pulled down is really needed e.g. .pak files.
if not os.path.exists(self._output_profile_path):
os.makedirs(self._output_profile_pathame)
- files = self.adb.RunShellCommandWithSU(
+ files = self.adb.device().RunShellCommand(
'ls "%s"' % self._backend_settings.profile_dir)
for f in files:
# Don't pull lib, since it is created by the installer.
# is fixed in android's adb_interface at 60 seconds, which may
# be too short to pull the cache.
cmd = 'pull %s %s' % (source, dest)
- self._adb.Adb().Adb().SendCommand(cmd, timeout_time=240)
+ self._adb.device().old_interface.Adb().SendCommand(
+ cmd, timeout_time=240)
def IsBrowserRunning(self):
pids = self._adb.ExtractPid(self._backend_settings.package)
return local_port
def GetStandardOutput(self):
- return '\n'.join(self._adb.RunShellCommand('logcat -d -t 500'))
+ return '\n'.join(self._adb.device().RunShellCommand('logcat -d -t 500'))
def GetStackTrace(self):
def Decorate(title, content):
'android_platform', 'development', 'scripts', 'stack')
# Try to symbolize logcat.
if os.path.exists(stack):
- p = subprocess.Popen([stack], stdin=subprocess.PIPE,
- stdout=subprocess.PIPE)
+ cmd = [stack]
+ if self._target_arch:
+ cmd.append('--arch=%s' % self._target_arch)
+ p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
ret += Decorate('Stack from Logcat', p.communicate(input=logcat)[0])
# Try to get tombstones.
if os.path.exists(tombstones):
ret += Decorate('Tombstones',
subprocess.Popen([tombstones, '-w', '--device',
- self._adb.device()],
+ self._adb.device_serial()],
stdout=subprocess.PIPE).communicate()[0])
return ret