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