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

Side by Side Diff: build/android/device_status_check.py

Issue 12382006: Check if mantarays are charging, and alert on all Android device errors. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed the last nit Created 7 years, 9 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
(...skipping 15 matching lines...) Expand all
26 Returns: 26 Returns:
27 Tuple of device type, build id and report as a string. 27 Tuple of device type, build id and report as a string.
28 """ 28 """
29 29
30 def AdbShellCmd(cmd): 30 def AdbShellCmd(cmd):
31 return GetCmdOutput('adb -s %s shell %s' % (serial, cmd), 31 return GetCmdOutput('adb -s %s shell %s' % (serial, cmd),
32 shell=True).strip() 32 shell=True).strip()
33 33
34 device_type = AdbShellCmd('getprop ro.build.product') 34 device_type = AdbShellCmd('getprop ro.build.product')
35 device_build = AdbShellCmd('getprop ro.build.id') 35 device_build = AdbShellCmd('getprop ro.build.id')
36 device_product_name = AdbShellCmd('getprop ro.product.name')
36 37
37 setup_wizard_disabled = AdbShellCmd( 38 setup_wizard_disabled = AdbShellCmd(
38 'getprop ro.setupwizard.mode') == 'DISABLED' 39 'getprop ro.setupwizard.mode') == 'DISABLED'
39 battery = AdbShellCmd('dumpsys battery') 40 battery = AdbShellCmd('dumpsys battery')
40 if 'Error' in battery: 41 if 'Error' in battery:
42 ac_power = 'Unknown'
41 battery_level = 'Unknown' 43 battery_level = 'Unknown'
42 battery_temp = 'Unknown' 44 battery_temp = 'Unknown'
43 else: 45 else:
46 ac_power = re.findall('AC powered: (\w+)', battery)[0]
44 battery_level = int(re.findall('level: (\d+)', battery)[0]) 47 battery_level = int(re.findall('level: (\d+)', battery)[0])
45 battery_temp = float(re.findall('temperature: (\d+)', battery)[0]) / 10 48 battery_temp = float(re.findall('temperature: (\d+)', battery)[0]) / 10
46 report = ['Device %s (%s)' % (serial, device_type), 49 report = ['Device %s (%s)' % (serial, device_type),
47 ' Build: %s (%s)' % (device_build, 50 ' Build: %s (%s)' % (device_build,
48 AdbShellCmd('getprop ro.build.fingerprint')), 51 AdbShellCmd('getprop ro.build.fingerprint')),
49 ' Battery: %s%%' % battery_level, 52 ' Battery: %s%%' % battery_level,
50 ' Battery temp: %s' % battery_temp, 53 ' Battery temp: %s' % battery_temp,
51 ' IMEI slice: %s' % AdbShellCmd('dumpsys iphonesubinfo ' 54 ' IMEI slice: %s' % AdbShellCmd('dumpsys iphonesubinfo '
52 '| grep Device' 55 '| grep Device'
53 "| awk '{print $4}'")[-6:], 56 "| awk '{print $4}'")[-6:],
54 ' Wifi IP: %s' % AdbShellCmd('getprop dhcp.wlan0.ipaddress'), 57 ' Wifi IP: %s' % AdbShellCmd('getprop dhcp.wlan0.ipaddress'),
55 ''] 58 '']
56 59
57 warnings = [] 60 errors = []
58 if battery_level < 5: 61 if battery_level < 5:
59 warnings += ['critically low battery'] 62 errors += ['Device critically low in battery.']
60 if not setup_wizard_disabled: 63 if not setup_wizard_disabled:
61 warnings += ['Setup wizard not disabled. Was it provisioned correctly?'] 64 errors += ['Setup wizard not disabled. Was it provisioned correctly?']
65 if device_product_name == 'mantaray' and ac_power != 'true':
66 errors += ['Mantaray device not connected to AC power.']
62 67
63 return device_type, device_build, '\n'.join(report), warnings 68 return device_type, device_build, '\n'.join(report), errors
64 69
65 70
66 def CheckForMissingDevices(options, adb_online_devs): 71 def CheckForMissingDevices(options, adb_online_devs):
67 """Uses file of previous online devices to detect broken phones. 72 """Uses file of previous online devices to detect broken phones.
68 73
69 Args: 74 Args:
70 options: out_dir parameter of options argument is used as the base 75 options: out_dir parameter of options argument is used as the base
71 directory to load and update the cache file. 76 directory to load and update the cache file.
72 adb_online_devs: A list of serial numbers of the currently visible 77 adb_online_devs: A list of serial numbers of the currently visible
73 and online attached devices. 78 and online attached devices.
(...skipping 19 matching lines...) Expand all
93 def WriteDeviceList(file_name, device_list): 98 def WriteDeviceList(file_name, device_list):
94 path = os.path.join(out_dir, file_name) 99 path = os.path.join(out_dir, file_name)
95 if not os.path.exists(out_dir): 100 if not os.path.exists(out_dir):
96 os.makedirs(out_dir) 101 os.makedirs(out_dir)
97 with open(path, 'w') as f: 102 with open(path, 'w') as f:
98 # Write devices currently visible plus devices previously seen. 103 # Write devices currently visible plus devices previously seen.
99 f.write('\n'.join(set(device_list))) 104 f.write('\n'.join(set(device_list)))
100 105
101 last_devices_path = os.path.join(out_dir, '.last_devices') 106 last_devices_path = os.path.join(out_dir, '.last_devices')
102 last_devices = ReadDeviceList('.last_devices') 107 last_devices = ReadDeviceList('.last_devices')
108 missing_devs = list(set(last_devices) - set(adb_online_devs))
103 109
104 missing_devs = list(set(last_devices) - set(adb_online_devs)) 110 WriteDeviceList('.last_devices', (adb_online_devs + last_devices))
111 WriteDeviceList('.last_missing', missing_devs)
112
105 if missing_devs: 113 if missing_devs:
106 from_address = 'buildbot@chromium.org'
107 to_address = 'chromium-android-device-alerts@google.com'
108 bot_name = os.environ.get('BUILDBOT_BUILDERNAME')
109 slave_name = os.environ.get('BUILDBOT_SLAVENAME')
110 num_online_devs = len(adb_online_devs)
111 subject = 'Devices offline on %s, %s (%d remaining).' % (slave_name,
112 bot_name,
113 num_online_devs)
114 buildbot_report.PrintWarning()
115 devices_missing_msg = '%d devices not detected.' % len(missing_devs) 114 devices_missing_msg = '%d devices not detected.' % len(missing_devs)
116 buildbot_report.PrintSummaryText(devices_missing_msg) 115 buildbot_report.PrintSummaryText(devices_missing_msg)
117 116
118 # TODO(navabi): Debug by printing both output from GetCmdOutput and 117 # TODO(navabi): Debug by printing both output from GetCmdOutput and
119 # GetAttachedDevices to compare results. 118 # GetAttachedDevices to compare results.
120 body = '\n'.join( 119 return ['Current online devices: %s' % adb_online_devs,
121 ['Current online devices: %s' % adb_online_devs, 120 '%s are no longer visible. Were they removed?\n' % missing_devs,
122 '%s are no longer visible. Were they removed?\n' % missing_devs, 121 'SHERIFF: See go/chrome_device_monitor',
123 'SHERIFF: See go/chrome_device_monitor', 122 'Cache file: %s\n\n' % last_devices_path,
124 'Cache file: %s\n\n' % last_devices_path, 123 'adb devices: %s' % GetCmdOutput(['adb', 'devices']),
125 'adb devices: %s' % GetCmdOutput(['adb', 'devices']), 124 'adb devices(GetAttachedDevices): %s' %
126 'adb devices(GetAttachedDevices): %s' % 125 android_commands.GetAttachedDevices()]
127 android_commands.GetAttachedDevices()])
128
129 print body
130
131 # Only send email if the first time a particular device goes offline
132 last_missing = ReadDeviceList('.last_missing')
133 new_missing_devs = set(missing_devs) - set(last_missing)
134
135 if new_missing_devs and bot_name:
136 msg_body = '\r\n'.join(
137 ['From: %s' % from_address,
138 'To: %s' % to_address,
139 'Subject: %s' % subject,
140 '', body])
141 try:
142 server = smtplib.SMTP('localhost')
143 server.sendmail(from_address, [to_address], msg_body)
144 server.quit()
145 except Exception as e:
146 print 'Failed to send alert email. Error: %s' % e
147 else: 126 else:
148 new_devs = set(adb_online_devs) - set(last_devices) 127 new_devs = set(adb_online_devs) - set(last_devices)
149 if new_devs and os.path.exists(last_devices_path): 128 if new_devs and os.path.exists(last_devices_path):
150 buildbot_report.PrintWarning() 129 buildbot_report.PrintWarning()
151 buildbot_report.PrintSummaryText( 130 buildbot_report.PrintSummaryText(
152 '%d new devices detected' % len(new_devs)) 131 '%d new devices detected' % len(new_devs))
153 print ('New devices detected %s. And now back to your ' 132 print ('New devices detected %s. And now back to your '
154 'regularly scheduled program.' % list(new_devs)) 133 'regularly scheduled program.' % list(new_devs))
155 WriteDeviceList('.last_devices', (adb_online_devs + last_devices)) 134
156 WriteDeviceList('.last_missing', missing_devs) 135
136 def SendDeviceStatusAlert(msg):
137 from_address = 'buildbot@chromium.org'
138 to_address = 'chromium-android-device-alerts@google.com'
139 bot_name = os.environ.get('BUILDBOT_BUILDERNAME')
140 slave_name = os.environ.get('BUILDBOT_SLAVENAME')
141 subject = 'Device status check errors on %s, %s.' % (slave_name, bot_name)
142 msg_body = '\r\n'.join(['From: %s' % from_address, 'To: %s' % to_address,
143 'Subject: %s' % subject, '', msg])
144 try:
145 server = smtplib.SMTP('localhost')
146 server.sendmail(from_address, [to_address], msg_body)
147 server.quit()
148 except Exception as e:
149 print 'Failed to send alert email. Error: %s' % e
157 150
158 151
159 def main(): 152 def main():
160 parser = optparse.OptionParser() 153 parser = optparse.OptionParser()
161 parser.add_option('', '--out-dir', 154 parser.add_option('', '--out-dir',
162 help='Directory where the device path is stored', 155 help='Directory where the device path is stored',
163 default=os.path.join(os.path.dirname(__file__), '..', 156 default=os.path.join(os.path.dirname(__file__), '..',
164 '..', 'out')) 157 '..', 'out'))
165 158
166 options, args = parser.parse_args() 159 options, args = parser.parse_args()
167 if args: 160 if args:
168 parser.error('Unknown options %s' % args) 161 parser.error('Unknown options %s' % args)
169 devices = android_commands.GetAttachedDevices() 162 devices = android_commands.GetAttachedDevices()
170 types, builds, reports, errors = [], [], [], [] 163 types, builds, reports, errors = [], [], [], []
171 if devices: 164 if devices:
172 types, builds, reports, errors = zip(*[DeviceInfo(dev) for dev in devices]) 165 types, builds, reports, errors = zip(*[DeviceInfo(dev) for dev in devices])
173 166
167 err_msg = CheckForMissingDevices(options, devices) or []
168
174 unique_types = list(set(types)) 169 unique_types = list(set(types))
175 unique_builds = list(set(builds)) 170 unique_builds = list(set(builds))
176 171
177 buildbot_report.PrintMsg('Online devices: %d. Device types %s, builds %s' 172 buildbot_report.PrintMsg('Online devices: %d. Device types %s, builds %s'
178 % (len(devices), unique_types, unique_builds)) 173 % (len(devices), unique_types, unique_builds))
179 print '\n'.join(reports) 174 print '\n'.join(reports)
180 175
181 full_errors = [] 176 for serial, dev_errors in zip(devices, errors):
182 for serial, device_errors in zip(devices, errors): 177 if dev_errors:
183 full_errors.extend('%s: %s' % (serial, error) for error in device_errors) 178 err_msg += ['%s errors:' % serial]
184 if full_errors: 179 err_msg += [' %s' % error for error in dev_errors]
180
181 if err_msg:
185 buildbot_report.PrintWarning() 182 buildbot_report.PrintWarning()
186 print '\n'.join(full_errors) 183 msg = '\n'.join(err_msg)
184 print msg
185 SendDeviceStatusAlert(msg)
186 return 1
187 187
188 CheckForMissingDevices(options, devices)
189 188
190 if __name__ == '__main__': 189 if __name__ == '__main__':
191 sys.exit(main()) 190 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698