| 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 logging | 14 import logging |
| 15 import os | 15 import os |
| 16 import posixpath |
| 16 import re | 17 import re |
| 17 import subprocess | 18 import subprocess |
| 18 import sys | 19 import sys |
| 19 import time | 20 import time |
| 20 | 21 |
| 21 from pylib import android_commands | 22 from pylib import android_commands |
| 22 from pylib import constants | 23 from pylib import constants |
| 23 from pylib import device_settings | 24 from pylib import device_settings |
| 24 from pylib.device import device_blacklist | 25 from pylib.device import device_blacklist |
| 25 from pylib.device import device_errors | 26 from pylib.device import device_errors |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 108 '\n'.join(local_props), as_root=True) | 109 '\n'.join(local_props), as_root=True) |
| 109 # Android will not respect the local props file if it is world writable. | 110 # Android will not respect the local props file if it is world writable. |
| 110 device.RunShellCommand( | 111 device.RunShellCommand( |
| 111 ['chmod', '644', constants.DEVICE_LOCAL_PROPERTIES_PATH], | 112 ['chmod', '644', constants.DEVICE_LOCAL_PROPERTIES_PATH], |
| 112 as_root=True) | 113 as_root=True) |
| 113 except device_errors.CommandFailedError as e: | 114 except device_errors.CommandFailedError as e: |
| 114 logging.warning(str(e)) | 115 logging.warning(str(e)) |
| 115 | 116 |
| 116 # LOCAL_PROPERTIES_PATH = '/data/local.prop' | 117 # LOCAL_PROPERTIES_PATH = '/data/local.prop' |
| 117 | 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) |
| 118 | 126 |
| 119 def WipeDeviceData(device): | 127 |
| 128 def WipeDeviceData(device, options): |
| 120 """Wipes data from device, keeping only the adb_keys for authorization. | 129 """Wipes data from device, keeping only the adb_keys for authorization. |
| 121 | 130 |
| 122 After wiping data on a device that has been authorized, adb can still | 131 After wiping data on a device that has been authorized, adb can still |
| 123 communicate with the device, but after reboot the device will need to be | 132 communicate with the device, but after reboot the device will need to be |
| 124 re-authorized because the adb keys file is stored in /data/misc/adb/. | 133 re-authorized because the adb keys file is stored in /data/misc/adb/. |
| 125 Thus, adb_keys file is rewritten so the device does not need to be | 134 Thus, adb_keys file is rewritten so the device does not need to be |
| 126 re-authorized. | 135 re-authorized. |
| 127 | 136 |
| 128 Arguments: | 137 Arguments: |
| 129 device: the device to wipe | 138 device: the device to wipe |
| 130 """ | 139 """ |
| 131 device_authorized = device.FileExists(constants.ADB_KEYS_FILE) | 140 device_authorized = device.FileExists(constants.ADB_KEYS_FILE) |
| 132 if device_authorized: | 141 if device_authorized: |
| 133 adb_keys = device.ReadFile(constants.ADB_KEYS_FILE, as_root=True) | 142 adb_keys = device.ReadFile(constants.ADB_KEYS_FILE, |
| 143 as_root=True).splitlines() |
| 134 device.RunShellCommand('wipe data', as_root=True) | 144 device.RunShellCommand('wipe data', as_root=True) |
| 135 if device_authorized: | 145 if device_authorized: |
| 136 path_list = constants.ADB_KEYS_FILE.split('/') | 146 adb_keys_set = set(adb_keys) |
| 137 dir_path = '/'.join(path_list[:len(path_list)-1]) | 147 for adb_key_file in options.adb_key_files or []: |
| 138 device.RunShellCommand('mkdir -p %s' % dir_path, as_root=True) | 148 try: |
| 139 device.RunShellCommand('restorecon %s' % dir_path, as_root=True) | 149 with open(adb_key_file, 'r') as f: |
| 140 device.WriteFile(constants.ADB_KEYS_FILE, adb_keys, as_root=True) | 150 adb_public_keys = f.readlines() |
| 141 device.RunShellCommand('restorecon %s' % constants.ADB_KEYS_FILE, | 151 adb_keys_set.update(adb_public_keys) |
| 142 as_root=True) | 152 except IOError: |
| 153 logging.warning('Unable to find adb keys file %s.' % adb_key_file) |
| 154 WriteAdbKeysFile(device, '\n'.join(adb_keys_set)) |
| 143 | 155 |
| 144 | 156 |
| 145 def WipeDeviceIfPossible(device, timeout): | 157 def WipeDeviceIfPossible(device, timeout, options): |
| 146 try: | 158 try: |
| 147 device.EnableRoot() | 159 device.EnableRoot() |
| 148 WipeDeviceData(device) | 160 WipeDeviceData(device, options) |
| 149 device.Reboot(True, timeout=timeout, retries=0) | 161 device.Reboot(True, timeout=timeout, retries=0) |
| 150 except (errors.DeviceUnresponsiveError, device_errors.CommandFailedError): | 162 except (errors.DeviceUnresponsiveError, device_errors.CommandFailedError): |
| 151 pass | 163 pass |
| 152 | 164 |
| 153 | 165 |
| 154 def ChargeDeviceToLevel(device, level): | 166 def ChargeDeviceToLevel(device, level): |
| 155 def device_charged(): | 167 def device_charged(): |
| 156 battery_level = device.GetBatteryInfo().get('level') | 168 battery_level = device.GetBatteryInfo().get('level') |
| 157 if battery_level is None: | 169 if battery_level is None: |
| 158 logging.warning('Unable to find current battery level.') | 170 logging.warning('Unable to find current battery level.') |
| (...skipping 10 matching lines...) Expand all Loading... |
| 169 if options.reboot_timeout: | 181 if options.reboot_timeout: |
| 170 reboot_timeout = options.reboot_timeout | 182 reboot_timeout = options.reboot_timeout |
| 171 elif (device.build_version_sdk >= | 183 elif (device.build_version_sdk >= |
| 172 constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP): | 184 constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP): |
| 173 reboot_timeout = _DEFAULT_TIMEOUTS.LOLLIPOP | 185 reboot_timeout = _DEFAULT_TIMEOUTS.LOLLIPOP |
| 174 else: | 186 else: |
| 175 reboot_timeout = _DEFAULT_TIMEOUTS.PRE_LOLLIPOP | 187 reboot_timeout = _DEFAULT_TIMEOUTS.PRE_LOLLIPOP |
| 176 | 188 |
| 177 try: | 189 try: |
| 178 if not options.skip_wipe: | 190 if not options.skip_wipe: |
| 179 WipeDeviceIfPossible(device, reboot_timeout) | 191 WipeDeviceIfPossible(device, reboot_timeout, options) |
| 180 try: | 192 try: |
| 181 device.EnableRoot() | 193 device.EnableRoot() |
| 182 except device_errors.CommandFailedError as e: | 194 except device_errors.CommandFailedError as e: |
| 183 logging.warning(str(e)) | 195 logging.warning(str(e)) |
| 184 _ConfigureLocalProperties(device, options.enable_java_debug) | 196 _ConfigureLocalProperties(device, options.enable_java_debug) |
| 185 device_settings.ConfigureContentSettings( | 197 device_settings.ConfigureContentSettings( |
| 186 device, device_settings.DETERMINISTIC_DEVICE_SETTINGS) | 198 device, device_settings.DETERMINISTIC_DEVICE_SETTINGS) |
| 187 if options.disable_location: | 199 if options.disable_location: |
| 188 device_settings.ConfigureContentSettings( | 200 device_settings.ConfigureContentSettings( |
| 189 device, device_settings.DISABLE_LOCATION_SETTINGS) | 201 device, device_settings.DISABLE_LOCATION_SETTINGS) |
| 190 else: | 202 else: |
| 191 device_settings.ConfigureContentSettings( | 203 device_settings.ConfigureContentSettings( |
| 192 device, device_settings.ENABLE_LOCATION_SETTINGS) | 204 device, device_settings.ENABLE_LOCATION_SETTINGS) |
| 193 device_settings.SetLockScreenSettings(device) | 205 device_settings.SetLockScreenSettings(device) |
| 194 if options.disable_network: | 206 if options.disable_network: |
| 195 device_settings.ConfigureContentSettings( | 207 device_settings.ConfigureContentSettings( |
| 196 device, device_settings.NETWORK_DISABLED_SETTINGS) | 208 device, device_settings.NETWORK_DISABLED_SETTINGS) |
| 197 if options.min_battery_level is not None: | 209 if options.min_battery_level is not None: |
| 198 try: | 210 try: |
| 199 device.SetUsbCharging(True) | 211 device.SetCharging(True) |
| 200 ChargeDeviceToLevel(device, options.min_battery_level) | 212 ChargeDeviceToLevel(device, options.min_battery_level) |
| 201 except device_errors.CommandFailedError as e: | 213 except device_errors.CommandFailedError as e: |
| 202 logging.exception('Unable to charge device to specified level.') | 214 logging.exception('Unable to charge device to specified level.') |
| 203 | 215 |
| 204 if not options.skip_wipe: | 216 if not options.skip_wipe: |
| 205 device.Reboot(True, timeout=reboot_timeout, retries=0) | 217 device.Reboot(True, timeout=reboot_timeout, retries=0) |
| 206 device.RunShellCommand('date -s %s' % time.strftime('%Y%m%d.%H%M%S', | 218 device.RunShellCommand('date -s %s' % time.strftime('%Y%m%d.%H%M%S', |
| 207 time.gmtime()), | 219 time.gmtime()), |
| 208 as_root=True) | 220 as_root=True) |
| 209 props = device.RunShellCommand('getprop') | 221 props = device.RunShellCommand('getprop') |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 273 parser.add_argument('--disable-network', action='store_true', | 285 parser.add_argument('--disable-network', action='store_true', |
| 274 help='disable network access on devices') | 286 help='disable network access on devices') |
| 275 parser.add_argument('--disable-java-debug', action='store_false', | 287 parser.add_argument('--disable-java-debug', action='store_false', |
| 276 dest='enable_java_debug', default=True, | 288 dest='enable_java_debug', default=True, |
| 277 help='disable Java property asserts and JNI checking') | 289 help='disable Java property asserts and JNI checking') |
| 278 parser.add_argument('-t', '--target', default='Debug', | 290 parser.add_argument('-t', '--target', default='Debug', |
| 279 help='the build target (default: %(default)s)') | 291 help='the build target (default: %(default)s)') |
| 280 parser.add_argument('-r', '--auto-reconnect', action='store_true', | 292 parser.add_argument('-r', '--auto-reconnect', action='store_true', |
| 281 help='push binary which will reboot the device on adb' | 293 help='push binary which will reboot the device on adb' |
| 282 ' disconnections') | 294 ' disconnections') |
| 295 parser.add_argument('--adb-key-files', type=str, nargs='+', |
| 296 help='list of adb keys to push to device') |
| 283 args = parser.parse_args() | 297 args = parser.parse_args() |
| 284 constants.SetBuildType(args.target) | 298 constants.SetBuildType(args.target) |
| 285 | 299 |
| 286 return ProvisionDevices(args) | 300 return ProvisionDevices(args) |
| 287 | 301 |
| 288 | 302 |
| 289 if __name__ == '__main__': | 303 if __name__ == '__main__': |
| 290 sys.exit(main()) | 304 sys.exit(main()) |
| OLD | NEW |