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