| OLD | NEW |
| 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 datetime | 14 import datetime |
| 15 import json | 15 import json |
| 16 import logging | 16 import logging |
| 17 import os | 17 import os |
| 18 import posixpath | 18 import posixpath |
| 19 import re | 19 import re |
| 20 import subprocess | 20 import subprocess |
| 21 import sys | 21 import sys |
| 22 import time | 22 import time |
| 23 | 23 |
| 24 import devil_chromium | 24 import devil_chromium |
| 25 from devil.android import battery_utils | 25 from devil.android import battery_utils |
| 26 from devil.android import device_blacklist | 26 from devil.android import device_blacklist |
| 27 from devil.android import device_errors | 27 from devil.android import device_errors |
| 28 from devil.android import device_temp_file | 28 from devil.android import device_temp_file |
| 29 from devil.android import device_utils | 29 from devil.android import device_utils |
| 30 from devil.android.sdk import keyevent |
| 30 from devil.android.sdk import version_codes | 31 from devil.android.sdk import version_codes |
| 31 from devil.utils import run_tests_helper | 32 from devil.utils import run_tests_helper |
| 32 from devil.utils import timeout_retry | 33 from devil.utils import timeout_retry |
| 33 from pylib import constants | 34 from pylib import constants |
| 34 from pylib import device_settings | 35 from pylib import device_settings |
| 35 | 36 |
| 36 _SYSTEM_WEBVIEW_PATHS = ['/system/app/webview', '/system/app/WebViewGoogle'] | 37 _SYSTEM_WEBVIEW_PATHS = ['/system/app/webview', '/system/app/WebViewGoogle'] |
| 37 _CHROME_PACKAGE_REGEX = re.compile('.*chrom.*') | 38 _CHROME_PACKAGE_REGEX = re.compile('.*chrom.*') |
| 38 _TOMBSTONE_REGEX = re.compile('tombstone.*') | 39 _TOMBSTONE_REGEX = re.compile('tombstone.*') |
| 39 | 40 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 except device_errors.CommandTimeoutError: | 98 except device_errors.CommandTimeoutError: |
| 98 logging.error('Device did not finish booting. Will try to reboot.') | 99 logging.error('Device did not finish booting. Will try to reboot.') |
| 99 device.Reboot(timeout=reboot_timeout) | 100 device.Reboot(timeout=reboot_timeout) |
| 100 phase_func(device, options) | 101 phase_func(device, options) |
| 101 if reboot: | 102 if reboot: |
| 102 device.Reboot(False, retries=0) | 103 device.Reboot(False, retries=0) |
| 103 device.adb.WaitForDevice() | 104 device.adb.WaitForDevice() |
| 104 | 105 |
| 105 try: | 106 try: |
| 106 if should_run_phase(_PHASES.WIPE): | 107 if should_run_phase(_PHASES.WIPE): |
| 107 if (options.chrome_specific_wipe or device.build_version_sdk >= | 108 if (options.chrome_specific_wipe or device.IsUserBuild() or |
| 108 version_codes.MARSHMALLOW): | 109 device.build_version_sdk >= version_codes.MARSHMALLOW): |
| 109 run_phase(WipeChromeData) | 110 run_phase(WipeChromeData) |
| 110 else: | 111 else: |
| 111 run_phase(WipeDevice) | 112 run_phase(WipeDevice) |
| 112 | 113 |
| 113 if should_run_phase(_PHASES.PROPERTIES): | 114 if should_run_phase(_PHASES.PROPERTIES): |
| 114 run_phase(SetProperties) | 115 run_phase(SetProperties) |
| 115 | 116 |
| 116 if should_run_phase(_PHASES.FINISH): | 117 if should_run_phase(_PHASES.FINISH): |
| 117 run_phase(FinishProvisioning, reboot=False) | 118 run_phase(FinishProvisioning, reboot=False) |
| 118 | 119 |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 168 (this is telemetry related) | 169 (this is telemetry related) |
| 169 (7) remove anything under /data/local/tmp/ | 170 (7) remove anything under /data/local/tmp/ |
| 170 | 171 |
| 171 Arguments: | 172 Arguments: |
| 172 device: the device to wipe | 173 device: the device to wipe |
| 173 """ | 174 """ |
| 174 if options.skip_wipe: | 175 if options.skip_wipe: |
| 175 return | 176 return |
| 176 | 177 |
| 177 try: | 178 try: |
| 178 device.EnableRoot() | 179 if device.IsUserBuild(): |
| 179 _UninstallIfMatch(device, _CHROME_PACKAGE_REGEX, | 180 _UninstallIfMatch(device, _CHROME_PACKAGE_REGEX, |
| 180 constants.PACKAGE_INFO['chrome_stable'].package) | 181 constants.PACKAGE_INFO['chrome_stable'].package) |
| 181 _WipeUnderDirIfMatch(device, '/data/app-lib/', _CHROME_PACKAGE_REGEX) | 182 device.RunShellCommand('rm -rf %s/*' % device.GetExternalStoragePath(), |
| 182 _WipeUnderDirIfMatch(device, '/data/tombstones/', _TOMBSTONE_REGEX) | 183 check_return=True) |
| 184 device.RunShellCommand('rm -rf /data/local/tmp/*', check_return=True) |
| 185 else: |
| 186 device.EnableRoot() |
| 187 _UninstallIfMatch(device, _CHROME_PACKAGE_REGEX, |
| 188 constants.PACKAGE_INFO['chrome_stable'].package) |
| 189 _WipeUnderDirIfMatch(device, '/data/app-lib/', _CHROME_PACKAGE_REGEX) |
| 190 _WipeUnderDirIfMatch(device, '/data/tombstones/', _TOMBSTONE_REGEX) |
| 183 | 191 |
| 184 _WipeFileOrDir(device, '/data/local.prop') | 192 _WipeFileOrDir(device, '/data/local.prop') |
| 185 _WipeFileOrDir(device, '/data/local/chrome-command-line') | 193 _WipeFileOrDir(device, '/data/local/chrome-command-line') |
| 186 _WipeFileOrDir(device, '/data/local/.config/') | 194 _WipeFileOrDir(device, '/data/local/.config/') |
| 187 _WipeFileOrDir(device, '/data/local/tmp/') | 195 _WipeFileOrDir(device, '/data/local/tmp/') |
| 188 | 196 device.RunShellCommand('rm -rf %s/*' % device.GetExternalStoragePath(), |
| 189 device.RunShellCommand('rm -rf %s/*' % device.GetExternalStoragePath(), | 197 check_return=True) |
| 190 check_return=True) | |
| 191 except device_errors.CommandFailedError: | 198 except device_errors.CommandFailedError: |
| 192 logging.exception('Possible failure while wiping the device. ' | 199 logging.exception('Possible failure while wiping the device. ' |
| 193 'Attempting to continue.') | 200 'Attempting to continue.') |
| 194 | 201 |
| 195 | 202 |
| 196 def WipeDevice(device, options): | 203 def WipeDevice(device, options): |
| 197 """Wipes data from device, keeping only the adb_keys for authorization. | 204 """Wipes data from device, keeping only the adb_keys for authorization. |
| 198 | 205 |
| 199 After wiping data on a device that has been authorized, adb can still | 206 After wiping data on a device that has been authorized, adb can still |
| 200 communicate with the device, but after reboot the device will need to be | 207 communicate with the device, but after reboot the device will need to be |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 243 device.RunShellCommand(['restorecon', constants.ADB_KEYS_FILE], | 250 device.RunShellCommand(['restorecon', constants.ADB_KEYS_FILE], |
| 244 as_root=True, check_return=True) | 251 as_root=True, check_return=True) |
| 245 | 252 |
| 246 | 253 |
| 247 def SetProperties(device, options): | 254 def SetProperties(device, options): |
| 248 try: | 255 try: |
| 249 device.EnableRoot() | 256 device.EnableRoot() |
| 250 except device_errors.CommandFailedError as e: | 257 except device_errors.CommandFailedError as e: |
| 251 logging.warning(str(e)) | 258 logging.warning(str(e)) |
| 252 | 259 |
| 253 _ConfigureLocalProperties(device, options.enable_java_debug) | 260 if not device.IsUserBuild(): |
| 261 _ConfigureLocalProperties(device, options.enable_java_debug) |
| 262 else: |
| 263 logging.warning('Cannot configure properties in user builds.') |
| 254 device_settings.ConfigureContentSettings( | 264 device_settings.ConfigureContentSettings( |
| 255 device, device_settings.DETERMINISTIC_DEVICE_SETTINGS) | 265 device, device_settings.DETERMINISTIC_DEVICE_SETTINGS) |
| 256 if options.disable_location: | 266 if options.disable_location: |
| 257 device_settings.ConfigureContentSettings( | 267 device_settings.ConfigureContentSettings( |
| 258 device, device_settings.DISABLE_LOCATION_SETTINGS) | 268 device, device_settings.DISABLE_LOCATION_SETTINGS) |
| 259 else: | 269 else: |
| 260 device_settings.ConfigureContentSettings( | 270 device_settings.ConfigureContentSettings( |
| 261 device, device_settings.ENABLE_LOCATION_SETTINGS) | 271 device, device_settings.ENABLE_LOCATION_SETTINGS) |
| 262 | 272 |
| 263 if options.disable_mock_location: | 273 if options.disable_mock_location: |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 308 '\n'.join(local_props), as_root=True) | 318 '\n'.join(local_props), as_root=True) |
| 309 # Android will not respect the local props file if it is world writable. | 319 # Android will not respect the local props file if it is world writable. |
| 310 device.RunShellCommand( | 320 device.RunShellCommand( |
| 311 ['chmod', '644', device.LOCAL_PROPERTIES_PATH], | 321 ['chmod', '644', device.LOCAL_PROPERTIES_PATH], |
| 312 as_root=True, check_return=True) | 322 as_root=True, check_return=True) |
| 313 except device_errors.CommandFailedError: | 323 except device_errors.CommandFailedError: |
| 314 logging.exception('Failed to configure local properties.') | 324 logging.exception('Failed to configure local properties.') |
| 315 | 325 |
| 316 | 326 |
| 317 def FinishProvisioning(device, options): | 327 def FinishProvisioning(device, options): |
| 328 # The lockscreen can't be disabled on user builds, so send a keyevent |
| 329 # to unlock it. |
| 330 if device.IsUserBuild(): |
| 331 device.SendKeyEvent(keyevent.KEYCODE_MENU) |
| 332 |
| 318 if options.min_battery_level is not None: | 333 if options.min_battery_level is not None: |
| 319 try: | 334 try: |
| 320 battery = battery_utils.BatteryUtils(device) | 335 battery = battery_utils.BatteryUtils(device) |
| 321 battery.ChargeDeviceToLevel(options.min_battery_level) | 336 battery.ChargeDeviceToLevel(options.min_battery_level) |
| 322 except device_errors.CommandFailedError: | 337 except device_errors.CommandFailedError: |
| 323 logging.exception('Unable to charge device to specified level.') | 338 logging.exception('Unable to charge device to specified level.') |
| 324 | 339 |
| 325 if options.max_battery_temp is not None: | 340 if options.max_battery_temp is not None: |
| 326 try: | 341 try: |
| 327 battery = battery_utils.BatteryUtils(device) | 342 battery = battery_utils.BatteryUtils(device) |
| (...skipping 20 matching lines...) Expand all Loading... |
| 348 tdelta = (correct_time - device_time).seconds | 363 tdelta = (correct_time - device_time).seconds |
| 349 if tdelta <= 1: | 364 if tdelta <= 1: |
| 350 logging.info('Date/time successfully set on %s', device) | 365 logging.info('Date/time successfully set on %s', device) |
| 351 return True | 366 return True |
| 352 else: | 367 else: |
| 353 logging.error('Date mismatch. Device: %s Correct: %s', | 368 logging.error('Date mismatch. Device: %s Correct: %s', |
| 354 device_time.isoformat(), correct_time.isoformat()) | 369 device_time.isoformat(), correct_time.isoformat()) |
| 355 return False | 370 return False |
| 356 | 371 |
| 357 # Sometimes the date is not set correctly on the devices. Retry on failure. | 372 # Sometimes the date is not set correctly on the devices. Retry on failure. |
| 358 if not timeout_retry.WaitFor(_set_and_verify_date, wait_period=1, | 373 if device.IsUserBuild(): |
| 359 max_tries=2): | 374 # TODO(bpastene): Figure out how to set the date & time on user builds. |
| 360 raise device_errors.CommandFailedError( | 375 pass |
| 361 'Failed to set date & time.', device_serial=str(device)) | 376 else: |
| 377 if not timeout_retry.WaitFor( |
| 378 _set_and_verify_date, wait_period=1, max_tries=2): |
| 379 raise device_errors.CommandFailedError( |
| 380 'Failed to set date & time.', device_serial=str(device)) |
| 362 | 381 |
| 363 props = device.RunShellCommand('getprop', check_return=True) | 382 props = device.RunShellCommand('getprop', check_return=True) |
| 364 for prop in props: | 383 for prop in props: |
| 365 logging.info(' %s', prop) | 384 logging.info(' %s', prop) |
| 366 if options.auto_reconnect: | 385 if options.auto_reconnect: |
| 367 _PushAndLaunchAdbReboot(device, options.target) | 386 _PushAndLaunchAdbReboot(device, options.target) |
| 368 | 387 |
| 369 | 388 |
| 370 def _UninstallIfMatch(device, pattern, app_to_keep): | 389 def _UninstallIfMatch(device, pattern, app_to_keep): |
| 371 installed_packages = device.RunShellCommand(['pm', 'list', 'packages']) | 390 installed_packages = device.RunShellCommand(['pm', 'list', 'packages']) |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 492 | 511 |
| 493 run_tests_helper.SetLogLevel(args.verbose) | 512 run_tests_helper.SetLogLevel(args.verbose) |
| 494 | 513 |
| 495 devil_chromium.Initialize() | 514 devil_chromium.Initialize() |
| 496 | 515 |
| 497 return ProvisionDevices(args) | 516 return ProvisionDevices(args) |
| 498 | 517 |
| 499 | 518 |
| 500 if __name__ == '__main__': | 519 if __name__ == '__main__': |
| 501 sys.exit(main()) | 520 sys.exit(main()) |
| OLD | NEW |