1#!/usr/bin/env python 2# 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 5# found in the LICENSE file. 6"""Provisions Android devices with settings required for bots. 7 8Usage: 9 ./provision_devices.py [-d <device serial number>] 10""" 11 12import argparse 13import datetime 14import json 15import logging 16import os 17import posixpath 18import re 19import sys 20import time 21 22# Import _strptime before threaded code. datetime.datetime.strptime is 23# threadsafe except for the initial import of the _strptime module. 24# See crbug.com/584730 and https://bugs.python.org/issue7980. 25import _strptime # pylint: disable=unused-import 26 27if __name__ == '__main__': 28 sys.path.append( 29 os.path.abspath( 30 os.path.join(os.path.dirname(__file__), '..', '..', '..'))) 31 32from devil.android import battery_utils 33from devil.android import device_denylist 34from devil.android import device_errors 35from devil.android import device_temp_file 36from devil.android import device_utils 37from devil.android import settings 38from devil.android.sdk import adb_wrapper 39from devil.android.sdk import intent 40from devil.android.sdk import keyevent 41from devil.android.sdk import shared_prefs 42from devil.android.sdk import version_codes 43from devil.android.tools import script_common 44from devil.constants import exit_codes 45from devil.utils import logging_common 46from devil.utils import timeout_retry 47 48logger = logging.getLogger(__name__) 49 50_SYSTEM_APP_DIRECTORIES = ['/system/app/', '/system/priv-app/'] 51_SYSTEM_WEBVIEW_NAMES = ['webview', 'WebViewGoogle'] 52_CHROME_PACKAGE_REGEX = re.compile('.*chrom.*') 53_TOMBSTONE_REGEX = re.compile('tombstone.*') 54_STANDALONE_VR_DEVICES = [ 55 'vega', # Lenovo Mirage Solo 56] 57 58 59class _DEFAULT_TIMEOUTS(object): 60 # L can take a while to reboot after a wipe. 61 LOLLIPOP = 600 62 PRE_LOLLIPOP = 180 63 64 HELP_TEXT = '{}s on L, {}s on pre-L'.format(LOLLIPOP, PRE_LOLLIPOP) 65 66 67class ProvisionStep(object): 68 def __init__(self, cmd, reboot=False): 69 self.cmd = cmd 70 self.reboot = reboot 71 72 73def ProvisionDevices(devices, 74 denylist_file, 75 adb_key_files=None, 76 disable_location=False, 77 disable_mock_location=False, 78 disable_network=False, 79 disable_system_chrome=False, 80 emulators=False, 81 enable_java_debug=False, 82 max_battery_temp=None, 83 min_battery_level=None, 84 output_device_denylist=None, 85 reboot_timeout=None, 86 remove_system_webview=False, 87 system_app_remove_list=None, 88 system_package_remove_list=None, 89 wipe=True): 90 denylist = (device_denylist.Denylist(denylist_file) 91 if denylist_file else None) 92 system_app_remove_list = system_app_remove_list or [] 93 system_package_remove_list = system_package_remove_list or [] 94 try: 95 devices = script_common.GetDevices(devices, denylist) 96 except device_errors.NoDevicesError: 97 logging.error('No available devices to provision.') 98 if denylist: 99 logging.error('Local device denylist: %s', denylist.Read()) 100 raise 101 devices = [d for d in devices if not emulators or d.adb.is_emulator] 102 parallel_devices = device_utils.DeviceUtils.parallel(devices) 103 104 steps = [] 105 if wipe: 106 steps += [ProvisionStep(lambda d: Wipe(d, adb_key_files), reboot=True)] 107 steps += [ 108 ProvisionStep( 109 lambda d: SetProperties(d, enable_java_debug, disable_location, 110 disable_mock_location), 111 reboot=not emulators) 112 ] 113 114 if disable_network: 115 steps.append(ProvisionStep(DisableNetwork)) 116 117 if disable_system_chrome: 118 steps.append(ProvisionStep(DisableSystemChrome)) 119 120 if max_battery_temp: 121 steps.append( 122 ProvisionStep(lambda d: WaitForBatteryTemperature(d, max_battery_temp))) 123 124 if min_battery_level: 125 steps.append(ProvisionStep(lambda d: WaitForCharge(d, min_battery_level))) 126 127 if remove_system_webview: 128 system_app_remove_list.extend(_SYSTEM_WEBVIEW_NAMES) 129 130 if system_app_remove_list or system_package_remove_list: 131 steps.append( 132 ProvisionStep(lambda d: RemoveSystemApps(d, system_app_remove_list, 133 system_package_remove_list))) 134 135 steps.append(ProvisionStep(SetDate)) 136 steps.append(ProvisionStep(CheckExternalStorage)) 137 steps.append(ProvisionStep(StandaloneVrDeviceSetup)) 138 139 parallel_devices.pMap(ProvisionDevice, steps, denylist, reboot_timeout) 140 141 denylisted_devices = denylist.Read() if denylist else [] 142 if output_device_denylist: 143 with open(output_device_denylist, 'w') as f: 144 json.dump(denylisted_devices, f) 145 if all(d in denylisted_devices for d in devices): 146 raise device_errors.NoDevicesError 147 return 0 148 149 150def ProvisionDevice(device, steps, denylist, reboot_timeout=None): 151 try: 152 if not reboot_timeout: 153 if device.build_version_sdk >= version_codes.LOLLIPOP: 154 reboot_timeout = _DEFAULT_TIMEOUTS.LOLLIPOP 155 else: 156 reboot_timeout = _DEFAULT_TIMEOUTS.PRE_LOLLIPOP 157 158 for step in steps: 159 try: 160 device.WaitUntilFullyBooted(timeout=reboot_timeout, retries=0) 161 except device_errors.CommandTimeoutError: 162 logger.error('Device did not finish booting. Will try to reboot.') 163 device.Reboot(timeout=reboot_timeout) 164 step.cmd(device) 165 if step.reboot: 166 device.Reboot(False, retries=0) 167 device.adb.WaitForDevice() 168 169 except device_errors.CommandTimeoutError: 170 logger.exception('Timed out waiting for device %s. Adding to denylist.', 171 str(device)) 172 if denylist: 173 denylist.Extend([str(device)], reason='provision_timeout') 174 175 except (device_errors.CommandFailedError, 176 device_errors.DeviceUnreachableError): 177 logger.exception('Failed to provision device %s. Adding to denylist.', 178 str(device)) 179 if denylist: 180 denylist.Extend([str(device)], reason='provision_failure') 181 182 183def Wipe(device, adb_key_files=None): 184 if (device.IsUserBuild() 185 or device.build_version_sdk >= version_codes.MARSHMALLOW): 186 WipeChromeData(device) 187 188 package = 'com.google.android.gms' 189 version_name = device.GetApplicationVersion(package) 190 if version_name: 191 logger.info('Version name for %s is %s', package, version_name) 192 else: 193 logger.info('Package %s is not installed', package) 194 else: 195 WipeDevice(device, adb_key_files) 196 197 198def WipeChromeData(device): 199 """Wipes chrome specific data from device 200 201 (1) uninstall any app whose name matches *chrom*, except 202 com.android.chrome, which is the chrome stable package. Doing so also 203 removes the corresponding dirs under /data/data/ and /data/app/ 204 (2) remove any dir under /data/app-lib/ whose name matches *chrom* 205 (3) remove any files under /data/tombstones/ whose name matches "tombstone*" 206 (4) remove /data/local.prop if there is any 207 (5) remove /data/local/chrome-command-line if there is any 208 (6) remove anything under /data/local/.config/ if the dir exists 209 (this is telemetry related) 210 (7) remove anything under /data/local/tmp/ 211 212 Arguments: 213 device: the device to wipe 214 """ 215 try: 216 if device.IsUserBuild(): 217 _UninstallIfMatch(device, _CHROME_PACKAGE_REGEX) 218 device.RunShellCommand( 219 'rm -rf %s/*' % device.GetExternalStoragePath(), 220 shell=True, 221 check_return=True) 222 device.RunShellCommand( 223 'rm -rf /data/local/tmp/*', shell=True, check_return=True) 224 else: 225 device.EnableRoot() 226 _UninstallIfMatch(device, _CHROME_PACKAGE_REGEX) 227 _WipeUnderDirIfMatch(device, '/data/app-lib/', _CHROME_PACKAGE_REGEX) 228 _WipeUnderDirIfMatch(device, '/data/tombstones/', _TOMBSTONE_REGEX) 229 230 _WipeFileOrDir(device, '/data/local.prop') 231 _WipeFileOrDir(device, '/data/local/chrome-command-line') 232 _WipeFileOrDir(device, '/data/local/.config/') 233 _WipeFileOrDir(device, '/data/local/tmp/') 234 device.RunShellCommand( 235 'rm -rf %s/*' % device.GetExternalStoragePath(), 236 shell=True, 237 check_return=True) 238 except device_errors.CommandFailedError: 239 logger.exception('Possible failure while wiping the device. ' 240 'Attempting to continue.') 241 242 243def _UninstallIfMatch(device, pattern): 244 installed_packages = device.RunShellCommand(['pm', 'list', 'packages'], 245 check_return=True) 246 installed_system_packages = [ 247 pkg.split(':')[1] 248 for pkg in device.RunShellCommand(['pm', 'list', 'packages', '-s'], 249 check_return=True) 250 ] 251 for package_output in installed_packages: 252 package = package_output.split(":")[1] 253 if pattern.match(package) and package not in installed_system_packages: 254 device.Uninstall(package) 255 256 257def _WipeUnderDirIfMatch(device, path, pattern): 258 for filename in device.ListDirectory(path): 259 if pattern.match(filename): 260 _WipeFileOrDir(device, posixpath.join(path, filename)) 261 262 263def _WipeFileOrDir(device, path): 264 if device.PathExists(path): 265 device.RunShellCommand(['rm', '-rf', path], check_return=True) 266 267 268def WipeDevice(device, adb_key_files): 269 """Wipes data from device, keeping only the adb_keys for authorization. 270 271 After wiping data on a device that has been authorized, adb can still 272 communicate with the device, but after reboot the device will need to be 273 re-authorized because the adb keys file is stored in /data/misc/adb/. 274 Thus, adb_keys file is rewritten so the device does not need to be 275 re-authorized. 276 277 Arguments: 278 device: the device to wipe 279 """ 280 try: 281 device.EnableRoot() 282 device_authorized = device.FileExists(adb_wrapper.ADB_KEYS_FILE) 283 if device_authorized: 284 adb_keys = device.ReadFile( 285 adb_wrapper.ADB_KEYS_FILE, as_root=True).splitlines() 286 device.RunShellCommand(['wipe', 'data'], as_root=True, check_return=True) 287 device.adb.WaitForDevice() 288 289 if device_authorized: 290 adb_keys_set = set(adb_keys) 291 for adb_key_file in adb_key_files or []: 292 try: 293 with open(adb_key_file, 'r') as f: 294 adb_public_keys = f.readlines() 295 adb_keys_set.update(adb_public_keys) 296 except IOError: 297 logger.warning('Unable to find adb keys file %s.', adb_key_file) 298 _WriteAdbKeysFile(device, '\n'.join(adb_keys_set)) 299 except device_errors.CommandFailedError: 300 logger.exception('Possible failure while wiping the device. ' 301 'Attempting to continue.') 302 303 304def _WriteAdbKeysFile(device, adb_keys_string): 305 dir_path = posixpath.dirname(adb_wrapper.ADB_KEYS_FILE) 306 device.RunShellCommand(['mkdir', '-p', dir_path], 307 as_root=True, 308 check_return=True) 309 device.RunShellCommand(['restorecon', dir_path], 310 as_root=True, 311 check_return=True) 312 device.WriteFile(adb_wrapper.ADB_KEYS_FILE, adb_keys_string, as_root=True) 313 device.RunShellCommand(['restorecon', adb_wrapper.ADB_KEYS_FILE], 314 as_root=True, 315 check_return=True) 316 317 318def SetProperties(device, enable_java_debug, disable_location, 319 disable_mock_location): 320 try: 321 device.EnableRoot() 322 except device_errors.CommandFailedError as e: 323 logger.warning(str(e)) 324 325 if not device.IsUserBuild(): 326 _ConfigureLocalProperties(device, enable_java_debug) 327 else: 328 logger.warning('Cannot configure properties in user builds.') 329 settings.ConfigureContentSettings(device, 330 settings.DETERMINISTIC_DEVICE_SETTINGS) 331 if disable_location: 332 settings.ConfigureContentSettings(device, 333 settings.DISABLE_LOCATION_SETTINGS) 334 else: 335 settings.ConfigureContentSettings(device, settings.ENABLE_LOCATION_SETTINGS) 336 337 if disable_mock_location: 338 settings.ConfigureContentSettings(device, 339 settings.DISABLE_MOCK_LOCATION_SETTINGS) 340 else: 341 settings.ConfigureContentSettings(device, 342 settings.ENABLE_MOCK_LOCATION_SETTINGS) 343 344 settings.SetLockScreenSettings(device) 345 346 # Some device types can momentarily disappear after setting properties. 347 device.adb.WaitForDevice() 348 349 350def DisableNetwork(device): 351 settings.ConfigureContentSettings(device, settings.NETWORK_DISABLED_SETTINGS) 352 if device.build_version_sdk >= version_codes.MARSHMALLOW: 353 # Ensure that NFC is also switched off. 354 device.RunShellCommand(['svc', 'nfc', 'disable'], 355 as_root=True, 356 check_return=True) 357 358 359def DisableSystemChrome(device): 360 # The system chrome version on the device interferes with some tests. 361 device.RunShellCommand(['pm', 'disable', 'com.android.chrome'], 362 as_root=True, 363 check_return=True) 364 365 366def _FindSystemPackagePaths(device, system_package_list): 367 found_paths = [] 368 for system_package in system_package_list: 369 found_paths.extend(device.GetApplicationPaths(system_package)) 370 return [p for p in found_paths if p.startswith('/system/')] 371 372 373def _FindSystemAppPaths(device, system_app_list): 374 found_paths = [] 375 for system_app in system_app_list: 376 for directory in _SYSTEM_APP_DIRECTORIES: 377 path = os.path.join(directory, system_app) 378 if device.PathExists(path): 379 found_paths.append(path) 380 return found_paths 381 382 383def RemoveSystemApps(device, system_app_remove_list, 384 system_package_remove_list): 385 """Attempts to remove the provided system apps from the given device. 386 387 Arguments: 388 device: The device to remove the system apps from. 389 system_app_remove_list: A list of app names to remove, e.g. 390 ['WebViewGoogle', 'GoogleVrCore'] 391 system_package_remove_list: A list of app packages to remove, e.g. 392 ['com.google.android.webview'] 393 """ 394 device.EnableRoot() 395 if device.HasRoot(): 396 system_app_paths = ( 397 _FindSystemAppPaths(device, system_app_remove_list) + 398 _FindSystemPackagePaths(device, system_package_remove_list)) 399 if system_app_paths: 400 # Disable Marshmallow's Verity security feature 401 if device.build_version_sdk >= version_codes.MARSHMALLOW: 402 logger.info('Disabling Verity on %s', device.serial) 403 device.adb.DisableVerity() 404 device.Reboot() 405 device.WaitUntilFullyBooted() 406 device.EnableRoot() 407 408 device.adb.Remount() 409 device.RunShellCommand(['stop'], check_return=True) 410 device.RemovePath(system_app_paths, force=True, recursive=True) 411 device.RunShellCommand(['start'], check_return=True) 412 else: 413 raise device_errors.CommandFailedError( 414 'Failed to remove system apps from non-rooted device', str(device)) 415 416 417def _ConfigureLocalProperties(device, java_debug=True): 418 """Set standard readonly testing device properties prior to reboot.""" 419 local_props = [ 420 'persist.sys.usb.config=adb', 421 'ro.monkey=1', 422 'ro.test_harness=1', 423 'ro.audio.silent=1', 424 'ro.setupwizard.mode=DISABLED', 425 ] 426 if java_debug: 427 local_props.append('%s=all' % device_utils.DeviceUtils.JAVA_ASSERT_PROPERTY) 428 local_props.append('debug.checkjni=1') 429 try: 430 device.WriteFile( 431 device.LOCAL_PROPERTIES_PATH, '\n'.join(local_props), as_root=True) 432 # Android will not respect the local props file if it is world writable. 433 device.RunShellCommand(['chmod', '644', device.LOCAL_PROPERTIES_PATH], 434 as_root=True, 435 check_return=True) 436 except device_errors.CommandFailedError: 437 logger.exception('Failed to configure local properties.') 438 439 440def FinishProvisioning(device): 441 # The lockscreen can't be disabled on user builds, so send a keyevent 442 # to unlock it. 443 if device.IsUserBuild(): 444 device.SendKeyEvent(keyevent.KEYCODE_MENU) 445 446 447def WaitForCharge(device, min_battery_level): 448 battery = battery_utils.BatteryUtils(device) 449 try: 450 battery.ChargeDeviceToLevel(min_battery_level) 451 except device_errors.DeviceChargingError: 452 device.Reboot() 453 battery.ChargeDeviceToLevel(min_battery_level) 454 455 456def WaitForBatteryTemperature(device, max_battery_temp): 457 try: 458 battery = battery_utils.BatteryUtils(device) 459 battery.LetBatteryCoolToTemperature(max_battery_temp) 460 except device_errors.CommandFailedError: 461 logger.exception('Unable to let battery cool to specified temperature.') 462 463 464def SetDate(device): 465 def _set_and_verify_date(): 466 if device.build_version_sdk >= version_codes.MARSHMALLOW: 467 date_format = '%m%d%H%M%Y.%S' 468 set_date_command = ['date', '-u'] 469 get_date_command = ['date', '-u'] 470 else: 471 date_format = '%Y%m%d.%H%M%S' 472 set_date_command = ['date', '-s'] 473 get_date_command = ['date'] 474 475 # TODO(jbudorick): This is wrong on pre-M devices -- get/set are 476 # dealing in local time, but we're setting based on GMT. 477 strgmtime = time.strftime(date_format, time.gmtime()) 478 set_date_command.append(strgmtime) 479 device.RunShellCommand(set_date_command, as_root=True, check_return=True) 480 481 get_date_command.append('+"%Y%m%d.%H%M%S"') 482 device_time = device.RunShellCommand( 483 get_date_command, check_return=True, as_root=True, 484 single_line=True).replace('"', '') 485 device_time = datetime.datetime.strptime(device_time, "%Y%m%d.%H%M%S") 486 correct_time = datetime.datetime.strptime(strgmtime, date_format) 487 tdelta = (correct_time - device_time).seconds 488 if tdelta <= 1: 489 logger.info('Date/time successfully set on %s', device) 490 return True 491 else: 492 logger.error('Date mismatch. Device: %s Correct: %s', 493 device_time.isoformat(), correct_time.isoformat()) 494 return False 495 496 # Sometimes the date is not set correctly on the devices. Retry on failure. 497 if device.IsUserBuild(): 498 # TODO(bpastene): Figure out how to set the date & time on user builds. 499 pass 500 else: 501 if not timeout_retry.WaitFor( 502 _set_and_verify_date, wait_period=1, max_tries=2): 503 raise device_errors.CommandFailedError( 504 'Failed to set date & time.', device_serial=str(device)) 505 device.EnableRoot() 506 # The following intent can take a bit to complete when ran shortly after 507 # device boot-up. 508 device.BroadcastIntent( 509 intent.Intent(action='android.intent.action.TIME_SET'), timeout=180) 510 511 512def LogDeviceProperties(device): 513 props = device.RunShellCommand(['getprop'], check_return=True) 514 for prop in props: 515 logger.info(' %s', prop) 516 517 518# TODO(jbudorick): Relocate this either to device_utils or a separate 519# and more intentionally reusable layer on top of device_utils. 520def CheckExternalStorage(device): 521 """Checks that storage is writable and if not makes it writable. 522 523 Arguments: 524 device: The device to check. 525 """ 526 try: 527 with device_temp_file.DeviceTempFile( 528 device.adb, suffix='.sh', dir=device.GetExternalStoragePath()) as f: 529 device.WriteFile(f.name, 'test') 530 except device_errors.CommandFailedError: 531 logger.info('External storage not writable. Remounting / as RW') 532 device.RunShellCommand(['mount', '-o', 'remount,rw', '/'], 533 check_return=True, 534 as_root=True) 535 device.EnableRoot() 536 with device_temp_file.DeviceTempFile( 537 device.adb, suffix='.sh', dir=device.GetExternalStoragePath()) as f: 538 device.WriteFile(f.name, 'test') 539 540 541def StandaloneVrDeviceSetup(device): 542 """Performs any additional setup necessary for standalone Android VR devices. 543 544 Arguments: 545 device: The device to check. 546 """ 547 if device.product_name not in _STANDALONE_VR_DEVICES: 548 return 549 550 # Modify VrCore's settings so that any first time setup, etc. is skipped. 551 shared_pref = shared_prefs.SharedPrefs( 552 device, 553 'com.google.vr.vrcore', 554 'VrCoreSettings.xml', 555 use_encrypted_path=True) 556 shared_pref.Load() 557 # Skip first time setup. 558 shared_pref.SetBoolean('DaydreamSetupComplete', True) 559 # Disable the automatic prompt that shows anytime the device detects that a 560 # controller isn't connected. 561 shared_pref.SetBoolean('gConfigFlags:controller_recovery_enabled', False) 562 # Use an automated controller instead of a real one so we get past the 563 # controller pairing screen that's shown on startup. 564 shared_pref.SetBoolean('UseAutomatedController', True) 565 shared_pref.Commit() 566 567 568def main(raw_args): 569 # Recommended options on perf bots: 570 # --disable-network 571 # TODO(tonyg): We eventually want network on. However, currently radios 572 # can cause perfbots to drain faster than they charge. 573 # --min-battery-level 95 574 # Some perf bots run benchmarks with USB charging disabled which leads 575 # to gradual draining of the battery. We must wait for a full charge 576 # before starting a run in order to keep the devices online. 577 578 parser = argparse.ArgumentParser( 579 description='Provision Android devices with settings required for bots.') 580 logging_common.AddLoggingArguments(parser) 581 script_common.AddDeviceArguments(parser) 582 script_common.AddEnvironmentArguments(parser) 583 parser.add_argument( 584 '--adb-key-files', 585 type=str, 586 nargs='+', 587 help='list of adb keys to push to device') 588 parser.add_argument( 589 '--disable-location', 590 action='store_true', 591 help='disable Google location services on devices') 592 parser.add_argument( 593 '--disable-mock-location', 594 action='store_true', 595 default=False, 596 help='Set ALLOW_MOCK_LOCATION to false') 597 parser.add_argument( 598 '--disable-network', 599 action='store_true', 600 help='disable network access on devices') 601 parser.add_argument( 602 '--disable-java-debug', 603 action='store_false', 604 dest='enable_java_debug', 605 default=True, 606 help='disable Java property asserts and JNI checking') 607 parser.add_argument( 608 '--disable-system-chrome', 609 action='store_true', 610 help='DEPRECATED: use --remove-system-packages com.android.google ' 611 'Disable the system chrome from devices.') 612 parser.add_argument( 613 '--emulators', 614 action='store_true', 615 help='provision only emulators and ignore usb devices ' 616 '(this will not wipe emulators)') 617 parser.add_argument( 618 '--max-battery-temp', 619 type=int, 620 metavar='NUM', 621 help='Wait for the battery to have this temp or lower.') 622 parser.add_argument( 623 '--min-battery-level', 624 type=int, 625 metavar='NUM', 626 help='wait for the device to reach this minimum battery' 627 ' level before trying to continue') 628 parser.add_argument('--output-device-denylist', 629 help='Json file to output the device denylist.') 630 parser.add_argument( 631 '--reboot-timeout', 632 metavar='SECS', 633 type=int, 634 help='when wiping the device, max number of seconds to' 635 ' wait after each reboot ' 636 '(default: %s)' % _DEFAULT_TIMEOUTS.HELP_TEXT) 637 parser.add_argument( 638 '--remove-system-apps', 639 nargs='*', 640 dest='system_app_remove_list', 641 help='DEPRECATED: use --remove-system-packages instead. ' 642 'The names of system apps to remove. ') 643 parser.add_argument( 644 '--remove-system-packages', 645 nargs='*', 646 dest='system_package_remove_list', 647 help='The names of system packages to remove.') 648 parser.add_argument( 649 '--remove-system-webview', 650 action='store_true', 651 help='DEPRECATED: use --remove-system-packages ' 652 'com.google.android.webview com.android.webview ' 653 'Remove the system webview from devices.') 654 parser.add_argument( 655 '--skip-wipe', 656 action='store_true', 657 default=False, 658 help='do not wipe device data during provisioning') 659 660 # No-op arguments for compatibility with build/android/provision_devices.py. 661 # TODO(jbudorick): Remove these once all callers have stopped using them. 662 parser.add_argument( 663 '--chrome-specific-wipe', action='store_true', help=argparse.SUPPRESS) 664 parser.add_argument('--phase', action='append', help=argparse.SUPPRESS) 665 parser.add_argument( 666 '-r', '--auto-reconnect', action='store_true', help=argparse.SUPPRESS) 667 parser.add_argument('-t', '--target', help=argparse.SUPPRESS) 668 669 args = parser.parse_args(raw_args) 670 671 logging_common.InitializeLogging(args) 672 script_common.InitializeEnvironment(args) 673 674 try: 675 return ProvisionDevices( 676 args.devices, 677 args.denylist_file, 678 adb_key_files=args.adb_key_files, 679 disable_location=args.disable_location, 680 disable_mock_location=args.disable_mock_location, 681 disable_network=args.disable_network, 682 disable_system_chrome=args.disable_system_chrome, 683 emulators=args.emulators, 684 enable_java_debug=args.enable_java_debug, 685 max_battery_temp=args.max_battery_temp, 686 min_battery_level=args.min_battery_level, 687 output_device_denylist=args.output_device_denylist, 688 reboot_timeout=args.reboot_timeout, 689 remove_system_webview=args.remove_system_webview, 690 system_app_remove_list=args.system_app_remove_list, 691 system_package_remove_list=args.system_package_remove_list, 692 wipe=not args.skip_wipe and not args.emulators) 693 except (device_errors.DeviceUnreachableError, device_errors.NoDevicesError): 694 logging.exception('Unable to provision local devices.') 695 return exit_codes.INFRA 696 697 698if __name__ == '__main__': 699 sys.exit(main(sys.argv[1:])) 700