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

Side by Side Diff: build/android/buildbot/bb_device_status_check.py

Issue 2180023002: Remove src/build/android/buildbot. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 5 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
« no previous file with comments | « build/android/buildbot/bb_annotations.py ('k') | build/android/buildbot/bb_device_steps.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 #
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
5 # found in the LICENSE file.
6
7 """A class to keep track of devices across builds and report state."""
8
9 import argparse
10 import json
11 import logging
12 import os
13 import psutil
14 import re
15 import signal
16 import sys
17
18 sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
19 import devil_chromium
20 from devil.android import battery_utils
21 from devil.android import device_blacklist
22 from devil.android import device_errors
23 from devil.android import device_list
24 from devil.android import device_utils
25 from devil.android.sdk import adb_wrapper
26 from devil.constants import exit_codes
27 from devil.utils import lsusb
28 from devil.utils import reset_usb
29 from devil.utils import run_tests_helper
30 from pylib.constants import host_paths
31
32 _RE_DEVICE_ID = re.compile(r'Device ID = (\d+)')
33
34
35 def KillAllAdb():
36 def GetAllAdb():
37 for p in psutil.process_iter():
38 try:
39 if 'adb' in p.name:
40 yield p
41 except (psutil.NoSuchProcess, psutil.AccessDenied):
42 pass
43
44 for sig in [signal.SIGTERM, signal.SIGQUIT, signal.SIGKILL]:
45 for p in GetAllAdb():
46 try:
47 logging.info('kill %d %d (%s [%s])', sig, p.pid, p.name,
48 ' '.join(p.cmdline))
49 p.send_signal(sig)
50 except (psutil.NoSuchProcess, psutil.AccessDenied):
51 pass
52 for p in GetAllAdb():
53 try:
54 logging.error('Unable to kill %d (%s [%s])', p.pid, p.name,
55 ' '.join(p.cmdline))
56 except (psutil.NoSuchProcess, psutil.AccessDenied):
57 pass
58
59
60 def _IsBlacklisted(serial, blacklist):
61 return blacklist and serial in blacklist.Read()
62
63
64 def _BatteryStatus(device, blacklist):
65 battery_info = {}
66 try:
67 battery = battery_utils.BatteryUtils(device)
68 battery_info = battery.GetBatteryInfo(timeout=5)
69 battery_level = int(battery_info.get('level', 100))
70
71 if battery_level < 15:
72 logging.error('Critically low battery level (%d)', battery_level)
73 battery = battery_utils.BatteryUtils(device)
74 if not battery.GetCharging():
75 battery.SetCharging(True)
76 if blacklist:
77 blacklist.Extend([device.adb.GetDeviceSerial()], reason='low_battery')
78
79 except device_errors.CommandFailedError:
80 logging.exception('Failed to get battery information for %s',
81 str(device))
82
83 return battery_info
84
85
86 def _IMEISlice(device):
87 imei_slice = ''
88 try:
89 for l in device.RunShellCommand(['dumpsys', 'iphonesubinfo'],
90 check_return=True, timeout=5):
91 m = _RE_DEVICE_ID.match(l)
92 if m:
93 imei_slice = m.group(1)[-6:]
94 except device_errors.CommandFailedError:
95 logging.exception('Failed to get IMEI slice for %s', str(device))
96
97 return imei_slice
98
99
100 def DeviceStatus(devices, blacklist):
101 """Generates status information for the given devices.
102
103 Args:
104 devices: The devices to generate status for.
105 blacklist: The current device blacklist.
106 Returns:
107 A dict of the following form:
108 {
109 '<serial>': {
110 'serial': '<serial>',
111 'adb_status': str,
112 'usb_status': bool,
113 'blacklisted': bool,
114 # only if the device is connected and not blacklisted
115 'type': ro.build.product,
116 'build': ro.build.id,
117 'build_detail': ro.build.fingerprint,
118 'battery': {
119 ...
120 },
121 'imei_slice': str,
122 'wifi_ip': str,
123 },
124 ...
125 }
126 """
127 adb_devices = {
128 a[0].GetDeviceSerial(): a
129 for a in adb_wrapper.AdbWrapper.Devices(desired_state=None, long_list=True)
130 }
131 usb_devices = set(lsusb.get_android_devices())
132
133 def blacklisting_device_status(device):
134 serial = device.adb.GetDeviceSerial()
135 adb_status = (
136 adb_devices[serial][1] if serial in adb_devices
137 else 'missing')
138 usb_status = bool(serial in usb_devices)
139
140 device_status = {
141 'serial': serial,
142 'adb_status': adb_status,
143 'usb_status': usb_status,
144 }
145
146 if not _IsBlacklisted(serial, blacklist):
147 if adb_status == 'device':
148 try:
149 build_product = device.build_product
150 build_id = device.build_id
151 build_fingerprint = device.GetProp('ro.build.fingerprint', cache=True)
152 wifi_ip = device.GetProp('dhcp.wlan0.ipaddress')
153 battery_info = _BatteryStatus(device, blacklist)
154 imei_slice = _IMEISlice(device)
155
156 if (device.product_name == 'mantaray' and
157 battery_info.get('AC powered', None) != 'true'):
158 logging.error('Mantaray device not connected to AC power.')
159
160 device_status.update({
161 'ro.build.product': build_product,
162 'ro.build.id': build_id,
163 'ro.build.fingerprint': build_fingerprint,
164 'battery': battery_info,
165 'imei_slice': imei_slice,
166 'wifi_ip': wifi_ip,
167
168 # TODO(jbudorick): Remove these once no clients depend on them.
169 'type': build_product,
170 'build': build_id,
171 'build_detail': build_fingerprint,
172 })
173
174 except device_errors.CommandFailedError:
175 logging.exception('Failure while getting device status for %s.',
176 str(device))
177 if blacklist:
178 blacklist.Extend([serial], reason='status_check_failure')
179
180 except device_errors.CommandTimeoutError:
181 logging.exception('Timeout while getting device status for %s.',
182 str(device))
183 if blacklist:
184 blacklist.Extend([serial], reason='status_check_timeout')
185
186 elif blacklist:
187 blacklist.Extend([serial],
188 reason=adb_status if usb_status else 'offline')
189
190 device_status['blacklisted'] = _IsBlacklisted(serial, blacklist)
191
192 return device_status
193
194 parallel_devices = device_utils.DeviceUtils.parallel(devices)
195 statuses = parallel_devices.pMap(blacklisting_device_status).pGet(None)
196 return statuses
197
198
199 def RecoverDevices(devices, blacklist):
200 """Attempts to recover any inoperable devices in the provided list.
201
202 Args:
203 devices: The list of devices to attempt to recover.
204 blacklist: The current device blacklist, which will be used then
205 reset.
206 Returns:
207 Nothing.
208 """
209
210 statuses = DeviceStatus(devices, blacklist)
211
212 should_restart_usb = set(
213 status['serial'] for status in statuses
214 if (not status['usb_status']
215 or status['adb_status'] in ('offline', 'missing')))
216 should_restart_adb = should_restart_usb.union(set(
217 status['serial'] for status in statuses
218 if status['adb_status'] == 'unauthorized'))
219 should_reboot_device = should_restart_adb.union(set(
220 status['serial'] for status in statuses
221 if status['blacklisted']))
222
223 logging.debug('Should restart USB for:')
224 for d in should_restart_usb:
225 logging.debug(' %s', d)
226 logging.debug('Should restart ADB for:')
227 for d in should_restart_adb:
228 logging.debug(' %s', d)
229 logging.debug('Should reboot:')
230 for d in should_reboot_device:
231 logging.debug(' %s', d)
232
233 if blacklist:
234 blacklist.Reset()
235
236 if should_restart_adb:
237 KillAllAdb()
238 for serial in should_restart_usb:
239 try:
240 reset_usb.reset_android_usb(serial)
241 except IOError:
242 logging.exception('Unable to reset USB for %s.', serial)
243 if blacklist:
244 blacklist.Extend([serial], reason='usb_failure')
245 except device_errors.DeviceUnreachableError:
246 logging.exception('Unable to reset USB for %s.', serial)
247 if blacklist:
248 blacklist.Extend([serial], reason='offline')
249
250 def blacklisting_recovery(device):
251 if _IsBlacklisted(device.adb.GetDeviceSerial(), blacklist):
252 logging.debug('%s is blacklisted, skipping recovery.', str(device))
253 return
254
255 if str(device) in should_reboot_device:
256 try:
257 device.WaitUntilFullyBooted(retries=0)
258 return
259 except (device_errors.CommandTimeoutError,
260 device_errors.CommandFailedError):
261 logging.exception('Failure while waiting for %s. '
262 'Attempting to recover.', str(device))
263
264 try:
265 try:
266 device.Reboot(block=False, timeout=5, retries=0)
267 except device_errors.CommandTimeoutError:
268 logging.warning('Timed out while attempting to reboot %s normally.'
269 'Attempting alternative reboot.', str(device))
270 # The device drops offline before we can grab the exit code, so
271 # we don't check for status.
272 device.adb.Root()
273 device.adb.Shell('echo b > /proc/sysrq-trigger', expect_status=None,
274 timeout=5, retries=0)
275 except device_errors.CommandFailedError:
276 logging.exception('Failed to reboot %s.', str(device))
277 if blacklist:
278 blacklist.Extend([device.adb.GetDeviceSerial()],
279 reason='reboot_failure')
280 except device_errors.CommandTimeoutError:
281 logging.exception('Timed out while rebooting %s.', str(device))
282 if blacklist:
283 blacklist.Extend([device.adb.GetDeviceSerial()],
284 reason='reboot_timeout')
285
286 try:
287 device.WaitUntilFullyBooted(retries=0)
288 except device_errors.CommandFailedError:
289 logging.exception('Failure while waiting for %s.', str(device))
290 if blacklist:
291 blacklist.Extend([device.adb.GetDeviceSerial()],
292 reason='reboot_failure')
293 except device_errors.CommandTimeoutError:
294 logging.exception('Timed out while waiting for %s.', str(device))
295 if blacklist:
296 blacklist.Extend([device.adb.GetDeviceSerial()],
297 reason='reboot_timeout')
298
299 device_utils.DeviceUtils.parallel(devices).pMap(blacklisting_recovery)
300
301
302 def main():
303 parser = argparse.ArgumentParser()
304 parser.add_argument('--out-dir',
305 help='Directory where the device path is stored',
306 default=os.path.join(host_paths.DIR_SOURCE_ROOT, 'out'))
307 parser.add_argument('--restart-usb', action='store_true',
308 help='DEPRECATED. '
309 'This script now always tries to reset USB.')
310 parser.add_argument('--json-output',
311 help='Output JSON information into a specified file.')
312 parser.add_argument('--adb-path', type=os.path.abspath,
313 help='Absolute path to the adb binary to use.')
314 parser.add_argument('--blacklist-file', help='Device blacklist JSON file.')
315 parser.add_argument('--known-devices-file', action='append', default=[],
316 dest='known_devices_files',
317 help='Path to known device lists.')
318 parser.add_argument('-v', '--verbose', action='count', default=1,
319 help='Log more information.')
320
321 args = parser.parse_args()
322
323 run_tests_helper.SetLogLevel(args.verbose)
324
325 devil_chromium.Initialize(adb_path=args.adb_path)
326
327 blacklist = (device_blacklist.Blacklist(args.blacklist_file)
328 if args.blacklist_file
329 else None)
330
331 expected_devices = set()
332 try:
333 for path in args.known_devices_files:
334 if os.path.exists(path):
335 expected_devices.update(device_list.GetPersistentDeviceList(path))
336 except IOError:
337 logging.warning('Problem reading %s, skipping.', path)
338
339 logging.info('Expected devices:')
340 for device in expected_devices:
341 logging.info(' %s', device)
342
343 usb_devices = set(lsusb.get_android_devices())
344 devices = [device_utils.DeviceUtils(s)
345 for s in expected_devices.union(usb_devices)]
346
347 RecoverDevices(devices, blacklist)
348 statuses = DeviceStatus(devices, blacklist)
349
350 # Log the state of all devices.
351 for status in statuses:
352 logging.info(status['serial'])
353 adb_status = status.get('adb_status')
354 blacklisted = status.get('blacklisted')
355 logging.info(' USB status: %s',
356 'online' if status.get('usb_status') else 'offline')
357 logging.info(' ADB status: %s', adb_status)
358 logging.info(' Blacklisted: %s', str(blacklisted))
359 if adb_status == 'device' and not blacklisted:
360 logging.info(' Device type: %s', status.get('ro.build.product'))
361 logging.info(' OS build: %s', status.get('ro.build.id'))
362 logging.info(' OS build fingerprint: %s',
363 status.get('ro.build.fingerprint'))
364 logging.info(' Battery state:')
365 for k, v in status.get('battery', {}).iteritems():
366 logging.info(' %s: %s', k, v)
367 logging.info(' IMEI slice: %s', status.get('imei_slice'))
368 logging.info(' WiFi IP: %s', status.get('wifi_ip'))
369
370 # Update the last devices file(s).
371 for path in args.known_devices_files:
372 device_list.WritePersistentDeviceList(
373 path, [status['serial'] for status in statuses])
374
375 # Write device info to file for buildbot info display.
376 if os.path.exists('/home/chrome-bot'):
377 with open('/home/chrome-bot/.adb_device_info', 'w') as f:
378 for status in statuses:
379 try:
380 if status['adb_status'] == 'device':
381 f.write('{serial} {adb_status} {build_product} {build_id} '
382 '{temperature:.1f}C {level}%\n'.format(
383 serial=status['serial'],
384 adb_status=status['adb_status'],
385 build_product=status['type'],
386 build_id=status['build'],
387 temperature=float(status['battery']['temperature']) / 10,
388 level=status['battery']['level']
389 ))
390 elif status.get('usb_status', False):
391 f.write('{serial} {adb_status}\n'.format(
392 serial=status['serial'],
393 adb_status=status['adb_status']
394 ))
395 else:
396 f.write('{serial} offline\n'.format(
397 serial=status['serial']
398 ))
399 except Exception: # pylint: disable=broad-except
400 pass
401
402 # Dump the device statuses to JSON.
403 if args.json_output:
404 with open(args.json_output, 'wb') as f:
405 f.write(json.dumps(statuses, indent=4))
406
407 live_devices = [status['serial'] for status in statuses
408 if (status['adb_status'] == 'device'
409 and not _IsBlacklisted(status['serial'], blacklist))]
410
411 # If all devices failed, or if there are no devices, it's an infra error.
412 if not live_devices:
413 logging.error('No available devices.')
414 return 0 if live_devices else exit_codes.INFRA
415
416
417 if __name__ == '__main__':
418 sys.exit(main())
OLDNEW
« no previous file with comments | « build/android/buildbot/bb_annotations.py ('k') | build/android/buildbot/bb_device_steps.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698