| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # | 2 # |
| 3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 3 # Copyright (c) 2012 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 logging | 8 import logging |
| 9 import optparse | 9 import optparse |
| 10 import os | 10 import os |
| 11 import smtplib | 11 import smtplib |
| 12 import sys | 12 import sys |
| 13 import re |
| 13 | 14 |
| 14 from pylib import buildbot_report | 15 from pylib import buildbot_report |
| 15 from pylib.android_commands import GetAttachedDevices | 16 from pylib import android_commands |
| 16 from pylib.cmd_helper import GetCmdOutput | 17 from pylib.cmd_helper import GetCmdOutput |
| 17 | 18 |
| 18 | 19 |
| 19 def DeviceInfo(serial): | 20 def DeviceInfo(serial): |
| 20 """Gathers info on a device via various adb calls. | 21 """Gathers info on a device via various adb calls. |
| 21 | 22 |
| 22 Args: | 23 Args: |
| 23 serial: The serial of the attached device to construct info about. | 24 serial: The serial of the attached device to construct info about. |
| 24 | 25 |
| 25 Returns: | 26 Returns: |
| 26 Tuple of device type, build id and report as a string. | 27 Tuple of device type, build id and report as a string. |
| 27 """ | 28 """ |
| 28 | 29 |
| 29 def AdbShellCmd(cmd): | 30 def AdbShellCmd(cmd): |
| 30 return GetCmdOutput('adb -s %s shell %s' % (serial, cmd), | 31 return GetCmdOutput('adb -s %s shell %s' % (serial, cmd), |
| 31 shell=True).strip() | 32 shell=True).strip() |
| 32 | 33 |
| 33 device_type = AdbShellCmd('getprop ro.build.product') | 34 device_type = AdbShellCmd('getprop ro.build.product') |
| 34 device_build = AdbShellCmd('getprop ro.build.id') | 35 device_build = AdbShellCmd('getprop ro.build.id') |
| 35 | 36 |
| 37 setup_wizard_disabled = AdbShellCmd( |
| 38 'getprop ro.setupwizard.mode') == 'DISABLED' |
| 39 battery = AdbShellCmd('dumpsys battery') |
| 40 battery_level = int(re.findall('level: (\d+)', battery)[0]) |
| 41 battery_temp = float(re.findall('temperature: (\d+)', battery)[0])/10 |
| 36 report = ['Device %s (%s)' % (serial, device_type), | 42 report = ['Device %s (%s)' % (serial, device_type), |
| 37 ' Build: %s (%s)' % (device_build, | 43 ' Build: %s (%s)' % (device_build, |
| 38 AdbShellCmd('getprop ro.build.fingerprint')), | 44 AdbShellCmd('getprop ro.build.fingerprint')), |
| 39 ' Battery: %s%%' % AdbShellCmd('dumpsys battery | grep level ' | 45 ' Battery: %s%%' % battery_level, |
| 40 "| awk '{print $2}'"), | 46 ' Battery temp: %s' % battery_temp, |
| 41 ' Battery temp: %s' % AdbShellCmd('dumpsys battery' | |
| 42 '| grep temp ' | |
| 43 "| awk '{print $2}'"), | |
| 44 ' IMEI slice: %s' % AdbShellCmd('dumpsys iphonesubinfo ' | 47 ' IMEI slice: %s' % AdbShellCmd('dumpsys iphonesubinfo ' |
| 45 '| grep Device' | 48 '| grep Device' |
| 46 "| awk '{print $4}'")[-6:], | 49 "| awk '{print $4}'")[-6:], |
| 47 ' Wifi IP: %s' % AdbShellCmd('getprop dhcp.wlan0.ipaddress'), | 50 ' Wifi IP: %s' % AdbShellCmd('getprop dhcp.wlan0.ipaddress'), |
| 48 ''] | 51 ''] |
| 49 | 52 |
| 50 return device_type, device_build, '\n'.join(report) | 53 warnings = [] |
| 54 if battery_level < 5: |
| 55 warnings += ['critically low battery'] |
| 56 if not setup_wizard_disabled: |
| 57 warnings += ['Setup wizard not disabled. Was it provisioned correctly?'] |
| 58 |
| 59 return device_type, device_build, '\n'.join(report), warnings |
| 51 | 60 |
| 52 | 61 |
| 53 def CheckForMissingDevices(options, adb_online_devs): | 62 def CheckForMissingDevices(options, adb_online_devs): |
| 54 """Uses file of previous online devices to detect broken phones. | 63 """Uses file of previous online devices to detect broken phones. |
| 55 | 64 |
| 56 Args: | 65 Args: |
| 57 options: out_dir parameter of options argument is used as the base | 66 options: out_dir parameter of options argument is used as the base |
| 58 directory to load and update the cache file. | 67 directory to load and update the cache file. |
| 59 adb_online_devs: A list of serial numbers of the currently visible | 68 adb_online_devs: A list of serial numbers of the currently visible |
| 60 and online attached devices. | 69 and online attached devices. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 85 # Write devices currently visible plus devices previously seen. | 94 # Write devices currently visible plus devices previously seen. |
| 86 f.write('\n'.join(set(device_list))) | 95 f.write('\n'.join(set(device_list))) |
| 87 | 96 |
| 88 last_devices_path = os.path.join(out_dir, '.last_devices') | 97 last_devices_path = os.path.join(out_dir, '.last_devices') |
| 89 last_devices = ReadDeviceList('.last_devices') | 98 last_devices = ReadDeviceList('.last_devices') |
| 90 | 99 |
| 91 missing_devs = list(set(last_devices) - set(adb_online_devs)) | 100 missing_devs = list(set(last_devices) - set(adb_online_devs)) |
| 92 if missing_devs: | 101 if missing_devs: |
| 93 from_address = 'buildbot@chromium.org' | 102 from_address = 'buildbot@chromium.org' |
| 94 to_address = 'chromium-android-device-alerts@google.com' | 103 to_address = 'chromium-android-device-alerts@google.com' |
| 95 bot_name = os.environ['BUILDBOT_BUILDERNAME'] | 104 bot_name = os.environ.get('BUILDBOT_BUILDERNAME') |
| 96 slave_name = os.environ['BUILDBOT_SLAVENAME'] | 105 slave_name = os.environ.get('BUILDBOT_SLAVENAME') |
| 97 num_online_devs = len(adb_online_devs) | 106 num_online_devs = len(adb_online_devs) |
| 98 subject = 'Devices offline on %s, %s (%d remaining).' % (slave_name, | 107 subject = 'Devices offline on %s, %s (%d remaining).' % (slave_name, |
| 99 bot_name, | 108 bot_name, |
| 100 num_online_devs) | 109 num_online_devs) |
| 101 buildbot_report.PrintWarning() | 110 buildbot_report.PrintWarning() |
| 102 devices_missing_msg = '%d devices not detected.' % len(missing_devs) | 111 devices_missing_msg = '%d devices not detected.' % len(missing_devs) |
| 103 buildbot_report.PrintSummaryText(devices_missing_msg) | 112 buildbot_report.PrintSummaryText(devices_missing_msg) |
| 104 | 113 |
| 105 # TODO(navabi): Debug by printing both output from GetCmdOutput and | 114 # TODO(navabi): Debug by printing both output from GetCmdOutput and |
| 106 # GetAttachedDevices to compare results. | 115 # GetAttachedDevices to compare results. |
| 107 body = '\n'.join( | 116 body = '\n'.join( |
| 108 ['Current online devices: %s' % adb_online_devs, | 117 ['Current online devices: %s' % adb_online_devs, |
| 109 '%s are no longer visible. Were they removed?\n' % missing_devs, | 118 '%s are no longer visible. Were they removed?\n' % missing_devs, |
| 110 'SHERIFF: See go/chrome_device_monitor', | 119 'SHERIFF: See go/chrome_device_monitor', |
| 111 'Cache file: %s\n\n' % last_devices_path, | 120 'Cache file: %s\n\n' % last_devices_path, |
| 112 'adb devices: %s' % GetCmdOutput(['adb', 'devices']), | 121 'adb devices: %s' % GetCmdOutput(['adb', 'devices']), |
| 113 'adb devices(GetAttachedDevices): %s' % GetAttachedDevices()]) | 122 'adb devices(GetAttachedDevices): %s' % |
| 123 android_commands.GetAttachedDevices()]) |
| 114 | 124 |
| 115 print body | 125 print body |
| 116 | 126 |
| 117 # Only send email if the first time a particular device goes offline | 127 # Only send email if the first time a particular device goes offline |
| 118 last_missing = ReadDeviceList('.last_missing') | 128 last_missing = ReadDeviceList('.last_missing') |
| 119 new_missing_devs = set(missing_devs) - set(last_missing) | 129 new_missing_devs = set(missing_devs) - set(last_missing) |
| 120 | 130 |
| 121 if new_missing_devs: | 131 if new_missing_devs and bot_name: |
| 122 msg_body = '\r\n'.join( | 132 msg_body = '\r\n'.join( |
| 123 ['From: %s' % from_address, | 133 ['From: %s' % from_address, |
| 124 'To: %s' % to_address, | 134 'To: %s' % to_address, |
| 125 'Subject: %s' % subject, | 135 'Subject: %s' % subject, |
| 126 '', body]) | 136 '', body]) |
| 127 try: | 137 try: |
| 128 server = smtplib.SMTP('localhost') | 138 server = smtplib.SMTP('localhost') |
| 129 server.sendmail(from_address, [to_address], msg_body) | 139 server.sendmail(from_address, [to_address], msg_body) |
| 130 server.quit() | 140 server.quit() |
| 131 except Exception as e: | 141 except Exception as e: |
| (...skipping 14 matching lines...) Expand all Loading... |
| 146 parser = optparse.OptionParser() | 156 parser = optparse.OptionParser() |
| 147 parser.add_option('', '--out-dir', | 157 parser.add_option('', '--out-dir', |
| 148 help='Directory where the device path is stored', | 158 help='Directory where the device path is stored', |
| 149 default=os.path.join(os.path.dirname(__file__), '..', | 159 default=os.path.join(os.path.dirname(__file__), '..', |
| 150 '..', 'out')) | 160 '..', 'out')) |
| 151 | 161 |
| 152 options, args = parser.parse_args() | 162 options, args = parser.parse_args() |
| 153 if args: | 163 if args: |
| 154 parser.error('Unknown options %s' % args) | 164 parser.error('Unknown options %s' % args) |
| 155 buildbot_report.PrintNamedStep('Device Status Check') | 165 buildbot_report.PrintNamedStep('Device Status Check') |
| 156 devices = GetAttachedDevices() | 166 devices = android_commands.GetAttachedDevices() |
| 157 types, builds, reports = [], [], [] | 167 types, builds, reports, errors = [], [], [], [] |
| 158 if devices: | 168 if devices: |
| 159 types, builds, reports = zip(*[DeviceInfo(dev) for dev in devices]) | 169 types, builds, reports, errors = zip(*[DeviceInfo(dev) for dev in devices]) |
| 160 | 170 |
| 161 unique_types = list(set(types)) | 171 unique_types = list(set(types)) |
| 162 unique_builds = list(set(builds)) | 172 unique_builds = list(set(builds)) |
| 163 | 173 |
| 164 buildbot_report.PrintMsg('Online devices: %d. Device types %s, builds %s' | 174 buildbot_report.PrintMsg('Online devices: %d. Device types %s, builds %s' |
| 165 % (len(devices), unique_types, unique_builds)) | 175 % (len(devices), unique_types, unique_builds)) |
| 166 print '\n'.join(reports) | 176 print '\n'.join(reports) |
| 177 |
| 178 full_errors = [] |
| 179 for serial, device_errors in zip(devices, errors): |
| 180 full_errors.extend('%s: %s' % (serial, error) for error in device_errors) |
| 181 if full_errors: |
| 182 buildbot_report.PrintWarning() |
| 183 print '\n'.join(full_errors) |
| 184 |
| 167 CheckForMissingDevices(options, devices) | 185 CheckForMissingDevices(options, devices) |
| 168 | 186 |
| 169 if __name__ == '__main__': | 187 if __name__ == '__main__': |
| 170 sys.exit(main()) | 188 sys.exit(main()) |
| OLD | NEW |