d9fa758292
BUG=skia:4763 GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1703663002 Review URL: https://codereview.chromium.org/1703663002
242 lines
8.5 KiB
Python
242 lines
8.5 KiB
Python
#!/usr/bin/env python
|
|
#
|
|
# Copyright 2016 Google Inc.
|
|
#
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
|
|
import android_devices
|
|
import default_flavor
|
|
import os
|
|
|
|
|
|
"""Android flavor utils, used for building for and running tests on Android."""
|
|
|
|
|
|
class _ADBWrapper(object):
|
|
"""Wrapper for ADB."""
|
|
def __init__(self, path_to_adb, serial, android_flavor):
|
|
self._adb = path_to_adb
|
|
self._serial = serial
|
|
self._wait_count = 0
|
|
self._android_flavor = android_flavor
|
|
|
|
def wait_for_device(self):
|
|
"""Run 'adb wait-for-device'."""
|
|
self._wait_count += 1
|
|
cmd = [
|
|
os.path.join(self._android_flavor.android_bin, 'adb_wait_for_device'),
|
|
'-s', self._serial,
|
|
]
|
|
self._android_flavor._bot_info.run(
|
|
cmd, env=self._android_flavor._default_env)
|
|
|
|
def maybe_wait_for_device(self):
|
|
"""Run 'adb wait-for-device' if it hasn't already been run."""
|
|
if self._wait_count == 0:
|
|
self.wait_for_device()
|
|
|
|
def __call__(self, *args, **kwargs):
|
|
self.maybe_wait_for_device()
|
|
return self._android_flavor._bot_info.run(self._adb + args, **kwargs)
|
|
|
|
|
|
class AndroidFlavorUtils(default_flavor.DefaultFlavorUtils):
|
|
def __init__(self, skia_api):
|
|
super(AndroidFlavorUtils, self).__init__(skia_api)
|
|
self.device = self._bot_info.spec['device_cfg']
|
|
slave_info = android_devices.SLAVE_INFO.get(
|
|
self._bot_info.slave_name,
|
|
android_devices.SLAVE_INFO['default'])
|
|
self.serial = slave_info.serial
|
|
self.android_bin = os.path.join(
|
|
self._bot_info.skia_dir, 'platform_tools', 'android', 'bin')
|
|
self._android_sdk_root = slave_info.android_sdk_root
|
|
self._adb = _ADBWrapper(
|
|
os.path.join(self._android_sdk_root, 'platform-tools', 'adb'),
|
|
self.serial,
|
|
self)
|
|
self._has_root = slave_info.has_root
|
|
self._default_env = {'ANDROID_SDK_ROOT': self._android_sdk_root,
|
|
'ANDROID_HOME': self._android_sdk_root,
|
|
'SKIA_ANDROID_VERBOSE_SETUP': '1'}
|
|
|
|
def step(self, name, cmd, env=None, **kwargs):
|
|
self._adb.maybe_wait_for_device()
|
|
args = [self.android_bin.join('android_run_skia'),
|
|
'--verbose',
|
|
'--logcat',
|
|
'-d', self.device,
|
|
'-s', self.serial,
|
|
'-t', self._bot_info.configuration,
|
|
]
|
|
env = dict(env or {})
|
|
env.update(self._default_env)
|
|
|
|
return self._bot_info.run(self._bot_info.m.step, name=name, cmd=args + cmd,
|
|
env=env, **kwargs)
|
|
|
|
def compile(self, target):
|
|
"""Build the given target."""
|
|
env = dict(self._default_env)
|
|
ccache = self._bot_info.ccache
|
|
if ccache:
|
|
env['ANDROID_MAKE_CCACHE'] = ccache
|
|
|
|
cmd = [os.path.join(self.android_bin, 'android_ninja'), target,
|
|
'-d', self.device]
|
|
if 'Clang' in self._bot_info.name:
|
|
cmd.append('--clang')
|
|
self._bot_info.run(cmd, env=env)
|
|
|
|
def device_path_join(self, *args):
|
|
"""Like os.path.join(), but for paths on a connected Android device."""
|
|
return '/'.join(args)
|
|
|
|
def device_path_exists(self, path):
|
|
"""Like os.path.exists(), but for paths on a connected device."""
|
|
exists_str = 'FILE_EXISTS'
|
|
return exists_str in self._adb(
|
|
name='exists %s' % self._bot_info.m.path.basename(path),
|
|
serial=self.serial,
|
|
cmd=['shell', 'if', '[', '-e', path, '];',
|
|
'then', 'echo', exists_str + ';', 'fi'],
|
|
stdout=self._bot_info.m.raw_io.output(),
|
|
infra_step=True
|
|
).stdout
|
|
|
|
def _remove_device_dir(self, path):
|
|
"""Remove the directory on the device."""
|
|
self._adb(name='rmdir %s' % self._bot_info.m.path.basename(path),
|
|
serial=self.serial,
|
|
cmd=['shell', 'rm', '-r', path],
|
|
infra_step=True)
|
|
# Sometimes the removal fails silently. Verify that it worked.
|
|
if self.device_path_exists(path):
|
|
raise Exception('Failed to remove %s!' % path) # pragma: no cover
|
|
|
|
def _create_device_dir(self, path):
|
|
"""Create the directory on the device."""
|
|
self._adb(name='mkdir %s' % self._bot_info.m.path.basename(path),
|
|
serial=self.serial,
|
|
cmd=['shell', 'mkdir', '-p', path],
|
|
infra_step=True)
|
|
|
|
def copy_directory_contents_to_device(self, host_dir, device_dir):
|
|
"""Like shutil.copytree(), but for copying to a connected device."""
|
|
self._bot_info.run(
|
|
self._bot_info.m.step,
|
|
name='push %s' % self._bot_info.m.path.basename(host_dir),
|
|
cmd=[self.android_bin.join('adb_push_if_needed'), '--verbose',
|
|
'-s', self.serial, host_dir, device_dir],
|
|
env=self._default_env,
|
|
infra_step=True)
|
|
|
|
def copy_directory_contents_to_host(self, device_dir, host_dir):
|
|
"""Like shutil.copytree(), but for copying from a connected device."""
|
|
self._bot_info.run(
|
|
self._bot_info.m.step,
|
|
name='pull %s' % self._bot_info.m.path.basename(device_dir),
|
|
cmd=[self.android_bin.join('adb_pull_if_needed'), '--verbose',
|
|
'-s', self.serial, device_dir, host_dir],
|
|
env=self._default_env,
|
|
infra_step=True)
|
|
|
|
def copy_file_to_device(self, host_path, device_path):
|
|
"""Like shutil.copyfile, but for copying to a connected device."""
|
|
self._adb(name='push %s' % self._bot_info.m.path.basename(host_path),
|
|
serial=self.serial,
|
|
cmd=['push', host_path, device_path],
|
|
infra_step=True)
|
|
|
|
def create_clean_device_dir(self, path):
|
|
"""Like shutil.rmtree() + os.makedirs(), but on a connected device."""
|
|
self._remove_device_dir(path)
|
|
self._create_device_dir(path)
|
|
|
|
def install(self):
|
|
"""Run device-specific installation steps."""
|
|
if self._has_root:
|
|
self._adb(name='adb root',
|
|
serial=self.serial,
|
|
cmd=['root'],
|
|
infra_step=True)
|
|
# Wait for the device to reconnect.
|
|
self._bot_info.run(
|
|
self._bot_info.m.step,
|
|
name='wait',
|
|
cmd=['sleep', '10'],
|
|
infra_step=True)
|
|
self._adb.wait_for_device()
|
|
|
|
# TODO(borenet): Set CPU scaling mode to 'performance'.
|
|
self._bot_info.run(self._bot_info.m.step,
|
|
name='kill skia',
|
|
cmd=[self.android_bin.join('android_kill_skia'),
|
|
'--verbose', '-s', self.serial],
|
|
env=self._default_env,
|
|
infra_step=True)
|
|
if self._has_root:
|
|
self._adb(name='stop shell',
|
|
serial=self.serial,
|
|
cmd=['shell', 'stop'],
|
|
infra_step=True)
|
|
|
|
# Print out battery stats.
|
|
self._adb(name='starting battery stats',
|
|
serial=self.serial,
|
|
cmd=['shell', 'dumpsys', 'batteryproperties'],
|
|
infra_step=True)
|
|
|
|
def cleanup_steps(self):
|
|
"""Run any device-specific cleanup steps."""
|
|
self._adb(name='final battery stats',
|
|
serial=self.serial,
|
|
cmd=['shell', 'dumpsys', 'batteryproperties'],
|
|
infra_step=True)
|
|
self._adb(name='reboot',
|
|
serial=self.serial,
|
|
cmd=['reboot'],
|
|
infra_step=True)
|
|
self._bot_info.run(
|
|
self._bot_info.m.step,
|
|
name='wait for reboot',
|
|
cmd=['sleep', '10'],
|
|
infra_step=True)
|
|
self._adb.wait_for_device()
|
|
|
|
def read_file_on_device(self, path, *args, **kwargs):
|
|
"""Read the given file."""
|
|
return self._adb(name='read %s' % self._bot_info.m.path.basename(path),
|
|
serial=self.serial,
|
|
cmd=['shell', 'cat', path],
|
|
stdout=self._bot_info.m.raw_io.output(),
|
|
infra_step=True).stdout.rstrip()
|
|
|
|
def remove_file_on_device(self, path, *args, **kwargs):
|
|
"""Delete the given file."""
|
|
return self._adb(name='rm %s' % self._bot_info.m.path.basename(path),
|
|
serial=self.serial,
|
|
cmd=['shell', 'rm', '-f', path],
|
|
infra_step=True,
|
|
*args,
|
|
**kwargs)
|
|
|
|
def get_device_dirs(self):
|
|
""" Set the directories which will be used by the build steps."""
|
|
device_scratch_dir = self._adb(
|
|
name='get EXTERNAL_STORAGE dir',
|
|
serial=self.serial,
|
|
cmd=['shell', 'echo', '$EXTERNAL_STORAGE'],
|
|
)
|
|
prefix = self.device_path_join(device_scratch_dir, 'skiabot', 'skia_')
|
|
return default_flavor.DeviceDirs(
|
|
dm_dir=prefix + 'dm',
|
|
perf_data_dir=prefix + 'perf',
|
|
resource_dir=prefix + 'resources',
|
|
images_dir=prefix + 'images',
|
|
skp_dir=prefix + 'skp/skps',
|
|
tmp_dir=prefix + 'tmp_dir')
|
|
|