• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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