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