• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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