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