OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright 2013 The Chromium Authors. All rights reserved. | 3 # Copyright 2013 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 json | 8 import json |
9 import logging | 9 import logging |
10 import optparse | 10 import optparse |
(...skipping 12 matching lines...) Expand all Loading... |
23 | 23 |
24 sys.path.append(os.path.join(os.path.dirname(__file__), | 24 sys.path.append(os.path.join(os.path.dirname(__file__), |
25 os.pardir, os.pardir, 'util', 'lib', | 25 os.pardir, os.pardir, 'util', 'lib', |
26 'common')) | 26 'common')) |
27 import perf_tests_results_helper # pylint: disable=F0401 | 27 import perf_tests_results_helper # pylint: disable=F0401 |
28 | 28 |
29 sys.path.append(os.path.join(os.path.dirname(__file__), '..')) | 29 sys.path.append(os.path.join(os.path.dirname(__file__), '..')) |
30 from pylib import android_commands | 30 from pylib import android_commands |
31 from pylib import constants | 31 from pylib import constants |
32 from pylib.cmd_helper import GetCmdOutput | 32 from pylib.cmd_helper import GetCmdOutput |
| 33 from pylib.device import battery_utils |
33 from pylib.device import device_blacklist | 34 from pylib.device import device_blacklist |
| 35 from pylib.device import device_errors |
34 from pylib.device import device_list | 36 from pylib.device import device_list |
35 from pylib.device import device_utils | 37 from pylib.device import device_utils |
| 38 from pylib.utils import run_tests_helper |
| 39 |
| 40 _RE_DEVICE_ID = re.compile('Device ID = (\d+)') |
36 | 41 |
37 def DeviceInfo(serial, options): | 42 def DeviceInfo(serial, options): |
38 """Gathers info on a device via various adb calls. | 43 """Gathers info on a device via various adb calls. |
39 | 44 |
40 Args: | 45 Args: |
41 serial: The serial of the attached device to construct info about. | 46 serial: The serial of the attached device to construct info about. |
42 | 47 |
43 Returns: | 48 Returns: |
44 Tuple of device type, build id, report as a string, error messages, and | 49 Tuple of device type, build id, report as a string, error messages, and |
45 boolean indicating whether or not device can be used for testing. | 50 boolean indicating whether or not device can be used for testing. |
46 """ | 51 """ |
| 52 device = device_utils.DeviceUtils(serial) |
| 53 battery = battery_utils.BatteryUtils(device) |
47 | 54 |
48 device_adb = device_utils.DeviceUtils(serial) | 55 battery_info = {} |
49 device_type = device_adb.build_product | 56 battery_level = 100 |
50 device_build = device_adb.build_id | 57 errors = [] |
51 device_build_type = device_adb.build_type | 58 dev_good = True |
52 device_product_name = device_adb.product_name | 59 json_data = { |
| 60 'serial': serial, |
| 61 'type': device.build_product, |
| 62 'build': device.build_id, |
| 63 'build_detail': device.GetProp('ro.build.fingerprint'), |
| 64 'battery': {}, |
| 65 'imei_slice': 'Unknown', |
| 66 'wifi_ip': device.GetProp('dhcp.wlan0.ipaddress'), |
| 67 } |
53 | 68 |
54 try: | 69 try: |
55 battery_info = device_adb.old_interface.GetBatteryInfo() | 70 try: |
56 except Exception as e: | 71 battery_info = battery.GetBatteryInfo(timeout=5) |
57 battery_info = {} | 72 battery_level = int(battery_info.get('level', battery_level)) |
58 logging.error('Unable to obtain battery info for %s, %s', serial, e) | 73 json_data['battery'] = battery_info |
| 74 except device_errors.CommandFailedError: |
| 75 logging.exception('Failed to get battery information for %s', serial) |
59 | 76 |
60 def _GetData(re_expression, line, lambda_function=lambda x: x): | 77 try: |
61 if not line: | 78 for l in device.RunShellCommand(['dumpsys', 'iphonesubinfo'], |
62 return 'Unknown' | 79 check_return=True, timeout=5): |
63 found = re.findall(re_expression, line) | 80 m = _RE_DEVICE_ID.match(l) |
64 if found and len(found): | 81 if m: |
65 return lambda_function(found[0]) | 82 json_data['imei_slice'] = m.group(1)[-6:] |
66 return 'Unknown' | 83 except device_errors.CommandFailedError: |
| 84 logging.exception('Failed to get IMEI slice for %s', serial) |
67 | 85 |
68 battery_level = int(battery_info.get('level', 100)) | 86 if battery_level < 15: |
69 imei_slice = _GetData(r'Device ID = (\d+)', | 87 errors += ['Device critically low in battery.'] |
70 device_adb.old_interface.GetSubscriberInfo(), | 88 dev_good = False |
71 lambda x: x[-6:]) | 89 if not battery.GetCharging(): |
72 json_data = { | 90 battery.SetCharging(True) |
73 'serial': serial, | 91 if not options.no_provisioning_check: |
74 'type': device_type, | 92 setup_wizard_disabled = ( |
75 'build': device_build, | 93 device.GetProp('ro.setupwizard.mode') == 'DISABLED') |
76 'build_detail': device_adb.GetProp('ro.build.fingerprint'), | 94 if not setup_wizard_disabled and device.build_type != 'user': |
77 'battery': battery_info, | 95 errors += ['Setup wizard not disabled. Was it provisioned correctly?'] |
78 'imei_slice': imei_slice, | 96 if (device.product_name == 'mantaray' and |
79 'wifi_ip': device_adb.GetProp('dhcp.wlan0.ipaddress'), | 97 battery_info.get('AC powered', None) != 'true'): |
80 } | 98 errors += ['Mantaray device not connected to AC power.'] |
81 report = ['Device %s (%s)' % (serial, device_type), | 99 except device_errors.CommandFailedError: |
82 ' Build: %s (%s)' % | 100 logging.exception('Failure while getting device status.') |
83 (device_build, json_data['build_detail']), | 101 dev_good = False |
84 ' Current Battery Service state: ', | 102 except device_errors.CommandTimeoutError: |
85 '\n'.join([' %s: %s' % (k, v) | 103 logging.exception('Timeout while getting device status.') |
86 for k, v in battery_info.iteritems()]), | 104 dev_good = False |
87 ' IMEI slice: %s' % imei_slice, | |
88 ' Wifi IP: %s' % json_data['wifi_ip'], | |
89 ''] | |
90 | 105 |
91 errors = [] | 106 return (device.build_product, device.build_id, battery_level, errors, |
92 dev_good = True | 107 dev_good, json_data) |
93 if battery_level < 15: | |
94 errors += ['Device critically low in battery. Will add to blacklist.'] | |
95 dev_good = False | |
96 if not device_adb.old_interface.IsDeviceCharging(): | |
97 if device_adb.old_interface.CanControlUsbCharging(): | |
98 device_adb.old_interface.EnableUsbCharging() | |
99 else: | |
100 logging.error('Device %s is not charging' % serial) | |
101 if not options.no_provisioning_check: | |
102 setup_wizard_disabled = ( | |
103 device_adb.GetProp('ro.setupwizard.mode') == 'DISABLED') | |
104 if not setup_wizard_disabled and device_build_type != 'user': | |
105 errors += ['Setup wizard not disabled. Was it provisioned correctly?'] | |
106 if (device_product_name == 'mantaray' and | |
107 battery_info.get('AC powered', None) != 'true'): | |
108 errors += ['Mantaray device not connected to AC power.'] | |
109 | |
110 full_report = '\n'.join(report) | |
111 | |
112 return (device_type, device_build, battery_level, full_report, errors, | |
113 dev_good, json_data) | |
114 | 108 |
115 | 109 |
116 def CheckForMissingDevices(options, adb_online_devs): | 110 def CheckForMissingDevices(options, adb_online_devs): |
117 """Uses file of previous online devices to detect broken phones. | 111 """Uses file of previous online devices to detect broken phones. |
118 | 112 |
119 Args: | 113 Args: |
120 options: out_dir parameter of options argument is used as the base | 114 options: out_dir parameter of options argument is used as the base |
121 directory to load and update the cache file. | 115 directory to load and update the cache file. |
122 adb_online_devs: A list of serial numbers of the currently visible | 116 adb_online_devs: A list of serial numbers of the currently visible |
123 and online attached devices. | 117 and online attached devices. |
124 """ | 118 """ |
125 # TODO(navabi): remove this once the bug that causes different number | |
126 # of devices to be detected between calls is fixed. | |
127 logger = logging.getLogger() | |
128 logger.setLevel(logging.INFO) | |
129 | |
130 out_dir = os.path.abspath(options.out_dir) | 119 out_dir = os.path.abspath(options.out_dir) |
131 | 120 |
132 # last_devices denotes all known devices prior to this run | 121 # last_devices denotes all known devices prior to this run |
133 last_devices_path = os.path.join(out_dir, device_list.LAST_DEVICES_FILENAME) | 122 last_devices_path = os.path.join(out_dir, device_list.LAST_DEVICES_FILENAME) |
134 last_missing_devices_path = os.path.join(out_dir, | 123 last_missing_devices_path = os.path.join(out_dir, |
135 device_list.LAST_MISSING_DEVICES_FILENAME) | 124 device_list.LAST_MISSING_DEVICES_FILENAME) |
136 try: | 125 try: |
137 last_devices = device_list.GetPersistentDeviceList(last_devices_path) | 126 last_devices = device_list.GetPersistentDeviceList(last_devices_path) |
138 except IOError: | 127 except IOError: |
139 # Ignore error, file might not exist | 128 # Ignore error, file might not exist |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
182 crbug_link = ('https://code.google.com/p/chromium/issues/entry?summary=' | 171 crbug_link = ('https://code.google.com/p/chromium/issues/entry?summary=' |
183 '%s&comment=%s&labels=Restrict-View-Google,OS-Android,Infra' % | 172 '%s&comment=%s&labels=Restrict-View-Google,OS-Android,Infra' % |
184 (urllib.quote('Device Offline'), | 173 (urllib.quote('Device Offline'), |
185 urllib.quote('Buildbot: %s %s\n' | 174 urllib.quote('Buildbot: %s %s\n' |
186 'Build: %s\n' | 175 'Build: %s\n' |
187 '(please don\'t change any labels)' % | 176 '(please don\'t change any labels)' % |
188 (os.environ.get('BUILDBOT_BUILDERNAME'), | 177 (os.environ.get('BUILDBOT_BUILDERNAME'), |
189 os.environ.get('BUILDBOT_SLAVENAME'), | 178 os.environ.get('BUILDBOT_SLAVENAME'), |
190 os.environ.get('BUILDBOT_BUILDNUMBER'))))) | 179 os.environ.get('BUILDBOT_BUILDNUMBER'))))) |
191 return ['Current online devices: %s' % adb_online_devs, | 180 return ['Current online devices: %s' % adb_online_devs, |
192 '%s are no longer visible. Were they removed?\n' % missing_devs, | 181 '%s are no longer visible. Were they removed?' % missing_devs, |
193 'SHERIFF:\n', | 182 'SHERIFF:', |
194 '@@@STEP_LINK@Click here to file a bug@%s@@@\n' % crbug_link, | 183 '@@@STEP_LINK@Click here to file a bug@%s@@@' % crbug_link, |
195 'Cache file: %s\n\n' % last_devices_path, | 184 'Cache file: %s' % last_devices_path, |
196 'adb devices: %s' % GetCmdOutput(['adb', 'devices']), | 185 'adb devices: %s' % GetCmdOutput(['adb', 'devices']), |
197 'adb devices(GetAttachedDevices): %s' % adb_online_devs] | 186 'adb devices(GetAttachedDevices): %s' % adb_online_devs] |
198 else: | 187 else: |
199 new_devs = set(adb_online_devs) - set(last_devices) | 188 new_devs = set(adb_online_devs) - set(last_devices) |
200 if new_devs and os.path.exists(last_devices_path): | 189 if new_devs and os.path.exists(last_devices_path): |
201 bb_annotations.PrintWarning() | 190 bb_annotations.PrintWarning() |
202 bb_annotations.PrintSummaryText( | 191 bb_annotations.PrintSummaryText( |
203 '%d new devices detected' % len(new_devs)) | 192 '%d new devices detected' % len(new_devs)) |
204 print ('New devices detected %s. And now back to your ' | 193 logging.info('New devices detected:') |
205 'regularly scheduled program.' % list(new_devs)) | 194 for d in new_devs: |
| 195 logging.info(' %s', d) |
206 | 196 |
207 | 197 |
208 def SendEmail(from_address, to_addresses, cc_addresses, subject, msg): | 198 def SendEmail(from_address, to_addresses, cc_addresses, subject, msg): |
209 msg_body = '\r\n'.join(['From: %s' % from_address, | 199 msg_body = '\r\n'.join(['From: %s' % from_address, |
210 'To: %s' % ', '.join(to_addresses), | 200 'To: %s' % ', '.join(to_addresses), |
211 'CC: %s' % ', '.join(cc_addresses), | 201 'CC: %s' % ', '.join(cc_addresses), |
212 'Subject: %s' % subject, '', msg]) | 202 'Subject: %s' % subject, '', msg]) |
213 try: | 203 try: |
214 server = smtplib.SMTP('localhost') | 204 server = smtplib.SMTP('localhost') |
215 server.sendmail(from_address, to_addresses, msg_body) | 205 server.sendmail(from_address, to_addresses, msg_body) |
216 server.quit() | 206 server.quit() |
217 except Exception as e: | 207 except Exception: |
218 print 'Failed to send alert email. Error: %s' % e | 208 logging.exception('Failed to send alert email.') |
219 | 209 |
220 | 210 |
221 def RestartUsb(): | 211 def RestartUsb(): |
222 if not os.path.isfile('/usr/bin/restart_usb'): | 212 if not os.path.isfile('/usr/bin/restart_usb'): |
223 print ('ERROR: Could not restart usb. /usr/bin/restart_usb not installed ' | 213 logging.error('Could not restart usb. ''/usr/bin/restart_usb not ' |
224 'on host (see BUG=305769).') | 214 'installed on host (see BUG=305769).') |
225 return False | 215 return False |
226 | 216 |
227 lsusb_proc = bb_utils.SpawnCmd(['lsusb'], stdout=subprocess.PIPE) | 217 lsusb_proc = bb_utils.SpawnCmd(['lsusb'], stdout=subprocess.PIPE) |
228 lsusb_output, _ = lsusb_proc.communicate() | 218 lsusb_output, _ = lsusb_proc.communicate() |
229 if lsusb_proc.returncode: | 219 if lsusb_proc.returncode: |
230 print 'Error: Could not get list of USB ports (i.e. lsusb).' | 220 logging.error('Could not get list of USB ports (i.e. lsusb).') |
231 return lsusb_proc.returncode | 221 return lsusb_proc.returncode |
232 | 222 |
233 usb_devices = [re.findall(r'Bus (\d\d\d) Device (\d\d\d)', lsusb_line)[0] | 223 usb_devices = [re.findall(r'Bus (\d\d\d) Device (\d\d\d)', lsusb_line)[0] |
234 for lsusb_line in lsusb_output.strip().split('\n')] | 224 for lsusb_line in lsusb_output.strip().split('\n')] |
235 | 225 |
236 all_restarted = True | 226 all_restarted = True |
237 # Walk USB devices from leaves up (i.e reverse sorted) restarting the | 227 # Walk USB devices from leaves up (i.e reverse sorted) restarting the |
238 # connection. If a parent node (e.g. usb hub) is restarted before the | 228 # connection. If a parent node (e.g. usb hub) is restarted before the |
239 # devices connected to it, the (bus, dev) for the hub can change, making the | 229 # devices connected to it, the (bus, dev) for the hub can change, making the |
240 # output we have wrong. This way we restart the devices before the hub. | 230 # output we have wrong. This way we restart the devices before the hub. |
241 for (bus, dev) in reversed(sorted(usb_devices)): | 231 for (bus, dev) in reversed(sorted(usb_devices)): |
242 # Can not restart root usb connections | 232 # Can not restart root usb connections |
243 if dev != '001': | 233 if dev != '001': |
244 return_code = bb_utils.RunCmd(['/usr/bin/restart_usb', bus, dev]) | 234 return_code = bb_utils.RunCmd(['/usr/bin/restart_usb', bus, dev]) |
245 if return_code: | 235 if return_code: |
246 print 'Error restarting USB device /dev/bus/usb/%s/%s' % (bus, dev) | 236 logging.error('Error restarting USB device /dev/bus/usb/%s/%s', |
| 237 bus, dev) |
247 all_restarted = False | 238 all_restarted = False |
248 else: | 239 else: |
249 print 'Restarted USB device /dev/bus/usb/%s/%s' % (bus, dev) | 240 logging.info('Restarted USB device /dev/bus/usb/%s/%s', bus, dev) |
250 | 241 |
251 return all_restarted | 242 return all_restarted |
252 | 243 |
253 | 244 |
254 def KillAllAdb(): | 245 def KillAllAdb(): |
255 def GetAllAdb(): | 246 def GetAllAdb(): |
256 for p in psutil.process_iter(): | 247 for p in psutil.process_iter(): |
257 try: | 248 try: |
258 if 'adb' in p.name: | 249 if 'adb' in p.name: |
259 yield p | 250 yield p |
260 except (psutil.NoSuchProcess, psutil.AccessDenied): | 251 except (psutil.NoSuchProcess, psutil.AccessDenied): |
261 pass | 252 pass |
262 | 253 |
263 for sig in [signal.SIGTERM, signal.SIGQUIT, signal.SIGKILL]: | 254 for sig in [signal.SIGTERM, signal.SIGQUIT, signal.SIGKILL]: |
264 for p in GetAllAdb(): | 255 for p in GetAllAdb(): |
265 try: | 256 try: |
266 print 'kill %d %d (%s [%s])' % (sig, p.pid, p.name, | 257 logging.info('kill %d %d (%s [%s])', sig, p.pid, p.name, |
267 ' '.join(p.cmdline)) | 258 ' '.join(p.cmdline)) |
268 p.send_signal(sig) | 259 p.send_signal(sig) |
269 except (psutil.NoSuchProcess, psutil.AccessDenied): | 260 except (psutil.NoSuchProcess, psutil.AccessDenied): |
270 pass | 261 pass |
271 for p in GetAllAdb(): | 262 for p in GetAllAdb(): |
272 try: | 263 try: |
273 print 'Unable to kill %d (%s [%s])' % (p.pid, p.name, ' '.join(p.cmdline)) | 264 logging.error('Unable to kill %d (%s [%s])', p.pid, p.name, |
| 265 ' '.join(p.cmdline)) |
274 except (psutil.NoSuchProcess, psutil.AccessDenied): | 266 except (psutil.NoSuchProcess, psutil.AccessDenied): |
275 pass | 267 pass |
276 | 268 |
277 | 269 |
278 def main(): | 270 def main(): |
279 parser = optparse.OptionParser() | 271 parser = optparse.OptionParser() |
280 parser.add_option('', '--out-dir', | 272 parser.add_option('', '--out-dir', |
281 help='Directory where the device path is stored', | 273 help='Directory where the device path is stored', |
282 default=os.path.join(constants.DIR_SOURCE_ROOT, 'out')) | 274 default=os.path.join(constants.DIR_SOURCE_ROOT, 'out')) |
283 parser.add_option('--no-provisioning-check', action='store_true', | 275 parser.add_option('--no-provisioning-check', action='store_true', |
284 help='Will not check if devices are provisioned properly.') | 276 help='Will not check if devices are provisioned properly.') |
285 parser.add_option('--device-status-dashboard', action='store_true', | 277 parser.add_option('--device-status-dashboard', action='store_true', |
286 help='Output device status data for dashboard.') | 278 help='Output device status data for dashboard.') |
287 parser.add_option('--restart-usb', action='store_true', | 279 parser.add_option('--restart-usb', action='store_true', |
288 help='Restart USB ports before running device check.') | 280 help='Restart USB ports before running device check.') |
289 parser.add_option('--json-output', | 281 parser.add_option('--json-output', |
290 help='Output JSON information into a specified file.') | 282 help='Output JSON information into a specified file.') |
| 283 parser.add_option('-v', '--verbose', action='count', default=1, |
| 284 help='Log more information.') |
291 | 285 |
292 options, args = parser.parse_args() | 286 options, args = parser.parse_args() |
293 if args: | 287 if args: |
294 parser.error('Unknown options %s' % args) | 288 parser.error('Unknown options %s' % args) |
295 | 289 |
| 290 run_tests_helper.SetLogLevel(options.verbose) |
| 291 |
296 # Remove the last build's "bad devices" before checking device statuses. | 292 # Remove the last build's "bad devices" before checking device statuses. |
297 device_blacklist.ResetBlacklist() | 293 device_blacklist.ResetBlacklist() |
298 | 294 |
299 try: | 295 try: |
300 expected_devices = device_list.GetPersistentDeviceList( | 296 expected_devices = device_list.GetPersistentDeviceList( |
301 os.path.join(options.out_dir, device_list.LAST_DEVICES_FILENAME)) | 297 os.path.join(options.out_dir, device_list.LAST_DEVICES_FILENAME)) |
302 except IOError: | 298 except IOError: |
303 expected_devices = [] | 299 expected_devices = [] |
304 devices = android_commands.GetAttachedDevices() | 300 devices = android_commands.GetAttachedDevices() |
305 # Only restart usb if devices are missing. | 301 # Only restart usb if devices are missing. |
306 if set(expected_devices) != set(devices): | 302 if set(expected_devices) != set(devices): |
307 print 'expected_devices: %s, devices: %s' % (expected_devices, devices) | 303 logging.warning('expected_devices: %s', expected_devices) |
| 304 logging.warning('devices: %s', devices) |
308 KillAllAdb() | 305 KillAllAdb() |
309 retries = 5 | 306 retries = 5 |
310 usb_restarted = True | 307 usb_restarted = True |
311 if options.restart_usb: | 308 if options.restart_usb: |
312 if not RestartUsb(): | 309 if not RestartUsb(): |
313 usb_restarted = False | 310 usb_restarted = False |
314 bb_annotations.PrintWarning() | 311 bb_annotations.PrintWarning() |
315 print 'USB reset stage failed, wait for any device to come back.' | 312 logging.error('USB reset stage failed, ' |
| 313 'wait for any device to come back.') |
316 while retries: | 314 while retries: |
317 print 'retry adb devices...' | 315 logging.info('retry adb devices...') |
318 time.sleep(1) | 316 time.sleep(1) |
319 devices = android_commands.GetAttachedDevices() | 317 devices = android_commands.GetAttachedDevices() |
320 if set(expected_devices) == set(devices): | 318 if set(expected_devices) == set(devices): |
321 # All devices are online, keep going. | 319 # All devices are online, keep going. |
322 break | 320 break |
323 if not usb_restarted and devices: | 321 if not usb_restarted and devices: |
324 # The USB wasn't restarted, but there's at least one device online. | 322 # The USB wasn't restarted, but there's at least one device online. |
325 # No point in trying to wait for all devices. | 323 # No point in trying to wait for all devices. |
326 break | 324 break |
327 retries -= 1 | 325 retries -= 1 |
328 | 326 |
329 # TODO(navabi): Test to make sure this fails and then fix call | 327 # TODO(navabi): Test to make sure this fails and then fix call |
330 offline_devices = android_commands.GetAttachedDevices( | 328 offline_devices = android_commands.GetAttachedDevices( |
331 hardware=False, emulator=False, offline=True) | 329 hardware=False, emulator=False, offline=True) |
332 | 330 |
333 types, builds, batteries, reports, errors, json_data = [], [], [], [], [], [] | 331 types, builds, batteries, errors, devices_ok, json_data = ( |
334 fail_step_lst = [] | 332 [], [], [], [], [], []) |
335 if devices: | 333 if devices: |
336 types, builds, batteries, reports, errors, fail_step_lst, json_data = ( | 334 types, builds, batteries, errors, devices_ok, json_data = ( |
337 zip(*[DeviceInfo(dev, options) for dev in devices])) | 335 zip(*[DeviceInfo(dev, options) for dev in devices])) |
338 | 336 |
339 # Write device info to file for buildbot info display. | 337 # Write device info to file for buildbot info display. |
340 if os.path.exists('/home/chrome-bot'): | 338 if os.path.exists('/home/chrome-bot'): |
341 with open('/home/chrome-bot/.adb_device_info', 'w') as f: | 339 with open('/home/chrome-bot/.adb_device_info', 'w') as f: |
342 for device in json_data: | 340 for device in json_data: |
343 try: | 341 try: |
344 f.write('%s %s %s %.1fC %s%%\n' % (device['serial'], device['type'], | 342 f.write('%s %s %s %.1fC %s%%\n' % (device['serial'], device['type'], |
345 device['build'], float(device['battery']['temperature']) / 10, | 343 device['build'], float(device['battery']['temperature']) / 10, |
346 device['battery']['level'])) | 344 device['battery']['level'])) |
347 except Exception: | 345 except Exception: |
348 pass | 346 pass |
349 | 347 |
350 err_msg = CheckForMissingDevices(options, devices) or [] | 348 err_msg = CheckForMissingDevices(options, devices) or [] |
351 | 349 |
352 unique_types = list(set(types)) | 350 unique_types = list(set(types)) |
353 unique_builds = list(set(builds)) | 351 unique_builds = list(set(builds)) |
354 | 352 |
355 bb_annotations.PrintMsg('Online devices: %d. Device types %s, builds %s' | 353 bb_annotations.PrintMsg('Online devices: %d. Device types %s, builds %s' |
356 % (len(devices), unique_types, unique_builds)) | 354 % (len(devices), unique_types, unique_builds)) |
357 print '\n'.join(reports) | 355 |
| 356 for j in json_data: |
| 357 logging.info('Device %s (%s)', j.get('serial'), j.get('type')) |
| 358 logging.info(' Build: %s (%s)', j.get('build'), j.get('build_detail')) |
| 359 logging.info(' Current Battery Service state:') |
| 360 for k, v in j.get('battery', {}).iteritems(): |
| 361 logging.info(' %s: %s', k, v) |
| 362 logging.info(' IMEI slice: %s', j.get('imei_slice')) |
| 363 logging.info(' WiFi IP: %s', j.get('wifi_ip')) |
| 364 |
358 | 365 |
359 for serial, dev_errors in zip(devices, errors): | 366 for serial, dev_errors in zip(devices, errors): |
360 if dev_errors: | 367 if dev_errors: |
361 err_msg += ['%s errors:' % serial] | 368 err_msg += ['%s errors:' % serial] |
362 err_msg += [' %s' % error for error in dev_errors] | 369 err_msg += [' %s' % error for error in dev_errors] |
363 | 370 |
364 if err_msg: | 371 if err_msg: |
365 bb_annotations.PrintWarning() | 372 bb_annotations.PrintWarning() |
366 msg = '\n'.join(err_msg) | 373 for e in err_msg: |
367 print msg | 374 logging.error(e) |
368 from_address = 'buildbot@chromium.org' | 375 from_address = 'buildbot@chromium.org' |
369 to_addresses = ['chromium-android-device-alerts@google.com'] | 376 to_addresses = ['chromium-android-device-alerts@google.com'] |
370 bot_name = os.environ.get('BUILDBOT_BUILDERNAME') | 377 bot_name = os.environ.get('BUILDBOT_BUILDERNAME') |
371 slave_name = os.environ.get('BUILDBOT_SLAVENAME') | 378 slave_name = os.environ.get('BUILDBOT_SLAVENAME') |
372 subject = 'Device status check errors on %s, %s.' % (slave_name, bot_name) | 379 subject = 'Device status check errors on %s, %s.' % (slave_name, bot_name) |
373 SendEmail(from_address, to_addresses, [], subject, msg) | 380 SendEmail(from_address, to_addresses, [], subject, '\n'.join(err_msg)) |
374 | 381 |
375 if options.device_status_dashboard: | 382 if options.device_status_dashboard: |
376 perf_tests_results_helper.PrintPerfResult('BotDevices', 'OnlineDevices', | 383 perf_tests_results_helper.PrintPerfResult('BotDevices', 'OnlineDevices', |
377 [len(devices)], 'devices') | 384 [len(devices)], 'devices') |
378 perf_tests_results_helper.PrintPerfResult('BotDevices', 'OfflineDevices', | 385 perf_tests_results_helper.PrintPerfResult('BotDevices', 'OfflineDevices', |
379 [len(offline_devices)], 'devices', | 386 [len(offline_devices)], 'devices', |
380 'unimportant') | 387 'unimportant') |
381 for serial, battery in zip(devices, batteries): | 388 for serial, battery in zip(devices, batteries): |
382 perf_tests_results_helper.PrintPerfResult('DeviceBattery', serial, | 389 perf_tests_results_helper.PrintPerfResult('DeviceBattery', serial, |
383 [battery], '%', | 390 [battery], '%', |
384 'unimportant') | 391 'unimportant') |
385 | 392 |
386 if options.json_output: | 393 if options.json_output: |
387 with open(options.json_output, 'wb') as f: | 394 with open(options.json_output, 'wb') as f: |
388 f.write(json.dumps(json_data, indent=4)) | 395 f.write(json.dumps(json_data, indent=4)) |
389 | 396 |
390 num_failed_devs = 0 | 397 num_failed_devs = 0 |
391 for fail_status, device in zip(fail_step_lst, devices): | 398 for device_ok, device in zip(devices_ok, devices): |
392 if not fail_status: | 399 if not device_ok: |
| 400 logging.warning('Blacklisting %s', str(device)) |
393 device_blacklist.ExtendBlacklist([str(device)]) | 401 device_blacklist.ExtendBlacklist([str(device)]) |
394 num_failed_devs += 1 | 402 num_failed_devs += 1 |
395 | 403 |
396 if num_failed_devs == len(devices): | 404 if num_failed_devs == len(devices): |
397 return 2 | 405 return 2 |
398 | 406 |
399 if not devices: | 407 if not devices: |
400 return 1 | 408 return 1 |
401 | 409 |
402 | 410 |
403 if __name__ == '__main__': | 411 if __name__ == '__main__': |
404 sys.exit(main()) | 412 sys.exit(main()) |
OLD | NEW |