"""Android module to prepare APKs and emulators to run webdriver-based tests.
"""
import re
import os
import subprocess
import sys
import packaging
import logging
from typing import List, Optional
from chrome.test.variations.test_utils import SRC_DIR
sys.path.append(os.path.join(SRC_DIR, 'build', 'android'))
import devil_chromium
from devil.android import apk_helper
from devil.android import device_utils
from devil.android import forwarder
from devil.android.sdk import adb_wrapper
from pylib.local.emulator import avd
_INSTALLER_SCRIPT_PY = os.path.join(
SRC_DIR, 'clank', 'bin', 'utils', 'installer_script_wrapper.py')
def _package_name(channel: str):
if channel in ('beta', 'dev', 'canary'):
return f'com.chrome.{channel}'
return 'com.android.chrome'
def _is_require_signed(channel: str) -> bool:
"""Check if we need to install a signed build."""
return channel == 'stable'
def install_chrome(channel: str, device: device_utils.DeviceUtils) -> str:
"""Installs Chrome to the device and returns the package name."""
args = [
_INSTALLER_SCRIPT_PY, f'--product=chrome',
f'--channel={channel}', f'--serial={device.serial}',
f'--adb={adb_wrapper.AdbWrapper.GetAdbPath()}',
]
args.append('--signed' if _is_require_signed(channel) else '--unsigned')
try:
subprocess.check_output(args=args)
except subprocess.CalledProcessError as e:
logging.error('Subprocess error caught %s', e.output.decode())
raise RuntimeError('Chrome installation failed.')
return _package_name(channel)
def install_webview(
channel: str,
device: device_utils.DeviceUtils
) -> packaging.version.Version:
"""Installs Webview to the device and returns the installed version."""
args = [
_INSTALLER_SCRIPT_PY, f'--product=webview',
f'--channel={channel}', f'--serial={device.serial}',
f'--adb={adb_wrapper.AdbWrapper.GetAdbPath()}',
]
args.append('--signed' if _is_require_signed(channel) else '--unsigned')
try:
subprocess.check_output(args=args)
except subprocess.CalledProcessError as e:
logging.error('Subprocess error caught %s', e.output.decode())
raise RuntimeError('Webview installation failed.')
version_regex = r'\s*Preferred WebView package[^:]*[^\d]*([^\)]+)'
version_output = device.RunShellCommand(['dumpsys' ,'webviewupdate'])
version = [
m.group(1)
for line in version_output if (m := re.match(version_regex, line))
]
return packaging.version.parse(version[0]) if version else None
def _forward_port(device: device_utils.DeviceUtils,
ports: Optional[List[int]] = None):
if ports:
forwarder.Forwarder.Map([(port, port) for port in ports], device)
def launch_emulator(avd_config: str,
emulator_window: bool,
ports: Optional[List[int]] = None) -> avd._AvdInstance:
"""Launches the emulator and forwards ports from device to host."""
avd_config = avd.AvdConfig(avd_config)
avd_config.Install()
instance = avd_config.CreateInstance()
instance.Start(writable_system=True,
window=emulator_window)
_forward_port(instance.device, ports)
return instance