| Index: build/android/buildbot/bb_device_status_check.py
|
| diff --git a/build/android/buildbot/bb_device_status_check.py b/build/android/buildbot/bb_device_status_check.py
|
| index 8561c0104b4724168cc20eda531e95f7849a6edb..8690a60a71409f3df38a6ce6a6a9ad384b9d2498 100755
|
| --- a/build/android/buildbot/bb_device_status_check.py
|
| +++ b/build/android/buildbot/bb_device_status_check.py
|
| @@ -30,9 +30,14 @@ sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
|
| from pylib import android_commands
|
| from pylib import constants
|
| from pylib.cmd_helper import GetCmdOutput
|
| +from pylib.device import battery_utils
|
| from pylib.device import device_blacklist
|
| +from pylib.device import device_errors
|
| from pylib.device import device_list
|
| from pylib.device import device_utils
|
| +from pylib.utils import run_tests_helper
|
| +
|
| +_RE_DEVICE_ID = re.compile('Device ID = (\d+)')
|
|
|
| def DeviceInfo(serial, options):
|
| """Gathers info on a device via various adb calls.
|
| @@ -44,73 +49,62 @@ def DeviceInfo(serial, options):
|
| Tuple of device type, build id, report as a string, error messages, and
|
| boolean indicating whether or not device can be used for testing.
|
| """
|
| + device = device_utils.DeviceUtils(serial)
|
| + battery = battery_utils.BatteryUtils(device)
|
|
|
| - device_adb = device_utils.DeviceUtils(serial)
|
| - device_type = device_adb.build_product
|
| - device_build = device_adb.build_id
|
| - device_build_type = device_adb.build_type
|
| - device_product_name = device_adb.product_name
|
| -
|
| - try:
|
| - battery_info = device_adb.old_interface.GetBatteryInfo()
|
| - except Exception as e:
|
| - battery_info = {}
|
| - logging.error('Unable to obtain battery info for %s, %s', serial, e)
|
| -
|
| - def _GetData(re_expression, line, lambda_function=lambda x: x):
|
| - if not line:
|
| - return 'Unknown'
|
| - found = re.findall(re_expression, line)
|
| - if found and len(found):
|
| - return lambda_function(found[0])
|
| - return 'Unknown'
|
| -
|
| - battery_level = int(battery_info.get('level', 100))
|
| - imei_slice = _GetData(r'Device ID = (\d+)',
|
| - device_adb.old_interface.GetSubscriberInfo(),
|
| - lambda x: x[-6:])
|
| + battery_info = {}
|
| + battery_level = 100
|
| + errors = []
|
| + dev_good = True
|
| json_data = {
|
| 'serial': serial,
|
| - 'type': device_type,
|
| - 'build': device_build,
|
| - 'build_detail': device_adb.GetProp('ro.build.fingerprint'),
|
| - 'battery': battery_info,
|
| - 'imei_slice': imei_slice,
|
| - 'wifi_ip': device_adb.GetProp('dhcp.wlan0.ipaddress'),
|
| + 'type': device.build_product,
|
| + 'build': device.build_id,
|
| + 'build_detail': device.GetProp('ro.build.fingerprint'),
|
| + 'battery': {},
|
| + 'imei_slice': 'Unknown',
|
| + 'wifi_ip': device.GetProp('dhcp.wlan0.ipaddress'),
|
| }
|
| - report = ['Device %s (%s)' % (serial, device_type),
|
| - ' Build: %s (%s)' %
|
| - (device_build, json_data['build_detail']),
|
| - ' Current Battery Service state: ',
|
| - '\n'.join([' %s: %s' % (k, v)
|
| - for k, v in battery_info.iteritems()]),
|
| - ' IMEI slice: %s' % imei_slice,
|
| - ' Wifi IP: %s' % json_data['wifi_ip'],
|
| - '']
|
|
|
| - errors = []
|
| - dev_good = True
|
| - if battery_level < 15:
|
| - errors += ['Device critically low in battery. Will add to blacklist.']
|
| - dev_good = False
|
| - if not device_adb.old_interface.IsDeviceCharging():
|
| - if device_adb.old_interface.CanControlUsbCharging():
|
| - device_adb.old_interface.EnableUsbCharging()
|
| - else:
|
| - logging.error('Device %s is not charging' % serial)
|
| - if not options.no_provisioning_check:
|
| - setup_wizard_disabled = (
|
| - device_adb.GetProp('ro.setupwizard.mode') == 'DISABLED')
|
| - if not setup_wizard_disabled and device_build_type != 'user':
|
| - errors += ['Setup wizard not disabled. Was it provisioned correctly?']
|
| - if (device_product_name == 'mantaray' and
|
| - battery_info.get('AC powered', None) != 'true'):
|
| - errors += ['Mantaray device not connected to AC power.']
|
| + try:
|
| + try:
|
| + battery_info = battery.GetBatteryInfo(timeout=5)
|
| + battery_level = int(battery_info.get('level', battery_level))
|
| + json_data['battery'] = battery_info
|
| + except device_errors.CommandFailedError:
|
| + logging.exception('Failed to get battery information for %s', serial)
|
|
|
| - full_report = '\n'.join(report)
|
| + try:
|
| + for l in device.RunShellCommand(['dumpsys', 'iphonesubinfo'],
|
| + check_return=True, timeout=5):
|
| + m = _RE_DEVICE_ID.match(l)
|
| + if m:
|
| + json_data['imei_slice'] = m.group(1)[-6:]
|
| + except device_errors.CommandFailedError:
|
| + logging.exception('Failed to get IMEI slice for %s', serial)
|
| +
|
| + if battery_level < 15:
|
| + errors += ['Device critically low in battery.']
|
| + dev_good = False
|
| + if not battery.GetCharging():
|
| + battery.SetCharging(True)
|
| + if not options.no_provisioning_check:
|
| + setup_wizard_disabled = (
|
| + device.GetProp('ro.setupwizard.mode') == 'DISABLED')
|
| + if not setup_wizard_disabled and device.build_type != 'user':
|
| + errors += ['Setup wizard not disabled. Was it provisioned correctly?']
|
| + if (device.product_name == 'mantaray' and
|
| + battery_info.get('AC powered', None) != 'true'):
|
| + errors += ['Mantaray device not connected to AC power.']
|
| + except device_errors.CommandFailedError:
|
| + logging.exception('Failure while getting device status.')
|
| + dev_good = False
|
| + except device_errors.CommandTimeoutError:
|
| + logging.exception('Timeout while getting device status.')
|
| + dev_good = False
|
|
|
| - return (device_type, device_build, battery_level, full_report, errors,
|
| - dev_good, json_data)
|
| + return (device.build_product, device.build_id, battery_level, errors,
|
| + dev_good, json_data)
|
|
|
|
|
| def CheckForMissingDevices(options, adb_online_devs):
|
| @@ -122,11 +116,6 @@ def CheckForMissingDevices(options, adb_online_devs):
|
| adb_online_devs: A list of serial numbers of the currently visible
|
| and online attached devices.
|
| """
|
| - # TODO(navabi): remove this once the bug that causes different number
|
| - # of devices to be detected between calls is fixed.
|
| - logger = logging.getLogger()
|
| - logger.setLevel(logging.INFO)
|
| -
|
| out_dir = os.path.abspath(options.out_dir)
|
|
|
| # last_devices denotes all known devices prior to this run
|
| @@ -189,10 +178,10 @@ def CheckForMissingDevices(options, adb_online_devs):
|
| os.environ.get('BUILDBOT_SLAVENAME'),
|
| os.environ.get('BUILDBOT_BUILDNUMBER')))))
|
| return ['Current online devices: %s' % adb_online_devs,
|
| - '%s are no longer visible. Were they removed?\n' % missing_devs,
|
| - 'SHERIFF:\n',
|
| - '@@@STEP_LINK@Click here to file a bug@%s@@@\n' % crbug_link,
|
| - 'Cache file: %s\n\n' % last_devices_path,
|
| + '%s are no longer visible. Were they removed?' % missing_devs,
|
| + 'SHERIFF:',
|
| + '@@@STEP_LINK@Click here to file a bug@%s@@@' % crbug_link,
|
| + 'Cache file: %s' % last_devices_path,
|
| 'adb devices: %s' % GetCmdOutput(['adb', 'devices']),
|
| 'adb devices(GetAttachedDevices): %s' % adb_online_devs]
|
| else:
|
| @@ -201,8 +190,9 @@ def CheckForMissingDevices(options, adb_online_devs):
|
| bb_annotations.PrintWarning()
|
| bb_annotations.PrintSummaryText(
|
| '%d new devices detected' % len(new_devs))
|
| - print ('New devices detected %s. And now back to your '
|
| - 'regularly scheduled program.' % list(new_devs))
|
| + logging.info('New devices detected:')
|
| + for d in new_devs:
|
| + logging.info(' %s', d)
|
|
|
|
|
| def SendEmail(from_address, to_addresses, cc_addresses, subject, msg):
|
| @@ -214,20 +204,20 @@ def SendEmail(from_address, to_addresses, cc_addresses, subject, msg):
|
| server = smtplib.SMTP('localhost')
|
| server.sendmail(from_address, to_addresses, msg_body)
|
| server.quit()
|
| - except Exception as e:
|
| - print 'Failed to send alert email. Error: %s' % e
|
| + except Exception:
|
| + logging.exception('Failed to send alert email.')
|
|
|
|
|
| def RestartUsb():
|
| if not os.path.isfile('/usr/bin/restart_usb'):
|
| - print ('ERROR: Could not restart usb. /usr/bin/restart_usb not installed '
|
| - 'on host (see BUG=305769).')
|
| + logging.error('Could not restart usb. ''/usr/bin/restart_usb not '
|
| + 'installed on host (see BUG=305769).')
|
| return False
|
|
|
| lsusb_proc = bb_utils.SpawnCmd(['lsusb'], stdout=subprocess.PIPE)
|
| lsusb_output, _ = lsusb_proc.communicate()
|
| if lsusb_proc.returncode:
|
| - print 'Error: Could not get list of USB ports (i.e. lsusb).'
|
| + logging.error('Could not get list of USB ports (i.e. lsusb).')
|
| return lsusb_proc.returncode
|
|
|
| usb_devices = [re.findall(r'Bus (\d\d\d) Device (\d\d\d)', lsusb_line)[0]
|
| @@ -243,10 +233,11 @@ def RestartUsb():
|
| if dev != '001':
|
| return_code = bb_utils.RunCmd(['/usr/bin/restart_usb', bus, dev])
|
| if return_code:
|
| - print 'Error restarting USB device /dev/bus/usb/%s/%s' % (bus, dev)
|
| + logging.error('Error restarting USB device /dev/bus/usb/%s/%s',
|
| + bus, dev)
|
| all_restarted = False
|
| else:
|
| - print 'Restarted USB device /dev/bus/usb/%s/%s' % (bus, dev)
|
| + logging.info('Restarted USB device /dev/bus/usb/%s/%s', bus, dev)
|
|
|
| return all_restarted
|
|
|
| @@ -263,14 +254,15 @@ def KillAllAdb():
|
| for sig in [signal.SIGTERM, signal.SIGQUIT, signal.SIGKILL]:
|
| for p in GetAllAdb():
|
| try:
|
| - print 'kill %d %d (%s [%s])' % (sig, p.pid, p.name,
|
| - ' '.join(p.cmdline))
|
| + logging.info('kill %d %d (%s [%s])', sig, p.pid, p.name,
|
| + ' '.join(p.cmdline))
|
| p.send_signal(sig)
|
| except (psutil.NoSuchProcess, psutil.AccessDenied):
|
| pass
|
| for p in GetAllAdb():
|
| try:
|
| - print 'Unable to kill %d (%s [%s])' % (p.pid, p.name, ' '.join(p.cmdline))
|
| + logging.error('Unable to kill %d (%s [%s])', p.pid, p.name,
|
| + ' '.join(p.cmdline))
|
| except (psutil.NoSuchProcess, psutil.AccessDenied):
|
| pass
|
|
|
| @@ -288,11 +280,15 @@ def main():
|
| help='Restart USB ports before running device check.')
|
| parser.add_option('--json-output',
|
| help='Output JSON information into a specified file.')
|
| + parser.add_option('-v', '--verbose', action='count', default=1,
|
| + help='Log more information.')
|
|
|
| options, args = parser.parse_args()
|
| if args:
|
| parser.error('Unknown options %s' % args)
|
|
|
| + run_tests_helper.SetLogLevel(options.verbose)
|
| +
|
| # Remove the last build's "bad devices" before checking device statuses.
|
| device_blacklist.ResetBlacklist()
|
|
|
| @@ -304,7 +300,8 @@ def main():
|
| devices = android_commands.GetAttachedDevices()
|
| # Only restart usb if devices are missing.
|
| if set(expected_devices) != set(devices):
|
| - print 'expected_devices: %s, devices: %s' % (expected_devices, devices)
|
| + logging.warning('expected_devices: %s', expected_devices)
|
| + logging.warning('devices: %s', devices)
|
| KillAllAdb()
|
| retries = 5
|
| usb_restarted = True
|
| @@ -312,9 +309,10 @@ def main():
|
| if not RestartUsb():
|
| usb_restarted = False
|
| bb_annotations.PrintWarning()
|
| - print 'USB reset stage failed, wait for any device to come back.'
|
| + logging.error('USB reset stage failed, '
|
| + 'wait for any device to come back.')
|
| while retries:
|
| - print 'retry adb devices...'
|
| + logging.info('retry adb devices...')
|
| time.sleep(1)
|
| devices = android_commands.GetAttachedDevices()
|
| if set(expected_devices) == set(devices):
|
| @@ -330,10 +328,10 @@ def main():
|
| offline_devices = android_commands.GetAttachedDevices(
|
| hardware=False, emulator=False, offline=True)
|
|
|
| - types, builds, batteries, reports, errors, json_data = [], [], [], [], [], []
|
| - fail_step_lst = []
|
| + types, builds, batteries, errors, devices_ok, json_data = (
|
| + [], [], [], [], [], [])
|
| if devices:
|
| - types, builds, batteries, reports, errors, fail_step_lst, json_data = (
|
| + types, builds, batteries, errors, devices_ok, json_data = (
|
| zip(*[DeviceInfo(dev, options) for dev in devices]))
|
|
|
| # Write device info to file for buildbot info display.
|
| @@ -354,7 +352,16 @@ def main():
|
|
|
| bb_annotations.PrintMsg('Online devices: %d. Device types %s, builds %s'
|
| % (len(devices), unique_types, unique_builds))
|
| - print '\n'.join(reports)
|
| +
|
| + for j in json_data:
|
| + logging.info('Device %s (%s)', j.get('serial'), j.get('type'))
|
| + logging.info(' Build: %s (%s)', j.get('build'), j.get('build_detail'))
|
| + logging.info(' Current Battery Service state:')
|
| + for k, v in j.get('battery', {}).iteritems():
|
| + logging.info(' %s: %s', k, v)
|
| + logging.info(' IMEI slice: %s', j.get('imei_slice'))
|
| + logging.info(' WiFi IP: %s', j.get('wifi_ip'))
|
| +
|
|
|
| for serial, dev_errors in zip(devices, errors):
|
| if dev_errors:
|
| @@ -363,14 +370,14 @@ def main():
|
|
|
| if err_msg:
|
| bb_annotations.PrintWarning()
|
| - msg = '\n'.join(err_msg)
|
| - print msg
|
| + for e in err_msg:
|
| + logging.error(e)
|
| from_address = 'buildbot@chromium.org'
|
| to_addresses = ['chromium-android-device-alerts@google.com']
|
| bot_name = os.environ.get('BUILDBOT_BUILDERNAME')
|
| slave_name = os.environ.get('BUILDBOT_SLAVENAME')
|
| subject = 'Device status check errors on %s, %s.' % (slave_name, bot_name)
|
| - SendEmail(from_address, to_addresses, [], subject, msg)
|
| + SendEmail(from_address, to_addresses, [], subject, '\n'.join(err_msg))
|
|
|
| if options.device_status_dashboard:
|
| perf_tests_results_helper.PrintPerfResult('BotDevices', 'OnlineDevices',
|
| @@ -388,8 +395,9 @@ def main():
|
| f.write(json.dumps(json_data, indent=4))
|
|
|
| num_failed_devs = 0
|
| - for fail_status, device in zip(fail_step_lst, devices):
|
| - if not fail_status:
|
| + for device_ok, device in zip(devices_ok, devices):
|
| + if not device_ok:
|
| + logging.warning('Blacklisting %s', str(device))
|
| device_blacklist.ExtendBlacklist([str(device)])
|
| num_failed_devs += 1
|
|
|
|
|