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 import re |
14 | 14 |
15 from pylib import android_commands | 15 from pylib import android_commands |
16 from pylib import buildbot_report | 16 from pylib import buildbot_report |
17 from pylib import constants | 17 from pylib import constants |
18 from pylib import perf_tests_helper | |
18 from pylib.cmd_helper import GetCmdOutput | 19 from pylib.cmd_helper import GetCmdOutput |
19 | 20 |
20 | 21 |
21 def DeviceInfo(serial, options): | 22 def DeviceInfo(serial, options): |
22 """Gathers info on a device via various adb calls. | 23 """Gathers info on a device via various adb calls. |
23 | 24 |
24 Args: | 25 Args: |
25 serial: The serial of the attached device to construct info about. | 26 serial: The serial of the attached device to construct info about. |
26 | 27 |
27 Returns: | 28 Returns: |
28 Tuple of device type, build id, report as a string, error messages, and | 29 Tuple of device type, build id, report as a string, error messages, and |
29 boolean indicating whether or not device can be used for testing. | 30 boolean indicating whether or not device can be used for testing. |
30 """ | 31 """ |
31 | 32 |
32 def AdbShellCmd(cmd): | |
33 return GetCmdOutput('adb -s %s shell %s' % (serial, cmd), | |
34 shell=True).strip() | |
35 | |
36 device_adb = android_commands.AndroidCommands(serial) | 33 device_adb = android_commands.AndroidCommands(serial) |
37 | 34 |
38 # TODO(navabi): Replace AdbShellCmd with device_adb. | 35 def AdbShellCommand(cmd): |
39 device_type = AdbShellCmd('getprop ro.build.product') | 36 return '\n'.join(device_adb.RunShellCommand(cmd)) |
40 device_build = AdbShellCmd('getprop ro.build.id') | |
41 device_build_type = AdbShellCmd('getprop ro.build.type') | |
42 device_product_name = AdbShellCmd('getprop ro.product.name') | |
43 | 37 |
44 setup_wizard_disabled = AdbShellCmd( | 38 device_type = AdbShellCommand('getprop ro.build.product') |
39 device_build = AdbShellCommand('getprop ro.build.id') | |
40 device_build_type = AdbShellCommand('getprop ro.build.type') | |
41 device_product_name = AdbShellCommand('getprop ro.product.name') | |
frankf
2013/07/16 19:12:54
There are existing methods in android_commands.py
navabi
2013/07/16 21:48:58
This is calling the android_commands.py. Look at t
frankf
2013/07/16 22:02:17
I meant these: https://code.google.com/p/chromium/
navabi
2013/07/16 23:23:17
Done.
| |
42 | |
43 setup_wizard_disabled = device_adb.RunShellCommand( | |
45 'getprop ro.setupwizard.mode') == 'DISABLED' | 44 'getprop ro.setupwizard.mode') == 'DISABLED' |
46 battery = AdbShellCmd('dumpsys battery') | 45 battery = AdbShellCommand('dumpsys battery') |
47 install_output = GetCmdOutput( | 46 install_output = GetCmdOutput( |
48 ['%s/build/android/adb_install_apk.py' % constants.DIR_SOURCE_ROOT, '--apk', | 47 ['%s/build/android/adb_install_apk.py' % constants.DIR_SOURCE_ROOT, '--apk', |
49 '%s/build/android/CheckInstallApk-debug.apk' % constants.DIR_SOURCE_ROOT]) | 48 '%s/build/android/CheckInstallApk-debug.apk' % constants.DIR_SOURCE_ROOT]) |
50 install_speed_found = re.findall('(\d+) KB/s', install_output) | 49 install_speed_found = re.findall('(\d+) KB/s', install_output) |
51 if install_speed_found: | 50 if install_speed_found: |
52 install_speed = int(install_speed_found[0]) | 51 install_speed = int(install_speed_found[0]) |
53 else: | 52 else: |
54 install_speed = 'Unknown' | 53 install_speed = 'Unknown' |
55 if 'Error' in battery: | 54 if 'Error' in battery: |
56 ac_power = 'Unknown' | 55 ac_power = 'Unknown' |
57 battery_level = 'Unknown' | 56 battery_level = 'Unknown' |
58 battery_temp = 'Unknown' | 57 battery_temp = 'Unknown' |
59 else: | 58 else: |
60 ac_power = re.findall('AC powered: (\w+)', battery)[0] | 59 ac_power = re.findall('AC powered: (\w+)', battery)[0] |
61 battery_level = int(re.findall('level: (\d+)', battery)[0]) | 60 battery_level = int(re.findall('level: (\d+)', battery)[0]) |
62 battery_temp = float(re.findall('temperature: (\d+)', battery)[0]) / 10 | 61 battery_temp = float(re.findall('temperature: (\d+)', battery)[0]) / 10 |
63 report = ['Device %s (%s)' % (serial, device_type), | 62 report = ['Device %s (%s)' % (serial, device_type), |
64 ' Build: %s (%s)' % (device_build, | 63 ' Build: %s (%s)' % |
65 AdbShellCmd('getprop ro.build.fingerprint')), | 64 (device_build, |
65 AdbShellCommand('getprop ro.build.fingerprint')), | |
66 ' Battery: %s%%' % battery_level, | 66 ' Battery: %s%%' % battery_level, |
67 ' Battery temp: %s' % battery_temp, | 67 ' Battery temp: %s' % battery_temp, |
68 ' IMEI slice: %s' % AdbShellCmd('dumpsys iphonesubinfo ' | 68 ' IMEI slice: %s' % AdbShellCommand('dumpsys iphonesubinfo ' |
69 '| grep Device' | 69 '| grep Device' |
70 "| awk '{print $4}'")[-6:], | 70 "| awk '{print $4}'")[-6:], |
71 ' Wifi IP: %s' % AdbShellCmd('getprop dhcp.wlan0.ipaddress'), | 71 ' Wifi IP: %s' % AdbShellCommand('getprop dhcp.wlan0.ipaddress'), |
frankf
2013/07/16 19:12:54
Same with these.
| |
72 ' Install Speed: %s KB/s' % install_speed, | 72 ' Install Speed: %s KB/s' % install_speed, |
73 ''] | 73 ''] |
74 | 74 |
75 errors = [] | 75 errors = [] |
76 if battery_level < 15: | 76 if battery_level < 15: |
77 errors += ['Device critically low in battery. Turning off device.'] | 77 errors += ['Device critically low in battery. Turning off device.'] |
78 if (not setup_wizard_disabled and device_build_type != 'user' and | 78 if (not setup_wizard_disabled and device_build_type != 'user' and |
79 not options.no_provisioning_check): | 79 not options.no_provisioning_check): |
80 errors += ['Setup wizard not disabled. Was it provisioned correctly?'] | 80 errors += ['Setup wizard not disabled. Was it provisioned correctly?'] |
81 if device_product_name == 'mantaray' and ac_power != 'true': | 81 if device_product_name == 'mantaray' and ac_power != 'true': |
82 errors += ['Mantaray device not connected to AC power.'] | 82 errors += ['Mantaray device not connected to AC power.'] |
83 # TODO(navabi): Insert warning once we have a better handle of what install | 83 # TODO(navabi): Insert warning once we have a better handle of what install |
84 # speeds to expect. The following lines were causing too many alerts. | 84 # speeds to expect. The following lines were causing too many alerts. |
85 # if install_speed < 500: | 85 # if install_speed < 500: |
86 # errors += ['Device install speed too low. Do not use for testing.'] | 86 # errors += ['Device install speed too low. Do not use for testing.'] |
87 | 87 |
88 # Causing the device status check step fail for slow install speed or low | 88 # Causing the device status check step fail for slow install speed or low |
89 # battery currently is too disruptive to the bots (especially try bots). | 89 # battery currently is too disruptive to the bots (especially try bots). |
90 # Turn off devices with low battery and the step does not fail. | 90 # Turn off devices with low battery and the step does not fail. |
91 if battery_level < 15: | 91 if battery_level < 15: |
92 device_adb.EnableAdbRoot() | 92 device_adb.EnableAdbRoot() |
93 AdbShellCmd('reboot -p') | 93 AdbShellCommand('reboot -p') |
frankf
2013/07/16 19:12:54
Also this.
navabi
2013/07/16 21:48:58
Done. Added shutdown to android_commands.py
| |
94 return device_type, device_build, '\n'.join(report), errors, True | 94 full_report = '\n'.join(report) |
95 return device_type, device_build, battery_level, full_report, errors, True | |
95 | 96 |
96 | 97 |
97 def CheckForMissingDevices(options, adb_online_devs): | 98 def CheckForMissingDevices(options, adb_online_devs): |
98 """Uses file of previous online devices to detect broken phones. | 99 """Uses file of previous online devices to detect broken phones. |
99 | 100 |
100 Args: | 101 Args: |
101 options: out_dir parameter of options argument is used as the base | 102 options: out_dir parameter of options argument is used as the base |
102 directory to load and update the cache file. | 103 directory to load and update the cache file. |
103 adb_online_devs: A list of serial numbers of the currently visible | 104 adb_online_devs: A list of serial numbers of the currently visible |
104 and online attached devices. | 105 and online attached devices. |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
182 | 183 |
183 def main(): | 184 def main(): |
184 parser = optparse.OptionParser() | 185 parser = optparse.OptionParser() |
185 parser.add_option('', '--out-dir', | 186 parser.add_option('', '--out-dir', |
186 help='Directory where the device path is stored', | 187 help='Directory where the device path is stored', |
187 default=os.path.join(os.path.dirname(__file__), '..', | 188 default=os.path.join(os.path.dirname(__file__), '..', |
188 '..', 'out')) | 189 '..', 'out')) |
189 parser.add_option('--no-provisioning-check', | 190 parser.add_option('--no-provisioning-check', |
190 help='Will not check if devices are provisioned properly.') | 191 help='Will not check if devices are provisioned properly.') |
191 | 192 |
193 parser.add_option('--device-status-dashboard', | |
194 help='Output device status data for dashboard.') | |
195 | |
192 options, args = parser.parse_args() | 196 options, args = parser.parse_args() |
193 if args: | 197 if args: |
194 parser.error('Unknown options %s' % args) | 198 parser.error('Unknown options %s' % args) |
195 devices = android_commands.GetAttachedDevices() | 199 devices = android_commands.GetAttachedDevices() |
196 types, builds, reports, errors = [], [], [], [] | 200 offline_devices = android_commands.GetAttachedOfflineDevices() |
201 | |
202 types, builds, batteries, reports, errors = [], [], [], [], [] | |
197 fail_step_lst = [] | 203 fail_step_lst = [] |
198 if devices: | 204 if devices: |
199 types, builds, reports, errors, fail_step_lst = ( | 205 types, builds, batteries, reports, errors, fail_step_lst = ( |
200 zip(*[DeviceInfo(dev, options) for dev in devices])) | 206 zip(*[DeviceInfo(dev, options) for dev in devices])) |
201 | 207 |
208 if options.device_status_dashboard: | |
209 perf_tests_helper.PrintPerfResult('BotDevices', 'OnlineDevices', | |
210 [len(devices)], 'devices') | |
211 perf_tests_helper.PrintPerfResult('BotDevices', 'OfflineDevices', | |
212 [len(offline_devices)], 'devices', | |
213 'unimportant') | |
214 for serial, battery in zip(devices, batteries): | |
215 perf_tests_helper.PrintPerfResult('DeviceBattery', serial, [battery], '%', | |
216 'unimportant') | |
217 return 0 | |
218 | |
202 err_msg = CheckForMissingDevices(options, devices) or [] | 219 err_msg = CheckForMissingDevices(options, devices) or [] |
203 | 220 |
204 unique_types = list(set(types)) | 221 unique_types = list(set(types)) |
205 unique_builds = list(set(builds)) | 222 unique_builds = list(set(builds)) |
206 | 223 |
207 buildbot_report.PrintMsg('Online devices: %d. Device types %s, builds %s' | 224 buildbot_report.PrintMsg('Online devices: %d. Device types %s, builds %s' |
208 % (len(devices), unique_types, unique_builds)) | 225 % (len(devices), unique_types, unique_builds)) |
209 print '\n'.join(reports) | 226 print '\n'.join(reports) |
210 | 227 |
211 for serial, dev_errors in zip(devices, errors): | 228 for serial, dev_errors in zip(devices, errors): |
(...skipping 12 matching lines...) Expand all Loading... | |
224 # devices with critically low battery or install speed. Remove those devices | 241 # devices with critically low battery or install speed. Remove those devices |
225 # from testing, allowing build to continue with good devices. | 242 # from testing, allowing build to continue with good devices. |
226 return 1 | 243 return 1 |
227 | 244 |
228 if not devices: | 245 if not devices: |
229 return 1 | 246 return 1 |
230 | 247 |
231 | 248 |
232 if __name__ == '__main__': | 249 if __name__ == '__main__': |
233 sys.exit(main()) | 250 sys.exit(main()) |
OLD | NEW |