cpu_temperature_reader.cc 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "chromeos/system/cpu_temperature_reader.h"
  5. #include "base/files/file_enumerator.h"
  6. #include "base/files/file_path.h"
  7. #include "base/files/file_util.h"
  8. #include "base/location.h"
  9. #include "base/logging.h"
  10. #include "base/strings/string_number_conversions.h"
  11. #include "base/strings/string_util.h"
  12. #include "base/task/task_traits.h"
  13. namespace chromeos {
  14. namespace system {
  15. using CPUTemperatureInfo = CPUTemperatureReader::CPUTemperatureInfo;
  16. namespace {
  17. // The location we read our CPU temperature and channel label from.
  18. constexpr char kDefaultHwmonDir[] = "/sys/class/hwmon/";
  19. constexpr char kDeviceDir[] = "device";
  20. constexpr char kHwmonDirectoryPattern[] = "hwmon*";
  21. constexpr char kCPUTempFilePattern[] = "temp*_input";
  22. // The contents of sysfs files might contain a newline at the end. Use this
  23. // function to read from a sysfs file and remove the newline.
  24. bool ReadFileContentsAndTrimWhitespace(const base::FilePath& path,
  25. std::string* contents_out) {
  26. if (!base::ReadFileToString(path, contents_out))
  27. return false;
  28. base::TrimWhitespaceASCII(*contents_out, base::TRIM_TRAILING, contents_out);
  29. return true;
  30. }
  31. // Reads the temperature as degrees Celsius from the file at |path|, which is
  32. // expected to contain the temperature in millidegrees Celsius. Converts the
  33. // value into degrees and then stores it in |*temp_celsius_out|. returns true if
  34. // the value was successfully read from file, parsed as an int, and converted.
  35. bool ReadTemperatureFromPath(const base::FilePath& path,
  36. double* temp_celsius_out) {
  37. std::string temperature_string;
  38. if (!ReadFileContentsAndTrimWhitespace(path, &temperature_string))
  39. return false;
  40. uint32_t temperature = 0;
  41. if (!base::StringToUint(temperature_string, &temperature))
  42. return false;
  43. *temp_celsius_out = temperature / 1000.0;
  44. return true;
  45. }
  46. // Gets the label describing this temperature. Use the file "temp*_label" if it
  47. // is present, or fall back on the file "name" or |label_path|.
  48. std::string GetLabelFromPath(const base::FilePath& label_path) {
  49. std::string label;
  50. if (base::PathExists(label_path) &&
  51. ReadFileContentsAndTrimWhitespace(base::FilePath(label_path), &label) &&
  52. !label.empty()) {
  53. return label;
  54. }
  55. base::FilePath name_path = label_path.DirName().Append("name");
  56. if (base::PathExists(name_path) &&
  57. ReadFileContentsAndTrimWhitespace(name_path, &label) && !label.empty()) {
  58. return label;
  59. }
  60. return label_path.value();
  61. }
  62. void ReadTemperaturesFromDirectory(const base::FilePath& hwmon_path,
  63. std::vector<CPUTemperatureInfo>* result) {
  64. base::FileEnumerator enumerator(
  65. hwmon_path, false, base::FileEnumerator::FILES, kCPUTempFilePattern);
  66. for (base::FilePath temperature_path = enumerator.Next();
  67. !temperature_path.empty(); temperature_path = enumerator.Next()) {
  68. CPUTemperatureInfo info;
  69. if (!ReadTemperatureFromPath(temperature_path, &info.temp_celsius)) {
  70. DLOG(WARNING) << "Unable to read CPU temperature from "
  71. << temperature_path.value();
  72. continue;
  73. }
  74. // Get appropriate temp*_label file.
  75. std::string label_path = temperature_path.value();
  76. base::ReplaceSubstringsAfterOffset(&label_path, 0, "input", "label");
  77. info.label = GetLabelFromPath(base::FilePath(label_path));
  78. result->push_back(info);
  79. }
  80. }
  81. } // namespace
  82. CPUTemperatureReader::CPUTemperatureInfo::CPUTemperatureInfo() = default;
  83. CPUTemperatureReader::CPUTemperatureInfo::~CPUTemperatureInfo() = default;
  84. CPUTemperatureReader::CPUTemperatureReader() : hwmon_dir_(kDefaultHwmonDir) {}
  85. CPUTemperatureReader::~CPUTemperatureReader() = default;
  86. std::vector<CPUTemperatureInfo> CPUTemperatureReader::GetCPUTemperatures() {
  87. std::vector<CPUTemperatureInfo> result;
  88. // Get directories /sys/class/hwmon/hwmon*.
  89. base::FileEnumerator hwmon_enumerator(hwmon_dir_, false,
  90. base::FileEnumerator::DIRECTORIES,
  91. kHwmonDirectoryPattern);
  92. for (base::FilePath hwmon_path = hwmon_enumerator.Next(); !hwmon_path.empty();
  93. hwmon_path = hwmon_enumerator.Next()) {
  94. // Get temp*_input files in hwmon*/ and hwmon*/device/. A survey of DUTs
  95. // suggests that temp values are contained in hwmon*/device on kernel 3.14
  96. // and earlier and directly in hwmon*/ in kernel 3.18 and later. When no
  97. // device subdirectory is present, the temp values are always contained
  98. // directly within the hwmon directory.
  99. ReadTemperaturesFromDirectory(hwmon_path, &result);
  100. if (base::PathExists(hwmon_path.Append(kDeviceDir))) {
  101. ReadTemperaturesFromDirectory(hwmon_path.Append(kDeviceDir), &result);
  102. }
  103. }
  104. return result;
  105. }
  106. } // namespace system
  107. } // namespace chromeos