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