ossi: Cleanup dead targets

* Adapt to LineageOS common MediaTek HALs.
* Import thermal HIDL because we can't use AIDL implement.
This commit is contained in:
lahaina
2024-04-03 23:27:20 +09:00
parent 1e1f004ca7
commit 310a02ad1f
13 changed files with 3363 additions and 4 deletions

66
hidl/thermal/Android.bp Normal file
View File

@@ -0,0 +1,66 @@
//
// 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.
cc_library_shared {
name: "android.hardware.thermal@2.0-impl-mtk",
defaults: ["hidl_defaults"],
vendor: true,
relative_install_path: "hw",
srcs: ["Thermal.cpp",
"thermal_watcher.cpp",
"thermal_helper.cpp",
],
shared_libs: [
"libc",
"liblog",
"libcutils",
"libhardware",
"libbase",
"libcutils",
"libutils",
"libhidlbase",
"android.hardware.thermal@1.0",
"android.hardware.thermal@2.0",
],
}
cc_binary {
name: "android.hardware.thermal@2.0-service.mtk",
defaults: ["hidl_defaults"],
relative_install_path: "hw",
vendor: true,
init_rc: ["android.hardware.thermal@2.0-service.mtk.rc"],
vintf_fragments: ["android.hardware.thermal@2.0-service.mtk.xml"],
required: [
"android.hardware.thermal@2.0-impl-mtk",
],
srcs: [
"service.cpp"
],
shared_libs: [
"libc",
"liblog",
"libcutils",
"libhardware",
"libcutils",
"libbase",
"libhidlbase",
"libutils",
"android.hardware.thermal@2.0",
"android.hardware.thermal@1.0",
],
}

228
hidl/thermal/Thermal.cpp Normal file
View File

@@ -0,0 +1,228 @@
/*
* 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.
*/
#define LOG_TAG "android.hardware.thermal@2.0-impl"
#include <cmath>
#include <set>
#include <android-base/logging.h>
#include <hidl/HidlTransportSupport.h>
#include "Thermal.h"
#include <errno.h>
#include <math.h>
#include <vector>
#include <hardware/hardware.h>
#include <hardware/thermal.h>
#include "thermal_helper.h"
namespace android {
namespace hardware {
namespace thermal {
namespace V2_0 {
namespace implementation {
using ::android::sp;
using ::android::hardware::interfacesEqual;
using ::android::hardware::thermal::V1_0::ThermalStatus;
using ::android::hardware::thermal::V1_0::ThermalStatusCode;
std::set<sp<IThermalChangedCallback>> gCallbacks;
Thermal::Thermal()
: thermal_helper_(
std::bind(&Thermal::sendThermalChangedCallback, this, std::placeholders::_1)) {
}
// Methods from ::android::hardware::thermal::V1_0::IThermal follow.
Return<void> Thermal::getTemperatures(getTemperatures_cb _hidl_cb) {
ThermalStatus status;
status.code = ThermalStatusCode::SUCCESS;
hidl_vec<Temperature_1_0> temperatures;
if (!thermal_helper_.fill_temperatures_1_0(&temperatures)) {
status.code = ThermalStatusCode::FAILURE;
status.debugMessage = "get temp fail";
}
_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_.fillCpuUsages(&cpu_usages)) {
status.code = ThermalStatusCode::FAILURE;
status.debugMessage = "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;
_hidl_cb(status, cooling_devices);
return Void();
}
// Methods from ::android::hardware::thermal::V2_0::IThermal follow.
Return<void> Thermal::getCurrentTemperatures(bool filterType, TemperatureType type,
getCurrentTemperatures_cb _hidl_cb) {
ThermalStatus status;
status.code = ThermalStatusCode::SUCCESS;
hidl_vec<Temperature_2_0> temperatures;
if (!thermal_helper_.fill_temperatures(filterType, &temperatures, type)) {
status.code = ThermalStatusCode::FAILURE;
status.debugMessage = "get temp fail";
}
_hidl_cb(status, temperatures);
return Void();
}
Return<void> Thermal::getTemperatureThresholds(bool filterType, TemperatureType type,
getTemperatureThresholds_cb _hidl_cb) {
ThermalStatus status;
status.code = ThermalStatusCode::SUCCESS;
hidl_vec<TemperatureThreshold> temperature_thresholds;
if (!thermal_helper_.fill_thresholds(filterType, &temperature_thresholds, type)) {
status.code = ThermalStatusCode::FAILURE;
status.debugMessage = "get temperature thresholds fail";
}
_hidl_cb(status, temperature_thresholds);
return Void();
}
Return<void> Thermal::getCurrentCoolingDevices(bool filterType, CoolingType type,
getCurrentCoolingDevices_cb _hidl_cb) {
ThermalStatus status;
status.code = ThermalStatusCode::SUCCESS;
std::vector<CoolingDevice_2_0> cooling_devices;
if (!thermal_helper_.fill_cooling_devices(filterType, &cooling_devices, type)) {
status.code = ThermalStatusCode::FAILURE;
status.debugMessage = "get cooling devices fail";
}
_hidl_cb(status, cooling_devices);
return Void();
}
Return<void> Thermal::registerThermalChangedCallback(const sp<IThermalChangedCallback>& callback,
bool filterType, TemperatureType 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 interface 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 from 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);
LOG(INFO) << "sendThermalChangedCallback";
return !ret.isOk();
}
LOG(ERROR)
<< "a Thermal callback is dead, removed from callback list.";
return false;
}),
callbacks_.end());
}
}
IThermal* HIDL_FETCH_IThermal(const char* /* name */) {
return new Thermal();
}
} // namespace implementation
} // namespace V2_0
} // namespace thermal
} // namespace hardware
} // namespace android

98
hidl/thermal/Thermal.h Normal file
View File

