host_info.py 3.9 KB

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