1 /*
2 * Copyright (c) 2022-2023 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 "power_supply_provider.h"
17 #include "charger_log.h"
18 #include <dirent.h>
19 #include <fcntl.h>
20 #include <fstream>
21 #include <securec.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25
26 namespace OHOS {
27 namespace PowerMgr {
28 namespace {
29 constexpr int32_t MAX_SYSFS_SIZE = 64;
30 constexpr int32_t MAX_BUFF_SIZE = 128;
31 constexpr int32_t STR_TO_LONG_LEN = 10;
32 constexpr int32_t MKDIR_WAIT_TIME = 1;
33 constexpr int32_t NUM_ZERO = 0;
34 const std::string POWER_SUPPLY_BASE_PATH = "/sys/class/power_supply";
35 const std::string MOCK_POWER_SUPPLY_BASE_PATH = "/data/service/el0/battery";
36 const std::string POWER_SUPPLY_BATTERY = "Battery";
37 const std::string INVALID_STRING_VALUE = "invalid";
38 const std::string BATTERY_NODE_PATH = "battery";
39 } // namespace
40
41 BatterydInfo g_batteryInfo;
42
43 struct StringEnumMap {
44 const char* str;
45 int32_t enumVal;
46 };
47
PowerSupplyProvider()48 PowerSupplyProvider::PowerSupplyProvider()
49 {
50 path_ = POWER_SUPPLY_BASE_PATH;
51 index_ = 0;
52 }
53
ParseInt(const char * str)54 inline int32_t PowerSupplyProvider::ParseInt(const char* str)
55 {
56 return static_cast<int32_t>(strtol(str, nullptr, STR_TO_LONG_LEN));
57 }
58
Trim(char * str)59 inline void PowerSupplyProvider::Trim(char* str)
60 {
61 if (str == nullptr) {
62 return;
63 }
64
65 str[strcspn(str, "\n")] = 0;
66 }
67
ChargeStateEnumConverter(const char * str)68 int32_t PowerSupplyProvider::ChargeStateEnumConverter(const char* str)
69 {
70 struct StringEnumMap chargeStateEnumMap[] = {
71 {"Discharging", CHARGE_STATE_NONE },
72 {"Charging", CHARGE_STATE_ENABLE },
73 {"Full", CHARGE_STATE_FULL },
74 {"Not charging", CHARGE_STATE_DISABLE },
75 {"Unknown", CHARGE_STATE_RESERVED},
76 {nullptr, CHARGE_STATE_RESERVED},
77 };
78
79 for (int32_t i = 0; chargeStateEnumMap[i].str; ++i) {
80 if (strcmp(str, chargeStateEnumMap[i].str) == 0) {
81 return chargeStateEnumMap[i].enumVal;
82 }
83 }
84
85 return CHARGE_STATE_RESERVED;
86 }
87
FormatPath(std::string & path,size_t size,const char * format,const char * basePath,const char * name) const88 void PowerSupplyProvider::FormatPath(
89 std::string& path, size_t size, const char* format, const char* basePath, const char* name) const
90 {
91 char buff[PATH_MAX] = {0};
92 if (strcpy_s(buff, PATH_MAX, path.c_str()) != EOK) {
93 BATTERY_HILOGW(FEATURE_CHARGING, "failed to copy path of %{public}s", name);
94 return;
95 }
96
97 if (snprintf_s(buff, PATH_MAX, size - 1, format, basePath, name) == -1) {
98 BATTERY_HILOGW(FEATURE_CHARGING, "failed to format path of %{public}s", name);
99 return;
100 }
101 path.assign(buff, strlen(buff));
102 }
103
FormatSysfsPaths()104 void PowerSupplyProvider::FormatSysfsPaths()
105 {
106 // Format paths for power supply types
107 FormatPath(batterySysfsInfo_.capacityPath, PATH_MAX, "%s/%s/capacity", path_.c_str(),
108 nodeNamePathMap_["capacity"].c_str());
109 FormatPath(
110 batterySysfsInfo_.temperaturePath, PATH_MAX, "%s/%s/temp", path_.c_str(), nodeNamePathMap_["temp"].c_str());
111 FormatPath(
112 batterySysfsInfo_.chargeStatePath, PATH_MAX, "%s/%s/status", path_.c_str(), nodeNamePathMap_["status"].c_str());
113 }
114
ReadSysfsFile(const char * path,char * buf,size_t size) const115 int32_t PowerSupplyProvider::ReadSysfsFile(const char* path, char* buf, size_t size) const
116 {
117 int32_t fd = open(path, O_RDONLY, S_IRUSR | S_IRGRP | S_IROTH);
118 if (fd < NUM_ZERO) {
119 BATTERY_HILOGE(FEATURE_CHARGING, "failed to open path");
120 return HDF_ERR_IO;
121 }
122
123 size_t readSize = read(fd, buf, size - 1);
124 buf[readSize] = '\0';
125 Trim(buf);
126 close(fd);
127
128 return HDF_SUCCESS;
129 }
130
ReadBatterySysfsToBuff(const char * path,char * buf,size_t size) const131 int32_t PowerSupplyProvider::ReadBatterySysfsToBuff(const char* path, char* buf, size_t size) const
132 {
133 int32_t ret = ReadSysfsFile(path, buf, size);
134 if (ret != HDF_SUCCESS) {
135 BATTERY_HILOGW(FEATURE_CHARGING, "read path failed, ret: %{public}d", ret);
136 return ret;
137 }
138
139 return HDF_SUCCESS;
140 }
141
CreateFile(const std::string & path,const std::string & content)142 void PowerSupplyProvider::CreateFile(const std::string& path, const std::string& content)
143 {
144 if (access(path.c_str(), F_OK) == 0) {
145 return;
146 }
147
148 std::ofstream stream(path.c_str());
149 if (!stream.is_open()) {
150 BATTERY_HILOGE(FEATURE_CHARGING, "cannot create file");
151 return;
152 }
153 stream << content.c_str() << std::endl;
154 stream.close();
155 }
156
InitBatteryPath()157 void PowerSupplyProvider::InitBatteryPath()
158 {
159 std::string sysLowercaseBatteryPath = "/sys/class/power_supply/battery";
160
161 if (access(sysLowercaseBatteryPath.c_str(), F_OK) == 0) {
162 BATTERY_HILOGI(FEATURE_CHARGING, "system battery path is exist");
163 return;
164 } else {
165 std::string sysCapitalBatteryPath = "/sys/class/power_supply/Battery";
166 if (access(sysCapitalBatteryPath.c_str(), F_OK) == 0) {
167 BATTERY_HILOGI(FEATURE_CHARGING, "system Battery path is exist");
168 return;
169 }
170 InitDefaultSysfs();
171 }
172 }
173
InitPowerSupplySysfs()174 int32_t PowerSupplyProvider::InitPowerSupplySysfs()
175 {
176 DIR* dir;
177 index_ = 0;
178
179 dir = opendir(path_.c_str());
180 if (dir == nullptr) {
181 BATTERY_HILOGE(FEATURE_CHARGING, "cannot open path_");
182 return HDF_ERR_IO;
183 }
184
185 while (true) {
186 struct dirent* entry = readdir(dir);
187 if (entry == nullptr) {
188 break;
189 }
190
191 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
192 continue;
193 }
194
195 if (entry->d_type == DT_DIR || entry->d_type == DT_LNK) {
196 if (index_ >= MAX_SYSFS_SIZE) {
197 BATTERY_HILOGW(FEATURE_CHARGING, "too many power supply types");
198 break;
199 }
200 nodeNames_.emplace_back(entry->d_name);
201 index_++;
202 }
203 }
204 nodeNamePathMap_.clear();
205 TraversalNode();
206 FormatSysfsPaths();
207 BATTERY_HILOGD(FEATURE_CHARGING, "init power supply sysfs nodes, total count %{public}d", index_);
208 closedir(dir);
209
210 return HDF_SUCCESS;
211 }
212
TraversalNode()213 void PowerSupplyProvider::TraversalNode()
214 {
215 nodeNamePathMap_.insert(std::make_pair("capacity", ""));
216 nodeNamePathMap_.insert(std::make_pair("temp", ""));
217 nodeNamePathMap_.insert(std::make_pair("status", ""));
218
219 auto iter = nodeNames_.begin();
220 while (iter != nodeNames_.end()) {
221 if (*iter == "battery") {
222 CheckSubfolderNode(*iter);
223 iter = nodeNames_.erase(iter);
224 } else {
225 iter++;
226 }
227 }
228
229 iter = nodeNames_.begin();
230 while (iter != nodeNames_.end()) {
231 if (*iter == POWER_SUPPLY_BATTERY) {
232 CheckSubfolderNode(*iter);
233 iter = nodeNames_.erase(iter);
234 } else {
235 iter++;
236 }
237 }
238
239 for (auto& nodeName : nodeNames_) {
240 CheckSubfolderNode(nodeName);
241 }
242 }
243
CheckSubfolderNode(const std::string & path)244 void PowerSupplyProvider::CheckSubfolderNode(const std::string& path)
245 {
246 DIR* dir;
247 std::string batteryPath = path_ + "/" + path;
248
249 dir = opendir(batteryPath.c_str());
250 if (dir == nullptr) {
251 BATTERY_HILOGE(FEATURE_CHARGING, "subfolder file is not exist.");
252 return;
253 }
254
255 while (true) {
256 struct dirent* entry = readdir(dir);
257 if (entry == nullptr) {
258 break;
259 }
260
261 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
262 continue;
263 }
264
265 if (entry->d_type == DT_DIR || entry->d_type == DT_LNK) {
266 continue;
267 }
268
269 if ((strcmp(entry->d_name, "type") == 0) && (nodeNamePathMap_["type"].empty()) &&
270 (strcasecmp(path.c_str(), BATTERY_NODE_PATH.c_str()) != 0)) {
271 nodeNamePathMap_["type"] = path;
272 }
273
274 for (auto& iter : nodeNamePathMap_) {
275 if ((strcmp(entry->d_name, iter.first.c_str()) == 0) && (nodeNamePathMap_[iter.first].empty())) {
276 nodeNamePathMap_[iter.first] = path;
277 }
278 }
279 }
280 closedir(dir);
281 }
282
ParseCapacity(int32_t * capacity) const283 int32_t PowerSupplyProvider::ParseCapacity(int32_t* capacity) const
284 {
285 char buf[MAX_BUFF_SIZE] = {0};
286
287 int32_t ret = ReadBatterySysfsToBuff(batterySysfsInfo_.capacityPath.c_str(), buf, sizeof(buf));
288 if (ret != HDF_SUCCESS) {
289 return ret;
290 }
291
292 int32_t value = ParseInt(buf);
293 *capacity = value;
294
295 return HDF_SUCCESS;
296 }
297
ParseTemperature(int32_t * temperature) const298 int32_t PowerSupplyProvider::ParseTemperature(int32_t* temperature) const
299 {
300 char buf[MAX_BUFF_SIZE] = {0};
301 int32_t ret = ReadBatterySysfsToBuff(batterySysfsInfo_.temperaturePath.c_str(), buf, sizeof(buf));
302 if (ret != HDF_SUCCESS) {
303 return ret;
304 }
305
306 int32_t value = ParseInt(buf);
307 *temperature = value;
308
309 return HDF_SUCCESS;
310 }
311
ParseChargeState(int32_t * chargeState) const312 int32_t PowerSupplyProvider::ParseChargeState(int32_t* chargeState) const
313 {
314 char buf[MAX_BUFF_SIZE] = {0};
315 int32_t ret = ReadBatterySysfsToBuff(batterySysfsInfo_.chargeStatePath.c_str(), buf, sizeof(buf));
316 if (ret != HDF_SUCCESS) {
317 return ret;
318 }
319
320 Trim(buf);
321 *chargeState = ChargeStateEnumConverter(buf);
322 return HDF_SUCCESS;
323 }
324
CreateMockTechPath(std::string & mockTechPath)325 void PowerSupplyProvider::CreateMockTechPath(std::string& mockTechPath)
326 {
327 BATTERY_HILOGI(FEATURE_CHARGING, "create mockFilePath path");
328 CreateFile(mockTechPath + "/capacity", "1000");
329 CreateFile(mockTechPath + "/status", "Not charging");
330 CreateFile(mockTechPath + "/temp", "345");
331 }
332
CreateMockChargerPath(std::string & mockChargerPath)333 void PowerSupplyProvider::CreateMockChargerPath(std::string& mockChargerPath)
334 {
335 BATTERY_HILOGI(FEATURE_CHARGING, "create mockFilePath path");
336 CreateFile(mockChargerPath + "/type", "USB");
337 CreateFile(mockChargerPath + "/constant_charge_current", "0");
338 CreateFile(mockChargerPath + "/health", "Good");
339 CreateFile(mockChargerPath + "/online", "1");
340 CreateFile(mockChargerPath + "/status", "Charging");
341 CreateFile(mockChargerPath + "/type", "USB");
342 }
343
CreateMockBatteryPath(std::string & mockBatteryPath)344 void PowerSupplyProvider::CreateMockBatteryPath(std::string& mockBatteryPath)
345 {
346 BATTERY_HILOGI(FEATURE_CHARGING, "create mockFilePath path");
347 CreateFile(mockBatteryPath + "/capacity", "11");
348 CreateFile(mockBatteryPath + "/status", "Charging");
349 CreateFile(mockBatteryPath + "/temp", "222");
350 }
351
InitDefaultSysfs()352 void PowerSupplyProvider::InitDefaultSysfs()
353 {
354 std::string mockBatteryPath = MOCK_POWER_SUPPLY_BASE_PATH + "/battery";
355 std::string mockChargerPath = MOCK_POWER_SUPPLY_BASE_PATH + "/ohos_charger";
356 std::string mockTechPath = MOCK_POWER_SUPPLY_BASE_PATH + "/ohos-fgu";
357
358 if (access(mockBatteryPath.c_str(), 0) == -1) {
359 mkdir(mockBatteryPath.c_str(), S_IRWXU | S_IRWXG);
360 sleep(MKDIR_WAIT_TIME);
361 }
362
363 if (access(mockChargerPath.c_str(), 0) == -1) {
364 mkdir(mockChargerPath.c_str(), S_IRWXU);
365 sleep(MKDIR_WAIT_TIME);
366 }
367
368 if (access(mockTechPath.c_str(), 0) == -1) {
369 mkdir(mockTechPath.c_str(), S_IRWXU);
370 sleep(MKDIR_WAIT_TIME);
371 }
372
373 CreateMockTechPath(mockTechPath);
374 CreateMockChargerPath(mockChargerPath);
375 CreateMockBatteryPath(mockBatteryPath);
376 path_ = MOCK_POWER_SUPPLY_BASE_PATH;
377 }
378 } // namespace PowerMgr
379 } // namespace OHOS
380