1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env vpython3 2*6777b538SAndroid Build Coastguard Worker# 3*6777b538SAndroid Build Coastguard Worker# Copyright 2013 The Chromium Authors 4*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 5*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file. 6*6777b538SAndroid Build Coastguard Worker 7*6777b538SAndroid Build Coastguard Worker"""Provisions Android devices with settings required for bots. 8*6777b538SAndroid Build Coastguard Worker 9*6777b538SAndroid Build Coastguard WorkerUsage: 10*6777b538SAndroid Build Coastguard Worker ./provision_devices.py [-d <device serial number>] 11*6777b538SAndroid Build Coastguard Worker""" 12*6777b538SAndroid Build Coastguard Worker 13*6777b538SAndroid Build Coastguard Workerimport argparse 14*6777b538SAndroid Build Coastguard Workerimport datetime 15*6777b538SAndroid Build Coastguard Workerimport json 16*6777b538SAndroid Build Coastguard Workerimport logging 17*6777b538SAndroid Build Coastguard Workerimport os 18*6777b538SAndroid Build Coastguard Workerimport posixpath 19*6777b538SAndroid Build Coastguard Workerimport re 20*6777b538SAndroid Build Coastguard Workerimport subprocess 21*6777b538SAndroid Build Coastguard Workerimport sys 22*6777b538SAndroid Build Coastguard Workerimport time 23*6777b538SAndroid Build Coastguard Worker 24*6777b538SAndroid Build Coastguard Worker# Import _strptime before threaded code. datetime.datetime.strptime is 25*6777b538SAndroid Build Coastguard Worker# threadsafe except for the initial import of the _strptime module. 26*6777b538SAndroid Build Coastguard Worker# See crbug.com/584730 and https://bugs.python.org/issue7980. 27*6777b538SAndroid Build Coastguard Workerimport _strptime # pylint: disable=unused-import 28*6777b538SAndroid Build Coastguard Worker 29*6777b538SAndroid Build Coastguard Workerimport devil_chromium 30*6777b538SAndroid Build Coastguard Workerfrom devil.android import battery_utils 31*6777b538SAndroid Build Coastguard Workerfrom devil.android import device_denylist 32*6777b538SAndroid Build Coastguard Workerfrom devil.android import device_errors 33*6777b538SAndroid Build Coastguard Workerfrom devil.android import device_temp_file 34*6777b538SAndroid Build Coastguard Workerfrom devil.android import device_utils 35*6777b538SAndroid Build Coastguard Workerfrom devil.android.sdk import keyevent 36*6777b538SAndroid Build Coastguard Workerfrom devil.android.sdk import version_codes 37*6777b538SAndroid Build Coastguard Workerfrom devil.constants import exit_codes 38*6777b538SAndroid Build Coastguard Workerfrom devil.utils import run_tests_helper 39*6777b538SAndroid Build Coastguard Workerfrom devil.utils import timeout_retry 40*6777b538SAndroid Build Coastguard Workerfrom pylib import constants 41*6777b538SAndroid Build Coastguard Workerfrom pylib import device_settings 42*6777b538SAndroid Build Coastguard Workerfrom pylib.constants import host_paths 43*6777b538SAndroid Build Coastguard Worker 44*6777b538SAndroid Build Coastguard Worker_SYSTEM_WEBVIEW_PATHS = ['/system/app/webview', '/system/app/WebViewGoogle'] 45*6777b538SAndroid Build Coastguard Worker_CHROME_PACKAGE_REGEX = re.compile('.*chrom.*') 46*6777b538SAndroid Build Coastguard Worker_TOMBSTONE_REGEX = re.compile('tombstone.*') 47*6777b538SAndroid Build Coastguard Worker 48*6777b538SAndroid Build Coastguard Worker 49*6777b538SAndroid Build Coastguard Workerclass _DEFAULT_TIMEOUTS: 50*6777b538SAndroid Build Coastguard Worker # L can take a while to reboot after a wipe. 51*6777b538SAndroid Build Coastguard Worker LOLLIPOP = 600 52*6777b538SAndroid Build Coastguard Worker PRE_LOLLIPOP = 180 53*6777b538SAndroid Build Coastguard Worker 54*6777b538SAndroid Build Coastguard Worker HELP_TEXT = '{}s on L, {}s on pre-L'.format(LOLLIPOP, PRE_LOLLIPOP) 55*6777b538SAndroid Build Coastguard Worker 56*6777b538SAndroid Build Coastguard Worker 57*6777b538SAndroid Build Coastguard Workerclass _PHASES: 58*6777b538SAndroid Build Coastguard Worker WIPE = 'wipe' 59*6777b538SAndroid Build Coastguard Worker PROPERTIES = 'properties' 60*6777b538SAndroid Build Coastguard Worker FINISH = 'finish' 61*6777b538SAndroid Build Coastguard Worker 62*6777b538SAndroid Build Coastguard Worker ALL = [WIPE, PROPERTIES, FINISH] 63*6777b538SAndroid Build Coastguard Worker 64*6777b538SAndroid Build Coastguard Worker 65*6777b538SAndroid Build Coastguard Workerdef ProvisionDevices(args): 66*6777b538SAndroid Build Coastguard Worker denylist = (device_denylist.Denylist(args.denylist_file) 67*6777b538SAndroid Build Coastguard Worker if args.denylist_file else None) 68*6777b538SAndroid Build Coastguard Worker devices = [ 69*6777b538SAndroid Build Coastguard Worker d for d in device_utils.DeviceUtils.HealthyDevices(denylist) 70*6777b538SAndroid Build Coastguard Worker if not args.emulators or d.is_emulator 71*6777b538SAndroid Build Coastguard Worker ] 72*6777b538SAndroid Build Coastguard Worker if args.device: 73*6777b538SAndroid Build Coastguard Worker devices = [d for d in devices if d == args.device] 74*6777b538SAndroid Build Coastguard Worker if not devices: 75*6777b538SAndroid Build Coastguard Worker raise device_errors.DeviceUnreachableError(args.device) 76*6777b538SAndroid Build Coastguard Worker parallel_devices = device_utils.DeviceUtils.parallel(devices) 77*6777b538SAndroid Build Coastguard Worker if args.emulators: 78*6777b538SAndroid Build Coastguard Worker parallel_devices.pMap(SetProperties, args) 79*6777b538SAndroid Build Coastguard Worker else: 80*6777b538SAndroid Build Coastguard Worker parallel_devices.pMap(ProvisionDevice, denylist, args) 81*6777b538SAndroid Build Coastguard Worker if args.auto_reconnect: 82*6777b538SAndroid Build Coastguard Worker _LaunchHostHeartbeat() 83*6777b538SAndroid Build Coastguard Worker denylisted_devices = denylist.Read() if denylist else [] 84*6777b538SAndroid Build Coastguard Worker if args.output_device_denylist: 85*6777b538SAndroid Build Coastguard Worker with open(args.output_device_denylist, 'w') as f: 86*6777b538SAndroid Build Coastguard Worker json.dump(denylisted_devices, f) 87*6777b538SAndroid Build Coastguard Worker if all(d in denylisted_devices for d in devices): 88*6777b538SAndroid Build Coastguard Worker raise device_errors.NoDevicesError 89*6777b538SAndroid Build Coastguard Worker return 0 90*6777b538SAndroid Build Coastguard Worker 91*6777b538SAndroid Build Coastguard Worker 92*6777b538SAndroid Build Coastguard Workerdef ProvisionDevice(device, denylist, options): 93*6777b538SAndroid Build Coastguard Worker def should_run_phase(phase_name): 94*6777b538SAndroid Build Coastguard Worker return not options.phases or phase_name in options.phases 95*6777b538SAndroid Build Coastguard Worker 96*6777b538SAndroid Build Coastguard Worker def run_phase(phase_func, reboot_timeout, reboot=True): 97*6777b538SAndroid Build Coastguard Worker try: 98*6777b538SAndroid Build Coastguard Worker device.WaitUntilFullyBooted(timeout=reboot_timeout, retries=0) 99*6777b538SAndroid Build Coastguard Worker except device_errors.CommandTimeoutError: 100*6777b538SAndroid Build Coastguard Worker logging.error('Device did not finish booting. Will try to reboot.') 101*6777b538SAndroid Build Coastguard Worker device.Reboot(timeout=reboot_timeout) 102*6777b538SAndroid Build Coastguard Worker phase_func(device, options) 103*6777b538SAndroid Build Coastguard Worker if reboot: 104*6777b538SAndroid Build Coastguard Worker device.Reboot(False, retries=0) 105*6777b538SAndroid Build Coastguard Worker device.adb.WaitForDevice() 106*6777b538SAndroid Build Coastguard Worker 107*6777b538SAndroid Build Coastguard Worker try: 108*6777b538SAndroid Build Coastguard Worker if options.reboot_timeout: 109*6777b538SAndroid Build Coastguard Worker reboot_timeout = options.reboot_timeout 110*6777b538SAndroid Build Coastguard Worker elif device.build_version_sdk >= version_codes.LOLLIPOP: 111*6777b538SAndroid Build Coastguard Worker reboot_timeout = _DEFAULT_TIMEOUTS.LOLLIPOP 112*6777b538SAndroid Build Coastguard Worker else: 113*6777b538SAndroid Build Coastguard Worker reboot_timeout = _DEFAULT_TIMEOUTS.PRE_LOLLIPOP 114*6777b538SAndroid Build Coastguard Worker 115*6777b538SAndroid Build Coastguard Worker if should_run_phase(_PHASES.WIPE): 116*6777b538SAndroid Build Coastguard Worker if (options.chrome_specific_wipe or device.IsUserBuild() or 117*6777b538SAndroid Build Coastguard Worker device.build_version_sdk >= version_codes.MARSHMALLOW): 118*6777b538SAndroid Build Coastguard Worker run_phase(WipeChromeData, reboot_timeout) 119*6777b538SAndroid Build Coastguard Worker else: 120*6777b538SAndroid Build Coastguard Worker run_phase(WipeDevice, reboot_timeout) 121*6777b538SAndroid Build Coastguard Worker 122*6777b538SAndroid Build Coastguard Worker if should_run_phase(_PHASES.PROPERTIES): 123*6777b538SAndroid Build Coastguard Worker run_phase(SetProperties, reboot_timeout) 124*6777b538SAndroid Build Coastguard Worker 125*6777b538SAndroid Build Coastguard Worker if should_run_phase(_PHASES.FINISH): 126*6777b538SAndroid Build Coastguard Worker run_phase(FinishProvisioning, reboot_timeout, reboot=False) 127*6777b538SAndroid Build Coastguard Worker 128*6777b538SAndroid Build Coastguard Worker if options.chrome_specific_wipe: 129*6777b538SAndroid Build Coastguard Worker package = "com.google.android.gms" 130*6777b538SAndroid Build Coastguard Worker version_name = device.GetApplicationVersion(package) 131*6777b538SAndroid Build Coastguard Worker logging.info("Version name for %s is %s", package, version_name) 132*6777b538SAndroid Build Coastguard Worker 133*6777b538SAndroid Build Coastguard Worker CheckExternalStorage(device) 134*6777b538SAndroid Build Coastguard Worker 135*6777b538SAndroid Build Coastguard Worker except device_errors.CommandTimeoutError: 136*6777b538SAndroid Build Coastguard Worker logging.exception('Timed out waiting for device %s. Adding to denylist.', 137*6777b538SAndroid Build Coastguard Worker str(device)) 138*6777b538SAndroid Build Coastguard Worker if denylist: 139*6777b538SAndroid Build Coastguard Worker denylist.Extend([str(device)], reason='provision_timeout') 140*6777b538SAndroid Build Coastguard Worker 141*6777b538SAndroid Build Coastguard Worker except (device_errors.CommandFailedError, 142*6777b538SAndroid Build Coastguard Worker device_errors.DeviceUnreachableError): 143*6777b538SAndroid Build Coastguard Worker logging.exception('Failed to provision device %s. Adding to denylist.', 144*6777b538SAndroid Build Coastguard Worker str(device)) 145*6777b538SAndroid Build Coastguard Worker if denylist: 146*6777b538SAndroid Build Coastguard Worker denylist.Extend([str(device)], reason='provision_failure') 147*6777b538SAndroid Build Coastguard Worker 148*6777b538SAndroid Build Coastguard Worker 149*6777b538SAndroid Build Coastguard Workerdef CheckExternalStorage(device): 150*6777b538SAndroid Build Coastguard Worker """Checks that storage is writable and if not makes it writable. 151*6777b538SAndroid Build Coastguard Worker 152*6777b538SAndroid Build Coastguard Worker Arguments: 153*6777b538SAndroid Build Coastguard Worker device: The device to check. 154*6777b538SAndroid Build Coastguard Worker """ 155*6777b538SAndroid Build Coastguard Worker try: 156*6777b538SAndroid Build Coastguard Worker with device_temp_file.DeviceTempFile( 157*6777b538SAndroid Build Coastguard Worker device.adb, suffix='.sh', dir=device.GetExternalStoragePath()) as f: 158*6777b538SAndroid Build Coastguard Worker device.WriteFile(f.name, 'test') 159*6777b538SAndroid Build Coastguard Worker except device_errors.CommandFailedError: 160*6777b538SAndroid Build Coastguard Worker logging.info('External storage not writable. Remounting / as RW') 161*6777b538SAndroid Build Coastguard Worker device.RunShellCommand(['mount', '-o', 'remount,rw', '/'], 162*6777b538SAndroid Build Coastguard Worker check_return=True, as_root=True) 163*6777b538SAndroid Build Coastguard Worker device.EnableRoot() 164*6777b538SAndroid Build Coastguard Worker with device_temp_file.DeviceTempFile( 165*6777b538SAndroid Build Coastguard Worker device.adb, suffix='.sh', dir=device.GetExternalStoragePath()) as f: 166*6777b538SAndroid Build Coastguard Worker device.WriteFile(f.name, 'test') 167*6777b538SAndroid Build Coastguard Worker 168*6777b538SAndroid Build Coastguard Workerdef WipeChromeData(device, options): 169*6777b538SAndroid Build Coastguard Worker """Wipes chrome specific data from device 170*6777b538SAndroid Build Coastguard Worker 171*6777b538SAndroid Build Coastguard Worker (1) uninstall any app whose name matches *chrom*, except 172*6777b538SAndroid Build Coastguard Worker com.android.chrome, which is the chrome stable package. Doing so also 173*6777b538SAndroid Build Coastguard Worker removes the corresponding dirs under /data/data/ and /data/app/ 174*6777b538SAndroid Build Coastguard Worker (2) remove any dir under /data/app-lib/ whose name matches *chrom* 175*6777b538SAndroid Build Coastguard Worker (3) remove any files under /data/tombstones/ whose name matches "tombstone*" 176*6777b538SAndroid Build Coastguard Worker (4) remove /data/local.prop if there is any 177*6777b538SAndroid Build Coastguard Worker (5) remove /data/local/chrome-command-line if there is any 178*6777b538SAndroid Build Coastguard Worker (6) remove anything under /data/local/.config/ if the dir exists 179*6777b538SAndroid Build Coastguard Worker (this is telemetry related) 180*6777b538SAndroid Build Coastguard Worker (7) remove anything under /data/local/tmp/ 181*6777b538SAndroid Build Coastguard Worker 182*6777b538SAndroid Build Coastguard Worker Arguments: 183*6777b538SAndroid Build Coastguard Worker device: the device to wipe 184*6777b538SAndroid Build Coastguard Worker """ 185*6777b538SAndroid Build Coastguard Worker if options.skip_wipe: 186*6777b538SAndroid Build Coastguard Worker return 187*6777b538SAndroid Build Coastguard Worker 188*6777b538SAndroid Build Coastguard Worker try: 189*6777b538SAndroid Build Coastguard Worker if device.IsUserBuild(): 190*6777b538SAndroid Build Coastguard Worker _UninstallIfMatch(device, _CHROME_PACKAGE_REGEX, 191*6777b538SAndroid Build Coastguard Worker constants.PACKAGE_INFO['chrome_stable'].package) 192*6777b538SAndroid Build Coastguard Worker device.RunShellCommand('rm -rf %s/*' % device.GetExternalStoragePath(), 193*6777b538SAndroid Build Coastguard Worker check_return=True) 194*6777b538SAndroid Build Coastguard Worker device.RunShellCommand('rm -rf /data/local/tmp/*', check_return=True) 195*6777b538SAndroid Build Coastguard Worker else: 196*6777b538SAndroid Build Coastguard Worker device.EnableRoot() 197*6777b538SAndroid Build Coastguard Worker _UninstallIfMatch(device, _CHROME_PACKAGE_REGEX, 198*6777b538SAndroid Build Coastguard Worker constants.PACKAGE_INFO['chrome_stable'].package) 199*6777b538SAndroid Build Coastguard Worker _WipeUnderDirIfMatch(device, '/data/app-lib/', _CHROME_PACKAGE_REGEX) 200*6777b538SAndroid Build Coastguard Worker _WipeUnderDirIfMatch(device, '/data/tombstones/', _TOMBSTONE_REGEX) 201*6777b538SAndroid Build Coastguard Worker 202*6777b538SAndroid Build Coastguard Worker _WipeFileOrDir(device, '/data/local.prop') 203*6777b538SAndroid Build Coastguard Worker _WipeFileOrDir(device, '/data/local/chrome-command-line') 204*6777b538SAndroid Build Coastguard Worker _WipeFileOrDir(device, '/data/local/.config/') 205*6777b538SAndroid Build Coastguard Worker _WipeFileOrDir(device, '/data/local/tmp/') 206*6777b538SAndroid Build Coastguard Worker device.RunShellCommand('rm -rf %s/*' % device.GetExternalStoragePath(), 207*6777b538SAndroid Build Coastguard Worker check_return=True) 208*6777b538SAndroid Build Coastguard Worker except device_errors.CommandFailedError: 209*6777b538SAndroid Build Coastguard Worker logging.exception('Possible failure while wiping the device. ' 210*6777b538SAndroid Build Coastguard Worker 'Attempting to continue.') 211*6777b538SAndroid Build Coastguard Worker 212*6777b538SAndroid Build Coastguard Worker 213*6777b538SAndroid Build Coastguard Workerdef WipeDevice(device, options): 214*6777b538SAndroid Build Coastguard Worker """Wipes data from device, keeping only the adb_keys for authorization. 215*6777b538SAndroid Build Coastguard Worker 216*6777b538SAndroid Build Coastguard Worker After wiping data on a device that has been authorized, adb can still 217*6777b538SAndroid Build Coastguard Worker communicate with the device, but after reboot the device will need to be 218*6777b538SAndroid Build Coastguard Worker re-authorized because the adb keys file is stored in /data/misc/adb/. 219*6777b538SAndroid Build Coastguard Worker Thus, adb_keys file is rewritten so the device does not need to be 220*6777b538SAndroid Build Coastguard Worker re-authorized. 221*6777b538SAndroid Build Coastguard Worker 222*6777b538SAndroid Build Coastguard Worker Arguments: 223*6777b538SAndroid Build Coastguard Worker device: the device to wipe 224*6777b538SAndroid Build Coastguard Worker """ 225*6777b538SAndroid Build Coastguard Worker if options.skip_wipe: 226*6777b538SAndroid Build Coastguard Worker return 227*6777b538SAndroid Build Coastguard Worker 228*6777b538SAndroid Build Coastguard Worker try: 229*6777b538SAndroid Build Coastguard Worker device.EnableRoot() 230*6777b538SAndroid Build Coastguard Worker device_authorized = device.FileExists(constants.ADB_KEYS_FILE) 231*6777b538SAndroid Build Coastguard Worker if device_authorized: 232*6777b538SAndroid Build Coastguard Worker adb_keys = device.ReadFile(constants.ADB_KEYS_FILE, 233*6777b538SAndroid Build Coastguard Worker as_root=True).splitlines() 234*6777b538SAndroid Build Coastguard Worker device.RunShellCommand(['wipe', 'data'], 235*6777b538SAndroid Build Coastguard Worker as_root=True, check_return=True) 236*6777b538SAndroid Build Coastguard Worker device.adb.WaitForDevice() 237*6777b538SAndroid Build Coastguard Worker 238*6777b538SAndroid Build Coastguard Worker if device_authorized: 239*6777b538SAndroid Build Coastguard Worker adb_keys_set = set(adb_keys) 240*6777b538SAndroid Build Coastguard Worker for adb_key_file in options.adb_key_files or []: 241*6777b538SAndroid Build Coastguard Worker try: 242*6777b538SAndroid Build Coastguard Worker with open(adb_key_file, 'r') as f: 243*6777b538SAndroid Build Coastguard Worker adb_public_keys = f.readlines() 244*6777b538SAndroid Build Coastguard Worker adb_keys_set.update(adb_public_keys) 245*6777b538SAndroid Build Coastguard Worker except IOError: 246*6777b538SAndroid Build Coastguard Worker logging.warning('Unable to find adb keys file %s.', adb_key_file) 247*6777b538SAndroid Build Coastguard Worker _WriteAdbKeysFile(device, '\n'.join(adb_keys_set)) 248*6777b538SAndroid Build Coastguard Worker except device_errors.CommandFailedError: 249*6777b538SAndroid Build Coastguard Worker logging.exception('Possible failure while wiping the device. ' 250*6777b538SAndroid Build Coastguard Worker 'Attempting to continue.') 251*6777b538SAndroid Build Coastguard Worker 252*6777b538SAndroid Build Coastguard Worker 253*6777b538SAndroid Build Coastguard Workerdef _WriteAdbKeysFile(device, adb_keys_string): 254*6777b538SAndroid Build Coastguard Worker dir_path = posixpath.dirname(constants.ADB_KEYS_FILE) 255*6777b538SAndroid Build Coastguard Worker device.RunShellCommand(['mkdir', '-p', dir_path], 256*6777b538SAndroid Build Coastguard Worker as_root=True, check_return=True) 257*6777b538SAndroid Build Coastguard Worker device.RunShellCommand(['restorecon', dir_path], 258*6777b538SAndroid Build Coastguard Worker as_root=True, check_return=True) 259*6777b538SAndroid Build Coastguard Worker device.WriteFile(constants.ADB_KEYS_FILE, adb_keys_string, as_root=True) 260*6777b538SAndroid Build Coastguard Worker device.RunShellCommand(['restorecon', constants.ADB_KEYS_FILE], 261*6777b538SAndroid Build Coastguard Worker as_root=True, check_return=True) 262*6777b538SAndroid Build Coastguard Worker 263*6777b538SAndroid Build Coastguard Worker 264*6777b538SAndroid Build Coastguard Workerdef SetProperties(device, options): 265*6777b538SAndroid Build Coastguard Worker try: 266*6777b538SAndroid Build Coastguard Worker device.EnableRoot() 267*6777b538SAndroid Build Coastguard Worker except device_errors.CommandFailedError as e: 268*6777b538SAndroid Build Coastguard Worker logging.warning(str(e)) 269*6777b538SAndroid Build Coastguard Worker 270*6777b538SAndroid Build Coastguard Worker if not device.IsUserBuild(): 271*6777b538SAndroid Build Coastguard Worker _ConfigureLocalProperties(device, options.enable_java_debug) 272*6777b538SAndroid Build Coastguard Worker else: 273*6777b538SAndroid Build Coastguard Worker logging.warning('Cannot configure properties in user builds.') 274*6777b538SAndroid Build Coastguard Worker device_settings.ConfigureContentSettings( 275*6777b538SAndroid Build Coastguard Worker device, device_settings.DETERMINISTIC_DEVICE_SETTINGS) 276*6777b538SAndroid Build Coastguard Worker if options.disable_location: 277*6777b538SAndroid Build Coastguard Worker device_settings.ConfigureContentSettings( 278*6777b538SAndroid Build Coastguard Worker device, device_settings.DISABLE_LOCATION_SETTINGS) 279*6777b538SAndroid Build Coastguard Worker else: 280*6777b538SAndroid Build Coastguard Worker device_settings.ConfigureContentSettings( 281*6777b538SAndroid Build Coastguard Worker device, device_settings.ENABLE_LOCATION_SETTINGS) 282*6777b538SAndroid Build Coastguard Worker 283*6777b538SAndroid Build Coastguard Worker if options.disable_mock_location: 284*6777b538SAndroid Build Coastguard Worker device_settings.ConfigureContentSettings( 285*6777b538SAndroid Build Coastguard Worker device, device_settings.DISABLE_MOCK_LOCATION_SETTINGS) 286*6777b538SAndroid Build Coastguard Worker else: 287*6777b538SAndroid Build Coastguard Worker device_settings.ConfigureContentSettings( 288*6777b538SAndroid Build Coastguard Worker device, device_settings.ENABLE_MOCK_LOCATION_SETTINGS) 289*6777b538SAndroid Build Coastguard Worker 290*6777b538SAndroid Build Coastguard Worker device_settings.SetLockScreenSettings(device) 291*6777b538SAndroid Build Coastguard Worker if options.disable_network: 292*6777b538SAndroid Build Coastguard Worker device_settings.ConfigureContentSettings( 293*6777b538SAndroid Build Coastguard Worker device, device_settings.NETWORK_DISABLED_SETTINGS) 294*6777b538SAndroid Build Coastguard Worker if device.build_version_sdk >= version_codes.MARSHMALLOW: 295*6777b538SAndroid Build Coastguard Worker # Ensure that NFC is also switched off. 296*6777b538SAndroid Build Coastguard Worker device.RunShellCommand(['svc', 'nfc', 'disable'], 297*6777b538SAndroid Build Coastguard Worker as_root=True, check_return=True) 298*6777b538SAndroid Build Coastguard Worker 299*6777b538SAndroid Build Coastguard Worker if options.disable_system_chrome: 300*6777b538SAndroid Build Coastguard Worker # The system chrome version on the device interferes with some tests. 301*6777b538SAndroid Build Coastguard Worker device.RunShellCommand(['pm', 'disable', 'com.android.chrome'], 302*6777b538SAndroid Build Coastguard Worker check_return=True) 303*6777b538SAndroid Build Coastguard Worker 304*6777b538SAndroid Build Coastguard Worker if options.remove_system_webview: 305*6777b538SAndroid Build Coastguard Worker if any(device.PathExists(p) for p in _SYSTEM_WEBVIEW_PATHS): 306*6777b538SAndroid Build Coastguard Worker logging.info('System WebView exists and needs to be removed') 307*6777b538SAndroid Build Coastguard Worker if device.HasRoot(): 308*6777b538SAndroid Build Coastguard Worker # Disabled Marshmallow's Verity security feature 309*6777b538SAndroid Build Coastguard Worker if device.build_version_sdk >= version_codes.MARSHMALLOW: 310*6777b538SAndroid Build Coastguard Worker device.adb.DisableVerity() 311*6777b538SAndroid Build Coastguard Worker device.Reboot() 312*6777b538SAndroid Build Coastguard Worker device.WaitUntilFullyBooted() 313*6777b538SAndroid Build Coastguard Worker device.EnableRoot() 314*6777b538SAndroid Build Coastguard Worker 315*6777b538SAndroid Build Coastguard Worker # This is required, e.g., to replace the system webview on a device. 316*6777b538SAndroid Build Coastguard Worker device.adb.Remount() 317*6777b538SAndroid Build Coastguard Worker device.RunShellCommand(['stop'], check_return=True) 318*6777b538SAndroid Build Coastguard Worker device.RunShellCommand(['rm', '-rf'] + _SYSTEM_WEBVIEW_PATHS, 319*6777b538SAndroid Build Coastguard Worker check_return=True) 320*6777b538SAndroid Build Coastguard Worker device.RunShellCommand(['start'], check_return=True) 321*6777b538SAndroid Build Coastguard Worker else: 322*6777b538SAndroid Build Coastguard Worker logging.warning('Cannot remove system webview from a non-rooted device') 323*6777b538SAndroid Build Coastguard Worker else: 324*6777b538SAndroid Build Coastguard Worker logging.info('System WebView already removed') 325*6777b538SAndroid Build Coastguard Worker 326*6777b538SAndroid Build Coastguard Worker # Some device types can momentarily disappear after setting properties. 327*6777b538SAndroid Build Coastguard Worker device.adb.WaitForDevice() 328*6777b538SAndroid Build Coastguard Worker 329*6777b538SAndroid Build Coastguard Worker 330*6777b538SAndroid Build Coastguard Workerdef _ConfigureLocalProperties(device, java_debug=True): 331*6777b538SAndroid Build Coastguard Worker """Set standard readonly testing device properties prior to reboot.""" 332*6777b538SAndroid Build Coastguard Worker local_props = [ 333*6777b538SAndroid Build Coastguard Worker 'persist.sys.usb.config=adb', 334*6777b538SAndroid Build Coastguard Worker 'ro.monkey=1', 335*6777b538SAndroid Build Coastguard Worker 'ro.test_harness=1', 336*6777b538SAndroid Build Coastguard Worker 'ro.audio.silent=1', 337*6777b538SAndroid Build Coastguard Worker 'ro.setupwizard.mode=DISABLED', 338*6777b538SAndroid Build Coastguard Worker ] 339*6777b538SAndroid Build Coastguard Worker if java_debug: 340*6777b538SAndroid Build Coastguard Worker local_props.append( 341*6777b538SAndroid Build Coastguard Worker '%s=all' % device_utils.DeviceUtils.JAVA_ASSERT_PROPERTY) 342*6777b538SAndroid Build Coastguard Worker local_props.append('debug.checkjni=1') 343*6777b538SAndroid Build Coastguard Worker try: 344*6777b538SAndroid Build Coastguard Worker device.WriteFile( 345*6777b538SAndroid Build Coastguard Worker device.LOCAL_PROPERTIES_PATH, 346*6777b538SAndroid Build Coastguard Worker '\n'.join(local_props), as_root=True) 347*6777b538SAndroid Build Coastguard Worker # Android will not respect the local props file if it is world writable. 348*6777b538SAndroid Build Coastguard Worker device.RunShellCommand( 349*6777b538SAndroid Build Coastguard Worker ['chmod', '644', device.LOCAL_PROPERTIES_PATH], 350*6777b538SAndroid Build Coastguard Worker as_root=True, check_return=True) 351*6777b538SAndroid Build Coastguard Worker except device_errors.CommandFailedError: 352*6777b538SAndroid Build Coastguard Worker logging.exception('Failed to configure local properties.') 353*6777b538SAndroid Build Coastguard Worker 354*6777b538SAndroid Build Coastguard Worker 355*6777b538SAndroid Build Coastguard Workerdef FinishProvisioning(device, options): 356*6777b538SAndroid Build Coastguard Worker # The lockscreen can't be disabled on user builds, so send a keyevent 357*6777b538SAndroid Build Coastguard Worker # to unlock it. 358*6777b538SAndroid Build Coastguard Worker if device.IsUserBuild(): 359*6777b538SAndroid Build Coastguard Worker device.SendKeyEvent(keyevent.KEYCODE_MENU) 360*6777b538SAndroid Build Coastguard Worker 361*6777b538SAndroid Build Coastguard Worker if options.min_battery_level is not None: 362*6777b538SAndroid Build Coastguard Worker battery = battery_utils.BatteryUtils(device) 363*6777b538SAndroid Build Coastguard Worker try: 364*6777b538SAndroid Build Coastguard Worker battery.ChargeDeviceToLevel(options.min_battery_level) 365*6777b538SAndroid Build Coastguard Worker except device_errors.DeviceChargingError: 366*6777b538SAndroid Build Coastguard Worker device.Reboot() 367*6777b538SAndroid Build Coastguard Worker battery.ChargeDeviceToLevel(options.min_battery_level) 368*6777b538SAndroid Build Coastguard Worker 369*6777b538SAndroid Build Coastguard Worker if options.max_battery_temp is not None: 370*6777b538SAndroid Build Coastguard Worker try: 371*6777b538SAndroid Build Coastguard Worker battery = battery_utils.BatteryUtils(device) 372*6777b538SAndroid Build Coastguard Worker battery.LetBatteryCoolToTemperature(options.max_battery_temp) 373*6777b538SAndroid Build Coastguard Worker except device_errors.CommandFailedError: 374*6777b538SAndroid Build Coastguard Worker logging.exception('Unable to let battery cool to specified temperature.') 375*6777b538SAndroid Build Coastguard Worker 376*6777b538SAndroid Build Coastguard Worker def _set_and_verify_date(): 377*6777b538SAndroid Build Coastguard Worker if device.build_version_sdk >= version_codes.MARSHMALLOW: 378*6777b538SAndroid Build Coastguard Worker date_format = '%m%d%H%M%Y.%S' 379*6777b538SAndroid Build Coastguard Worker set_date_command = ['date', '-u'] 380*6777b538SAndroid Build Coastguard Worker get_date_command = ['date', '-u'] 381*6777b538SAndroid Build Coastguard Worker else: 382*6777b538SAndroid Build Coastguard Worker date_format = '%Y%m%d.%H%M%S' 383*6777b538SAndroid Build Coastguard Worker set_date_command = ['date', '-s'] 384*6777b538SAndroid Build Coastguard Worker get_date_command = ['date'] 385*6777b538SAndroid Build Coastguard Worker 386*6777b538SAndroid Build Coastguard Worker # TODO(jbudorick): This is wrong on pre-M devices -- get/set are 387*6777b538SAndroid Build Coastguard Worker # dealing in local time, but we're setting based on GMT. 388*6777b538SAndroid Build Coastguard Worker strgmtime = time.strftime(date_format, time.gmtime()) 389*6777b538SAndroid Build Coastguard Worker set_date_command.append(strgmtime) 390*6777b538SAndroid Build Coastguard Worker device.RunShellCommand(set_date_command, as_root=True, check_return=True) 391*6777b538SAndroid Build Coastguard Worker 392*6777b538SAndroid Build Coastguard Worker get_date_command.append('+"%Y%m%d.%H%M%S"') 393*6777b538SAndroid Build Coastguard Worker device_time = device.RunShellCommand( 394*6777b538SAndroid Build Coastguard Worker get_date_command, as_root=True, single_line=True).replace('"', '') 395*6777b538SAndroid Build Coastguard Worker device_time = datetime.datetime.strptime(device_time, "%Y%m%d.%H%M%S") 396*6777b538SAndroid Build Coastguard Worker correct_time = datetime.datetime.strptime(strgmtime, date_format) 397*6777b538SAndroid Build Coastguard Worker tdelta = abs(correct_time - device_time).seconds 398*6777b538SAndroid Build Coastguard Worker if tdelta <= 1: 399*6777b538SAndroid Build Coastguard Worker logging.info('Date/time successfully set on %s', device) 400*6777b538SAndroid Build Coastguard Worker return True 401*6777b538SAndroid Build Coastguard Worker logging.error('Date mismatch. Device: %s Correct: %s', 402*6777b538SAndroid Build Coastguard Worker device_time.isoformat(), correct_time.isoformat()) 403*6777b538SAndroid Build Coastguard Worker return False 404*6777b538SAndroid Build Coastguard Worker 405*6777b538SAndroid Build Coastguard Worker # Sometimes the date is not set correctly on the devices. Retry on failure. 406*6777b538SAndroid Build Coastguard Worker if device.IsUserBuild(): 407*6777b538SAndroid Build Coastguard Worker # TODO(bpastene): Figure out how to set the date & time on user builds. 408*6777b538SAndroid Build Coastguard Worker pass 409*6777b538SAndroid Build Coastguard Worker else: 410*6777b538SAndroid Build Coastguard Worker if not timeout_retry.WaitFor( 411*6777b538SAndroid Build Coastguard Worker _set_and_verify_date, wait_period=1, max_tries=2): 412*6777b538SAndroid Build Coastguard Worker raise device_errors.CommandFailedError( 413*6777b538SAndroid Build Coastguard Worker 'Failed to set date & time.', device_serial=str(device)) 414*6777b538SAndroid Build Coastguard Worker 415*6777b538SAndroid Build Coastguard Worker props = device.RunShellCommand('getprop', check_return=True) 416*6777b538SAndroid Build Coastguard Worker for prop in props: 417*6777b538SAndroid Build Coastguard Worker logging.info(' %s', prop) 418*6777b538SAndroid Build Coastguard Worker if options.auto_reconnect: 419*6777b538SAndroid Build Coastguard Worker _PushAndLaunchAdbReboot(device, options.target) 420*6777b538SAndroid Build Coastguard Worker 421*6777b538SAndroid Build Coastguard Worker 422*6777b538SAndroid Build Coastguard Workerdef _UninstallIfMatch(device, pattern, app_to_keep): 423*6777b538SAndroid Build Coastguard Worker installed_packages = device.RunShellCommand(['pm', 'list', 'packages']) 424*6777b538SAndroid Build Coastguard Worker installed_system_packages = [ 425*6777b538SAndroid Build Coastguard Worker pkg.split(':')[1] for pkg in device.RunShellCommand(['pm', 'list', 426*6777b538SAndroid Build Coastguard Worker 'packages', '-s'])] 427*6777b538SAndroid Build Coastguard Worker for package_output in installed_packages: 428*6777b538SAndroid Build Coastguard Worker package = package_output.split(":")[1] 429*6777b538SAndroid Build Coastguard Worker if pattern.match(package) and not package == app_to_keep: 430*6777b538SAndroid Build Coastguard Worker if not device.IsUserBuild() or package not in installed_system_packages: 431*6777b538SAndroid Build Coastguard Worker device.Uninstall(package) 432*6777b538SAndroid Build Coastguard Worker 433*6777b538SAndroid Build Coastguard Worker 434*6777b538SAndroid Build Coastguard Workerdef _WipeUnderDirIfMatch(device, path, pattern): 435*6777b538SAndroid Build Coastguard Worker for filename in device.ListDirectory(path): 436*6777b538SAndroid Build Coastguard Worker if pattern.match(filename): 437*6777b538SAndroid Build Coastguard Worker _WipeFileOrDir(device, posixpath.join(path, filename)) 438*6777b538SAndroid Build Coastguard Worker 439*6777b538SAndroid Build Coastguard Worker 440*6777b538SAndroid Build Coastguard Workerdef _WipeFileOrDir(device, path): 441*6777b538SAndroid Build Coastguard Worker if device.PathExists(path): 442*6777b538SAndroid Build Coastguard Worker device.RunShellCommand(['rm', '-rf', path], check_return=True) 443*6777b538SAndroid Build Coastguard Worker 444*6777b538SAndroid Build Coastguard Worker 445*6777b538SAndroid Build Coastguard Workerdef _PushAndLaunchAdbReboot(device, target): 446*6777b538SAndroid Build Coastguard Worker """Pushes and launches the adb_reboot binary on the device. 447*6777b538SAndroid Build Coastguard Worker 448*6777b538SAndroid Build Coastguard Worker Arguments: 449*6777b538SAndroid Build Coastguard Worker device: The DeviceUtils instance for the device to which the adb_reboot 450*6777b538SAndroid Build Coastguard Worker binary should be pushed. 451*6777b538SAndroid Build Coastguard Worker target: The build target (example, Debug or Release) which helps in 452*6777b538SAndroid Build Coastguard Worker locating the adb_reboot binary. 453*6777b538SAndroid Build Coastguard Worker """ 454*6777b538SAndroid Build Coastguard Worker logging.info('Will push and launch adb_reboot on %s', str(device)) 455*6777b538SAndroid Build Coastguard Worker # Kill if adb_reboot is already running. 456*6777b538SAndroid Build Coastguard Worker device.KillAll('adb_reboot', blocking=True, timeout=2, quiet=True) 457*6777b538SAndroid Build Coastguard Worker # Push adb_reboot 458*6777b538SAndroid Build Coastguard Worker logging.info(' Pushing adb_reboot ...') 459*6777b538SAndroid Build Coastguard Worker adb_reboot = os.path.join(host_paths.DIR_SOURCE_ROOT, 460*6777b538SAndroid Build Coastguard Worker 'out/%s/adb_reboot' % target) 461*6777b538SAndroid Build Coastguard Worker device.PushChangedFiles([(adb_reboot, '/data/local/tmp/')]) 462*6777b538SAndroid Build Coastguard Worker # Launch adb_reboot 463*6777b538SAndroid Build Coastguard Worker logging.info(' Launching adb_reboot ...') 464*6777b538SAndroid Build Coastguard Worker device.RunShellCommand( 465*6777b538SAndroid Build Coastguard Worker ['/data/local/tmp/adb_reboot'], 466*6777b538SAndroid Build Coastguard Worker check_return=True) 467*6777b538SAndroid Build Coastguard Worker 468*6777b538SAndroid Build Coastguard Worker 469*6777b538SAndroid Build Coastguard Workerdef _LaunchHostHeartbeat(): 470*6777b538SAndroid Build Coastguard Worker # Kill if existing host_heartbeat 471*6777b538SAndroid Build Coastguard Worker KillHostHeartbeat() 472*6777b538SAndroid Build Coastguard Worker # Launch a new host_heartbeat 473*6777b538SAndroid Build Coastguard Worker logging.info('Spawning host heartbeat...') 474*6777b538SAndroid Build Coastguard Worker subprocess.Popen([os.path.join(host_paths.DIR_SOURCE_ROOT, 475*6777b538SAndroid Build Coastguard Worker 'build/android/host_heartbeat.py')]) 476*6777b538SAndroid Build Coastguard Worker 477*6777b538SAndroid Build Coastguard Workerdef KillHostHeartbeat(): 478*6777b538SAndroid Build Coastguard Worker ps = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE) 479*6777b538SAndroid Build Coastguard Worker stdout, _ = ps.communicate() 480*6777b538SAndroid Build Coastguard Worker matches = re.findall('\\n.*host_heartbeat.*', stdout) 481*6777b538SAndroid Build Coastguard Worker for match in matches: 482*6777b538SAndroid Build Coastguard Worker logging.info('An instance of host heart beart running... will kill') 483*6777b538SAndroid Build Coastguard Worker pid = re.findall(r'(\S+)', match)[1] 484*6777b538SAndroid Build Coastguard Worker subprocess.call(['kill', str(pid)]) 485*6777b538SAndroid Build Coastguard Worker 486*6777b538SAndroid Build Coastguard Workerdef main(): 487*6777b538SAndroid Build Coastguard Worker # Recommended options on perf bots: 488*6777b538SAndroid Build Coastguard Worker # --disable-network 489*6777b538SAndroid Build Coastguard Worker # TODO(tonyg): We eventually want network on. However, currently radios 490*6777b538SAndroid Build Coastguard Worker # can cause perfbots to drain faster than they charge. 491*6777b538SAndroid Build Coastguard Worker # --min-battery-level 95 492*6777b538SAndroid Build Coastguard Worker # Some perf bots run benchmarks with USB charging disabled which leads 493*6777b538SAndroid Build Coastguard Worker # to gradual draining of the battery. We must wait for a full charge 494*6777b538SAndroid Build Coastguard Worker # before starting a run in order to keep the devices online. 495*6777b538SAndroid Build Coastguard Worker 496*6777b538SAndroid Build Coastguard Worker parser = argparse.ArgumentParser( 497*6777b538SAndroid Build Coastguard Worker description='Provision Android devices with settings required for bots.') 498*6777b538SAndroid Build Coastguard Worker parser.add_argument('-d', '--device', metavar='SERIAL', 499*6777b538SAndroid Build Coastguard Worker help='the serial number of the device to be provisioned' 500*6777b538SAndroid Build Coastguard Worker ' (the default is to provision all devices attached)') 501*6777b538SAndroid Build Coastguard Worker parser.add_argument('--adb-path', 502*6777b538SAndroid Build Coastguard Worker help='Absolute path to the adb binary to use.') 503*6777b538SAndroid Build Coastguard Worker parser.add_argument('--denylist-file', help='Device denylist JSON file.') 504*6777b538SAndroid Build Coastguard Worker parser.add_argument('--phase', action='append', choices=_PHASES.ALL, 505*6777b538SAndroid Build Coastguard Worker dest='phases', 506*6777b538SAndroid Build Coastguard Worker help='Phases of provisioning to run. ' 507*6777b538SAndroid Build Coastguard Worker '(If omitted, all phases will be run.)') 508*6777b538SAndroid Build Coastguard Worker parser.add_argument('--skip-wipe', action='store_true', default=False, 509*6777b538SAndroid Build Coastguard Worker help="don't wipe device data during provisioning") 510*6777b538SAndroid Build Coastguard Worker parser.add_argument('--reboot-timeout', metavar='SECS', type=int, 511*6777b538SAndroid Build Coastguard Worker help='when wiping the device, max number of seconds to' 512*6777b538SAndroid Build Coastguard Worker ' wait after each reboot ' 513*6777b538SAndroid Build Coastguard Worker '(default: %s)' % _DEFAULT_TIMEOUTS.HELP_TEXT) 514*6777b538SAndroid Build Coastguard Worker parser.add_argument('--min-battery-level', type=int, metavar='NUM', 515*6777b538SAndroid Build Coastguard Worker help='wait for the device to reach this minimum battery' 516*6777b538SAndroid Build Coastguard Worker ' level before trying to continue') 517*6777b538SAndroid Build Coastguard Worker parser.add_argument('--disable-location', action='store_true', 518*6777b538SAndroid Build Coastguard Worker help='disable Google location services on devices') 519*6777b538SAndroid Build Coastguard Worker parser.add_argument('--disable-mock-location', action='store_true', 520*6777b538SAndroid Build Coastguard Worker default=False, help='Set ALLOW_MOCK_LOCATION to false') 521*6777b538SAndroid Build Coastguard Worker parser.add_argument('--disable-network', action='store_true', 522*6777b538SAndroid Build Coastguard Worker help='disable network access on devices') 523*6777b538SAndroid Build Coastguard Worker parser.add_argument('--disable-java-debug', action='store_false', 524*6777b538SAndroid Build Coastguard Worker dest='enable_java_debug', default=True, 525*6777b538SAndroid Build Coastguard Worker help='disable Java property asserts and JNI checking') 526*6777b538SAndroid Build Coastguard Worker parser.add_argument('--disable-system-chrome', action='store_true', 527*6777b538SAndroid Build Coastguard Worker help='Disable the system chrome from devices.') 528*6777b538SAndroid Build Coastguard Worker parser.add_argument('--remove-system-webview', action='store_true', 529*6777b538SAndroid Build Coastguard Worker help='Remove the system webview from devices.') 530*6777b538SAndroid Build Coastguard Worker parser.add_argument('-t', '--target', default='Debug', 531*6777b538SAndroid Build Coastguard Worker help='the build target (default: %(default)s)') 532*6777b538SAndroid Build Coastguard Worker parser.add_argument('-r', '--auto-reconnect', action='store_true', 533*6777b538SAndroid Build Coastguard Worker help='push binary which will reboot the device on adb' 534*6777b538SAndroid Build Coastguard Worker ' disconnections') 535*6777b538SAndroid Build Coastguard Worker parser.add_argument('--adb-key-files', type=str, nargs='+', 536*6777b538SAndroid Build Coastguard Worker help='list of adb keys to push to device') 537*6777b538SAndroid Build Coastguard Worker parser.add_argument('-v', '--verbose', action='count', default=1, 538*6777b538SAndroid Build Coastguard Worker help='Log more information.') 539*6777b538SAndroid Build Coastguard Worker parser.add_argument('--max-battery-temp', type=int, metavar='NUM', 540*6777b538SAndroid Build Coastguard Worker help='Wait for the battery to have this temp or lower.') 541*6777b538SAndroid Build Coastguard Worker parser.add_argument('--output-device-denylist', 542*6777b538SAndroid Build Coastguard Worker help='Json file to output the device denylist.') 543*6777b538SAndroid Build Coastguard Worker parser.add_argument('--chrome-specific-wipe', action='store_true', 544*6777b538SAndroid Build Coastguard Worker help='only wipe chrome specific data during provisioning') 545*6777b538SAndroid Build Coastguard Worker parser.add_argument('--emulators', action='store_true', 546*6777b538SAndroid Build Coastguard Worker help='provision only emulators and ignore usb devices') 547*6777b538SAndroid Build Coastguard Worker args = parser.parse_args() 548*6777b538SAndroid Build Coastguard Worker constants.SetBuildType(args.target) 549*6777b538SAndroid Build Coastguard Worker 550*6777b538SAndroid Build Coastguard Worker run_tests_helper.SetLogLevel(args.verbose) 551*6777b538SAndroid Build Coastguard Worker 552*6777b538SAndroid Build Coastguard Worker devil_chromium.Initialize(adb_path=args.adb_path) 553*6777b538SAndroid Build Coastguard Worker 554*6777b538SAndroid Build Coastguard Worker try: 555*6777b538SAndroid Build Coastguard Worker return ProvisionDevices(args) 556*6777b538SAndroid Build Coastguard Worker except (device_errors.DeviceUnreachableError, device_errors.NoDevicesError): 557*6777b538SAndroid Build Coastguard Worker logging.exception('Unable to provision local devices.') 558*6777b538SAndroid Build Coastguard Worker return exit_codes.INFRA 559*6777b538SAndroid Build Coastguard Worker 560*6777b538SAndroid Build Coastguard Worker 561*6777b538SAndroid Build Coastguard Workerif __name__ == '__main__': 562*6777b538SAndroid Build Coastguard Worker sys.exit(main()) 563