1/* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16#include "thermal_zone_manager.h" 17 18#include <cstdio> 19#include <cstring> 20#include <vector> 21#include <string> 22#include <iostream> 23#include <dirent.h> 24#include <fcntl.h> 25#include <climits> 26#include <securec.h> 27#include <unistd.h> 28#include <sys/types.h> 29 30#include "osal_mem.h" 31#include "thermal_hdf_utils.h" 32#include "thermal_log.h" 33 34using namespace std; 35 36namespace OHOS { 37namespace HDI { 38namespace Thermal { 39namespace V1_1 { 40namespace { 41const std::string THERMAL_ZONE_TEMP_PATH = "/sys/class/thermal/thermal_zone%d/temp"; 42const std::string THERMAL_ZONE_TYPE_PATH = "/sys/class/thermal/thermal_zone%d/type"; 43const int32_t MAX_THERMAL_ZONE_NUM = 200; 44const int32_t MAX_PATH_LEN = 64; 45const int32_t NUM_ZERO = 0; 46} 47 48void ThermalZoneManager::Init() 49{ 50 std::lock_guard<std::mutex> lock(mutex_); 51 InitThermalZoneSysfs(); 52 pollingMap_ = ThermalHdfConfig::GetInstance().GetPollingConfig(); 53} 54 55void ThermalZoneManager::InitThermalZoneSysfs() 56{ 57 int32_t maxTzNum = 0; 58 for (int32_t idx = 0; idx < MAX_THERMAL_ZONE_NUM; ++idx) { 59 char path[MAX_PATH_LEN]; 60 if (sprintf_s(path, MAX_PATH_LEN, THERMAL_ZONE_TYPE_PATH.c_str(), idx) <= 0) { 61 break; 62 } 63 std::string type; 64 if (!ThermalHdfUtils::ReadNode(path, type)) { 65 break; 66 } 67 tznMap_[type] = idx; 68 maxTzNum = idx; 69 } 70 THERMAL_HILOGI(COMP_HDI, "max thermal zone num is %{public}d", maxTzNum); 71} 72 73void ThermalZoneManager::UpdateDataType(XMLThermalZoneInfo& tzIter, ReportedThermalData& data, int32_t tzn) 74{ 75 if (tzIter.isReplace) { 76 data.type = tzIter.replace; 77 } else { 78 data.type = tzIter.type; 79 } 80 char path[MAX_PATH_LEN]; 81 if (sprintf_s(path, MAX_PATH_LEN, THERMAL_ZONE_TEMP_PATH.c_str(), tzn) > 0) { 82 data.tempPath = path; 83 } else { 84 THERMAL_HILOGE(COMP_HDI, "thermal zone path format failed, num is %{public}d", tzn); 85 } 86} 87 88void ThermalZoneManager::UpdateThermalZoneInfo(std::shared_ptr<SensorInfoConfig> &infoConfig) 89{ 90 auto tzInfoList = infoConfig->GetXMLThermalZoneInfo(); 91 auto tnInfoList = infoConfig->GetXMLThermalNodeInfo(); 92 infoConfig->thermalDataList_.clear(); 93 for (auto tzIter : tzInfoList) { 94 if (tznMap_.empty()) { 95 break; 96 } 97 auto typeIter = tznMap_.find(tzIter.type); 98 if (typeIter != tznMap_.end()) { 99 ReportedThermalData data; 100 UpdateDataType(tzIter, data, typeIter->second); 101 infoConfig->thermalDataList_.push_back(data); 102 } 103 } 104 for (auto tnIter : tnInfoList) { 105 ReportedThermalData data; 106 data.type = tnIter.type; 107 if (access(tnIter.path.c_str(), 0) == NUM_ZERO) { 108 THERMAL_HILOGD(COMP_HDI, "This directory already exists."); 109 data.tempPath = tnIter.path; 110 } 111 infoConfig->thermalDataList_.push_back(data); 112 } 113} 114 115int32_t ThermalZoneManager::UpdateThermalZoneData() 116{ 117 { 118 // Multi-thread access to pollingMap_ require lock 119 std::lock_guard<std::mutex> lock(mutex_); 120 for (auto &polling : pollingMap_) { 121 for (auto &group : polling.second) { 122 UpdateThermalZoneInfo(group.second); 123 } 124 } 125 } 126 127 CalculateMaxCd(); 128 return HDF_SUCCESS; 129} 130 131void ThermalZoneManager::CalculateMaxCd() 132{ 133 std::lock_guard<std::mutex> lock(mutex_); 134 135 if (pollingMap_.empty()) { 136 THERMAL_HILOGE(COMP_HDI, "configured sensor info is empty"); 137 return; 138 } 139 std::vector<int32_t> intervalList; 140 for (auto &polling : pollingMap_) { 141 for (auto &group : polling.second) { 142 intervalList.emplace_back(group.second->GetInterval()); 143 } 144 } 145 146 maxCd_ = GetIntervalCommonDivisor(intervalList); 147 if (maxCd_ == 0) { 148 return; 149 } 150 151 int32_t maxMultiple = 0; 152 for (auto &polling : pollingMap_) { 153 for (auto &group : polling.second) { 154 group.second->multiple_ = group.second->GetInterval() / maxCd_; 155 maxMultiple = std::max(maxMultiple, group.second->multiple_); 156 } 157 } 158 maxReportTime_ = maxMultiple; 159 160 THERMAL_HILOGI(COMP_HDI, "maxCd_ %{public}d maxReportTime_ %{public}d", maxCd_, maxReportTime_); 161 return; 162} 163 164int32_t ThermalZoneManager::GetIntervalCommonDivisor(std::vector<int32_t> intervalList) 165{ 166 if (intervalList.empty()) { 167 return NUM_ZERO; 168 } 169 170 uint32_t count = intervalList.size(); 171 int32_t commonDivisor = intervalList[0]; 172 for (uint32_t i = 1; i < count; i++) { 173 commonDivisor = ThermalHdfUtils::GetMaxCommonDivisor(commonDivisor, intervalList[i]); 174 } 175 return commonDivisor; 176} 177 178void ThermalZoneManager::CollectCallbackInfo( 179 HdfThermalCallbackInfo &callbackInfo, const std::shared_ptr<SensorInfoConfig> &sensorInfo, int32_t reportTime) 180{ 181 if (sensorInfo->multiple_ == NUM_ZERO) { 182 return; 183 } 184 185 if (reportTime % (sensorInfo->multiple_) == NUM_ZERO) { 186 for (auto iter : sensorInfo->thermalDataList_) { 187 ThermalZoneInfo info; 188 info.type = iter.type; 189 info.temp = ThermalHdfUtils::ReadNodeToInt(iter.tempPath); 190 THERMAL_HILOGD(COMP_HDI, "type: %{public}s temp: %{public}d", iter.type.c_str(), info.temp); 191 callbackInfo.info.emplace_back(info); 192 } 193 } 194 195 return; 196} 197 198void ThermalZoneManager::ReportThermalZoneData(int32_t reportTime) 199{ 200 std::lock_guard<std::mutex> lock(mutex_); 201 202 for (auto &polling : pollingMap_) { 203 HdfThermalCallbackInfo callbackInfo; 204 for (auto &group : polling.second) { 205 CollectCallbackInfo(callbackInfo, group.second, reportTime); 206 } 207 if (!callbackInfo.info.empty()) { 208 CallbackOnEvent(polling.first, callbackInfo); 209 } 210 } 211 212 return; 213} 214 215void ThermalZoneManager::CallbackOnEvent(std::string name, HdfThermalCallbackInfo &info) 216{ 217 if (name == "thermal") { 218 if (thermalCb_ != nullptr) { 219 thermalCb_->OnThermalDataEvent(info); 220 } 221 } else if (name == "fan") { 222 if (fanCb_ != nullptr) { 223 fanCb_->OnFanDataEvent(info); 224 } 225 } 226 227 return; 228} 229 230HdfThermalCallbackInfo ThermalZoneManager::GetCallbackInfo() 231{ 232 HdfThermalCallbackInfo callbackInfo; 233 std::lock_guard<std::mutex> lock(mutex_); 234 235 for (auto &polling : pollingMap_) { 236 if (polling.first == "fan") { 237 continue; 238 } 239 for (auto &group : polling.second) { 240 for (auto iter : group.second->thermalDataList_) { 241 ThermalZoneInfo info; 242 info.type = iter.type; 243 info.temp = ThermalHdfUtils::ReadNodeToInt(iter.tempPath); 244 callbackInfo.info.emplace_back(info); 245 } 246 } 247 } 248 249 return callbackInfo; 250} 251 252void ThermalZoneManager::DumpPollingInfo() 253{ 254 std::lock_guard<std::mutex> lock(mutex_); 255 256 for (auto &polling : pollingMap_) { 257 THERMAL_HILOGI(COMP_HDI, "pollingName %{public}s", polling.first.c_str()); 258 for (auto &group : polling.second) { 259 THERMAL_HILOGI(COMP_HDI, "groupName %{public}s, interval %{public}d, multiple %{public}d", 260 group.first.c_str(), group.second->GetInterval(), group.second->multiple_); 261 for (auto tzIter : group.second->GetXMLThermalZoneInfo()) { 262 THERMAL_HILOGI(COMP_HDI, "type %{public}s, replace %{public}s", tzIter.type.c_str(), 263 tzIter.replace.c_str()); 264 } 265 for (auto tnIter : group.second->GetXMLThermalNodeInfo()) { 266 THERMAL_HILOGI(COMP_HDI, "type %{public}s", tnIter.type.c_str()); 267 } 268 for (auto dataIter : group.second->thermalDataList_) { 269 THERMAL_HILOGI(COMP_HDI, "data type %{public}s", dataIter.type.c_str()); 270 } 271 } 272 } 273} 274} // V1_1 275} // Thermal 276} // HDI 277} // OHOS 278