@@ -0,0 +1,98 @@
/*
* 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 <android/hardware/thermal/2.0/IThermal.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
#include <hardware/thermal.h>
#include "thermal_helper.h"
namespace android {
namespace hardware {
namespace thermal {
namespace V2_0 {
namespace implementation {
using ::android::sp;
using ::android::hardware::hidl_array;
using ::android::hardware::hidl_memory;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
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 ::android::hardware::thermal::V2_0::IThermalChangedCallback;
using ::android::hardware::thermal::V2_0::TemperatureThreshold;
using ::android::hardware::thermal::V2_0::TemperatureType;
struct CallbackSetting {
CallbackSetting(sp<IThermalChangedCallback> callback, bool is_filter_type, TemperatureType type)
: callback(callback), is_filter_type(is_filter_type), type(type) {}
sp<IThermalChangedCallback> callback;
bool is_filter_type;
TemperatureType type;
};
class Thermal : public IThermal {
public:
//Thermal(thermal_module_t* module);
Thermal();
~Thermal() = default;
// Methods from ::android::hardware::thermal::V1_0::IThermal follow.
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 type,
getCurrentTemperatures_cb _hidl_cb) override;
Return<void> getTemperatureThresholds(bool filterType, TemperatureType type,
getTemperatureThresholds_cb _hidl_cb) override;
Return<void> registerThermalChangedCallback(
const sp<IThermalChangedCallback>& callback, bool filterType, TemperatureType 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;
// 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_;
};
extern "C" IThermal* HIDL_FETCH_IThermal(const char* name);
} // namespace implementation
} // namespace V2_0
} // namespace thermal
} // namespace hardware
} // namespace android

View File

@@ -0,0 +1,7 @@
service vendor.thermal-hal-2-0.mtk /vendor/bin/hw/android.hardware.thermal@2.0-service.mtk
interface android.hardware.thermal@1.0::IThermal default
interface android.hardware.thermal@2.0::IThermal default
socket thermal_hal_socket stream 660 root system
class hal
user system
group system

View File

@@ -0,0 +1,12 @@
<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>

39
hidl/thermal/service.cpp Normal file
View File

@@ -0,0 +1,39 @@
/*
* 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.
*/
#define LOG_TAG "android.hardware.thermal@2.0-service"
#include <android-base/logging.h>
#include <hidl/HidlTransportSupport.h>
#include "Thermal.h"
#include <android/hardware/thermal/1.0/IThermal.h>
#include <hidl/LegacySupport.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;
using android::hardware::defaultPassthroughServiceImplementation;
int main() {
return defaultPassthroughServiceImplementation<IThermal>();
}

View File

