blob: 01fcc30cb7bbe171d63a7918488f87e14601d2c7 [file] [log] [blame]
Eric Boren7e97dc02017-02-02 09:02:37 -05001# Copyright 2016 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.
4
Kevin Lubick90e3cd72017-02-09 10:08:13 -05005from recipe_engine import recipe_api
6
Eric Boren7e97dc02017-02-02 09:02:37 -05007import default_flavor
Eric Borenfe40abc2017-07-20 10:21:38 -04008import re
Eric Boren7e97dc02017-02-02 09:02:37 -05009import subprocess
10
11
12"""GN Android flavor utils, used for building Skia for Android with GN."""
13class GNAndroidFlavorUtils(default_flavor.DefaultFlavorUtils):
14 def __init__(self, m):
15 super(GNAndroidFlavorUtils, self).__init__(m)
16 self._ever_ran_adb = False
Kevin Lubick4fd283e2017-12-07 11:19:31 -050017 self.ADB_BINARY = '/usr/bin/adb.1.0.35'
Kevin Lubicke9188852017-12-14 09:47:05 -050018 self._golo_devices = ['Nexus5x']
19 if self.m.vars.builder_cfg.get('model') in self._golo_devices:
Kevin Lubick4fd283e2017-12-07 11:19:31 -050020 self.ADB_BINARY = '/opt/infra-android/tools/adb'
Eric Boren7e97dc02017-02-02 09:02:37 -050021
22 self.device_dirs = default_flavor.DeviceDirs(
23 dm_dir = self.m.vars.android_data_dir + 'dm_out',
24 perf_data_dir = self.m.vars.android_data_dir + 'perf',
25 resource_dir = self.m.vars.android_data_dir + 'resources',
26 images_dir = self.m.vars.android_data_dir + 'images',
27 skp_dir = self.m.vars.android_data_dir + 'skps',
28 svg_dir = self.m.vars.android_data_dir + 'svgs',
29 tmp_dir = self.m.vars.android_data_dir)
30
Eric Boren7e97dc02017-02-02 09:02:37 -050031 def _run(self, title, *cmd, **kwargs):
Robert Iannucci297a7ef2017-05-12 19:09:38 -070032 with self.m.context(cwd=self.m.vars.skia_dir):
Eric Boren53262d02017-03-20 15:40:12 -040033 return self.m.run(self.m.step, title, cmd=list(cmd), **kwargs)
Eric Boren7e97dc02017-02-02 09:02:37 -050034
35 def _py(self, title, script, infra_step=True):
Robert Iannucci297a7ef2017-05-12 19:09:38 -070036 with self.m.context(cwd=self.m.vars.skia_dir):
Eric Boren53262d02017-03-20 15:40:12 -040037 return self.m.run(self.m.python, title, script=script,
38 infra_step=infra_step)
Eric Boren7e97dc02017-02-02 09:02:37 -050039
40 def _adb(self, title, *cmd, **kwargs):
Eric Boren7e97dc02017-02-02 09:02:37 -050041 # The only non-infra adb steps (dm / nanobench) happen to not use _adb().
42 if 'infra_step' not in kwargs:
43 kwargs['infra_step'] = True
Ben Wagnercf9365a2017-09-08 14:06:38 -040044
Kevin Lubick4fd283e2017-12-07 11:19:31 -050045 self._ever_ran_adb = True
Ben Wagnercf9365a2017-09-08 14:06:38 -040046 attempts = 1
47 flaky_devices = ['NexusPlayer', 'PixelC']
48 if self.m.vars.builder_cfg.get('model') in flaky_devices:
49 attempts = 3
50
51 def wait_for_device(attempt):
52 self.m.run(self.m.step,
53 'kill adb server after failure of \'%s\' (attempt %d)' % (
54 title, attempt),
Kevin Lubick4fd283e2017-12-07 11:19:31 -050055 cmd=[self.ADB_BINARY, 'kill-server'],
Ben Wagnercf9365a2017-09-08 14:06:38 -040056 infra_step=True, timeout=30, abort_on_failure=False,
57 fail_build_on_failure=False)
Ben Wagner79a12562017-09-12 12:32:59 -040058 self.m.run(self.m.step,
Ben Wagnercf9365a2017-09-08 14:06:38 -040059 'wait for device after failure of \'%s\' (attempt %d)' % (
60 title, attempt),
Kevin Lubick4fd283e2017-12-07 11:19:31 -050061 cmd=[self.ADB_BINARY, 'wait-for-device'], infra_step=True,
Kevin Lubick587afc92017-10-12 12:21:47 -040062 timeout=180, abort_on_failure=False,
63 fail_build_on_failure=False)
Ben Wagnercf9365a2017-09-08 14:06:38 -040064
65 with self.m.context(cwd=self.m.vars.skia_dir):
Kevin Lubick7c1eae52017-10-13 12:57:49 -040066 return self.m.run.with_retry(self.m.step, title, attempts,
Kevin Lubick4fd283e2017-12-07 11:19:31 -050067 cmd=[self.ADB_BINARY]+list(cmd),
Kevin Lubick7c1eae52017-10-13 12:57:49 -040068 between_attempts_fn=wait_for_device,
69 **kwargs)
Kevin Lubickbca95a52017-11-20 16:06:06 -050070
Kevin Lubickd1bbd5f2017-11-21 16:47:16 -050071 # A list of devices we can't root. If rooting fails and a device is not
72 # on the list, we fail the task to avoid perf inconsistencies.
73 rootable_blacklist = ['GalaxyS6', 'GalaxyS7_G930A', 'GalaxyS7_G930FD',
74 'MotoG4', 'NVIDIA_Shield']
75
Kevin Lubicke9188852017-12-14 09:47:05 -050076 # Maps device type -> CPU ids that should be scaled for nanobench.
77 # Many devices have two (or more) different CPUs (e.g. big.LITTLE
78 # on Nexus5x). The CPUs listed are the biggest cpus on the device.
79 # The CPUs are grouped together, so we only need to scale one of them
80 # (the one listed) in order to scale them all.
81 # E.g. Nexus5x has cpu0-3 as one chip and cpu4-5 as the other. Thus,
82 # if one wants to run a single-threaded application (e.g. nanobench), one
83 # can disable cpu0-3 and scale cpu 4 to have only cpu4 and 5 at the same
84 # frequency. See also disable_for_nanobench.
Kevin Lubickf1585aa2017-12-12 07:33:48 -050085 cpus_to_scale = {
Kevin Lubicke9188852017-12-14 09:47:05 -050086 'Nexus5x': [4],
87 'NexusPlayer': [0, 2], # has 2 identical chips, so scale them both.
88 'Pixel': [2],
89 'Pixel2XL': [4]
Kevin Lubickf1585aa2017-12-12 07:33:48 -050090 }
91
Kevin Lubicke9188852017-12-14 09:47:05 -050092 # Maps device type -> CPU ids that should be turned off when running
93 # single-threaded applications like nanobench. The devices listed have
94 # multiple, differnt CPUs. We notice a lot of noise that seems to be
95 # caused by nanobench running on the slow CPU, then the big CPU. By
96 # disabling this, we see less of that noise by forcing the same CPU
97 # to be used for the performance testing every time.
98 disable_for_nanobench = {
99 'Nexus5x': range(0, 4),
100 'Pixel': range(0, 2),
101 'Pixel2XL': range(0, 4),
102 'PixelC': range(0, 2)
Kevin Lubicke3b01302017-12-12 15:57:20 -0500103 }
104
Kevin Lubickf1585aa2017-12-12 07:33:48 -0500105 def _scale_for_dm(self):
106 device = self.m.vars.builder_cfg.get('model')
107 if (device in self.rootable_blacklist or
Kevin Lubick082f00a2017-11-28 08:33:37 -0500108 self.m.vars.internal_hardware_label):
Kevin Lubickbca95a52017-11-20 16:06:06 -0500109 return
Kevin Lubickf1585aa2017-12-12 07:33:48 -0500110
Kevin Lubicke9188852017-12-14 09:47:05 -0500111 # This is paranoia... any CPUs we disabled while running nanobench
112 # ought to be back online now that we've restarted the device.
113 for i in self.disable_for_nanobench.get(device, []):
114 self._set_cpu_online(i, 1) # enable
115
Kevin Lubick031e7cf2017-12-19 10:11:19 -0500116 scale_up = self.cpus_to_scale.get(device, [0])
117 # For big.LITTLE devices, make sure we scale the LITTLE cores up;
118 # there is a chance they are still in powersave mode from when
119 # swarming slows things down for cooling down and charging.
120 if 0 not in scale_up:
121 scale_up.append(0)
122 for i in scale_up:
Kevin Lubick17634922017-12-12 08:14:19 -0500123 # AndroidOne doesn't support ondemand governor. hotplug is similar.
124 if device == 'AndroidOne':
125 self._set_governor(i, 'hotplug')
126 else:
127 self._set_governor(i, 'ondemand')
Kevin Lubickf1585aa2017-12-12 07:33:48 -0500128
129 def _scale_for_nanobench(self):
130 device = self.m.vars.builder_cfg.get('model')
131 if (device in self.rootable_blacklist or
132 self.m.vars.internal_hardware_label):
133 return
134
Kevin Lubicke9188852017-12-14 09:47:05 -0500135 for i in self.cpus_to_scale.get(device, [0]):
136 self._set_governor(i, 'userspace')
137 self._scale_cpu(i, 0.6)
Kevin Lubickf1585aa2017-12-12 07:33:48 -0500138
Kevin Lubicke9188852017-12-14 09:47:05 -0500139 for i in self.disable_for_nanobench.get(device, []):
140 self._set_cpu_online(i, 0) # disable
Kevin Lubickf1585aa2017-12-12 07:33:48 -0500141
Kevin Lubickf1585aa2017-12-12 07:33:48 -0500142
143 def _set_governor(self, cpu, gov):
144 self._ever_ran_adb = True
Kevin Lubick1c8092ac2017-11-30 08:35:29 -0500145 self.m.run.with_retry(self.m.python.inline,
Kevin Lubickf1585aa2017-12-12 07:33:48 -0500146 "Set CPU %d's governor to %s" % (cpu, gov),
Kevin Lubick1c8092ac2017-11-30 08:35:29 -0500147 3, # attempts
Kevin Lubickd1bbd5f2017-11-21 16:47:16 -0500148 program="""
149import os
150import subprocess
151import sys
Kevin Lubick1c8092ac2017-11-30 08:35:29 -0500152import time
Kevin Lubickd1bbd5f2017-11-21 16:47:16 -0500153ADB = sys.argv[1]
Kevin Lubickf1585aa2017-12-12 07:33:48 -0500154cpu = int(sys.argv[2])
155gov = sys.argv[3]
156
Kevin Lubickd1bbd5f2017-11-21 16:47:16 -0500157log = subprocess.check_output([ADB, 'root'])
158# check for message like 'adbd cannot run as root in production builds'
Kevin Lubick7f5d5d22017-12-08 10:26:56 -0500159print log
Kevin Lubickd1bbd5f2017-11-21 16:47:16 -0500160if 'cannot' in log:
161 raise Exception('adb root failed')
Kevin Lubickbca95a52017-11-20 16:06:06 -0500162
Kevin Lubickf1585aa2017-12-12 07:33:48 -0500163subprocess.check_output([ADB, 'shell', 'echo "%s" > '
164 '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor' % (gov, cpu)])
165actual_gov = subprocess.check_output([ADB, 'shell', 'cat '
166 '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor' % cpu]).strip()
Kevin Lubick17634922017-12-12 08:14:19 -0500167if actual_gov != gov:
168 raise Exception('(actual, expected) (%s, %s)'
Kevin Lubickf1585aa2017-12-12 07:33:48 -0500169 % (actual_gov, gov))
170""",
171 args = [self.ADB_BINARY, cpu, gov],
172 infra_step=True,
173 timeout=30)
Kevin Lubickbca95a52017-11-20 16:06:06 -0500174
Kevin Lubickf1585aa2017-12-12 07:33:48 -0500175
Kevin Lubicke9188852017-12-14 09:47:05 -0500176 def _set_cpu_online(self, cpu, value):
177 """Set /sys/devices/system/cpu/cpu{N}/online to value (0 or 1)."""
Kevin Lubicke3b01302017-12-12 15:57:20 -0500178 self._ever_ran_adb = True
Kevin Lubicke9188852017-12-14 09:47:05 -0500179 msg = 'Disabling'
180 if value:
181 msg = 'Enabling'
Kevin Lubicke3b01302017-12-12 15:57:20 -0500182 self.m.run.with_retry(self.m.python.inline,
Kevin Lubicke9188852017-12-14 09:47:05 -0500183 '%s CPU %d' % (msg, cpu),
Kevin Lubicke3b01302017-12-12 15:57:20 -0500184 3, # attempts
185 program="""
186import os
187import subprocess
188import sys
189import time
190ADB = sys.argv[1]
191cpu = int(sys.argv[2])
Kevin Lubicke9188852017-12-14 09:47:05 -0500192value = int(sys.argv[3])
Kevin Lubicke3b01302017-12-12 15:57:20 -0500193
194log = subprocess.check_output([ADB, 'root'])
195# check for message like 'adbd cannot run as root in production builds'
196print log
197if 'cannot' in log:
198 raise Exception('adb root failed')
199
Kevin Lubicke9188852017-12-14 09:47:05 -0500200# If we try to echo 1 to an already online cpu, adb returns exit code 1.
201# So, check the value before trying to write it.
202prior_status = subprocess.check_output([ADB, 'shell', 'cat '
203 '/sys/devices/system/cpu/cpu%d/online' % cpu]).strip()
204if prior_status == str(value):
205 print 'CPU %d online already %d' % (cpu, value)
206 sys.exit()
207
208subprocess.check_output([ADB, 'shell', 'echo %s > '
209 '/sys/devices/system/cpu/cpu%d/online' % (value, cpu)])
Kevin Lubicke3b01302017-12-12 15:57:20 -0500210actual_status = subprocess.check_output([ADB, 'shell', 'cat '
211 '/sys/devices/system/cpu/cpu%d/online' % cpu]).strip()
Kevin Lubicke9188852017-12-14 09:47:05 -0500212if actual_status != str(value):
Kevin Lubicke3b01302017-12-12 15:57:20 -0500213 raise Exception('(actual, expected) (%s, %d)'
Kevin Lubicke9188852017-12-14 09:47:05 -0500214 % (actual_status, value))
Kevin Lubicke3b01302017-12-12 15:57:20 -0500215""",
Kevin Lubicke9188852017-12-14 09:47:05 -0500216 args = [self.ADB_BINARY, cpu, value],
Kevin Lubicke3b01302017-12-12 15:57:20 -0500217 infra_step=True,
218 timeout=30)
219
220
Kevin Lubickf1585aa2017-12-12 07:33:48 -0500221 def _scale_cpu(self, cpu, target_percent):
222 self._ever_ran_adb = True
223 self.m.run.with_retry(self.m.python.inline,
224 'Scale CPU %d to %f' % (cpu, target_percent),
225 3, # attempts
226 program="""
227import os
228import subprocess
229import sys
230import time
231ADB = sys.argv[1]
232target_percent = float(sys.argv[2])
233cpu = int(sys.argv[3])
234log = subprocess.check_output([ADB, 'root'])
235# check for message like 'adbd cannot run as root in production builds'
236print log
237if 'cannot' in log:
238 raise Exception('adb root failed')
239
240root = '/sys/devices/system/cpu/cpu%d/cpufreq' %cpu
241
242# All devices we test on give a list of their available frequencies.
243available_freqs = subprocess.check_output([ADB, 'shell',
244 'cat %s/scaling_available_frequencies' % root])
245
246# Check for message like '/system/bin/sh: file not found'
247if available_freqs and '/system/bin/sh' not in available_freqs:
248 available_freqs = sorted(
249 int(i) for i in available_freqs.strip().split())
250else:
251 raise Exception('Could not get list of available frequencies: %s' %
252 available_freqs)
Kevin Lubickbca95a52017-11-20 16:06:06 -0500253
Kevin Lubickd1bbd5f2017-11-21 16:47:16 -0500254maxfreq = available_freqs[-1]
255target = int(round(maxfreq * target_percent))
256freq = maxfreq
257for f in reversed(available_freqs):
258 if f <= target:
259 freq = f
260 break
261
262print 'Setting frequency to %d' % freq
263
Kevin Lubickd1bbd5f2017-11-21 16:47:16 -0500264# If scaling_max_freq is lower than our attempted setting, it won't take.
Kevin Lubick7f5d5d22017-12-08 10:26:56 -0500265# We must set min first, because if we try to set max to be less than min
266# (which sometimes happens after certain devices reboot) it returns a
267# perplexing permissions error.
Kevin Lubick4c6bde22017-12-05 15:54:19 -0500268subprocess.check_output([ADB, 'shell', 'echo 0 > '
Kevin Lubickf1585aa2017-12-12 07:33:48 -0500269 '%s/scaling_min_freq' % root])
Kevin Lubick1c8092ac2017-11-30 08:35:29 -0500270subprocess.check_output([ADB, 'shell', 'echo %d > '
Kevin Lubickf1585aa2017-12-12 07:33:48 -0500271 '%s/scaling_max_freq' % (freq, root)])
Kevin Lubick7f5d5d22017-12-08 10:26:56 -0500272subprocess.check_output([ADB, 'shell', 'echo %d > '
Kevin Lubickf1585aa2017-12-12 07:33:48 -0500273 '%s/scaling_setspeed' % (freq, root)])
Kevin Lubick1c8092ac2017-11-30 08:35:29 -0500274time.sleep(5)
Kevin Lubickd1bbd5f2017-11-21 16:47:16 -0500275actual_freq = subprocess.check_output([ADB, 'shell', 'cat '
Kevin Lubickf1585aa2017-12-12 07:33:48 -0500276 '%s/scaling_cur_freq' % root]).strip()
Kevin Lubickd1bbd5f2017-11-21 16:47:16 -0500277if actual_freq != str(freq):
278 raise Exception('(actual, expected) (%s, %d)'
279 % (actual_freq, freq))
Kevin Lubick7f5d5d22017-12-08 10:26:56 -0500280""",
Kevin Lubickf1585aa2017-12-12 07:33:48 -0500281 args = [self.ADB_BINARY, str(target_percent), cpu],
Kevin Lubickd1bbd5f2017-11-21 16:47:16 -0500282 infra_step=True,
283 timeout=30)
Kevin Lubickbca95a52017-11-20 16:06:06 -0500284
Eric Boren53262d02017-03-20 15:40:12 -0400285 def compile(self, unused_target):
Eric Boren7e97dc02017-02-02 09:02:37 -0500286 compiler = self.m.vars.builder_cfg.get('compiler')
287 configuration = self.m.vars.builder_cfg.get('configuration')
Ben Wagner37491d22017-12-13 13:00:47 -0500288 extra_tokens = self.m.vars.extra_tokens
Eric Boren7e97dc02017-02-02 09:02:37 -0500289 os = self.m.vars.builder_cfg.get('os')
290 target_arch = self.m.vars.builder_cfg.get('target_arch')
291
292 assert compiler == 'Clang' # At this rate we might not ever support GCC.
293
294 extra_cflags = []
295 if configuration == 'Debug':
296 extra_cflags.append('-O1')
297
298 ndk_asset = 'android_ndk_linux'
299 if 'Mac' in os:
300 ndk_asset = 'android_ndk_darwin'
301 elif 'Win' in os:
302 ndk_asset = 'n'
303
304 quote = lambda x: '"%s"' % x
305 args = {
306 'ndk': quote(self.m.vars.slave_dir.join(ndk_asset)),
307 'target_cpu': quote(target_arch),
308 }
309
310 if configuration != 'Debug':
311 args['is_debug'] = 'false'
Ben Wagner37491d22017-12-13 13:00:47 -0500312 if 'Vulkan' in extra_tokens:
Eric Boren7e97dc02017-02-02 09:02:37 -0500313 args['ndk_api'] = 24
314 args['skia_enable_vulkan_debug_layers'] = 'false'
Eric Borenfe40abc2017-07-20 10:21:38 -0400315
316 # If an Android API level is specified, use that.
Ben Wagner37491d22017-12-13 13:00:47 -0500317 for t in extra_tokens:
318 m = re.search(r'API(\d+)', t)
319 if m and len(m.groups()) == 1:
320 args['ndk_api'] = m.groups()[0]
321 break
Eric Borenfe40abc2017-07-20 10:21:38 -0400322
Eric Boren7e97dc02017-02-02 09:02:37 -0500323 if extra_cflags:
324 args['extra_cflags'] = repr(extra_cflags).replace("'", '"')
325
326 gn_args = ' '.join('%s=%s' % (k,v) for (k,v) in sorted(args.iteritems()))
327
328 gn = 'gn.exe' if 'Win' in os else 'gn'
329 ninja = 'ninja.exe' if 'Win' in os else 'ninja'
330 gn = self.m.vars.skia_dir.join('bin', gn)
331
332 self._py('fetch-gn', self.m.vars.skia_dir.join('bin', 'fetch-gn'))
333 self._run('gn gen', gn, 'gen', self.out_dir, '--args=' + gn_args)
Mike Klein7a13d872017-11-06 09:28:59 -0500334 self._run('ninja', ninja, '-k', '0', '-C', self.out_dir)
Eric Boren7e97dc02017-02-02 09:02:37 -0500335
336 def install(self):
337 self._adb('mkdir ' + self.device_dirs.resource_dir,
338 'shell', 'mkdir', '-p', self.device_dirs.resource_dir)
339
Kevin Lubick90e3cd72017-02-09 10:08:13 -0500340
Eric Boren7e97dc02017-02-02 09:02:37 -0500341 def cleanup_steps(self):
342 if self._ever_ran_adb:
Kevin Lubick549638c2017-02-09 16:13:10 -0500343 self.m.run(self.m.python.inline, 'dump log', program="""
Eric Borenb82fdc72017-04-19 13:36:00 -0400344 import os
345 import subprocess
346 import sys
347 out = sys.argv[1]
Kevin Lubick587afc92017-10-12 12:21:47 -0400348 log = subprocess.check_output(['%s', 'logcat', '-d'])
Eric Borenb82fdc72017-04-19 13:36:00 -0400349 for line in log.split('\\n'):
350 tokens = line.split()
351 if len(tokens) == 11 and tokens[-7] == 'F' and tokens[-3] == 'pc':
352 addr, path = tokens[-2:]
353 local = os.path.join(out, os.path.basename(path))
354 if os.path.exists(local):
355 sym = subprocess.check_output(['addr2line', '-Cfpe', local, addr])
356 line = line.replace(addr, addr + ' ' + sym.strip())
357 print line
Kevin Lubick4fd283e2017-12-07 11:19:31 -0500358 """ % self.ADB_BINARY,
Eric Borenb82fdc72017-04-19 13:36:00 -0400359 args=[self.m.vars.skia_out.join(self.m.vars.configuration)],
360 infra_step=True,
Kevin Lubick587afc92017-10-12 12:21:47 -0400361 timeout=300,
Eric Borenb82fdc72017-04-19 13:36:00 -0400362 abort_on_failure=False)
Kevin Lubick90e3cd72017-02-09 10:08:13 -0500363
Kevin Lubick60bb2d52017-12-22 10:43:15 -0500364 # Only quarantine the bot if the first failed step
Kevin Lubick65e8a712017-02-15 10:08:51 -0500365 # is an infra step. If, instead, we did this for any infra failures, we
Kevin Lubick60bb2d52017-12-22 10:43:15 -0500366 # would do this too much. For example, if a Nexus 10 died during dm
Kevin Lubick65e8a712017-02-15 10:08:51 -0500367 # and the following pull step would also fail "device not found" - causing
368 # us to run the shutdown command when the device was probably not in a
369 # broken state; it was just rebooting.
370 if (self.m.run.failed_steps and
Kevin Lubick60bb2d52017-12-22 10:43:15 -0500371 isinstance(self.m.run.failed_steps[0], recipe_api.InfraFailure)):
372 self.m.file.write_text('Quarantining Bot', '~/force_quarantine', ' ')
Kevin Lubick90e3cd72017-02-09 10:08:13 -0500373
374 if self._ever_ran_adb:
Eric Boren7e97dc02017-02-02 09:02:37 -0500375 self._adb('kill adb server', 'kill-server')
376
Eric Boren53262d02017-03-20 15:40:12 -0400377 def step(self, name, cmd, **kwargs):
Kevin Lubickbca95a52017-11-20 16:06:06 -0500378 if (cmd[0] == 'nanobench'):
Kevin Lubickf1585aa2017-12-12 07:33:48 -0500379 self._scale_for_nanobench()
Kevin Lubickbca95a52017-11-20 16:06:06 -0500380 else:
Kevin Lubickf1585aa2017-12-12 07:33:48 -0500381 self._scale_for_dm()
Eric Boren7e97dc02017-02-02 09:02:37 -0500382 app = self.m.vars.skia_out.join(self.m.vars.configuration, cmd[0])
383 self._adb('push %s' % cmd[0],
384 'push', app, self.m.vars.android_bin_dir)
385
386 sh = '%s.sh' % cmd[0]
387 self.m.run.writefile(self.m.vars.tmp_dir.join(sh),
388 'set -x; %s%s; echo $? >%src' %
389 (self.m.vars.android_bin_dir, subprocess.list2cmdline(map(str, cmd)),
390 self.m.vars.android_bin_dir))
391 self._adb('push %s' % sh,
392 'push', self.m.vars.tmp_dir.join(sh), self.m.vars.android_bin_dir)
393
394 self._adb('clear log', 'logcat', '-c')
395 self.m.python.inline('%s' % cmd[0], """
396 import subprocess
397 import sys
398 bin_dir = sys.argv[1]
399 sh = sys.argv[2]
Kevin Lubick587afc92017-10-12 12:21:47 -0400400 subprocess.check_call(['%s', 'shell', 'sh', bin_dir + sh])
Eric Boren7e97dc02017-02-02 09:02:37 -0500401 try:
Kevin Lubick587afc92017-10-12 12:21:47 -0400402 sys.exit(int(subprocess.check_output(['%s', 'shell', 'cat',
Eric Boren7e97dc02017-02-02 09:02:37 -0500403 bin_dir + 'rc'])))
404 except ValueError:
405 print "Couldn't read the return code. Probably killed for OOM."
406 sys.exit(1)
Kevin Lubick4fd283e2017-12-07 11:19:31 -0500407 """ % (self.ADB_BINARY, self.ADB_BINARY),
408 args=[self.m.vars.android_bin_dir, sh])
Eric Boren7e97dc02017-02-02 09:02:37 -0500409
410 def copy_file_to_device(self, host, device):
411 self._adb('push %s %s' % (host, device), 'push', host, device)
412
413 def copy_directory_contents_to_device(self, host, device):
414 # Copy the tree, avoiding hidden directories and resolving symlinks.
Kevin Lubick549638c2017-02-09 16:13:10 -0500415 self.m.run(self.m.python.inline, 'push %s/* %s' % (host, device),
416 program="""
Eric Boren7e97dc02017-02-02 09:02:37 -0500417 import os
418 import subprocess
419 import sys
420 host = sys.argv[1]
421 device = sys.argv[2]
422 for d, _, fs in os.walk(host):
423 p = os.path.relpath(d, host)
424 if p != '.' and p.startswith('.'):
425 continue
426 for f in fs:
427 print os.path.join(p,f)
Kevin Lubick587afc92017-10-12 12:21:47 -0400428 subprocess.check_call(['%s', 'push',
Eric Boren7e97dc02017-02-02 09:02:37 -0500429 os.path.realpath(os.path.join(host, p, f)),
430 os.path.join(device, p, f)])
Kevin Lubick4fd283e2017-12-07 11:19:31 -0500431 """ % self.ADB_BINARY, args=[host, device], infra_step=True)
Eric Boren7e97dc02017-02-02 09:02:37 -0500432
433 def copy_directory_contents_to_host(self, device, host):
434 self._adb('pull %s %s' % (device, host), 'pull', device, host)
435
Eric Borenbb05f702017-04-24 15:59:55 -0400436 def read_file_on_device(self, path, **kwargs):
437 rv = self._adb('read %s' % path,
438 'shell', 'cat', path, stdout=self.m.raw_io.output(),
439 **kwargs)
440 return rv.stdout.rstrip() if rv and rv.stdout else None
Eric Boren7e97dc02017-02-02 09:02:37 -0500441
442 def remove_file_on_device(self, path):
443 self._adb('rm %s' % path, 'shell', 'rm', '-f', path)
444
445 def create_clean_device_dir(self, path):
446 self._adb('rm %s' % path, 'shell', 'rm', '-rf', path)
447 self._adb('mkdir %s' % path, 'shell', 'mkdir', '-p', path)