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

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: 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
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):
rnephew (Reviews Here) 2015/08/07 22:26:31 Should this transition from optprase to argparse b
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 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 main(): 227 def main():
228 parser = optparse.OptionParser() 228 parser = argparse.ArgumentParser()
229 parser.add_option('', '--out-dir', 229 parser.add_argument('--out-dir',
230 help='Directory where the device path is stored', 230 help='Directory where the device path is stored',
231 default=os.path.join(constants.DIR_SOURCE_ROOT, 'out')) 231 default=os.path.join(constants.DIR_SOURCE_ROOT, 'out'))
232 parser.add_option('--no-provisioning-check', action='store_true', 232 parser.add_argument('--no-provisioning-check', action='store_true',
233 help='Will not check if devices are provisioned properly.') 233 help='Will not check if devices are provisioned '
234 parser.add_option('--device-status-dashboard', action='store_true', 234 'properly.')
235 help='Output device status data for dashboard.') 235 parser.add_argument('--device-status-dashboard', action='store_true',
236 parser.add_option('--restart-usb', action='store_true', 236 help='Output device status data for dashboard.')
237 help='DEPRECATED. ' 237 parser.add_argument('--restart-usb', action='store_true',
238 'This script now always tries to reset USB.') 238 help='DEPRECATED. '
239 parser.add_option('--json-output', 239 'This script now always tries to reset USB.')
240 help='Output JSON information into a specified file.') 240 parser.add_argument('--json-output',
241 parser.add_option('-v', '--verbose', action='count', default=1, 241 help='Output JSON information into a specified file.')
242 help='Log more information.') 242 parser.add_argument('--blacklist-file', help='Device blacklist JSON file.')
243 parser.add_argument('-v', '--verbose', action='count', default=1,
244 help='Log more information.')
243 245
244 options, args = parser.parse_args() 246 args = parser.parse_args()
245 if args:
246 parser.error('Unknown options %s' % args)
247 247
248 run_tests_helper.SetLogLevel(options.verbose) 248 run_tests_helper.SetLogLevel(args.verbose)
249
250 if args.blacklist_file:
251 blacklist = device_blacklist.Blacklist(args.blacklist_file)
252 else:
253 # TODO(jbudorick): Remove this once bots pass the blacklist file.
254 blacklist = device_blacklist.Blacklist(device_blacklist.BLACKLIST_JSON)
249 255
250 # Remove the last build's "bad devices" before checking device statuses. 256 # Remove the last build's "bad devices" before checking device statuses.
251 device_blacklist.ResetBlacklist() 257 blacklist.Reset()
252 258
253 KillAllAdb() 259 KillAllAdb()
254 reset_usb.reset_all_android_devices() 260 reset_usb.reset_all_android_devices()
255 261
256 try: 262 try:
257 expected_devices = set(device_list.GetPersistentDeviceList( 263 expected_devices = set(device_list.GetPersistentDeviceList(
258 os.path.join(options.out_dir, device_list.LAST_DEVICES_FILENAME))) 264 os.path.join(args.out_dir, device_list.LAST_DEVICES_FILENAME)))
259 except IOError: 265 except IOError:
260 expected_devices = set() 266 expected_devices = set()
261 267
262 def all_devices_found(): 268 def all_devices_found():
263 devices = device_utils.DeviceUtils.HealthyDevices() 269 devices = device_utils.DeviceUtils.HealthyDevices(blacklist)
264 device_serials = set(d.adb.GetDeviceSerial() for d in devices) 270 device_serials = set(d.adb.GetDeviceSerial() for d in devices)
265 return not bool(expected_devices.difference(device_serials)) 271 return not bool(expected_devices.difference(device_serials))
266 272
267 timeout_retry.WaitFor(all_devices_found, wait_period=1, max_tries=5) 273 timeout_retry.WaitFor(all_devices_found, wait_period=1, max_tries=5)
268 274
269 devices = device_utils.DeviceUtils.HealthyDevices() 275 devices = device_utils.DeviceUtils.HealthyDevices(blacklist)
270 device_serials = set(d.adb.GetDeviceSerial() for d in devices) 276 device_serials = set(d.adb.GetDeviceSerial() for d in devices)
271 277
272 missing_devices = expected_devices.difference(device_serials) 278 missing_devices = expected_devices.difference(device_serials)
273 new_devices = device_serials.difference(expected_devices) 279 new_devices = device_serials.difference(expected_devices)
274 280
275 if missing_devices or new_devices: 281 if missing_devices or new_devices:
276 logging.warning('expected_devices:') 282 logging.warning('expected_devices:')
277 for d in sorted(expected_devices): 283 for d in sorted(expected_devices):
278 logging.warning(' %s', d) 284 logging.warning(' %s', d)
279 logging.warning('devices:') 285 logging.warning('devices:')
280 for d in sorted(device_serials): 286 for d in sorted(device_serials):
281 logging.warning(' %s', d) 287 logging.warning(' %s', d)
282 288
283 types, builds, batteries, errors, devices_ok, json_data = ( 289 types, builds, batteries, errors, devices_ok, json_data = (
284 [], [], [], [], [], []) 290 [], [], [], [], [], [])
285 if devices: 291 if devices:
286 types, builds, batteries, errors, devices_ok, json_data = ( 292 types, builds, batteries, errors, devices_ok, json_data = (
287 zip(*[DeviceInfo(dev, options) for dev in devices])) 293 zip(*[DeviceInfo(dev, args) for dev in devices]))
288 294
289 # Write device info to file for buildbot info display. 295 # Write device info to file for buildbot info display.
290 if os.path.exists('/home/chrome-bot'): 296 if os.path.exists('/home/chrome-bot'):
291 with open('/home/chrome-bot/.adb_device_info', 'w') as f: 297 with open('/home/chrome-bot/.adb_device_info', 'w') as f:
292 for device in json_data: 298 for device in json_data:
293 try: 299 try:
294 f.write('%s %s %s %.1fC %s%%\n' % (device['serial'], device['type'], 300 f.write('%s %s %s %.1fC %s%%\n' % (device['serial'], device['type'],
295 device['build'], float(device['battery']['temperature']) / 10, 301 device['build'], float(device['battery']['temperature']) / 10,
296 device['battery']['level'])) 302 device['battery']['level']))
297 except Exception: 303 except Exception:
298 pass 304 pass
299 305
300 err_msg = CheckForMissingDevices(options, devices) or [] 306 err_msg = CheckForMissingDevices(args, devices) or []
301 307
302 unique_types = list(set(types)) 308 unique_types = list(set(types))
303 unique_builds = list(set(builds)) 309 unique_builds = list(set(builds))
304 310
305 bb_annotations.PrintMsg('Online devices: %d. Device types %s, builds %s' 311 bb_annotations.PrintMsg('Online devices: %d. Device types %s, builds %s'
306 % (len(devices), unique_types, unique_builds)) 312 % (len(devices), unique_types, unique_builds))
307 313
308 for j in json_data: 314 for j in json_data:
309 logging.info('Device %s (%s)', j.get('serial'), j.get('type')) 315 logging.info('Device %s (%s)', j.get('serial'), j.get('type'))
310 logging.info(' Build: %s (%s)', j.get('build'), j.get('build_detail')) 316 logging.info(' Build: %s (%s)', j.get('build'), j.get('build_detail'))
(...skipping 13 matching lines...) Expand all
324 bb_annotations.PrintWarning() 330 bb_annotations.PrintWarning()
325 for e in err_msg: 331 for e in err_msg:
326 logging.error(e) 332 logging.error(e)
327 from_address = 'buildbot@chromium.org' 333 from_address = 'buildbot@chromium.org'
328 to_addresses = ['chromium-android-device-alerts@google.com'] 334 to_addresses = ['chromium-android-device-alerts@google.com']
329 bot_name = os.environ.get('BUILDBOT_BUILDERNAME') 335 bot_name = os.environ.get('BUILDBOT_BUILDERNAME')
330 slave_name = os.environ.get('BUILDBOT_SLAVENAME') 336 slave_name = os.environ.get('BUILDBOT_SLAVENAME')
331 subject = 'Device status check errors on %s, %s.' % (slave_name, bot_name) 337 subject = 'Device status check errors on %s, %s.' % (slave_name, bot_name)
332 SendEmail(from_address, to_addresses, [], subject, '\n'.join(err_msg)) 338 SendEmail(from_address, to_addresses, [], subject, '\n'.join(err_msg))
333 339
334 if options.device_status_dashboard: 340 if args.device_status_dashboard:
335 offline_devices = [ 341 offline_devices = [
336 device_utils.DeviceUtils(a) 342 device_utils.DeviceUtils(a)
337 for a in adb_wrapper.AdbWrapper.Devices(is_ready=False) 343 for a in adb_wrapper.AdbWrapper.Devices(is_ready=False)
338 if a.GetState() == 'offline'] 344 if a.GetState() == 'offline']
339 345
340 perf_tests_results_helper.PrintPerfResult('BotDevices', 'OnlineDevices', 346 perf_tests_results_helper.PrintPerfResult('BotDevices', 'OnlineDevices',
341 [len(devices)], 'devices') 347 [len(devices)], 'devices')
342 perf_tests_results_helper.PrintPerfResult('BotDevices', 'OfflineDevices', 348 perf_tests_results_helper.PrintPerfResult('BotDevices', 'OfflineDevices',
343 [len(offline_devices)], 'devices', 349 [len(offline_devices)], 'devices',
344 'unimportant') 350 'unimportant')
345 for dev, battery in zip(devices, batteries): 351 for dev, battery in zip(devices, batteries):
346 perf_tests_results_helper.PrintPerfResult('DeviceBattery', str(dev), 352 perf_tests_results_helper.PrintPerfResult('DeviceBattery', str(dev),
347 [battery], '%', 353 [battery], '%',
348 'unimportant') 354 'unimportant')
349 355
350 if options.json_output: 356 if args.json_output:
351 with open(options.json_output, 'wb') as f: 357 with open(args.json_output, 'wb') as f:
352 f.write(json.dumps(json_data, indent=4)) 358 f.write(json.dumps(json_data, indent=4))
353 359
354 num_failed_devs = 0 360 num_failed_devs = 0
355 for device_ok, device in zip(devices_ok, devices): 361 for device_ok, device in zip(devices_ok, devices):
356 if not device_ok: 362 if not device_ok:
357 logging.warning('Blacklisting %s', str(device)) 363 logging.warning('Blacklisting %s', str(device))
358 device_blacklist.ExtendBlacklist([str(device)]) 364 blacklist.Extend([str(device)])
359 num_failed_devs += 1 365 num_failed_devs += 1
360 366
361 if num_failed_devs == len(devices): 367 if num_failed_devs == len(devices):
362 return 2 368 return 2
363 369
364 if not devices: 370 if not devices:
365 return 1 371 return 1
366 372
367 373
368 if __name__ == '__main__': 374 if __name__ == '__main__':
369 sys.exit(main()) 375 sys.exit(main())
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698