replace common qcom sources with samsung ones

This commit is contained in:
SaschaNes
2025-08-12 22:13:00 +02:00
parent ba24dcded9
commit 6f7753de11
5682 changed files with 2450203 additions and 103634 deletions

View File

@@ -0,0 +1,77 @@
cc_binary {
name: "android.hardware.thermal-service.qti",
relative_install_path: "hw",
init_rc: ["android.hardware.thermal-service.qti.rc"],
vintf_fragments: ["android.hardware.thermal-service.qti.xml"],
vendor: true,
shared_libs: [
"libbase",
"libbinder_ndk",
"android.hardware.thermal-V2-ndk",
"libcutils",
"libutils",
"liblog",
"libnl",
],
srcs: [
"service.cpp",
"thermal.cpp",
"thermalConfig.cpp",
"thermalCommon.cpp",
"thermalUtilsNetlink.cpp",
"thermalMonitorNetlink.cpp",
],
header_libs: [
"liblog_headers",
"libcutils_headers",
"qti_kernel_headers"
],
cflags: [
"-Wno-unused-parameter",
"-Wno-unused-variable",
"-DENABLE_THERMAL_NETLINK",
"-fexceptions",
],
}
cc_fuzz {
name: "aidl_fuzzer_thermal",
vendor: true,
shared_libs: [
"liblog",
"libbase",
"libutils",
"libcutils",
"libbinder",
"libbinder_ndk",
"android.hardware.thermal-V2-ndk",
"libnl",
],
srcs: [
"fuzzer.cpp",
"thermal.cpp",
"thermalConfig.cpp",
"thermalCommon.cpp",
"thermalUtilsNetlink.cpp",
"thermalMonitorNetlink.cpp",
],
header_libs: [
"liblog_headers",
"libcutils_headers",
"qti_kernel_headers"
],
cflags: [
"-Wno-unused-parameter",
"-Wno-unused-variable",
"-DENABLE_THERMAL_NETLINK",
"-fexceptions",
],
static_libs: [
"libbinder_random_parcel",
],
}

View File

@@ -0,0 +1,39 @@
# Copyright (c) 2021, The Linux Foundation. All rights reserved.
# Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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.
#Changes from Qualcomm Innovation Center are provided under the following license:
#Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
#SPDX-License-Identifier: BSD-3-Clause-Clear
service vendor.thermal-hal /vendor/bin/hw/android.hardware.thermal-service.qti
interface aidl android.hardware.thermal.IThermal/default
class hal
user root
group root

View File

@@ -0,0 +1,43 @@
<!--
Copyright (c) 2020, 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.
-->
<!-- Changes from Qualcomm Innovation Center are provided under the following license:
Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear -->
<manifest version="2.0" type="device">
<hal format="aidl">
<name>android.hardware.thermal</name>
<version>2</version>
<fqname>IThermal/default</fqname>
</hal>
</manifest>

View File

@@ -0,0 +1,26 @@
/*
* Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*/
#include <fuzzbinder/libbinder_ndk_driver.h>
#include <fuzzer/FuzzedDataProvider.h>
#include "thermal.h"
using aidl::android::hardware::thermal::Thermal;
std::shared_ptr<Thermal> service;
extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
service = ndk::SharedRefBase::make<Thermal>();
return 0;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if( service == nullptr ) return 0;
FuzzedDataProvider provider(data, size);
android::fuzzService(service->asBinder().get(),std::move(provider));
return 0;
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
* Not a contribution
* 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.
*/
/* Changes from Qualcomm Innovation Center are provided under the following license:
Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear */
#define LOG_TAG "thermal_hal"
#include "thermal.h"
#include <android-base/logging.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
using ::android::OK;
using ::android::status_t;
using aidl::android::hardware::thermal::Thermal;
int main() {
LOG(INFO) << "Thermal HAL Service AIDL starting...";
ABinderProcess_setThreadPoolMaxThreadCount(0);
std::shared_ptr<Thermal> therm = ndk::SharedRefBase::make<Thermal>();
const std::string instance = std::string() + Thermal::descriptor + "/default";
if(therm){
binder_status_t status =
AServiceManager_addService(therm->asBinder().get(), instance.c_str());
CHECK(status == STATUS_OK);
}
LOG(INFO) << "Thermal HAL Service AIDL started successfully.";
ABinderProcess_joinThreadPool();
return EXIT_FAILURE; // should not reach
}

View File

@@ -0,0 +1,359 @@
/*
* Copyright (c) 2020, 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.
*/
/* Changes from Qualcomm Innovation Center are provided under the following license:
Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear */
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include <cerrno>
#include <mutex>
#include <string>
#include <android-base/file.h>
#include <android-base/logging.h>
#include "thermal.h"
namespace aidl::android::hardware::thermal{
using ndk::ScopedAStatus;
namespace {
bool interfacesEqual(const std::shared_ptr<::ndk::ICInterface>& left,
const std::shared_ptr<::ndk::ICInterface>& right) {
if (left == nullptr || right == nullptr || !left->isRemote() || !right->isRemote()) {
return left == right;
}
return left->asBinder() == right->asBinder();
}
}// namespace
static const Temperature dummy_temp_1_0 = {
.type = TemperatureType::SKIN,
.name = "test sensor",
.value = 30,
.throttlingStatus = ThrottlingSeverity::NONE,
};
Thermal::Thermal():
utils(std::bind(&Thermal::sendThrottlingChangeCB, this,
std::placeholders::_1),
std::bind(&Thermal::sendCoolingDeviceChangeCB, this,
std::placeholders::_1))
{ }
ScopedAStatus Thermal::getCoolingDevices(std::vector<CoolingDevice>* out_data) {
std::vector<CoolingDevice> cdev;
if (!utils.isCdevInitialized())
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"ThermalHAL not initialized properly.");
else {
if (utils.readCdevStates(cdev) <= 0)
LOG(VERBOSE) << __func__ << "Failed to read thermal cooling devices.";
}
if (out_data != nullptr)
*out_data = std::move(cdev);
return ScopedAStatus::ok();
}
ScopedAStatus Thermal::getCoolingDevicesWithType(CoolingType in_type,
std::vector<CoolingDevice>* out_data) {
std::vector<CoolingDevice> cdev;
if (!utils.isCdevInitialized())
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"ThermalHAL not initialized properly.");
else {
if (utils.readCdevStates(in_type, cdev) <= 0)
LOG(VERBOSE) << __func__ << "Failed to read thermal cooling devices.";
}
if (out_data != nullptr)
*out_data = std::move(cdev);
return ScopedAStatus::ok();
}
ScopedAStatus Thermal::getTemperatures(std::vector<Temperature>* out_temp) {
LOG(VERBOSE) << __func__;
std::vector<Temperature> temperatures;
if (!utils.isSensorInitialized()) {
std::vector<Temperature> _temp = {dummy_temp_1_0};
LOG(VERBOSE) << __func__ << " Returning Dummy Value";
if (out_temp != nullptr)
*out_temp = std::move(_temp);
return ScopedAStatus::ok();
}
if (utils.readTemperatures(temperatures) <= 0)
LOG(VERBOSE) << __func__ << "Sensor Temperature read failure.";
if (out_temp != nullptr)
*out_temp = std::move(temperatures);
return ScopedAStatus::ok();
}
ScopedAStatus Thermal::getTemperaturesWithType(TemperatureType in_type,
std::vector<Temperature>* out_temp) {
std::vector<Temperature> temperatures;
if (!utils.isSensorInitialized())
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"ThermalHAL not initialized properly.");
else {
if (utils.readTemperatures(in_type, temperatures) <= 0)
LOG(VERBOSE) << __func__ << "Sensor Temperature read failure.";
}
if (out_temp != nullptr)
*out_temp = std::move(temperatures);
return ScopedAStatus::ok();
}
ScopedAStatus Thermal::getTemperatureThresholds(std::vector<TemperatureThreshold>* out_temp_thresh) {
std::vector<TemperatureThreshold> thresh;
if (!utils.isSensorInitialized())
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"ThermalHAL not initialized properly.");
if (utils.readTemperatureThreshold(thresh) <= 0)
LOG(VERBOSE) << __func__ << "Sensor Threshold read failure or type not supported.";
if (out_temp_thresh != nullptr)
*out_temp_thresh = std::move(thresh);
return ScopedAStatus::ok();
}
ScopedAStatus Thermal::getTemperatureThresholdsWithType(
TemperatureType in_type,
std::vector<TemperatureThreshold>* out_temp_thresh) {
std::vector<TemperatureThreshold> thresh;
if (!utils.isSensorInitialized())
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"ThermalHAL not initialized properly.");
else{
if (utils.readTemperatureThreshold(in_type, thresh) <= 0)
LOG(VERBOSE) << __func__ << "Sensor Threshold read failure or type not supported.";
}
if (out_temp_thresh != nullptr)
*out_temp_thresh = std::move(thresh);
return ScopedAStatus::ok();
}
ScopedAStatus Thermal::registerThermalChangedCallback(
const std::shared_ptr<IThermalChangedCallback>& in_callback) {
if (in_callback == nullptr) {
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"Invalid nullptr callback");
}
{
std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
TemperatureType in_type = TemperatureType::UNKNOWN;
for (CallbackSetting _cb: cb) {
if (interfacesEqual(_cb.callback, in_callback))
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"Callback already registered");
}
cb.emplace_back(in_callback, in_type);
LOG(DEBUG) << "A callback has been registered to ThermalHAL ";
}
return ScopedAStatus::ok();
}
ScopedAStatus Thermal::registerThermalChangedCallbackWithType(
const std::shared_ptr<IThermalChangedCallback>& in_callback, TemperatureType in_type) {
LOG(VERBOSE) << __func__ << " IThermalChangedCallback: " << in_callback
<< ", TemperatureType: " << static_cast<int32_t>(in_type);
if (in_callback == nullptr) {
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"Invalid nullptr callback");
}
if (in_type == TemperatureType::BCL_VOLTAGE ||
in_type == TemperatureType::BCL_CURRENT)
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"BCL current and voltage notification not supported");
{
std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
for (CallbackSetting _cb: cb) {
if (interfacesEqual(_cb.callback, in_callback))
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"Callback already registered");
}
cb.emplace_back(in_callback, in_type);
LOG(DEBUG) << "A callback has been registered to ThermalHAL Type: " << android::hardware::thermal::toString(in_type);
}
return ScopedAStatus::ok();
}
ScopedAStatus Thermal::unregisterThermalChangedCallback(
const std::shared_ptr<IThermalChangedCallback>& in_callback) {
if (in_callback == nullptr) {
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"Invalid nullptr callback");
}
std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
std::vector<CallbackSetting>::iterator it;
bool removed = false;
for (it = cb.begin(); it != cb.end(); it++) {
if (interfacesEqual(it->callback, in_callback)) {
cb.erase(it);
LOG(DEBUG) << "callback unregistered. isFilter: ";
removed = true;
break;
}
}
if (!removed) {
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"Callback wasn't registered");
}
LOG(DEBUG) << "A callback has been registered to ThermalHAL" ;
return ScopedAStatus::ok();
}
ScopedAStatus Thermal::registerCoolingDeviceChangedCallbackWithType(
const std::shared_ptr<ICoolingDeviceChangedCallback> &in_callback, CoolingType in_type)
{
if (in_callback == nullptr)
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"Invalid nullptr callback");
std::lock_guard<std::mutex> _lock(cdev_callback_mutex_);
for (CdevCallbackSetting _cb: cdev_cb) {
if (interfacesEqual(_cb.callback, in_callback))
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"Callback already registered");
}
cdev_cb.emplace_back(CdevCallbackSetting(in_callback, in_type));
LOG(DEBUG) << "CoolingDevice changed callback has been registered. Type: "<< android::hardware::thermal::toString(in_type);
return ScopedAStatus::ok();
}
ScopedAStatus Thermal::unregisterCoolingDeviceChangedCallback(
const std::shared_ptr<ICoolingDeviceChangedCallback> &in_callback) {
if (in_callback == nullptr)
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"Invalid nullptr callback");
std::lock_guard<std::mutex> _lock(cdev_callback_mutex_);
std::vector<CdevCallbackSetting>::iterator it;
bool removed = false;
for (auto it = cdev_cb.begin(); it != cdev_cb.end(); it++) {
if (interfacesEqual(it->callback, in_callback)) {
cdev_cb.erase(it);
removed = true;
break;
}
}
if (!removed) {
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
"CoolingDevice changed callback wasn't registered");
}
LOG(DEBUG) << "A CoolingDevice changed callback has been unregistered to CDEV" ;
return ScopedAStatus::ok();
}
void Thermal::sendCoolingDeviceChangeCB(const CoolingDevice &c)
{
std::lock_guard<std::mutex> _lock(cdev_callback_mutex_);
std::vector<CdevCallbackSetting>::iterator it;
LOG(DEBUG) << "Cooling device Name: " << c.name <<
" type: " << (int)c.type << " cur_level: " << c.value;
it = cdev_cb.begin();
while (it != cdev_cb.end()) {
if (it->type == c.type) {
::ndk::ScopedAStatus ret = it->callback->notifyCoolingDeviceChanged(c);
if (!ret.isOk()) {
LOG(ERROR) << "Notify CoolingDevice changed callback execution error. Removing"
<<ret.getMessage();
it = cdev_cb.erase(it);
continue;
}
}
it++;
}
}
void Thermal::sendThrottlingChangeCB(const Temperature &t)
{
std::lock_guard<std::mutex> _lock(thermal_callback_mutex_);
std::vector<CallbackSetting>::iterator it;
LOG(DEBUG) << "Throttle Severity change: " << " Type: " << (int)t.type
<< " Name: " << t.name << " Value: " << t.value <<
" ThrottlingStatus: " << (int)t.throttlingStatus;
it = cb.begin();
while (it != cb.end()) {
if (it->type == t.type || it->type == TemperatureType::UNKNOWN) {
::ndk::ScopedAStatus ret = it->callback->notifyThrottling(t);
if (!ret.isOk()) {
LOG(ERROR) << "Notify callback execution error. Removing"<<ret.getMessage();
it = cb.erase(it);
continue;
}
}
it++;
}
}
} // namespace aidl::android::hardware::thermal

