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 |