diff --git a/bundle.json b/bundle.json index 0432c0f9677afa9d0f18be3abeb07c7fb267878a..7c021ef2121bff26b4229ed4d98fe003d9c83780 100644 --- a/bundle.json +++ b/bundle.json @@ -32,7 +32,8 @@ "ipc", "jsoncpp", "safwk", - "samgr" + "samgr", + "libxml2" ], "third_party": [ "json" @@ -45,7 +46,8 @@ "//foundation/resourceschedule/qos_manager/services:concurrentsvc", "//foundation/resourceschedule/qos_manager/frameworks/concurrent_task_client:concurrent_task_client", "//foundation/resourceschedule/qos_manager/qos:qos", - "//foundation/resourceschedule/qos_manager/frameworks/native:qos_ndk" + "//foundation/resourceschedule/qos_manager/frameworks/native:qos_ndk", + "//foundation/resourceschedule/qos_manager/qos_pro:qos_pro" ], "inner_kits": [ { diff --git a/qos/qos.cpp b/qos/qos.cpp index fc928a6899aa17bf845996ee14106a4a994673dd..ca4f037f3f62d4ed54a00d566dc46c14df5693f0 100644 --- a/qos/qos.cpp +++ b/qos/qos.cpp @@ -75,16 +75,18 @@ int QosController::GetThreadQosForOtherThread(enum QosLevel &level, int tid) int qos; int ret = QosGetForOther(tid, qos); if (ret == 0) { + if (qos < static_cast(QosLevel::QOS_BACKGROUND) || + qos >= static_cast(QosLevel::QOS_MAX)) { + CONCUR_LOGD("[Qos] not set qos for tid %{public}d ", tid); + return ERROR_NUM; + } CONCUR_LOGD("[Qos] qoslevel get for tid %{public}d success", tid); + level = static_cast(qos); + return ret; } else { CONCUR_LOGE("[Qos] qoslevel get for tid %{public}d failure", tid); + return ret; } - if (qos < static_cast(QosLevel::QOS_BACKGROUND) || qos >= static_cast(QosLevel::QOS_MAX)) { - return ERROR_NUM; - } - level = static_cast(qos); - - return ret; } int SetThreadQos(enum QosLevel level) diff --git a/qos_pro/BUILD.gn b/qos_pro/BUILD.gn new file mode 100644 index 0000000000000000000000000000000000000000..165c8d23b6f752eaff94d15b3668240e6cd25904 --- /dev/null +++ b/qos_pro/BUILD.gn @@ -0,0 +1,38 @@ +# Copyright (C) 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. + +import("//build/ohos.gni") + +ohos_shared_library("qos_pro") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + + include_dirs = [ + "include/", + "../include", + ] + + sources = [ "src/qos_config_manager.cpp" ] + + external_deps = [ + "hilog:libhilog", + "libxml2:libxml2", + ] + + subsystem_name = "resourceschedule" + part_name = "qos_manager" +} diff --git a/qos_pro/include/qos_config_manager.h b/qos_pro/include/qos_config_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..d52659284e641133c9c028261c3e1ce6620f06d8 --- /dev/null +++ b/qos_pro/include/qos_config_manager.h @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2024 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. + */ +#ifndef QOS_CONFIG_MANAGER_H +#define QOS_CONFIG_MANAGER_H + +#include +#include +#include "libxml/parser.h" + +namespace OHOS { +namespace ConcurrentTask { + +#define TO_STRING(ENUM) #ENUM +#define STRING_ENUM_PAIR(ENUM) {TO_STRING(ENUM), ENUM} +#define SCHED_STRING_ENUM_PAIR(ENUM) {TO_STRING(ENUM), SCHED_POLICY_##ENUM} + +enum QosLevel { + QOS_BACKGROUND, + QOS_UTILITY, + QOS_DEFAULT, + QOS_USER_INITIATED, + QOS_DEADLINE_REQUEST, + QOS_USER_INTERACTIVE, + QOS_KEY_BACKGROUND, + QOS_MAX, +}; + +struct QosPolicyConfig { + int nice; + int latencyNice; + int uclampMin; + int uclampMax; + int rtSchedPriority; + int policy; + int quota; +}; + +enum SchedPolicy { + SCHED_POLICY_OTHER = 0, + SCHED_POLICY_FIFO = 1, + SCHED_POLICY_RR = 2, + SCHED_POLICY_RT_EX = 0xFF, +}; + +enum QosPolicyType { + QOS_POLICY_DEFAULT = 1, + QOS_POLICY_SYSTEM_SERVER = 2, + QOS_POLICY_FRONT = 3, + QOS_POLICY_BACK = 4, + QOS_POLICY_FOCUS = 5, + QOS_POLICY_MAX_NR, +}; + + +#define SCHED_POLICY_RESET_ON_FORK 0x40000000 + +struct StatusConfig { + struct QosPolicyConfig policies[QOS_MAX]; +}; + +struct SceneConfig { + struct StatusConfig status[QOS_POLICY_MAX_NR]; +}; + +using SceneConfigMap = std::unordered_map; + +class QosConfigManager { +public: + static QosConfigManager& GetInstance(); + bool LoadConfigXML(const std::string& filepath); + void Init(); + void Release(); + SceneConfigMap GetSceneConfig(); + +private: + QosConfigManager() = default; + ~QosConfigManager() = default; + + QosConfigManager(const QosConfigManager&) = delete; + QosConfigManager& operator=(const QosConfigManager&) = delete; + QosConfigManager(QosConfigManager&&) = delete; + QosConfigManager& operator=(const QosConfigManager&&) = delete; + + int StrToInt32(const char* num); + bool IsValidNode(const xmlNodePtr node); + bool IsNumber(const char* num); + bool CheckIdAndName(const char* id, const char* name); + bool ReadSceneConfig(const xmlNodePtr node); + bool ReadSystemAppList(const xmlNodePtr node); + bool ReadWhiteList(const xmlNodePtr node); + bool ReadBlackList(const xmlNodePtr node); + bool ReadStatusConfig(const xmlNodePtr node, StatusConfig& statusConfig); + bool ReadQosLevelConfig(const xmlNodePtr node, QosPolicyConfig& qosPolicy); + bool ReadPolicyConfig(std::string& policyName, char* value, QosPolicyConfig& qosConfig); + bool ReadNice(char* value, int& nice); + bool ReadLatencyNice(char* value, int& uclampMin); + bool ReadUclampMin(char* value, int& uclampMax); + bool ReadUclampMax(char* value, int& uclampMax); + bool ReadRt(char* value, int& rt); + bool ReadSchedPolicy(const std::string& policyStr, int& policy); + bool ReadQuota(char* value, int& quota); + bool IsValidNice(int nice); + bool IsValidUclamp(int uclamp); + bool IsValidRt(int rt); + bool IsValidQuota(int quota); + void InitStatusStringToIndexMap(); + void InitQosStringToIndexMap(); + void InitSchedPolicyToValueMap(); + + bool configInitialized_ = false; + std::unordered_map statusStringToIndexMap_; + std::unordered_map qosStringToIndexMap_; + std::unordered_map schedPolicyToValueMap_; + SceneConfigMap sceneMap_; +}; +} +} +#endif \ No newline at end of file diff --git a/qos_pro/src/qos_config_manager.cpp b/qos_pro/src/qos_config_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..87c853a453dd6de6a23f4fbe2f26118b7a98f9b1 --- /dev/null +++ b/qos_pro/src/qos_config_manager.cpp @@ -0,0 +1,429 @@ +/* + * Copyright (c) 2024 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 "qos_config_manager.h" +#include +#include +#include +#include "concurrent_task_log.h" + +namespace OHOS { +namespace ConcurrentTask { +namespace { + const std::string QOS_CONFIG_FILE = ""; + const std::string NICE = "nice"; + const std::string LATENCY_NICE = "latency_nice"; + const std::string UCLAMP_MIN = "uclamp_min"; + const std::string UCLAMP_MAX = "uclamp_max"; + const std::string RT = "rt"; + const std::string SCHED_POLICY = "sched_policy"; + const std::string QUOTA = "quota"; + constexpr int NICE_MIN = -20; + constexpr int NICE_MAX = 19; + constexpr int UCLAMP_MIN_VALUE = 0; + constexpr int UCLAMP_MAX_VALUE = 1024; + constexpr int RT_MIN = 0; + constexpr int RT_MAX = 99; +} + +QosConfigManager& QosConfigManager::GetInstance() +{ + static QosConfigManager instance; + return instance; +} + +bool QosConfigManager::LoadConfigXML(const std::string& filepath) +{ + if (!configInitialized_) { + Init(); + } + xmlDocPtr docPtr = xmlReadFile(filepath.c_str(), nullptr, XML_PARSE_NOBLANKS); + if (docPtr == nullptr) { + CONCUR_LOGE("load xml failed!"); + return false; + } + + xmlNodePtr rootPtr = xmlDocGetRootElement(docPtr); + if (rootPtr == nullptr || rootPtr->name == nullptr || + xmlStrcmp(rootPtr->name, reinterpret_cast("Configs"))) { + CONCUR_LOGE("get xml root element failed!"); + xmlFreeDoc(docPtr); + return false; + } + + for (xmlNodePtr currNode = rootPtr->xmlChildrenNode; currNode != nullptr; currNode = currNode->next) { + if (!IsValidNode(currNode)) { + CONCUR_LOGW("invalid xml node"); + continue; + } + if (!xmlStrcmp(currNode->name, reinterpret_cast("scene"))) { + if (!ReadSceneConfig(currNode)) { + return false; + } + } else if (!xmlStrcmp(currNode->name, reinterpret_cast("authsystemapplist"))) { + if (!ReadSystemAppList(currNode)) { + return false; + } + } else if (!xmlStrcmp(currNode->name, reinterpret_cast("whitelist"))) { + if (!ReadWhiteList(currNode)) { + return false; + } + } else if (!xmlStrcmp(currNode->name, reinterpret_cast("blocklist"))) { + if (!ReadBlackList(currNode)) { + return false; + } + } + } + xmlFreeDoc(docPtr); + return true; +} + +bool QosConfigManager::ReadSceneConfig(const xmlNodePtr node) +{ + char* id = reinterpret_cast(xmlGetProp(node, reinterpret_cast("id"))); + char* name = reinterpret_cast(xmlGetProp(node, reinterpret_cast("name"))); + if (!CheckIdAndName(id, name)) { + xmlFree(id); + xmlFree(name); + return false; + } + + if (sceneMap_.find(name) == sceneMap_.end()) { + if (sceneMap_.size() == 0 && strcmp(name, "base") != 0) { + CONCUR_LOGE("please fisrt fill base scene configuration!"); + return false; + } + // The basic scene is the foundation of other scenes, + // and other scenes inherit the configuration of the basic scene by default. + SceneConfig sceneConfig = sceneMap_["base"]; + for (xmlNodePtr currNode = node->xmlChildrenNode; currNode != nullptr; currNode = currNode->next) { + if (!IsValidNode(currNode)) { + CONCUR_LOGW("invalid status xml node!"); + continue; + } + std::string currNodeName = reinterpret_cast(currNode->name); + if (statusStringToIndexMap_.find(currNodeName) == statusStringToIndexMap_.end()) { + CONCUR_LOGE("invlid status name %s", currNodeName.c_str()); + return false; + } + if (!ReadStatusConfig(currNode, sceneConfig.status[statusStringToIndexMap_[currNodeName]])) { + return false; + } + } + sceneMap_[name] = std::move(sceneConfig); + } + xmlFree(id); + xmlFree(name); + return true; +} + +bool QosConfigManager::ReadSystemAppList(const xmlNodePtr node) +{ + return true; +} + +bool QosConfigManager::ReadWhiteList(const xmlNodePtr node) +{ + return true; +} + +bool QosConfigManager::ReadBlackList(const xmlNodePtr node) +{ + return true; +} + +bool QosConfigManager::ReadStatusConfig(const xmlNodePtr node, StatusConfig& statusConfig) +{ + for (xmlNodePtr currNode = node->xmlChildrenNode; currNode != nullptr; currNode = currNode->next) { + if (!IsValidNode(currNode)) { + CONCUR_LOGE("invalid qos level xml node"); + continue; + } + std::string name = reinterpret_cast(currNode->name); + if (qosStringToIndexMap_.find(name) == qosStringToIndexMap_.end()) { + CONCUR_LOGE("invlid qos level name %s", name.c_str()); + return false; + } + if (!ReadQosLevelConfig(currNode, statusConfig.policies[qosStringToIndexMap_[name]])) { + return false; + } + } + + return true; +} + +bool QosConfigManager::ReadQosLevelConfig(const xmlNodePtr node, QosPolicyConfig& qosPolicy) +{ + for (xmlNodePtr currNode = node->xmlChildrenNode; currNode != nullptr; currNode = currNode->next) { + if (!IsValidNode(currNode)) { + CONCUR_LOGW("invalid qos level policy xml node"); + continue; + } + std::string policyName = reinterpret_cast(currNode->name); + char* value = reinterpret_cast(xmlNodeGetContent(currNode)); + if (!ReadPolicyConfig(policyName, value, qosPolicy)) { + xmlFree(value); + return false; + } + xmlFree(value); + } + + return true; +} + +bool QosConfigManager::ReadPolicyConfig(std::string& policy, char* value, QosPolicyConfig& qosPolicy) +{ + int ret = true; + if (policy == NICE) { + ret = ReadNice(value, qosPolicy.nice); + } else if (policy == LATENCY_NICE) { + ret = ReadLatencyNice(value, qosPolicy.latencyNice); + } else if (policy == UCLAMP_MIN) { + ret = ReadUclampMin(value, qosPolicy.uclampMin); + } else if (policy == UCLAMP_MAX) { + ret = ReadUclampMax(value, qosPolicy.uclampMax); + } else if (policy == RT) { + ret = ReadRt(value, qosPolicy.rtSchedPriority); + } else if (policy == SCHED_POLICY) { + ret = ReadSchedPolicy(value, qosPolicy.policy); + } else if (policy == QUOTA) { + ret = ReadQuota(value, qosPolicy.quota); + } else { + CONCUR_LOGE("invalid qos level policy name %s", policy.c_str()); + ret = false; + } + + return ret; +} + +bool QosConfigManager::ReadNice(char* value, int& nice) +{ + int num = StrToInt32(value); + if (!IsValidNice(num)) { + return false; + } + nice = num; + return true; +} + +bool QosConfigManager::ReadLatencyNice(char* value, int& latencyNice) +{ + int num = StrToInt32(value); + if (!IsValidUclamp(num)) { + return false; + } + latencyNice = num; + return true; +} + +bool QosConfigManager::ReadUclampMin(char* value, int& uclampMin) +{ + int num = StrToInt32(value); + if (!IsValidUclamp(num)) { + return false; + } + uclampMin = num; + return true; +} + +bool QosConfigManager::ReadUclampMax(char* value, int& uclampMax) +{ + int num = StrToInt32(value); + if (!IsValidUclamp(num)) { + return false; + } + uclampMax = num; + return true; +} + +bool QosConfigManager::ReadRt(char* value, int& rt) +{ + int num = StrToInt32(value); + if (!IsValidRt(num)) { + return false; + } + rt = num; + return true; +} + +bool QosConfigManager::ReadQuota(char* value, int& quota) +{ + int num = StrToInt32(value); + if (!IsValidQuota(num)) { + return false; + } + quota = num; + return true; +} + +bool QosConfigManager::ReadSchedPolicy(const std::string& policyStr, int& policy) +{ + std::stringstream ss; + std::string tmp; + ss << policyStr; + int value = 0; + while (getline(ss, tmp, '|')) { + if (schedPolicyToValueMap_.find(tmp) == schedPolicyToValueMap_.end()) { + CONCUR_LOGE("invalid sched policy %s", policyStr.c_str()); + return false; + } + value |= schedPolicyToValueMap_[tmp]; + } + policy = value; + return true; +} + +SceneConfigMap QosConfigManager::GetSceneConfig() +{ + return sceneMap_; +} + +bool QosConfigManager::IsValidNode(const xmlNodePtr node) +{ + if (node->name == nullptr || node->type == XML_COMMENT_NODE) { + return false; + } + return true; +} + +int QosConfigManager::StrToInt32(const char* num) +{ + char* endPtr = nullptr; + errno = 0; + int64_t res = strtol(num, &endPtr, 10); + if (errno == ERANGE || endPtr == num || *endPtr != '\0' || + (res < INT32_MIN || res > INT32_MAX)) { + return INT32_MIN; + } + return res; +} + +bool QosConfigManager::IsNumber(const char* num) +{ + char* endPtr = nullptr; + errno = 0; + int64_t res = strtol(num, &endPtr, 10); + if (errno == ERANGE || endPtr == num || *endPtr != '\0' || + (res < INT32_MIN || res > INT32_MAX)) { + return false; + } + return true; +} + +bool QosConfigManager::CheckIdAndName(const char* id, const char* name) +{ + if (!id || !IsNumber(id)) { + CONCUR_LOGE("invalid id!"); + return false; + } + if (!name) { + CONCUR_LOGE("invalid name!"); + return false; + } + return true; +} + +bool QosConfigManager::IsValidNice(int nice) +{ + if (nice < NICE_MIN || nice > NICE_MAX) { + CONCUR_LOGE("invalid nice or latency nice %d", nice); + return false; + } + return true; +} + +bool QosConfigManager::IsValidUclamp(int uclamp) +{ + if (uclamp < UCLAMP_MIN_VALUE || uclamp > UCLAMP_MAX_VALUE) { + CONCUR_LOGE("invalid uclamp %d", uclamp); + return false; + } + return true; +} + +bool QosConfigManager::IsValidRt(int rt) +{ + if (rt < RT_MIN || rt > RT_MAX) { + CONCUR_LOGE("invalid rt %d", rt); + return false; + } + return true; +} + +bool QosConfigManager::IsValidQuota(int quota) +{ + if (quota != -1) { + CONCUR_LOGE("invalid quota %d", quota); + return false; + } + return true; +} + +void QosConfigManager::Init() +{ + InitStatusStringToIndexMap(); + InitQosStringToIndexMap(); + InitSchedPolicyToValueMap(); + configInitialized_ = true; + return; +} + +void QosConfigManager::Release() +{ + statusStringToIndexMap_.clear(); + qosStringToIndexMap_.clear(); + schedPolicyToValueMap_.clear(); + sceneMap_.clear(); + configInitialized_ = false; + return; +} + +void QosConfigManager::InitStatusStringToIndexMap() +{ + statusStringToIndexMap_.clear(); + statusStringToIndexMap_.insert(std::pair("reserve", 0)); + statusStringToIndexMap_.insert(std::pair("default", QOS_POLICY_DEFAULT)); + statusStringToIndexMap_.insert(std::pair("system_server", QOS_POLICY_SYSTEM_SERVER)); + statusStringToIndexMap_.insert(std::pair("foreground", QOS_POLICY_FRONT)); + statusStringToIndexMap_.insert(std::pair("background", QOS_POLICY_BACK)); + statusStringToIndexMap_.insert(std::pair("focus", QOS_POLICY_FOCUS)); + return; +} + +void QosConfigManager::InitQosStringToIndexMap() +{ + qosStringToIndexMap_.clear(); + qosStringToIndexMap_.insert(STRING_ENUM_PAIR(QOS_BACKGROUND)); + qosStringToIndexMap_.insert(STRING_ENUM_PAIR(QOS_UTILITY)); + qosStringToIndexMap_.insert(STRING_ENUM_PAIR(QOS_DEFAULT)); + qosStringToIndexMap_.insert(STRING_ENUM_PAIR(QOS_USER_INITIATED)); + qosStringToIndexMap_.insert(STRING_ENUM_PAIR(QOS_DEADLINE_REQUEST)); + qosStringToIndexMap_.insert(STRING_ENUM_PAIR(QOS_USER_INTERACTIVE)); + qosStringToIndexMap_.insert(STRING_ENUM_PAIR(QOS_KEY_BACKGROUND)); + return; +} + +void QosConfigManager::InitSchedPolicyToValueMap() +{ + schedPolicyToValueMap_.clear(); + schedPolicyToValueMap_.insert(SCHED_STRING_ENUM_PAIR(OTHER)); + schedPolicyToValueMap_.insert(SCHED_STRING_ENUM_PAIR(FIFO)); + schedPolicyToValueMap_.insert(SCHED_STRING_ENUM_PAIR(RR)); + schedPolicyToValueMap_.insert(SCHED_STRING_ENUM_PAIR(RT_EX)); + schedPolicyToValueMap_.insert(SCHED_STRING_ENUM_PAIR(RESET_ON_FORK)); + return; +} +} +} \ No newline at end of file