• 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_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 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 
Init()54 void ThermalZoneManager::Init()
55 {
56     std::lock_guard<std::mutex> lock(mutex_);
57     pollingMap_ = ThermalHdfConfig::GetInstance().GetPollingConfig();
58 }
59 
FormatThermalPaths(char * path,size_t size,const char * format,const char * name)60 void ThermalZoneManager::FormatThermalPaths(char *path, size_t size, const char *format, const char* name)
61 {
62     if (snprintf_s(path, size, size - 1, format, name) < EOK) {
63         THERMAL_HILOGW(COMP_HDI, "failed to format path of %{public}s", name);
64     }
65 }
66 
FormatThermalSysfsPaths(struct ThermalSysfsPathInfo * pTSysPathInfo)67 void ThermalZoneManager::FormatThermalSysfsPaths(struct ThermalSysfsPathInfo *pTSysPathInfo)
68 {
69     // Format Paths for thermal path
70     FormatThermalPaths(pTSysPathInfo->thermalZonePath, sizeof(pTSysPathInfo->thermalZonePath),
71         THERMAL_ZONE_DIR_PATH.c_str(), pTSysPathInfo->name);
72     // Format paths for thermal zone node
73     tzSysPathInfo_.name = pTSysPathInfo->name;
74     FormatThermalPaths(tzSysPathInfo_.temperturePath, sizeof(tzSysPathInfo_.temperturePath),
75         THERMAL_TEMPERATURE_PATH.c_str(), pTSysPathInfo->name);
76 
77     FormatThermalPaths(tzSysPathInfo_.typePath, sizeof(tzSysPathInfo_.typePath),
78         THEERMAL_TYPE_PATH.c_str(), pTSysPathInfo->name);
79 
80     tzSysPathInfo_.fd = pTSysPathInfo->fd;
81     lTzSysPathInfo_.push_back(tzSysPathInfo_);
82 }
83 
InitThermalZoneSysfs()84 int32_t ThermalZoneManager::InitThermalZoneSysfs()
85 {
86     DIR *dir = NULL;
87     struct dirent *entry = NULL;
88     int32_t index = 0;
89     int32_t id = 0;
90 
91     dir = opendir(THERMAL_SYSFS.c_str());
92     if (dir == NULL) {
93         THERMAL_HILOGE(COMP_HDI, "cannot open thermal zone path");
94         return HDF_ERR_IO;
95     }
96 
97     while (true) {
98         entry = readdir(dir);
99         if (entry == NULL) {
100             break;
101         }
102 
103         if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
104             continue;
105         }
106 
107         if (strncmp(entry->d_name, CDEV_DIR_NAME.c_str(), CDEV_DIR_NAME.size()) == 0) {
108             continue;
109         }
110 
111         if (entry->d_type == DT_DIR || entry->d_type == DT_LNK) {
112             struct ThermalSysfsPathInfo sysfsInfo = {0};
113             sysfsInfo.name = entry->d_name;
114             THERMAL_HILOGI(COMP_HDI, "init sysfs info of %{public}s", sysfsInfo.name);
115             int32_t ret = sscanf_s(sysfsInfo.name, THERMAL_ZONE_DIR_NAME.c_str(), &id);
116             if (ret < HDF_SUCCESS) {
117                 closedir(dir);
118                 return ret;
119             }
120 
121             THERMAL_HILOGI(COMP_HDI, "Sensor %{public}s found at tz: %{public}d", sysfsInfo.name, id);
122             sysfsInfo.fd = id;
123             if (index > MAX_SYSFS_SIZE) {
124                 THERMAL_HILOGE(COMP_HDI, "too many plugged types");
125                 break;
126             }
127 
128             FormatThermalSysfsPaths(&sysfsInfo);
129             index++;
130         }
131     }
132     closedir(dir);
133     return HDF_SUCCESS;
134 }
135 
ParseThermalZoneInfo()136 int32_t ThermalZoneManager::ParseThermalZoneInfo()
137 {
138     int32_t ret;
139     THERMAL_HILOGD(COMP_HDI, "start to parse thermal zone");
140 
141     ret = InitThermalZoneSysfs();
142     if (ret != HDF_SUCCESS) {
143         THERMAL_HILOGE(COMP_HDI, "failed to init thermal zone node");
144     }
145     std::map<std::string, std::string> tzPathMap;
146     if (!lTzSysPathInfo_.empty()) {
147         THERMAL_HILOGI(COMP_HDI, "thermal_zone size: %{public}zu", GetLTZPathInfo().size());
148         for (auto iter = lTzSysPathInfo_.begin(); iter != lTzSysPathInfo_.end(); iter++) {
149             std::string tzType;
150             if (!ThermalHdfUtils::ReadNode(iter->typePath, tzType)) {
151                 THERMAL_HILOGE(COMP_HDI, "read tz type failed");
152                 continue;
153             }
154             tzPathMap.insert(std::make_pair(tzType, iter->temperturePath));
155         }
156     }
157     return UpdateThermalZoneData(tzPathMap);
158 }
159 
UpdateDataType(XMLThermalZoneInfo & tzIter,ReportedThermalData & data)160 void ThermalZoneManager::UpdateDataType(XMLThermalZoneInfo& tzIter, ReportedThermalData& data)
161 {
162     if (tzIter.isReplace) {
163         data.type = tzIter.isReplace;
164     } else {
165         data.type = tzIter.type;
166     }
167 }
168 
UpdateThermalZoneData(std::map<std::string,std::string> & tzPathMap)169 int32_t ThermalZoneManager::UpdateThermalZoneData(std::map<std::string, std::string> &tzPathMap)
170 {
171     {
172         // Multi-thread access to pollingMap_ require lock
173         std::lock_guard<std::mutex> lock(mutex_);
174         for (auto &polling : pollingMap_) {
175             for (auto &group : polling.second) {
176                 auto tzInfoList = group.second->GetXMLThermalZoneInfo();
177                 auto tnInfoList = group.second->GetXMLThermalNodeInfo();
178                 group.second->thermalDataList_.clear();
179                 for (auto tzIter : tzInfoList) {
180                     if (tzPathMap.empty()) {
181                         break;
182                     }
183                     auto typeIter = tzPathMap.find(tzIter.type);
184                     if (typeIter != tzPathMap.end()) {
185                         ReportedThermalData data;
186                         UpdateDataType(tzIter, data);
187                         data.tempPath = typeIter->second;
188                         group.second->thermalDataList_.push_back(data);
189                     }
190                 }
191                 for (auto tnIter : tnInfoList) {
192                     ReportedThermalData data;
193                     data.type = tnIter.type;
194                     if (access(tnIter.path.c_str(), 0) == NUM_ZERO) {
195                         THERMAL_HILOGD(COMP_HDI, "This directory already exists.");
196                         data.tempPath = tnIter.path;
197                     }
198                     group.second->thermalDataList_.push_back(data);
199                 }
200             }
201         }
202     }
203     CalculateMaxCd();
204     return HDF_SUCCESS;
205 }
206 
CalculateMaxCd()207 void ThermalZoneManager::CalculateMaxCd()
208 {
209     std::lock_guard<std::mutex> lock(mutex_);
210 
211     if (pollingMap_.empty()) {
212         THERMAL_HILOGE(COMP_HDI, "configured sensor info is empty");
213         return;
214     }
215     std::vector<int32_t> intervalList;
216     for (auto &polling : pollingMap_) {
217         for (auto &group : polling.second) {
218             intervalList.emplace_back(group.second->GetInterval());
219         }
220     }
221 
222     maxCd_ = GetIntervalCommonDivisor(intervalList);
223     if (maxCd_ == 0) {
224         return;
225     }
226 
227     int32_t maxMultiple = 0;
228     for (auto &polling : pollingMap_) {
229         for (auto &group : polling.second) {
230             group.second->multiple_ = group.second->GetInterval() / maxCd_;
231             maxMultiple = std::max(maxMultiple, group.second->multiple_);
232         }
233     }
234     maxReportTime_ = maxMultiple;
235 
236     THERMAL_HILOGI(COMP_HDI, "maxCd_ %{public}d maxReportTime_ %{public}d", maxCd_, maxReportTime_);
237     return;
238 }
239 
GetMaxCommonDivisor(int32_t a,int32_t b)240 int32_t ThermalZoneManager::GetMaxCommonDivisor(int32_t a, int32_t b)
241 {
242     if (b == 0) {
243         return NUM_ZERO;
244     }
245 
246     if (a % b == 0) {
247         return b;
248     } else {
249         return GetMaxCommonDivisor(b, a % b);
250     }
251 }
252 
GetIntervalCommonDivisor(std::vector<int32_t> intervalList)253 int32_t ThermalZoneManager::GetIntervalCommonDivisor(std::vector<int32_t> intervalList)
254 {
255     if (intervalList.empty()) {
256         return ARG_0;
257     }
258 
259     int32_t count = intervalList.size();
260     int32_t commonDivisor = intervalList[0];
261     for (int32_t i = 1; i < count; i++) {
262         commonDivisor = GetMaxCommonDivisor(commonDivisor, intervalList[i]);
263     }
264     return commonDivisor;
265 }
266 
CollectCallbackInfo(HdfThermalCallbackInfo & callbackInfo,const std::shared_ptr<SensorInfoConfig> & sensorInfo,int32_t reportTime)267 void ThermalZoneManager::CollectCallbackInfo(
268     HdfThermalCallbackInfo &callbackInfo, const std::shared_ptr<SensorInfoConfig> &sensorInfo, int32_t reportTime)
269 {
270     if (sensorInfo->multiple_ == NUM_ZERO) {
271         return;
272     }
273 
274     if (reportTime % (sensorInfo->multiple_) == NUM_ZERO) {
275         for (auto iter : sensorInfo->thermalDataList_) {
276             ThermalZoneInfo info;
277             info.type = iter.type;
278             info.temp = ThermalHdfUtils::ReadNodeToInt(iter.tempPath);
279             THERMAL_HILOGD(COMP_HDI, "type: %{public}s temp: %{public}d", iter.type.c_str(), info.temp);
280             callbackInfo.info.emplace_back(info);
281         }
282     }
283 
284     return;
285 }
286 
ReportThermalZoneData(int32_t reportTime)287 void ThermalZoneManager::ReportThermalZoneData(int32_t reportTime)
288 {
289     std::lock_guard<std::mutex> lock(mutex_);
290 
291     for (auto &polling : pollingMap_) {
292         HdfThermalCallbackInfo callbackInfo;
293         for (auto &group : polling.second) {
294             CollectCallbackInfo(callbackInfo, group.second, reportTime);
295         }
296         if (!callbackInfo.info.empty()) {
297             CallbackOnEvent(polling.first, callbackInfo);
298         }
299     }
300 
301     return;
302 }
303 
CallbackOnEvent(std::string name,HdfThermalCallbackInfo & info)304 void ThermalZoneManager::CallbackOnEvent(std::string name, HdfThermalCallbackInfo &info)
305 {
306     if (name == "thermal") {
307         if (thermalCb_ != nullptr) {
308             thermalCb_->OnThermalDataEvent(info);
309         }
310     } else if (name == "fan") {
311         if (fanCb_ != nullptr) {
312             fanCb_->OnFanDataEvent(info);
313         }
314     }
315 
316     return;
317 }
318 
GetCallbackInfo()319 HdfThermalCallbackInfo ThermalZoneManager::GetCallbackInfo()
320 {
321     HdfThermalCallbackInfo callbackInfo;
322     std::lock_guard<std::mutex> lock(mutex_);
323 
324     for (auto &polling : pollingMap_) {
325         if (polling.first == "fan") {
326             continue;
327         }
328         for (auto &group : polling.second) {
329             for (auto iter : group.second->thermalDataList_) {
330                 ThermalZoneInfo info;
331                 info.type = iter.type;
332                 info.temp = ThermalHdfUtils::ReadNodeToInt(iter.tempPath);
333                 callbackInfo.info.emplace_back(info);
334             }
335         }
336     }
337 
338     return callbackInfo;
339 }
340 
DumpPollingInfo()341 void ThermalZoneManager::DumpPollingInfo()
342 {
343     std::lock_guard<std::mutex> lock(mutex_);
344 
345     for (auto &polling : pollingMap_) {
346         THERMAL_HILOGI(COMP_HDI, "pollingName %{public}s", polling.first.c_str());
347         for (auto &group : polling.second) {
348             THERMAL_HILOGI(COMP_HDI, "groupName %{public}s, interval %{public}d, multiple %{public}d",
349                 group.first.c_str(), group.second->GetInterval(), group.second->multiple_);
350             for (auto tzIter : group.second->GetXMLThermalZoneInfo()) {
351                 THERMAL_HILOGI(COMP_HDI, "type %{public}s, replace %{public}s", tzIter.type.c_str(),
352                     tzIter.replace.c_str());
353             }
354             for (auto tnIter : group.second->GetXMLThermalNodeInfo()) {
355                 THERMAL_HILOGI(COMP_HDI, "type %{public}s", tnIter.type.c_str());
356             }
357             for (auto dataIter : group.second->thermalDataList_) {
358                 THERMAL_HILOGI(COMP_HDI, "data type %{public}s", dataIter.type.c_str());
359             }
360         }
361     }
362 }
363 } // V1_1
364 } // Thermal
365 } // HDI
366 } // OHOS
367