Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/env python | |
| 2 # | |
| 3 # Copyright 2016 Google Inc. | |
| 4 # | |
| 5 # Use of this source code is governed by a BSD-style license that can be | |
| 6 # found in the LICENSE file. | |
| 7 | |
| 8 | |
| 9 import android_devices | |
| 10 import copy | |
|
rmistry
2016/02/18 15:29:21
unused
borenet
2016/02/18 15:40:56
Done.
| |
| 11 import default_flavor | |
| 12 import os | |
| 13 | |
| 14 | |
| 15 """Android flavor utils, used for building for and running tests on Android.""" | |
| 16 | |
| 17 | |
| 18 class _ADBWrapper(object): | |
| 19 """Wrapper for ADB.""" | |
| 20 def __init__(self, path_to_adb, serial, android_flavor): | |
| 21 self._adb = path_to_adb | |
| 22 self._serial = serial | |
| 23 self._wait_count = 0 | |
| 24 self._android_flavor = android_flavor | |
| 25 | |
| 26 def wait_for_device(self): | |
| 27 """Run 'adb wait-for-device'.""" | |
| 28 self._wait_count += 1 | |
| 29 cmd = [ | |
| 30 os.path.join(self._android_flavor.android_bin, 'adb_wait_for_device'), | |
| 31 '-s', self._serial, | |
| 32 ] | |
| 33 self._android_flavor._bot_info.run( | |
| 34 cmd, env=self._android_flavor._default_env) | |
| 35 | |
| 36 def maybe_wait_for_device(self): | |
| 37 """Run 'adb wait-for-device' if it hasn't already been run.""" | |
| 38 if self._wait_count == 0: | |
| 39 self.wait_for_device() | |
| 40 | |
| 41 def __call__(self, *args, **kwargs): | |
| 42 self.maybe_wait_for_device() | |
| 43 return self._android_flavor._bot_info.run(self._adb + args, **kwargs) | |
| 44 | |
| 45 | |
| 46 class AndroidFlavorUtils(default_flavor.DefaultFlavorUtils): | |
| 47 def __init__(self, skia_api): | |
| 48 super(AndroidFlavorUtils, self).__init__(skia_api) | |
| 49 self.device = self._bot_info.spec['device_cfg'] | |
| 50 slave_info = android_devices.SLAVE_INFO.get( | |
| 51 self._bot_info.slave_name, | |
| 52 android_devices.SLAVE_INFO['default']) | |
| 53 self.serial = slave_info.serial | |
| 54 self.android_bin = os.path.join( | |
| 55 self._bot_info.skia_dir, 'platform_tools', 'android', 'bin') | |
| 56 self._android_sdk_root = slave_info.android_sdk_root | |
| 57 self._adb = _ADBWrapper( | |
| 58 os.path.join(self._android_sdk_root, 'platform-tools', 'adb'), | |
| 59 self.serial, | |
| 60 self) | |
| 61 self._has_root = slave_info.has_root | |
| 62 self._default_env = {'ANDROID_SDK_ROOT': self._android_sdk_root, | |
| 63 'ANDROID_HOME': self._android_sdk_root, | |
| 64 'SKIA_ANDROID_VERBOSE_SETUP': '1'} | |
| 65 | |
| 66 def step(self, name, cmd, env=None, **kwargs): | |
| 67 self._adb.maybe_wait_for_device() | |
| 68 args = [self.android_bin.join('android_run_skia'), | |
| 69 '--verbose', | |
| 70 '--logcat', | |
| 71 '-d', self.device, | |
| 72 '-s', self.serial, | |
| 73 '-t', self._bot_info.configuration, | |
| 74 ] | |
| 75 env = dict(env or {}) | |
| 76 env.update(self._default_env) | |
| 77 | |
| 78 return self._bot_info.run(self._bot_info.m.step, name=name, cmd=args + cmd, | |
| 79 env=env, **kwargs) | |
| 80 | |
| 81 def compile(self, target): | |
| 82 """Build the given target.""" | |
| 83 env = dict(self._default_env) | |
| 84 ccache = self._bot_info.ccache | |
| 85 if ccache: | |
| 86 env['ANDROID_MAKE_CCACHE'] = ccache | |
| 87 | |
| 88 cmd = [os.path.join(self.android_bin, 'android_ninja'), target, | |
| 89 '-d', self.device] | |
| 90 if 'Clang' in self._bot_info.name: | |
| 91 cmd.append('--clang') | |
| 92 self._bot_info.run(cmd, env=env) | |
| 93 | |
| 94 def device_path_join(self, *args): | |
| 95 """Like os.path.join(), but for paths on a connected Android device.""" | |
| 96 return '/'.join(args) | |
| 97 | |
| 98 def device_path_exists(self, path): | |
| 99 """Like os.path.exists(), but for paths on a connected device.""" | |
| 100 exists_str = 'FILE_EXISTS' | |
| 101 return exists_str in self._adb( | |
| 102 name='exists %s' % self._bot_info.m.path.basename(path), | |
| 103 serial=self.serial, | |
| 104 cmd=['shell', 'if', '[', '-e', path, '];', | |
| 105 'then', 'echo', exists_str + ';', 'fi'], | |
| 106 stdout=self._bot_info.m.raw_io.output(), | |
| 107 infra_step=True | |
| 108 ).stdout | |
| 109 | |
| 110 def _remove_device_dir(self, path): | |
| 111 """Remove the directory on the device.""" | |
| 112 self._adb(name='rmdir %s' % self._bot_info.m.path.basename(path), | |
| 113 serial=self.serial, | |
| 114 cmd=['shell', 'rm', '-r', path], | |
| 115 infra_step=True) | |
| 116 # Sometimes the removal fails silently. Verify that it worked. | |
| 117 if self.device_path_exists(path): | |
| 118 raise Exception('Failed to remove %s!' % path) # pragma: no cover | |
| 119 | |
| 120 def _create_device_dir(self, path): | |
| 121 """Create the directory on the device.""" | |
| 122 self._adb(name='mkdir %s' % self._bot_info.m.path.basename(path), | |
| 123 serial=self.serial, | |
| 124 cmd=['shell', 'mkdir', '-p', path], | |
| 125 infra_step=True) | |
| 126 | |
| 127 def copy_directory_contents_to_device(self, host_dir, device_dir): | |
| 128 """Like shutil.copytree(), but for copying to a connected device.""" | |
| 129 self._bot_info.run( | |
| 130 self._bot_info.m.step, | |
| 131 name='push %s' % self._bot_info.m.path.basename(host_dir), | |
| 132 cmd=[self.android_bin.join('adb_push_if_needed'), '--verbose', | |
| 133 '-s', self.serial, host_dir, device_dir], | |
| 134 env=self._default_env, | |
| 135 infra_step=True) | |
| 136 | |
| 137 def copy_directory_contents_to_host(self, device_dir, host_dir): | |
| 138 """Like shutil.copytree(), but for copying from a connected device.""" | |
| 139 self._bot_info.run( | |
| 140 self._bot_info.m.step, | |
| 141 name='pull %s' % self._bot_info.m.path.basename(device_dir), | |
| 142 cmd=[self.android_bin.join('adb_pull_if_needed'), '--verbose', | |
| 143 '-s', self.serial, device_dir, host_dir], | |
| 144 env=self._default_env, | |
| 145 infra_step=True) | |
| 146 | |
| 147 def copy_file_to_device(self, host_path, device_path): | |
| 148 """Like shutil.copyfile, but for copying to a connected device.""" | |
| 149 self._adb(name='push %s' % self._bot_info.m.path.basename(host_path), | |
| 150 serial=self.serial, | |
| 151 cmd=['push', host_path, device_path], | |
| 152 infra_step=True) | |
| 153 | |
| 154 def create_clean_device_dir(self, path): | |
| 155 """Like shutil.rmtree() + os.makedirs(), but on a connected device.""" | |
| 156 self._remove_device_dir(path) | |
| 157 self._create_device_dir(path) | |
| 158 | |
| 159 def install(self): | |
| 160 """Run device-specific installation steps.""" | |
| 161 if self._has_root: | |
| 162 self._adb(name='adb root', | |
| 163 serial=self.serial, | |
| 164 cmd=['root'], | |
| 165 infra_step=True) | |
| 166 # Wait for the device to reconnect. | |
| 167 self._bot_info.run( | |
| 168 self._bot_info.m.step, | |
| 169 name='wait', | |
| 170 cmd=['sleep', '10'], | |
| 171 infra_step=True) | |
| 172 self._adb.wait_for_device() | |
| 173 | |
| 174 # TODO(borenet): Set CPU scaling mode to 'performance'. | |
| 175 self._bot_info.run(self._bot_info.m.step, | |
| 176 name='kill skia', | |
| 177 cmd=[self.android_bin.join('android_kill_skia'), | |
| 178 '--verbose', '-s', self.serial], | |
| 179 env=self._default_env, | |
| 180 infra_step=True) | |
| 181 if self._has_root: | |
| 182 self._adb(name='stop shell', | |
| 183 serial=self.serial, | |
| 184 cmd=['shell', 'stop'], | |
| 185 infra_step=True) | |
| 186 | |
| 187 # Print out battery stats. | |
| 188 self._adb(name='starting battery stats', | |
| 189 serial=self.serial, | |
| 190 cmd=['shell', 'dumpsys', 'batteryproperties'], | |
| 191 infra_step=True) | |
| 192 | |
| 193 def cleanup_steps(self): | |
| 194 """Run any device-specific cleanup steps.""" | |
| 195 self._adb(name='final battery stats', | |
| 196 serial=self.serial, | |
| 197 cmd=['shell', 'dumpsys', 'batteryproperties'], | |
| 198 infra_step=True) | |
| 199 self._adb(name='reboot', | |
| 200 serial=self.serial, | |
| 201 cmd=['reboot'], | |
| 202 infra_step=True) | |
| 203 self._bot_info.run( | |
| 204 self._bot_info.m.step, | |
| 205 name='wait for reboot', | |
| 206 cmd=['sleep', '10'], | |
| 207 infra_step=True) | |
| 208 self._adb.wait_for_device() | |
| 209 | |
| 210 def read_file_on_device(self, path, *args, **kwargs): | |
| 211 """Read the given file.""" | |
| 212 return self._adb(name='read %s' % self._bot_info.m.path.basename(path), | |
| 213 serial=self.serial, | |
| 214 cmd=['shell', 'cat', path], | |
| 215 stdout=self._bot_info.m.raw_io.output(), | |
| 216 infra_step=True).stdout.rstrip() | |
| 217 | |
| 218 def remove_file_on_device(self, path, *args, **kwargs): | |
| 219 """Delete the given file.""" | |
| 220 return self._adb(name='rm %s' % self._bot_info.m.path.basename(path), | |
| 221 serial=self.serial, | |
| 222 cmd=['shell', 'rm', '-f', path], | |
| 223 infra_step=True, | |
| 224 *args, | |
| 225 **kwargs) | |
| 226 | |
| 227 def get_device_dirs(self): | |
| 228 """ Set the directories which will be used by the build steps.""" | |
| 229 device_scratch_dir = self._adb( | |
| 230 name='get EXTERNAL_STORAGE dir', | |
| 231 serial=self.serial, | |
| 232 cmd=['shell', 'echo', '$EXTERNAL_STORAGE'], | |
| 233 ) | |
| 234 prefix = self.device_path_join(device_scratch_dir, 'skiabot', 'skia_') | |
| 235 return default_flavor.DeviceDirs( | |
| 236 dm_dir=prefix + 'dm', | |
| 237 perf_data_dir=prefix + 'perf', | |
| 238 resource_dir=prefix + 'resources', | |
| 239 images_dir=prefix + 'images', | |
| 240 skp_dir=prefix + 'skp/skps', | |
| 241 tmp_dir=prefix + 'tmp_dir') | |
| 242 | |
| OLD | NEW |