• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, size, size - 1, format, name) < EOK) {
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             THERMAL_HILOGI(COMP_HDI, "init sysfs info of %{public}s", sysfsInfo.name);
109             int32_t ret = sscanf_s(sysfsInfo.name, THERMAL_ZONE_DIR_NAME.c_str(), &id);
110             if (ret < HDF_SUCCESS) {
111                 closedir(dir);
112                 return ret;
113             }
114 
115             THERMAL_HILOGI(COMP_HDI, "Sensor %{public}s found at tz: %{public}d", sysfsInfo.name, id);
116             sysfsInfo.fd = id;
117             if (index > MAX_SYSFS_SIZE) {
118                 THERMAL_HILOGE(COMP_HDI, "too many plugged types");
119                 break;
120             }
121 
122             FormatThermalSysfsPaths(&sysfsInfo);
123             index++;
124         }
125     }
126     closedir(dir);
127     return HDF_SUCCESS;
128 }
129 
Trim(char * str) const130 inline void ThermalZoneManager::Trim(char* str) const
131 {
132     if (str == nullptr) {
133         return;
134     }
135 
136     str[strcspn(str, "\n")] = 0;
137 }
138 
ReadSysfsFile(const char * path,char * buf,size_t size) const139 int32_t ThermalZoneManager::ReadSysfsFile(const char* path, char* buf, size_t size) const
140 {
141     int32_t readSize;
142     int32_t fd = open(path, O_RDONLY, S_IRUSR | S_IRGRP | S_IROTH);
143     if (fd < NUM_ZERO) {
144         THERMAL_HILOGW(COMP_HDI, "failed to open file");
145         return HDF_ERR_IO;
146     }
147 
148     readSize = read(fd, buf, size - 1);
149     if (readSize < NUM_ZERO) {
150         THERMAL_HILOGW(COMP_HDI, "failed to read file");
151         close(fd);
152         return HDF_ERR_IO;
153     }
154 
155     buf[readSize] = '\0';
156     Trim(buf);
157     close(fd);
158 
159     return HDF_SUCCESS;
160 }
161 
ReadThermalSysfsToBuff(const char * path,char * buf,size_t size) const162 int32_t ThermalZoneManager::ReadThermalSysfsToBuff(const char* path, char* buf, size_t size) const
163 {
164     int32_t ret = ReadSysfsFile(path, buf, size);
165     if (ret != HDF_SUCCESS) {
166         THERMAL_HILOGW(COMP_HDI, "read path failed, ret: %{public}d", ret);
167         return ret;
168     }
169 
170     return HDF_SUCCESS;
171 }
172 
ParseThermalZoneInfo()173 int32_t ThermalZoneManager::ParseThermalZoneInfo()
174 {
175     int32_t ret;
176     char bufType[MAX_BUFF_SIZE] = {0};
177     THERMAL_HILOGD(COMP_HDI, "start to parse thermal zone");
178 
179     ret = InitThermalZoneSysfs();
180     if (ret != HDF_SUCCESS) {
181         THERMAL_HILOGE(COMP_HDI, "failed to init thermal zone node");
182     }
183     std::map<std::string, std::string> tzPathMap;
184     if (!lTzSysPathInfo_.empty()) {
185         THERMAL_HILOGI(COMP_HDI, "tzInfo.size=%{public}zu", GetLTZPathInfo().size());
186         for (auto iter = lTzSysPathInfo_.begin(); iter != lTzSysPathInfo_.end(); iter++) {
187             ret = ReadThermalSysfsToBuff(iter->typePath, bufType, sizeof(bufType));
188             if (ret != HDF_SUCCESS) {
189                 THERMAL_HILOGE(COMP_HDI, "failed to read thermal zone type");
190                 return ret;
191             }
192             std::string tzType = bufType;
193             tzPathMap.insert(std::make_pair(tzType, iter->temperturePath));
194         }
195     }
196     return UpdateThermalZoneData(tzPathMap);
197 }
198 
UpdateDataType(XMLThermalZoneInfo & tzIter,ReportedThermalData & data)199 void ThermalZoneManager::UpdateDataType(XMLThermalZoneInfo& tzIter, ReportedThermalData& data)
200 {
201     if (tzIter.isReplace) {
202         data.type = tzIter.isReplace;
203     } else {
204         data.type = tzIter.type;
205     }
206 }
207 
UpdateThermalZoneData(std::map<std::string,std::string> & tzPathMap)208 int32_t ThermalZoneManager::UpdateThermalZoneData(std::map<std::string, std::string> &tzPathMap)
209 {
210     int32_t reportTime = 1;
211     std::vector<int32_t> multipleList;
212     {
213         // Multi-threaded access to sensorTypeMap_ requires locking
214         std::lock_guard<std::mutex> lock(mutex_);
215         for (auto sensorIter : sensorTypeMap_) {
216             auto tzInfoList = sensorIter.second->GetXMLThermalZoneInfo();
217             auto tnInfoList = sensorIter.second->GetXMLThermalNodeInfo();
218             sensorIter.second->thermalDataList_.clear();
219             for (auto tzIter : tzInfoList) {
220                 if (tzPathMap.empty()) {
221                     break;
222                 }
223                 auto typeIter = tzPathMap.find(tzIter.type);
224                 if (typeIter != tzPathMap.end()) {
225                     ReportedThermalData data;
226                     UpdateDataType(tzIter, data);
227                     data.tempPath = typeIter->second;
228                     sensorIter.second->thermalDataList_.push_back(data);
229                 }
230             }
231             for (auto tnIter : tnInfoList) {
232                 ReportedThermalData data;
233                 data.type = tnIter.type;
234                 if (access(tnIter.path.c_str(), 0) == NUM_ZERO) {
235                     THERMAL_HILOGD(COMP_HDI, "This directory already exists.");
236                     data.tempPath = tnIter.path;
237                 }
238                 sensorIter.second->thermalDataList_.push_back(data);
239             }
240         }
241     }
242     multipleList.push_back(reportTime);
243     CalculateMaxCd();
244     ReportThermalZoneData(reportTime, multipleList);
245     return HDF_SUCCESS;
246 }
247 
ClearThermalZoneInfo()248 void ThermalZoneManager::ClearThermalZoneInfo()
249 {
250     if (!tzInfoList_.empty()) {
251         tzInfoList_.clear();
252     } else {
253         return;
254     }
255 }
256 
CalculateMaxCd()257 void ThermalZoneManager::CalculateMaxCd()
258 {
259     std::lock_guard<std::mutex> lock(mutex_);
260     sensorTypeMap_ = ThermalHdfConfig::GetInsance().GetSensorTypeMap();
261     if (sensorTypeMap_.empty()) {
262         THERMAL_HILOGE(COMP_HDI, "configured sensor info is empty");
263         return;
264     }
265 
266     std::vector<int32_t> intervalList;
267     std::transform(sensorTypeMap_.begin(), sensorTypeMap_.end(), std::back_inserter(intervalList),
268         [](auto& sensorIter) { return sensorIter.second->GetInterval(); });
269 
270     maxCd_ = GetIntervalCommonDivisor(intervalList);
271     THERMAL_HILOGI(COMP_HDI, "maxCd_ %{public}d", maxCd_);
272 }
273 
GetMaxCommonDivisor(int32_t a,int32_t b)274 int32_t ThermalZoneManager::GetMaxCommonDivisor(int32_t a, int32_t b)
275 {
276     if (b == 0) {
277         return NUM_ZERO;
278     }
279 
280     if (a % b == 0) {
281         return b;
282     } else {
283         return GetMaxCommonDivisor(b, a % b);
284     }
285 }
286 
GetIntervalCommonDivisor(std::vector<int32_t> intervalList)287 int32_t ThermalZoneManager::GetIntervalCommonDivisor(std::vector<int32_t> intervalList)
288 {
289     if (intervalList.empty()) {
290         return ARG_0;
291     }
292 
293     int32_t count = intervalList.size();
294     int32_t commonDivisor = intervalList[0];
295     for (int32_t i = 1; i < count; i++) {
296         commonDivisor = GetMaxCommonDivisor(commonDivisor, intervalList[i]);
297     }
298     return commonDivisor;
299 }
300 
SetMultiples()301 void ThermalZoneManager::SetMultiples()
302 {
303     if (maxCd_ == NUM_ZERO) {
304         return;
305     }
306     for (auto sensorIter : sensorTypeMap_) {
307         sensorIter.second->multiple_ = (sensorIter.second->GetInterval()) / maxCd_;
308     }
309     ThermalHdfConfig::GetInsance().SetSensorTypeMap(sensorTypeMap_);
310 }
311 
ReportThermalZoneData(int32_t reportTime,std::vector<int32_t> & multipleList)312 void ThermalZoneManager::ReportThermalZoneData(int32_t reportTime, std::vector<int32_t> &multipleList)
313 {
314     std::lock_guard<std::mutex> lock(mutex_);
315     char tempBuf[MAX_BUFF_SIZE] = {0};
316     if (sensorTypeMap_.empty()) {
317         THERMAL_HILOGD(COMP_HDI, "sensorTypeMap is empty");
318         return;
319     }
320 
321     int32_t ret;
322     tzInfoAcaualEvent_.info.clear();
323     multipleList.clear();
324     for (auto sensorIter : sensorTypeMap_) {
325         multipleList.push_back(sensorIter.second->multiple_);
326         if (sensorIter.second->multiple_ == NUM_ZERO) {
327             return;
328         }
329         THERMAL_HILOGD(COMP_HDI, "multiple %{public}d", sensorIter.second->multiple_);
330         if (reportTime % (sensorIter.second->multiple_) == NUM_ZERO) {
331             for (auto iter : sensorIter.second->thermalDataList_) {
332                 THERMAL_HILOGD(COMP_HDI, "data type %{public}s", iter.type.c_str());
333                 ThermalZoneInfo info;
334                 info.type = iter.type;
335                 ret = ReadThermalSysfsToBuff(iter.tempPath.c_str(), tempBuf, sizeof(tempBuf));
336                 if (ret != NUM_ZERO) {
337                     THERMAL_HILOGE(COMP_HDI, "failed to read thermal zone temp");
338                     continue;
339                 }
340                 info.temp = ConvertInt(tempBuf);
341                 THERMAL_HILOGD(COMP_HDI, "temp=%{public}d", info.temp);
342                 tzInfoAcaualEvent_.info.push_back(info);
343             }
344         }
345     }
346 }
347 } // V1_0
348 } // Thermal
349 } // HDI
350 } // OHOS
351