+++ /dev/null
-cc_binary {
- name: "android.hardware.thermal@2.0-service.samsung",
- defaults: [
- "hidl_defaults",
- ],
- vendor: true,
- relative_install_path: "hw",
- vintf_fragments: ["android.hardware.thermal@2.0-service.samsung.xml"],
- init_rc: [
- "android.hardware.thermal@2.0-service.samsung.rc",
- ],
- srcs: [
- "service.cpp",
- "Thermal.cpp",
- "thermal-helper.cpp",
- "utils/config_parser.cpp",
- "utils/thermal_files.cpp",
- "utils/thermal_watcher.cpp",
- ],
- static_libs: [
- "libjsoncpp",
- ],
- shared_libs: [
- "libbase",
- "libcutils",
- "libhidlbase",
- "libutils",
- "android.hardware.thermal@1.0",
- "android.hardware.thermal@2.0",
- ],
- cflags: [
- "-Wall",
- "-Werror",
- "-Wextra",
- "-Wunused",
- ],
- tidy: true,
- tidy_checks_as_errors: [
- "android-*",
- "cert-*",
- "clang-analyzer-security*",
- ],
-}
-
-sh_binary {
- name: "thermal_logd.samsung",
- src: "init.thermal.logging.sh",
- vendor: true,
- init_rc: [
- "samsung-thermal-logd.rc",
- ],
-}
+++ /dev/null
-# Samsung HIDL thermal HAL
-
-The HAL uses the standard linux thermal interface and can be configured by
-adding thermal zones and cooling devices present on the device in a
-`thermal_info_config.json` file.
-
-To probe them, just connect the phone via ADB and check the nodes available
-under `/sys/class/thermal/`. The name of each thermal zone and cooling device
-can be found in the type node, e.g.
-
- /sys/class/thermal/thermal_zone0/type
- /sys/class/thermal/cooling_device0/type
-
-For each thermal device it is possible to configure a "Sensor" node in
-`thermal_info_config.json`, and setting up to 7 throttling levels, from NONE to
-SHUTDOWN. At each severity level, the hal send signals to throttle the device to the
-framework, according to : https://source.android.com/devices/architecture/hidl/thermal-mitigation
-In order to set temperature curve for the desired component you can
-took as a refererence the kernel trip points temperatures, for the specific devices,
-available in the thermal_zoneX sysfs.
-Each sensor can be classified as *CPU*, *GPU*, *USB_PORT* or *BATTERY* type.
-If you have a thermal monitor which does not belong to any of this categories you can
-classify it as *UNKNOWN*.
-You can specify hysteresis as well as if the interface should be monitored.
-If you monitor the interface, the HAL takes action when the specifc treshold is passed.
-You should not enable monitor if your kernel already implement thermal mitigatoin for
-the specified component.
-Since each device reports temperatures multiplied by different factor of 10,
-you should set the Multipler field such as
-`/sys/class/thermal/thermal_zoneX/temp` is reported in Celusis degrees (e.g.
-25100 reported by sysfs, multiplied by 0.001 is 25.1).
-
-The same can be said for cooling devices. For each cooling devices can be
-created a CoolingDevices node in `thermal_info_config.json`.
-Each cooling interface can be classified as *CPU*, *GPU* or *BATTERY* type.
-If you have a cooling device which does not belong to any of this categories you can
-classify it as *COMPONENT*.
-The `thermal_info_config.json` should be copied under /vendor/etc.
-
-For more details, refer on the sample config schema.
+++ /dev/null
-/*
- * 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 <cerrno>
-#include <mutex>
-#include <string>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <hidl/HidlTransportSupport.h>
-
-#include "Thermal.h"
-#include "thermal-helper.h"
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V2_0 {
-namespace implementation {
-
-namespace {
-
-using ::android::hardware::interfacesEqual;
-using ::android::hardware::thermal::V1_0::ThermalStatus;
-using ::android::hardware::thermal::V1_0::ThermalStatusCode;
-using ::android::hidl::base::V1_0::IBase;
-
-template <typename T, typename U>
-Return<void> setFailureAndCallback(T _hidl_cb, hidl_vec<U> data, std::string_view debug_msg) {
- ThermalStatus status;
- status.code = ThermalStatusCode::FAILURE;
- status.debugMessage = debug_msg.data();
- _hidl_cb(status, data);
- return Void();
-}
-
-template <typename T, typename U>
-Return<void> setInitFailureAndCallback(T _hidl_cb, hidl_vec<U> data) {
- return setFailureAndCallback(_hidl_cb, data, "Failure initializing thermal HAL");
-}
-
-} // namespace
-
-// On init we will spawn a thread which will continually watch for
-// throttling. When throttling is seen, if we have a callback registered
-// the thread will call notifyThrottling() else it will log the dropped
-// throttling event and do nothing. The thread is only killed when
-// Thermal() is killed.
-Thermal::Thermal()
- : thermal_helper_(
- std::bind(&Thermal::sendThermalChangedCallback, this, std::placeholders::_1)) {}
-
-// Methods from ::android::hardware::thermal::V1_0::IThermal.
-Return<void> Thermal::getTemperatures(getTemperatures_cb _hidl_cb) {
- ThermalStatus status;
- status.code = ThermalStatusCode::SUCCESS;
- hidl_vec<Temperature_1_0> temperatures;
-
- if (!thermal_helper_.isInitializedOk()) {
- LOG(ERROR) << "ThermalHAL not initialized properly.";
- return setInitFailureAndCallback(_hidl_cb, temperatures);
- }
-
- if (!thermal_helper_.fillTemperatures(&temperatures)) {
- return setFailureAndCallback(_hidl_cb, temperatures, "Failed to read thermal sensors.");
- }
-
- _hidl_cb(status, temperatures);
- return Void();
-}
-
-Return<void> Thermal::getCpuUsages(getCpuUsages_cb _hidl_cb) {
- ThermalStatus status;
- status.code = ThermalStatusCode::SUCCESS;
- hidl_vec<CpuUsage> cpu_usages;
-
- if (!thermal_helper_.isInitializedOk()) {
- return setInitFailureAndCallback(_hidl_cb, cpu_usages);
- }
-
- if (!thermal_helper_.fillCpuUsages(&cpu_usages)) {
- return setFailureAndCallback(_hidl_cb, cpu_usages, "Failed to get CPU usages.");
- }
-
- _hidl_cb(status, cpu_usages);
- return Void();
-}
-
-Return<void> Thermal::getCoolingDevices(getCoolingDevices_cb _hidl_cb) {
- ThermalStatus status;
- status.code = ThermalStatusCode::SUCCESS;
- hidl_vec<CoolingDevice_1_0> cooling_devices;
-
- if (!thermal_helper_.isInitializedOk()) {
- return setInitFailureAndCallback(_hidl_cb, cooling_devices);
- }
- _hidl_cb(status, cooling_devices);
- return Void();
-}
-
-Return<void> Thermal::getCurrentTemperatures(bool filterType, TemperatureType_2_0 type,
- getCurrentTemperatures_cb _hidl_cb) {
- ThermalStatus status;
- status.code = ThermalStatusCode::SUCCESS;
- hidl_vec<Temperature_2_0> temperatures;
-
- if (!thermal_helper_.isInitializedOk()) {
- LOG(ERROR) << "ThermalHAL not initialized properly.";
- return setInitFailureAndCallback(_hidl_cb, temperatures);
- }
-
- if (!thermal_helper_.fillCurrentTemperatures(filterType, type, &temperatures)) {
- return setFailureAndCallback(_hidl_cb, temperatures, "Failed to read thermal sensors.");
- }
-
- _hidl_cb(status, temperatures);
- return Void();
-}
-
-Return<void> Thermal::getTemperatureThresholds(bool filterType, TemperatureType_2_0 type,
- getTemperatureThresholds_cb _hidl_cb) {
- ThermalStatus status;
- status.code = ThermalStatusCode::SUCCESS;
- hidl_vec<TemperatureThreshold> temperatures;
-
- if (!thermal_helper_.isInitializedOk()) {
- LOG(ERROR) << "ThermalHAL not initialized properly.";
- return setInitFailureAndCallback(_hidl_cb, temperatures);
- }
-
- if (!thermal_helper_.fillTemperatureThresholds(filterType, type, &temperatures)) {
- return setFailureAndCallback(_hidl_cb, temperatures, "Failed to read thermal sensors.");
- }
-
- _hidl_cb(status, temperatures);
- return Void();
-}
-
-Return<void> Thermal::getCurrentCoolingDevices(bool filterType, CoolingType type,
- getCurrentCoolingDevices_cb _hidl_cb) {
- ThermalStatus status;
- status.code = ThermalStatusCode::SUCCESS;
- hidl_vec<CoolingDevice_2_0> cooling_devices;
-
- if (!thermal_helper_.isInitializedOk()) {
- LOG(ERROR) << "ThermalHAL not initialized properly.";
- return setInitFailureAndCallback(_hidl_cb, cooling_devices);
- }
-
- if (!thermal_helper_.fillCurrentCoolingDevices(filterType, type, &cooling_devices)) {
- return setFailureAndCallback(_hidl_cb, cooling_devices, "Failed to read thermal sensors.");
- }
-
- _hidl_cb(status, cooling_devices);
- return Void();
-}
-
-Return<void> Thermal::registerThermalChangedCallback(const sp<IThermalChangedCallback> &callback,
- bool filterType, TemperatureType_2_0 type,
- registerThermalChangedCallback_cb _hidl_cb) {
- ThermalStatus status;
- if (callback == nullptr) {
- status.code = ThermalStatusCode::FAILURE;
- status.debugMessage = "Invalid nullptr callback";
- LOG(ERROR) << status.debugMessage;
- _hidl_cb(status);
- return Void();
- } else {
- status.code = ThermalStatusCode::SUCCESS;
- }
- std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
- if (std::any_of(callbacks_.begin(), callbacks_.end(), [&](const CallbackSetting &c) {
- return interfacesEqual(c.callback, callback);
- })) {
- status.code = ThermalStatusCode::FAILURE;
- status.debugMessage = "Same callback registered already";
- LOG(ERROR) << status.debugMessage;
- } else {
- callbacks_.emplace_back(callback, filterType, type);
- LOG(INFO) << "a callback has been registered to ThermalHAL, isFilter: " << filterType
- << " Type: " << android::hardware::thermal::V2_0::toString(type);
- }
- _hidl_cb(status);
- return Void();
-}
-
-Return<void> Thermal::unregisterThermalChangedCallback(
- const sp<IThermalChangedCallback> &callback, unregisterThermalChangedCallback_cb _hidl_cb) {
- ThermalStatus status;
- if (callback == nullptr) {
- status.code = ThermalStatusCode::FAILURE;
- status.debugMessage = "Invalid nullptr callback";
- LOG(ERROR) << status.debugMessage;
- _hidl_cb(status);
- return Void();
- } else {
- status.code = ThermalStatusCode::SUCCESS;
- }
- bool removed = false;
- std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
- callbacks_.erase(
- std::remove_if(callbacks_.begin(), callbacks_.end(),
- [&](const CallbackSetting &c) {
- if (interfacesEqual(c.callback, callback)) {
- LOG(INFO)
- << "a callback has been unregistered to ThermalHAL, isFilter: "
- << c.is_filter_type << " Type: "
- << android::hardware::thermal::V2_0::toString(c.type);
- removed = true;
- return true;
- }
- return false;
- }),
- callbacks_.end());
- if (!removed) {
- status.code = ThermalStatusCode::FAILURE;
- status.debugMessage = "The callback was not registered before";
- LOG(ERROR) << status.debugMessage;
- }
- _hidl_cb(status);
- return Void();
-}
-
-void Thermal::sendThermalChangedCallback(const std::vector<Temperature_2_0> &temps) {
- std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
- for (auto &t : temps) {
- LOG(INFO) << "Sending notification: "
- << " Type: " << android::hardware::thermal::V2_0::toString(t.type)
- << " Name: " << t.name << " CurrentValue: " << t.value << " ThrottlingStatus: "
- << android::hardware::thermal::V2_0::toString(t.throttlingStatus);
- callbacks_.erase(
- std::remove_if(callbacks_.begin(), callbacks_.end(),
- [&](const CallbackSetting &c) {
- if (!c.is_filter_type || t.type == c.type) {
- Return<void> ret = c.callback->notifyThrottling(t);
- return !ret.isOk();
- }
- LOG(ERROR)
- << "a Thermal callback is dead, removed from callback list.";
- return false;
- }),
- callbacks_.end());
- }
-}
-
-Return<void> Thermal::debug(const hidl_handle &handle, const hidl_vec<hidl_string> &) {
- if (handle != nullptr && handle->numFds >= 1) {
- int fd = handle->data[0];
- std::ostringstream dump_buf;
-
- if (!thermal_helper_.isInitializedOk()) {
- dump_buf << "ThermalHAL not initialized properly." << std::endl;
- } else {
- {
- hidl_vec<Temperature_1_0> temperatures;
- dump_buf << "getTemperatures:" << std::endl;
- if (!thermal_helper_.fillTemperatures(&temperatures)) {
- dump_buf << "Failed to read thermal sensors." << std::endl;
- }
-
- for (const auto &t : temperatures) {
- dump_buf << " Type: " << android::hardware::thermal::V1_0::toString(t.type)
- << " Name: " << t.name << " CurrentValue: " << t.currentValue
- << " ThrottlingThreshold: " << t.throttlingThreshold
- << " ShutdownThreshold: " << t.shutdownThreshold
- << " VrThrottlingThreshold: " << t.vrThrottlingThreshold << std::endl;
- }
- }
- {
- hidl_vec<CpuUsage> cpu_usages;
- dump_buf << "getCpuUsages:" << std::endl;
- if (!thermal_helper_.fillCpuUsages(&cpu_usages)) {
- dump_buf << "Failed to get CPU usages." << std::endl;
- }
-
- for (const auto &usage : cpu_usages) {
- dump_buf << " Name: " << usage.name << " Active: " << usage.active
- << " Total: " << usage.total << " IsOnline: " << usage.isOnline
- << std::endl;
- }
- }
- {
- dump_buf << "getCurrentTemperatures:" << std::endl;
- hidl_vec<Temperature_2_0> temperatures;
- if (!thermal_helper_.fillCurrentTemperatures(false, TemperatureType_2_0::SKIN,
- &temperatures)) {
- dump_buf << "Failed to getCurrentTemperatures." << std::endl;
- }
-
- for (const auto &t : temperatures) {
- dump_buf << " Type: " << android::hardware::thermal::V2_0::toString(t.type)
- << " Name: " << t.name << " CurrentValue: " << t.value
- << " ThrottlingStatus: "
- << android::hardware::thermal::V2_0::toString(t.throttlingStatus)
- << std::endl;
- }
- }
- {
- dump_buf << "getTemperatureThresholds:" << std::endl;
- hidl_vec<TemperatureThreshold> temperatures;
- if (!thermal_helper_.fillTemperatureThresholds(false, TemperatureType_2_0::SKIN,
- &temperatures)) {
- dump_buf << "Failed to getTemperatureThresholds." << std::endl;
- }
-
- for (const auto &t : temperatures) {
- dump_buf << " Type: " << android::hardware::thermal::V2_0::toString(t.type)
- << " Name: " << t.name;
- dump_buf << " hotThrottlingThreshold: [";
- for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
- dump_buf << t.hotThrottlingThresholds[i] << " ";
- }
- dump_buf << "] coldThrottlingThreshold: [";
- for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
- dump_buf << t.coldThrottlingThresholds[i] << " ";
- }
- dump_buf << "] vrThrottlingThreshold: " << t.vrThrottlingThreshold;
- dump_buf << std::endl;
- }
- }
- {
- dump_buf << "getCurrentCoolingDevices:" << std::endl;
- hidl_vec<CoolingDevice_2_0> cooling_devices;
- if (!thermal_helper_.fillCurrentCoolingDevices(false, CoolingType::CPU,
- &cooling_devices)) {
- dump_buf << "Failed to getCurrentCoolingDevices." << std::endl;
- }
-
- for (const auto &c : cooling_devices) {
- dump_buf << " Type: " << android::hardware::thermal::V2_0::toString(c.type)
- << " Name: " << c.name << " CurrentValue: " << c.value << std::endl;
- }
- }
- {
- dump_buf << "Callbacks: Total " << callbacks_.size() << std::endl;
- for (const auto &c : callbacks_) {
- dump_buf << " IsFilter: " << c.is_filter_type
- << " Type: " << android::hardware::thermal::V2_0::toString(c.type)
- << std::endl;
- }
- }
- {
- dump_buf << "getHysteresis:" << std::endl;
- const auto &map = thermal_helper_.GetSensorInfoMap();
- for (const auto &name_info_pair : map) {
- dump_buf << " Name: " << name_info_pair.first;
- dump_buf << " hotHysteresis: [";
- for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
- dump_buf << name_info_pair.second.hot_hysteresis[i] << " ";
- }
- dump_buf << "] coldHysteresis: [";
- for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
- dump_buf << name_info_pair.second.cold_hysteresis[i] << " ";
- }
- dump_buf << "]" << std::endl;
- }
- }
- {
- dump_buf << "Monitor:" << std::endl;
- const auto &map = thermal_helper_.GetSensorInfoMap();
- for (const auto &name_info_pair : map) {
- dump_buf << " Name: " << name_info_pair.first;
- dump_buf << " Monitor: " << std::boolalpha << name_info_pair.second.is_monitor
- << std::noboolalpha << std::endl;
- }
- }
- }
- std::string buf = dump_buf.str();
- if (!android::base::WriteStringToFd(buf, fd)) {
- PLOG(ERROR) << "Failed to dump state to fd";
- }
- fsync(fd);
- }
- return Void();
-}
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace thermal
-} // namespace hardware
-} // namespace android
+++ /dev/null
-/*
- * Copyright (C) 2018 The Android Open Source Project
- * 2022 The LineageOS 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.
- */
-
-#pragma once
-
-#include <mutex>
-#include <thread>
-
-#include <android/hardware/thermal/2.0/IThermal.h>
-#include <android/hardware/thermal/2.0/IThermalChangedCallback.h>
-#include <hidl/Status.h>
-
-#include "thermal-helper.h"
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::sp;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::Return;
-using ::android::hardware::thermal::V2_0::IThermal;
-using ::android::hardware::thermal::V2_0::IThermalChangedCallback;
-
-struct CallbackSetting {
- CallbackSetting(sp<IThermalChangedCallback> callback, bool is_filter_type,
- TemperatureType_2_0 type)
- : callback(callback), is_filter_type(is_filter_type), type(type) {}
- sp<IThermalChangedCallback> callback;
- bool is_filter_type;
- TemperatureType_2_0 type;
-};
-
-class Thermal : public IThermal {
- public:
- Thermal();
- ~Thermal() = default;
-
- // Disallow copy and assign.
- Thermal(const Thermal &) = delete;
- void operator=(const Thermal &) = delete;
-
- // Methods from ::android::hardware::thermal::V1_0::IThermal.
- Return<void> getTemperatures(getTemperatures_cb _hidl_cb) override;
- Return<void> getCpuUsages(getCpuUsages_cb _hidl_cb) override;
- Return<void> getCoolingDevices(getCoolingDevices_cb _hidl_cb) override;
-
- // Methods from ::android::hardware::thermal::V2_0::IThermal follow.
- Return<void> getCurrentTemperatures(bool filterType, TemperatureType_2_0 type,
- getCurrentTemperatures_cb _hidl_cb) override;
- Return<void> getTemperatureThresholds(bool filterType, TemperatureType_2_0 type,
- getTemperatureThresholds_cb _hidl_cb) override;
- Return<void> registerThermalChangedCallback(const sp<IThermalChangedCallback> &callback,
- bool filterType, TemperatureType_2_0 type,
- registerThermalChangedCallback_cb _hidl_cb) override;
- Return<void> unregisterThermalChangedCallback(
- const sp<IThermalChangedCallback> &callback,
- unregisterThermalChangedCallback_cb _hidl_cb) override;
- Return<void> getCurrentCoolingDevices(bool filterType, CoolingType type,
- getCurrentCoolingDevices_cb _hidl_cb) override;
-
- // Methods from ::android::hidl::base::V1_0::IBase follow.
- Return<void> debug(const hidl_handle &fd, const hidl_vec<hidl_string> &args) override;
-
- // Helper function for calling callbacks
- void sendThermalChangedCallback(const std::vector<Temperature_2_0> &temps);
-
- private:
- ThermalHelper thermal_helper_;
- std::mutex thermal_callback_mutex_;
- std::vector<CallbackSetting> callbacks_;
-};
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace thermal
-} // namespace hardware
-} // namespace android
+++ /dev/null
-service vendor.thermal-hal-2-0 /vendor/bin/hw/android.hardware.thermal@2.0-service.samsung
- interface android.hardware.thermal@1.0::IThermal default
- interface android.hardware.thermal@2.0::IThermal default
- class hal
- user system
- group system
+++ /dev/null
-<manifest version="1.0" type="device">
- <hal format="hidl">
- <name>android.hardware.thermal</name>
- <transport>hwbinder</transport>
- <version>1.0</version>
- <version>2.0</version>
- <interface>
- <name>IThermal</name>
- <instance>default</instance>
- </interface>
- </hal>
-</manifest>
+++ /dev/null
-#!/vendor/bin/sh
-
-if [ $# -eq 1 ]; then
- interval=$1
-else
- exit 1
-fi
-
-while true
-do
- logline="tz:"
- for f in /sys/class/thermal/thermal*
- do
- temp=`cat $f/temp`
- logline+="|$temp"
- done
- logline+=" cdev:"
- for f in /sys/class/thermal/cooling_device*
- do
- cur_state=`cat $f/cur_state`
- logline+="|$cur_state"
- done
- log -p w -t THERMAL_LOG $logline
- sleep $interval
-done
+++ /dev/null
-on property:persist.vendor.log.thermal=1
- start vendor.thermal.logd
-
-on property:persist.vendor.log.thermal=0
- stop vendor.thermal.logd
-
-on property:persist.vendor.log.thermal=1 && property:persist.vendor.log.thermal.interval=*
- restart vendor.thermal.logd
-
-service vendor.thermal.logd /vendor/bin/thermal_logd.samsung ${persist.vendor.log.thermal.interval:-5}
- class main
- user root
- group root system
- disabled
+++ /dev/null
-/*
- * 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 <android-base/logging.h>
-#include <hidl/HidlTransportSupport.h>
-#include "Thermal.h"
-
-using ::android::OK;
-using ::android::status_t;
-
-// libhwbinder:
-using ::android::hardware::configureRpcThreadpool;
-using ::android::hardware::joinRpcThreadpool;
-
-// Generated HIDL files:
-using ::android::hardware::thermal::V2_0::IThermal;
-using ::android::hardware::thermal::V2_0::implementation::Thermal;
-
-static int shutdown() {
- LOG(ERROR) << "Samsung Thermal HAL Service is shutting down.";
- return 1;
-}
-
-int main(int /* argc */, char ** /* argv */) {
- status_t status;
- android::sp<IThermal> service = nullptr;
-
- LOG(INFO) << "Samsung Thermal HAL Service 2.0 starting...";
-
- service = new Thermal();
- if (service == nullptr) {
- LOG(ERROR) << "Error creating an instance of Thermal HAL. Exiting...";
- return shutdown();
- }
-
- configureRpcThreadpool(1, true /* callerWillJoin */);
-
- status = service->registerAsService();
- if (status != OK) {
- LOG(ERROR) << "Could not register service for ThermalHAL (" << status << ")";
- return shutdown();
- }
-
- LOG(INFO) << "Samsung Thermal HAL Service 2.0 started successfully.";
- joinRpcThreadpool();
- // We should not get past the joinRpcThreadpool().
- return shutdown();
-}
+++ /dev/null
-/*
- * 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 <iterator>
-#include <set>
-#include <sstream>
-#include <thread>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <hidl/HidlTransportSupport.h>
-
-#include "thermal-helper.h"
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V2_0 {
-namespace implementation {
-
-constexpr std::string_view kCpuOnlineRoot("/sys/devices/system/cpu");
-constexpr std::string_view kThermalSensorsRoot("/sys/devices/virtual/thermal");
-constexpr std::string_view kCpuUsageFile("/proc/stat");
-constexpr std::string_view kCpuOnlineFileSuffix("online");
-constexpr std::string_view kCpuPresentFile("/sys/devices/system/cpu/present");
-constexpr std::string_view kSensorPrefix("thermal_zone");
-constexpr std::string_view kCoolingDevicePrefix("cooling_device");
-constexpr std::string_view kThermalNameFile("type");
-constexpr std::string_view kSensorPolicyFile("policy");
-constexpr std::string_view kSensorTempSuffix("temp");
-constexpr std::string_view kSensorTripPointTempZeroFile("trip_point_0_temp");
-constexpr std::string_view kSensorTripPointHystZeroFile("trip_point_0_hyst");
-constexpr std::string_view kUserSpaceSuffix("user_space");
-constexpr std::string_view kCoolingDeviceCurStateSuffix("cur_state");
-constexpr std::string_view kConfigProperty("vendor.thermal.config");
-constexpr std::string_view kConfigDefaultFileName("thermal_info_config.json");
-
-namespace {
-using android::base::StringPrintf;
-
-/*
- * The phone don't offline CPU, so std::thread::hardware_concurrency(); should
- * work.
- * However /sys/devices/system/cpu/present is preferred.
- * The file is expected to contain single text line with two numbers %d-%d,
- * which is a range of available cpu numbers, e.g. 0-7 would mean there
- * are 8 cores number from 0 to 7.
- * For Android systems this approach is safer than using cpufeatures, see bug
- * b/36941727.
- */
-std::size_t getNumberOfCores() {
- std::string file;
- if (!android::base::ReadFileToString(kCpuPresentFile.data(), &file)) {
- LOG(ERROR) << "Error reading Cpu present file: " << kCpuPresentFile;
- return 0;
- }
- std::vector<std::string> pieces = android::base::Split(file, "-");
- if (pieces.size() != 2) {
- LOG(ERROR) << "Error parsing Cpu present file content: " << file;
- return 0;
- }
- auto min_core = std::stoul(pieces[0]);
- auto max_core = std::stoul(pieces[1]);
- if (max_core < min_core) {
- LOG(ERROR) << "Error parsing Cpu present min and max: " << min_core << " - " << max_core;
- return 0;
- }
- return static_cast<std::size_t>(max_core - min_core + 1);
-}
-const std::size_t kMaxCpus = getNumberOfCores();
-
-void parseCpuUsagesFileAndAssignUsages(hidl_vec<CpuUsage> *cpu_usages) {
- uint64_t cpu_num, user, nice, system, idle;
- std::string cpu_name;
- std::string data;
- if (!android::base::ReadFileToString(kCpuUsageFile.data(), &data)) {
- LOG(ERROR) << "Error reading Cpu usage file: " << kCpuUsageFile;
- return;
- }
-
- std::istringstream stat_data(data);
- std::string line;
- while (std::getline(stat_data, line)) {
- if (line.find("cpu") == 0 && isdigit(line[3])) {
- // Split the string using spaces.
- std::vector<std::string> words = android::base::Split(line, " ");
- cpu_name = words[0];
- cpu_num = std::stoi(cpu_name.substr(3));
-
- if (cpu_num < kMaxCpus) {
- user = std::stoi(words[1]);
- nice = std::stoi(words[2]);
- system = std::stoi(words[3]);
- idle = std::stoi(words[4]);
-
- // Check if the CPU is online by reading the online file.
- std::string cpu_online_path =
- StringPrintf("%s/%s/%s", kCpuOnlineRoot.data(), cpu_name.c_str(),
- kCpuOnlineFileSuffix.data());
- std::string is_online;
- if (!android::base::ReadFileToString(cpu_online_path, &is_online)) {
- LOG(ERROR) << "Could not open Cpu online file: " << cpu_online_path;
- return;
- }
- is_online = android::base::Trim(is_online);
-
- (*cpu_usages)[cpu_num].name = cpu_name;
- (*cpu_usages)[cpu_num].active = user + nice + system;
- (*cpu_usages)[cpu_num].total = user + nice + system + idle;
- (*cpu_usages)[cpu_num].isOnline = (is_online == "1") ? true : false;
- } else {
- LOG(ERROR) << "Unexpected cpu number: " << words[0];
- return;
- }
- }
- }
-}
-
-std::map<std::string, std::string> parseThermalPathMap(std::string_view prefix) {
- std::map<std::string, std::string> path_map;
- std::unique_ptr<DIR, int (*)(DIR *)> dir(opendir(kThermalSensorsRoot.data()), closedir);
- if (!dir) {
- return path_map;
- }
-
- // std::filesystem is not available for vendor yet
- // see discussion: aosp/894015
- while (struct dirent *dp = readdir(dir.get())) {
- if (dp->d_type != DT_DIR) {
- continue;
- }
-
- if (!android::base::StartsWith(dp->d_name, prefix.data())) {
- continue;
- }
-
- std::string path = android::base::StringPrintf("%s/%s/%s", kThermalSensorsRoot.data(),
- dp->d_name, kThermalNameFile.data());
- std::string name;
- if (!android::base::ReadFileToString(path, &name)) {
- PLOG(ERROR) << "Failed to read from " << path;
- continue;
- }
-
- path_map.emplace(
- android::base::Trim(name),
- android::base::StringPrintf("%s/%s", kThermalSensorsRoot.data(), dp->d_name));
- }
-
- return path_map;
-}
-
-} // namespace
-
-/*
- * Populate the sensor_name_to_file_map_ map by walking through the file tree,
- * reading the type file and assigning the temp file path to the map. If we do
- * not succeed, abort.
- */
-ThermalHelper::ThermalHelper(const NotificationCallback &cb)
- : thermal_watcher_(new ThermalWatcher(
- std::bind(&ThermalHelper::thermalWatcherCallbackFunc, this, std::placeholders::_1))),
- cb_(cb),
- cooling_device_info_map_(ParseCoolingDevice(
- "/vendor/etc/" +
- android::base::GetProperty(kConfigProperty.data(), kConfigDefaultFileName.data()))),
- sensor_info_map_(ParseSensorInfo(
- "/vendor/etc/" +
- android::base::GetProperty(kConfigProperty.data(), kConfigDefaultFileName.data()))) {
- for (auto const &name_status_pair : sensor_info_map_) {
- sensor_status_map_[name_status_pair.first] = {
- .severity = ThrottlingSeverity::NONE,
- .prev_hot_severity = ThrottlingSeverity::NONE,
- .prev_cold_severity = ThrottlingSeverity::NONE,
- };
- }
-
- auto tz_map = parseThermalPathMap(kSensorPrefix.data());
- auto cdev_map = parseThermalPathMap(kCoolingDevicePrefix.data());
-
- is_initialized_ = initializeSensorMap(tz_map) && initializeCoolingDevices(cdev_map);
- if (!is_initialized_) {
- LOG(FATAL) << "ThermalHAL could not be initialized properly.";
- }
- std::set<std::string> monitored_sensors;
- std::transform(sensor_info_map_.cbegin(), sensor_info_map_.cend(),
- std::inserter(monitored_sensors, monitored_sensors.begin()),
- [](std::pair<std::string, SensorInfo> const &sensor) {
- if (sensor.second.is_monitor)
- return sensor.first;
- else
- return std::string();
- });
-
- thermal_watcher_->registerFilesToWatch(monitored_sensors, initializeTrip(tz_map));
-
- // Need start watching after status map initialized
- is_initialized_ = thermal_watcher_->startWatchingDeviceFiles();
- if (!is_initialized_) {
- LOG(FATAL) << "ThermalHAL could not start watching thread properly.";
- }
-}
-
-bool ThermalHelper::readCoolingDevice(std::string_view cooling_device,
- CoolingDevice_2_0 *out) const {
- // Read the file. If the file can't be read temp will be empty string.
- std::string data;
-
- if (!cooling_devices_.readThermalFile(cooling_device, &data)) {
- LOG(ERROR) << "readCoolingDevice: failed to read cooling_device: " << cooling_device;
- return false;
- }
-
- const CoolingType &type = cooling_device_info_map_.at(cooling_device.data());
-
- out->type = type;
- out->name = cooling_device.data();
- out->value = std::stoi(data);
-
- return true;
-}
-
-bool ThermalHelper::readTemperature(std::string_view sensor_name, Temperature_1_0 *out) const {
- // Read the file. If the file can't be read temp will be empty string.
- std::string temp;
-
- if (!thermal_sensors_.readThermalFile(sensor_name, &temp)) {
- LOG(ERROR) << "readTemperature: sensor not found: " << sensor_name;
- return false;
- }
-
- if (temp.empty()) {
- LOG(ERROR) << "readTemperature: failed to read sensor: " << sensor_name;
- return false;
- }
-
- const SensorInfo &sensor_info = sensor_info_map_.at(sensor_name.data());
- TemperatureType_1_0 type =
- (static_cast<int>(sensor_info.type) > static_cast<int>(TemperatureType_1_0::SKIN))
- ? TemperatureType_1_0::UNKNOWN
- : static_cast<TemperatureType_1_0>(sensor_info.type);
- out->type = type;
- out->name = sensor_name.data();
- out->currentValue = std::stof(temp) * sensor_info.multiplier;
- out->throttlingThreshold =
- sensor_info.hot_thresholds[static_cast<size_t>(ThrottlingSeverity::SEVERE)];
- out->shutdownThreshold =
- sensor_info.hot_thresholds[static_cast<size_t>(ThrottlingSeverity::SHUTDOWN)];
- out->vrThrottlingThreshold = sensor_info.vr_threshold;
-
- return true;
-}
-
-bool ThermalHelper::readTemperature(
- std::string_view sensor_name, Temperature_2_0 *out,
- std::pair<ThrottlingSeverity, ThrottlingSeverity> *throtting_status) const {
- // Read the file. If the file can't be read temp will be empty string.
- std::string temp;
-
- if (!thermal_sensors_.readThermalFile(sensor_name, &temp)) {
- LOG(ERROR) << "readTemperature: sensor not found: " << sensor_name;
- return false;
- }
-
- if (temp.empty()) {
- LOG(ERROR) << "readTemperature: failed to read sensor: " << sensor_name;
- return false;
- }
-
- const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
- out->type = sensor_info.type;
- out->name = sensor_name.data();
- out->value = std::stof(temp) * sensor_info.multiplier;
-
- std::pair<ThrottlingSeverity, ThrottlingSeverity> status =
- std::make_pair(ThrottlingSeverity::NONE, ThrottlingSeverity::NONE);
- // Only update status if the thermal sensor is being monitored
- if (sensor_info.is_monitor) {
- ThrottlingSeverity prev_hot_severity, prev_cold_severity;
- {
- // reader lock, readTemperature will be called in Binder call and the watcher thread.
- std::shared_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
- prev_hot_severity = sensor_status_map_.at(sensor_name.data()).prev_hot_severity;
- prev_cold_severity = sensor_status_map_.at(sensor_name.data()).prev_cold_severity;
- }
- status = getSeverityFromThresholds(sensor_info.hot_thresholds, sensor_info.cold_thresholds,
- sensor_info.hot_hysteresis, sensor_info.cold_hysteresis,
- prev_hot_severity, prev_cold_severity, out->value);
- }
- if (throtting_status) {
- *throtting_status = status;
- }
-
- out->throttlingStatus = static_cast<size_t>(status.first) > static_cast<size_t>(status.second)
- ? status.first
- : status.second;
-
- return true;
-}
-
-bool ThermalHelper::readTemperatureThreshold(std::string_view sensor_name,
- TemperatureThreshold *out) const {
- // Read the file. If the file can't be read temp will be empty string.
- std::string temp;
- std::string path;
-
- if (!sensor_info_map_.count(sensor_name.data())) {
- LOG(ERROR) << __func__ << ": sensor not found: " << sensor_name;
- return false;
- }
-
- const auto &sensor_info = sensor_info_map_.at(sensor_name.data());
-
- out->type = sensor_info.type;
- out->name = sensor_name.data();
- out->hotThrottlingThresholds = sensor_info.hot_thresholds;
- out->coldThrottlingThresholds = sensor_info.cold_thresholds;
- out->vrThrottlingThreshold = sensor_info.vr_threshold;
- return true;
-}
-
-std::pair<ThrottlingSeverity, ThrottlingSeverity> ThermalHelper::getSeverityFromThresholds(
- const ThrottlingArray &hot_thresholds, const ThrottlingArray &cold_thresholds,
- const ThrottlingArray &hot_hysteresis, const ThrottlingArray &cold_hysteresis,
- ThrottlingSeverity prev_hot_severity, ThrottlingSeverity prev_cold_severity,
- float value) const {
- ThrottlingSeverity ret_hot = ThrottlingSeverity::NONE;
- ThrottlingSeverity ret_hot_hysteresis = ThrottlingSeverity::NONE;
- ThrottlingSeverity ret_cold = ThrottlingSeverity::NONE;
- ThrottlingSeverity ret_cold_hysteresis = ThrottlingSeverity::NONE;
-
- // Here we want to control the iteration from high to low, and hidl_enum_range doesn't support
- // a reverse iterator yet.
- for (size_t i = static_cast<size_t>(ThrottlingSeverity::SHUTDOWN);
- i > static_cast<size_t>(ThrottlingSeverity::NONE); --i) {
- if (!std::isnan(hot_thresholds[i]) && hot_thresholds[i] <= value &&
- ret_hot == ThrottlingSeverity::NONE) {
- ret_hot = static_cast<ThrottlingSeverity>(i);
- }
- if (!std::isnan(hot_thresholds[i]) && (hot_thresholds[i] - hot_hysteresis[i]) < value &&
- ret_hot_hysteresis == ThrottlingSeverity::NONE) {
- ret_hot_hysteresis = static_cast<ThrottlingSeverity>(i);
- }
- if (!std::isnan(cold_thresholds[i]) && cold_thresholds[i] >= value &&
- ret_cold == ThrottlingSeverity::NONE) {
- ret_cold = static_cast<ThrottlingSeverity>(i);
- }
- if (!std::isnan(cold_thresholds[i]) && (cold_thresholds[i] + cold_hysteresis[i]) > value &&
- ret_cold_hysteresis == ThrottlingSeverity::NONE) {
- ret_cold_hysteresis = static_cast<ThrottlingSeverity>(i);
- }
- }
- if (static_cast<size_t>(ret_hot) < static_cast<size_t>(prev_hot_severity)) {
- ret_hot = ret_hot_hysteresis;
- }
- if (static_cast<size_t>(ret_cold) < static_cast<size_t>(prev_cold_severity)) {
- ret_cold = ret_cold_hysteresis;
- }
-
- return std::make_pair(ret_hot, ret_cold);
-}
-
-bool ThermalHelper::initializeSensorMap(const std::map<std::string, std::string> &path_map) {
- for (const auto &sensor_info_pair : sensor_info_map_) {
- std::string_view sensor_name = sensor_info_pair.first;
- if (!path_map.count(sensor_name.data())) {
- LOG(ERROR) << "Could not find " << sensor_name << " in sysfs";
- continue;
- }
- std::string path = android::base::StringPrintf(
- "%s/%s", path_map.at(sensor_name.data()).c_str(), kSensorTempSuffix.data());
- if (!thermal_sensors_.addThermalFile(sensor_name, path)) {
- LOG(ERROR) << "Could not add " << sensor_name << "to sensors map";
- }
- }
- if (sensor_info_map_.size() == thermal_sensors_.getNumThermalFiles()) {
- return true;
- }
- return false;
-}
-
-bool ThermalHelper::initializeCoolingDevices(const std::map<std::string, std::string> &path_map) {
- for (const auto &cooling_device_info_pair : cooling_device_info_map_) {
- std::string_view cooling_device_name = cooling_device_info_pair.first;
- if (!path_map.count(cooling_device_name.data())) {
- LOG(ERROR) << "Could not find " << cooling_device_name << " in sysfs";
- continue;
- }
- std::string path = android::base::StringPrintf(
- "%s/%s", path_map.at(cooling_device_name.data()).c_str(),
- kCoolingDeviceCurStateSuffix.data());
- if (!cooling_devices_.addThermalFile(cooling_device_name, path)) {
- LOG(ERROR) << "Could not add " << cooling_device_name << "to cooling device map";
- continue;
- }
- }
-
- if (cooling_device_info_map_.size() == cooling_devices_.getNumThermalFiles()) {
- return true;
- }
- return false;
-}
-
-bool ThermalHelper::initializeTrip(const std::map<std::string, std::string> &path_map) {
- for (const auto &sensor_info : sensor_info_map_) {
- if (sensor_info.second.is_monitor) {
- std::string_view sensor_name = sensor_info.first;
- std::string_view tz_path = path_map.at(sensor_name.data());
- std::string tz_policy;
- std::string path = android::base::StringPrintf("%s/%s", (tz_path.data()),
- kSensorPolicyFile.data());
- if (!android::base::ReadFileToString(path, &tz_policy)) {
- LOG(ERROR) << sensor_name << " could not open tz policy file:" << path;
- return false;
- }
- // Check if thermal zone support uevent notify
- tz_policy = android::base::Trim(tz_policy);
- if (tz_policy != kUserSpaceSuffix) {
- LOG(ERROR) << sensor_name << " does not support uevent notify";
- return false;
- }
-
- // Update thermal zone trip point
- for (size_t i = 0; i < kThrottlingSeverityCount; ++i) {
- if (!std::isnan(sensor_info.second.hot_thresholds[i]) &&
- !std::isnan(sensor_info.second.hot_hysteresis[i])) {
- // Update trip_point_0_temp threshold
- std::string threshold = std::to_string(static_cast<int>(
- sensor_info.second.hot_thresholds[i] / sensor_info.second.multiplier));
- path = android::base::StringPrintf("%s/%s", (tz_path.data()),
- kSensorTripPointTempZeroFile.data());
- if (!android::base::WriteStringToFile(threshold, path)) {
- LOG(ERROR) << "fail to update " << sensor_name
- << " trip point: " << threshold << path;
- return false;
- }
- // Update trip_point_0_hyst threshold
- threshold = std::to_string(static_cast<int>(
- sensor_info.second.hot_hysteresis[i] / sensor_info.second.multiplier));
- path = android::base::StringPrintf("%s/%s", (tz_path.data()),
- kSensorTripPointHystZeroFile.data());
- if (!android::base::WriteStringToFile(threshold, path)) {
- LOG(ERROR) << "fail to update " << sensor_name << "trip hyst" << threshold
- << path;
- return false;
- }
- break;
- } else if (i == kThrottlingSeverityCount - 1) {
- LOG(ERROR) << sensor_name << ":all thresholds are NAN";
- return false;
- }
- }
- }
- }
- return true;
-}
-bool ThermalHelper::fillTemperatures(hidl_vec<Temperature_1_0> *temperatures) const {
- temperatures->resize(sensor_info_map_.size());
- int current_index = 0;
- for (const auto &name_info_pair : sensor_info_map_) {
- Temperature_1_0 temp;
-
- if (readTemperature(name_info_pair.first, &temp)) {
- (*temperatures)[current_index] = temp;
- } else {
- LOG(ERROR) << __func__
- << ": error reading temperature for sensor: " << name_info_pair.first;
- return false;
- }
- ++current_index;
- }
- return current_index > 0;
-}
-
-bool ThermalHelper::fillCurrentTemperatures(bool filterType, TemperatureType_2_0 type,
- hidl_vec<Temperature_2_0> *temperatures) const {
- std::vector<Temperature_2_0> ret;
- for (const auto &name_info_pair : sensor_info_map_) {
- Temperature_2_0 temp;
- if (filterType && name_info_pair.second.type != type) {
- continue;
- }
- if (readTemperature(name_info_pair.first, &temp)) {
- ret.emplace_back(std::move(temp));
- } else {
- LOG(ERROR) << __func__
- << ": error reading temperature for sensor: " << name_info_pair.first;
- return false;
- }
- }
- *temperatures = ret;
- return ret.size() > 0;
-}
-
-bool ThermalHelper::fillTemperatureThresholds(bool filterType, TemperatureType_2_0 type,
- hidl_vec<TemperatureThreshold> *thresholds) const {
- std::vector<TemperatureThreshold> ret;
- for (const auto &name_info_pair : sensor_info_map_) {
- TemperatureThreshold temp;
- if (filterType && name_info_pair.second.type != type) {
- continue;
- }
- if (readTemperatureThreshold(name_info_pair.first, &temp)) {
- ret.emplace_back(std::move(temp));
- } else {
- LOG(ERROR) << __func__ << ": error reading temperature threshold for sensor: "
- << name_info_pair.first;
- return false;
- }
- }
- *thresholds = ret;
- return ret.size() > 0;
-}
-
-bool ThermalHelper::fillCurrentCoolingDevices(bool filterType, CoolingType type,
- hidl_vec<CoolingDevice_2_0> *cooling_devices) const {
- std::vector<CoolingDevice_2_0> ret;
- for (const auto &name_info_pair : cooling_device_info_map_) {
- CoolingDevice_2_0 value;
- if (filterType && name_info_pair.second != type) {
- continue;
- }
- if (readCoolingDevice(name_info_pair.first, &value)) {
- ret.emplace_back(std::move(value));
- } else {
- LOG(ERROR) << __func__ << ": error reading cooling device: " << name_info_pair.first;
- return false;
- }
- }
- *cooling_devices = ret;
- return ret.size() > 0;
-}
-
-bool ThermalHelper::fillCpuUsages(hidl_vec<CpuUsage> *cpu_usages) const {
- cpu_usages->resize(kMaxCpus);
- parseCpuUsagesFileAndAssignUsages(cpu_usages);
- return true;
-}
-
-// This is called in the different thread context and will update sensor_status
-// uevent_sensors is the set of sensors which trigger uevent from thermal core driver.
-bool ThermalHelper::thermalWatcherCallbackFunc(const std::set<std::string> &uevent_sensors) {
- std::vector<Temperature_2_0> temps;
- bool thermal_triggered = false;
- for (auto &name_status_pair : sensor_status_map_) {
- Temperature_2_0 temp;
- TemperatureThreshold threshold;
- SensorStatus &sensor_status = name_status_pair.second;
- const SensorInfo &sensor_info = sensor_info_map_.at(name_status_pair.first);
- // Only send notification on whitelisted sensors
- if (!sensor_info.is_monitor) {
- continue;
- }
- // If callback is triggered by uevent, only check the sensors within uevent_sensors
- if (uevent_sensors.size() != 0 &&
- uevent_sensors.find(name_status_pair.first) == uevent_sensors.end()) {
- if (sensor_status.severity != ThrottlingSeverity::NONE) {
- thermal_triggered = true;
- }
- continue;
- }
-
- std::pair<ThrottlingSeverity, ThrottlingSeverity> throtting_status;
- if (!readTemperature(name_status_pair.first, &temp, &throtting_status)) {
- LOG(ERROR) << __func__
- << ": error reading temperature for sensor: " << name_status_pair.first;
- continue;
- }
- if (!readTemperatureThreshold(name_status_pair.first, &threshold)) {
- LOG(ERROR) << __func__ << ": error reading temperature threshold for sensor: "
- << name_status_pair.first;
- continue;
- }
-
- {
- // writer lock
- std::unique_lock<std::shared_mutex> _lock(sensor_status_map_mutex_);
- if (throtting_status.first != sensor_status.prev_hot_severity) {
- sensor_status.prev_hot_severity = throtting_status.first;
- }
- if (throtting_status.second != sensor_status.prev_cold_severity) {
- sensor_status.prev_cold_severity = throtting_status.second;
- }
- if (temp.throttlingStatus != sensor_status.severity) {
- temps.push_back(temp);
- sensor_status.severity = temp.throttlingStatus;
- }
- }
- if (sensor_status.severity != ThrottlingSeverity::NONE) {
- thermal_triggered = true;
- LOG(INFO) << temp.name << ": " << temp.value;
- }
- }
- if (!temps.empty() && cb_) {
- cb_(temps);
- }
-
- return thermal_triggered;
-}
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace thermal
-} // namespace hardware
-} // namespace android
+++ /dev/null
-/*
- * Copyright (c) 2018, The Linux Foundation. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- * * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- * * Neither the name of The Linux Foundation nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
- * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
- * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#pragma once
-
-#include <array>
-#include <chrono>
-#include <mutex>
-#include <shared_mutex>
-#include <string>
-#include <string_view>
-#include <thread>
-#include <unordered_map>
-#include <vector>
-
-#include <android/hardware/thermal/2.0/IThermal.h>
-
-#include "utils/config_parser.h"
-#include "utils/thermal_files.h"
-#include "utils/thermal_watcher.h"
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::hidl_vec;
-using ::android::hardware::thermal::V1_0::CpuUsage;
-using ::android::hardware::thermal::V2_0::CoolingType;
-using ::android::hardware::thermal::V2_0::IThermal;
-using CoolingDevice_1_0 = ::android::hardware::thermal::V1_0::CoolingDevice;
-using CoolingDevice_2_0 = ::android::hardware::thermal::V2_0::CoolingDevice;
-using Temperature_1_0 = ::android::hardware::thermal::V1_0::Temperature;
-using Temperature_2_0 = ::android::hardware::thermal::V2_0::Temperature;
-using TemperatureType_1_0 = ::android::hardware::thermal::V1_0::TemperatureType;
-using TemperatureType_2_0 = ::android::hardware::thermal::V2_0::TemperatureType;
-using ::android::hardware::thermal::V2_0::TemperatureThreshold;
-using ::android::hardware::thermal::V2_0::ThrottlingSeverity;
-
-using NotificationCallback = std::function<void(const std::vector<Temperature_2_0> &temps)>;
-using NotificationTime = std::chrono::time_point<std::chrono::steady_clock>;
-
-struct SensorStatus {
- ThrottlingSeverity severity;
- ThrottlingSeverity prev_hot_severity;
- ThrottlingSeverity prev_cold_severity;
-};
-
-class ThermalHelper {
- public:
- ThermalHelper(const NotificationCallback &cb);
- ~ThermalHelper() = default;
-
- bool fillTemperatures(hidl_vec<Temperature_1_0> *temperatures) const;
- bool fillCurrentTemperatures(bool filterType, TemperatureType_2_0 type,
- hidl_vec<Temperature_2_0> *temperatures) const;
- bool fillTemperatureThresholds(bool filterType, TemperatureType_2_0 type,
- hidl_vec<TemperatureThreshold> *thresholds) const;
- bool fillCurrentCoolingDevices(bool filterType, CoolingType type,
- hidl_vec<CoolingDevice_2_0> *coolingdevices) const;
- bool fillCpuUsages(hidl_vec<CpuUsage> *cpu_usages) const;
-
- // Dissallow copy and assign.
- ThermalHelper(const ThermalHelper &) = delete;
- void operator=(const ThermalHelper &) = delete;
-
- bool isInitializedOk() const { return is_initialized_; }
-
- // Read the temperature of a single sensor.
- bool readTemperature(std::string_view sensor_name, Temperature_1_0 *out) const;
- bool readTemperature(
- std::string_view sensor_name, Temperature_2_0 *out,
- std::pair<ThrottlingSeverity, ThrottlingSeverity> *throtting_status = nullptr) const;
- bool readTemperatureThreshold(std::string_view sensor_name, TemperatureThreshold *out) const;
- // Read the value of a single cooling device.
- bool readCoolingDevice(std::string_view cooling_device, CoolingDevice_2_0 *out) const;
- // Get SensorInfo Map
- const std::map<std::string, SensorInfo> &GetSensorInfoMap() const { return sensor_info_map_; }
-
- private:
- bool initializeSensorMap(const std::map<std::string, std::string> &path_map);
- bool initializeCoolingDevices(const std::map<std::string, std::string> &path_map);
- bool initializeTrip(const std::map<std::string, std::string> &path_map);
-
- // For thermal_watcher_'s polling thread
- bool thermalWatcherCallbackFunc(const std::set<std::string> &uevent_sensors);
- // Return hot and cold severity status as std::pair
- std::pair<ThrottlingSeverity, ThrottlingSeverity> getSeverityFromThresholds(
- const ThrottlingArray &hot_thresholds, const ThrottlingArray &cold_thresholds,
- const ThrottlingArray &hot_hysteresis, const ThrottlingArray &cold_hysteresis,
- ThrottlingSeverity prev_hot_severity, ThrottlingSeverity prev_cold_severity,
- float value) const;
-
- sp<ThermalWatcher> thermal_watcher_;
- ThermalFiles thermal_sensors_;
- ThermalFiles cooling_devices_;
- bool is_initialized_;
- const NotificationCallback cb_;
- const std::map<std::string, CoolingType> cooling_device_info_map_;
- const std::map<std::string, SensorInfo> sensor_info_map_;
-
- mutable std::shared_mutex sensor_status_map_mutex_;
- std::map<std::string, SensorStatus> sensor_status_map_;
-};
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace thermal
-} // namespace hardware
-} // namespace android
+++ /dev/null
-{
- "Sensors":[
- {
- "Name":"therm_zone0",
- "Type":"CPU",
- "HotThreshold":[
- "NAN",
- 76.0,
- 81.0,
- 86.0,
- 96.0,
- 101.0,
- 115.0
- ],
- "VrThreshold":"NAN",
- "Multiplier":0.001
- },
- {
- "Name":"therm_zone1",
- "Type":"CPU",
- "HotThreshold":[
- "NAN",
- 76.0,
- 81.0,
- 86.0,
- 96.0,
- 101.0,
- 115.0
- ],
- "VrThreshold":"NAN",
- "Multiplier":0.001
- },
- {
- "Name":"therm_zone2",
- "Type":"CPU",
- "HotThreshold":[
- "NAN",
- 76.0,
- 81.0,
- 86.0,
- 96.0,
- 101.0,
- 115.0
- ],
- "VrThreshold":"NAN",
- "Multiplier":0.001
- },
- {
- "Name":"therm_zone3",
- "Type":"CPU",
- "HotThreshold":[
- "NAN",
- 76.0,
- 81.0,
- 86.0,
- 96.0,
- 101.0,
- 115.0
- ],
- "VrThreshold":"NAN",
- "Multiplier":0.001
- },
- {
- "Name":"therm_zone4",
- "Type":"CPU",
- "HotThreshold":[
- "NAN",
- 76.0,
- 81.0,
- 86.0,
- 96.0,
- 101.0,
- 115.0
- ],
- "VrThreshold":"NAN",
- "Multiplier":0.001
- },
- {
- "Name":"ac",
- "Type":"USB_PORT",
- "HotThreshold":[
- "NAN",
- "NAN",
- "NAN",
- "NAN",
- "NAN",
- "60.0",
- "NAN"
- ],
- "HotHysteresis":[
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- 0.0,
- 5.0,
- 0.0
- ],
- "VrThreshold":"NAN",
- "Multiplier":0.001,
- "Monitor": true
- },
- {
- "Name":"max77854-fuelgauge",
- "Type":"UNKNOWN",
- "HotThreshold":[
- "NAN",
- "NAN",
- "NAN",
- "NAN",
- "NAN",
- "NAN",
- "NAN"
- ],
- "VrThreshold":"NAN",
- "Multiplier":0.001
- },
- {
- "Name":"battery",
- "Type":"BATTERY",
- "HotThreshold":[
- "NAN",
- "NAN",
- "NAN",
- "NAN",
- "NAN",
- "NAN",
- 60.0
- ],
- "VrThreshold":"NAN",
- "Multiplier":0.001
- }
- ],
- "CoolingDevices":[
- {
- "Name":"thermal-cpufreq-0",
- "Type":"CPU"
- },
- {
- "Name":"thermal-cpufreq-1",
- "Type":"CPU"
- },
- {
- "Name":"thermal-cpufreq-2",
- "Type":"CPU"
- },
- {
- "Name":"thermal-gpufreq-0",
- "Type":"GPU"
- },
- {
- "Name":"thermal-isp-0",
- "Type":"COMPONENT"
- },
- {
- "Name":"battery",
- "Type":"BATTERY"
- }
- ]
-}
+++ /dev/null
-/*
- * 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 <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/strings.h>
-#include <cmath>
-#include <set>
-
-#include <json/reader.h>
-#include <json/value.h>
-
-#include "config_parser.h"
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::hidl_enum_range;
-using ::android::hardware::thermal::V2_0::toString;
-using TemperatureType_2_0 = ::android::hardware::thermal::V2_0::TemperatureType;
-
-namespace {
-
-template <typename T>
-// Return false when failed parsing
-bool getTypeFromString(std::string_view str, T *out) {
- auto types = hidl_enum_range<T>();
- for (const auto &type : types) {
- if (toString(type) == str) {
- *out = type;
- return true;
- }
- }
- return false;
-}
-
-float getFloatFromValue(const Json::Value &value) {
- if (value.isString()) {
- return std::stof(value.asString());
- } else {
- return value.asFloat();
- }
-}
-
-} // namespace
-
-std::map<std::string, SensorInfo> ParseSensorInfo(std::string_view config_path) {
- std::string json_doc;
- std::map<std::string, SensorInfo> sensors_parsed;
- if (!android::base::ReadFileToString(config_path.data(), &json_doc)) {
- LOG(ERROR) << "Failed to read JSON config from " << config_path;
- return sensors_parsed;
- }
-
- Json::Value root;
- Json::CharReaderBuilder builder;
- std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
- std::string errorMessage;
-
- if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
- LOG(ERROR) << "Failed to parse JSON config";
- return sensors_parsed;
- }
-
- Json::Value sensors = root["Sensors"];
- std::size_t total_parsed = 0;
- std::set<std::string> sensors_name_parsed;
-
- for (Json::Value::ArrayIndex i = 0; i < sensors.size(); ++i) {
- const std::string &name = sensors[i]["Name"].asString();
- LOG(INFO) << "Sensor[" << i << "]'s Name: " << name;
- if (name.empty()) {
- LOG(ERROR) << "Failed to read "
- << "Sensor[" << i << "]'s Name";
- sensors_parsed.clear();
- return sensors_parsed;
- }
-
- auto result = sensors_name_parsed.insert(name);
- if (!result.second) {
- LOG(ERROR) << "Duplicate Sensor[" << i << "]'s Name";
- sensors_parsed.clear();
- return sensors_parsed;
- }
-
- std::string sensor_type_str = sensors[i]["Type"].asString();
- LOG(INFO) << "Sensor[" << name << "]'s Type: " << sensor_type_str;
- TemperatureType_2_0 sensor_type;
-
- if (!getTypeFromString(sensor_type_str, &sensor_type)) {
- LOG(ERROR) << "Invalid "
- << "Sensor[" << name << "]'s Type: " << sensor_type_str;
- sensors_parsed.clear();
- return sensors_parsed;
- }
-
- std::array<float, kThrottlingSeverityCount> hot_thresholds;
- hot_thresholds.fill(NAN);
- std::array<float, kThrottlingSeverityCount> cold_thresholds;
- cold_thresholds.fill(NAN);
- std::array<float, kThrottlingSeverityCount> hot_hysteresis;
- hot_hysteresis.fill(0.0);
- std::array<float, kThrottlingSeverityCount> cold_hysteresis;
- cold_hysteresis.fill(0.0);
-
- Json::Value values = sensors[i]["HotThreshold"];
- if (values.size() != kThrottlingSeverityCount) {
- LOG(ERROR) << "Invalid "
- << "Sensor[" << name << "]'s HotThreshold count" << values.size();
- sensors_parsed.clear();
- return sensors_parsed;
- } else {
- float min = std::numeric_limits<float>::min();
- for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
- hot_thresholds[j] = getFloatFromValue(values[j]);
- if (!std::isnan(hot_thresholds[j])) {
- if (hot_thresholds[j] < min) {
- LOG(ERROR) << "Invalid "
- << "Sensor[" << name << "]'s HotThreshold[j" << j
- << "]: " << hot_thresholds[j] << " < " << min;
- sensors_parsed.clear();
- return sensors_parsed;
- }
- min = hot_thresholds[j];
- }
- LOG(INFO) << "Sensor[" << name << "]'s HotThreshold[" << j
- << "]: " << hot_thresholds[j];
- }
- }
-
- values = sensors[i]["HotHysteresis"];
- if (values.size() != kThrottlingSeverityCount) {
- LOG(INFO) << "Cannot find valid "
- << "Sensor[" << name << "]'s HotHysteresis, default all to 0.0";
- } else {
- for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
- hot_hysteresis[j] = getFloatFromValue(values[j]);
- if (std::isnan(hot_hysteresis[j])) {
- LOG(ERROR) << "Invalid "
- << "Sensor[" << name << "]'s HotHysteresis: " << hot_hysteresis[j];
- sensors_parsed.clear();
- return sensors_parsed;
- }
- LOG(INFO) << "Sensor[" << name << "]'s HotHysteresis[" << j
- << "]: " << hot_hysteresis[j];
- }
- }
-
- values = sensors[i]["ColdThreshold"];
- if (values.size() != kThrottlingSeverityCount) {
- LOG(INFO) << "Cannot find valid "
- << "Sensor[" << name << "]'s ColdThreshold, default all to NAN";
- } else {
- float max = std::numeric_limits<float>::max();
- for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
- cold_thresholds[j] = getFloatFromValue(values[j]);
- if (!std::isnan(cold_thresholds[j])) {
- if (cold_thresholds[j] > max) {
- LOG(ERROR) << "Invalid "
- << "Sensor[" << name << "]'s ColdThreshold[j" << j
- << "]: " << cold_thresholds[j] << " > " << max;
- sensors_parsed.clear();
- return sensors_parsed;
- }
- max = cold_thresholds[j];
- }
- LOG(INFO) << "Sensor[" << name << "]'s ColdThreshold[" << j
- << "]: " << cold_thresholds[j];
- }
- }
-
- values = sensors[i]["ColdHysteresis"];
- if (values.size() != kThrottlingSeverityCount) {
- LOG(INFO) << "Cannot find valid "
- << "Sensor[" << name << "]'s ColdHysteresis, default all to 0.0";
- } else {
- for (Json::Value::ArrayIndex j = 0; j < kThrottlingSeverityCount; ++j) {
- cold_hysteresis[j] = getFloatFromValue(values[j]);
- if (std::isnan(cold_hysteresis[j])) {
- LOG(ERROR) << "Invalid "
- << "Sensor[" << name
- << "]'s ColdHysteresis: " << cold_hysteresis[j];
- sensors_parsed.clear();
- return sensors_parsed;
- }
- LOG(INFO) << "Sensor[" << name << "]'s ColdHysteresis[" << j
- << "]: " << cold_hysteresis[j];
- }
- }
-
- float vr_threshold = NAN;
- vr_threshold = getFloatFromValue(sensors[i]["VrThreshold"]);
- LOG(INFO) << "Sensor[" << name << "]'s VrThreshold: " << vr_threshold;
-
- float multiplier = sensors[i]["Multiplier"].asFloat();
- LOG(INFO) << "Sensor[" << name << "]'s Multiplier: " << multiplier;
-
- bool is_monitor = false;
- if (sensors[i]["Monitor"].empty() || !sensors[i]["Monitor"].isBool()) {
- LOG(INFO) << "Failed to read Sensor[" << name << "]'s Monitor, set to 'false'";
- } else {
- is_monitor = sensors[i]["Monitor"].asBool();
- }
- LOG(INFO) << "Sensor[" << name << "]'s Monitor: " << std::boolalpha << is_monitor
- << std::noboolalpha;
-
- sensors_parsed[name] = {
- .type = sensor_type,
- .hot_thresholds = hot_thresholds,
- .cold_thresholds = cold_thresholds,
- .hot_hysteresis = hot_hysteresis,
- .cold_hysteresis = cold_hysteresis,
- .vr_threshold = vr_threshold,
- .multiplier = multiplier,
- .is_monitor = is_monitor,
- };
- ++total_parsed;
- }
-
- LOG(INFO) << total_parsed << " Sensors parsed successfully";
- return sensors_parsed;
-}
-
-std::map<std::string, CoolingType> ParseCoolingDevice(std::string_view config_path) {
- std::string json_doc;
- std::map<std::string, CoolingType> cooling_devices_parsed;
- if (!android::base::ReadFileToString(config_path.data(), &json_doc)) {
- LOG(ERROR) << "Failed to read JSON config from " << config_path;
- return cooling_devices_parsed;
- }
-
- Json::Value root;
- Json::CharReaderBuilder builder;
- std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
- std::string errorMessage;
-
- if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) {
- LOG(ERROR) << "Failed to parse JSON config";
- return cooling_devices_parsed;
- }
-
- Json::Value cooling_devices = root["CoolingDevices"];
- std::size_t total_parsed = 0;
- std::set<std::string> cooling_devices_name_parsed;
-
- for (Json::Value::ArrayIndex i = 0; i < cooling_devices.size(); ++i) {
- const std::string &name = cooling_devices[i]["Name"].asString();
- LOG(INFO) << "CoolingDevice[" << i << "]'s Name: " << name;
- if (name.empty()) {
- LOG(ERROR) << "Failed to read "
- << "CoolingDevice[" << i << "]'s Name";
- cooling_devices_parsed.clear();
- return cooling_devices_parsed;
- }
-
- auto result = cooling_devices_name_parsed.insert(name.data());
- if (!result.second) {
- LOG(ERROR) << "Duplicate CoolingDevice[" << i << "]'s Name";
- cooling_devices_parsed.clear();
- return cooling_devices_parsed;
- }
-
- std::string cooling_device_type_str = cooling_devices[i]["Type"].asString();
- LOG(INFO) << "CoolingDevice[" << name << "]'s Type: " << cooling_device_type_str;
- CoolingType cooling_device_type;
-
- if (!getTypeFromString(cooling_device_type_str, &cooling_device_type)) {
- LOG(ERROR) << "Invalid "
- << "CoolingDevice[" << name << "]'s Type: " << cooling_device_type_str;
- cooling_devices_parsed.clear();
- return cooling_devices_parsed;
- }
-
- cooling_devices_parsed[name] = cooling_device_type;
-
- ++total_parsed;
- }
-
- LOG(INFO) << total_parsed << " CoolingDevices parsed successfully";
- return cooling_devices_parsed;
-}
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace thermal
-} // namespace hardware
-} // namespace android
+++ /dev/null
-/*
- * 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.
- */
-
-#pragma once
-
-#include <map>
-#include <string>
-
-#include <android/hardware/thermal/2.0/IThermal.h>
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V2_0 {
-namespace implementation {
-
-using ::android::hardware::hidl_enum_range;
-using ::android::hardware::thermal::V2_0::CoolingType;
-using TemperatureType_2_0 = ::android::hardware::thermal::V2_0::TemperatureType;
-using ::android::hardware::thermal::V2_0::ThrottlingSeverity;
-constexpr size_t kThrottlingSeverityCount = std::distance(
- hidl_enum_range<ThrottlingSeverity>().begin(), hidl_enum_range<ThrottlingSeverity>().end());
-using ThrottlingArray = std::array<float, static_cast<size_t>(kThrottlingSeverityCount)>;
-
-struct SensorInfo {
- TemperatureType_2_0 type;
- ThrottlingArray hot_thresholds;
- ThrottlingArray cold_thresholds;
- ThrottlingArray hot_hysteresis;
- ThrottlingArray cold_hysteresis;
- float vr_threshold;
- float multiplier;
- bool is_monitor;
-};
-
-std::map<std::string, SensorInfo> ParseSensorInfo(std::string_view config_path);
-std::map<std::string, CoolingType> ParseCoolingDevice(std::string_view config_path);
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace thermal
-} // namespace hardware
-} // namespace android
+++ /dev/null
-{
- "definitions":{
-
- },
- "$schema":"http://json-schema.org/draft-07/schema#",
- "$id":"http://example.com/root.json",
- "type":"object",
- "title":"The Root Schema",
- "required":[
- "Sensors"
- ],
- "properties":{
- "Sensors":{
- "$id":"#/properties/Sensors",
- "type":"array",
- "title":"The Sensors Schema",
- "items":{
- "$id":"#/properties/Sensors/items",
- "type":"object",
- "title":"The Items Schema",
- "required":[
- "Name",
- "Type",
- "HotThreshold",
- "VrThreshold",
- "Multiplier"
- ],
- "properties":{
- "Name":{
- "$id":"#/properties/Sensors/items/properties/Name",
- "type":"string",
- "title":"The Name Schema",
- "default":"",
- "examples":[
- "cpu0-silver-usr"
- ],
- "pattern":"^(.+)$"
- },
- "Type":{
- "$id":"#/properties/Sensors/items/properties/Type",
- "type":"string",
- "title":"The Type Schema",
- "default":"",
- "examples":[
- "CPU"
- ],
- "pattern":"^(.+)$"
- },
- "HotThreshold":{
- "$id":"#/properties/Sensors/items/properties/HotThreshold",
- "type":"array",
- "title":"The hot threshold Schema, values are thresholds from ThrottlingSeverity::NONE to ThrottlingSeverity::SHUTDOWN",
- "default":"NAN",
- "maxItems":7,
- "minItems":7,
- "items":{
- "$id":"#/properties/Sensors/items/properties/HotThreshold/items",
- "type":[
- "string",
- "number"
- ],
- "title":"The Items Schema",
- "default":"",
- "examples":[
- "NAN",
- "NAN",
- "NAN",
- 95,
- "NAN",
- "NAN",
- 125
- ],
- "pattern":"^([-+]?[0-9]*\\.?[0-9]+|NAN)$"
- }
- },
- "HotHysteresis":{
- "$id":"#/properties/Sensors/items/properties/HotHysteresis",
- "type":"array",
- "title":"The hot hysteresis Schema, values are thresholds from ThrottlingSeverity::NONE to ThrottlingSeverity::SHUTDOWN. Throttling status will be cleared HotThreshold - HotHysteresis.",
- "default":null,
- "maxItems":7,
- "minItems":7,
- "items":{
- "$id":"#/properties/Sensors/items/properties/HotHysteresis/items",
- "type":[
- "number"
- ],
- "title":"The Items Schema",
- "default":0.0,
- "examples":[
- 0.0,
- 0.0,
- 0.0,
- 1.0,
- 1.5,
- 1.0,
- 2.0
- ]
- }
- },
- "ColdThreshold":{
- "$id":"#/properties/Sensors/items/properties/ColdThreshold",
- "type":"array",
- "title":"The cold threshold Schema, values are thresholds from ThrottlingSeverity::NONE to ThrottlingSeverity::SHUTDOWN, default to NAN",
- "default":null,
- "maxItems":7,
- "minItems":7,
- "items":{
- "$id":"#/properties/Sensors/items/properties/ColdThreshold/items",
- "type":"string",
- "title":"The Items Schema",
- "default":"NAN",
- "examples":[
- "NAN",
- "NAN",
- "NAN",
- "NAN",
- "NAN",
- "NAN",
- "NAN"
- ],
- "pattern":"^([-+]?[0-9]*\\.?[0-9]+|NAN)$"
- }
- },
- "ColdHysteresis":{
- "$id":"#/properties/Sensors/items/properties/ColdHysteresis",
- "type":"array",
- "title":"The cold hysteresis Schema, values are thresholds from ThrottlingSeverity::NONE to ThrottlingSeverity::SHUTDOWN. Throttling status will be cleared ColdThreshold + ColdHysteresis.",
- "default":null,
- "maxItems":7,
- "minItems":7,
- "items":{
- "$id":"#/properties/Sensors/items/properties/ColdHysteresis/items",
- "type":[
- "number"
- ],
- "title":"The Items Schema",
- "default":0.0,
- "examples":[
- 0.0,
- 0.0,
- 0.0,
- 1.0,
- 1.5,
- 1.0,
- 2.0
- ]
- }
- },
- "VrThreshold":{
- "$id":"#/properties/Sensors/items/properties/VrThreshold",
- "type":"string",
- "title":"The Vrthreshold Schema",
- "default":"",
- "examples":[
- "NAN"
- ],
- "pattern":"^(.*)$"
- },
- "Multiplier":{
- "$id":"#/properties/Sensors/items/properties/Multiplier",
- "type":"number",
- "title":"The Multiplier Schema",
- "default":0.001,
- "examples":[
- 0.001
- ],
- "exclusiveMinimum":0.0
- },
- "Monitor":{
- "$id":"#/properties/Sensors/items/properties/Monitor",
- "type":"boolean",
- "title":"The Monitor Schema, if the sensor will be monitored and used to trigger throttling event",
- "default":false,
- "examples":[
- true
- ]
- }
- }
- }
- },
- "CoolingDevices":{
- "$id":"#/properties/CoolingDevices",
- "type":"array",
- "title":"The Coolingdevices Schema",
- "items":{
- "$id":"#/properties/CoolingDevices/items",
- "type":"object",
- "title":"The Items Schema",
- "required":[
- "Name",
- "Type"
- ],
- "properties":{
- "Name":{
- "$id":"#/properties/CoolingDevices/items/properties/Name",
- "type":"string",
- "title":"The Name Schema",
- "default":"",
- "examples":[
- "thermal-cpufreq-0"
- ],
- "pattern":"^(.+)$"
- },
- "Type":{
- "$id":"#/properties/CoolingDevices/items/properties/Type",
- "type":"string",
- "title":"The Type Schema",
- "default":"",
- "examples":[
- "CPU"
- ],
- "pattern":"^(.+)$"
- }
- }
- }
- }
- }
-}
+++ /dev/null
-/*
- * 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 <string_view>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/strings.h>
-#include "thermal_files.h"
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V2_0 {
-namespace implementation {
-
-std::string ThermalFiles::getThermalFilePath(std::string_view thermal_name) const {
- auto sensor_itr = thermal_name_to_path_map_.find(thermal_name.data());
- if (sensor_itr == thermal_name_to_path_map_.end()) {
- return "";
- }
- return sensor_itr->second;
-}
-
-bool ThermalFiles::addThermalFile(std::string_view thermal_name, std::string_view path) {
- return thermal_name_to_path_map_.emplace(thermal_name, path).second;
-}
-
-bool ThermalFiles::readThermalFile(std::string_view thermal_name, std::string *data) const {
- std::string sensor_reading;
- std::string file_path = getThermalFilePath(std::string_view(thermal_name));
- *data = "";
- if (file_path.empty()) {
- return false;
- }
-
- if (!::android::base::ReadFileToString(file_path, &sensor_reading)) {
- PLOG(WARNING) << "Failed to read sensor: " << thermal_name;
- return false;
- }
-
- // Strip the newline.
- *data = ::android::base::Trim(sensor_reading);
- return true;
-}
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace thermal
-} // namespace hardware
-} // namespace android
+++ /dev/null
-/*
- * 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.
- */
-
-#pragma once
-
-#include <string>
-#include <unordered_map>
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V2_0 {
-namespace implementation {
-
-class ThermalFiles {
- public:
- ThermalFiles() = default;
- ~ThermalFiles() = default;
- ThermalFiles(const ThermalFiles &) = delete;
- void operator=(const ThermalFiles &) = delete;
-
- std::string getThermalFilePath(std::string_view thermal_name) const;
- // Returns true if add was successful, false otherwise.
- bool addThermalFile(std::string_view thermal_name, std::string_view path);
- // If thermal_name is not found in the thermal names to path map, this will set
- // data to empty and return false. If the thermal_name is found and its content
- // is read, this function will fill in data accordingly then return true.
- bool readThermalFile(std::string_view thermal_name, std::string *data) const;
- size_t getNumThermalFiles() const { return thermal_name_to_path_map_.size(); }
-
- private:
- std::unordered_map<std::string, std::string> thermal_name_to_path_map_;
-};
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace thermal
-} // namespace hardware
-} // namespace android
+++ /dev/null
-/*
- * 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 <cutils/uevent.h>
-#include <dirent.h>
-#include <sys/inotify.h>
-#include <sys/resource.h>
-#include <sys/types.h>
-#include <chrono>
-#include <fstream>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/strings.h>
-
-#include "thermal_watcher.h"
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V2_0 {
-namespace implementation {
-
-using std::chrono_literals::operator""ms;
-
-void ThermalWatcher::registerFilesToWatch(const std::set<std::string> &sensors_to_watch,
- bool uevent_monitor) {
- monitored_sensors_.insert(sensors_to_watch.begin(), sensors_to_watch.end());
- if (!uevent_monitor) {
- is_polling_ = true;
- return;
- }
- uevent_fd_.reset((TEMP_FAILURE_RETRY(uevent_open_socket(64 * 1024, true))));
- if (uevent_fd_.get() < 0) {
- LOG(ERROR) << "failed to open uevent socket";
- is_polling_ = true;
- return;
- }
-
- fcntl(uevent_fd_, F_SETFL, O_NONBLOCK);
-
- looper_->addFd(uevent_fd_.get(), 0, Looper::EVENT_INPUT, nullptr, nullptr);
- is_polling_ = false;
- thermal_triggered_ = true;
- last_update_time_ = boot_clock::now();
-}
-
-bool ThermalWatcher::startWatchingDeviceFiles() {
- if (cb_) {
- auto ret = this->run("FileWatcherThread", PRIORITY_HIGHEST);
- if (ret != NO_ERROR) {
- LOG(ERROR) << "ThermalWatcherThread start fail";
- return false;
- } else {
- LOG(INFO) << "ThermalWatcherThread started";
- return true;
- }
- }
- return false;
-}
-void ThermalWatcher::parseUevent(std::set<std::string> *sensors_set) {
- bool thermal_event = false;
- constexpr int kUeventMsgLen = 2048;
- char msg[kUeventMsgLen + 2];
- char *cp;
-
- while (true) {
- int n = uevent_kernel_multicast_recv(uevent_fd_.get(), msg, kUeventMsgLen);
- if (n <= 0) {
- if (errno != EAGAIN && errno != EWOULDBLOCK) {
- LOG(ERROR) << "Error reading from Uevent Fd";
- }
- break;
- }
-
- if (n >= kUeventMsgLen) {
- LOG(ERROR) << "Uevent overflowed buffer, discarding";
- continue;
- }
-
- msg[n] = '\0';
- msg[n + 1] = '\0';
-
- cp = msg;
- while (*cp) {
- std::string uevent = cp;
- if (!thermal_event) {
- if (uevent.find("SUBSYSTEM=") == 0) {
- if (uevent.find("SUBSYSTEM=thermal") != std::string::npos) {
- thermal_event = true;
- } else {
- break;
- }
- }
- } else {
- auto start_pos = uevent.find("NAME=");
- if (start_pos != std::string::npos) {
- start_pos += 5;
- std::string name = uevent.substr(start_pos);
- if (std::find(monitored_sensors_.begin(), monitored_sensors_.end(), name) !=
- monitored_sensors_.end()) {
- sensors_set->insert(name);
- }
- break;
- }
- }
- while (*cp++) {
- }
- }
- }
-}
-
-void ThermalWatcher::wake() {
- looper_->wake();
-}
-
-bool ThermalWatcher::threadLoop() {
- LOG(VERBOSE) << "ThermalWatcher polling...";
- // Polling interval 2s
- static constexpr int kMinPollIntervalMs = 2000;
- // Max uevent timeout 5mins
- static constexpr int kUeventPollTimeoutMs = 300000;
- int fd;
- std::set<std::string> sensors;
-
- auto time_elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(boot_clock::now() -
- last_update_time_)
- .count();
- int timeout = (thermal_triggered_ || is_polling_) ? kMinPollIntervalMs : kUeventPollTimeoutMs;
- if (time_elapsed_ms < timeout && looper_->pollOnce(timeout, &fd, nullptr, nullptr) >= 0) {
- if (fd != uevent_fd_.get()) {
- return true;
- }
- parseUevent(&sensors);
- // Ignore cb_ if uevent is not from monitored sensors
- if (sensors.size() == 0) {
- return true;
- }
- }
- thermal_triggered_ = cb_(sensors);
- last_update_time_ = boot_clock::now();
- return true;
-}
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace thermal
-} // namespace hardware
-} // namespace android
+++ /dev/null
-/*
- * 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.
- */
-
-#pragma once
-
-#include <chrono>
-#include <condition_variable>
-#include <future>
-#include <list>
-#include <mutex>
-#include <set>
-#include <string>
-#include <thread>
-#include <unordered_map>
-#include <vector>
-
-#include <android-base/chrono_utils.h>
-#include <android-base/unique_fd.h>
-#include <utils/Looper.h>
-#include <utils/Thread.h>
-
-namespace android {
-namespace hardware {
-namespace thermal {
-namespace V2_0 {
-namespace implementation {
-
-using android::base::boot_clock;
-using android::base::unique_fd;
-using WatcherCallback = std::function<bool(const std::set<std::string> &name)>;
-
-// A helper class for monitoring thermal files changes.
-class ThermalWatcher : public ::android::Thread {
- public:
- ThermalWatcher(const WatcherCallback &cb)
- : Thread(false), cb_(cb), looper_(new Looper(true)) {}
- ~ThermalWatcher() = default;
-
- // Disallow copy and assign.
- ThermalWatcher(const ThermalWatcher &) = delete;
- void operator=(const ThermalWatcher &) = delete;
-
- // Start the thread and return true if it succeeds.
- 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 with a looper.
- // This should be called before starting watcher thread.
- void registerFilesToWatch(const std::set<std::string> &sensors_to_watch, bool uevent_monitor);
- // Wake up the looper thus the worker thread, immediately. This can be called
- // in any thread.
- void wake();
-
- 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.
- bool threadLoop() override;
-
- // Parse uevent message
- void parseUevent(std::set<std::string> *sensor_name);
-
- // Maps watcher filer descriptor to watched file path.
- std::unordered_map<int, std::string> watch_to_file_path_map_;
-
- // The callback function. Called whenever thermal uevent is seen.
- // The function passed in should expect a string in the form (type).
- // Where type is the name of the thermal zone that trigger a uevent notification.
- // Callback will return thermal trigger status for next polling decision.
- const WatcherCallback cb_;
-
- sp<Looper> looper_;
-
- // For uevent socket registration.
- android::base::unique_fd uevent_fd_;
- // Sensor list which monitor flag is enabled.
- std::set<std::string> monitored_sensors_;
- // Flag to point out if any sensor across the first threshold.
- bool thermal_triggered_;
- // Flag to point out if device can support uevent notify.
- bool is_polling_;
- // Timestamp for last thermal update
- boot_clock::time_point last_update_time_;
-};
-
-} // namespace implementation
-} // namespace V2_0
-} // namespace thermal
-} // namespace hardware
-} // namespace android