1#!/usr/bin/env python 2# Copyright 2015 The Chromium Authors 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6import json 7import multiprocessing 8import os 9import platform 10import sys 11 12# Add src/testing/ into sys.path for importing common without pylint errors. 13sys.path.append( 14 os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))) 15from scripts import common 16 17 18def is_linux(): 19 return sys.platform.startswith('linux') 20 21 22def get_free_disk_space(failures): 23 """Returns the amount of free space on the current disk, in GiB. 24 25 Returns: 26 The amount of free space on the current disk, measured in GiB. 27 """ 28 if os.name == 'posix': 29 # Stat the current path for info on the current disk. 30 stat_result = os.statvfs('.') 31 # Multiply block size by number of free blocks, express in GiB. 32 return stat_result.f_frsize * stat_result.f_bavail / (1024.0 ** 3) 33 34 failures.append('get_free_disk_space: OS %s not supported.' % os.name) 35 return 0 36 37 38def get_num_cpus(failures): 39 """Returns the number of logical CPUs on this machine. 40 41 Returns: 42 The number of logical CPUs on this machine, or 'unknown' if indeterminate. 43 """ 44 try: 45 return multiprocessing.cpu_count() 46 except NotImplementedError: 47 failures.append('get_num_cpus') 48 return 'unknown' 49 50 51def get_device_info(args, failures): 52 """Parses the device info for each attached device, and returns a summary 53 of the device info and any mismatches. 54 55 Returns: 56 A dict indicating the result. 57 """ 58 if not is_linux(): 59 return {} 60 61 with common.temporary_file() as tempfile_path: 62 test_cmd = [ 63 sys.executable, 64 os.path.join(args.paths['checkout'], 65 'third_party', 66 'catapult', 67 'devil', 68 'devil', 69 'android', 70 'tools', 71 'device_status.py'), 72 '--json-output', tempfile_path, 73 '--denylist-file', os.path.join( 74 args.paths['checkout'], 'out', 'bad_devices.json') 75 ] 76 if args.args: 77 test_cmd.extend(args.args) 78 79 rc = common.run_command(test_cmd) 80 if rc: 81 failures.append('device_status') 82 return {} 83 84 with open(tempfile_path, 'r') as src: 85 device_info = json.load(src) 86 87 results = {} 88 results['devices'] = sorted(v['serial'] for v in device_info) 89 90 details = [ 91 v['ro.build.fingerprint'] for v in device_info if not v['denylisted']] 92 93 def unique_build_details(index): 94 return sorted(list({v.split(':')[index] for v in details})) 95 96 parsed_details = { 97 'device_names': unique_build_details(0), 98 'build_versions': unique_build_details(1), 99 'build_types': unique_build_details(2), 100 } 101 102 for k, v in parsed_details.items(): 103 if len(v) == 1: 104 results[k] = v[0] 105 else: 106 results[k] = 'MISMATCH' 107 results['%s_list' % k] = v 108 failures.append(k) 109 110 for v in device_info: 111 if v['denylisted']: 112 failures.append('Device %s denylisted' % v['serial']) 113 114 return results 115 116 117def main_run(args): 118 failures = [] 119 host_info = {} 120 host_info['os_system'] = platform.system() 121 host_info['os_release'] = platform.release() 122 123 host_info['processor'] = platform.processor() 124 host_info['num_cpus'] = get_num_cpus(failures) 125 host_info['free_disk_space'] = get_free_disk_space(failures) 126 127 host_info['python_version'] = platform.python_version() 128 host_info['python_path'] = sys.executable 129 130 host_info['devices'] = get_device_info(args, failures) 131 132 json.dump({ 133 'valid': True, 134 'failures': failures, 135 '_host_info': host_info, 136 }, args.output) 137 138 if len(failures) != 0: 139 return common.INFRA_FAILURE_EXIT_CODE 140 return 0 141 142 143def main_compile_targets(args): 144 json.dump([], args.output) 145 146 147if __name__ == '__main__': 148 funcs = { 149 'run': main_run, 150 'compile_targets': main_compile_targets, 151 } 152 sys.exit(common.run_script(sys.argv[1:], funcs)) 153