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