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 from devil.android import battery_utils | 24 from devil.android import battery_utils |
25 from devil.android import device_blacklist | 25 from devil.android import device_blacklist |
26 from devil.android import device_errors | 26 from devil.android import device_errors |
| 27 from devil.android import device_temp_file |
27 from devil.android import device_utils | 28 from devil.android import device_utils |
28 from devil.android.sdk import version_codes | 29 from devil.android.sdk import version_codes |
29 from devil.utils import run_tests_helper | 30 from devil.utils import run_tests_helper |
30 from devil.utils import timeout_retry | 31 from devil.utils import timeout_retry |
31 from pylib import constants | 32 from pylib import constants |
32 from pylib import device_settings | 33 from pylib import device_settings |
33 | 34 |
34 _SYSTEM_WEBVIEW_PATHS = ['/system/app/webview', '/system/app/WebViewGoogle'] | 35 _SYSTEM_WEBVIEW_PATHS = ['/system/app/webview', '/system/app/WebViewGoogle'] |
35 _CHROME_PACKAGE_REGEX = re.compile('.*chrom.*') | 36 _CHROME_PACKAGE_REGEX = re.compile('.*chrom.*') |
36 _TOMBSTONE_REGEX = re.compile('tombstone.*') | 37 _TOMBSTONE_REGEX = re.compile('tombstone.*') |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
92 device.WaitUntilFullyBooted(timeout=reboot_timeout, retries=0) | 93 device.WaitUntilFullyBooted(timeout=reboot_timeout, retries=0) |
93 except device_errors.CommandTimeoutError: | 94 except device_errors.CommandTimeoutError: |
94 logging.error('Device did not finish booting. Will try to reboot.') | 95 logging.error('Device did not finish booting. Will try to reboot.') |
95 device.Reboot(timeout=reboot_timeout) | 96 device.Reboot(timeout=reboot_timeout) |
96 phase_func(device, options) | 97 phase_func(device, options) |
97 if reboot: | 98 if reboot: |
98 device.Reboot(False, retries=0) | 99 device.Reboot(False, retries=0) |
99 device.adb.WaitForDevice() | 100 device.adb.WaitForDevice() |
100 | 101 |
101 try: | 102 try: |
| 103 CheckExternalStorage(device) |
102 if should_run_phase(_PHASES.WIPE): | 104 if should_run_phase(_PHASES.WIPE): |
103 if options.chrome_specific_wipe: | 105 if options.chrome_specific_wipe: |
104 run_phase(WipeChromeData) | 106 run_phase(WipeChromeData) |
105 else: | 107 else: |
106 run_phase(WipeDevice) | 108 run_phase(WipeDevice) |
107 | 109 |
108 if should_run_phase(_PHASES.PROPERTIES): | 110 if should_run_phase(_PHASES.PROPERTIES): |
109 run_phase(SetProperties) | 111 run_phase(SetProperties) |
110 | 112 |
111 if should_run_phase(_PHASES.FINISH): | 113 if should_run_phase(_PHASES.FINISH): |
112 run_phase(FinishProvisioning, reboot=False) | 114 run_phase(FinishProvisioning, reboot=False) |
113 | 115 |
114 if options.chrome_specific_wipe: | 116 if options.chrome_specific_wipe: |
115 package = "com.google.android.gms" | 117 package = "com.google.android.gms" |
116 version_name = device.GetApplicationVersion(package) | 118 version_name = device.GetApplicationVersion(package) |
117 logging.info("Version name for %s is %s", package, version_name) | 119 logging.info("Version name for %s is %s", package, version_name) |
118 | 120 |
119 except device_errors.CommandTimeoutError: | 121 except device_errors.CommandTimeoutError: |
120 logging.exception('Timed out waiting for device %s. Adding to blacklist.', | 122 logging.exception('Timed out waiting for device %s. Adding to blacklist.', |
121 str(device)) | 123 str(device)) |
122 blacklist.Extend([str(device)]) | 124 blacklist.Extend([str(device)]) |
123 | 125 |
124 except device_errors.CommandFailedError: | 126 except device_errors.CommandFailedError: |
125 logging.exception('Failed to provision device %s. Adding to blacklist.', | 127 logging.exception('Failed to provision device %s. Adding to blacklist.', |
126 str(device)) | 128 str(device)) |
127 blacklist.Extend([str(device)]) | 129 blacklist.Extend([str(device)]) |
128 | 130 |
| 131 def CheckExternalStorage(device): |
| 132 """Checks that storage is writable and if not makes it writable. |
| 133 |
| 134 Arguments: |
| 135 device: The device to check. |
| 136 """ |
| 137 try: |
| 138 with device_temp_file.DeviceTempFile( |
| 139 device.adb, suffix='.sh', dir=device.GetExternalStoragePath()): |
| 140 pass |
| 141 except device_errors.CommandFailedError: |
| 142 logging.info('External storage not writable. Remounting / as RW') |
| 143 device.RunShellCommand(['mount', '-o', 'remount,rw', '/'], |
| 144 check_return=True, as_root=True) |
| 145 with device_temp_file.DeviceTempFile( |
| 146 device.adb, suffix='.sh', dir=device.GetExternalStoragePath()): |
| 147 pass |
129 | 148 |
130 def WipeChromeData(device, options): | 149 def WipeChromeData(device, options): |
131 """Wipes chrome specific data from device | 150 """Wipes chrome specific data from device |
132 | 151 |
133 (1) uninstall any app whose name matches *chrom*, except | 152 (1) uninstall any app whose name matches *chrom*, except |
134 com.android.chrome, which is the chrome stable package. Doing so also | 153 com.android.chrome, which is the chrome stable package. Doing so also |
135 removes the corresponding dirs under /data/data/ and /data/app/ | 154 removes the corresponding dirs under /data/data/ and /data/app/ |
136 (2) remove any dir under /data/app-lib/ whose name matches *chrom* | 155 (2) remove any dir under /data/app-lib/ whose name matches *chrom* |
137 (3) remove any files under /data/tombstones/ whose name matches "tombstone*" | 156 (3) remove any files under /data/tombstones/ whose name matches "tombstone*" |
138 (4) remove /data/local.prop if there is any | 157 (4) remove /data/local.prop if there is any |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
385 | 404 |
386 | 405 |
387 def _LaunchHostHeartbeat(): | 406 def _LaunchHostHeartbeat(): |
388 # Kill if existing host_heartbeat | 407 # Kill if existing host_heartbeat |
389 KillHostHeartbeat() | 408 KillHostHeartbeat() |
390 # Launch a new host_heartbeat | 409 # Launch a new host_heartbeat |
391 logging.info('Spawning host heartbeat...') | 410 logging.info('Spawning host heartbeat...') |
392 subprocess.Popen([os.path.join(constants.DIR_SOURCE_ROOT, | 411 subprocess.Popen([os.path.join(constants.DIR_SOURCE_ROOT, |
393 'build/android/host_heartbeat.py')]) | 412 'build/android/host_heartbeat.py')]) |
394 | 413 |
395 | |
396 def KillHostHeartbeat(): | 414 def KillHostHeartbeat(): |
397 ps = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE) | 415 ps = subprocess.Popen(['ps', 'aux'], stdout=subprocess.PIPE) |
398 stdout, _ = ps.communicate() | 416 stdout, _ = ps.communicate() |
399 matches = re.findall('\\n.*host_heartbeat.*', stdout) | 417 matches = re.findall('\\n.*host_heartbeat.*', stdout) |
400 for match in matches: | 418 for match in matches: |
401 logging.info('An instance of host heart beart running... will kill') | 419 logging.info('An instance of host heart beart running... will kill') |
402 pid = re.findall(r'(\S+)', match)[1] | 420 pid = re.findall(r'(\S+)', match)[1] |
403 subprocess.call(['kill', str(pid)]) | 421 subprocess.call(['kill', str(pid)]) |
404 | 422 |
405 | |
406 def main(): | 423 def main(): |
407 # Recommended options on perf bots: | 424 # Recommended options on perf bots: |
408 # --disable-network | 425 # --disable-network |
409 # TODO(tonyg): We eventually want network on. However, currently radios | 426 # TODO(tonyg): We eventually want network on. However, currently radios |
410 # can cause perfbots to drain faster than they charge. | 427 # can cause perfbots to drain faster than they charge. |
411 # --min-battery-level 95 | 428 # --min-battery-level 95 |
412 # Some perf bots run benchmarks with USB charging disabled which leads | 429 # Some perf bots run benchmarks with USB charging disabled which leads |
413 # to gradual draining of the battery. We must wait for a full charge | 430 # to gradual draining of the battery. We must wait for a full charge |
414 # before starting a run in order to keep the devices online. | 431 # before starting a run in order to keep the devices online. |
415 | 432 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
463 args = parser.parse_args() | 480 args = parser.parse_args() |
464 constants.SetBuildType(args.target) | 481 constants.SetBuildType(args.target) |
465 | 482 |
466 run_tests_helper.SetLogLevel(args.verbose) | 483 run_tests_helper.SetLogLevel(args.verbose) |
467 | 484 |
468 return ProvisionDevices(args) | 485 return ProvisionDevices(args) |
469 | 486 |
470 | 487 |
471 if __name__ == '__main__': | 488 if __name__ == '__main__': |
472 sys.exit(main()) | 489 sys.exit(main()) |
OLD | NEW |