View File

@@ -0,0 +1,130 @@
/*
* Copyright (c) 2020, 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.
*/
/* Changes from Qualcomm Innovation Center are provided under the following license:
Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear */
#ifndef ANDROID_QTI_VENDOR_THERMAL_H
#define ANDROID_QTI_VENDOR_THERMAL_H
#include <mutex>
#include <thread>
#include <set>
#include <aidl/android/hardware/thermal/BnThermal.h>
#include <aidl/android/hardware/thermal/IThermalChangedCallback.h>
#include <aidl/android/hardware/thermal/ICoolingDeviceChangedCallback.h>
#ifdef ENABLE_THERMAL_NETLINK
#include "thermalUtilsNetlink.h"
#else
#include "thermalUtils.h"
#endif
#include "thermalData.h"
namespace aidl {
namespace android {
namespace hardware {
namespace thermal {
struct CallbackSetting {
std::shared_ptr<IThermalChangedCallback> callback;
TemperatureType type;
CallbackSetting(std::shared_ptr<IThermalChangedCallback> callback,
TemperatureType type)
: callback(callback), type(type) {}
};
struct CdevCallbackSetting {
std::shared_ptr<ICoolingDeviceChangedCallback> callback;
CoolingType type;
CdevCallbackSetting(std::shared_ptr<ICoolingDeviceChangedCallback> callback,
CoolingType type)
: callback(callback), type(type) {}
};
class Thermal : public BnThermal {
public:
Thermal();
~Thermal() = default;
Thermal(const Thermal &) = delete;
void operator=(const Thermal &) = delete;
ndk::ScopedAStatus getCoolingDevices(std::vector<CoolingDevice>* out_devices) override;
ndk::ScopedAStatus getCoolingDevicesWithType(CoolingType in_type,
std::vector<CoolingDevice>* out_devices) override;
ndk::ScopedAStatus getTemperatures(std::vector<Temperature>* out_temperatures) override;
ndk::ScopedAStatus getTemperaturesWithType(TemperatureType in_type,
std::vector<Temperature>* out_temperatures) override;
ndk::ScopedAStatus getTemperatureThresholds(
std::vector<TemperatureThreshold>* out_temperatureThresholds) override;
ndk::ScopedAStatus getTemperatureThresholdsWithType(
TemperatureType in_type,
std::vector<TemperatureThreshold>* out_temperatureThresholds) override;
ndk::ScopedAStatus registerThermalChangedCallback(
const std::shared_ptr<IThermalChangedCallback>& in_callback) override;
ndk::ScopedAStatus registerThermalChangedCallbackWithType(
const std::shared_ptr<IThermalChangedCallback>& in_callback,
TemperatureType in_type) override;
ndk::ScopedAStatus registerCoolingDeviceChangedCallbackWithType(
const std::shared_ptr<ICoolingDeviceChangedCallback> &in_callback,
CoolingType in_type) override;
ndk::ScopedAStatus unregisterThermalChangedCallback(
const std::shared_ptr<IThermalChangedCallback>& in_callback) override;
ndk::ScopedAStatus unregisterCoolingDeviceChangedCallback(
const std::shared_ptr<ICoolingDeviceChangedCallback> &in_callback) override;
void sendThrottlingChangeCB(const Temperature &t);
void sendCoolingDeviceChangeCB(const CoolingDevice &c);
private:
std::mutex thermal_callback_mutex_;
std::mutex cdev_callback_mutex_;
std::vector<CallbackSetting> cb;
std::vector<CdevCallbackSetting> cdev_cb;
ThermalUtils utils;
};
} // namespace thermal
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // ANDROID_QTI_VENDOR_THERMAL_H

View File

@@ -0,0 +1,642 @@
/*
* Copyright (c) 2020, 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.
*/
/* Changes from Qualcomm Innovation Center are provided under the following license:
Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear */
#include <cstdio>
#include <cinttypes>
#include <string>
#include <dirent.h>
#include <unordered_map>
#include <fstream>
#include <android-base/logging.h>
#include "thermalCommon.h"
#define MAX_LENGTH 50
#define MAX_PATH (256)
#define DEFAULT_HYSTERESIS 5
#define DEFAULT_SKIN_HYSTERESIS 2
#define THERMAL_SYSFS "/sys/class/thermal/"
#define TZ_DIR_NAME "thermal_zone"
#define TZ_DIR_FMT "thermal_zone%d"
#define TEMPERATURE_FILE_FORMAT "/sys/class/thermal/thermal_zone%d/temp"
#define POLICY_FILE_FORMAT "/sys/class/thermal/thermal_zone%d/policy"
#define TRIP_FILE_FORMAT "/sys/class/thermal/thermal_zone%d/trip_point_1_temp"
#define HYST_FILE_FORMAT "/sys/class/thermal/thermal_zone%d/trip_point_1_hyst"
#define TRIP_TYPE_FILE_FORMAT "/sys/class/thermal/thermal_zone%d/trip_point_%d_type"
#define TRIP_N_FILE_FORMAT "/sys/class/thermal/thermal_zone%d/trip_point_%d_temp"
#define USER_SPACE_POLICY "user_space"
#define TZ_TYPE "type"
#define CDEV_DIR_NAME "cooling_device"
#define CDEV_DIR_FMT "cooling_device%d"
#define CDEV_CUR_STATE_PATH "/sys/class/thermal/cooling_device%d/cur_state"
#define CPU_USAGE_FILE "/proc/stat"
#define CPU_ONLINE_FILE_FORMAT "/sys/devices/system/cpu/cpu%d/online"
#define LIMIT_PROFILE_1_SD_TEMP 125000
#define LIMIT_PROFILE_TRIP_TYPE "hot"
#define LIMIT_PROFILE_SD_TZ "aoss-0"
#define LIMIT_PROFILE_TRIP_MAX 11
namespace aidl {
namespace android {
namespace hardware {
namespace thermal {
static std::unordered_map<std::string, cdevType> cdev_map = {
{"thermal-cpufreq-0", cdevType::CPU},
{"thermal-cpufreq-1", cdevType::CPU},
{"thermal-cpufreq-2", cdevType::CPU},
{"thermal-cpufreq-3", cdevType::CPU},
{"thermal-cpufreq-4", cdevType::CPU},
{"thermal-cpufreq-5", cdevType::CPU},
{"thermal-cpufreq-6", cdevType::CPU},
{"thermal-cpufreq-7", cdevType::CPU},
{"cpufreq-cpu0", cdevType::CPU},
{"cpufreq-cpu1", cdevType::CPU},
{"cpufreq-cpu2", cdevType::CPU},
{"cpufreq-cpu3", cdevType::CPU},
{"cpufreq-cpu4", cdevType::CPU},
{"cpufreq-cpu5", cdevType::CPU},
{"cpufreq-cpu6", cdevType::CPU},
{"cpufreq-cpu7", cdevType::CPU},
{"thermal-cluster-4-7", cdevType::CPU},
{"thermal-cluster-3-7", cdevType::CPU},
{"cpu-isolate0", cdevType::CPU},
{"cpu-isolate1", cdevType::CPU},
{"cpu-isolate2", cdevType::CPU},
{"cpu-isolate3", cdevType::CPU},
{"cpu-isolate4", cdevType::CPU},
{"cpu-isolate5", cdevType::CPU},
{"cpu-isolate6", cdevType::CPU},
{"cpu-isolate7", cdevType::CPU},
{"thermal-pause-1", cdevType::CPU},
{"thermal-pause-2", cdevType::CPU},
{"thermal-pause-4", cdevType::CPU},
{"thermal-pause-8", cdevType::CPU},
{"thermal-pause-10", cdevType::CPU},
{"thermal-pause-20", cdevType::CPU},
{"thermal-pause-40", cdevType::CPU},
{"thermal-pause-80", cdevType::CPU},
{"thermal-devfreq-0", cdevType::GPU},
{"devfreq-3d00000.qcom,kgsl-3d0", cdevType::GPU},
{"gpu", cdevType::GPU},
{"modem_tj", cdevType::MODEM},
{"modem_lte_dsc", cdevType::MODEM},
{"modem_nr_dsc", cdevType::MODEM},
{"modem_nr_scg_dsc", cdevType::MODEM},
{"cdsp", cdevType::NPU},
{"cdsp_hw", cdevType::NPU},
{"battery", cdevType::BATTERY},
{"fan-max31760", cdevType::FAN},
{"display-fps", cdevType::DISPLAY},
};
ThermalCommon::ThermalCommon()
{
LOG(DEBUG) << "Entering " << __func__;
ncpus = (int)sysconf(_SC_NPROCESSORS_CONF);
if (ncpus < 1)
LOG(ERROR) << "Error retrieving number of cores";
}
static int writeToFile(std::string_view path, std::string data)
{
std::fstream outFile;
outFile.open(std::string(path).c_str(),
std::fstream::binary | std::fstream::out);
if (outFile.is_open()) {
LOG(DEBUG) << "writing: "<< data << " in path:" << path
<< std::endl;
outFile << data;
outFile.close();
return data.length();
}
LOG(ERROR) << "Error opening file: "<< path << std::endl;
return -1;
}
static int readLineFromFile(std::string_view path, std::string& out)
{
char *fgets_ret;
FILE *fd;
int rv;
char buf[MAX_LENGTH];
out.clear();
fd = fopen(std::string(path).c_str(), "r");
if (fd == NULL) {
LOG(ERROR) << "Path:" << std::string(path) << " file open error.err:"
<< strerror(errno) << std::endl;
return -errno;
}
fgets_ret = fgets(buf, MAX_LENGTH, fd);
if (NULL != fgets_ret) {
rv = (int)strlen(buf);
out.append(buf, rv);
} else {
rv = ferror(fd);
}
fclose(fd);
out.erase(std::remove(out.begin(), out.end(), '\n'), out.end());
LOG(DEBUG) << "Path:" << std::string(path) << " Val:" << out << std::endl;
return rv;
}
int ThermalCommon::readFromFile(std::string_view path, std::string& out)
{
return readLineFromFile(path, out);
}
static int get_tzn(std::string sensor_name)
{
DIR *tdir = NULL;
struct dirent *tdirent = NULL;
int found = -1;
int tzn = 0;
char name[MAX_PATH] = {0};
char cwd[MAX_PATH] = {0};
int ret = 0;
if (!getcwd(cwd, sizeof(cwd)))
return found;
/* Change dir to read the entries. Doesnt work otherwise */
ret = chdir(THERMAL_SYSFS);
if (ret) {
LOG(ERROR) << "Unable to change to " << THERMAL_SYSFS << std::endl;
return found;
}
tdir = opendir(THERMAL_SYSFS);
if (!tdir) {
LOG(ERROR) << "Unable to open " << THERMAL_SYSFS << std::endl;
return found;
}
while ((tdirent = readdir(tdir))) {
std::string buf;
if (strncmp(tdirent->d_name, TZ_DIR_NAME,
strlen(TZ_DIR_NAME)) != 0)
continue;
snprintf(name, MAX_PATH, "%s%s/%s", THERMAL_SYSFS,
tdirent->d_name, TZ_TYPE);
ret = readLineFromFile(std::string_view(name), buf);
if (ret <= 0) {
LOG(ERROR) <<
"get_tzn: sensor name read error for tz:" <<
tdirent->d_name << std::endl;
continue;
}
if (!strncmp(buf.c_str(), sensor_name.c_str(),
sensor_name.length())) {
found = 1;
break;
}
}
if (found == 1) {
sscanf(tdirent->d_name, TZ_DIR_FMT, &tzn);
LOG(DEBUG) << "Sensor: " << sensor_name <<
" found at tz: " << tzn << std::endl;
found = tzn;
}
closedir(tdir);
/* Restore current working dir */
ret = chdir(cwd);
return found;
}
int ThermalCommon::initialize_sensor(struct target_therm_cfg& cfg, int sens_idx)
{
struct therm_sensor sensor;
int idx = 0;
sensor.tzn = get_tzn(cfg.sensor_list[sens_idx]);
if (sensor.tzn < 0) {
LOG(ERROR) << "No thermal zone for sensor: " <<
cfg.sensor_list[sens_idx] << ", ret:" <<
sensor.tzn << std::endl;
return -1;
}
if (cfg.type == TemperatureType::CPU)
sensor.thresh.name = sensor.t.name =
std::string("CPU") + std::to_string(sens_idx);
else
sensor.thresh.name = sensor.t.name = cfg.label;
if (cfg.type == TemperatureType::BCL_PERCENTAGE)
sensor.mulFactor = 1;
else
sensor.mulFactor = 1000;
sensor.sensor_name = cfg.sensor_list[sens_idx];
sensor.positiveThresh = cfg.positive_thresh_ramp;
sensor.no_trip_set = cfg.no_trip_set;
sensor.lastThrottleStatus = sensor.t.throttlingStatus =
ThrottlingSeverity::NONE;
sensor.thresh.type = sensor.t.type = cfg.type;
for (idx = 0; idx <= (size_t)ThrottlingSeverity::SHUTDOWN; idx++) {
sensor.thresh.hotThrottlingThresholds.push_back(UNKNOWN_TEMPERATURE);
sensor.thresh.coldThrottlingThresholds.push_back(UNKNOWN_TEMPERATURE);
}
for (idx = 0; idx <= (size_t)ThrottlingSeverity::SHUTDOWN; idx++) {
if (cfg.thresh[idx] != 0 && cfg.positive_thresh_ramp)
sensor.thresh.hotThrottlingThresholds[idx] =
cfg.thresh[idx] / (float)sensor.mulFactor;
else if (cfg.thresh[idx] != 0 && !cfg.positive_thresh_ramp)
sensor.thresh.coldThrottlingThresholds[idx] =
cfg.thresh[idx] / (float)sensor.mulFactor;
}
sens.push_back(sensor);
return 0;
}
int ThermalCommon::initializeCpuSensor(struct target_therm_cfg& cpu_cfg)
{
int cpu = 0;
for (;cpu < ncpus; cpu++) {
if (initialize_sensor(cpu_cfg, cpu) < 0)
return -1;
}
return 0;
}
int ThermalCommon::initThermalZones(std::vector<struct target_therm_cfg>& cfg)
{
std::vector<struct target_therm_cfg>::iterator it;
if (cfg.empty()) {
LOG(ERROR) << std::string(__func__) +":Invalid input";
return -1;
}
for (it = cfg.begin(); it != cfg.end(); it++)
{
if (it->type == TemperatureType::CPU) {
if (initializeCpuSensor(*it) < 0)
return -1;
continue;
}
if (initialize_sensor(*it, 0) < 0) {
return -1;
}
}
return sens.size();
}
int ThermalCommon::initCdev()
{
DIR *tdir = NULL;
struct dirent *tdirent = NULL;
int cdevn = 0;
char name[MAX_PATH] = {0};
char cwd[MAX_PATH] = {0};
int ret = 0;
if (!getcwd(cwd, sizeof(cwd)))
return 0;
/* Change dir to read the entries. Doesnt work otherwise */
ret = chdir(THERMAL_SYSFS);
if (ret) {
LOG(ERROR) << "Unable to change to " << THERMAL_SYSFS << std::endl;
return 0;
}
tdir = opendir(THERMAL_SYSFS);
if (!tdir) {
LOG(ERROR) << "Unable to open " << THERMAL_SYSFS << std::endl;
return 0;
}
while ((tdirent = readdir(tdir))) {
std::string buf;
struct dirent *tzdirent;
std::unordered_map<std::string, cdevType>::iterator it;
struct therm_cdev cdevInst;
if (strncmp(tdirent->d_name, CDEV_DIR_NAME,
strlen(CDEV_DIR_NAME)) != 0)
continue;
snprintf(name, MAX_PATH, "%s%s/%s", THERMAL_SYSFS,
tdirent->d_name, TZ_TYPE);
ret = readLineFromFile(std::string_view(name), buf);
if (ret <= 0) {
LOG(ERROR) <<
"init_cdev: cdev type read error for cdev:" <<
tdirent->d_name << std::endl;
}
it = cdev_map.find(buf);
if (it == cdev_map.end())
continue;
sscanf(tdirent->d_name, CDEV_DIR_FMT, &cdevn);
LOG(DEBUG) << "cdev: " << it->first <<
" found at cdev number: " << cdevn << std::endl;
cdevInst.c.name = it->first;
cdevInst.c.type = it->second;
cdevInst.cdevn = cdevn;
read_cdev_state(cdevInst);
cdev.push_back(cdevInst);
}
closedir(tdir);
/* Restore current working dir */
ret = chdir(cwd);
return cdev.size();
}
int ThermalCommon::read_cdev_state(struct therm_cdev& cdev)
{
char file_name[MAX_PATH];
std::string buf;
int ret = 0, ct = 0;
bool read_ok = false;
snprintf(file_name, sizeof(file_name), CDEV_CUR_STATE_PATH,
cdev.cdevn);
do {
ret = readLineFromFile(std::string(file_name), buf);
if (ret <= 0) {
LOG(ERROR) << "Cdev state read error:"<< ret <<
" for cdev: " << cdev.c.name;
return -1;
}
try {
cdev.c.value = std::stoi(buf, nullptr, 0);
read_ok = true;
}
catch (std::exception &err) {
LOG(ERROR) << "Cdev read stoi error:" << err.what()
<< " cdev:" << cdev.c.name << " ID:"
<< cdev.cdevn << " buf:" << buf <<
std::endl;
}
ct++;
} while (!read_ok && ct < RETRY_CT);
LOG(DEBUG) << "cdev Name:" << cdev.c.name << ". state:" <<
cdev.c.value << std::endl;
return cdev.c.value;
}
int ThermalCommon::estimateSeverity(struct therm_sensor& sensor)
{
int idx = 0;
ThrottlingSeverity severity = ThrottlingSeverity::NONE;
float temp = sensor.t.value;
int hysteresis = (sensor.thresh.type == TemperatureType::SKIN) ?
DEFAULT_SKIN_HYSTERESIS : DEFAULT_HYSTERESIS;
for (idx = (int)ThrottlingSeverity::SHUTDOWN; idx >= 0; idx--) {
/* If a particular threshold is hit already, check if the
* hysteresis is cleared before changing the severity */
if (idx <= (int)sensor.t.throttlingStatus) {
if ((sensor.positiveThresh &&
!isnan(sensor.thresh.hotThrottlingThresholds[idx]) &&
temp >=
(sensor.thresh.hotThrottlingThresholds[idx] - hysteresis)) ||
(!sensor.positiveThresh &&
!isnan(sensor.thresh.coldThrottlingThresholds[idx]) &&
temp <=
(sensor.thresh.coldThrottlingThresholds[idx] + hysteresis)))
break;
continue;
}
if ((sensor.positiveThresh &&
!isnan(sensor.thresh.hotThrottlingThresholds[idx]) &&
temp >=
sensor.thresh.hotThrottlingThresholds[idx]) ||
(!sensor.positiveThresh &&
!isnan(sensor.thresh.coldThrottlingThresholds[idx]) &&
temp <=
sensor.thresh.coldThrottlingThresholds[idx]))
break;
}
if (idx >= 0)
severity = (ThrottlingSeverity)(idx);
LOG(DEBUG) << "Sensor Name:" << sensor.t.name << "temp: " <<
temp << ". prev severity:" <<
(int)sensor.lastThrottleStatus << ". cur severity:" <<
(int)sensor.t.throttlingStatus << " New severity:" <<
(int)severity << std::endl;
if (severity == sensor.t.throttlingStatus)
return -1;
sensor.lastThrottleStatus = sensor.t.throttlingStatus;
sensor.t.throttlingStatus = severity;
return (int)severity;
}
int ThermalCommon::read_temperature(struct therm_sensor& sensor)
{
char file_name[MAX_PATH];
float temp;
std::string buf;
int ret = 0, ct = 0;
bool read_ok = false;
do {
snprintf(file_name, sizeof(file_name), TEMPERATURE_FILE_FORMAT,
sensor.tzn);
ret = readLineFromFile(std::string(file_name), buf);
if (ret <= 0) {
LOG(ERROR) << "Temperature read error:"<< ret <<
" for sensor " << sensor.t.name;
return -1;
}
try {
sensor.t.value = (float)std::stoi(buf, nullptr, 0) /
(float)sensor.mulFactor;
read_ok = true;
}
catch (std::exception &err) {
LOG(ERROR) << "Temperature buf stoi error: "
<< err.what()
<< " buf:" << buf << " sensor:"
<< sensor.t.name << " TZ:" <<
sensor.tzn << std::endl;
}
ct++;
} while (!read_ok && ct < RETRY_CT);
LOG(DEBUG) << "Sensor Name:" << sensor.t.name << ". Temperature:" <<
(float)sensor.t.value << std::endl;
return ret;
}
void ThermalCommon::initThreshold(struct therm_sensor& sensor)
{
char file_name[MAX_PATH] = "";
std::string buf;
int ret = 0, idx;
ThrottlingSeverity severity = ThrottlingSeverity::NONE;
int next_trip, curr_trip, hyst_temp = 0;
int hysteresis = (sensor.thresh.type == TemperatureType::SKIN) ?
DEFAULT_SKIN_HYSTERESIS : DEFAULT_HYSTERESIS;
LOG(DEBUG) << "Entering " <<__func__;
if (!sensor.positiveThresh) {
LOG(ERROR) << "negative temperature ramp for sensor:"<<
sensor.t.name;
return;
}
#ifndef ENABLE_THERMAL_NETLINK
snprintf(file_name, sizeof(file_name), POLICY_FILE_FORMAT,
sensor.tzn);
ret = readLineFromFile(std::string(file_name), buf);
if (ret <= 0) {
LOG(ERROR) << "Policy read error:"<< ret <<
" for sensor " << sensor.t.name;
return;
}
if (buf != std::string(USER_SPACE_POLICY)) {
LOG(ERROR) << "Policy error:"<< buf << " sensor:" <<
sensor.t.name << std::endl;
return;
}
#endif
next_trip = UNKNOWN_TEMPERATURE;
for (idx = 0;idx <= (int)ThrottlingSeverity::SHUTDOWN; idx++) {
if (isnan(sensor.thresh.hotThrottlingThresholds[idx])
|| idx <= (int)sensor.t.throttlingStatus)
continue;
next_trip = sensor.thresh.hotThrottlingThresholds[idx] *
sensor.mulFactor;
break;
}
if (!isnan(next_trip)) {
LOG(DEBUG) << "Sensor: " << sensor.t.name << " high trip:"
<< next_trip << std::endl;
snprintf(file_name, sizeof(file_name), TRIP_FILE_FORMAT,
sensor.tzn);
writeToFile(std::string_view(file_name), std::to_string(next_trip));
}
if (sensor.t.throttlingStatus != ThrottlingSeverity::NONE) {
curr_trip = sensor.thresh.hotThrottlingThresholds[
(int)sensor.t.throttlingStatus]
* sensor.mulFactor;
if (!isnan(next_trip))
hyst_temp = (next_trip - curr_trip) + (hysteresis *
sensor.mulFactor);
else
hyst_temp = hysteresis * sensor.mulFactor;
LOG(DEBUG) << "Sensor: " << sensor.t.name << " hysteresis:"
<< hyst_temp << std::endl;
snprintf(file_name, sizeof(file_name), HYST_FILE_FORMAT,
sensor.tzn);
writeToFile(std::string_view(file_name), std::to_string(hyst_temp));
}
return;
}
int ThermalCommon::findLimitProfile(void)
{
char file_name[MAX_PATH];
std::string buf;
int trip = 1, lp = -1;
int ct = 0, ret = 0;
bool read_ok = false;
int tzn = get_tzn(LIMIT_PROFILE_SD_TZ);
if (tzn < 0) {
LOG(ERROR) <<" Not able to get tz id for "
<< LIMIT_PROFILE_SD_TZ << std::endl;
return -1;
}
do {
snprintf(file_name, sizeof(file_name), TRIP_TYPE_FILE_FORMAT,
tzn, trip);
ret = readFromFile(std::string_view(file_name), buf);
if (ret <= 0) {
LOG(ERROR) <<" Not able to read trip type trip: "
<< trip << std::endl;
return -1;
}
if (strncmp(buf.c_str(), LIMIT_PROFILE_TRIP_TYPE,
strlen(LIMIT_PROFILE_TRIP_TYPE))) {
trip++;
if (trip > LIMIT_PROFILE_TRIP_MAX)
return -1;
continue;
}
snprintf(file_name, sizeof(file_name), TRIP_N_FILE_FORMAT,
tzn, trip);
do {
ret = readFromFile(std::string_view(file_name), buf);
if (ret <= 0) {
LOG(ERROR) <<" Not able to read trip temp, id: "
<< trip << std::endl;
return -1;
}
try {
lp = std::stoi(buf, nullptr, 0);
read_ok = true;
}
catch (std::exception &err) {
LOG(ERROR) <<"limits profile stoi err:"
<< err.what() << " buf:" << buf;
}
ct++;
} while (!read_ok && ct < RETRY_CT);
lp = lp == LIMIT_PROFILE_1_SD_TEMP ? 1 : 0;
break;
} while (1);
return lp;
}
}// namespace thermal
}// namespace hardware
}// namespace android
}// namespace aidl

View File

@@ -0,0 +1,81 @@
/*
* Copyright (c) 2020, 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.
*/
#ifndef THERMAL_THERMAL_COMMON_H__
#define THERMAL_THERMAL_COMMON_H__
#include "thermalData.h"
namespace aidl {
namespace android {
namespace hardware {
namespace thermal {
#define RETRY_CT 3
class ThermalCommon {
public:
ThermalCommon();
~ThermalCommon() = default;
int readFromFile(std::string_view path, std::string& out);
int initThermalZones(std::vector<struct target_therm_cfg>& cfg);
void initThreshold(struct therm_sensor& sens);
int initCdev();
int read_cdev_state(struct therm_cdev& cdev);
int read_temperature(struct therm_sensor& sensor);
int estimateSeverity(struct therm_sensor& sensor);
int findLimitProfile(void);
std::vector<struct therm_sensor> fetch_sensor_list()
{
return sens;
};
std::vector<struct therm_cdev> fetch_cdev_list()
{
return cdev;
};
private:
int ncpus;
std::vector<struct target_therm_cfg> cfg;
std::vector<struct therm_sensor> sens;
std::vector<struct therm_cdev> cdev;
int initializeCpuSensor(struct target_therm_cfg& cpu_cfg);
int initialize_sensor(struct target_therm_cfg& cfg,
int sens_idx);
};
} // namespace thermal
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // THERMAL_THERMAL_COMMON_H__

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,72 @@
/*
* Copyright (c) 2020, 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.
*/
/* Changes from Qualcomm Innovation Center are provided under the following license:
Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear */
#ifndef THERMAL_THERMAL_CONFIG_H__
#define THERMAL_THERMAL_CONFIG_H__
#include <aidl/android/hardware/thermal/BnThermal.h>
#include "thermalData.h"
#include "thermalCommon.h"
namespace aidl {
namespace android {
namespace hardware {
namespace thermal {
class ThermalConfig {
public:
ThermalConfig();
~ThermalConfig() = default;
std::vector<struct target_therm_cfg> fetchConfig(void)
{
return thermalConfig;
}
private:
std::vector<struct target_therm_cfg> thermalConfig;
int soc_id;
std::string hw_platform;
int limitp;
ThermalCommon cmnInst;
};
} // namespace thermal
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // THERMAL_THERMAL_CONFIG_H__

View File

@@ -0,0 +1,104 @@
/*
* Copyright (c) 2020, 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.
*/
/* Changes from Qualcomm Innovation Center are provided under the following license:
Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear */
#ifndef THERMAL_THERMAL_DATA_H__
#define THERMAL_THERMAL_DATA_H__
#include <vector>
#include <string>
#include <mutex>
#include <cmath>
#include <aidl/android/hardware/thermal/BnThermal.h>
#define UNKNOWN_TEMPERATURE (NAN)
namespace aidl{
namespace android {
namespace hardware {
namespace thermal {
using CoolingDevice = ::aidl::android::hardware::thermal::CoolingDevice;
using Temperature = ::aidl::android::hardware::thermal::Temperature;
using TemperatureType = ::aidl::android::hardware::thermal::TemperatureType;
using cdevType = ::aidl::android::hardware::thermal::CoolingType;
using CoolingDevice = ::aidl::android::hardware::thermal::CoolingDevice;
using Temperature = ::aidl::android::hardware::thermal::Temperature;
using TemperatureType = ::aidl::android::hardware::thermal::TemperatureType;
using TemperatureThreshold =
::aidl::android::hardware::thermal::TemperatureThreshold;
using ::aidl::android::hardware::thermal::ThrottlingSeverity;
enum QthrottlingSeverity {
NONE = (size_t)ThrottlingSeverity::NONE,
LIGHT = (size_t)ThrottlingSeverity::LIGHT,
MODERATE = (size_t)ThrottlingSeverity::MODERATE,
SEVERE = (size_t)ThrottlingSeverity::SEVERE,
CRITICAL = (size_t)ThrottlingSeverity::CRITICAL,
EMERGENCY = (size_t)ThrottlingSeverity::EMERGENCY,
SHUTDOWN = (size_t)ThrottlingSeverity::SHUTDOWN,
};
struct target_therm_cfg {
TemperatureType type;
std::vector<std::string> sensor_list;
std::string label;
int thresh[SHUTDOWN + 1];
bool positive_thresh_ramp;
bool no_trip_set = false;
};
struct therm_sensor {
int tzn;
int mulFactor;
bool positiveThresh;
std::string sensor_name;
ThrottlingSeverity lastThrottleStatus;
Temperature t;
TemperatureThreshold thresh;
bool no_trip_set;
};
struct therm_cdev {
int cdevn;
CoolingDevice c;
};
} // namespace thermal
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // THERMAL_THERMAL_DATA_H__

View File

@@ -0,0 +1,195 @@
/*
* Copyright (c) 2020,2023, 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.
*/
/* Changes from Qualcomm Innovation Center are provided under the following license:
Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear */
#include <unistd.h>
#include <poll.h>
#include <sys/socket.h>
#include <linux/types.h>
#include <linux/netlink.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include "thermalMonitor.h"
#define UEVENT_BUF 1024
#define HYST_FMT "change@/devices/virtual/thermal/thermal_zone%d\n\
ACTION=change\n\
DEVPATH=/devices/virtual/thermal/thermal_zone%d\n\
SUBSYSTEM=thermal\n\
NAME=%s\n\
TEMP=%d\n\
HYST=%d\n\
EVENT=%d\n"\
#define TRIP_FMT "change@/devices/virtual/thermal/thermal_zone%d\n\
ACTION=change\n\
DEVPATH=/devices/virtual/thermal/thermal_zone%d\n\
SUBSYSTEM=thermal\n\
NAME=%s\n\
TEMP=%d\n\
TRIP=%d\n\
EVENT=%d\n"\
namespace aidl {
namespace android {
namespace hardware {
namespace thermal {
using parseCB = std::function<void(char *inp_buf, ssize_t len)>;
using pollCB = std::function<bool()>;
void thermal_monitor_uevent(const parseCB &parse_cb, const pollCB &stopPollCB)
{
struct pollfd pfd;
char buf[UEVENT_BUF] = {0};
int sz = 64*1024;
struct sockaddr_nl nls;
memset(&nls, 0, sizeof(nls));
nls.nl_family = AF_NETLINK;
nls.nl_pid = getpid();
nls.nl_groups = 0xffffffff;
pfd.events = POLLIN;
pfd.fd = socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC,
NETLINK_KOBJECT_UEVENT);
if (pfd.fd < 0) {
LOG(ERROR) << "socket creation error:" << errno << std::endl;
return;
}
LOG(DEBUG) << "socket creation success" << std::endl;
setsockopt(pfd.fd, SOL_SOCKET, SO_RCVBUF, &sz, sizeof(sz));
if (bind(pfd.fd, (struct sockaddr *)&nls, sizeof(nls)) < 0) {
close(pfd.fd);
LOG(ERROR) << "socket bind failed:" << errno << std::endl;
return;
}
LOG(DEBUG) << "Listening for uevent" << std::endl;
while (!stopPollCB()) {
ssize_t len;
int err;
err = poll(&pfd, 1, -1);
if (err == -1) {
LOG(ERROR) << "Error in uevent poll.";
break;
}
if (stopPollCB()) {
LOG(INFO) << "Exiting uevent monitor" << std::endl;
return;
}
len = recv(pfd.fd, buf, sizeof(buf) - 1, MSG_DONTWAIT);
if (len == -1) {
LOG(ERROR) << "uevent read failed:" << errno << std::endl;
continue;
}
buf[len] = '\0';
parse_cb(buf, len);
}
return;
}
ThermalMonitor::ThermalMonitor(const ueventMonitorCB &inp_cb):
cb(inp_cb)
{
monitor_shutdown = false;
}
ThermalMonitor::~ThermalMonitor()
{
monitor_shutdown = true;
th.join();
}
void ThermalMonitor::start()
{
th = std::thread(thermal_monitor_uevent,
std::bind(&ThermalMonitor::parse_and_notify, this,
std::placeholders::_1, std::placeholders::_2),
std::bind(&ThermalMonitor::stopPolling, this));
}
void ThermalMonitor::parse_and_notify(char *inp_buf, ssize_t len)
{
int zone_num, temp, trip, ret = 0, event;
ssize_t i = 0;
char sensor_name[30] = "", buf[UEVENT_BUF] = {0};
LOG(DEBUG) << "monitor received thermal uevent: " << inp_buf
<< std::endl;
while (i < len) {
if (i >= UEVENT_BUF)
return;
ret = snprintf(buf + i, UEVENT_BUF - i, "%s ", inp_buf + i);
if (ret == (strlen(inp_buf + i) + 1))
i += ret;
else
return;
}
if (!strstr(buf, "SUBSYSTEM=thermal"))
return;
if (strstr(buf, "TRIP=")) {
ret = sscanf(buf, TRIP_FMT, &zone_num, &zone_num, sensor_name,
&temp, &trip, &event);
LOG(DEBUG) << "zone:" << zone_num << " sensor:" << sensor_name
<<" temp:" << temp << " trip:" << trip << " event:" <<
event << std::endl;
} else {
ret = sscanf(buf, HYST_FMT, &zone_num, &zone_num, sensor_name,
&temp, &trip, &event);
LOG(DEBUG) << "zone:" << zone_num << " sensor:" << sensor_name
<<" temp:" << temp << " trip:" << trip << " event:" <<
event << std::endl;
}
if (ret <= 0 || ret == EOF) {
LOG(ERROR) << "read error:" << ret <<". buf:" << buf << std::endl;
return;
}
cb(sensor_name, temp);
}
} // namespace thermal
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 2020, 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.
*/
/* Changes from Qualcomm Innovation Center are provided under the following license:
Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear */
#ifndef THERMAL_THERMAL_MONITOR_H__
#define THERMAL_THERMAL_MONITOR_H__
#include <thread>
#include <aidl/android/hardware/thermal/BnThermal.h>
namespace aidl {
namespace android {
namespace hardware {
namespace thermal {
using ueventMonitorCB = std::function<void(std::string sensor_name, int temp)>;
class ThermalMonitor {
public:
ThermalMonitor(const ueventMonitorCB &inp_cb);
~ThermalMonitor();
void parse_and_notify(char *inp_buf, ssize_t len);
bool stopPolling()
{
return monitor_shutdown;
}
void start();
private:
std::thread th;
bool monitor_shutdown;
ueventMonitorCB cb;
};
} // namespace thermal
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // THERMAL_THERMAL_MONITOR_H__

View File

@@ -0,0 +1,324 @@
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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.
*/
/* Changes from Qualcomm Innovation Center are provided under the following license:
Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear */
#include <unistd.h>
#include <linux/thermal.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include "thermalMonitorNetlink.h"
namespace aidl {
namespace android {
namespace hardware {
namespace thermal {
using pollCB = std::function<bool()>;
using familyCB = std::function<int(struct nl_msg *, void *)>;
void thermal_listen(struct nl_sock *soc, const pollCB &stopCB)
{
while (!stopCB())
nl_recvmsgs_default(soc);
LOG(INFO) << "thermal_listen_event Exit" << std::endl;
return;
}
int thermal_event_cb(struct nl_msg *n, void *data)
{
ThermalMonitor *t = (ThermalMonitor *)data;
return t->event_parse(n, NULL);
}
int thermal_sample_cb(struct nl_msg *n, void *data)
{
ThermalMonitor *t = (ThermalMonitor *)data;
return t->sample_parse(n, NULL);
}
int thermal_family_cb(struct nl_msg *n, void *data)
{
ThermalMonitor *t = (ThermalMonitor *)data;
return t->family_msg_cb(n, NULL);
}
ThermalMonitor::ThermalMonitor(const eventMonitorCB &inp_event_cb,
const eventMonitorCB &inp_sample_cb,
const eventCreateMonitorCB &inp_event_create_cb,
const eventMonitorCB &inp_event_cdev_cb):
event_group(-1),
sample_group(-1),
event_cb(inp_event_cb),
sample_cb(inp_sample_cb),
event_create_cb(inp_event_create_cb),
cdev_cb(inp_event_cdev_cb)
{
monitor_shutdown = false;
}
ThermalMonitor::~ThermalMonitor()
{
monitor_shutdown = true;
event_th.join();
sample_th.join();
if (sample_soc)
nl_socket_free(sample_soc);
if (event_soc)
nl_socket_free(event_soc);
}
int ThermalMonitor::event_parse(struct nl_msg *n, void *data)
{
struct nlmsghdr *nl_hdr = nlmsg_hdr(n);
struct genlmsghdr *hdr = genlmsg_hdr(nl_hdr);
struct nlattr *attrs[THERMAL_GENL_ATTR_MAX + 1];
int tzn = -1, trip = -1, cdev_id = -1, curr_state = -1;
const char *tz_name = "";
genlmsg_parse(nl_hdr, 0, attrs, THERMAL_GENL_ATTR_MAX, NULL);
switch (hdr->cmd) {
case THERMAL_GENL_EVENT_TZ_TRIP_UP:
case THERMAL_GENL_EVENT_TZ_TRIP_DOWN:
if (attrs[THERMAL_GENL_ATTR_TZ_ID])
tzn = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
if (attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID])
trip = nla_get_u32(
attrs[THERMAL_GENL_ATTR_TZ_TRIP_ID]);
LOG(DEBUG) << "thermal_nl_event: TZ:" << tzn << " Trip:"
<< trip << "event:" << (int)hdr->cmd << std::endl;
event_cb(tzn, trip);
break;
case THERMAL_GENL_EVENT_TZ_CREATE:
if (attrs[THERMAL_GENL_ATTR_TZ_ID])
tzn = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
if (attrs[THERMAL_GENL_ATTR_TZ_NAME])
tz_name = nla_get_string(attrs[THERMAL_GENL_ATTR_TZ_NAME]);
LOG(DEBUG) << "thermal_nl_event: TZ_CREATE: TZ:" << tzn << " TZ_NAME:"
<< tz_name << "event:" << (int)hdr->cmd << std::endl;
event_create_cb(tzn, tz_name);
break;
case THERMAL_GENL_EVENT_CDEV_STATE_UPDATE:
if (attrs[THERMAL_GENL_ATTR_CDEV_ID])
cdev_id = nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_ID]);
if (attrs[THERMAL_GENL_ATTR_CDEV_CUR_STATE])
curr_state = nla_get_u32(attrs[THERMAL_GENL_ATTR_CDEV_CUR_STATE]);
LOG(DEBUG) << "thermal_nl_event: CDEV:" << cdev_id <<
" curr_state :" << curr_state << " event:" << (int)hdr->cmd<< std::endl;
cdev_cb(cdev_id, curr_state);
break;
}
return 0;
}
int ThermalMonitor::sample_parse(struct nl_msg *n, void *data)
{
struct nlmsghdr *nl_hdr = nlmsg_hdr(n);
struct genlmsghdr *hdr = genlmsg_hdr(nl_hdr);
struct nlattr *attrs[THERMAL_GENL_ATTR_MAX + 1];
int tzn = -1, temp = -1;
genlmsg_parse(nl_hdr, 0, attrs, THERMAL_GENL_ATTR_MAX, NULL);
switch (hdr->cmd) {
case THERMAL_GENL_SAMPLING_TEMP:
if (attrs[THERMAL_GENL_ATTR_TZ_ID])
tzn = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_ID]);
if (attrs[THERMAL_GENL_ATTR_TZ_TEMP])
temp = nla_get_u32(attrs[THERMAL_GENL_ATTR_TZ_TEMP]);
LOG(DEBUG) << "thermal_sample_event: TZ:" << tzn << " temp:"
<< temp << std::endl;
sample_cb(tzn, temp);
break;
}
return 0;
}
int ThermalMonitor::family_msg_cb(struct nl_msg *msg, void *data)
{
struct nlattr *tb[CTRL_ATTR_MAX + 1];
struct genlmsghdr *gnlh = genlmsg_hdr(nlmsg_hdr(msg));
struct nlattr *mc_group;
int rem_mcgrp;
nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
genlmsg_attrlen(gnlh, 0), NULL);
if (!tb[CTRL_ATTR_MCAST_GROUPS]) {
LOG(ERROR) << "Multicast group not available\n";
return -1;
}
nla_for_each_nested(mc_group, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcgrp) {
struct nlattr *nl_group[CTRL_ATTR_MCAST_GRP_MAX + 1];
nla_parse(nl_group, CTRL_ATTR_MCAST_GRP_MAX,
(struct nlattr *)nla_data(mc_group),
nla_len(mc_group), NULL);
if (!nl_group[CTRL_ATTR_MCAST_GRP_NAME] ||
!nl_group[CTRL_ATTR_MCAST_GRP_ID])
continue;
std::string family((char *)nla_data(
nl_group[CTRL_ATTR_MCAST_GRP_NAME]));
LOG(DEBUG) << "Family:" << family << std::endl;
if (family == THERMAL_GENL_EVENT_GROUP_NAME)
event_group = nla_get_u32(
nl_group[CTRL_ATTR_MCAST_GRP_ID]);
if (family == THERMAL_GENL_SAMPLING_GROUP_NAME)
sample_group = nla_get_u32(
nl_group[CTRL_ATTR_MCAST_GRP_ID]);
}
return 0;
}
int ThermalMonitor::send_nl_msg(struct nl_msg *msg)
{
int ret = 0;
ret = nl_send_auto(event_soc, msg);
if (ret < 0) {
LOG(ERROR) << "Error sending NL message\n";
return ret;
}
nl_socket_disable_seq_check(event_soc);
nl_socket_modify_cb(event_soc, NL_CB_VALID, NL_CB_CUSTOM,
thermal_family_cb, this);
ret = nl_recvmsgs_default(event_soc);
return ret;
}
int ThermalMonitor::fetch_group_id(void)
{
struct nl_msg *msg;
int ctrlid, ret = 0;
msg = nlmsg_alloc();
if (!msg)
return -1;
ctrlid = genl_ctrl_resolve(event_soc, "nlctrl");
genlmsg_put(msg, 0, 0, ctrlid, 0, 0, CTRL_CMD_GETFAMILY, 0);
nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, THERMAL_GENL_FAMILY_NAME);
send_nl_msg(msg);
nlmsg_free(msg);
if (event_group != -1 && sample_group != -1) {
LOG(DEBUG) << "Netlink event: " << event_group <<
" Sample:" << sample_group << std::endl;
ret = nl_socket_add_membership(event_soc, event_group);
if (ret) {
LOG(ERROR) << "Netlink event Socket membership add error\n";
return ret;
}
ret = nl_socket_add_membership(sample_soc, sample_group);
if (ret) {
LOG(ERROR) << "Netlink sample Socket membership add error\n";
return ret;
}
}
return 0;
}
void ThermalMonitor::start()
{
struct nl_msg *msg;
event_soc = nl_socket_alloc();
if (!event_soc) {
LOG(ERROR) << "Netlink Event socket alloc failed\n";
return;
}
if (genl_connect(event_soc)) {
LOG(ERROR) << "Netlink Event socket connect failed\n";
nl_socket_free(event_soc);
event_soc = nullptr;
return;
}
sample_soc = nl_socket_alloc();
if (!sample_soc) {
LOG(ERROR) << "Netlink Sample socket alloc failed\n";
nl_socket_free(event_soc);
event_soc = nullptr;
return;
}
if (genl_connect(sample_soc)) {
LOG(ERROR) << "Netlink Sample socket connect failed\n";
nl_socket_free(sample_soc);
nl_socket_free(event_soc);
event_soc = nullptr;
sample_soc = nullptr;
return;
}
if (fetch_group_id())
return;
LOG(DEBUG) << "Netlink connection established.\n";
nl_socket_disable_seq_check(sample_soc);
nl_socket_modify_cb(sample_soc, NL_CB_VALID, NL_CB_CUSTOM,
thermal_sample_cb, this);
nl_socket_disable_seq_check(event_soc);
nl_socket_modify_cb(event_soc, NL_CB_VALID, NL_CB_CUSTOM,
thermal_event_cb, this);
event_th = std::thread(thermal_listen, event_soc,
std::bind(&ThermalMonitor::stopPolling, this));
sample_th = std::thread(thermal_listen, sample_soc,
std::bind(&ThermalMonitor::stopPolling, this));
}
} // namespace thermal
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,90 @@
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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.
*/
/* Changes from Qualcomm Innovation Center are provided under the following license:
Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear */
#ifndef THERMAL_THERMAL_MONITOR_NETLINK_H__
#define THERMAL_THERMAL_MONITOR_NETLINK_H__
#include <thread>
#include <netlink/genl/genl.h>
#include <netlink/genl/mngt.h>
#include <netlink/genl/ctrl.h>
#include <netlink/netlink.h>
#include <aidl/android/hardware/thermal/BnThermal.h>
namespace aidl{
namespace android {
namespace hardware {
namespace thermal {
using eventMonitorCB = std::function<void(int, int)>;
using eventCreateMonitorCB = std::function<void(int, const char *)>;
class ThermalMonitor {
public:
ThermalMonitor(const eventMonitorCB &inp_event_cb,
const eventMonitorCB &inp_sample_cb,
const eventCreateMonitorCB &inp_event_create_cb,
const eventMonitorCB &inp_event_cdev_cb);
~ThermalMonitor();
void parse_and_notify(char *inp_buf, ssize_t len);
bool stopPolling()
{
return monitor_shutdown;
}
void start();
int family_msg_cb(struct nl_msg *msg, void *data);
int event_parse(struct nl_msg *n, void *data);
int sample_parse(struct nl_msg *n, void *data);
private:
std::thread event_th, sample_th;
struct nl_sock *event_soc, *sample_soc;
int event_group, sample_group;
bool monitor_shutdown;
eventMonitorCB event_cb, sample_cb;
eventCreateMonitorCB event_create_cb;
eventMonitorCB cdev_cb;
int fetch_group_id();
int send_nl_msg(struct nl_msg *msg);
};
} // namespace thermal
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // THERMAL_THERMAL_MONITOR_NETLINK_H__

View File

@@ -0,0 +1,232 @@
/*
* Copyright (c) 2020, 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.
*/
/* Changes from Qualcomm Innovation Center are provided under the following license:
Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear */
#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 "thermalConfig.h"
#include "thermalUtils.h"
namespace aidl {
namespace android {
namespace hardware {
namespace thermal {
ThermalUtils::ThermalUtils(const ueventCB &inp_cb):
cfg(),
cmnInst(),
monitor(std::bind(&ThermalUtils::ueventParse, this,
std::placeholders::_1,
std::placeholders::_2)),
cb(inp_cb)
{
int ret = 0;
std::vector<struct therm_sensor> sensorList;
std::vector<struct target_therm_cfg> therm_cfg = cfg.fetchConfig();
is_sensor_init = false;
is_cdev_init = false;
ret = cmnInst.initThermalZones(therm_cfg);
if (ret > 0) {
is_sensor_init = true;
sensorList = cmnInst.fetch_sensor_list();
std::lock_guard<std::mutex> _lock(sens_cb_mutex);
for (struct therm_sensor sens: sensorList) {
thermalConfig[sens.sensor_name] = sens;
cmnInst.read_temperature(sens);
cmnInst.estimateSeverity(sens);
cmnInst.initThreshold(sens);
}
monitor.start();
}
ret = cmnInst.initCdev();
if (ret > 0) {
is_cdev_init = true;
cdevList = cmnInst.fetch_cdev_list();
}
}
void ThermalUtils::Notify(struct therm_sensor& sens)
{
int severity = cmnInst.estimateSeverity(sens);
if (severity != -1) {
LOG(INFO) << "sensor: " << sens.sensor_name <<" temperature: "
<< sens.t.value << " old: " <<
(int)sens.lastThrottleStatus << " new: " <<
(int)sens.t.throttlingStatus << std::endl;
cb(sens.t);
cmnInst.initThreshold(sens);
}
}
void ThermalUtils::ueventParse(std::string sensor_name, int temp)
{
LOG(DEBUG) << "uevent triggered for sensor: " << sensor_name
<< std::endl;
if (thermalConfig.find(sensor_name) == thermalConfig.end()) {
LOG(DEBUG) << "sensor is not monitored:" << sensor_name
<< std::endl;
return;
}
std::lock_guard<std::mutex> _lock(sens_cb_mutex);
struct therm_sensor& sens = thermalConfig[sensor_name];
sens.t.value = (float)temp / (float)sens.mulFactor;
return Notify(sens);
}
int ThermalUtils::readTemperatures(std::vector<Temperature>& temp)
{
std::unordered_map<std::string, struct therm_sensor>::iterator it;
int ret = 0;
std::vector<Temperature> _temp;
std::lock_guard<std::mutex> _lock(sens_cb_mutex);
for (it = thermalConfig.begin(); it != thermalConfig.end(); it++) {
struct therm_sensor& sens = it->second;
ret = cmnInst.read_temperature(sens);
if (ret < 0)
return ret;
Notify(sens);
_temp.push_back(sens.t);
}
temp = _temp;
return temp.size();
}
int ThermalUtils::readTemperatures(TemperatureType type,
std::vector<Temperature>& temp)
{
std::unordered_map<std::string, struct therm_sensor>::iterator it;
int ret = 0;
std::vector<Temperature> _temp;
std::lock_guard<std::mutex> _lock(sens_cb_mutex);
for (it = thermalConfig.begin(); it != thermalConfig.end(); it++) {
struct therm_sensor& sens = it->second;
if (sens.t.type != type)
continue;
ret = cmnInst.read_temperature(sens);
if (ret < 0)
return ret;
Notify(sens);
_temp.push_back(sens.t);
}
temp = _temp;
return temp.size();
}
int ThermalUtils::readTemperatureThreshold(std::vector<TemperatureThreshold>& thresh)
{
std::unordered_map<std::string, struct therm_sensor>::iterator it;
std::vector<TemperatureThreshold> _thresh;
for (it = thermalConfig.begin(); it != thermalConfig.end(); it++) {
struct therm_sensor& sens = it->second;
_thresh.push_back(sens.thresh);
}
thresh = _thresh;
return thresh.size();
}
int ThermalUtils::readTemperatureThreshold(TemperatureType type,
std::vector<TemperatureThreshold>& thresh)
{
std::unordered_map<std::string, struct therm_sensor>::iterator it;
std::vector<TemperatureThreshold> _thresh;
for (it = thermalConfig.begin(); it != thermalConfig.end(); it++) {
struct therm_sensor& sens = it->second;
if (sens.t.type != type)
continue;
_thresh.push_back(sens.thresh);
}
thresh = _thresh;
return thresh.size();
}
int ThermalUtils::readCdevStates(std::vector<CoolingDevice>& cdev_out)
{
int ret = 0;
std::vector<CoolingDevice> _cdev;
for (struct therm_cdev cdev: cdevList) {
ret = cmnInst.read_cdev_state(cdev);
if (ret < 0)
return ret;
_cdev.push_back(cdev.c);
}
cdev_out = _cdev;
return cdev_out.size();
}
int ThermalUtils::readCdevStates(cdevType type,
std::vector<CoolingDevice>& cdev_out)
{
int ret = 0;
std::vector<CoolingDevice> _cdev;
for (struct therm_cdev cdev: cdevList) {
if (cdev.c.type != type)
continue;
ret = cmnInst.read_cdev_state(cdev);
if (ret < 0)
return ret;
_cdev.push_back(cdev.c);
}
cdev_out = _cdev;
return cdev_out.size();
}
} // namespace thermal
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,97 @@
/*
* Copyright (c) 2020, 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.
*/
/* Changes from Qualcomm Innovation Center are provided under the following license:
Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear */
#ifndef THERMAL_THERMAL_UTILS_H__
#define THERMAL_THERMAL_UTILS_H__
#include <unordered_map>
#include <mutex>
#include <aidl/android/hardware/thermal/BnThermal.h>
#include "thermalConfig.h"
#include "thermalMonitor.h"
#include "thermalCommon.h"
#include "thermalData.h"
namespace aidl {
namespace android {
namespace hardware {
namespace thermal {
using ueventCB = std::function<void(Temperature &t)>;
class ThermalUtils {
public:
ThermalUtils(const ueventCB &inp_cb);
~ThermalUtils() = default;
bool isSensorInitialized()
{
return is_sensor_init;
};
bool isCdevInitialized()
{
return is_cdev_init;
};
int readTemperatures(std::vector<Temperature>& temp);
int readTemperatures(TemperatureType type,
std::vector<Temperature>& temperatures);
int readTemperatureThreshold(std::vector<TemperatureThreshold>& thresh);
int readTemperatureThreshold(TemperatureType type,
std::vector<TemperatureThreshold>& thresh);
int readCdevStates(std::vector<CoolingDevice>& cdev);
int readCdevStates(cdevType type,
std::vector<CoolingDevice>& cdev);
private:
bool is_sensor_init;
bool is_cdev_init;
ThermalConfig cfg;
ThermalCommon cmnInst;
ThermalMonitor monitor;
std::unordered_map<std::string, struct therm_sensor>
thermalConfig;
std::vector<struct therm_cdev> cdevList;
std::mutex sens_cb_mutex;
ueventCB cb;
void ueventParse(std::string sensor_name, int temp);
void Notify(struct therm_sensor& sens);
};
} // namespace thermal
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // THERMAL_THERMAL_UTILS_H__

View File

@@ -0,0 +1,326 @@
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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.
*/
/* Changes from Qualcomm Innovation Center are provided under the following license:
Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear */
#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 "thermalConfig.h"
#include "thermalUtilsNetlink.h"
#include "thermalCommon.h"
namespace aidl {
namespace android {
namespace hardware {
namespace thermal {
ThermalUtils::ThermalUtils(const ueventCB &inp_cb, const notifyCB &inp_cdev_cb):
cfg(),
cmnInst(),
monitor(std::bind(&ThermalUtils::eventParse, this,
std::placeholders::_1,
std::placeholders::_2),
std::bind(&ThermalUtils::sampleParse, this,
std::placeholders::_1,
std::placeholders::_2),
std::bind(&ThermalUtils::eventCreateParse, this,
std::placeholders::_1,
std::placeholders::_2),
std::bind(&ThermalUtils::cdevEventParse, this,
std::placeholders::_1,
std::placeholders::_2)),
cb(inp_cb),
notify(inp_cdev_cb)
{
int ret = 0;
std::vector<struct therm_sensor> sensorList;
std::vector<struct target_therm_cfg> therm_cfg = cfg.fetchConfig();
is_sensor_init = false;
is_cdev_init = false;
ret = cmnInst.initThermalZones(therm_cfg);
if (ret > 0) {
is_sensor_init = true;
sensorList = cmnInst.fetch_sensor_list();
std::lock_guard<std::mutex> _lock(sens_cb_mutex);
for (struct therm_sensor sens: sensorList) {
thermalConfig[sens.tzn] = sens;
cmnInst.read_temperature(sens);
cmnInst.estimateSeverity(sens);
if (!sens.no_trip_set)
cmnInst.initThreshold(sens);
}
}
monitor.start();
ret = cmnInst.initCdev();
if (ret > 0) {
is_cdev_init = true;
cdevList = cmnInst.fetch_cdev_list();
std::lock_guard<std::mutex> _lock(cdev_cb_mutex);
for (struct therm_cdev cdevs: cdevList) {
cmnInst.read_cdev_state(cdevs);
cdev[cdevs.cdevn] = cdevs;
}
}
}
void ThermalUtils::Notify(struct therm_sensor& sens)
{
int severity = cmnInst.estimateSeverity(sens);
if (severity != -1) {
LOG(INFO) << "sensor: " << sens.sensor_name <<" temperature: "
<< sens.t.value << " old: " <<
(int)sens.lastThrottleStatus << " new: " <<
(int)sens.t.throttlingStatus << std::endl;
cb(sens.t);
if (!sens.no_trip_set)
cmnInst.initThreshold(sens);
}
}
void ThermalUtils::cdevNotify(struct therm_cdev& cdev, int state)
{
if (state > -1) {
cdev.c.value = state;
notify(cdev.c);
}
}
void ThermalUtils::cdevEventParse(int cdevn, int state)
{
if (cdev.find(cdevn) == cdev.end()) {
LOG(DEBUG) << "cdev is not supported:" << cdevn
<< std::endl;
return;
}
std::lock_guard<std::mutex> _lock(cdev_cb_mutex);
struct therm_cdev& cdevs = cdev[cdevn];
return cdevNotify(cdevs, state);
}
void ThermalUtils::eventParse(int tzn, int trip)
{
if (trip != 1)
return;
if (thermalConfig.find(tzn) == thermalConfig.end()) {
LOG(DEBUG) << "sensor is not monitored:" << tzn
<< std::endl;
return;
}
std::lock_guard<std::mutex> _lock(sens_cb_mutex);
struct therm_sensor& sens = thermalConfig[tzn];
return Notify(sens);
}
void ThermalUtils::sampleParse(int tzn, int temp)
{
if (thermalConfig.find(tzn) == thermalConfig.end()) {
LOG(DEBUG) << "sensor is not monitored:" << tzn
<< std::endl;
return;
}
std::lock_guard<std::mutex> _lock(sens_cb_mutex);
struct therm_sensor& sens = thermalConfig[tzn];
sens.t.value = (float)temp / (float)sens.mulFactor;
return Notify(sens);
}
void ThermalUtils::eventCreateParse(int tzn, const char *name)
{
int ret = 0;
std::vector<struct therm_sensor> sensorList;
std::vector<struct target_therm_cfg> therm_cfg = cfg.fetchConfig();
std::vector<struct target_therm_cfg>::iterator it_vec;
std::vector<std::string>::iterator it;
if (isSensorInitialized())
return;
for (it_vec = therm_cfg.begin();
it_vec != therm_cfg.end(); it_vec++) {
for (it = it_vec->sensor_list.begin();
it != it_vec->sensor_list.end(); it++) {
if (!it->compare(name))
break;
}
if (it != it_vec->sensor_list.end())
break;
}
if (it_vec == therm_cfg.end()) {
LOG(DEBUG) << "sensor is not monitored:" << tzn
<< std::endl;
return;
}
ret = cmnInst.initThermalZones(therm_cfg);
if (ret > 0) {
is_sensor_init = true;
sensorList = cmnInst.fetch_sensor_list();
std::lock_guard<std::mutex> _lock(sens_cb_mutex);
for (struct therm_sensor sens: sensorList) {
thermalConfig[sens.tzn] = sens;
cmnInst.read_temperature(sens);
cmnInst.estimateSeverity(sens);
if (!sens.no_trip_set)
cmnInst.initThreshold(sens);
}
}
}
int ThermalUtils::readTemperatures(std::vector<Temperature>& temp)
{
std::unordered_map<int, struct therm_sensor>::iterator it;
int ret = 0;
std::vector<Temperature> _temp;
std::lock_guard<std::mutex> _lock(sens_cb_mutex);
for (it = thermalConfig.begin(); it != thermalConfig.end(); it++) {
struct therm_sensor& sens = it->second;
ret = cmnInst.read_temperature(sens);
if (ret < 0)
return ret;
Notify(sens);
_temp.push_back(sens.t);
}
temp = _temp;
return temp.size();
}
int ThermalUtils::readTemperatures(TemperatureType type,
std::vector<Temperature>& temp)
{
std::unordered_map<int, struct therm_sensor>::iterator it;
int ret = 0;
std::vector<Temperature> _temp;
std::lock_guard<std::mutex> _lock(sens_cb_mutex);
for (it = thermalConfig.begin(); it != thermalConfig.end(); it++) {
struct therm_sensor& sens = it->second;
if (sens.t.type != type)
continue;
ret = cmnInst.read_temperature(sens);
if (ret < 0)
return ret;
Notify(sens);
_temp.push_back(sens.t);
}
temp = _temp;
return temp.size();
}
int ThermalUtils::readTemperatureThreshold(std::vector<TemperatureThreshold>& thresh)
{
std::unordered_map<int, struct therm_sensor>::iterator it;
std::vector<TemperatureThreshold> _thresh;
for (it = thermalConfig.begin(); it != thermalConfig.end(); it++) {
struct therm_sensor& sens = it->second;
_thresh.push_back(sens.thresh);
}
thresh = _thresh;
return thresh.size();
}
int ThermalUtils::readTemperatureThreshold(TemperatureType type,
std::vector<TemperatureThreshold>& thresh)
{
std::unordered_map<int, struct therm_sensor>::iterator it;
std::vector<TemperatureThreshold> _thresh;
for (it = thermalConfig.begin(); it != thermalConfig.end(); it++) {
struct therm_sensor& sens = it->second;
if (sens.t.type != type)
continue;
_thresh.push_back(sens.thresh);
}
thresh = _thresh;
return thresh.size();
}
int ThermalUtils::readCdevStates(std::vector<CoolingDevice>& cdev_out)
{
int ret = 0;
std::vector<CoolingDevice> _cdev;
for (struct therm_cdev cdev: cdevList) {
ret = cmnInst.read_cdev_state(cdev);
if (ret < 0)
return ret;
_cdev.push_back(cdev.c);
}
cdev_out = _cdev;
return cdev_out.size();
}
int ThermalUtils::readCdevStates(cdevType type,
std::vector<CoolingDevice>& cdev_out)
{
int ret = 0;
std::vector<CoolingDevice> _cdev;
for (struct therm_cdev cdev: cdevList) {
if (cdev.c.type != type)
continue;
ret = cmnInst.read_cdev_state(cdev);
if (ret < 0)
return ret;
_cdev.push_back(cdev.c);
}
cdev_out = _cdev;
return cdev_out.size();
}
} // namespace thermal
} // namespace hardware
} // namespace android
} // namespace aidl

View File

@@ -0,0 +1,106 @@
/*
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
* Copyright (c) 2022 Qualcomm Innovation Center, Inc. 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.
*/
/* Changes from Qualcomm Innovation Center are provided under the following license:
Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
SPDX-License-Identifier: BSD-3-Clause-Clear */
#ifndef THERMAL_THERMAL_UTILS_H__
#define THERMAL_THERMAL_UTILS_H__
#include <unordered_map>
#include <mutex>
#include <aidl/android/hardware/thermal/BnThermal.h>
#include "thermalConfig.h"
#include "thermalMonitorNetlink.h"
#include "thermalCommon.h"
#include "thermalData.h"
namespace aidl {
namespace android {
namespace hardware {
namespace thermal {
using ueventCB = std::function<void(Temperature &t)>;
using notifyCB = std::function<void(CoolingDevice &c)>;
class ThermalUtils {
public:
ThermalUtils(const ueventCB &inp_cb, const notifyCB &inp_cdev_cb);
~ThermalUtils() = default;
bool isSensorInitialized()
{
return is_sensor_init;
};
bool isCdevInitialized()
{
return is_cdev_init;
};
int readTemperatures(std::vector<Temperature>& temp);
int readTemperatures(TemperatureType type,
std::vector<Temperature>& temperatures);
int readTemperatureThreshold(std::vector<TemperatureThreshold>& thresh);
int readTemperatureThreshold(TemperatureType type,
std::vector<TemperatureThreshold>& thresh);
int readCdevStates(std::vector<CoolingDevice>& cdev);
int readCdevStates(cdevType type,
std::vector<CoolingDevice>& cdev);
private:
bool is_sensor_init;
bool is_cdev_init;
ThermalConfig cfg;
ThermalCommon cmnInst;
ThermalMonitor monitor;
std::unordered_map<int, struct therm_sensor>
thermalConfig;
std::unordered_map<int, struct therm_cdev>
cdev;
std::vector<struct therm_cdev> cdevList;
std::mutex sens_cb_mutex;
std::mutex cdev_cb_mutex;
ueventCB cb;
notifyCB notify;
void eventParse(int tzn, int trip);
void sampleParse(int tzn, int temp);
void eventCreateParse(int tzn, const char *name);
void Notify(struct therm_sensor& sens);
void cdevNotify(struct therm_cdev& cdev, int state);
void cdevEventParse(int cdevn, int state);
};
} // namespace thermal
} // namespace hardware
} // namespace android
} // namespace aidl
#endif // THERMAL_THERMAL_UTILS_H__