media/webrtc/trunk/build/android/device_status_check.py

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/media/webrtc/trunk/build/android/device_status_check.py	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,170 @@
     1.4 +#!/usr/bin/env python
     1.5 +#
     1.6 +# Copyright (c) 2012 The Chromium Authors. All rights reserved.
     1.7 +# Use of this source code is governed by a BSD-style license that can be
     1.8 +# found in the LICENSE file.
     1.9 +
    1.10 +"""A class to keep track of devices across builds and report state."""
    1.11 +import logging
    1.12 +import optparse
    1.13 +import os
    1.14 +import smtplib
    1.15 +import sys
    1.16 +
    1.17 +from pylib import buildbot_report
    1.18 +from pylib.android_commands import GetAttachedDevices
    1.19 +from pylib.cmd_helper import GetCmdOutput
    1.20 +
    1.21 +
    1.22 +def DeviceInfo(serial):
    1.23 +  """Gathers info on a device via various adb calls.
    1.24 +
    1.25 +  Args:
    1.26 +    serial: The serial of the attached device to construct info about.
    1.27 +
    1.28 +  Returns:
    1.29 +    Tuple of device type, build id and report as a string.
    1.30 +  """
    1.31 +
    1.32 +  def AdbShellCmd(cmd):
    1.33 +    return GetCmdOutput('adb -s %s shell %s' % (serial, cmd),
    1.34 +                        shell=True).strip()
    1.35 +
    1.36 +  device_type = AdbShellCmd('getprop ro.build.product')
    1.37 +  device_build = AdbShellCmd('getprop ro.build.id')
    1.38 +
    1.39 +  report = ['Device %s (%s)' % (serial, device_type),
    1.40 +            '  Build: %s (%s)' % (device_build,
    1.41 +                                  AdbShellCmd('getprop ro.build.fingerprint')),
    1.42 +            '  Battery: %s%%' % AdbShellCmd('dumpsys battery | grep level '
    1.43 +                                            "| awk '{print $2}'"),
    1.44 +            '  Battery temp: %s' % AdbShellCmd('dumpsys battery'
    1.45 +                                               '| grep temp '
    1.46 +                                               "| awk '{print $2}'"),
    1.47 +            '  IMEI slice: %s' % AdbShellCmd('dumpsys iphonesubinfo '
    1.48 +                                             '| grep Device'
    1.49 +                                             "| awk '{print $4}'")[-6:],
    1.50 +            '  Wifi IP: %s' % AdbShellCmd('getprop dhcp.wlan0.ipaddress'),
    1.51 +            '']
    1.52 +
    1.53 +  return device_type, device_build, '\n'.join(report)
    1.54 +
    1.55 +
    1.56 +def CheckForMissingDevices(options, adb_online_devs):
    1.57 +  """Uses file of previous online devices to detect broken phones.
    1.58 +
    1.59 +  Args:
    1.60 +    options: out_dir parameter of options argument is used as the base
    1.61 +             directory to load and update the cache file.
    1.62 +    adb_online_devs: A list of serial numbers of the currently visible
    1.63 +                     and online attached devices.
    1.64 +  """
    1.65 +  # TODO(navabi): remove this once the bug that causes different number
    1.66 +  # of devices to be detected between calls is fixed.
    1.67 +  logger = logging.getLogger()
    1.68 +  logger.setLevel(logging.INFO)
    1.69 +
    1.70 +  out_dir = os.path.abspath(options.out_dir)
    1.71 +
    1.72 +  def ReadDeviceList(file_name):
    1.73 +    devices_path = os.path.join(out_dir, file_name)
    1.74 +    devices = []
    1.75 +    try:
    1.76 +      with open(devices_path) as f:
    1.77 +        devices = f.read().splitlines()
    1.78 +    except IOError:
    1.79 +      # Ignore error, file might not exist
    1.80 +      pass
    1.81 +    return devices
    1.82 +
    1.83 +  def WriteDeviceList(file_name, device_list):
    1.84 +    path = os.path.join(out_dir, file_name)
    1.85 +    if not os.path.exists(out_dir):
    1.86 +      os.makedirs(out_dir)
    1.87 +    with open(path, 'w') as f:
    1.88 +      # Write devices currently visible plus devices previously seen.
    1.89 +      f.write('\n'.join(set(device_list)))
    1.90 +
    1.91 +  last_devices_path = os.path.join(out_dir, '.last_devices')
    1.92 +  last_devices = ReadDeviceList('.last_devices')
    1.93 +
    1.94 +  missing_devs = list(set(last_devices) - set(adb_online_devs))
    1.95 +  if missing_devs:
    1.96 +    from_address = 'buildbot@chromium.org'
    1.97 +    to_address = 'chromium-android-device-alerts@google.com'
    1.98 +    bot_name = os.environ['BUILDBOT_BUILDERNAME']
    1.99 +    slave_name = os.environ['BUILDBOT_SLAVENAME']
   1.100 +    num_online_devs = len(adb_online_devs)
   1.101 +    subject = 'Devices offline on %s, %s (%d remaining).' % (slave_name,
   1.102 +                                                             bot_name,
   1.103 +                                                             num_online_devs)
   1.104 +    buildbot_report.PrintWarning()
   1.105 +    devices_missing_msg = '%d devices not detected.' % len(missing_devs)
   1.106 +    buildbot_report.PrintSummaryText(devices_missing_msg)
   1.107 +
   1.108 +    # TODO(navabi): Debug by printing both output from GetCmdOutput and
   1.109 +    # GetAttachedDevices to compare results.
   1.110 +    body = '\n'.join(
   1.111 +        ['Current online devices: %s' % adb_online_devs,
   1.112 +         '%s are no longer visible. Were they removed?\n' % missing_devs,
   1.113 +         'SHERIFF: See go/chrome_device_monitor',
   1.114 +         'Cache file: %s\n\n' % last_devices_path,
   1.115 +         'adb devices: %s' % GetCmdOutput(['adb', 'devices']),
   1.116 +         'adb devices(GetAttachedDevices): %s' % GetAttachedDevices()])
   1.117 +
   1.118 +    print body
   1.119 +
   1.120 +    # Only send email if the first time a particular device goes offline
   1.121 +    last_missing = ReadDeviceList('.last_missing')
   1.122 +    new_missing_devs = set(missing_devs) - set(last_missing)
   1.123 +
   1.124 +    if new_missing_devs:
   1.125 +      msg_body = '\r\n'.join(
   1.126 +          ['From: %s' % from_address,
   1.127 +           'To: %s' % to_address,
   1.128 +           'Subject: %s' % subject,
   1.129 +           '', body])
   1.130 +      try:
   1.131 +        server = smtplib.SMTP('localhost')
   1.132 +        server.sendmail(from_address, [to_address], msg_body)
   1.133 +        server.quit()
   1.134 +      except Exception as e:
   1.135 +        print 'Failed to send alert email. Error: %s' % e
   1.136 +  else:
   1.137 +    new_devs = set(adb_online_devs) - set(last_devices)
   1.138 +    if new_devs and os.path.exists(last_devices_path):
   1.139 +      buildbot_report.PrintWarning()
   1.140 +      buildbot_report.PrintSummaryText(
   1.141 +          '%d new devices detected' % len(new_devs))
   1.142 +      print ('New devices detected %s. And now back to your '
   1.143 +             'regularly scheduled program.' % list(new_devs))
   1.144 +  WriteDeviceList('.last_devices', (adb_online_devs + last_devices))
   1.145 +  WriteDeviceList('.last_missing', missing_devs)
   1.146 +
   1.147 +
   1.148 +def main():
   1.149 +  parser = optparse.OptionParser()
   1.150 +  parser.add_option('', '--out-dir',
   1.151 +                    help='Directory where the device path is stored',
   1.152 +                    default=os.path.join(os.path.dirname(__file__), '..',
   1.153 +                                         '..', 'out'))
   1.154 +
   1.155 +  options, args = parser.parse_args()
   1.156 +  if args:
   1.157 +    parser.error('Unknown options %s' % args)
   1.158 +  buildbot_report.PrintNamedStep('Device Status Check')
   1.159 +  devices = GetAttachedDevices()
   1.160 +  types, builds, reports = [], [], []
   1.161 +  if devices:
   1.162 +    types, builds, reports = zip(*[DeviceInfo(dev) for dev in devices])
   1.163 +
   1.164 +  unique_types = list(set(types))
   1.165 +  unique_builds = list(set(builds))
   1.166 +
   1.167 +  buildbot_report.PrintMsg('Online devices: %d. Device types %s, builds %s'
   1.168 +                           % (len(devices), unique_types, unique_builds))
   1.169 +  print '\n'.join(reports)
   1.170 +  CheckForMissingDevices(options, devices)
   1.171 +
   1.172 +if __name__ == '__main__':
   1.173 +  sys.exit(main())

mercurial