1 /*
2 * Copyright (c) 2021 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_sensor_provision.h"
17
18 #include <climits>
19 #include <cerrno>
20 #include <cstdio>
21 #include <cstring>
22 #include <dirent.h>
23 #include <iostream>
24 #include <vector>
25 #include <thread>
26 #include <securec.h>
27 #include <string>
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <sys/epoll.h>
31 #include <sys/timerfd.h>
32 #include <unistd.h>
33
34 #include "thermal_kernel_config_file.h"
35 #include "thermal_common.h"
36 #include "thermal_kernel_service.h"
37
38 namespace OHOS {
39 namespace PowerMgr {
40 namespace {
41 constexpr int32_t MAX_BUFF_SIZE = 128;
42 constexpr int32_t MAX_SYSFS_SIZE = 128;
43 constexpr uint32_t ARG_0 = 0;
44 constexpr int32_t NUM_ZERO = 0;
45 const std::string THERMAL_SYSFS = "/sys/devices/virtual/thermal";
46 const std::string THERMAL_ZONE_DIR_NAME = "thermal_zone%d";
47 const std::string COOLING_DEVICE_DIR_NAME = "cooling_device%d";
48 const std::string THERMAL_ZONE_DIR_PATH = "/sys/class/thermal/%s";
49 const std::string THERMAL_TEMPERATURE_PATH = "/sys/class/thermal/%s/temp";
50 const std::string THEERMAL_TYPE_PATH = "/sys/class/thermal/%s/type";
51 const std::string CDEV_DIR_NAME = "cooling_device";
52 const std::string THERMAL_ZONE_TEMP_PATH_NAME = "/sys/class/thermal/thermal_zone%d/temp";
53 auto &g_service = ThermalKernelService::GetInstance();
54 }
55
InitProvision()56 bool ThermalSensorProvision::InitProvision()
57 {
58 int32_t ret = ParseThermalZoneInfo();
59 if (ret != NUM_ZERO) {
60 return false;
61 }
62 return true;
63 }
64
ReadThermalSysfsToBuff(const char * path,char * buf,size_t size) const65 int32_t ThermalSensorProvision::ReadThermalSysfsToBuff(const char* path, char* buf, size_t size) const
66 {
67 int32_t ret = ReadSysfsFile(path, buf, size);
68 if (ret != ERR_OK) {
69 THERMAL_HILOGW(FEATURE_PROTECTOR, "read path %{private}s failed, ret: %{public}d", path, ret);
70 return ret;
71 }
72
73 return ERR_OK;
74 }
75
ReadSysfsFile(const char * path,char * buf,size_t size) const76 int32_t ThermalSensorProvision::ReadSysfsFile(const char* path, char* buf, size_t size) const
77 {
78 int32_t readSize;
79 int32_t fd = open(path, O_RDONLY);
80 if (fd < NUM_ZERO) {
81 THERMAL_HILOGE(FEATURE_PROTECTOR, "failed to open %{public}s", path);
82 return ERR_INVALID_OPERATION;
83 }
84
85 readSize = read(fd, buf, size - 1);
86 if (readSize < NUM_ZERO) {
87 THERMAL_HILOGE(FEATURE_PROTECTOR, "failed to read %{public}s", path);
88 close(fd);
89 return ERR_INVALID_OPERATION;
90 }
91
92 buf[readSize] = '\0';
93 Trim(buf);
94 close(fd);
95
96 return ERR_OK;
97 }
98
Trim(char * str) const99 inline void ThermalSensorProvision::Trim(char* str) const
100 {
101 if (str == nullptr) {
102 return;
103 }
104
105 str[strcspn(str, "\n")] = 0;
106 }
107
FormatThermalSysfsPaths(struct ThermalSysfsPathInfo * pTSysPathInfo)108 void ThermalSensorProvision::FormatThermalSysfsPaths(struct ThermalSysfsPathInfo *pTSysPathInfo)
109 {
110 // Format Paths for thermal path
111 FormatThermalPaths(pTSysPathInfo->thermalZonePath, sizeof(pTSysPathInfo->thermalZonePath),
112 THERMAL_ZONE_DIR_PATH.c_str(), pTSysPathInfo->name);
113 // Format paths for thermal zone node
114 tzSysPathInfo_.name = pTSysPathInfo->name;
115 FormatThermalPaths(tzSysPathInfo_.tempPath, sizeof(tzSysPathInfo_.tempPath),
116 THERMAL_TEMPERATURE_PATH.c_str(), pTSysPathInfo->name);
117
118 FormatThermalPaths(tzSysPathInfo_.typePath, sizeof(tzSysPathInfo_.typePath),
119 THEERMAL_TYPE_PATH.c_str(), pTSysPathInfo->name);
120
121 THERMAL_HILOGI(FEATURE_PROTECTOR, "temp path: %{public}s, type path: %{public}s ",
122 tzSysPathInfo_.tempPath, tzSysPathInfo_.typePath);
123
124 tzSysPathInfo_.fd = pTSysPathInfo->fd;
125 lTzSysPathInfo_.push_back(tzSysPathInfo_);
126 }
127
FormatThermalPaths(char * path,size_t size,const char * format,const char * name)128 void ThermalSensorProvision::FormatThermalPaths(char *path, size_t size, const char *format, const char* name)
129 {
130 if (snprintf_s(path, PATH_MAX, size - 1, format, name) < NUM_ZERO) {
131 THERMAL_HILOGW(FEATURE_PROTECTOR, "failed to format path of %{public}s", name);
132 }
133 }
134
InitThermalZoneSysfs()135 int32_t ThermalSensorProvision::InitThermalZoneSysfs()
136 {
137 DIR *dir = NULL;
138 struct dirent *entry = NULL;
139 int32_t index = 0;
140 int32_t id = 0;
141
142 dir = opendir(THERMAL_SYSFS.c_str());
143 if (dir == nullptr) {
144 THERMAL_HILOGE(FEATURE_PROTECTOR, "cannot open thermal zone path");
145 return ERR_INVALID_VALUE;
146 }
147
148 while (true) {
149 entry = readdir(dir);
150 if (entry == nullptr) {
151 break;
152 }
153
154 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
155 continue;
156 }
157
158 if (strncmp(entry->d_name, CDEV_DIR_NAME.c_str(), CDEV_DIR_NAME.size()) == 0) {
159 continue;
160 }
161
162 if (entry->d_type == DT_DIR || entry->d_type == DT_LNK) {
163 struct ThermalSysfsPathInfo sysfsInfo = {0};
164 sysfsInfo.name = entry->d_name;
165 THERMAL_HILOGI(FEATURE_PROTECTOR, "init sysfs info of %{public}s", sysfsInfo.name);
166 int32_t ret = sscanf_s(sysfsInfo.name, THERMAL_ZONE_DIR_NAME.c_str(), &id);
167 if (ret < ARG_0) {
168 return ret;
169 }
170
171 THERMAL_HILOGI(FEATURE_PROTECTOR, "Sensor %{public}s found at tz: %{public}d", sysfsInfo.name, id);
172 sysfsInfo.fd = id;
173 if (index > MAX_SYSFS_SIZE) {
174 THERMAL_HILOGE(FEATURE_PROTECTOR, "too many plugged types");
175 break;
176 }
177
178 FormatThermalSysfsPaths(&sysfsInfo);
179 index++;
180 }
181 }
182 closedir(dir);
183 return ERR_OK;
184 }
185
ParseThermalZoneInfo()186 int32_t ThermalSensorProvision::ParseThermalZoneInfo()
187 {
188 char bufType[MAX_BUFF_SIZE] = {0};
189 int32_t ret = InitThermalZoneSysfs();
190 if (ret != ERR_OK) {
191 THERMAL_HILOGE(FEATURE_PROTECTOR, "failed to get path info.");
192 return false;
193 }
194
195 std::map<std::string, std::string> tzPathMap;
196 if (!lTzSysPathInfo_.empty()) {
197 for (auto iter = lTzSysPathInfo_.begin(); iter != lTzSysPathInfo_.end(); iter++) {
198 int32_t ret = ReadThermalSysfsToBuff(iter->typePath, bufType, sizeof(bufType));
199 if (ret != NUM_ZERO) {
200 THERMAL_HILOGE(FEATURE_PROTECTOR, "failed to read thermal zone type");
201 return ret;
202 }
203 std::string tzType = bufType;
204 tzPathMap.insert(std::make_pair(tzType, iter->tempPath));
205 }
206 }
207 auto tzInfoMap = g_service.GetPolicy()->GetThermalZoneMap();
208 if (tzInfoMap.empty()) {
209 return ERR_INVALID_VALUE;
210 }
211 for (auto tzIter : tzInfoMap) {
212 auto typeIter = tzPathMap.find(tzIter.first);
213 if (typeIter != tzPathMap.end()) {
214 tzIter.second->SetPath(typeIter->second);
215 }
216 }
217 return ERR_OK;
218 }
219
ReportThermalZoneData(int32_t reportTime,std::vector<int32_t> & multipleList)220 void ThermalSensorProvision::ReportThermalZoneData(int32_t reportTime, std::vector<int32_t> &multipleList)
221 {
222 char tempBuf[MAX_BUFF_SIZE] = {0};
223 typeTempMap_.clear();
224 multipleList.clear();
225
226 auto tzInfoMap = g_service.GetPolicy()->GetThermalZoneMap();
227 if (tzInfoMap.empty()) {
228 return;
229 }
230
231 for (auto sensorIter : tzInfoMap) {
232 int multiple = sensorIter.second->GetMultiple();
233 if (multiple == 0) {
234 continue;
235 }
236 int result = reportTime % multiple;
237 multipleList.push_back(multiple);
238 if (result == NUM_ZERO) {
239 if (sensorIter.second->GetPath().empty()) {
240 continue;
241 }
242
243 int32_t ret = ReadThermalSysfsToBuff(sensorIter.second->GetPath().c_str(), tempBuf, sizeof(tempBuf));
244 if (ret != NUM_ZERO) {
245 continue;
246 }
247 int32_t temp = std::stoi(tempBuf);
248 typeTempMap_.insert(std::make_pair(sensorIter.first, temp));
249 }
250 }
251 }
252
GetMaxCd()253 int32_t ThermalSensorProvision::GetMaxCd()
254 {
255 return g_service.GetPolicy()->GetMaxCd();
256 }
257 } // namespace PowerMgr
258 } // namespace OHOS
259