Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(154)

Side by Side Diff: build/android/provision_devices.py

Issue 1124763003: Update from https://crrev.com/327068 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: update nacl, buildtools, fix display_change_notifier_unittest Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # 2 #
3 # Copyright (c) 2013 The Chromium Authors. All rights reserved. 3 # Copyright (c) 2013 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be 4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file. 5 # found in the LICENSE file.
6 6
7 """Provisions Android devices with settings required for bots. 7 """Provisions Android devices with settings required for bots.
8 8
9 Usage: 9 Usage:
10 ./provision_devices.py [-d <device serial number>] 10 ./provision_devices.py [-d <device serial number>]
11 """ 11 """
12 12
13 import argparse 13 import argparse
14 import logging 14 import logging
15 import os 15 import os
16 import posixpath 16 import posixpath
17 import re 17 import re
18 import subprocess 18 import subprocess
19 import sys 19 import sys
20 import time 20 import time
21 21
22 from pylib import android_commands
23 from pylib import constants 22 from pylib import constants
24 from pylib import device_settings 23 from pylib import device_settings
24 from pylib.device import battery_utils
25 from pylib.device import device_blacklist 25 from pylib.device import device_blacklist
26 from pylib.device import device_errors 26 from pylib.device import device_errors
27 from pylib.device import device_utils 27 from pylib.device import device_utils
28 from pylib.utils import run_tests_helper 28 from pylib.utils import run_tests_helper
29 from pylib.utils import timeout_retry 29 from pylib.utils import timeout_retry
30 30
31 sys.path.append(os.path.join(constants.DIR_SOURCE_ROOT, 31 sys.path.append(os.path.join(constants.DIR_SOURCE_ROOT,
32 'third_party', 'android_testrunner')) 32 'third_party', 'android_testrunner'))
33 import errors 33 import errors
34 34
35 35
36 class _DEFAULT_TIMEOUTS(object): 36 class _DEFAULT_TIMEOUTS(object):
37 # L can take a while to reboot after a wipe. 37 # L can take a while to reboot after a wipe.
38 LOLLIPOP = 600 38 LOLLIPOP = 600
39 PRE_LOLLIPOP = 180 39 PRE_LOLLIPOP = 180
40 40
41 HELP_TEXT = '{}s on L, {}s on pre-L'.format(LOLLIPOP, PRE_LOLLIPOP) 41 HELP_TEXT = '{}s on L, {}s on pre-L'.format(LOLLIPOP, PRE_LOLLIPOP)
42 42
43 43
44 def KillHostHeartbeat(): 44 class _PHASES(object):
45 ps = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE) 45 WIPE = 'wipe'
46 stdout, _ = ps.communicate() 46 PROPERTIES = 'properties'
47 matches = re.findall('\\n.*host_heartbeat.*', stdout) 47 FINISH = 'finish'
48 for match in matches: 48
49 logging.info('An instance of host heart beart running... will kill') 49 ALL = [WIPE, PROPERTIES, FINISH]
50 pid = re.findall(r'(\S+)', match)[1]
51 subprocess.call(['kill', str(pid)])
52 50
53 51
54 def LaunchHostHeartbeat(): 52 def ProvisionDevices(options):
55 # Kill if existing host_heartbeat 53 if options.device is not None:
56 KillHostHeartbeat() 54 devices = [options.device]
57 # Launch a new host_heartbeat 55 else:
58 logging.info('Spawning host heartbeat...') 56 devices = device_utils.DeviceUtils.HealthyDevices()
59 subprocess.Popen([os.path.join(constants.DIR_SOURCE_ROOT, 57
60 'build/android/host_heartbeat.py')]) 58 parallel_devices = device_utils.DeviceUtils.parallel(devices)
59 parallel_devices.pMap(ProvisionDevice, options)
60 if options.auto_reconnect:
61 _LaunchHostHeartbeat()
62 blacklist = device_blacklist.ReadBlacklist()
63 if all(d in blacklist for d in devices):
64 raise device_errors.NoDevicesError
65 return 0
61 66
62 67
63 def PushAndLaunchAdbReboot(device, target): 68 def ProvisionDevice(device, options):
64 """Pushes and launches the adb_reboot binary on the device. 69 if options.reboot_timeout:
70 reboot_timeout = options.reboot_timeout
71 elif (device.build_version_sdk >=
72 constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP):
73 reboot_timeout = _DEFAULT_TIMEOUTS.LOLLIPOP
74 else:
75 reboot_timeout = _DEFAULT_TIMEOUTS.PRE_LOLLIPOP
76
77 def should_run_phase(phase_name):
78 return not options.phases or phase_name in options.phases
79
80 def run_phase(phase_func, reboot=True):
81 device.WaitUntilFullyBooted(timeout=reboot_timeout)
82 phase_func(device, options)
83 if reboot:
84 device.Reboot(False, retries=0)
85 device.adb.WaitForDevice()
86
87 try:
88 if should_run_phase(_PHASES.WIPE):
89 run_phase(WipeDevice)
90
91 if should_run_phase(_PHASES.PROPERTIES):
92 run_phase(SetProperties)
93
94 if should_run_phase(_PHASES.FINISH):
95 run_phase(FinishProvisioning, reboot=False)
96
97 except (errors.WaitForResponseTimedOutError,
98 device_errors.CommandTimeoutError):
99 logging.exception('Timed out waiting for device %s. Adding to blacklist.',
100 str(device))
101 device_blacklist.ExtendBlacklist([str(device)])
102
103 except device_errors.CommandFailedError:
104 logging.exception('Failed to provision device %s. Adding to blacklist.',
105 str(device))
106 device_blacklist.ExtendBlacklist([str(device)])
107
108
109 def WipeDevice(device, options):
110 """Wipes data from device, keeping only the adb_keys for authorization.
111
112 After wiping data on a device that has been authorized, adb can still
113 communicate with the device, but after reboot the device will need to be
114 re-authorized because the adb keys file is stored in /data/misc/adb/.
115 Thus, adb_keys file is rewritten so the device does not need to be
116 re-authorized.
65 117
66 Arguments: 118 Arguments:
67 device: The DeviceUtils instance for the device to which the adb_reboot 119 device: the device to wipe
68 binary should be pushed.
69 target: The build target (example, Debug or Release) which helps in
70 locating the adb_reboot binary.
71 """ 120 """
72 logging.info('Will push and launch adb_reboot on %s' % str(device)) 121 if options.skip_wipe:
73 # Kill if adb_reboot is already running. 122 return
123
74 try: 124 try:
75 # Don't try to kill adb_reboot more than once. We don't expect it to be 125 device.EnableRoot()
76 # running at all. 126 device_authorized = device.FileExists(constants.ADB_KEYS_FILE)
77 device.KillAll('adb_reboot', blocking=True, timeout=2, retries=0) 127 if device_authorized:
128 adb_keys = device.ReadFile(constants.ADB_KEYS_FILE,
129 as_root=True).splitlines()
130 device.RunShellCommand(['wipe', 'data'],
131 as_root=True, check_return=True)
132 device.adb.WaitForDevice()
133
134 if device_authorized:
135 adb_keys_set = set(adb_keys)
136 for adb_key_file in options.adb_key_files or []:
137 try:
138 with open(adb_key_file, 'r') as f:
139 adb_public_keys = f.readlines()
140 adb_keys_set.update(adb_public_keys)
141 except IOError:
142 logging.warning('Unable to find adb keys file %s.' % adb_key_file)
143 _WriteAdbKeysFile(device, '\n'.join(adb_keys_set))
78 except device_errors.CommandFailedError: 144 except device_errors.CommandFailedError:
79 # We can safely ignore the exception because we don't expect adb_reboot 145 logging.exception('Possible failure while wiping the device. '
80 # to be running. 146 'Attempting to continue.')
81 pass 147
82 # Push adb_reboot 148
83 logging.info(' Pushing adb_reboot ...') 149 def _WriteAdbKeysFile(device, adb_keys_string):
84 adb_reboot = os.path.join(constants.DIR_SOURCE_ROOT, 150 dir_path = posixpath.dirname(constants.ADB_KEYS_FILE)
85 'out/%s/adb_reboot' % target) 151 device.RunShellCommand(['mkdir', '-p', dir_path],
86 device.PushChangedFiles([(adb_reboot, '/data/local/tmp/')]) 152 as_root=True, check_return=True)
87 # Launch adb_reboot 153 device.RunShellCommand(['restorecon', dir_path],
88 logging.info(' Launching adb_reboot ...') 154 as_root=True, check_return=True)
89 device.RunShellCommand([ 155 device.WriteFile(constants.ADB_KEYS_FILE, adb_keys_string, as_root=True)
90 device.GetDevicePieWrapper(), 156 device.RunShellCommand(['restorecon', constants.ADB_KEYS_FILE],
91 '/data/local/tmp/adb_reboot']) 157 as_root=True, check_return=True)
158
159
160 def SetProperties(device, options):
161 try:
162 device.EnableRoot()
163 except device_errors.CommandFailedError as e:
164 logging.warning(str(e))
165
166 _ConfigureLocalProperties(device, options.enable_java_debug)
167 device_settings.ConfigureContentSettings(
168 device, device_settings.DETERMINISTIC_DEVICE_SETTINGS)
169 if options.disable_location:
170 device_settings.ConfigureContentSettings(
171 device, device_settings.DISABLE_LOCATION_SETTINGS)
172 else:
173 device_settings.ConfigureContentSettings(
174 device, device_settings.ENABLE_LOCATION_SETTINGS)
175 device_settings.SetLockScreenSettings(device)
176 if options.disable_network:
177 device_settings.ConfigureContentSettings(
178 device, device_settings.NETWORK_DISABLED_SETTINGS)
179
180 if options.min_battery_level is not None:
181 try:
182 battery = battery_utils.BatteryUtils(device)
183 battery.ChargeDeviceToLevel(options.min_battery_level)
184 except device_errors.CommandFailedError as e:
185 logging.exception('Unable to charge device to specified level.')
92 186
93 187
94 def _ConfigureLocalProperties(device, java_debug=True): 188 def _ConfigureLocalProperties(device, java_debug=True):
95 """Set standard readonly testing device properties prior to reboot.""" 189 """Set standard readonly testing device properties prior to reboot."""
96 local_props = [ 190 local_props = [
97 'persist.sys.usb.config=adb', 191 'persist.sys.usb.config=adb',
98 'ro.monkey=1', 192 'ro.monkey=1',
99 'ro.test_harness=1', 193 'ro.test_harness=1',
100 'ro.audio.silent=1', 194 'ro.audio.silent=1',
101 'ro.setupwizard.mode=DISABLED', 195 'ro.setupwizard.mode=DISABLED',
102 ] 196 ]
103 if java_debug: 197 if java_debug:
104 local_props.append('%s=all' % android_commands.JAVA_ASSERT_PROPERTY) 198 local_props.append(
199 '%s=all' % device_utils.DeviceUtils.JAVA_ASSERT_PROPERTY)
105 local_props.append('debug.checkjni=1') 200 local_props.append('debug.checkjni=1')
106 try: 201 try:
107 device.WriteFile( 202 device.WriteFile(
108 constants.DEVICE_LOCAL_PROPERTIES_PATH, 203 constants.DEVICE_LOCAL_PROPERTIES_PATH,
109 '\n'.join(local_props), as_root=True) 204 '\n'.join(local_props), as_root=True)
110 # Android will not respect the local props file if it is world writable. 205 # Android will not respect the local props file if it is world writable.
111 device.RunShellCommand( 206 device.RunShellCommand(
112 ['chmod', '644', constants.DEVICE_LOCAL_PROPERTIES_PATH], 207 ['chmod', '644', constants.DEVICE_LOCAL_PROPERTIES_PATH],
113 as_root=True) 208 as_root=True, check_return=True)
114 except device_errors.CommandFailedError as e: 209 except device_errors.CommandFailedError:
115 logging.warning(str(e)) 210 logging.exception('Failed to configure local properties.')
116
117 # LOCAL_PROPERTIES_PATH = '/data/local.prop'
118
119 def WriteAdbKeysFile(device, adb_keys_string):
120 dir_path = posixpath.dirname(constants.ADB_KEYS_FILE)
121 device.RunShellCommand('mkdir -p %s' % dir_path, as_root=True)
122 device.RunShellCommand('restorecon %s' % dir_path, as_root=True)
123 device.WriteFile(constants.ADB_KEYS_FILE, adb_keys_string, as_root=True)
124 device.RunShellCommand('restorecon %s' % constants.ADB_KEYS_FILE,
125 as_root=True)
126 211
127 212
128 def WipeDeviceData(device, options): 213 def FinishProvisioning(device, options):
129 """Wipes data from device, keeping only the adb_keys for authorization. 214 device.RunShellCommand(
215 ['date', '-s', time.strftime('%Y%m%d.%H%M%S', time.gmtime())],
216 as_root=True, check_return=True)
217 props = device.RunShellCommand('getprop', check_return=True)
218 for prop in props:
219 logging.info(' %s' % prop)
220 if options.auto_reconnect:
221 _PushAndLaunchAdbReboot(device, options.target)
130 222
131 After wiping data on a device that has been authorized, adb can still 223
132 communicate with the device, but after reboot the device will need to be 224 def _PushAndLaunchAdbReboot(device, target):
133 re-authorized because the adb keys file is stored in /data/misc/adb/. 225 """Pushes and launches the adb_reboot binary on the device.
134 Thus, adb_keys file is rewritten so the device does not need to be
135 re-authorized.
136 226
137 Arguments: 227 Arguments:
138 device: the device to wipe 228 device: The DeviceUtils instance for the device to which the adb_reboot
229 binary should be pushed.
230 target: The build target (example, Debug or Release) which helps in
231 locating the adb_reboot binary.
139 """ 232 """
140 device_authorized = device.FileExists(constants.ADB_KEYS_FILE) 233 logging.info('Will push and launch adb_reboot on %s' % str(device))
141 if device_authorized: 234 # Kill if adb_reboot is already running.
142 adb_keys = device.ReadFile(constants.ADB_KEYS_FILE, 235 device.KillAll('adb_reboot', blocking=True, timeout=2, quiet=True)
143 as_root=True).splitlines() 236 # Push adb_reboot
144 device.RunShellCommand('wipe data', as_root=True) 237 logging.info(' Pushing adb_reboot ...')
145 if device_authorized: 238 adb_reboot = os.path.join(constants.DIR_SOURCE_ROOT,
146 adb_keys_set = set(adb_keys) 239 'out/%s/adb_reboot' % target)
147 for adb_key_file in options.adb_key_files or []: 240 device.PushChangedFiles([(adb_reboot, '/data/local/tmp/')])
148 try: 241 # Launch adb_reboot
149 with open(adb_key_file, 'r') as f: 242 logging.info(' Launching adb_reboot ...')
150 adb_public_keys = f.readlines() 243 device.RunShellCommand(
151 adb_keys_set.update(adb_public_keys) 244 [device.GetDevicePieWrapper(), '/data/local/tmp/adb_reboot'],
152 except IOError: 245 check_return=True)
153 logging.warning('Unable to find adb keys file %s.' % adb_key_file)
154 WriteAdbKeysFile(device, '\n'.join(adb_keys_set))
155 246
156 247
157 def WipeDeviceIfPossible(device, timeout, options): 248 def _LaunchHostHeartbeat():
158 try: 249 # Kill if existing host_heartbeat
159 device.EnableRoot() 250 KillHostHeartbeat()
160 WipeDeviceData(device, options) 251 # Launch a new host_heartbeat
161 device.Reboot(True, timeout=timeout, retries=0) 252 logging.info('Spawning host heartbeat...')
162 except (errors.DeviceUnresponsiveError, device_errors.CommandFailedError): 253 subprocess.Popen([os.path.join(constants.DIR_SOURCE_ROOT,
163 pass 254 'build/android/host_heartbeat.py')])
164 255
165 256
166 def ChargeDeviceToLevel(device, level): 257 def KillHostHeartbeat():
167 def device_charged(): 258 ps = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE)
168 battery_level = device.GetBatteryInfo().get('level') 259 stdout, _ = ps.communicate()
169 if battery_level is None: 260 matches = re.findall('\\n.*host_heartbeat.*', stdout)
170 logging.warning('Unable to find current battery level.') 261 for match in matches:
171 battery_level = 100 262 logging.info('An instance of host heart beart running... will kill')
172 else: 263 pid = re.findall(r'(\S+)', match)[1]
173 logging.info('current battery level: %d', battery_level) 264 subprocess.call(['kill', str(pid)])
174 battery_level = int(battery_level)
175 return battery_level >= level
176
177 timeout_retry.WaitFor(device_charged, wait_period=60)
178
179
180 def ProvisionDevice(device, options):
181 if options.reboot_timeout:
182 reboot_timeout = options.reboot_timeout
183 elif (device.build_version_sdk >=
184 constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP):
185 reboot_timeout = _DEFAULT_TIMEOUTS.LOLLIPOP
186 else:
187 reboot_timeout = _DEFAULT_TIMEOUTS.PRE_LOLLIPOP
188
189 try:
190 if not options.skip_wipe:
191 WipeDeviceIfPossible(device, reboot_timeout, options)
192 try:
193 device.EnableRoot()
194 except device_errors.CommandFailedError as e:
195 logging.warning(str(e))
196 _ConfigureLocalProperties(device, options.enable_java_debug)
197 device_settings.ConfigureContentSettings(
198 device, device_settings.DETERMINISTIC_DEVICE_SETTINGS)
199 if options.disable_location:
200 device_settings.ConfigureContentSettings(
201 device, device_settings.DISABLE_LOCATION_SETTINGS)
202 else:
203 device_settings.ConfigureContentSettings(
204 device, device_settings.ENABLE_LOCATION_SETTINGS)
205 device_settings.SetLockScreenSettings(device)
206 if options.disable_network:
207 device_settings.ConfigureContentSettings(
208 device, device_settings.NETWORK_DISABLED_SETTINGS)
209 if options.min_battery_level is not None:
210 try:
211 device.SetCharging(True)
212 ChargeDeviceToLevel(device, options.min_battery_level)
213 except device_errors.CommandFailedError as e:
214 logging.exception('Unable to charge device to specified level.')
215
216 if not options.skip_wipe:
217 device.Reboot(True, timeout=reboot_timeout, retries=0)
218 device.RunShellCommand('date -s %s' % time.strftime('%Y%m%d.%H%M%S',
219 time.gmtime()),
220 as_root=True)
221 props = device.RunShellCommand('getprop')
222 for prop in props:
223 logging.info(' %s' % prop)
224 if options.auto_reconnect:
225 PushAndLaunchAdbReboot(device, options.target)
226 except (errors.WaitForResponseTimedOutError,
227 device_errors.CommandTimeoutError):
228 logging.info('Timed out waiting for device %s. Adding to blacklist.',
229 str(device))
230 # Device black list is reset by bb_device_status_check.py per build.
231 device_blacklist.ExtendBlacklist([str(device)])
232 except device_errors.CommandFailedError:
233 logging.exception('Failed to provision device %s. Adding to blacklist.',
234 str(device))
235 device_blacklist.ExtendBlacklist([str(device)])
236
237
238 def ProvisionDevices(options):
239 if options.device is not None:
240 devices = [options.device]
241 else:
242 devices = android_commands.GetAttachedDevices()
243
244 parallel_devices = device_utils.DeviceUtils.parallel(devices)
245 parallel_devices.pMap(ProvisionDevice, options)
246 if options.auto_reconnect:
247 LaunchHostHeartbeat()
248 blacklist = device_blacklist.ReadBlacklist()
249 if all(d in blacklist for d in devices):
250 raise device_errors.NoDevicesError
251 return 0
252 265
253 266
254 def main(): 267 def main():
255 custom_handler = logging.StreamHandler(sys.stdout)
256 custom_handler.setFormatter(run_tests_helper.CustomFormatter())
257 logging.getLogger().addHandler(custom_handler)
258 logging.getLogger().setLevel(logging.INFO)
259
260 # Recommended options on perf bots: 268 # Recommended options on perf bots:
261 # --disable-network 269 # --disable-network
262 # TODO(tonyg): We eventually want network on. However, currently radios 270 # TODO(tonyg): We eventually want network on. However, currently radios
263 # can cause perfbots to drain faster than they charge. 271 # can cause perfbots to drain faster than they charge.
264 # --min-battery-level 95 272 # --min-battery-level 95
265 # Some perf bots run benchmarks with USB charging disabled which leads 273 # Some perf bots run benchmarks with USB charging disabled which leads
266 # to gradual draining of the battery. We must wait for a full charge 274 # to gradual draining of the battery. We must wait for a full charge
267 # before starting a run in order to keep the devices online. 275 # before starting a run in order to keep the devices online.
268 276
269 parser = argparse.ArgumentParser( 277 parser = argparse.ArgumentParser(
270 description='Provision Android devices with settings required for bots.') 278 description='Provision Android devices with settings required for bots.')
271 parser.add_argument('-d', '--device', metavar='SERIAL', 279 parser.add_argument('-d', '--device', metavar='SERIAL',
272 help='the serial number of the device to be provisioned' 280 help='the serial number of the device to be provisioned'
273 ' (the default is to provision all devices attached)') 281 ' (the default is to provision all devices attached)')
282 parser.add_argument('--phase', action='append', choices=_PHASES.ALL,
283 dest='phases',
284 help='Phases of provisioning to run. '
285 '(If omitted, all phases will be run.)')
274 parser.add_argument('--skip-wipe', action='store_true', default=False, 286 parser.add_argument('--skip-wipe', action='store_true', default=False,
275 help="don't wipe device data during provisioning") 287 help="don't wipe device data during provisioning")
276 parser.add_argument('--reboot-timeout', metavar='SECS', type=int, 288 parser.add_argument('--reboot-timeout', metavar='SECS', type=int,
277 help='when wiping the device, max number of seconds to' 289 help='when wiping the device, max number of seconds to'
278 ' wait after each reboot ' 290 ' wait after each reboot '
279 '(default: %s)' % _DEFAULT_TIMEOUTS.HELP_TEXT) 291 '(default: %s)' % _DEFAULT_TIMEOUTS.HELP_TEXT)
280 parser.add_argument('--min-battery-level', type=int, metavar='NUM', 292 parser.add_argument('--min-battery-level', type=int, metavar='NUM',
281 help='wait for the device to reach this minimum battery' 293 help='wait for the device to reach this minimum battery'
282 ' level before trying to continue') 294 ' level before trying to continue')
283 parser.add_argument('--disable-location', action='store_true', 295 parser.add_argument('--disable-location', action='store_true',
284 help='disable Google location services on devices') 296 help='disable Google location services on devices')
285 parser.add_argument('--disable-network', action='store_true', 297 parser.add_argument('--disable-network', action='store_true',
286 help='disable network access on devices') 298 help='disable network access on devices')
287 parser.add_argument('--disable-java-debug', action='store_false', 299 parser.add_argument('--disable-java-debug', action='store_false',
288 dest='enable_java_debug', default=True, 300 dest='enable_java_debug', default=True,
289 help='disable Java property asserts and JNI checking') 301 help='disable Java property asserts and JNI checking')
290 parser.add_argument('-t', '--target', default='Debug', 302 parser.add_argument('-t', '--target', default='Debug',
291 help='the build target (default: %(default)s)') 303 help='the build target (default: %(default)s)')
292 parser.add_argument('-r', '--auto-reconnect', action='store_true', 304 parser.add_argument('-r', '--auto-reconnect', action='store_true',
293 help='push binary which will reboot the device on adb' 305 help='push binary which will reboot the device on adb'
294 ' disconnections') 306 ' disconnections')
295 parser.add_argument('--adb-key-files', type=str, nargs='+', 307 parser.add_argument('--adb-key-files', type=str, nargs='+',
296 help='list of adb keys to push to device') 308 help='list of adb keys to push to device')
309 parser.add_argument('-v', '--verbose', action='count', default=1,
310 help='Log more information.')
297 args = parser.parse_args() 311 args = parser.parse_args()
298 constants.SetBuildType(args.target) 312 constants.SetBuildType(args.target)
299 313
314 run_tests_helper.SetLogLevel(args.verbose)
315
300 return ProvisionDevices(args) 316 return ProvisionDevices(args)
301 317
302 318
303 if __name__ == '__main__': 319 if __name__ == '__main__':
304 sys.exit(main()) 320 sys.exit(main())
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698