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
23 namespace OHOS {
24 namespace HDI {
25 namespace Battery {
26 namespace V2_0 {
27 namespace {
28 constexpr const char* BATTERY_CONFIG_PATH = "etc/battery/battery_config.json";
29 constexpr const char* SYSTEM_BATTERY_CONFIG_PATH = "/system/etc/battery/battery_config.json";
30 constexpr const char* VENDOR_BATTERY_CONFIG_PATH = "/vendor/etc/battery/battery_config.json";
31 constexpr const char* VENDOR_BATTERY_SPLIT_CONFIG_PATH = "/vendor/etc/battery/charge_config.json";
32 constexpr const char* BATTERY_CONFIG_EXCEPTION_PATH = "";
33 constexpr int32_t MAP_KEY_INDEX = 0;
34 constexpr int32_t BEGIN_SOC_INDEX = 0;
35 constexpr int32_t END_SOC_INDEX = 1;
36 constexpr int32_t MAX_SOC_RANGE = 2;
37 constexpr int32_t RED_INDEX = 0;
38 constexpr int32_t GREEN_INDEX = 1;
39 constexpr int32_t BLUE_INDEX = 2;
40 constexpr int32_t MAX_RGB_RANGE = 3;
41 constexpr int32_t MAX_DEPTH = 5;
42 constexpr int32_t MIN_DEPTH = 1;
43 constexpr uint32_t MOVE_LEFT_16 = 16;
44 constexpr uint32_t MOVE_LEFT_8 = 8;
45 constexpr uint32_t SYSTEM_PATH_CHECK = 4;
46 constexpr uint32_t DATA_PATH_CHECK = 5;
47 }
48 std::shared_ptr<BatteryConfig> BatteryConfig::instance_ = nullptr;
49 std::mutex BatteryConfig::mutex_;
50
GetInstance()51 BatteryConfig& BatteryConfig::GetInstance()
52 {
53 std::lock_guard<std::mutex> lock(mutex_);
54 if (instance_ == nullptr) {
55 instance_ = std::make_shared<BatteryConfig>();
56 }
57 return *(instance_.get());
58 }
59
ParseConfig()60 bool BatteryConfig::ParseConfig()
61 {
62 char buf[MAX_PATH_LEN];
63 char* path = GetOneCfgFile(BATTERY_CONFIG_PATH, buf, MAX_PATH_LEN);
64 if (path == nullptr || *path == '\0') {
65 BATTERY_HILOGW(COMP_HDI, "GetOneCfgFile battery_config.json is NULL");
66 path = const_cast<char*>(BATTERY_CONFIG_EXCEPTION_PATH);
67 }
68 BATTERY_HILOGD(COMP_HDI, "GetOneCfgFile battery_config.json");
69
70 Json::CharReaderBuilder readerBuilder;
71 std::ifstream ifsConf;
72 Json::Value config;
73 readerBuilder["collectComments"] = false;
74 JSONCPP_STRING errs;
75
76 ifsConf.open(VENDOR_BATTERY_SPLIT_CONFIG_PATH);
77 bool isOpen = ifsConf.is_open();
78 if (isOpen) {
79 if (parseFromStream(readerBuilder, ifsConf, &config, &errs) && !config.empty()) {
80 ParseConfSplit(config);
81 }
82 ifsConf.close();
83
84 if (!OpenFile(ifsConf, path)) {
85 return false;
86 }
87 if (parseFromStream(readerBuilder, ifsConf, &config, &errs) && !config.empty()) {
88 ParseConfInner(config);
89 }
90 } else {
91 if (!OpenFile(ifsConf, path)) {
92 return false;
93 }
94 if (parseFromStream(readerBuilder, ifsConf, &config, &errs) && !config.empty()) {
95 ParseConfInner(config);
96 ParseConfSplit(config);
97 }
98 }
99
100 ifsConf.close();
101 return true;
102 }
103
GetLightConfig() const104 const std::vector<BatteryConfig::LightConfig>& BatteryConfig::GetLightConfig() const
105 {
106 return lightConfig_;
107 }
108
GetChargerConfig() const109 const BatteryConfig::ChargerConfig& BatteryConfig::GetChargerConfig() const
110 {
111 return chargerConfig_;
112 }
113
GetChargeSceneConfigMap() const114 const std::map<std::string, BatteryConfig::ChargeSceneConfig>& BatteryConfig::GetChargeSceneConfigMap() const
115 {
116 return chargeSceneConfigMap_;
117 }
118
GetUeventList() const119 const UeventMap& BatteryConfig::GetUeventList() const
120 {
121 return ueventMap_;
122 }
123
DestroyInstance()124 void BatteryConfig::DestroyInstance()
125 {
126 std::lock_guard<std::mutex> lock(mutex_);
127 instance_ = nullptr;
128 }
129
OpenFile(std::ifstream & ifsConf,const std::string & configPath)130 bool BatteryConfig::OpenFile(std::ifstream& ifsConf, const std::string& configPath)
131 {
132 bool isOpen = false;
133 if (!configPath.empty()) {
134 ifsConf.open(configPath);
135 isOpen = ifsConf.is_open();
136 BATTERY_HILOGD(COMP_HDI, "open file is %{public}d", isOpen);
137 }
138 if (isOpen) {
139 return true;
140 }
141
142 ifsConf.open(VENDOR_BATTERY_CONFIG_PATH);
143 isOpen = ifsConf.is_open();
144 BATTERY_HILOGI(COMP_HDI, "open then vendor battery_config.json is %{public}d", isOpen);
145
146 if (isOpen) {
147 return true;
148 }
149
150 ifsConf.open(SYSTEM_BATTERY_CONFIG_PATH);
151 isOpen = ifsConf.is_open();
152 BATTERY_HILOGI(FEATURE_CHARGING, "open then system battery_config.json is %{public}d", isOpen);
153 return isOpen;
154 }
155
ParseConfInner(const Json::Value & config)156 void BatteryConfig::ParseConfInner(const Json::Value& config)
157 {
158 BATTERY_HILOGI(COMP_HDI, "start parse battery config inner");
159 ParseLightConfig(GetValue(config, "light"));
160 ParseChargerConfig(GetValue(config, "charger"));
161 }
162
ParseConfSplit(const Json::Value & config)163 void BatteryConfig::ParseConfSplit(const Json::Value& config)
164 {
165 BATTERY_HILOGI(COMP_HDI, "start parse split config inner");
166 ParseChargeSceneConfig(GetValue(config, "charge_scene"));
167 ParseUeventConfig(GetValue(config, "uevent"));
168 }
169
ParseChargerConfig(const Json::Value & chargerConfig)170 void BatteryConfig::ParseChargerConfig(const Json::Value& chargerConfig)
171 {
172 if (chargerConfig.isNull() || !chargerConfig.isObject()) {
173 BATTERY_HILOGW(COMP_HDI, "chargerConfig is invalid");
174 return;
175 }
176
177 Json::Value currentPath = GetValue(chargerConfig, "current_limit.path");
178 if (isValidJsonString(currentPath)) {
179 chargerConfig_.currentPath = currentPath.asString();
180 }
181
182 Json::Value voltagePath = GetValue(chargerConfig, "voltage_limit.path");
183 if (isValidJsonString(voltagePath)) {
184 chargerConfig_.voltagePath = voltagePath.asString();
185 }
186
187 Json::Value chargeTypePath = GetValue(chargerConfig, "type.path");
188 if (isValidJsonString(chargeTypePath)) {
189 chargerConfig_.chargeTypePath = chargeTypePath.asString();
190 }
191 BATTERY_HILOGI(COMP_HDI, "The battery charger configuration parse succeed");
192 }
193
ParseLightConfig(const Json::Value & lightConfig)194 void BatteryConfig::ParseLightConfig(const Json::Value& lightConfig)
195 {
196 if (lightConfig.isNull() || !lightConfig.isObject()) {
197 BATTERY_HILOGW(COMP_HDI, "lightConf is invalid");
198 return;
199 }
200 lightConfig_.clear();
201 Json::Value::Members members = lightConfig.getMemberNames();
202 for (auto iter = members.begin(); iter != members.end(); iter++) {
203 std::string key = *iter;
204 Json::Value valueObj = lightConfig[key];
205 if (valueObj.isNull() || !valueObj.isObject()) {
206 BATTERY_HILOGW(COMP_HDI, "The light conf is invalid, key=%{public}s", key.c_str());
207 continue;
208 }
209
210 Json::Value soc = GetValue(valueObj, "soc");
211 Json::Value rgb = GetValue(valueObj, "rgb");
212 if (!soc.isArray() || !rgb.isArray()) {
213 BATTERY_HILOGW(COMP_HDI, "The battery light %{public}s configuration is invalid.", key.c_str());
214 continue;
215 }
216 if (soc.size() != MAX_SOC_RANGE || !soc[BEGIN_SOC_INDEX].isInt() || !soc[END_SOC_INDEX].isInt()) {
217 BATTERY_HILOGW(COMP_HDI, "The battery light %{public}s soc data type error.", key.c_str());
218 continue;
219 }
220 if (rgb.size() != MAX_RGB_RANGE || !rgb[RED_INDEX].isUInt() || !rgb[GREEN_INDEX].isUInt() ||
221 !rgb[BLUE_INDEX].isUInt()) {
222 BATTERY_HILOGW(COMP_HDI, "The battery light %{public}s rgb data type error.", key.c_str());
223 continue;
224 }
225
226 BatteryConfig::LightConfig tempLightConfig = {
227 .beginSoc = soc[BEGIN_SOC_INDEX].asInt(),
228 .endSoc = soc[END_SOC_INDEX].asInt(),
229 .rgb = (rgb[RED_INDEX].asUInt() << MOVE_LEFT_16) |
230 (rgb[GREEN_INDEX].asUInt() << MOVE_LEFT_8) |
231 rgb[BLUE_INDEX].asUInt()
232 };
233 lightConfig_.push_back(tempLightConfig);
234 }
235 BATTERY_HILOGI(COMP_HDI, "The battery light configuration size %{public}d",
236 static_cast<int32_t>(lightConfig_.size()));
237 }
238
ParseChargeSceneConfig(const Json::Value & chargeSceneConfig)239 void BatteryConfig::ParseChargeSceneConfig(const Json::Value& chargeSceneConfig)
240 {
241 if (chargeSceneConfig.isNull() || !chargeSceneConfig.isObject()) {
242 BATTERY_HILOGW(COMP_HDI, "chargeSceneConfig is invalid");
243 return;
244 }
245
246 chargeSceneConfigMap_.clear();
247 Json::Value::Members members = chargeSceneConfig.getMemberNames();
248 for (auto iter = members.begin(); iter != members.end(); iter++) {
249 std::string key = *iter;
250 Json::Value valueObj = chargeSceneConfig[key];
251 if (!IsValidChargeSceneConfig(key, valueObj)) {
252 continue;
253 }
254
255 BatteryConfig::ChargeSceneConfig tempChargeSceneConfig;
256 bool parseSupportPathResult = ParseChargeSceneSupport(valueObj, tempChargeSceneConfig);
257 bool parseSetPathResult = ParseChargeSceneSet(valueObj, tempChargeSceneConfig);
258 bool parseGetPathResult = ParseChargeSceneGet(valueObj, tempChargeSceneConfig);
259 if (parseSupportPathResult || parseSetPathResult || parseGetPathResult) {
260 chargeSceneConfigMap_.insert(std::make_pair(key, tempChargeSceneConfig));
261 }
262 }
263
264 BATTERY_HILOGI(COMP_HDI, "The charge scene config size: %{public}d",
265 static_cast<int32_t>(chargeSceneConfigMap_.size()));
266 }
267
IsValidChargeSceneConfig(const std::string & key,const Json::Value & valueObj)268 bool BatteryConfig::IsValidChargeSceneConfig(const std::string& key, const Json::Value& valueObj)
269 {
270 if (key.empty() || valueObj.isNull() || !valueObj.isObject()) {
271 BATTERY_HILOGW(COMP_HDI, "The charge scene config is invalid, key=%{public}s", key.c_str());
272 return false;
273 }
274
275 Json::Value supportPath = GetValue(valueObj, "support.path");
276 Json::Value setPath = GetValue(valueObj, "set.path");
277 Json::Value getPath = GetValue(valueObj, "get.path");
278 if (!isValidJsonString(supportPath) && !isValidJsonString(setPath) && !isValidJsonString(getPath)) {
279 BATTERY_HILOGW(COMP_HDI, "The charge scene config path is invalid, key=%{public}s", key.c_str());
280 return false;
281 }
282
283 return true;
284 }
285
ParseChargeSceneSupport(const Json::Value & valueObj,BatteryConfig::ChargeSceneConfig & config)286 bool BatteryConfig::ParseChargeSceneSupport(const Json::Value& valueObj, BatteryConfig::ChargeSceneConfig& config)
287 {
288 Json::Value supportPath = GetValue(valueObj, "support.path");
289 Json::Value type = GetValue(valueObj, "support.type");
290 Json::Value expectValue = GetValue(valueObj, "support.expect_value");
291 if (isValidJsonString(supportPath)) {
292 std::string path = supportPath.asString();
293 if (IsValidSysPath(path)) {
294 config.supportPath = path;
295 config.type = isValidJsonString(type) ? type.asString() : "";
296 config.expectValue = isValidJsonString(expectValue) ? expectValue.asString() : "";
297 return true;
298 }
299 }
300 return false;
301 }
302
ParseChargeSceneSet(const Json::Value & valueObj,BatteryConfig::ChargeSceneConfig & config)303 bool BatteryConfig::ParseChargeSceneSet(const Json::Value& valueObj, BatteryConfig::ChargeSceneConfig& config)
304 {
305 Json::Value setPath = GetValue(valueObj, "set.path");
306 if (isValidJsonString(setPath)) {
307 std::string path = setPath.asString();
308 if (IsValidSysPath(path)) {
309 config.setPath = path;
310 return true;
311 }
312 }
313 return false;
314 }
315
ParseChargeSceneGet(const Json::Value & valueObj,BatteryConfig::ChargeSceneConfig & config)316 bool BatteryConfig::ParseChargeSceneGet(const Json::Value& valueObj, BatteryConfig::ChargeSceneConfig& config)
317 {
318 Json::Value getPath = GetValue(valueObj, "get.path");
319 if (isValidJsonString(getPath)) {
320 std::string path = getPath.asString();
321 if (IsValidSysPath(path)) {
322 config.getPath = path;
323 return true;
324 }
325 }
326 return false;
327 }
328
IsValidSysPath(const std::string & path)329 bool BatteryConfig::IsValidSysPath(const std::string& path)
330 {
331 char resolvedPath[PATH_MAX] = {};
332 if ((realpath(path.c_str(), resolvedPath) == nullptr) ||
333 ((strncmp(resolvedPath, "/sys", SYSTEM_PATH_CHECK) != 0) &&
334 (strncmp(resolvedPath, "/data", DATA_PATH_CHECK) != 0))) {
335 return false;
336 }
337 return true;
338 }
339
ParseUeventConfig(const Json::Value & ueventConfig)340 void BatteryConfig::ParseUeventConfig(const Json::Value& ueventConfig)
341 {
342 if (ueventConfig.isNull() || !ueventConfig.isObject()) {
343 BATTERY_HILOGW(COMP_HDI, "ueventConfig is invalid");
344 return;
345 }
346 ueventMap_.clear();
347 Json::Value::Members members = ueventConfig.getMemberNames();
348 for (auto iter = members.begin(); iter != members.end(); iter++) {
349 std::string key = *iter;
350 Json::Value valueObj = ueventConfig[key];
351 if (valueObj.isNull() || !valueObj.isObject()) {
352 BATTERY_HILOGW(COMP_HDI, "The uevent conf is invalid, key=%{public}s", key.c_str());
353 continue;
354 }
355 std::vector<std::pair<std::string, std::string>> ueventList;
356 Json::Value::Members ObjMembers = valueObj.getMemberNames();
357 for (auto it = ObjMembers.begin(); it != ObjMembers.end(); it++) {
358 std::string event = *it;
359 if (!valueObj[event].isString()) {
360 BATTERY_HILOGW(COMP_SVC, "The uevent conf is invalid, key=%{public}s", key.c_str());
361 }
362 std::string act = valueObj[event].asString();
363 ueventList.push_back(std::make_pair(event, act));
364 }
365 ueventMap_.emplace(*iter, ueventList);
366 BATTERY_HILOGI(COMP_HDI, "%{public}s size: %{public}d", key.c_str(),
367 static_cast<int32_t>(ueventList.size()));
368 }
369 BATTERY_HILOGI(COMP_HDI, "The uevent config size: %{public}d", static_cast<int32_t>(ueventMap_.size()));
370 }
371
SplitKey(const std::string & key,std::vector<std::string> & keys) const372 bool BatteryConfig::SplitKey(const std::string& key, std::vector<std::string>& keys) const
373 {
374 SplitStr(TrimStr(key), ".", keys);
375 return (keys.size() < MIN_DEPTH || keys.size() > MAX_DEPTH) ? false : true;
376 }
377
GetValue(const Json::Value & config,std::string key) const378 Json::Value BatteryConfig::GetValue(const Json::Value& config, std::string key) const
379 {
380 std::vector<std::string> keys;
381 if (!SplitKey(key, keys)) {
382 BATTERY_HILOGW(COMP_HDI, "The key does not meet the. key=%{public}s", key.c_str());
383 return Json::Value();
384 }
385
386 std::string firstKey = keys[MAP_KEY_INDEX];
387 Json::Value value = (config.isObject() && config.isMember(firstKey)) ? config[firstKey] : Json::Value();
388 if (value.isNull()) {
389 BATTERY_HILOGD(COMP_HDI, "Value is empty. key=%{public}s", key.c_str());
390 return value;
391 }
392
393 for (size_t i = 1; i < keys.size(); ++i) {
394 if (!value.isObject() || !value.isMember(keys[i])) {
395 BATTERY_HILOGW(COMP_HDI, "The key is not configured. key=%{public}s", keys[i].c_str());
396 break;
397 }
398 value = value[keys[i]];
399 }
400 return value;
401 }
402
isValidJsonString(const Json::Value & config) const403 bool BatteryConfig::isValidJsonString(const Json::Value& config) const
404 {
405 return !config.isNull() && config.isString();
406 }
407 } // namespace V2_0
408 } // namespace Battery
409 } // namespace HDI
410 } // namespace OHOS
411