1# Copyright 2017 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 5# Disable warning about setting self.device_dirs in install(); we need to. 6# pylint: disable=W0201 7 8 9from . import default 10 11 12"""iOS flavor, used for running code on iOS.""" 13 14 15class iOSFlavor(default.DefaultFlavor): 16 def __init__(self, m): 17 super(iOSFlavor, self).__init__(m) 18 self.device_dirs = default.DeviceDirs( 19 bin_dir='[unused]', 20 dm_dir='dm', 21 perf_data_dir='perf', 22 resource_dir='resources', 23 images_dir='images', 24 lotties_dir='lotties', 25 skp_dir='skps', 26 svg_dir='svgs', 27 mskp_dir='mskp', 28 tmp_dir='tmp', 29 texttraces_dir='') 30 31 def _run(self, title, *cmd, **kwargs): 32 def sleep(attempt): 33 self.m.python.inline('sleep before attempt %d' % attempt, """ 34import time 35time.sleep(2) 36""") # pragma: nocover 37 return self.m.run.with_retry(self.m.step, title, 3, cmd=list(cmd), 38 between_attempts_fn=sleep, **kwargs) 39 40 def install(self): 41 # We assume a single device is connected. 42 43 # Pair the device. 44 try: 45 self.m.run(self.m.step, 'check if device is paired', 46 cmd=['idevicepair', 'validate'], 47 infra_step=True, abort_on_failure=True, 48 fail_build_on_failure=False) 49 except self.m.step.StepFailure: # pragma: nocover 50 self._run('pair device', 'idevicepair', 'pair') # pragma: nocover 51 52 # Mount developer image. 53 image_info = self._run('list mounted image', 54 'ideviceimagemounter', '--list') 55 image_info_out = image_info.stdout.strip() if image_info.stdout else '' 56 if ('ImagePresent: true' not in image_info_out and 57 'ImageSignature:' not in image_info_out): 58 image_pkgs = self.m.file.glob_paths('locate ios-dev-image package', 59 self.m.path['start_dir'], 60 'ios-dev-image*', 61 test_data=['ios-dev-image-13.2']) 62 if len(image_pkgs) != 1: 63 raise Exception('glob for ios-dev-image* returned %s' 64 % image_pkgs) # pragma: nocover 65 66 image_pkg = image_pkgs[0] 67 contents = self.m.file.listdir( 68 'locate image and signature', image_pkg, 69 test_data=['DeveloperDiskImage.dmg', 70 'DeveloperDiskImage.dmg.signature']) 71 image = None 72 sig = None 73 for f in contents: 74 if str(f).endswith('.dmg'): 75 image = f 76 if str(f).endswith('.dmg.signature'): 77 sig = f 78 if not image or not sig: 79 raise Exception('%s does not contain *.dmg and *.dmg.signature' % 80 image_pkg) # pragma: nocover 81 82 self._run('mount developer image', 'ideviceimagemounter', image, sig) 83 84 # Install the apps (necessary before copying any resources to the device). 85 for app_name in ['dm', 'nanobench']: 86 app_package = self.host_dirs.bin_dir.join('%s.app' % app_name) 87 88 def uninstall_app(attempt): 89 # If app ID changes, upgrade will fail, so try uninstalling. 90 self.m.run(self.m.step, 91 'uninstall %s' % app_name, 92 cmd=['ideviceinstaller', '-U', 'com.google.%s' % app_name], 93 infra_step=True, 94 # App may not be installed. 95 abort_on_failure=False, fail_build_on_failure=False) 96 97 num_attempts = 2 98 self.m.run.with_retry(self.m.step, 'install %s' % app_name, num_attempts, 99 cmd=['ideviceinstaller', '-i', app_package], 100 between_attempts_fn=uninstall_app, 101 infra_step=True) 102 103 def step(self, name, cmd, **kwargs): 104 app_name = cmd[0] 105 bundle_id = 'com.google.%s' % app_name 106 args = [bundle_id] + map(str, cmd[1:]) 107 success = False 108 try: 109 self.m.run(self.m.step, name, cmd=['idevicedebug', 'run'] + args) 110 success = True 111 finally: 112 if not success: 113 self.m.run(self.m.python, '%s with full debug output' % name, 114 script=self.module.resource('ios_debug_cmd.py'), 115 args=args) 116 117 def _run_ios_script(self, script, first, *rest): 118 full = self.m.path['start_dir'].join( 119 'skia', 'platform_tools', 'ios', 'bin', 'ios_' + script) 120 self.m.run(self.m.step, 121 name = '%s %s' % (script, first), 122 cmd = [full, first] + list(rest), 123 infra_step=True) 124 125 def copy_file_to_device(self, host, device): 126 self._run_ios_script('push_file', host, device) 127 128 def copy_directory_contents_to_device(self, host, device): 129 self._run_ios_script('push_if_needed', host, device) 130 131 def copy_directory_contents_to_host(self, device, host): 132 self._run_ios_script('pull_if_needed', device, host) 133 134 def remove_file_on_device(self, path): 135 self._run_ios_script('rm', path) 136 137 def create_clean_device_dir(self, path): 138 self._run_ios_script('rm', path) 139 self._run_ios_script('mkdir', path) 140 141 def read_file_on_device(self, path, **kwargs): 142 full = self.m.path['start_dir'].join( 143 'skia', 'platform_tools', 'ios', 'bin', 'ios_cat_file') 144 rv = self.m.run(self.m.step, 145 name = 'cat_file %s' % path, 146 cmd = [full, path], 147 stdout=self.m.raw_io.output(), 148 infra_step=True, 149 **kwargs) 150 return rv.stdout.rstrip() if rv and rv.stdout else None 151