@@ -0,0 +1,888 @@
/*
* 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 <errno.h>
#include <ctype.h>
#include <dirent.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstring>
#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"
#include "thermal_map_table_type.h"
#include "thermal_map_table.h"
#define TH_LOG_TAG "thermal_hal"
#define TH_DLOG(_priority_, _fmt_, args...) /*LOG_PRI(_priority_, TH_LOG_TAG, _fmt_, ##args)*/
#define TH_LOG(_priority_, _fmt_, args...) LOG_PRI(_priority_, TH_LOG_TAG, _fmt_, ##args)
namespace android {
namespace hardware {
namespace thermal {
namespace V2_0 {
namespace implementation {
using ::android::hardware::thermal::V1_0::ThermalStatus;
using ::android::hardware::thermal::V1_0::ThermalStatusCode;
using ::android::hardware::thermal::V2_0::implementation::kMtkTempThreshold;
using ::android::hardware::thermal::V2_0::implementation::tz_data;
using ::android::hardware::thermal::V2_0::implementation::tz_data_v1;
using ::android::hardware::thermal::V2_0::implementation::tz_data_v2;
using ::android::hardware::thermal::V2_0::implementation::tz_data_v3;
using ::android::hardware::thermal::V2_0::implementation::cdata;
ThermalHelper::ThermalHelper(const NotificationCallback &cb)
: thermal_watcher_(new ThermalWatcher(
std::bind(&ThermalHelper::thermalWatcherCallbackFunc, this, std::placeholders::_1))),
cb_(cb) {
thermal_zone_num = 0;
cooling_device_num = 0;
tz_map_version = get_tz_map_version();
ALOGW("%s:tz_map_version %d", __func__, tz_map_version);
thermal_watcher_->initThermalWatcher(tz_map_version);
// Need start watching after status map initialized
is_initialized_ = thermal_watcher_->startThermalWatcher();
if (!is_initialized_) {
LOG(FATAL) << "ThermalHAL could not start watching thread properly.";
}
}
ThrottlingSeverity ThermalHelper::getSeverityFromThresholds(float value, TemperatureType_2_0 type) {
ThrottlingSeverity ret_hot = ThrottlingSeverity::NONE;
int typetoint = static_cast<int>(type);
if (typetoint < 0)
return ret_hot;
for (size_t i = static_cast<size_t>(ThrottlingSeverity::SHUTDOWN);
i > static_cast<size_t>(ThrottlingSeverity::NONE); --i) {
if (!std::isnan(kMtkTempThreshold[typetoint].hotThrottlingThresholds[i]) && kMtkTempThreshold[typetoint].hotThrottlingThresholds[i] <= value &&
ret_hot == ThrottlingSeverity::NONE) {
ret_hot = static_cast<ThrottlingSeverity>(i);
}
}
return ret_hot;
}
float ThermalHelper::get_max_temp(int type) {
FILE *file;
float temp = 0;
char temp_path[TZPATH_LENGTH];
float max_temp = INVALID_TEMP;
int ret;
if (type < 0 || type >= TT_MAX) {
return INVALID_TEMP;
}
for (int i = 0; i < MAX_MUTI_TZ_NUM; i++) {
ret = snprintf(temp_path, TZPATH_LENGTH, TZPATH_PREFIX"%d/temp", tz_data[type].tz_idx[i]);
if (ret < 0) {
ALOGW("%s: snprintf fail: %d", __func__, ret);
}
file = fopen(temp_path, "r");
if (file == NULL) {
//ALOGW("%s: failed to open type %d path %s", __func__, type, temp_path);
break;
} else {
if ((fscanf(file, "%f", &temp) > 0) && (temp > max_temp)){
max_temp = temp;
}
}
ret = fclose(file);
if (ret) {
ALOGW("%s: fclose fail: %d", __func__, ret);
}
}
return max_temp;
}
bool ThermalHelper::read_temperature(int type, Temperature_1_0 *ret_temp) {
float temp;
bool ret = false;
if (type < 0 || type > TT_SKIN) {
return ret;
}
temp = get_max_temp(type);
ret_temp->name = tz_data[type].label;
ret_temp->type = static_cast<TemperatureType_1_0>(type);
ret_temp->currentValue = temp * 0.001;
ret_temp->throttlingThreshold = kMtkTempThreshold[type].hotThrottlingThresholds[static_cast<size_t>(ThrottlingSeverity::SEVERE)];
ret_temp->shutdownThreshold = kMtkTempThreshold[type].hotThrottlingThresholds[static_cast<size_t>(ThrottlingSeverity::SHUTDOWN)];
ret_temp->vrThrottlingThreshold = kMtkTempThreshold[type].vrThrottlingThreshold;
ret = true;
return ret;
}
bool ThermalHelper::read_temperature(int type, Temperature_2_0 *ret_temp) {
float temp;
bool ret = false;
if (type < 0 || type >= TT_MAX) {
return ret;
}
temp = get_max_temp(type);
ret_temp->name = tz_data[type].label;
ret_temp->type = static_cast<TemperatureType_2_0>(type);
ret_temp->value = temp * 0.001;
ret_temp->throttlingStatus = getSeverityFromThresholds(ret_temp->value, ret_temp->type);
ret = true;
return ret;
}
bool ThermalHelper::fillCpuUsages(hidl_vec<CpuUsage> *cpu_usages) {
int vals, ret;
ssize_t read;
uint64_t user, nice, system, idle, active, total;
char *line = NULL;
size_t len = 0;
int size = 0;
FILE *file = NULL;
unsigned int max_core_num, cpu_array;
unsigned int cpu_num = 0;
FILE *core_num_file = NULL;
std::vector<CpuUsage> ret_cpu_usages;
int i;
/*======get device max core num=======*/
core_num_file = fopen(CORENUM_PATH, "r");
if (core_num_file == NULL) {
ALOGW("thermal_hal: %s: failed to open:CORENUM_PATH %s", __func__, strerror(errno));
return false;
}
if (fscanf(core_num_file, "%*d-%d", &max_core_num) != 1) {
ALOGW("thermal_hal: %s: unable to parse CORENUM_PATH", __func__);
ret = fclose(core_num_file);
if (ret) {
ALOGW("%s: fclose fail: %d", __func__, ret);
}
return false;
}
ret = fclose(core_num_file);
if (ret) {
ALOGW("%s: fclose fail: %d", __func__, ret);
}
cpu_array = sizeof(CPU_ALL_LABEL) / sizeof(CPU_ALL_LABEL[0]);
if (((max_core_num + 1) > cpu_array) || ((max_core_num + 1) <= 0)) {
ALOGW("thermal_hal: %s: max_core_num = %d, cpu_array = %d", __func__, max_core_num, cpu_array);
return false;
}
max_core_num += 1;
ALOGW("%s: max_core_num=%d", __func__, max_core_num);
/*======get device max core num=======*/
file = fopen(CPU_USAGE_FILE, "r");
if (file == NULL) {
ALOGW("thermal_hal: %s: failed to open: CPU_USAGE_FILE: %s", __func__, strerror(errno));
return false;
}
while ((read = getline(&line, &len, file)) != -1) {
CpuUsage cpu_usage;
// Skip non "cpu[0-9]" lines.
if (strnlen(line, read) < 4 || strncmp(line, "cpu", 3) != 0 || !isdigit(line[3])) {
free(line);
line = NULL;
len = 0;
continue;
}
vals = sscanf(line, "cpu%d %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64, &cpu_num, &user,
&nice, &system, &idle);
free(line);
line = NULL;
len = 0;
if (vals != 5) {
ALOGW("thermal_hal: %s: failed to read CPU information from file: %s", __func__, strerror(errno));
ret = fclose(file);
if (ret) {
ALOGW("%s: fclose fail: %d", __func__, ret);
}
return false;
}
active = user + nice + system;
total = active + idle;
if (cpu_num < max_core_num) {
cpu_usage.name = CPU_ALL_LABEL[cpu_num];
cpu_usage.active = active;
cpu_usage.total = total;
cpu_usage.isOnline = 1;
ret_cpu_usages.emplace_back(std::move(cpu_usage));
} else {
ALOGW("thermal_hal: %s: cpu_num %d > max_core_num %d", __func__, cpu_num, max_core_num);
ret = fclose(file);
if (ret) {
ALOGW("%s: fclose fail: %d", __func__, ret);
}
return false;
}
size++;
}
/*if there are hotplug off CPUs, set cpu_usage.total = 0*/
for (i = size; i < max_core_num; i++) {
CpuUsage cpu_usage;
cpu_usage.name = CPU_ALL_LABEL[i];
cpu_usage.active = 0;
cpu_usage.total = 0;
cpu_usage.isOnline = 0;
ret_cpu_usages.emplace_back(std::move(cpu_usage));
}
ALOGW("%s end loop, size %d, cpu_num = %d, max_core_num = %d", __func__, size, cpu_num, max_core_num);
ret = fclose(file);
if (ret) {
ALOGW("%s: fclose fail: %d", __func__, ret);
}
*cpu_usages = ret_cpu_usages;
return true;
}
bool ThermalHelper::fill_temperatures_1_0(hidl_vec<Temperature_1_0> *temperatures) {
bool ret = false;
std::vector<Temperature_1_0> ret_temps;
int current_index = 0;
for (int i = 0; i <= TT_SKIN; i++) {
Temperature_1_0 ret_temp;
if (!is_tz_path_valided(i))
init_tz_path();
if (tz_data[i].tz_idx[0] == -1) {
continue;
}
if (read_temperature(i, &ret_temp)) {
LOG(INFO) << "fill_temperatures_1_0 "
<< " name: " << ret_temp.name
<< " throttlingStatus: " << ret_temp.throttlingThreshold
<< " value: " << ret_temp.currentValue;
ret_temps.emplace_back(std::move(ret_temp));
ret = true;
} else {
ALOGW("%s: read temp fail type:%d", __func__, i);
return false;
}
++current_index;
}
*temperatures = ret_temps;
return current_index > 0;
}
bool ThermalHelper::fill_temperatures(bool filterType, hidl_vec<Temperature_2_0> *temperatures, TemperatureType_2_0 type) {
bool ret = false;
std::vector<Temperature_2_0> ret_temps;
int typetoint = static_cast<int>(type);
if (!is_tz_path_valided(typetoint))
init_tz_path();
for (int i = 0; i < TT_MAX; i++) {
Temperature_2_0 ret_temp;
if ((filterType && i != typetoint) || (tz_data[i].tz_idx[0] == -1)) {
continue;
}
if (read_temperature(i, &ret_temp)) {
LOG(INFO) << "fill_temperatures "
<< "filterType" << filterType
<< " name: " << ret_temp.name
<< " type: " << android::hardware::thermal::V2_0::toString(ret_temp.type)
<< " throttlingStatus: " << android::hardware::thermal::V2_0::toString(ret_temp.throttlingStatus)
<< " value: " << ret_temp.value
<< " ret_temps size " << ret_temps.size();
ret_temps.emplace_back(std::move(ret_temp));
ret = true;
} else {
ALOGW("%s: read temp fail type:%d", __func__, i);
return false;
}
}
*temperatures = ret_temps;
return ret;
}
bool ThermalHelper::fill_thresholds(bool filterType, hidl_vec<TemperatureThreshold> *Threshold, TemperatureType_2_0 type) {
FILE *file;
bool ret = false;
std::vector<TemperatureThreshold> ret_thresholds;
int typetoint = static_cast<int>(type);
char temp_path[TZPATH_LENGTH];
int r;
for (int i = 0; i < TT_MAX; i++) {
TemperatureThreshold ret_threshold;
if (filterType && i != typetoint) {
continue;
}
r = snprintf(temp_path, TZPATH_LENGTH, TZPATH_PREFIX"%d/type", tz_data[i].tz_idx[0]);
if (r < 0) {
ALOGW("%s: snprintf fail: %d", __func__, r);
}
file = fopen(temp_path, "r");
if (file) {
ret_threshold = {kMtkTempThreshold[i]};
LOG(INFO) << "fill_thresholds "
<< "filterType" << filterType
<< " name: " << ret_threshold.name
<< " type: " << android::hardware::thermal::V2_0::toString(ret_threshold.type)
<< " hotThrottlingThresholds: " << ret_threshold.hotThrottlingThresholds[static_cast<size_t>(ThrottlingSeverity::SEVERE)]
<< " vrThrottlingThreshold: " << ret_threshold.vrThrottlingThreshold
<< " ret_thresholds size " << ret_thresholds.size();
ret_thresholds.emplace_back(std::move(ret_threshold));
ret = true;
r = fclose(file);
if (r) {
ALOGW("%s: fclose fail: %d", __func__, r);
}
}
else {
ALOGW("%s: %s not support", __func__, kMtkTempThreshold[i].name.c_str());
}
}
*Threshold = ret_thresholds;
return ret;
}
bool ThermalHelper::fill_cooling_devices(bool filterType, std::vector<CoolingDevice_2_0> *CoolingDevice, CoolingType type) {
std::vector<CoolingDevice_2_0> ret_coolings;
bool ret = false;
if (!is_cooling_path_valided())
init_cl_path();
for (int i = 0; i < MAX_COOLING; i++) {
if (filterType && type != cdata[i].cl_2_0.type) {
continue;
}
if (cdata[i].cl_idx != -1) {
CoolingDevice_2_0 coolingdevice;
coolingdevice.name = cdata[i].cl_2_0.name;
coolingdevice.type = cdata[i].cl_2_0.type;
coolingdevice.value = cdata[i].cl_2_0.value;
LOG(INFO) << "fill_cooling_devices "
<< "filterType" << filterType
<< " name: " << coolingdevice.name
<< " type: " << android::hardware::thermal::V2_0::toString(coolingdevice.type)
<< " value: " << coolingdevice.value
<< " ret_coolings size " << ret_coolings.size();
ret_coolings.emplace_back(std::move(coolingdevice));
ret = true;
}
}
*CoolingDevice = ret_coolings;
return ret;
}
bool ThermalHelper::init_cl_path() {
char temp_path[CDPATH_LENGTH];
char temp_value_path[CDPATH_LENGTH];
char buf[CDNAME_SZ];
int fd = -1;
int fd_value = -1;
int read_len = 0;
int i = 0;
bool ret = true;
int r;
/*initial cdata*/
for (int j = 0; j < MAX_COOLING; ++j) {
cdata[j].cl_2_0.value = 0;
cdata[j].cl_idx = -1;
}
cooling_device_num = 0;
while(1) {
r = snprintf(temp_path, CDPATH_LENGTH, CDPATH_PREFIX"%d/type", i);
if (r < 0) {
ALOGW("%s: snprintf fail: %d", __func__, r);
}
fd = open(temp_path, O_RDONLY);
if (fd == -1) {
ALOGW("%s:find out cooling path", __func__);
cooling_device_num = i;
break;
} else {
CoolingDevice_2_0 coolingdevice;
read_len = read(fd, buf, CDNAME_SZ);
for (int j = 0; j < MAX_COOLING; ++j) {
if (std::strncmp(buf, cdata[j].cl_2_0.name.c_str(), std::strlen(cdata[j].cl_2_0.name.c_str())) == 0) {
cdata[j].cl_idx = i;
r = snprintf(temp_value_path, CDPATH_LENGTH, CDPATH_PREFIX"%d/cur_state", i);
if (r < 0) {
ALOGW("%s: snprintf fail: %d", __func__, r);
}
fd_value = open(temp_value_path, O_RDONLY);
if (fd_value == -1) {
ALOGW("%s:get value fail", __func__);
ret = false;
break;
} else {
read_len = read(fd_value, buf, CDNAME_SZ);
cdata[j].cl_2_0.value = std::atoi(buf);
LOG(INFO) << "init_cl_path"
<< "cl_idx" << cdata[j].cl_idx
<< " name: " << cdata[j].cl_2_0.name
<< " value: " << cdata[j].cl_2_0.value;
}
close(fd_value);
}
}
}
i++;
close(fd);
}
return ret;
}
bool ThermalHelper::is_cooling_path_valided() {
char temp_path[CDPATH_LENGTH];
char buf[CDNAME_SZ];
int fd = -1;
int read_len = 0;
bool ret = true;
int r;
/*check if cooling device number are changed*/
r = snprintf(temp_path, CDPATH_LENGTH, CDPATH_PREFIX"%d/type", (cooling_device_num - 1));
if (r < 0) {
ALOGW("%s: snprintf fail: %d", __func__, r);
}
fd = open(temp_path, O_RDONLY);
if (fd == -1) {
LOG(INFO) << "cl_num are changed" << cooling_device_num;
return false;
} else {
close(fd);
}
r = snprintf(temp_path, CDPATH_LENGTH, CDPATH_PREFIX"%d/type", cooling_device_num);
if (r < 0) {
ALOGW("%s: snprintf fail: %d", __func__, r);
}
fd = open(temp_path, O_RDONLY);
if (fd != -1) {
close(fd);
LOG(INFO) << "cl_num are increased" << cooling_device_num;
return false;
}
for (int i = 0; i < MAX_COOLING; i++) {
if (cdata[i].cl_idx != -1) {
r = snprintf(temp_path, CDPATH_LENGTH, CDPATH_PREFIX"%d/type", cdata[i].cl_idx);
if (r < 0) {
ALOGW("%s: snprintf fail: %d", __func__, r);
}
fd = open(temp_path, O_RDONLY);
if (fd == -1) {
ALOGW("%s:cl path error %d %s" , __func__, i, temp_path);
ret = false;
break;
} else {
read_len = read(fd, buf, CDNAME_SZ);
if (std::strncmp(buf, cdata[i].cl_2_0.name.c_str(), std::strlen(cdata[i].cl_2_0.name.c_str())) != 0) {
ret = false;
close(fd);
LOG(INFO) << " cl name mismatch "<< i << cdata[i].cl_2_0.name;
break;
}
close(fd);
}
}
}
return ret;
}
bool ThermalHelper::is_tz_path_valided(int type) {
char temp_path[TZPATH_LENGTH];
char buf[TZNAME_SZ];
int fd = -1;
int read_len = 0;
bool ret = true;
int r;
if (type < 0 || type >= TT_MAX) {
return false;
}
/*check if thermal zone number are changed*/
r = snprintf(temp_path, TZPATH_LENGTH, TZPATH_PREFIX"%d/type", (thermal_zone_num - 1));
if (r < 0) {
ALOGW("%s: snprintf fail: %d", __func__, r);
}
fd = open(temp_path, O_RDONLY);
if (fd == -1) {
LOG(INFO) << "thermal_zone_num are changed" << thermal_zone_num;
return false;
} else {
close(fd);
}
r = snprintf(temp_path, TZPATH_LENGTH, TZPATH_PREFIX"%d/type", thermal_zone_num);
if (r < 0) {
ALOGW("%s: snprintf fail: %d", __func__, r);
}
fd = open(temp_path, O_RDONLY);
if (fd != -1) {
close(fd);
LOG(INFO) << "thermal_zone_num are increased" << thermal_zone_num;
return false;
}
if (tz_data[type].tz_idx[0] != -1) {
r = snprintf(temp_path, TZPATH_LENGTH, TZPATH_PREFIX"%d/type", tz_data[type].tz_idx[0]);
if (r < 0) {
ALOGW("%s: snprintf fail: %d", __func__, r);
}
fd = open(temp_path, O_RDONLY);
if (fd == -1) {
ALOGW("%s:tz path error %d %s" , __func__, type, temp_path);
ret = false;
} else {
read_len = read(fd, buf, TZNAME_SZ);
/*/sys/class/thermal/thermal_zone{$tz_idx}/type should equal tzName*/
if (std::strncmp(buf, tz_data[type].tzName, strlen(tz_data[type].tzName)) != 0) {
ret = false;
LOG(INFO) << " tz name mismatch "<< type << tz_data[type].tzName;
}
close(fd);
}
}
return ret;
}
void ThermalHelper::get_tz_map() {
int v2_idx = 0;
int v3_idx = 0;
int r;
if (tz_map_version == TZ_MAP_LEGANCY) {
for (int j = 0; j < TT_MAX; ++j) {
r = snprintf(tz_data[j].tzName, sizeof(tz_data_v1[j].tzName), "%s", tz_data_v1[j].tzName);
if (r < 0) {
ALOGW("%s: snprintf fail: %d", __func__, r);
}
tz_data[j].muti_tz_num = 1;
tz_data[j].tz_idx[0] = tz_data_v1[j].tz_idx[0];
}
} else if (tz_map_version == TZ_MAP_V2) {
for (int j = 0; j < TT_MAX; ++j) {
r = snprintf(tz_data[j].tzName, sizeof(tz_data_v2[v2_idx].tzName), "%s", tz_data_v2[v2_idx].tzName);
if (r < 0) {
ALOGW("%s: snprintf fail: %d", __func__, r);
}
tz_data[j].muti_tz_num = tz_data_v2[v2_idx].muti_tz_num;
for (int l = 0; l < tz_data[j].muti_tz_num ; ++l)
tz_data[j].tz_idx[l] = tz_data_v2[v2_idx + l].tz_idx[0];
if (tz_data[j].muti_tz_num > 1)
v2_idx += (tz_data[j].muti_tz_num - 1);
v2_idx++;
}
} else if (tz_map_version == TZ_MAP_V3) {
for (int j = 0; j < TT_MAX; ++j) {
r = snprintf(tz_data[j].tzName, sizeof(tz_data_v3[v3_idx].tzName), "%s", tz_data_v3[v3_idx].tzName);
if (r < 0) {
ALOGW("%s: snprintf fail: %d", __func__, r);
}
tz_data[j].muti_tz_num = tz_data_v3[v3_idx].muti_tz_num;
for (int l = 0; l < tz_data[j].muti_tz_num ; ++l)
tz_data[j].tz_idx[l] = tz_data_v3[v3_idx + l].tz_idx[0];
if (tz_data[j].muti_tz_num > 1)
v3_idx += (tz_data[j].muti_tz_num - 1);
v3_idx++;
}
}
for (int j = 0; j < TT_MAX; ++j) {
ALOGW("%s: tz%d, name=%s, label=%s, muti_tz_num=%d", __func__, j, tz_data[j].tzName, tz_data[j].label, tz_data[j].muti_tz_num);
ALOGW("tz_idx0:%d, tz_idx1:%d,tz_idx2:%d,tz_idx3:%d,tz_idx4:%d,", tz_data[j].tz_idx[0], tz_data[j].tz_idx[1], tz_data[j].tz_idx[2], tz_data[j].tz_idx[3], tz_data[j].tz_idx[4]);
}
}
int ThermalHelper::get_tz_map_version() {
char temp_path[TZPATH_LENGTH];
char buf[TZNAME_SZ];
int fd = -1;
int read_len = 0;
int i = 0;
int version = 0;
int soc_max_exist = 0;
int ap_ntc_exist = 0;
int r;
while(1) {
r = snprintf(temp_path, TZPATH_LENGTH, TZPATH_PREFIX"%d/type", i);
if (r < 0) {
ALOGW("%s: snprintf fail: %d", __func__, r);
}
fd = open(temp_path, O_RDONLY);
if (fd == -1) {
ALOGW("%s:find out tz path", __func__);
break;
} else {
read_len = read(fd, buf, TZNAME_SZ);
if (std::strncmp(buf, tz_data_v1[0].tzName, strlen(tz_data_v1[0].tzName)) == 0) {
version = TZ_MAP_LEGANCY;
close(fd);
break;
ALOGW("support legancy tz data");
} else {
if (std::strncmp(buf, tz_data_v2[0].tzName, strlen(tz_data_v2[0].tzName)) == 0)
soc_max_exist = 1;
if (std::strncmp(buf, tz_data_v2[TT_SKIN].tzName, strlen(tz_data_v2[TT_SKIN].tzName)) == 0)
ap_ntc_exist = 1;
}
i++;
close(fd);
}
}
if ((soc_max_exist == 1) && (ap_ntc_exist == 1))
version = TZ_MAP_V2;
else if ((soc_max_exist == 1) && (ap_ntc_exist == 0))
version = TZ_MAP_V3;
else
version = TZ_MAP_LEGANCY;
return version;
}
void ThermalHelper::init_tz_path() {
if (tz_map_version == TZ_MAP_LEGANCY)
init_tz_path_v1();
else if (tz_map_version == TZ_MAP_V2)
init_tz_path_v2();
else if (tz_map_version == TZ_MAP_V3)
init_tz_path_v3();
get_tz_map();
}
void ThermalHelper::init_tz_path_v1() {
char temp_path[TZPATH_LENGTH];
char buf[TZNAME_SZ];
int fd = -1;
int read_len = 0;
int i = 0;
int r;
/*initial tz_data*/
for (int j = 0; j < TT_MAX; ++j) {
for (int k = 0; k < MAX_MUTI_TZ_NUM; ++k)
tz_data[j].tz_idx[k] = -1;
}
thermal_zone_num = 0;
while(1) {
r = snprintf(temp_path, TZPATH_LENGTH, TZPATH_PREFIX"%d/type", i);
if (r < 0) {
ALOGW("%s: snprintf fail: %d", __func__, r);
}
fd = open(temp_path, O_RDONLY);
if (fd == -1) {
ALOGW("%s:find out tz path", __func__);
thermal_zone_num = i;
break;
} else {
read_len = read(fd, buf, TZNAME_SZ);
for (int j = 0; j < TT_MAX; ++j) {
if (std::strncmp(buf, tz_data_v1[j].tzName, strlen(tz_data_v1[j].tzName)) == 0) {
tz_data_v1[j].tz_idx[0] = i;
ALOGW("tz_data_v1[%d].tz_idx:%d",j,i);
}
}
i++;
close(fd);
}
}
}
void ThermalHelper::init_tz_path_v2() {
char temp_path[TZPATH_LENGTH];
char buf[TZNAME_SZ];
int fd = -1;
int read_len = 0;
int i = 0;
int r;
/*initial tz_data*/
for (int j = 0; j < TT_MAX; ++j) {
for (int k = 0; k < MAX_MUTI_TZ_NUM; ++k)
tz_data[j].tz_idx[k] = -1;
tz_data_v2[j].tz_idx[0] = -1;
}
thermal_zone_num = 0;
while(1) {
r = snprintf(temp_path, TZPATH_LENGTH, TZPATH_PREFIX"%d/type", i);
if (r < 0) {
ALOGW("%s: snprintf fail: %d", __func__, r);
}
fd = open(temp_path, O_RDONLY);
if (fd == -1) {
ALOGW("%s:find out tz path", __func__);
thermal_zone_num = i;
break;
} else {
read_len = read(fd, buf, TZNAME_SZ);
for (int j = 0; j < TZ_DATA_NUM_MAX; ++j) {
if (tz_data_v2[j].tz_idx[0] != -1)
continue;
if (std::strncmp(buf, tz_data_v2[j].tzName, strlen(tz_data_v2[j].tzName)) == 0) {
tz_data_v2[j].tz_idx[0] = i;
ALOGW("tz_data_v2[%d].tz_idx:%d",j,i);
}
}
i++;
close(fd);
}
}
}
void ThermalHelper::init_tz_path_v3() {
char temp_path[TZPATH_LENGTH];
char buf[TZNAME_SZ];
int fd = -1;
int read_len = 0;
int i = 0;
int r;
/*initial tz_data*/
for (int j = 0; j < TT_MAX; ++j) {
for (int k = 0; k < MAX_MUTI_TZ_NUM; ++k)
tz_data[j].tz_idx[k] = -1;
tz_data_v3[j].tz_idx[0] = -1;
}
thermal_zone_num = 0;
while(1) {
r = snprintf(temp_path, TZPATH_LENGTH, TZPATH_PREFIX"%d/type", i);
if (r < 0) {
ALOGW("%s: snprintf fail: %d", __func__, r);
}
fd = open(temp_path, O_RDONLY);
if (fd == -1) {
ALOGW("%s:find out tz path", __func__);
thermal_zone_num = i;
break;
} else {
read_len = read(fd, buf, TZNAME_SZ);
for (int j = 0; j < TZ_DATA_NUM_MAX; ++j) {
if (tz_data_v3[j].tz_idx[0] != -1)
continue;
if (std::strncmp(buf, tz_data_v3[j].tzName, strlen(tz_data_v3[j].tzName)) == 0) {
tz_data_v3[j].tz_idx[0] = i;
ALOGW("tz_data_v3[%d].tz_idx:%d",j,i);
}
}
i++;
close(fd);
}
}
}
// 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;
Temperature_2_0 temp;
if (uevent_sensors.size() != 0) {
// writer lock
std::unique_lock<std::mutex> _lock(sensor_status_map_mutex_);
for (const auto &name : uevent_sensors) {
for (int i = 0; i < TT_MAX; i++) {
if (strncmp(name.c_str(), tz_data[i].label, strlen(tz_data[i].label)) == 0) {
if (!is_tz_path_valided(i))
init_tz_path();
if (read_temperature(i,&temp))
temps.push_back(temp);
}
}
}
thermal_triggered = true;
}
if (!temps.empty() && cb_) {
cb_(temps);
}
return thermal_triggered;
}
} // namespace implementation
} // namespace V2_0
} // namespace thermal
} // namespace hardware
} // namespace android

