diff -r 000000000000 -r 6474c204b198 media/webrtc/trunk/build/android/device_status_check.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/media/webrtc/trunk/build/android/device_status_check.py Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,170 @@ +#!/usr/bin/env python +# +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""A class to keep track of devices across builds and report state.""" +import logging +import optparse +import os +import smtplib +import sys + +from pylib import buildbot_report +from pylib.android_commands import GetAttachedDevices +from pylib.cmd_helper import GetCmdOutput + + +def DeviceInfo(serial): + """Gathers info on a device via various adb calls. + + Args: + serial: The serial of the attached device to construct info about. + + Returns: + Tuple of device type, build id and report as a string. + """ + + def AdbShellCmd(cmd): + return GetCmdOutput('adb -s %s shell %s' % (serial, cmd), + shell=True).strip() + + device_type = AdbShellCmd('getprop ro.build.product') + device_build = AdbShellCmd('getprop ro.build.id') + + report = ['Device %s (%s)' % (serial, device_type), + ' Build: %s (%s)' % (device_build, + AdbShellCmd('getprop ro.build.fingerprint')), + ' Battery: %s%%' % AdbShellCmd('dumpsys battery | grep level ' + "| awk '{print $2}'"), + ' Battery temp: %s' % AdbShellCmd('dumpsys battery' + '| grep temp ' + "| awk '{print $2}'"), + ' IMEI slice: %s' % AdbShellCmd('dumpsys iphonesubinfo ' + '| grep Device' + "| awk '{print $4}'")[-6:], + ' Wifi IP: %s' % AdbShellCmd('getprop dhcp.wlan0.ipaddress'), + ''] + + return device_type, device_build, '\n'.join(report) + + +def CheckForMissingDevices(options, adb_online_devs): + """Uses file of previous online devices to detect broken phones. + + Args: + options: out_dir parameter of options argument is used as the base + directory to load and update the cache file. + 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) + + def ReadDeviceList(file_name): + devices_path = os.path.join(out_dir, file_name) + devices = [] + try: + with open(devices_path) as f: + devices = f.read().splitlines() + except IOError: + # Ignore error, file might not exist + pass + return devices + + def WriteDeviceList(file_name, device_list): + path = os.path.join(out_dir, file_name) + if not os.path.exists(out_dir): + os.makedirs(out_dir) + with open(path, 'w') as f: + # Write devices currently visible plus devices previously seen. + f.write('\n'.join(set(device_list))) + + last_devices_path = os.path.join(out_dir, '.last_devices') + last_devices = ReadDeviceList('.last_devices') + + missing_devs = list(set(last_devices) - set(adb_online_devs)) + if missing_devs: + from_address = 'buildbot@chromium.org' + to_address = 'chromium-android-device-alerts@google.com' + bot_name = os.environ['BUILDBOT_BUILDERNAME'] + slave_name = os.environ['BUILDBOT_SLAVENAME'] + num_online_devs = len(adb_online_devs) + subject = 'Devices offline on %s, %s (%d remaining).' % (slave_name, + bot_name, + num_online_devs) + buildbot_report.PrintWarning() + devices_missing_msg = '%d devices not detected.' % len(missing_devs) + buildbot_report.PrintSummaryText(devices_missing_msg) + + # TODO(navabi): Debug by printing both output from GetCmdOutput and + # GetAttachedDevices to compare results. + body = '\n'.join( + ['Current online devices: %s' % adb_online_devs, + '%s are no longer visible. Were they removed?\n' % missing_devs, + 'SHERIFF: See go/chrome_device_monitor', + 'Cache file: %s\n\n' % last_devices_path, + 'adb devices: %s' % GetCmdOutput(['adb', 'devices']), + 'adb devices(GetAttachedDevices): %s' % GetAttachedDevices()]) + + print body + + # Only send email if the first time a particular device goes offline + last_missing = ReadDeviceList('.last_missing') + new_missing_devs = set(missing_devs) - set(last_missing) + + if new_missing_devs: + msg_body = '\r\n'.join( + ['From: %s' % from_address, + 'To: %s' % to_address, + 'Subject: %s' % subject, + '', body]) + try: + server = smtplib.SMTP('localhost') + server.sendmail(from_address, [to_address], msg_body) + server.quit() + except Exception as e: + print 'Failed to send alert email. Error: %s' % e + else: + new_devs = set(adb_online_devs) - set(last_devices) + if new_devs and os.path.exists(last_devices_path): + buildbot_report.PrintWarning() + buildbot_report.PrintSummaryText( + '%d new devices detected' % len(new_devs)) + print ('New devices detected %s. And now back to your ' + 'regularly scheduled program.' % list(new_devs)) + WriteDeviceList('.last_devices', (adb_online_devs + last_devices)) + WriteDeviceList('.last_missing', missing_devs) + + +def main(): + parser = optparse.OptionParser() + parser.add_option('', '--out-dir', + help='Directory where the device path is stored', + default=os.path.join(os.path.dirname(__file__), '..', + '..', 'out')) + + options, args = parser.parse_args() + if args: + parser.error('Unknown options %s' % args) + buildbot_report.PrintNamedStep('Device Status Check') + devices = GetAttachedDevices() + types, builds, reports = [], [], [] + if devices: + types, builds, reports = zip(*[DeviceInfo(dev) for dev in devices]) + + unique_types = list(set(types)) + unique_builds = list(set(builds)) + + buildbot_report.PrintMsg('Online devices: %d. Device types %s, builds %s' + % (len(devices), unique_types, unique_builds)) + print '\n'.join(reports) + CheckForMissingDevices(options, devices) + +if __name__ == '__main__': + sys.exit(main())