/* * Copyright (c) 2022-2023 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "battery_config.h" #include "battery_log.h" #include #include "string_ex.h" #include "config_policy_utils.h" namespace OHOS { namespace HDI { namespace Battery { namespace V2_0 { namespace { constexpr const char* BATTERY_CONFIG_PATH = "etc/battery/battery_config.json"; constexpr const char* SYSTEM_BATTERY_CONFIG_PATH = "/system/etc/battery/battery_config.json"; constexpr const char* VENDOR_BATTERY_CONFIG_PATH = "/vendor/etc/battery/battery_config.json"; constexpr const char* VENDOR_BATTERY_SPLIT_CONFIG_PATH = "/vendor/etc/battery/charge_config.json"; constexpr const char* BATTERY_CONFIG_EXCEPTION_PATH = ""; constexpr int32_t MAP_KEY_INDEX = 0; constexpr int32_t BEGIN_SOC_INDEX = 0; constexpr int32_t END_SOC_INDEX = 1; constexpr int32_t MAX_SOC_RANGE = 2; constexpr int32_t RED_INDEX = 0; constexpr int32_t GREEN_INDEX = 1; constexpr int32_t BLUE_INDEX = 2; constexpr int32_t MAX_RGB_RANGE = 3; constexpr int32_t MAX_DEPTH = 5; constexpr int32_t MIN_DEPTH = 1; constexpr uint32_t MOVE_LEFT_16 = 16; constexpr uint32_t MOVE_LEFT_8 = 8; constexpr uint32_t SYSTEM_PATH_CHECK = 4; constexpr uint32_t DATA_PATH_CHECK = 5; } std::shared_ptr BatteryConfig::instance_ = nullptr; std::mutex BatteryConfig::mutex_; BatteryConfig& BatteryConfig::GetInstance() { std::lock_guard lock(mutex_); if (instance_ == nullptr) { instance_ = std::make_shared(); } return *(instance_.get()); } bool BatteryConfig::ParseConfig() { char buf[MAX_PATH_LEN]; char* path = GetOneCfgFile(BATTERY_CONFIG_PATH, buf, MAX_PATH_LEN); if (path == nullptr || *path == '\0') { BATTERY_HILOGW(COMP_HDI, "GetOneCfgFile battery_config.json is NULL"); path = const_cast(BATTERY_CONFIG_EXCEPTION_PATH); } BATTERY_HILOGD(COMP_HDI, "GetOneCfgFile battery_config.json"); Json::CharReaderBuilder readerBuilder; std::ifstream ifsConf; Json::Value config; readerBuilder["collectComments"] = false; JSONCPP_STRING errs; ifsConf.open(VENDOR_BATTERY_SPLIT_CONFIG_PATH); bool isOpen = ifsConf.is_open(); if (isOpen) { if (parseFromStream(readerBuilder, ifsConf, &config, &errs) && !config.empty()) { ParseConfSplit(config); } ifsConf.close(); if (!OpenFile(ifsConf, path)) { return false; } if (parseFromStream(readerBuilder, ifsConf, &config, &errs) && !config.empty()) { ParseConfInner(config); } } else { if (!OpenFile(ifsConf, path)) { return false; } if (parseFromStream(readerBuilder, ifsConf, &config, &errs) && !config.empty()) { ParseConfInner(config); ParseConfSplit(config); } } ifsConf.close(); return true; } const std::vector& BatteryConfig::GetLightConfig() const { return lightConfig_; } const BatteryConfig::ChargerConfig& BatteryConfig::GetChargerConfig() const { return chargerConfig_; } const std::map& BatteryConfig::GetChargeSceneConfigMap() const { return chargeSceneConfigMap_; } const UeventMap& BatteryConfig::GetUeventList() const { return ueventMap_; } void BatteryConfig::DestroyInstance() { std::lock_guard lock(mutex_); instance_ = nullptr; } bool BatteryConfig::OpenFile(std::ifstream& ifsConf, const std::string& configPath) { bool isOpen = false; if (!configPath.empty()) { ifsConf.open(configPath); isOpen = ifsConf.is_open(); BATTERY_HILOGD(COMP_HDI, "open file is %{public}d", isOpen); } if (isOpen) { return true; } ifsConf.open(VENDOR_BATTERY_CONFIG_PATH); isOpen = ifsConf.is_open(); BATTERY_HILOGI(COMP_HDI, "open then vendor battery_config.json is %{public}d", isOpen); if (isOpen) { return true; } ifsConf.open(SYSTEM_BATTERY_CONFIG_PATH); isOpen = ifsConf.is_open(); BATTERY_HILOGI(FEATURE_CHARGING, "open then system battery_config.json is %{public}d", isOpen); return isOpen; } void BatteryConfig::ParseConfInner(const Json::Value& config) { BATTERY_HILOGI(COMP_HDI, "start parse battery config inner"); ParseLightConfig(GetValue(config, "light")); ParseChargerConfig(GetValue(config, "charger")); } void BatteryConfig::ParseConfSplit(const Json::Value& config) { BATTERY_HILOGI(COMP_HDI, "start parse split config inner"); ParseChargeSceneConfig(GetValue(config, "charge_scene")); ParseUeventConfig(GetValue(config, "uevent")); } void BatteryConfig::ParseChargerConfig(const Json::Value& chargerConfig) { if (chargerConfig.isNull() || !chargerConfig.isObject()) { BATTERY_HILOGW(COMP_HDI, "chargerConfig is invalid"); return; } Json::Value currentPath = GetValue(chargerConfig, "current_limit.path"); if (isValidJsonString(currentPath)) { chargerConfig_.currentPath = currentPath.asString(); } Json::Value voltagePath = GetValue(chargerConfig, "voltage_limit.path"); if (isValidJsonString(voltagePath)) { chargerConfig_.voltagePath = voltagePath.asString(); } Json::Value chargeTypePath = GetValue(chargerConfig, "type.path"); if (isValidJsonString(chargeTypePath)) { chargerConfig_.chargeTypePath = chargeTypePath.asString(); } BATTERY_HILOGI(COMP_HDI, "The battery charger configuration parse succeed"); } void BatteryConfig::ParseLightConfig(const Json::Value& lightConfig) { if (lightConfig.isNull() || !lightConfig.isObject()) { BATTERY_HILOGW(COMP_HDI, "lightConf is invalid"); return; } lightConfig_.clear(); Json::Value::Members members = lightConfig.getMemberNames(); for (auto iter = members.begin(); iter != members.end(); iter++) { std::string key = *iter; Json::Value valueObj = lightConfig[key]; if (valueObj.isNull() || !valueObj.isObject()) { BATTERY_HILOGW(COMP_HDI, "The light conf is invalid, key=%{public}s", key.c_str()); continue; } Json::Value soc = GetValue(valueObj, "soc"); Json::Value rgb = GetValue(valueObj, "rgb"); if (!soc.isArray() || !rgb.isArray()) { BATTERY_HILOGW(COMP_HDI, "The battery light %{public}s configuration is invalid.", key.c_str()); continue; } if (soc.size() != MAX_SOC_RANGE || !soc[BEGIN_SOC_INDEX].isInt() || !soc[END_SOC_INDEX].isInt()) { BATTERY_HILOGW(COMP_HDI, "The battery light %{public}s soc data type error.", key.c_str()); continue; } if (rgb.size() != MAX_RGB_RANGE || !rgb[RED_INDEX].isUInt() || !rgb[GREEN_INDEX].isUInt() || !rgb[BLUE_INDEX].isUInt()) { BATTERY_HILOGW(COMP_HDI, "The battery light %{public}s rgb data type error.", key.c_str()); continue; } BatteryConfig::LightConfig tempLightConfig = { .beginSoc = soc[BEGIN_SOC_INDEX].asInt(), .endSoc = soc[END_SOC_INDEX].asInt(), .rgb = (rgb[RED_INDEX].asUInt() << MOVE_LEFT_16) | (rgb[GREEN_INDEX].asUInt() << MOVE_LEFT_8) | rgb[BLUE_INDEX].asUInt() }; lightConfig_.push_back(tempLightConfig); } BATTERY_HILOGI(COMP_HDI, "The battery light configuration size %{public}d", static_cast(lightConfig_.size())); } void BatteryConfig::ParseChargeSceneConfig(const Json::Value& chargeSceneConfig) { if (chargeSceneConfig.isNull() || !chargeSceneConfig.isObject()) { BATTERY_HILOGW(COMP_HDI, "chargeSceneConfig is invalid"); return; } chargeSceneConfigMap_.clear(); Json::Value::Members members = chargeSceneConfig.getMemberNames(); for (auto iter = members.begin(); iter != members.end(); iter++) { std::string key = *iter; Json::Value valueObj = chargeSceneConfig[key]; if (!IsValidChargeSceneConfig(key, valueObj)) { continue; } BatteryConfig::ChargeSceneConfig tempChargeSceneConfig; bool parseSupportPathResult = ParseChargeSceneSupport(valueObj, tempChargeSceneConfig); bool parseSetPathResult = ParseChargeSceneSet(valueObj, tempChargeSceneConfig); bool parseGetPathResult = ParseChargeSceneGet(valueObj, tempChargeSceneConfig); if (parseSupportPathResult || parseSetPathResult || parseGetPathResult) { chargeSceneConfigMap_.insert(std::make_pair(key, tempChargeSceneConfig)); } } BATTERY_HILOGI(COMP_HDI, "The charge scene config size: %{public}d", static_cast(chargeSceneConfigMap_.size())); } bool BatteryConfig::IsValidChargeSceneConfig(const std::string& key, const Json::Value& valueObj) { if (key.empty() || valueObj.isNull() || !valueObj.isObject()) { BATTERY_HILOGW(COMP_HDI, "The charge scene config is invalid, key=%{public}s", key.c_str()); return false; } Json::Value supportPath = GetValue(valueObj, "support.path"); Json::Value setPath = GetValue(valueObj, "set.path"); Json::Value getPath = GetValue(valueObj, "get.path"); if (!isValidJsonString(supportPath) && !isValidJsonString(setPath) && !isValidJsonString(getPath)) { BATTERY_HILOGW(COMP_HDI, "The charge scene config path is invalid, key=%{public}s", key.c_str()); return false; } return true; } bool BatteryConfig::ParseChargeSceneSupport(const Json::Value& valueObj, BatteryConfig::ChargeSceneConfig& config) { Json::Value supportPath = GetValue(valueObj, "support.path"); Json::Value type = GetValue(valueObj, "support.type"); Json::Value expectValue = GetValue(valueObj, "support.expect_value"); if (isValidJsonString(supportPath)) { std::string path = supportPath.asString(); if (IsValidSysPath(path)) { config.supportPath = path; config.type = isValidJsonString(type) ? type.asString() : ""; config.expectValue = isValidJsonString(expectValue) ? expectValue.asString() : ""; return true; } } return false; } bool BatteryConfig::ParseChargeSceneSet(const Json::Value& valueObj, BatteryConfig::ChargeSceneConfig& config) { Json::Value setPath = GetValue(valueObj, "set.path"); if (isValidJsonString(setPath)) { std::string path = setPath.asString(); if (IsValidSysPath(path)) { config.setPath = path; return true; } } return false; } bool BatteryConfig::ParseChargeSceneGet(const Json::Value& valueObj, BatteryConfig::ChargeSceneConfig& config) { Json::Value getPath = GetValue(valueObj, "get.path"); if (isValidJsonString(getPath)) { std::string path = getPath.asString(); if (IsValidSysPath(path)) { config.getPath = path; return true; } } return false; } bool BatteryConfig::IsValidSysPath(const std::string& path) { char resolvedPath[PATH_MAX] = {}; if ((realpath(path.c_str(), resolvedPath) == nullptr) || ((strncmp(resolvedPath, "/sys", SYSTEM_PATH_CHECK) != 0) && (strncmp(resolvedPath, "/data", DATA_PATH_CHECK) != 0))) { return false; } return true; } void BatteryConfig::ParseUeventConfig(const Json::Value& ueventConfig) { if (ueventConfig.isNull() || !ueventConfig.isObject()) { BATTERY_HILOGW(COMP_HDI, "ueventConfig is invalid"); return; } ueventMap_.clear(); Json::Value::Members members = ueventConfig.getMemberNames(); for (auto iter = members.begin(); iter != members.end(); iter++) { std::string key = *iter; Json::Value valueObj = ueventConfig[key]; if (valueObj.isNull() || !valueObj.isObject()) { BATTERY_HILOGW(COMP_HDI, "The uevent conf is invalid, key=%{public}s", key.c_str()); continue; } std::vector> ueventList; Json::Value::Members ObjMembers = valueObj.getMemberNames(); for (auto it = ObjMembers.begin(); it != ObjMembers.end(); it++) { std::string event = *it; if (!valueObj[event].isString()) { BATTERY_HILOGW(COMP_SVC, "The uevent conf is invalid, key=%{public}s", key.c_str()); } std::string act = valueObj[event].asString(); ueventList.push_back(std::make_pair(event, act)); } ueventMap_.emplace(*iter, ueventList); BATTERY_HILOGI(COMP_HDI, "%{public}s size: %{public}d", key.c_str(), static_cast(ueventList.size())); } BATTERY_HILOGI(COMP_HDI, "The uevent config size: %{public}d", static_cast(ueventMap_.size())); } bool BatteryConfig::SplitKey(const std::string& key, std::vector& keys) const { SplitStr(TrimStr(key), ".", keys); return (keys.size() < MIN_DEPTH || keys.size() > MAX_DEPTH) ? false : true; } Json::Value BatteryConfig::GetValue(const Json::Value& config, std::string key) const { std::vector keys; if (!SplitKey(key, keys)) { BATTERY_HILOGW(COMP_HDI, "The key does not meet the. key=%{public}s", key.c_str()); return Json::Value(); } std::string firstKey = keys[MAP_KEY_INDEX]; Json::Value value = (config.isObject() && config.isMember(firstKey)) ? config[firstKey] : Json::Value(); if (value.isNull()) { BATTERY_HILOGD(COMP_HDI, "Value is empty. key=%{public}s", key.c_str()); return value; } for (size_t i = 1; i < keys.size(); ++i) { if (!value.isObject() || !value.isMember(keys[i])) { BATTERY_HILOGW(COMP_HDI, "The key is not configured. key=%{public}s", keys[i].c_str()); break; } value = value[keys[i]]; } return value; } bool BatteryConfig::isValidJsonString(const Json::Value& config) const { return !config.isNull() && config.isString(); } } // namespace V2_0 } // namespace Battery } // namespace HDI } // namespace OHOS