View File

@@ -0,0 +1,120 @@
/*
* 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 "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;
// Dissallow copy and assign.
ThermalHelper(const ThermalHelper &) = delete;
void operator=(const ThermalHelper &) = delete;
bool isInitializedOk() const { return is_initialized_; }
ThrottlingSeverity getSeverityFromThresholds(float value, TemperatureType_2_0 type);
bool fillCpuUsages(hidl_vec<CpuUsage> *cpu_usages);
bool fill_temperatures_1_0(hidl_vec<Temperature_1_0> *temperatures);
bool fill_temperatures(bool filterType, hidl_vec<Temperature_2_0> *temperatures, TemperatureType_2_0 type);
bool fill_thresholds(bool filterType, hidl_vec<TemperatureThreshold> *Threshold, TemperatureType_2_0 type);
bool fill_cooling_devices(bool filterType, std::vector<CoolingDevice_2_0> *CoolingDevice, CoolingType type);
void init_tz_path(void);
void init_tz_path_v1(void);
void init_tz_path_v2(void);
void init_tz_path_v3(void);
void get_tz_map(void);
int get_tz_map_version(void);
float get_max_temp(int type);
bool init_cl_path(void);
bool read_temperature(int type, Temperature_1_0 *ret_temp);
bool read_temperature(int type, Temperature_2_0 *ret_temp);
int get_tz_num() const { return thermal_zone_num; };
int get_cooling_num() const { return cooling_device_num; }
bool is_tz_path_valided(int type);
bool is_cooling_path_valided();
private:
// For thermal_watcher_'s polling thread
bool thermalWatcherCallbackFunc(const std::set<std::string> &uevent_sensors);
sp<ThermalWatcher> thermal_watcher_;
bool is_initialized_;
const NotificationCallback cb_;
mutable std::mutex sensor_status_map_mutex_;
std::map<std::string, SensorStatus> sensor_status_map_;
int thermal_zone_num;
int cooling_device_num;
int tz_map_version;
};
} // namespace implementation
} // namespace V2_0
} // namespace thermal
} // namespace hardware
} // namespace android

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,155 @@
/*
* Copyright (C) 2016 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 <stdbool.h>
#include <stdint.h>
#include <float.h>
#include <sys/cdefs.h>
#include <sys/types.h>
#include <hardware/hardware.h>
#include <errno.h>
#include <ctype.h>
#include <dirent.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <log/log.h>
#include <hardware/thermal.h>
#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>
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 ::android::hardware::thermal::V2_0::TemperatureThreshold;
using ::android::hardware::thermal::V2_0::TemperatureType;
using ::android::hardware::thermal::V2_0::ThrottlingSeverity;
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;
#define CPU_USAGE_FILE "/proc/stat"
#define CORENUM_PATH "/sys/devices/system/cpu/possible"
#define TZPATH_LENGTH 40
#define TZPATH_PREFIX "/sys/class/thermal/thermal_zone"
#define TZNAME_SZ 20
#define CDPATH_LENGTH 50
#define CDPATH_PREFIX "/sys/class/thermal/cooling_device"
#define CDNAME_SZ 25
#define CPU_TZ_NAME "mtktscpu"
#define GPU_TZ_NAME "mtktscpu"
#define BATTERY_TZ_NAME "mtktsbattery"
#define SKIN_TZ_NAME "mtktsAP"
#define USB_PORT_TZ_NAME "notsupport"
#define POWER_AMPLIFIER_TZ_NAME "mtktsbtsmdpa"
#define BCL_VOLTAGE_TZ_NAME "notsupport"
#define BCL_CURRENT_TZ_NAME "notsupport"
#define BCL_PERCENTAGE_TZ_NAME "notsupport"
#define NPU_TZ_NAME "mtktscpu"
#define MAX_MUTI_TZ_NUM 5
#define INVALID_TEMP -274000
enum TempType {
TT_UNKNOWN = -1,
TT_CPU = 0,
TT_GPU = 1,
TT_BATTERY = 2,
TT_SKIN = 3,
TT_USB_PORT = 4,
TT_POWER_AMPLIFIER = 5,
/** Battery Charge Limit - virtual thermal sensors */
TT_BCL_VOLTAGE = 6,
TT_BCL_CURRENT = 7,
TT_BCL_PERCENTAGE = 8,
/** Neural Processing Unit */
TT_NPU = 9,
TT_MAX = 10,
};
typedef struct _TZ_DATA {
char tzName[TZNAME_SZ];
const char label[TZNAME_SZ];
int tz_idx[MAX_MUTI_TZ_NUM];
int muti_tz_num;
} TZ_DATA;
#define MAX_COOLING 140
typedef struct _COOLING_DATA {
CoolingDevice_2_0 cl_2_0;
int cl_idx; /* /sys/class/thermal/cooling_device{$cl_idx} */
} COOLING_DATA;
/** Device cooling device types */
enum coolingType {
CT_UNKNOWN = -1,
CT_FAN = 0,
CT_BATTERY = 1,
CT_CPU = 2,
CT_GPU = 3,
CT_MODEM = 4,
CT_NPU = 5,
CT_COMPONENT = 6,
CT_MAX = 7,
};
/** tz map version */
enum tz_version {
TZ_MAP_UNKNOWN = 0,
TZ_MAP_LEGANCY = 1,
TZ_MAP_V2 = 2,
TZ_MAP_V3= 3,
};
} // namespace implementation
} // namespace V2_0
} // namespace thermal
} // namespace hardware
} // namespace android

