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
34 using namespace std;
35
36 namespace OHOS {
37 namespace HDI {
38 namespace Thermal {
39 namespace V1_1 {
40 namespace {
41 const std::string THERMAL_ZONE_TEMP_PATH = "/sys/class/thermal/thermal_zone%d/temp";
42 const std::string THERMAL_ZONE_TYPE_PATH = "/sys/class/thermal/thermal_zone%d/type";
43 const int32_t MAX_THERMAL_ZONE_NUM = 200;
44 const int32_t MAX_PATH_LEN = 64;
45 const int32_t NUM_ZERO = 0;
46 }
47
Init()48 void ThermalZoneManager::Init()
49 {
50 std::lock_guard<std::mutex> lock(mutex_);
51 InitThermalZoneSysfs();
52 pollingMap_ = ThermalHdfConfig::GetInstance().GetPollingConfig();
53 }
54
InitThermalZoneSysfs()55 void 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
UpdateDataType(XMLThermalZoneInfo & tzIter,ReportedThermalData & data,int32_t tzn)73 void 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
UpdateThermalZoneInfo(std::shared_ptr<SensorInfoConfig> & infoConfig)88 void 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
UpdateThermalZoneData()115 int32_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
CalculateMaxCd()131 void 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
GetIntervalCommonDivisor(std::vector<int32_t> intervalList)164 int32_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
CollectCallbackInfo(HdfThermalCallbackInfo & callbackInfo,const std::shared_ptr<SensorInfoConfig> & sensorInfo,int32_t reportTime)178 void 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
ReportThermalZoneData(int32_t reportTime)198 void 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
CallbackOnEvent(std::string name,HdfThermalCallbackInfo & info)215 void 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
GetCallbackInfo()230 HdfThermalCallbackInfo 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
DumpPollingInfo()252 void 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