Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(46)

Side by Side Diff: build/android/buildbot/bb_device_status_check.py

Issue 1281923003: [Android] Add --blacklist-file as a command-line option. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix telemetry_unittests Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « build/android/adb_reverse_forwarder.py ('k') | build/android/buildbot/bb_device_steps.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # 2 #
3 # Copyright 2013 The Chromium Authors. All rights reserved. 3 # Copyright 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 """A class to keep track of devices across builds and report state.""" 7 """A class to keep track of devices across builds and report state."""
8 import argparse
8 import json 9 import json
9 import logging 10 import logging
10 import optparse
11 import os 11 import os
12 import psutil 12 import psutil
13 import re 13 import re
14 import signal 14 import signal
15 import smtplib 15 import smtplib
16 import subprocess 16 import subprocess
17 import sys 17 import sys
18 import time 18 import time
19 import urllib 19 import urllib
20 20
(...skipping 13 matching lines...) Expand all
34 from pylib.device import battery_utils 34 from pylib.device import battery_utils
35 from pylib.device import device_blacklist 35 from pylib.device import device_blacklist
36 from pylib.device import device_errors 36 from pylib.device import device_errors
37 from pylib.device import device_list 37 from pylib.device import device_list
38 from pylib.device import device_utils 38 from pylib.device import device_utils
39 from pylib.utils import run_tests_helper 39 from pylib.utils import run_tests_helper
40 from pylib.utils import timeout_retry 40 from pylib.utils import timeout_retry
41 41
42 _RE_DEVICE_ID = re.compile('Device ID = (\d+)') 42 _RE_DEVICE_ID = re.compile('Device ID = (\d+)')
43 43
44 def DeviceInfo(device, options): 44 def DeviceInfo(device, args):
45 """Gathers info on a device via various adb calls. 45 """Gathers info on a device via various adb calls.
46 46
47 Args: 47 Args:
48 device: A DeviceUtils instance for the device to construct info about. 48 device: A DeviceUtils instance for the device to construct info about.
49 49
50 Returns: 50 Returns:
51 Tuple of device type, build id, report as a string, error messages, and 51 Tuple of device type, build id, report as a string, error messages, and
52 boolean indicating whether or not device can be used for testing. 52 boolean indicating whether or not device can be used for testing.
53 """ 53 """
54 battery = battery_utils.BatteryUtils(device) 54 battery = battery_utils.BatteryUtils(device)
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 if m: 89 if m:
90 json_data['imei_slice'] = m.group(1)[-6:] 90 json_data['imei_slice'] = m.group(1)[-6:]
91 except device_errors.CommandFailedError: 91 except device_errors.CommandFailedError:
92 logging.exception('Failed to get IMEI slice for %s', str(device)) 92 logging.exception('Failed to get IMEI slice for %s', str(device))
93 93
94 if battery_level < 15: 94 if battery_level < 15:
95 errors += ['Device critically low in battery.'] 95 errors += ['Device critically low in battery.']
96 dev_good = False 96 dev_good = False
97 if not battery.GetCharging(): 97 if not battery.GetCharging():
98 battery.SetCharging(True) 98 battery.SetCharging(True)
99 if not options.no_provisioning_check: 99 if not args.no_provisioning_check:
100 setup_wizard_disabled = ( 100 setup_wizard_disabled = (
101 device.GetProp('ro.setupwizard.mode') == 'DISABLED') 101 device.GetProp('ro.setupwizard.mode') == 'DISABLED')
102 if not setup_wizard_disabled and device.build_type != 'user': 102 if not setup_wizard_disabled and device.build_type != 'user':
103 errors += ['Setup wizard not disabled. Was it provisioned correctly?'] 103 errors += ['Setup wizard not disabled. Was it provisioned correctly?']
104 if (device.product_name == 'mantaray' and 104 if (device.product_name == 'mantaray' and
105 battery_info.get('AC powered', None) != 'true'): 105 battery_info.get('AC powered', None) != 'true'):
106 errors += ['Mantaray device not connected to AC power.'] 106 errors += ['Mantaray device not connected to AC power.']
107 except device_errors.CommandFailedError: 107 except device_errors.CommandFailedError:
108 logging.exception('Failure while getting device status.') 108 logging.exception('Failure while getting device status.')
109 dev_good = False 109 dev_good = False
110 except device_errors.CommandTimeoutError: 110 except device_errors.CommandTimeoutError:
111 logging.exception('Timeout while getting device status.') 111 logging.exception('Timeout while getting device status.')
112 dev_good = False 112 dev_good = False
113 113
114 return (build_product, build_id, battery_level, errors, dev_good, json_data) 114 return (build_product, build_id, battery_level, errors, dev_good, json_data)
115 115
116 116
117 def CheckForMissingDevices(options, devices): 117 def CheckForMissingDevices(args, devices):
118 """Uses file of previous online devices to detect broken phones. 118 """Uses file of previous online devices to detect broken phones.
119 119
120 Args: 120 Args:
121 options: out_dir parameter of options argument is used as the base 121 args: out_dir parameter of args argument is used as the base
122 directory to load and update the cache file. 122 directory to load and update the cache file.
123 devices: A list of DeviceUtils instance for the currently visible and 123 devices: A list of DeviceUtils instance for the currently visible and
124 online attached devices. 124 online attached devices.
125 """ 125 """
126 out_dir = os.path.abspath(options.out_dir) 126 out_dir = os.path.abspath(args.out_dir)
127 device_serials = set(d.adb.GetDeviceSerial() for d in devices) 127 device_serials = set(d.adb.GetDeviceSerial() for d in devices)
128 128
129 # last_devices denotes all known devices prior to this run 129 # last_devices denotes all known devices prior to this run
130 last_devices_path = os.path.join(out_dir, device_list.LAST_DEVICES_FILENAME) 130 last_devices_path = os.path.join(out_dir, device_list.LAST_DEVICES_FILENAME)
131 last_missing_devices_path = os.path.join(out_dir, 131 last_missing_devices_path = os.path.join(out_dir,
132 device_list.LAST_MISSING_DEVICES_FILENAME) 132 device_list.LAST_MISSING_DEVICES_FILENAME)
133 try: 133 try:
134 last_devices = device_list.GetPersistentDeviceList(last_devices_path) 134 last_devices = device_list.GetPersistentDeviceList(last_devices_path)
135 except IOError: 135 except IOError:
136 # Ignore error, file might not exist 136 # Ignore error, file might not exist
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
217 except (psutil.NoSuchProcess, psutil.AccessDenied): 217 except (psutil.NoSuchProcess, psutil.AccessDenied):
218 pass 218 pass
219 for p in GetAllAdb(): 219 for p in GetAllAdb():
220 try: 220 try:
221 logging.error('Unable to kill %d (%s [%s])', p.pid, p.name, 221 logging.error('Unable to kill %d (%s [%s])', p.pid, p.name,
222 ' '.join(p.cmdline)) 222 ' '.join(p.cmdline))
223 except (psutil.NoSuchProcess, psutil.AccessDenied): 223 except (psutil.NoSuchProcess, psutil.AccessDenied):
224 pass 224 pass
225 225
226 226
227 def RecoverDevices(args): 227 def RecoverDevices(blacklist, output_directory):
228 # Remove the last build's "bad devices" before checking device statuses. 228 # Remove the last build's "bad devices" before checking device statuses.
229 device_blacklist.ResetBlacklist() 229 blacklist.Reset()
230 230
231 previous_devices = set(a.GetDeviceSerial() 231 previous_devices = set(a.GetDeviceSerial()
232 for a in adb_wrapper.AdbWrapper.Devices()) 232 for a in adb_wrapper.AdbWrapper.Devices())
233 233
234 KillAllAdb() 234 KillAllAdb()
235 reset_usb.reset_all_android_devices() 235 reset_usb.reset_all_android_devices()
236 236
237 try: 237 try:
238 expected_devices = set(device_list.GetPersistentDeviceList( 238 expected_devices = set(device_list.GetPersistentDeviceList(
239 os.path.join(args.out_dir, device_list.LAST_DEVICES_FILENAME))) 239 os.path.join(output_directory, device_list.LAST_DEVICES_FILENAME)))
240 except IOError: 240 except IOError:
241 expected_devices = set() 241 expected_devices = set()
242 242
243 all_devices = [device_utils.DeviceUtils(d) 243 all_devices = [device_utils.DeviceUtils(d)
244 for d in previous_devices.union(expected_devices)] 244 for d in previous_devices.union(expected_devices)]
245 245
246 def blacklisting_recovery(device): 246 def blacklisting_recovery(device):
247 try: 247 try:
248 device.WaitUntilFullyBooted() 248 device.WaitUntilFullyBooted()
249 except device_errors.CommandFailedError: 249 except device_errors.CommandFailedError:
250 logging.exception('Failure while waiting for %s. Adding to blacklist.', 250 logging.exception('Failure while waiting for %s. Adding to blacklist.',
251 str(device)) 251 str(device))
252 device_blacklist.ExtendBlacklist([str(device)]) 252 blacklist.Extend([str(device)])
253 except device_errors.CommandTimeoutError: 253 except device_errors.CommandTimeoutError:
254 logging.exception('Timed out while waiting for %s. Adding to blacklist.', 254 logging.exception('Timed out while waiting for %s. Adding to blacklist.',
255 str(device)) 255 str(device))
256 device_blacklist.ExtendBlacklist([str(device)]) 256 blacklist.Extend([str(device)])
257 257
258 device_utils.DeviceUtils.parallel(all_devices).pMap(blacklisting_recovery) 258 device_utils.DeviceUtils.parallel(all_devices).pMap(blacklisting_recovery)
259 259
260 devices = device_utils.DeviceUtils.HealthyDevices() 260 devices = device_utils.DeviceUtils.HealthyDevices(blacklist)
261 device_serials = set(d.adb.GetDeviceSerial() for d in devices) 261 device_serials = set(d.adb.GetDeviceSerial() for d in devices)
262 262
263 missing_devices = expected_devices.difference(device_serials) 263 missing_devices = expected_devices.difference(device_serials)
264 new_devices = device_serials.difference(expected_devices) 264 new_devices = device_serials.difference(expected_devices)
265 265
266 if missing_devices or new_devices: 266 if missing_devices or new_devices:
267 logging.warning('expected_devices:') 267 logging.warning('expected_devices:')
268 for d in sorted(expected_devices): 268 for d in sorted(expected_devices):
269 logging.warning(' %s', d) 269 logging.warning(' %s', d)
270 logging.warning('devices:') 270 logging.warning('devices:')
271 for d in sorted(device_serials): 271 for d in sorted(device_serials):
272 logging.warning(' %s', d) 272 logging.warning(' %s', d)
273 273
274 return devices 274 return devices
275 275
276 276
277 def main(): 277 def main():
278 parser = optparse.OptionParser() 278 parser = argparse.ArgumentParser()
279 parser.add_option('', '--out-dir', 279 parser.add_argument('--out-dir',
280 help='Directory where the device path is stored', 280 help='Directory where the device path is stored',
281 default=os.path.join(constants.DIR_SOURCE_ROOT, 'out')) 281 default=os.path.join(constants.DIR_SOURCE_ROOT, 'out'))
282 parser.add_option('--no-provisioning-check', action='store_true', 282 parser.add_argument('--no-provisioning-check', action='store_true',
283 help='Will not check if devices are provisioned properly.') 283 help='Will not check if devices are provisioned '
284 parser.add_option('--device-status-dashboard', action='store_true', 284 'properly.')
285 help='Output device status data for dashboard.') 285 parser.add_argument('--device-status-dashboard', action='store_true',
286 parser.add_option('--restart-usb', action='store_true', 286 help='Output device status data for dashboard.')
287 help='DEPRECATED. ' 287 parser.add_argument('--restart-usb', action='store_true',
288 'This script now always tries to reset USB.') 288 help='DEPRECATED. '
289 parser.add_option('--json-output', 289 'This script now always tries to reset USB.')
290 help='Output JSON information into a specified file.') 290 parser.add_argument('--json-output',
291 parser.add_option('-v', '--verbose', action='count', default=1, 291 help='Output JSON information into a specified file.')
292 help='Log more information.') 292 parser.add_argument('--blacklist-file', help='Device blacklist JSON file.')
293 parser.add_argument('-v', '--verbose', action='count', default=1,
294 help='Log more information.')
293 295
294 options, args = parser.parse_args() 296 args = parser.parse_args()
295 if args:
296 parser.error('Unknown options %s' % args)
297 297
298 run_tests_helper.SetLogLevel(options.verbose) 298 run_tests_helper.SetLogLevel(args.verbose)
299 299
300 devices = RecoverDevices(options) 300 if args.blacklist_file:
301 blacklist = device_blacklist.Blacklist(args.blacklist_file)
302 else:
303 # TODO(jbudorick): Remove this once bots pass the blacklist file.
304 blacklist = device_blacklist.Blacklist(device_blacklist.BLACKLIST_JSON)
305
306 devices = RecoverDevices(blacklist, args.out_dir)
301 307
302 types, builds, batteries, errors, devices_ok, json_data = ( 308 types, builds, batteries, errors, devices_ok, json_data = (
303 [], [], [], [], [], []) 309 [], [], [], [], [], [])
304 if devices: 310 if devices:
305 types, builds, batteries, errors, devices_ok, json_data = ( 311 types, builds, batteries, errors, devices_ok, json_data = (
306 zip(*[DeviceInfo(dev, options) for dev in devices])) 312 zip(*[DeviceInfo(dev, args) for dev in devices]))
307 313
308 # Write device info to file for buildbot info display. 314 # Write device info to file for buildbot info display.
309 if os.path.exists('/home/chrome-bot'): 315 if os.path.exists('/home/chrome-bot'):
310 with open('/home/chrome-bot/.adb_device_info', 'w') as f: 316 with open('/home/chrome-bot/.adb_device_info', 'w') as f:
311 for device in json_data: 317 for device in json_data:
312 try: 318 try:
313 f.write('%s %s %s %.1fC %s%%\n' % (device['serial'], device['type'], 319 f.write('%s %s %s %.1fC %s%%\n' % (device['serial'], device['type'],
314 device['build'], float(device['battery']['temperature']) / 10, 320 device['build'], float(device['battery']['temperature']) / 10,
315 device['battery']['level'])) 321 device['battery']['level']))
316 except Exception: 322 except Exception:
317 pass 323 pass
318 324
319 err_msg = CheckForMissingDevices(options, devices) or [] 325 err_msg = CheckForMissingDevices(args, devices) or []
320 326
321 unique_types = list(set(types)) 327 unique_types = list(set(types))
322 unique_builds = list(set(builds)) 328 unique_builds = list(set(builds))
323 329
324 bb_annotations.PrintMsg('Online devices: %d. Device types %s, builds %s' 330 bb_annotations.PrintMsg('Online devices: %d. Device types %s, builds %s'
325 % (len(devices), unique_types, unique_builds)) 331 % (len(devices), unique_types, unique_builds))
326 332
327 for j in json_data: 333 for j in json_data:
328 logging.info('Device %s (%s)', j.get('serial'), j.get('type')) 334 logging.info('Device %s (%s)', j.get('serial'), j.get('type'))
329 logging.info(' Build: %s (%s)', j.get('build'), j.get('build_detail')) 335 logging.info(' Build: %s (%s)', j.get('build'), j.get('build_detail'))
(...skipping 13 matching lines...) Expand all
343 bb_annotations.PrintWarning() 349 bb_annotations.PrintWarning()
344 for e in err_msg: 350 for e in err_msg:
345 logging.error(e) 351 logging.error(e)
346 from_address = 'buildbot@chromium.org' 352 from_address = 'buildbot@chromium.org'
347 to_addresses = ['chromium-android-device-alerts@google.com'] 353 to_addresses = ['chromium-android-device-alerts@google.com']
348 bot_name = os.environ.get('BUILDBOT_BUILDERNAME') 354 bot_name = os.environ.get('BUILDBOT_BUILDERNAME')
349 slave_name = os.environ.get('BUILDBOT_SLAVENAME') 355 slave_name = os.environ.get('BUILDBOT_SLAVENAME')
350 subject = 'Device status check errors on %s, %s.' % (slave_name, bot_name) 356 subject = 'Device status check errors on %s, %s.' % (slave_name, bot_name)
351 SendEmail(from_address, to_addresses, [], subject, '\n'.join(err_msg)) 357 SendEmail(from_address, to_addresses, [], subject, '\n'.join(err_msg))
352 358
353 if options.device_status_dashboard: 359 if args.device_status_dashboard:
354 offline_devices = [ 360 offline_devices = [
355 device_utils.DeviceUtils(a) 361 device_utils.DeviceUtils(a)
356 for a in adb_wrapper.AdbWrapper.Devices(is_ready=False) 362 for a in adb_wrapper.AdbWrapper.Devices(is_ready=False)
357 if a.GetState() == 'offline'] 363 if a.GetState() == 'offline']
358 364
359 perf_tests_results_helper.PrintPerfResult('BotDevices', 'OnlineDevices', 365 perf_tests_results_helper.PrintPerfResult('BotDevices', 'OnlineDevices',
360 [len(devices)], 'devices') 366 [len(devices)], 'devices')
361 perf_tests_results_helper.PrintPerfResult('BotDevices', 'OfflineDevices', 367 perf_tests_results_helper.PrintPerfResult('BotDevices', 'OfflineDevices',
362 [len(offline_devices)], 'devices', 368 [len(offline_devices)], 'devices',
363 'unimportant') 369 'unimportant')
364 for dev, battery in zip(devices, batteries): 370 for dev, battery in zip(devices, batteries):
365 perf_tests_results_helper.PrintPerfResult('DeviceBattery', str(dev), 371 perf_tests_results_helper.PrintPerfResult('DeviceBattery', str(dev),
366 [battery], '%', 372 [battery], '%',
367 'unimportant') 373 'unimportant')
368 374
369 if options.json_output: 375 if args.json_output:
370 with open(options.json_output, 'wb') as f: 376 with open(args.json_output, 'wb') as f:
371 f.write(json.dumps(json_data, indent=4)) 377 f.write(json.dumps(json_data, indent=4))
372 378
373 num_failed_devs = 0 379 num_failed_devs = 0
374 for device_ok, device in zip(devices_ok, devices): 380 for device_ok, device in zip(devices_ok, devices):
375 if not device_ok: 381 if not device_ok:
376 logging.warning('Blacklisting %s', str(device)) 382 logging.warning('Blacklisting %s', str(device))
377 device_blacklist.ExtendBlacklist([str(device)]) 383 blacklist.Extend([str(device)])
378 num_failed_devs += 1 384 num_failed_devs += 1
379 385
380 if num_failed_devs == len(devices): 386 if num_failed_devs == len(devices):
381 return 2 387 return 2
382 388
383 if not devices: 389 if not devices:
384 return 1 390 return 1
385 391
386 392
387 if __name__ == '__main__': 393 if __name__ == '__main__':
388 sys.exit(main()) 394 sys.exit(main())
OLDNEW
« no previous file with comments | « build/android/adb_reverse_forwarder.py ('k') | build/android/buildbot/bb_device_steps.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698