View File

@@ -0,0 +1,331 @@
/*
* 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"
#include "thermal_map_table_type.h"
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <dirent.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <cutils/sockets.h>
#include <sys/un.h>
#define THERMAL_HAL_SOCKET_NAME "thermal_hal_socket"
#define THERMAL_HAL_SOCKET_IDENTIFY_WORD "TYPE"
#define BUFFER_SIZE (128)
namespace android {
namespace hardware {
namespace thermal {
namespace V2_0 {
namespace implementation {
using std::chrono_literals::operator""ms;
extern TZ_DATA tz_data[TT_MAX];
extern TemperatureThreshold kMtkTempThreshold[TT_MAX];
static int create_socket_server(void)
{
int ret, socket_fd;
socket_fd = android_get_control_socket(THERMAL_HAL_SOCKET_NAME);
if (socket_fd == -1) {
ALOGE("Failed to create a local socket\n");
return -1;
}
ret = listen(socket_fd, 20);
if (ret == -1) {
ALOGE("Failed to listen socket\n");
close(socket_fd);
return -1;
}
return socket_fd;
}
void ThermalWatcher::initThermalWatcher(int tz_version) {
if (tz_version == TZ_MAP_LEGANCY)
event_fd_.reset((TEMP_FAILURE_RETRY(uevent_open_socket(64 * 1024, true))));
else
event_fd_.reset((TEMP_FAILURE_RETRY(create_socket_server())));
if (event_fd_.get() < 0) {
LOG(ERROR) << "failed to open thermal hal socket";
is_polling_ = true;
return;
}
fcntl(event_fd_, F_SETFL, O_NONBLOCK);
looper_->addFd(event_fd_.get(), 0, Looper::EVENT_INPUT, nullptr, nullptr);
is_polling_ = false;
thermal_triggered_ = true;
tz_map_version = tz_version;
}
bool ThermalWatcher::startThermalWatcher() {
if (cb_) {
auto ret = this->run("ThermalWatcherThread", PRIORITY_HIGHEST);
if (ret != NO_ERROR) {
LOG(ERROR) << "ThermalWatcherThread start fail";
return false;
} else {
LOG(INFO) << "ThermalWatcherThread started";
return true;
}
}
return false;
}
void ThermalWatcher::parseMsg(std::set<std::string> *sensors_set) {
bool thermal_event = false;
bool thermal_update = false;
char *cp;
int ret, client_socket;
char buffer[BUFFER_SIZE];
while (true) {
client_socket = accept(event_fd_.get(), NULL, NULL);
if (client_socket == -1) {
LOG(INFO) << "Wait to accept a connection";
break;
}
ret = recv(client_socket, buffer, BUFFER_SIZE,0);
if (ret == -1) {
LOG(ERROR) << "Socket recv failed";
} else {
if (ret < BUFFER_SIZE)
buffer[ret] = '\0';
else
buffer[ret - 1] = '\0';
ALOGW("%s: Get from client %s", __func__, buffer);
cp = buffer;
while (*cp) {
ret = strncmp(cp, THERMAL_HAL_SOCKET_IDENTIFY_WORD, 4);
if (ret != 0){
LOG(ERROR) << "Message format error\n";
break;
}
std::string uevent = cp;
if (uevent.find("TYPE=") == 0) {
if (uevent.find("TYPE=thermal_hal_notify") != std::string::npos) {
thermal_event = true;
} else if (uevent.find("TYPE=thermal_hal_update") != std::string::npos) {
thermal_update = true;
} else {
break;
}
}
if (thermal_event) {
auto start_pos = uevent.find("NAME=");
if (start_pos != std::string::npos) {
start_pos += 5;
std::string name = uevent.substr(start_pos);
ALOGW("%s:name.c_str():%s", __func__, name.c_str());
for (int j = 0; j < TT_MAX; ++j) {
if (strncmp(name.c_str(), tz_data[j].label, strlen(tz_data[j].label)) == 0) {
ALOGW("%s:tz notify:%s", __func__, tz_data[j].label);
sensors_set->insert(name);
}
}
break;
}
}
if (thermal_update) {
auto start_pos = uevent.find("NAME=");
auto threshold_pos = uevent.find("THRESHOLD=");
auto critical_pos = uevent.find("CRITICAL=");
auto emerency_pos = uevent.find("EMERGENCY=");
auto shutdown_pos = uevent.find("SHUTDOWN=");
if (start_pos != std::string::npos && threshold_pos != std::string::npos) {
start_pos += 5;
threshold_pos += 10;
std::string name = uevent.substr(start_pos);
std::string threshold = uevent.substr(threshold_pos);
for (int j = 0; j < TT_MAX; ++j) {
if (strncmp(name.c_str(), kMtkTempThreshold[j].name.c_str(), strlen(kMtkTempThreshold[j].name.c_str())) == 0) {
kMtkTempThreshold[j].hotThrottlingThresholds[static_cast<size_t>(ThrottlingSeverity::SEVERE)] = std::stoi(threshold);
LOG(INFO) << "thermal update "
<< " name: " << kMtkTempThreshold[j].name
<< " hotThrottlingThresholds: " << kMtkTempThreshold[j].hotThrottlingThresholds[static_cast<size_t>(ThrottlingSeverity::SEVERE)];
}
}
break;
} else if (start_pos != std::string::npos && critical_pos != std::string::npos) {
start_pos += 5;
critical_pos += 9;
std::string name = uevent.substr(start_pos);
std::string threshold = uevent.substr(critical_pos);
for (int j = 0; j < TT_MAX; ++j) {
if (strncmp(name.c_str(), kMtkTempThreshold[j].name.c_str(), strlen(kMtkTempThreshold[j].name.c_str())) == 0) {
kMtkTempThreshold[j].hotThrottlingThresholds[static_cast<size_t>(ThrottlingSeverity::CRITICAL)] = std::stoi(threshold);
LOG(INFO) << "thermal update "
<< " name: " << kMtkTempThreshold[j].name
<< " hotThrottlingThresholds: " << kMtkTempThreshold[j].hotThrottlingThresholds[static_cast<size_t>(ThrottlingSeverity::CRITICAL)];
}
}
break;
}
else if (start_pos != std::string::npos && emerency_pos != std::string::npos) {
start_pos += 5;
emerency_pos += 10;
std::string name = uevent.substr(start_pos);
std::string threshold = uevent.substr(emerency_pos);
for (int j = 0; j < TT_MAX; ++j) {
if (strncmp(name.c_str(), kMtkTempThreshold[j].name.c_str(), strlen(kMtkTempThreshold[j].name.c_str())) == 0) {
kMtkTempThreshold[j].hotThrottlingThresholds[static_cast<size_t>(ThrottlingSeverity::EMERGENCY)] = std::stoi(threshold);
LOG(INFO) << "thermal update "
<< " name: " << kMtkTempThreshold[j].name
<< " hotThrottlingThresholds: " << kMtkTempThreshold[j].hotThrottlingThresholds[static_cast<size_t>(ThrottlingSeverity::EMERGENCY)];
}
}
break;
}
else if (start_pos != std::string::npos && shutdown_pos != std::string::npos) {
start_pos += 5;
shutdown_pos += 9;
std::string name = uevent.substr(start_pos);
std::string threshold = uevent.substr(shutdown_pos);
for (int j = 0; j < TT_MAX; ++j) {
if (strncmp(name.c_str(), kMtkTempThreshold[j].name.c_str(), strlen(kMtkTempThreshold[j].name.c_str())) == 0) {
kMtkTempThreshold[j].hotThrottlingThresholds[static_cast<size_t>(ThrottlingSeverity::SHUTDOWN)] = std::stoi(threshold);
LOG(INFO) << "thermal update "
<< " name: " << kMtkTempThreshold[j].name
<< " hotThrottlingThresholds: " << kMtkTempThreshold[j].hotThrottlingThresholds[static_cast<size_t>(ThrottlingSeverity::SHUTDOWN)];
}
}
break;
}
}
cp++;
}
}
close(client_socket);
}
}
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(event_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);
for (int j = 0; j < TT_MAX; ++j) {
if (strncmp(name.c_str(), tz_data[j].label, strlen(tz_data[j].label)) == 0) {
sensors_set->insert(name);
}
}
break;
}
}
while (*cp++) {
}
}
}
}
void ThermalWatcher::wake() {
looper_->wake();
}
bool ThermalWatcher::threadLoop() {
// Polling interval 2s
static constexpr int kMinPollIntervalMs = 2000;
// Max event timeout 5mins
static constexpr int keventPollTimeoutMs = 300000;
int fd;
std::set<std::string> sensors;
int timeout = (thermal_triggered_ || is_polling_) ? kMinPollIntervalMs : keventPollTimeoutMs;
if (looper_->pollOnce(timeout, &fd, nullptr, nullptr) >= 0) {
if (fd != event_fd_.get()) {
return true;
}
if (tz_map_version == TZ_MAP_LEGANCY)
parseUevent(&sensors);
else
parseMsg(&sensors);
// Ignore cb_ if uevent is not from monitored sensors
if (sensors.size() == 0) {
return true;
}
}
thermal_triggered_ = cb_(sensors);
return true;
}
} // namespace implementation
} // namespace V2_0
} // namespace thermal
} // namespace hardware
} // namespace android

View File

@@ -0,0 +1,95 @@
/*
* 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/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::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 startThermalWatcher();
// init uevent socket
void initThermalWatcher(int tz_version);
// 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 or socket message
void parseUevent(std::set<std::string> *sensors_set);
void parseMsg(std::set<std::string> *sensors_set);
// 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_;
// listen thermal info from theraml core via thermal hal socket
// uevent socket registration for legancy tz map
android::base::unique_fd event_fd_;
// 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_;
int tz_map_version;
};
} // namespace implementation
} // namespace V2_0
} // namespace thermal
} // namespace hardware
} // namespace android

View File

@@ -376,9 +376,7 @@ PRODUCT_COPY_FILES += \
$(call inherit-product, hardware/oplus/power-libperfmgr/power-libperfmgr.mk)
PRODUCT_PACKAGES += \
vendor.mediatek.hardware.mtkpower@1.2-service.stub \
libmtkperf_client_vendor \
libmtkperf_client
vendor.mediatek.hardware.mtkpower@1.2-service.stub
PRODUCT_PACKAGES += \
android.hardware.power@1.2.vendor \
@@ -500,7 +498,7 @@ PRODUCT_PACKAGES += \
# USB
PRODUCT_PACKAGES += \
android.hardware.usb@1.3-service-mediatekv2
android.hardware.usb-service.mediatek
# Vibrator
PRODUCT_PACKAGES += \