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/osal_mem.h"
31 #include "thermal_log.h"
32
33 using namespace std;
34
35 namespace OHOS {
36 namespace HDI {
37 namespace Thermal {
38 namespace V1_0 {
39 namespace {
40 const int32_t MAX_BUFF_SIZE = 128;
41 const int32_t MAX_SYSFS_SIZE = 128;
42 const std::string THERMAL_SYSFS = "/sys/devices/virtual/thermal";
43 const std::string THERMAL_ZONE_DIR_NAME = "thermal_zone%d";
44 const std::string COOLING_DEVICE_DIR_NAME = "cooling_device%d";
45 const std::string THERMAL_ZONE_DIR_PATH = "/sys/class/thermal/%s";
46 const std::string THERMAL_TEMPERATURE_PATH = "/sys/class/thermal/%s/temp";
47 const std::string THEERMAL_TYPE_PATH = "/sys/class/thermal/%s/type";
48 const std::string CDEV_DIR_NAME = "cooling_device";
49 const std::string THERMAL_ZONE_TEMP_PATH_NAME = "/sys/class/thermal/thermal_zone%d/temp";
50 const uint32_t ARG_0 = 0;
51 const int32_t NUM_ZERO = 0;
52 }
53
FormatThermalPaths(char * path,size_t size,const char * format,const char * name)54 void ThermalZoneManager::FormatThermalPaths(char *path, size_t size, const char *format, const char* name)
55 {
56 if (snprintf_s(path, PATH_MAX, size - 1, format, name) < HDF_SUCCESS) {
57 THERMAL_HILOGW(COMP_HDI, "failed to format path of %{public}s", name);
58 }
59 }
60
FormatThermalSysfsPaths(struct ThermalSysfsPathInfo * pTSysPathInfo)61 void ThermalZoneManager::FormatThermalSysfsPaths(struct ThermalSysfsPathInfo *pTSysPathInfo)
62 {
63 // Format Paths for thermal path
64 FormatThermalPaths(pTSysPathInfo->thermalZonePath, sizeof(pTSysPathInfo->thermalZonePath),
65 THERMAL_ZONE_DIR_PATH.c_str(), pTSysPathInfo->name);
66 // Format paths for thermal zone node
67 tzSysPathInfo_.name = pTSysPathInfo->name;
68 FormatThermalPaths(tzSysPathInfo_.temperturePath, sizeof(tzSysPathInfo_.temperturePath),
69 THERMAL_TEMPERATURE_PATH.c_str(), pTSysPathInfo->name);
70
71 FormatThermalPaths(tzSysPathInfo_.typePath, sizeof(tzSysPathInfo_.typePath),
72 THEERMAL_TYPE_PATH.c_str(), pTSysPathInfo->name);
73
74 tzSysPathInfo_.fd = pTSysPathInfo->fd;
75 lTzSysPathInfo_.push_back(tzSysPathInfo_);
76 }
77
InitThermalZoneSysfs()78 int32_t ThermalZoneManager::InitThermalZoneSysfs()
79 {
80 DIR *dir = NULL;
81 struct dirent *entry = NULL;
82 int32_t index = 0;
83 int32_t id = 0;
84
85 dir = opendir(THERMAL_SYSFS.c_str());
86 if (dir == NULL) {
87 THERMAL_HILOGE(COMP_HDI, "cannot open thermal zone path");
88 return HDF_ERR_IO;
89 }
90
91 while (true) {
92 entry = readdir(dir);
93 if (entry == NULL) {
94 break;
95 }
96
97 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
98 continue;
99 }
100
101 if (strncmp(entry->d_name, CDEV_DIR_NAME.c_str(), CDEV_DIR_NAME.size()) == 0) {
102 continue;
103 }
104
105 if (entry->d_type == DT_DIR || entry->d_type == DT_LNK) {
106 struct ThermalSysfsPathInfo sysfsInfo = {0};
107 sysfsInfo.name = entry->d_name;
108 int32_t ret = sscanf_s(sysfsInfo.name, THERMAL_ZONE_DIR_NAME.c_str(), &id);
109 if (ret < HDF_SUCCESS) {
110 return ret;
111 }
112
113 sysfsInfo.fd = id;
114 if (index > MAX_SYSFS_SIZE) {
115 THERMAL_HILOGE(COMP_HDI, "too many plugged types");
116 break;
117 }
118
119 FormatThermalSysfsPaths(&sysfsInfo);
120 index++;
121 }
122 }
123 closedir(dir);
124 return HDF_SUCCESS;
125 }
126
Trim(char * str) const127 inline void ThermalZoneManager::Trim(char* str) const
128 {
129 if (str == nullptr) {
130 return;
131 }
132
133 str[strcspn(str, "\n")] = 0;
134 }
135
ReadSysfsFile(const char * path,char * buf,size_t size) const136 int32_t ThermalZoneManager::ReadSysfsFile(const char* path, char* buf, size_t size) const
137 {
138 int32_t readSize;
139 int32_t fd = open(path, O_RDONLY);
140 if (fd < NUM_ZERO) {
141 THERMAL_HILOGE(COMP_HDI, "failed to open %{public}s", path);
142 return HDF_ERR_IO;
143 }
144
145 readSize = read(fd, buf, size - 1);
146 if (readSize < NUM_ZERO) {
147 THERMAL_HILOGE(COMP_HDI, "failed to read %{public}s", path);
148 close(fd);
149 return HDF_ERR_IO;
150 }
151
152 buf[readSize] = '\0';
153 Trim(buf);
154 close(fd);
155
156 return HDF_SUCCESS;
157 }
158
ReadThermalSysfsToBuff(const char * path,char * buf,size_t size) const159 int32_t ThermalZoneManager::ReadThermalSysfsToBuff(const char* path, char* buf, size_t size) const
160 {
161 int32_t ret = ReadSysfsFile(path, buf, size);
162 if (ret != HDF_SUCCESS) {
163 THERMAL_HILOGW(COMP_HDI, "read path %{private}s failed, ret: %{public}d", path, ret);
164 return ret;
165 }
166
167 return HDF_SUCCESS;
168 }
169
ParseThermalZoneInfo()170 int32_t ThermalZoneManager::ParseThermalZoneInfo()
171 {
172 int32_t ret;
173 char bufType[MAX_BUFF_SIZE] = {0};
174 THERMAL_HILOGD(COMP_HDI, "start to parse thermal zone");
175
176 ret = InitThermalZoneSysfs();
177 if (ret != HDF_SUCCESS) {
178 THERMAL_HILOGE(COMP_HDI, "failed to init thermal zone node");
179 }
180 std::map<std::string, std::string> tzPathMap;
181 if (!lTzSysPathInfo_.empty()) {
182 for (auto iter = lTzSysPathInfo_.begin(); iter != lTzSysPathInfo_.end(); iter++) {
183 ret = ReadThermalSysfsToBuff(iter->typePath, bufType, sizeof(bufType));
184 if (ret != HDF_SUCCESS) {
185 THERMAL_HILOGE(COMP_HDI, "failed to read thermal zone type");
186 return ret;
187 }
188 std::string tzType = bufType;
189 tzPathMap.insert(std::make_pair(tzType, iter->temperturePath));
190 }
191 }
192 return UpdateThermalZoneData(tzPathMap);
193 }
194
UpdateThermalZoneData(std::map<std::string,std::string> & tzPathMap)195 int32_t ThermalZoneManager::UpdateThermalZoneData(std::map<std::string, std::string> &tzPathMap)
196 {
197 for (auto sensorIter : sensorTypeMap_) {
198 auto tzInfoList = sensorIter.second->GetXMLThermalZoneInfo();
199 auto tnInfoList = sensorIter.second->GetXMLThermalNodeInfo();
200 for (auto tzIter : tzInfoList) {
201 if (tzPathMap.empty()) {
202 break;
203 }
204 auto typeIter = tzPathMap.find(tzIter.type);
205 if (typeIter != tzPathMap.end()) {
206 ReportedThermalData data;
207 if (tzIter.isReplace) {
208 data.type = tzIter.isReplace;
209 } else {
210 data.type = tzIter.type;
211 }
212 data.tempPath = typeIter->second;
213 sensorIter.second->thermalDataList_.push_back(data);
214 }
215 }
216 for (auto tnIter : tnInfoList) {
217 ReportedThermalData data;
218 data.type = tnIter.type;
219 if (access(tnIter.path.c_str(), 0) == NUM_ZERO) {
220 THERMAL_HILOGD(COMP_HDI, "This directory already exists.");
221 data.tempPath = tnIter.path;
222 }
223 sensorIter.second->thermalDataList_.push_back(data);
224 }
225 }
226 return HDF_SUCCESS;
227 }
228
ClearThermalZoneInfo()229 void ThermalZoneManager::ClearThermalZoneInfo()
230 {
231 if (!tzInfoList_.empty()) {
232 tzInfoList_.clear();
233 } else {
234 return;
235 }
236 }
237
CalculateMaxCd()238 void ThermalZoneManager::CalculateMaxCd()
239 {
240 sensorTypeMap_ = ThermalHdfConfig::GetInsance().GetSensorTypeMap();
241 if (sensorTypeMap_.empty()) {
242 THERMAL_HILOGE(COMP_HDI, "configed sensor info is empty");
243 return;
244 }
245
246 std::vector<int32_t> intervalList;
247 if (!sensorTypeMap_.empty()) {
248 for (auto sensorIter : sensorTypeMap_) {
249 intervalList.push_back(sensorIter.second->GetInterval());
250 }
251 }
252 maxCd_ = GetIntervalCommonDivisor(intervalList);
253 }
254
GetMaxCommonDivisor(int32_t a,int32_t b)255 int32_t ThermalZoneManager::GetMaxCommonDivisor(int32_t a, int32_t b)
256 {
257 if (b == 0) {
258 return NUM_ZERO;
259 }
260
261 if (a % b == 0) {
262 return b;
263 } else {
264 return GetMaxCommonDivisor(b, a % b);
265 }
266 }
267
GetIntervalCommonDivisor(std::vector<int32_t> intervalList)268 int32_t ThermalZoneManager::GetIntervalCommonDivisor(std::vector<int32_t> intervalList)
269 {
270 if (intervalList.empty()) {
271 return ARG_0;
272 }
273
274 int32_t count = intervalList.size();
275 int32_t commonDivisor = intervalList[0];
276 for (int32_t i = 1; i < count; i++) {
277 commonDivisor = GetMaxCommonDivisor(commonDivisor, intervalList[i]);
278 }
279 return commonDivisor;
280 }
281
SetMultiples()282 void ThermalZoneManager::SetMultiples()
283 {
284 if (maxCd_ == NUM_ZERO) {
285 return;
286 }
287 for (auto sensorIter : sensorTypeMap_) {
288 sensorIter.second->multiple_ = (sensorIter.second->GetInterval()) / maxCd_;
289 }
290 ThermalHdfConfig::GetInsance().SetSensorTypeMap(sensorTypeMap_);
291 }
292
ReportThermalZoneData(int32_t reportTime,std::vector<int32_t> & multipleList)293 void ThermalZoneManager::ReportThermalZoneData(int32_t reportTime, std::vector<int32_t> &multipleList)
294 {
295 char tempBuf[MAX_BUFF_SIZE] = {0};
296 if (sensorTypeMap_.empty()) {
297 return;
298 }
299
300 int32_t ret;
301 tzInfoAcaualEvent_.info.clear();
302 multipleList.clear();
303 for (auto sensorIter : sensorTypeMap_) {
304 multipleList.push_back(sensorIter.second->multiple_);
305 if (sensorIter.second->multiple_ == NUM_ZERO) {
306 return;
307 }
308 if (reportTime % (sensorIter.second->multiple_) == NUM_ZERO) {
309 for (auto iter : sensorIter.second->thermalDataList_) {
310 ThermalZoneInfo info;
311 info.type = iter.type;
312 ret = ReadThermalSysfsToBuff(iter.tempPath.c_str(), tempBuf, sizeof(tempBuf));
313 if (ret != NUM_ZERO) {
314 continue;
315 }
316 info.temp = ConvertInt(tempBuf);
317 tzInfoAcaualEvent_.info.push_back(info);
318 }
319 }
320 }
321 }
322 } // V1_0
323 } // Thermal
324 } // HDI
325 } // OHOS
326