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 "battery_config.h"
17
18 #include "battery_log.h"
19 #include <climits>
20 #include "string_ex.h"
21 #include "config_policy_utils.h"
22 #include "hdf_battery_json_utils.h"
23
24 namespace OHOS {
25 namespace HDI {
26 namespace Battery {
27 namespace V2_0 {
28 namespace {
29 constexpr const char* BATTERY_CONFIG_PATH = "etc/battery/battery_config.json";
30 constexpr const char* SYSTEM_BATTERY_CONFIG_PATH = "/system/etc/battery/battery_config.json";
31 constexpr const char* VENDOR_BATTERY_CONFIG_PATH = "/vendor/etc/battery/battery_config.json";
32 constexpr const char* VENDOR_BATTERY_SPLIT_CONFIG_PATH = "/vendor/etc/battery/charge_config.json";
33 constexpr const char* BATTERY_CONFIG_EXCEPTION_PATH = "";
34 constexpr int32_t MAP_KEY_INDEX = 0;
35 constexpr int32_t BEGIN_SOC_INDEX = 0;
36 constexpr int32_t END_SOC_INDEX = 1;
37 constexpr int32_t MAX_SOC_RANGE = 2;
38 constexpr int32_t RED_INDEX = 0;
39 constexpr int32_t GREEN_INDEX = 1;
40 constexpr int32_t BLUE_INDEX = 2;
41 constexpr int32_t MAX_RGB_RANGE = 3;
42 constexpr int32_t MAX_DEPTH = 5;
43 constexpr int32_t MIN_DEPTH = 1;
44 constexpr uint32_t MOVE_LEFT_16 = 16;
45 constexpr uint32_t MOVE_LEFT_8 = 8;
46 constexpr uint32_t SYSTEM_PATH_CHECK = 4;
47 constexpr uint32_t DATA_PATH_CHECK = 5;
48 }
49 std::shared_ptr<BatteryConfig> BatteryConfig::instance_ = nullptr;
50 std::mutex BatteryConfig::mutex_;
51
GetInstance()52 BatteryConfig& BatteryConfig::GetInstance()
53 {
54 std::lock_guard<std::mutex> lock(mutex_);
55 if (instance_ == nullptr) {
56 instance_ = std::make_shared<BatteryConfig>();
57 }
58 return *(instance_.get());
59 }
60
ParseJsonStream(std::istream & ifsConf)61 cJSON* BatteryConfig::ParseJsonStream(std::istream& ifsConf)
62 {
63 std::string content((std::istreambuf_iterator<char>(ifsConf)), std::istreambuf_iterator<char>());
64 cJSON* config = cJSON_Parse(content.c_str());
65 if (config == nullptr) {
66 const char* errorPtr = cJSON_GetErrorPtr();
67 BATTERY_HILOGE(COMP_HDI, "cJSON parse error: in %{public}s",
68 (errorPtr != nullptr) ? errorPtr : "unknown error");
69 return nullptr;
70 }
71 if (HdfBatteryJsonUtils::IsEmptyJsonParse(config)) {
72 cJSON_Delete(config);
73 BATTERY_HILOGW(COMP_HDI, "cJSON parse result is empty, battery config is %{public}s", content.c_str());
74 return nullptr;
75 }
76 return config;
77 }
78
ParseConfig()79 bool BatteryConfig::ParseConfig()
80 {
81 char buf[MAX_PATH_LEN];
82 char* path = GetOneCfgFile(BATTERY_CONFIG_PATH, buf, MAX_PATH_LEN);
83 if (path == nullptr || *path == '\0') {
84 BATTERY_HILOGW(COMP_HDI, "GetOneCfgFile battery_config.json is NULL");
85 path = const_cast<char*>(BATTERY_CONFIG_EXCEPTION_PATH);
86 }
87 BATTERY_HILOGD(COMP_HDI, "GetOneCfgFile battery_config.json");
88
89 cJSON* config = nullptr;
90 std::ifstream ifsConf;
91 ifsConf.open(VENDOR_BATTERY_SPLIT_CONFIG_PATH);
92 bool isOpen = ifsConf.is_open();
93 if (isOpen) {
94 config = ParseJsonStream(ifsConf);
95 if (config) {
96 ParseConfSplit(config);
97 cJSON_Delete(config);
98 }
99 ifsConf.close();
100 config = nullptr;
101
102 if (!OpenFile(ifsConf, path)) {
103 return false;
104 }
105 config = ParseJsonStream(ifsConf);
106 if (config) {
107 ParseConfInner(config);
108 cJSON_Delete(config);
109 }
110 } else {
111 if (!OpenFile(ifsConf, path)) {
112 return false;
113 }
114 config = ParseJsonStream(ifsConf);
115 if (config) {
116 ParseConfInner(config);
117 ParseConfSplit(config);
118 cJSON_Delete(config);
119 }
120 }
121 ifsConf.close();
122 config = nullptr;
123 return true;
124 }
125
GetLightConfig() const126 const std::vector<BatteryConfig::LightConfig>& BatteryConfig::GetLightConfig() const
127 {
128 return lightConfig_;
129 }
130
GetChargerConfig() const131 const BatteryConfig::ChargerConfig& BatteryConfig::GetChargerConfig() const
132 {
133 return chargerConfig_;
134 }
135
GetChargeSceneConfigMap() const136 const std::map<std::string, BatteryConfig::ChargeSceneConfig>& BatteryConfig::GetChargeSceneConfigMap() const
137 {
138 return chargeSceneConfigMap_;
139 }
140
GetUeventList() const141 const UeventMap& BatteryConfig::GetUeventList() const
142 {
143 return ueventMap_;
144 }
145
DestroyInstance()146 void BatteryConfig::DestroyInstance()
147 {
148 std::lock_guard<std::mutex> lock(mutex_);
149 instance_ = nullptr;
150 }
151
OpenFile(std::ifstream & ifsConf,const std::string & configPath)152 bool BatteryConfig::OpenFile(std::ifstream& ifsConf, const std::string& configPath)
153 {
154 bool isOpen = false;
155 if (!configPath.empty()) {
156 ifsConf.open(configPath);
157 isOpen = ifsConf.is_open();
158 BATTERY_HILOGD(COMP_HDI, "open file is %{public}d", isOpen);
159 }
160 if (isOpen) {
161 return true;
162 }
163
164 ifsConf.open(VENDOR_BATTERY_CONFIG_PATH);
165 isOpen = ifsConf.is_open();
166 BATTERY_HILOGI(COMP_HDI, "open then vendor battery_config.json is %{public}d", isOpen);
167
168 if (isOpen) {
169 return true;
170 }
171
172 ifsConf.open(SYSTEM_BATTERY_CONFIG_PATH);
173 isOpen = ifsConf.is_open();
174 BATTERY_HILOGI(FEATURE_CHARGING, "open then system battery_config.json is %{public}d", isOpen);
175 return isOpen;
176 }
177
ParseConfInner(const cJSON * config)178 void BatteryConfig::ParseConfInner(const cJSON* config)
179 {
180 BATTERY_HILOGI(COMP_HDI, "start parse battery config inner");
181 ParseLightConfig(GetValue(config, "light"));
182 ParseChargerConfig(GetValue(config, "charger"));
183 }
184
ParseConfSplit(const cJSON * config)185 void BatteryConfig::ParseConfSplit(const cJSON* config)
186 {
187 BATTERY_HILOGI(COMP_HDI, "start parse split config inner");
188 ParseChargeSceneConfig(GetValue(config, "charge_scene"));
189 ParseUeventConfig(GetValue(config, "uevent"));
190 }
191
ParseChargerConfig(const cJSON * chargerConfig)192 void BatteryConfig::ParseChargerConfig(const cJSON* chargerConfig)
193 {
194 if (!HdfBatteryJsonUtils::IsValidJsonObject(chargerConfig)) {
195 BATTERY_HILOGW(COMP_HDI, "chargerConfig is invalid");
196 return;
197 }
198
199 cJSON* currentPath = GetValue(chargerConfig, "current_limit.path");
200 if (HdfBatteryJsonUtils::IsValidJsonString(currentPath)) {
201 chargerConfig_.currentPath = currentPath->valuestring;
202 }
203
204 cJSON* voltagePath = GetValue(chargerConfig, "voltage_limit.path");
205 if (HdfBatteryJsonUtils::IsValidJsonString(voltagePath)) {
206 chargerConfig_.voltagePath = voltagePath->valuestring;
207 }
208
209 cJSON* chargeTypePath = GetValue(chargerConfig, "type.path");
210 if (HdfBatteryJsonUtils::IsValidJsonString(chargeTypePath)) {
211 chargerConfig_.chargeTypePath = chargeTypePath->valuestring;
212 }
213 BATTERY_HILOGI(COMP_HDI, "The battery charger configuration parse succeed");
214 }
215
ParseLightConfig(const cJSON * lightConfig)216 void BatteryConfig::ParseLightConfig(const cJSON* lightConfig)
217 {
218 if (!HdfBatteryJsonUtils::IsValidJsonObject(lightConfig)) {
219 BATTERY_HILOGW(COMP_HDI, "lightConf is invalid");
220 return;
221 }
222 lightConfig_.clear();
223 SaveJsonResult(lightConfig);
224 BATTERY_HILOGI(COMP_HDI, "The battery light configuration size %{public}d",
225 static_cast<int32_t>(lightConfig_.size()));
226 }
227
SaveJsonResult(const cJSON * lightConfig)228 void BatteryConfig::SaveJsonResult(const cJSON* lightConfig)
229 {
230 cJSON* valueObj = nullptr;
231 cJSON_ArrayForEach(valueObj, lightConfig) {
232 if (valueObj->string == nullptr) {
233 BATTERY_HILOGW(COMP_HDI, "Found null key in light config");
234 continue;
235 }
236 const std::string key = valueObj->string;
237 if (cJSON_IsNull(valueObj) || !cJSON_IsObject(valueObj)) {
238 BATTERY_HILOGW(COMP_HDI, "The light conf is invalid, key=%{public}s", key.c_str());
239 continue;
240 }
241 cJSON* soc = GetValue(valueObj, "soc");
242 cJSON* rgb = GetValue(valueObj, "rgb");
243 if (!HdfBatteryJsonUtils::IsValidJsonArray(soc) || !HdfBatteryJsonUtils::IsValidJsonArray(rgb)) {
244 BATTERY_HILOGW(COMP_HDI, "The battery light %{public}s configuration is invalid.", key.c_str());
245 continue;
246 }
247 if (cJSON_GetArraySize(soc) != MAX_SOC_RANGE) {
248 BATTERY_HILOGW(COMP_HDI, "The battery light %{public}s soc data length error.", key.c_str());
249 continue;
250 }
251 cJSON* beginSocItem = cJSON_GetArrayItem(soc, BEGIN_SOC_INDEX);
252 cJSON* endSocItem = cJSON_GetArrayItem(soc, END_SOC_INDEX);
253 if (!HdfBatteryJsonUtils::IsValidJsonNumber(beginSocItem) ||
254 !HdfBatteryJsonUtils::IsValidJsonNumber(endSocItem)) {
255 BATTERY_HILOGW(COMP_HDI, "The battery light %{public}s soc data type error.", key.c_str());
256 continue;
257 }
258 if (cJSON_GetArraySize(rgb) != MAX_RGB_RANGE) {
259 BATTERY_HILOGW(COMP_HDI, "The battery light %{public}s rgb data length error.", key.c_str());
260 continue;
261 }
262 cJSON* redItem = cJSON_GetArrayItem(rgb, RED_INDEX);
263 cJSON* greenItem = cJSON_GetArrayItem(rgb, GREEN_INDEX);
264 cJSON* blueItem = cJSON_GetArrayItem(rgb, BLUE_INDEX);
265 if (!HdfBatteryJsonUtils::IsValidJsonNumber(redItem) || !HdfBatteryJsonUtils::IsValidJsonNumber(greenItem) ||
266 !HdfBatteryJsonUtils::IsValidJsonNumber(blueItem)) {
267 BATTERY_HILOGW(COMP_HDI, "The battery light %{public}s rgb data type error.", key.c_str());
268 continue;
269 }
270 BatteryConfig::LightConfig tempLightConfig = {
271 .beginSoc = static_cast<int32_t>(beginSocItem->valueint),
272 .endSoc = static_cast<int32_t>(endSocItem->valueint),
273 .rgb = (static_cast<uint32_t>(redItem->valueint) << MOVE_LEFT_16) |
274 (static_cast<uint32_t>(greenItem->valueint) << MOVE_LEFT_8) | static_cast<uint32_t>(blueItem->valueint)
275 };
276 lightConfig_.push_back(tempLightConfig);
277 }
278 }
279
ParseChargeSceneConfig(const cJSON * chargeSceneConfig)280 void BatteryConfig::ParseChargeSceneConfig(const cJSON* chargeSceneConfig)
281 {
282 if (!HdfBatteryJsonUtils::IsValidJsonObject(chargeSceneConfig)) {
283 BATTERY_HILOGW(COMP_HDI, "chargeSceneConfig is invalid");
284 return;
285 }
286
287 chargeSceneConfigMap_.clear();
288 cJSON* valueObj = nullptr;
289 cJSON_ArrayForEach(valueObj, chargeSceneConfig) {
290 if (valueObj->string == nullptr) {
291 BATTERY_HILOGW(COMP_HDI, "Found null key in charge scene config");
292 continue;
293 }
294 const std::string key = valueObj->string;
295 if (!IsValidChargeSceneConfig(key, valueObj)) {
296 continue;
297 }
298
299 BatteryConfig::ChargeSceneConfig tempChargeSceneConfig;
300 bool parseSupportPathResult = ParseChargeSceneSupport(valueObj, tempChargeSceneConfig);
301 bool parseSetPathResult = ParseChargeSceneSet(valueObj, tempChargeSceneConfig);
302 bool parseGetPathResult = ParseChargeSceneGet(valueObj, tempChargeSceneConfig);
303 if (parseSupportPathResult || parseSetPathResult || parseGetPathResult) {
304 chargeSceneConfigMap_.insert(std::make_pair(key, tempChargeSceneConfig));
305 }
306 }
307
308 BATTERY_HILOGI(COMP_HDI, "The charge scene config size: %{public}d",
309 static_cast<int32_t>(chargeSceneConfigMap_.size()));
310 }
311
IsValidChargeSceneConfig(const std::string & key,const cJSON * valueObj)312 bool BatteryConfig::IsValidChargeSceneConfig(const std::string& key, const cJSON* valueObj)
313 {
314 if (key.empty() || !HdfBatteryJsonUtils::IsValidJsonObject(valueObj)) {
315 BATTERY_HILOGW(COMP_HDI, "The charge scene config is invalid, key=%{public}s", key.c_str());
316 return false;
317 }
318
319 cJSON* supportPath = GetValue(valueObj, "support.path");
320 cJSON* setPath = GetValue(valueObj, "set.path");
321 cJSON* getPath = GetValue(valueObj, "get.path");
322 if (!HdfBatteryJsonUtils::IsValidJsonString(supportPath) && !HdfBatteryJsonUtils::IsValidJsonString(setPath) &&
323 !HdfBatteryJsonUtils::IsValidJsonString(getPath)) {
324 BATTERY_HILOGW(COMP_HDI, "The charge scene config path is invalid, key=%{public}s", key.c_str());
325 return false;
326 }
327
328 return true;
329 }
330
ParseChargeSceneSupport(const cJSON * valueObj,BatteryConfig::ChargeSceneConfig & config)331 bool BatteryConfig::ParseChargeSceneSupport(const cJSON* valueObj, BatteryConfig::ChargeSceneConfig& config)
332 {
333 cJSON* supportPath = GetValue(valueObj, "support.path");
334 cJSON* type = GetValue(valueObj, "support.type");
335 cJSON* expectValue = GetValue(valueObj, "support.expect_value");
336 if (HdfBatteryJsonUtils::IsValidJsonString(supportPath)) {
337 std::string path = supportPath->valuestring;
338 if (IsValidSysPath(path)) {
339 config.supportPath = path;
340 config.type = HdfBatteryJsonUtils::IsValidJsonString(type) ? type->valuestring : "";
341 config.expectValue = HdfBatteryJsonUtils::IsValidJsonString(expectValue) ? expectValue->valuestring : "";
342 return true;
343 }
344 }
345 return false;
346 }
347
ParseChargeSceneSet(const cJSON * valueObj,BatteryConfig::ChargeSceneConfig & config)348 bool BatteryConfig::ParseChargeSceneSet(const cJSON* valueObj, BatteryConfig::ChargeSceneConfig& config)
349 {
350 cJSON* setPath = GetValue(valueObj, "set.path");
351 if (HdfBatteryJsonUtils::IsValidJsonString(setPath)) {
352 std::string path = setPath->valuestring;
353 if (IsValidSysPath(path)) {
354 config.setPath = path;
355 return true;
356 }
357 }
358 return false;
359 }
360
ParseChargeSceneGet(const cJSON * valueObj,BatteryConfig::ChargeSceneConfig & config)361 bool BatteryConfig::ParseChargeSceneGet(const cJSON* valueObj, BatteryConfig::ChargeSceneConfig& config)
362 {
363 cJSON* getPath = GetValue(valueObj, "get.path");
364 if (HdfBatteryJsonUtils::IsValidJsonString(getPath)) {
365 std::string path = getPath->valuestring;
366 if (IsValidSysPath(path)) {
367 config.getPath = path;
368 return true;
369 }
370 }
371 return false;
372 }
373
IsValidSysPath(const std::string & path)374 bool BatteryConfig::IsValidSysPath(const std::string& path)
375 {
376 char resolvedPath[PATH_MAX] = {};
377 if ((realpath(path.c_str(), resolvedPath) == nullptr) ||
378 ((strncmp(resolvedPath, "/sys", SYSTEM_PATH_CHECK) != 0) &&
379 (strncmp(resolvedPath, "/data", DATA_PATH_CHECK) != 0))) {
380 return false;
381 }
382 return true;
383 }
384
ParseUeventConfig(const cJSON * ueventConfig)385 void BatteryConfig::ParseUeventConfig(const cJSON* ueventConfig)
386 {
387 if (!HdfBatteryJsonUtils::IsValidJsonObject(ueventConfig)) {
388 BATTERY_HILOGW(COMP_HDI, "ueventConfig is invalid");
389 return;
390 }
391 ueventMap_.clear();
392 cJSON* valueObj = nullptr;
393 cJSON_ArrayForEach(valueObj, ueventConfig) {
394 if (valueObj->string == nullptr) {
395 BATTERY_HILOGW(COMP_HDI, "Found null key in uevent config");
396 continue;
397 }
398 const std::string key = valueObj->string;
399 if (cJSON_IsNull(valueObj) || !cJSON_IsObject(valueObj)) {
400 BATTERY_HILOGW(COMP_HDI, "The uevent conf is invalid, key=%{public}s", key.c_str());
401 continue;
402 }
403
404 std::vector<std::pair<std::string, std::string>> ueventList;
405 cJSON* subChild = nullptr;
406 cJSON_ArrayForEach(subChild, valueObj) {
407 if (subChild->string == nullptr) {
408 BATTERY_HILOGW(COMP_SVC, "Found null key in uevent conf");
409 continue;
410 }
411 const std::string event = subChild->string;
412 if (!HdfBatteryJsonUtils::IsValidJsonString(subChild)) {
413 BATTERY_HILOGW(COMP_SVC, "The uevent conf is invalid, key=%{public}s", key.c_str());
414 continue;
415 }
416 std::string act = subChild->valuestring;
417 ueventList.emplace_back(std::make_pair(event, act));
418 }
419
420 ueventMap_.emplace(key, ueventList);
421 BATTERY_HILOGI(COMP_HDI, "%{public}s size: %{public}d", key.c_str(), static_cast<int32_t>(ueventList.size()));
422 }
423 BATTERY_HILOGI(COMP_HDI, "The uevent config size: %{public}d", static_cast<int32_t>(ueventMap_.size()));
424 }
425
SplitKey(const std::string & key,std::vector<std::string> & keys) const426 bool BatteryConfig::SplitKey(const std::string& key, std::vector<std::string>& keys) const
427 {
428 SplitStr(TrimStr(key), ".", keys);
429 return (keys.size() < MIN_DEPTH || keys.size() > MAX_DEPTH) ? false : true;
430 }
431
GetValue(const cJSON * config,std::string key) const432 cJSON* BatteryConfig::GetValue(const cJSON* config, std::string key) const
433 {
434 std::vector<std::string> keys;
435 if (!SplitKey(key, keys)) {
436 BATTERY_HILOGW(COMP_HDI, "The key does not meet the. key=%{public}s", key.c_str());
437 return nullptr;
438 }
439
440 std::string firstKey = keys[MAP_KEY_INDEX];
441 cJSON* value = (config && cJSON_IsObject(config) && cJSON_HasObjectItem(config, firstKey.c_str())) ?
442 cJSON_GetObjectItemCaseSensitive(config, firstKey.c_str()) : nullptr;
443 if (!value || cJSON_IsNull(value)) {
444 BATTERY_HILOGD(COMP_HDI, "Value is empty. key=%{public}s", key.c_str());
445 return value;
446 }
447
448 for (size_t i = 1; i < keys.size(); ++i) {
449 if (!cJSON_IsObject(value) || !cJSON_HasObjectItem(value, keys[i].c_str())) {
450 BATTERY_HILOGW(COMP_HDI, "The key is not configured. key=%{public}s", keys[i].c_str());
451 break;
452 }
453 value = cJSON_GetObjectItemCaseSensitive(value, keys[i].c_str());
454 }
455 return value;
456 }
457 } // namespace V2_0
458 } // namespace Battery
459 } // namespace HDI
460 } // namespace OHOS
461