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

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: 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]
Isaac (away) 2013/03/05 07:12:22 This will throw an exception if the regex does not
Siva Chandra 2013/03/13 02:18:33 As per xsdg@, yes.
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 warnings = []
61 errors = []
58 if battery_level < 5: 62 if battery_level < 5:
59 warnings += ['critically low battery'] 63 warnings += ['\tDevice critically low in battery.\n']
60 if not setup_wizard_disabled: 64 if not setup_wizard_disabled:
61 warnings += ['Setup wizard not disabled. Was it provisioned correctly?'] 65 warnings += ['\tSetup wizard not disabled. Was it provisioned correctly?\n']
66 if device_product_name == 'mantaray' and ac_power == 'false':
Isaac (away) 2013/03/05 07:12:22 I would prefer a positive check, i.e. ac_power !=
Siva Chandra 2013/03/13 02:18:33 Done.
67 errors += ['\tMantaray device not connected to AC power.\n']
68 if warnings:
69 warnings = [''.join(warnings)]
Isaac (away) 2013/03/05 07:12:22 What is this code for?
Siva Chandra 2013/03/13 02:18:33 Now removed.
70 if errors:
71 errors = [''.join(errors)]
62 72
63 return device_type, device_build, '\n'.join(report), warnings 73 return device_type, device_build, '\n'.join(report), warnings, errors
64 74
65 75
66 def CheckForMissingDevices(options, adb_online_devs): 76 def CheckForMissingDevices(options, adb_online_devs):
67 """Uses file of previous online devices to detect broken phones. 77 """Uses file of previous online devices to detect broken phones.
68 78
69 Args: 79 Args:
70 options: out_dir parameter of options argument is used as the base 80 options: out_dir parameter of options argument is used as the base
71 directory to load and update the cache file. 81 directory to load and update the cache file.
72 adb_online_devs: A list of serial numbers of the currently visible 82 adb_online_devs: A list of serial numbers of the currently visible
73 and online attached devices. 83 and online attached devices.
(...skipping 21 matching lines...) Expand all
95 if not os.path.exists(out_dir): 105 if not os.path.exists(out_dir):
96 os.makedirs(out_dir) 106 os.makedirs(out_dir)
97 with open(path, 'w') as f: 107 with open(path, 'w') as f:
98 # Write devices currently visible plus devices previously seen. 108 # Write devices currently visible plus devices previously seen.
99 f.write('\n'.join(set(device_list))) 109 f.write('\n'.join(set(device_list)))
100 110
101 last_devices_path = os.path.join(out_dir, '.last_devices') 111 last_devices_path = os.path.join(out_dir, '.last_devices')
102 last_devices = ReadDeviceList('.last_devices') 112 last_devices = ReadDeviceList('.last_devices')
103 113
104 missing_devs = list(set(last_devices) - set(adb_online_devs)) 114 missing_devs = list(set(last_devices) - set(adb_online_devs))
115 err_msg = ''
105 if missing_devs: 116 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() 117 buildbot_report.PrintWarning()
115 devices_missing_msg = '%d devices not detected.' % len(missing_devs) 118 devices_missing_msg = '%d devices not detected.' % len(missing_devs)
116 buildbot_report.PrintSummaryText(devices_missing_msg) 119 buildbot_report.PrintSummaryText(devices_missing_msg)
117 120
118 # TODO(navabi): Debug by printing both output from GetCmdOutput and 121 # TODO(navabi): Debug by printing both output from GetCmdOutput and
119 # GetAttachedDevices to compare results. 122 # GetAttachedDevices to compare results.
120 body = '\n'.join( 123 err = '\n'.join(
121 ['Current online devices: %s' % adb_online_devs, 124 ['Current online devices: %s' % adb_online_devs,
122 '%s are no longer visible. Were they removed?\n' % missing_devs, 125 '%s are no longer visible. Were they removed?\n' % missing_devs,
123 'SHERIFF: See go/chrome_device_monitor', 126 'SHERIFF: See go/chrome_device_monitor',
124 'Cache file: %s\n\n' % last_devices_path, 127 'Cache file: %s\n\n' % last_devices_path,
125 'adb devices: %s' % GetCmdOutput(['adb', 'devices']), 128 'adb devices: %s' % GetCmdOutput(['adb', 'devices']),
126 'adb devices(GetAttachedDevices): %s' % 129 'adb devices(GetAttachedDevices): %s' %
127 android_commands.GetAttachedDevices()]) 130 android_commands.GetAttachedDevices()])
128 131
129 print body 132 print err
130 133
131 # Only send email if the first time a particular device goes offline 134 # Only send email if the first time a particular device goes offline
132 last_missing = ReadDeviceList('.last_missing') 135 last_missing = ReadDeviceList('.last_missing')
133 new_missing_devs = set(missing_devs) - set(last_missing) 136 new_missing_devs = set(missing_devs) - set(last_missing)
134 137
135 if new_missing_devs and bot_name: 138 if new_missing_devs:
136 msg_body = '\r\n'.join( 139 err_msg = err
Isaac (away) 2013/03/05 07:12:22 Just create the message here and return directly
Siva Chandra 2013/03/13 02:18:33 Done.
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: 140 else:
148 new_devs = set(adb_online_devs) - set(last_devices) 141 new_devs = set(adb_online_devs) - set(last_devices)
149 if new_devs and os.path.exists(last_devices_path): 142 if new_devs and os.path.exists(last_devices_path):
150 buildbot_report.PrintWarning() 143 buildbot_report.PrintWarning()
151 buildbot_report.PrintSummaryText( 144 buildbot_report.PrintSummaryText(
152 '%d new devices detected' % len(new_devs)) 145 '%d new devices detected' % len(new_devs))
153 print ('New devices detected %s. And now back to your ' 146 print ('New devices detected %s. And now back to your '
154 'regularly scheduled program.' % list(new_devs)) 147 'regularly scheduled program.' % list(new_devs))
155 WriteDeviceList('.last_devices', (adb_online_devs + last_devices)) 148 WriteDeviceList('.last_devices', (adb_online_devs + last_devices))
156 WriteDeviceList('.last_missing', missing_devs) 149 WriteDeviceList('.last_missing', missing_devs)
157 150
151 return err_msg
152
153
154 def SendDeviceStatusAlert(msg):
155 if not msg:
156 return
Isaac (away) 2013/03/05 07:12:22 remove 155-156. Don't call this function if you d
Siva Chandra 2013/03/13 02:18:33 Done.
157 from_address = 'buildbot@chromium.org'
158 to_address = 'chromium-android-device-alerts@google.com'
159 bot_name = os.environ.get('BUILDBOT_BUILDERNAME')
160 slave_name = os.environ.get('BUILDBOT_SLAVENAME')
161 subject = 'Device status check errors on %s, %s.' % (slave_name, bot_name)
162 msg_body = '\r\n'.join(['From: %s' % from_address, 'To: %s' % to_address,
163 'Subject: %s' % subject, '', msg])
164 try:
165 server = smtplib.SMTP('localhost')
166 server.sendmail(from_address, [to_address], msg_body)
167 server.quit()
168 except Exception as e:
169 print 'Failed to send alert email. Error: %s' % e
170
158 171
159 def main(): 172 def main():
160 parser = optparse.OptionParser() 173 parser = optparse.OptionParser()
161 parser.add_option('', '--out-dir', 174 parser.add_option('', '--out-dir',
162 help='Directory where the device path is stored', 175 help='Directory where the device path is stored',
163 default=os.path.join(os.path.dirname(__file__), '..', 176 default=os.path.join(os.path.dirname(__file__), '..',
164 '..', 'out')) 177 '..', 'out'))
165 178
166 options, args = parser.parse_args() 179 options, args = parser.parse_args()
167 if args: 180 if args:
168 parser.error('Unknown options %s' % args) 181 parser.error('Unknown options %s' % args)
169 devices = android_commands.GetAttachedDevices() 182 devices = android_commands.GetAttachedDevices()
170 types, builds, reports, errors = [], [], [], [] 183 types, builds, reports, warnings, errors = [], [], [], [], []
Isaac (away) 2013/03/05 07:12:22 It's not clear to me that we need a new class of a
Siva Chandra 2013/03/13 02:18:33 Converted everything into an error.
171 if devices: 184 if devices:
172 types, builds, reports, errors = zip(*[DeviceInfo(dev) for dev in devices]) 185 types, builds, reports, warnings, errors = zip(
186 *[DeviceInfo(dev) for dev in devices])
187
188 missing_devices_msg = CheckForMissingDevices(options, devices)
173 189
174 unique_types = list(set(types)) 190 unique_types = list(set(types))
175 unique_builds = list(set(builds)) 191 unique_builds = list(set(builds))
176 192
177 buildbot_report.PrintMsg('Online devices: %d. Device types %s, builds %s' 193 buildbot_report.PrintMsg('Online devices: %d. Device types %s, builds %s'
178 % (len(devices), unique_types, unique_builds)) 194 % (len(devices), unique_types, unique_builds))
179 print '\n'.join(reports) 195 print '\n'.join(reports)
180 196
197 full_warnings = []
181 full_errors = [] 198 full_errors = []
182 for serial, device_errors in zip(devices, errors): 199 device_info_err_msg = ''
183 full_errors.extend('%s: %s' % (serial, error) for error in device_errors) 200 for serial, dev_warnings in zip(devices, warnings):
201 full_warnings.extend('%s:\n%s' % (serial, error) for error in dev_warnings)
202 for serial, dev_errors in zip(devices, errors):
203 full_errors.extend('%s:\n%s' % (serial, error) for error in dev_errors)
204
205 if full_warnings or full_errors or missing_devices_msg:
206 buildbot_report.PrintWarning()
207
208 if full_warnings:
209 print '\n'.join(full_warnings)
184 if full_errors: 210 if full_errors:
185 buildbot_report.PrintWarning() 211 device_info_err_msg = '\n'.join(full_errors)
186 print '\n'.join(full_errors) 212 print device_info_err_msg
187 213
188 CheckForMissingDevices(options, devices) 214 SendDeviceStatusAlert(missing_devices_msg + device_info_err_msg)
215
189 216
190 if __name__ == '__main__': 217 if __name__ == '__main__':
191 sys.exit(main()) 218 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