diff options
author | Vincent Palomares <paillon@google.com> | 2018-10-04 13:48:14 -0700 |
---|---|---|
committer | Vincent Palomares <paillon@google.com> | 2018-10-05 15:36:27 -0700 |
commit | 28c812c5095885d9b70e88c8da07650aa7f74105 (patch) | |
tree | a02afd093c4fb46df77116dec85329a59f19ce6a /thermal | |
parent | 38a12db3544f3fbd3c85dff1129ad1c00d997d30 (diff) | |
download | pixel-28c812c5095885d9b70e88c8da07650aa7f74105.tar.gz |
thermal: Move common thermal HAL code to shared Pixel library.
Created new 'thermal_structs.h' file to avoid library -> HAL include dependency.
Removed battery_thresholds.cpp/h.
Bug: 117104007
Test: adb shell dumpsys hardware_properties
adb shell su 0 lshal debug android.hardware.thermal@1.1::IThermal/default
pts -m PtsThermalHalTestCases
vts -m VtsHalThermalV1_0Target
vts -m VtsHalThermalV1_1Target
Change-Id: Id517eea8e3e9bee1fbc579f176ff8850180ed105
Signed-off-by: Vincent Palomares <paillon@google.com>
Diffstat (limited to 'thermal')
-rw-r--r-- | thermal/Android.bp | 25 | ||||
-rw-r--r-- | thermal/ThermalConfigParser.cpp | 211 | ||||
-rw-r--r-- | thermal/cooling_devices.cpp | 79 | ||||
-rw-r--r-- | thermal/device_file_watcher.cpp | 146 | ||||
-rw-r--r-- | thermal/include/pixelthermal/ThermalConfigParser.h | 44 | ||||
-rw-r--r-- | thermal/include/pixelthermal/cooling_devices.h | 75 | ||||
-rw-r--r-- | thermal/include/pixelthermal/device_file_watcher.h | 122 | ||||
-rw-r--r-- | thermal/include/pixelthermal/sensors.h | 59 | ||||
-rw-r--r-- | thermal/include/pixelthermal/thermal_structs.h | 54 | ||||
-rw-r--r-- | thermal/sensors.cpp | 65 |
10 files changed, 880 insertions, 0 deletions
diff --git a/thermal/Android.bp b/thermal/Android.bp new file mode 100644 index 00000000..0f2a5823 --- /dev/null +++ b/thermal/Android.bp @@ -0,0 +1,25 @@ +cc_library { + name: "libpixelthermal", + vendor_available: true, + export_include_dirs: ["include"], + + srcs: [ + "cooling_devices.cpp", + "device_file_watcher.cpp", + "sensors.cpp", + "ThermalConfigParser.cpp", + ], + + cflags: [ + "-Wall", + "-Werror", + ], + + shared_libs: [ + "libbase", + "libcutils", + "libhwbinder", + "libutils", + "android.hardware.thermal@1.0" + ], +} diff --git a/thermal/ThermalConfigParser.cpp b/thermal/ThermalConfigParser.cpp new file mode 100644 index 00000000..04ed25be --- /dev/null +++ b/thermal/ThermalConfigParser.cpp @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <regex> +#include <vector> + +#include <android-base/file.h> +#include <android-base/logging.h> +#include <android-base/properties.h> +#include <android-base/stringprintf.h> + +#include "include/pixelthermal/ThermalConfigParser.h" + +namespace android { +namespace hardware { +namespace google { +namespace pixel { +namespace thermal { + +constexpr float kConfigMultiplier = .001; + +// For now this just defines the sensor name and thresholds. +struct SensorConfig { + SensorConfig() : sensor_name(""), threshold(0.0), action(""), + rule_name("") {} + SensorConfig( + const std::string& sensor_name, float threshold, + const std::string& action, const std::string& rule_name) + : sensor_name(sensor_name), + threshold(threshold), + action(action), + rule_name(rule_name) {} + std::string sensor_name; + float threshold; + std::string action; + std::string rule_name; +}; + +// Assign out if out == NAN or config_threshold < out. +static void checkAndAssignThreshold(float config_threshold, float* out) { + if (std::isnan(*out) || config_threshold < *out) { + *out = config_threshold; + } +} + +static void assignThresholdsFromConfig( + const std::vector<SensorConfig>& configs, + const std::map<std::string, SensorInfo>& sensor_name_type_map, + ThrottlingThresholds* threshold) { + for (const SensorConfig& config : configs) { + switch (sensor_name_type_map.at(config.sensor_name).type) { + case TemperatureType::CPU: + checkAndAssignThreshold(config.threshold, &threshold->cpu); + break; + case TemperatureType::GPU: + checkAndAssignThreshold(config.threshold, &threshold->gpu); + break; + case TemperatureType::BATTERY: + checkAndAssignThreshold(config.threshold, &threshold->battery); + break; + case TemperatureType::SKIN: + // For the skin throttling threshold take the min value from + // the skin-monitor rule. + if (config.rule_name == "SKIN-MONITOR") { + checkAndAssignThreshold(config.threshold, &threshold->ss); + } + break; + default: + LOG(ERROR) << "Unknown sensor: " << config.sensor_name; + break; + } + } +} + +static void parseThermalEngineConfig( + const std::string& config_path, std::vector<SensorConfig>* configs, + std::vector<SensorConfig>* shutdown_configs) { + std::string data; + if (!android::base::ReadFileToString(config_path, &data)) { + LOG(ERROR) << "Error reading config path: " << config_path; + return; + } + + // Parse out sensor name and thresholds for ss configs. + static const std::regex ss_block_regex( + R"([.\n]*\[(.+)\]\nalgo_type\s+ss\n(?:.*\n)?sensor\s+)" + R"(([\w\d-]+)\n(?:.*\n)?set_point\s+(\d+))"); + auto block_begin = std::sregex_iterator( + data.begin(), data.end(), ss_block_regex); + auto block_end = std::sregex_iterator(); + for (std::sregex_iterator itr = block_begin; itr != block_end; ++itr) { + configs->emplace_back( + SensorConfig( + itr->str(2), std::stoi(itr->str(3)) * kConfigMultiplier, "", + itr->str(1))); + } + + // Parse out sensor name, thresholds, and action for monitor configs. + static const std::regex monitor_block_regex( + R"([.\n]*\[(.+)\]\nalgo_type\s+monitor\n(?:.*\n)?sensor\s+)" + R"(([\w\d-]+)\n(?:.*\n)?thresholds\s+([^\n]+)\n(?:.*\n)?actions\s+([^\n]+))"); + block_begin = std::sregex_iterator( + data.begin(), data.end(), monitor_block_regex); + for (std::sregex_iterator itr = block_begin; itr != block_end; ++itr) { + SensorConfig sensor_config; + + sensor_config.rule_name = itr->str(1); + sensor_config.sensor_name = itr->str(2); + std::string thresholds_str = itr->str(3); + std::string actions_str = itr->str(4); + + static const std::regex delim_regex{R"(\s+)"}; + std::vector<std::string> thresholds{ + std::sregex_token_iterator(thresholds_str.begin(), thresholds_str.end(), delim_regex, -1), + std::sregex_token_iterator() + }; + std::vector<std::string> actions{ + std::sregex_token_iterator(actions_str.begin(), actions_str.end(), delim_regex, -1), + std::sregex_token_iterator() + }; + + if (thresholds.size() != actions.size()) { + LOG(ERROR) << "Unbalanced thresholds (" + << thresholds.size() + << ") and actions (" + << actions.size() << ") in monitor algo for sensor (" + << sensor_config.sensor_name + << ") of rule (" << sensor_config.rule_name << ")"; + return; + } + + for (std::size_t i = 0; i < thresholds.size(); ++i) { + sensor_config.threshold = std::stoi(thresholds[i]) * kConfigMultiplier; + sensor_config.action = actions[i]; + + // Filter out the shutdown thresholds. + if (sensor_config.action.find("shutdown") != std::string::npos) { + shutdown_configs->push_back(sensor_config); + } else { + configs->push_back(sensor_config); + } + } + } +} + +static void dumpSensorConfigs( + const std::vector<SensorConfig>& sensor_config_vec, + const std::map<std::string, SensorInfo>& typeMap) { + for (const auto& sensor_config : sensor_config_vec) { + LOG(INFO) << "Sensor name: " << sensor_config.sensor_name + << " type: " << android::hardware::thermal::V1_0::toString( + typeMap.at(sensor_config.sensor_name).type) + << " with threshold: " << sensor_config.threshold + << " from rule: " << sensor_config.rule_name + << sensor_config.action.empty() ? "" + : " sensor config action " + sensor_config.action; + } +} + +void InitializeThresholdsFromThermalConfig( + const std::string& thermal_config, + const std::string& vr_thermal_config, + const std::map<std::string, SensorInfo>& typeMap, + ThrottlingThresholds *thresholds, + ThrottlingThresholds *shutdown_thresholds, + ThrottlingThresholds *vr_thresholds) { + std::vector<SensorConfig> sensor_configs; + std::vector<SensorConfig> shutdown_configs; + parseThermalEngineConfig( + thermal_config, &sensor_configs, &shutdown_configs); + + assignThresholdsFromConfig(sensor_configs, typeMap, thresholds); + assignThresholdsFromConfig(shutdown_configs, typeMap, shutdown_thresholds); + + LOG(INFO) << "Sensor configs"; + dumpSensorConfigs(sensor_configs, typeMap); + LOG(INFO) << "Shutdown configs"; + dumpSensorConfigs(shutdown_configs, typeMap); + + sensor_configs.clear(); + shutdown_configs.clear(); + parseThermalEngineConfig( + vr_thermal_config, &sensor_configs, &shutdown_configs); + + LOG(INFO) << "VR Sensor configs"; + dumpSensorConfigs(sensor_configs, typeMap); + LOG(INFO) << "VR Shutdown configs"; + dumpSensorConfigs(shutdown_configs, typeMap); + + assignThresholdsFromConfig( + sensor_configs, typeMap, vr_thresholds); +} + +} // namespace thermal +} // namespace pixel +} // namespace google +} // namespace hardware +} // namespace android diff --git a/thermal/cooling_devices.cpp b/thermal/cooling_devices.cpp new file mode 100644 index 00000000..a8babf94 --- /dev/null +++ b/thermal/cooling_devices.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <fstream> + +#include <android-base/file.h> +#include <android-base/logging.h> +#include <android-base/stringprintf.h> +#include <android-base/strings.h> + +#include "include/pixelthermal/cooling_devices.h" + +namespace android { +namespace hardware { +namespace google { +namespace pixel { +namespace thermal { + +constexpr char kCoolingDeviceCurStateSuffix[] = "cur_state"; + +bool CoolingDevices::addCoolingDevice( + const std::string& cooling_device_name, const std::string& path) { + return cooling_device_name_to_path_map_.emplace( + cooling_device_name, path).second; +} + +bool CoolingDevices::getCoolingDeviceState( + const std::string& cooling_device_name, int* data) const { + auto cooling_device_itr = cooling_device_name_to_path_map_.find( + cooling_device_name); + if (cooling_device_itr == cooling_device_name_to_path_map_.end()) { + return false; + } + + std::string path = android::base::StringPrintf( + "%s/%s", cooling_device_itr->second.c_str(), + kCoolingDeviceCurStateSuffix); + + std::string cooling_device_data; + android::base::ReadFileToString(path, &cooling_device_data); + cooling_device_data = android::base::Trim(cooling_device_data); + + if (cooling_device_data.empty()) { + LOG(ERROR) << "Could not read " + << getCoolingDevicePath(cooling_device_name); + return false; + } + + *data = std::stoi(cooling_device_data); + return true; +} + +std::string CoolingDevices::getCoolingDevicePath( + const std::string& cooling_device_name) const { + auto cooling_device_itr = cooling_device_name_to_path_map_.find( + cooling_device_name); + if (cooling_device_itr == cooling_device_name_to_path_map_.end()) { + return ""; + } + return cooling_device_itr->second; +} + +} // namespace thermal +} // namespace pixel +} // namespace google +} // namespace hardware +} // namespace android diff --git a/thermal/device_file_watcher.cpp b/thermal/device_file_watcher.cpp new file mode 100644 index 00000000..109ac9a3 --- /dev/null +++ b/thermal/device_file_watcher.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include <chrono> +#include <dirent.h> +#include <fstream> +#include <sys/inotify.h> +#include <sys/resource.h> +#include <sys/types.h> + +#include <android-base/logging.h> +#include <android-base/strings.h> + +#include "include/pixelthermal/device_file_watcher.h" + +namespace android { +namespace hardware { +namespace google { +namespace pixel { +namespace thermal { + +using std::chrono_literals::operator""ms; + +// iNotify constants. +constexpr int kiNotifyEventSize = sizeof(struct inotify_event); + +void DeviceFileWatcher::registerFilesToWatch( + const std::vector<std::string> files_to_watch) { + inotify_fd_ = unique_fd(inotify_init()); + if (inotify_fd_ < 0) { + LOG(ERROR) << "iNotify init error."; + return; + } + + for (const auto& path : files_to_watch) { + std::lock_guard<std::mutex> _lock(watcher_mutex_); + watch_to_file_path_map_.emplace( + inotify_add_watch(inotify_fd_, path.c_str(), IN_MODIFY), + path); + } +} + +bool DeviceFileWatcher::startWatchingDeviceFiles() { + if (initializedOk()) { + // Start the watcher thread. + std::packaged_task<void(void)> watcher_task( + std::bind(&DeviceFileWatcher::watchFilesForModificationsAndCallback, + this)); + watcher_future_ = watcher_task.get_future(); + watcher_thread_ = std::thread(std::move(watcher_task)); + watcher_thread_.detach(); + return true; + } + return false; +} + +void DeviceFileWatcher::registerCallback( + std::function<void(const std::pair<std::string, std::string>&)> cb) { + std::lock_guard<std::mutex> _lock(watcher_mutex_); + cb_ = cb; +} + +void DeviceFileWatcher::registerQueueOverflowCallback( + std::function<void(void)> cb) { + std::lock_guard<std::mutex> _lock(watcher_mutex_); + queue_overflow_cb_ = cb; +} + +void DeviceFileWatcher::watchFilesForModificationsAndCallback() { + // Increase the priority of the watcher thread so we minimize losing + // data. + if (int errval = setpriority(PRIO_PROCESS, 0, -5)) { + LOG(ERROR) << "Failed to setpriority the watcher thread: " << errval; + } + + // We use this while(1) because inotify read() blocks, thus stopping the + // watcher thread from just spinning. + while (initializedOk()) { + char buffer[kiNotifyEventSize]; + TEMP_FAILURE_RETRY(read(inotify_fd_, buffer, sizeof(buffer))); + struct inotify_event* event; + event = reinterpret_cast<struct inotify_event*>(buffer); + + // Catch the case where we overflow the queue. In this case we probably + // dropped some modifications so we re-read everything and re-notify. + if (event->mask & IN_Q_OVERFLOW) { + LOG(ERROR) << "iNotify queue overflowed! Modification events " + << "dropped."; + { + std::lock_guard<std::mutex> _lock(watcher_mutex_); + if (queue_overflow_cb_) { + queue_overflow_cb_(); + } + } + } + + if (event->mask & IN_MODIFY) { + std::lock_guard<std::mutex> _lock(watcher_mutex_); + std::string path = watch_to_file_path_map_.at(event->wd); + + // Bound the read to 2 characters because we should only be reading + // integer CPU throttling values. + char file_contents[2]; + std::ifstream infile(path, std::ifstream::in); + infile.read(file_contents, 2); + std::string data(file_contents); + data = android::base::Trim(data); + + if (!data.empty()) { + if (cb_) { + cb_(std::make_pair(path, data)); + } else { + LOG(ERROR) << "Consumer callback is null!"; + } + } + } + + // Rate limit our thread to be able to service changes at around a + // second. We don't want to make the system do more work if things fall + // off a cliff. We are watching eight files, one per CPU, so 125 + // milliseconds should be such that if all of them had a modification at + // the same time it would take the thread a second to read all of them. + std::this_thread::sleep_for(125ms); + } + + // We should really not get here until DeviceFileWatcher is destroyed. + LOG(ERROR) << "Watcher thread has stopped."; +} + +} // namespace thermal +} // namespace pixel +} // namespace google +} // namespace hardware +} // namespace android diff --git a/thermal/include/pixelthermal/ThermalConfigParser.h b/thermal/include/pixelthermal/ThermalConfigParser.h new file mode 100644 index 00000000..89b53497 --- /dev/null +++ b/thermal/include/pixelthermal/ThermalConfigParser.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __THERMAL_CONFIG_PARSER_H__ +#define __THERMAL_CONFIG_PARSER_H__ + +#include "thermal_structs.h" + +#include <map> + +namespace android { +namespace hardware { +namespace google { +namespace pixel { +namespace thermal { + +void InitializeThresholdsFromThermalConfig( + const std::string& thermal_config, + const std::string& vr_thermal_config, + const std::map<std::string, SensorInfo>& typeMap, + ThrottlingThresholds *thresholds, + ThrottlingThresholds *shutdown_thresholds, + ThrottlingThresholds *vr_thresholds); + +} // namespace thermal +} // namespace pixel +} // namespace google +} // namespace hardware +} // namespace android + +#endif diff --git a/thermal/include/pixelthermal/cooling_devices.h b/thermal/include/pixelthermal/cooling_devices.h new file mode 100644 index 00000000..dde39be8 --- /dev/null +++ b/thermal/include/pixelthermal/cooling_devices.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __COOLING_DEVICES_H__ +#define __COOLING_DEVICES_H__ + +#include <unordered_map> +#include <string> + +namespace android { +namespace hardware { +namespace google { +namespace pixel { +namespace thermal { + +class CoolingDevices { + public: + CoolingDevices() = default; + ~CoolingDevices() = default; + CoolingDevices(const CoolingDevices&) = delete; + void operator=(const CoolingDevices&) = delete; + + // Keep track of the cooling device given the path to its directory. + // The cooling device names are defined in: thermal-helper.cpp in + // kValidCoolingDeviceNameTypeMap. Path is the cooling device directory. + // This is something like: /sys/devices/virtual/thermal/cooling_device_X. + // This function assumes that the top level directory at least has a + // cur_state file in it, which represents the current state of the cooling + // device. Returns true if add succeeds. False otherwise. + bool addCoolingDevice(const std::string& cooling_device_name, + const std::string& path); + + // If the cooling device name is in the map this will read the cur_state + // file within the directory, fill in the data param with the contents of + // that file, and return true. Else it will return false and leave data + // untouched. + bool getCoolingDeviceState(const std::string& cooling_device_name, + int* data) const; + + // Get the file path given the cooling device name. If the cooling device + // name has not been added to CoolingDevices, this will return an empty + // string. + std::string getCoolingDevicePath( + const std::string& cooling_device_name) const; + + size_t getNumCoolingDevices() const { + return cooling_device_name_to_path_map_.size(); + } + + private: + std::unordered_map<std::string, std::string> + cooling_device_name_to_path_map_; +}; + +} // namespace thermal +} // namespace pixel +} // namespace google +} // namespace hardware +} // namespace android + +#endif // __COOLING_DEVICES_H__ + diff --git a/thermal/include/pixelthermal/device_file_watcher.h b/thermal/include/pixelthermal/device_file_watcher.h new file mode 100644 index 00000000..3d208545 --- /dev/null +++ b/thermal/include/pixelthermal/device_file_watcher.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __DEVICE_FILE_WATCHER_H__ +#define __DEVICE_FILE_WATCHER_H__ + +#include <chrono> +#include <condition_variable> +#include <future> +#include <list> +#include <mutex> +#include <string> +#include <thread> +#include <vector> + +#include <android-base/unique_fd.h> + +#include "cooling_devices.h" + +namespace android { +namespace hardware { +namespace google { +namespace pixel { +namespace thermal { + +using android::base::unique_fd; +using std::chrono_literals::operator""ms; +using WatcherCallback = + std::function<void(const std::pair<std::string, std::string>&)>; + +/* A helper class to watch modifications to files. */ +class DeviceFileWatcher { + public: + DeviceFileWatcher() = default; + ~DeviceFileWatcher() = default; + + // Disallow copy and assign. + DeviceFileWatcher(const DeviceFileWatcher&) = delete; + void operator=(const DeviceFileWatcher&) = delete; + + // Start the thread and return true if it succeeds. This function will + // check that there are files registered to watch and that there is a + // callback registered. If either conditions are not met this function will + // return false. + bool startWatchingDeviceFiles(); + // Give the file watcher a list of files to start watching. This helper + // class will by default wait for modifications to the file. + void registerFilesToWatch(const std::vector<std::string> files_to_watch); + // Give the file watcher a callback to be called when processing the data + // read from the watched changes list. + void registerCallback(std::function<void( + const std::pair<std::string, std::string>&)> cb); + // Register a function called back if we see a queue overflow event from + // inotify. + void registerQueueOverflowCallback(std::function<void(void)> cb); + // This class is properly initialized if there is a callback that's + // registered and if we have files to watch. + bool initializedOk() const { + return watch_to_file_path_map_.size() && cb_; + } + + // Get the status of the threads. watcher_future_ can be invalid here, if + // we call getWatcherThreadStatus() without first calling + // startWatchingDeviceFiles(). In the case that we haven't spawned any + // threads, we'll just return std::future_status::ready which indicates + // that the thread is no longer running. + std::future_status getWatcherThreadStatus() const { + return watcher_future_.valid() ? + watcher_future_.wait_for(0ms) : std::future_status::ready; + } + + private: + // The work done by the watcher thread. This will use inotify to check for + // modifications to the files to watch. If any modification is seen this + // will callback the registered function with the new data read from the + // modified file. + void watchFilesForModificationsAndCallback(); + + unique_fd inotify_fd_; + // Maps iNotify watch descriptor to cooling device state file path. + std::unordered_map<int, std::string> watch_to_file_path_map_; + + // This thread watches the files for modifications and fills out the values + // buffer. + std::thread watcher_thread_; + std::future<void> watcher_future_; + + // The callback function. Called whenever a modification is seen. The + // function passed in should expect a pair of strings in the form + // (path, data). Where path is the path of the file that saw a modification + // and data was the modification. + WatcherCallback cb_; + + // A callback function to use if we ever see the queue overflow. This is + // not required to start watching files. However, if no callback is + // registered and we see the queue overflow we will just log that + // modification events were dropped and do nothing. + std::function<void(void)> queue_overflow_cb_; + + // Variables shared between the watcher and consumer threads. + std::mutex watcher_mutex_; +}; + +} // namespace thermal +} // namespace pixel +} // namespace google +} // namespace hardware +} // namespace android + +#endif // __DEVICE_FILE_WATCHER_H__ diff --git a/thermal/include/pixelthermal/sensors.h b/thermal/include/pixelthermal/sensors.h new file mode 100644 index 00000000..82582104 --- /dev/null +++ b/thermal/include/pixelthermal/sensors.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __SENSORS_H__ +#define __SENSORS_H__ + +#include <string> +#include <unordered_map> + +namespace android { +namespace hardware { +namespace google { +namespace pixel { +namespace thermal { + +class Sensors { + public: + Sensors() = default; + ~Sensors() = default; + Sensors(const Sensors&) = delete; + void operator=(const Sensors&) = delete; + + std::string getSensorPath(const std::string& sensor_name); + // Returns true if add was successful, false otherwise. + bool addSensor(const std::string& sensor_name, const std::string& path); + // If sensor is not found in the sensor names to path map, this will set + // data and file path to empty and return false. If the sensor is found, + // this function will fill in data and file_path accordingly then return + // true. + bool readSensorFile( + const std::string& sensor_name, std::string* data, + std::string* file_path) const; + size_t getNumSensors() const { return sensor_names_to_path_map_.size(); } + + private: + std::unordered_map<std::string, std::string> sensor_names_to_path_map_; +}; + +} // namespace thermal +} // namespace pixel +} // namespace google +} // namespace hardware +} // namespace android + +#endif // __SENSORS_H__ + diff --git a/thermal/include/pixelthermal/thermal_structs.h b/thermal/include/pixelthermal/thermal_structs.h new file mode 100644 index 00000000..5644a698 --- /dev/null +++ b/thermal/include/pixelthermal/thermal_structs.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __THERMAL_STRUCTS_PARSER_H__ +#define __THERMAL_STRUCTS_PARSER_H__ + +#include <android/hardware/thermal/1.0/IThermal.h> + +#include <cmath> + +namespace android { +namespace hardware { +namespace google { +namespace pixel { +namespace thermal { + +using ::android::hardware::thermal::V1_0::TemperatureType; + +struct SensorInfo { + TemperatureType type; + bool is_override; + float throttling; + float shutdown; + float multiplier; +}; + +struct ThrottlingThresholds { + ThrottlingThresholds() : cpu(NAN), gpu(NAN), ss(NAN), battery(NAN) {} + float cpu; + float gpu; + float ss; + float battery; +}; + +} // namespace thermal +} // namespace pixel +} // namespace google +} // namespace hardware +} // namespace android + +#endif diff --git a/thermal/sensors.cpp b/thermal/sensors.cpp new file mode 100644 index 00000000..c9b39e83 --- /dev/null +++ b/thermal/sensors.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <algorithm> + +#include <android-base/file.h> +#include <android-base/strings.h> +#include "include/pixelthermal/sensors.h" + +namespace android { +namespace hardware { +namespace google { +namespace pixel { +namespace thermal { + +std::string Sensors::getSensorPath(const std::string& sensor_name) { + if (sensor_names_to_path_map_.find(sensor_name) != + sensor_names_to_path_map_.end()) { + return sensor_names_to_path_map_.at(sensor_name); + } + return ""; +} + +bool Sensors::addSensor( + const std::string& sensor_name, const std::string& path) { + return sensor_names_to_path_map_.emplace(sensor_name, path).second; +} + +bool Sensors::readSensorFile( + const std::string& sensor_name, std::string* data, + std::string* file_path) const { + std::string sensor_reading; + if (sensor_names_to_path_map_.find(sensor_name) == + sensor_names_to_path_map_.end()) { + *data = ""; + *file_path = ""; + return false; + } + + android::base::ReadFileToString( + sensor_names_to_path_map_.at(sensor_name), &sensor_reading); + // Strip the newline. + *data = ::android::base::Trim(sensor_reading); + *file_path = sensor_names_to_path_map_.at(sensor_name); + return true; +} + +} // namespace thermal +} // namespace pixel +} // namespace google +} // namespace hardware +} // namespace android |