diff --git a/bundle.json b/bundle.json index 0432c0f9677afa9d0f18be3abeb07c7fb267878a..6b2a023178db1c23223d7cd460af5772192fe8a5 100644 --- a/bundle.json +++ b/bundle.json @@ -24,6 +24,7 @@ "ability_base", "ability_runtime", "access_token", + "config_policy", "c_utils", "frame_aware_sched", "hilog", @@ -31,6 +32,7 @@ "init", "ipc", "jsoncpp", + "libxml2", "safwk", "samgr" ], diff --git a/common/include/config_reader.h b/common/include/config_reader.h new file mode 100644 index 0000000000000000000000000000000000000000..94629b09054e2f21a324af19a4ee96a8d2a3520e --- /dev/null +++ b/common/include/config_reader.h @@ -0,0 +1,42 @@ +/* + * 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 CONCURRENT_TASK_SERVICES_COMMON_INCLUDE_CONFIG_READER_H +#define CONCURRENT_TASK_SERVICES_COMMON_INCLUDE_CONFIG_READER_H + +#include +#include +#include "libxml/parser.h" +#include "libxml/xpath.h" + +namespace OHOS { +namespace ConcurrentTask { +class ConfigReader { +public: + bool LoadFromConfigFile(const std::string& configFile); + void GetRealConfigPath(const char* configName, std::string& configPath); + bool IsUidAuth(pid_t uid); + bool IsBundleNameAuth(std::string& bundleName); +private: + bool IsValidNode(const xmlNode* currNode); + bool FillinUidInfo(const xmlNode* currNode); + bool FillinBundleNameInfo(const xmlNode* currNode); + void ParseAuth(const xmlNode* currNode); + void ConfigHilog(); + std::unordered_set authProcUidConfigs_; + std::unordered_set authProcBundleNameConfigs_; +}; +} // namespace ConcurrentTask +} // namespace OHOS +#endif // CONCURRENT_TASK_SERVICES_COMMON_INCLUDE_CONFIG_READER_H diff --git a/common/src/config_reader.cpp b/common/src/config_reader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5374fa232f16c4d9da0aa673f08e5f9d345f4811 --- /dev/null +++ b/common/src/config_reader.cpp @@ -0,0 +1,190 @@ +/* + * 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 +#include +#include + +#include "config_reader.h" +#include "config_policy_utils.h" +#include "concurrent_task_log.h" +#include "parameters.h" + +using namespace std; + +namespace OHOS { +namespace ConcurrentTask { +namespace { + const std::string XML_TAG_QOS_CONFIG = "qosconfig"; + const std::string XML_TAG_QOS_AUTH = "auth"; + const std::string XML_TAG_UIDLIST = "uidlist"; + const std::string XML_TAG_UID = "uid"; + const std::string XML_TAG_BUNDLENAMELIST = "bundlenamelist"; + const std::string XML_TAG_BUNDLENAME = "bundlename"; +} + +bool ConfigReader::IsValidNode(const xmlNode* currNode) +{ + if (!currNode) { + return false; + } + if (!currNode->name || currNode->type == XML_COMMENT_NODE) { + return false; + } + return true; +} + +bool ConfigReader::FillinUidInfo(const xmlNode* currNode) +{ + if (!IsValidNode(currNode)) { + CONCUR_LOGE("FillinUidInfo:: currNode is nullptr!"); + return false; + } + xmlNodePtr currNodePtr = currNode->xmlChildrenNode; + for (; currNodePtr; currNodePtr = currNodePtr->next) { + if (xmlStrcmp(currNodePtr->name, reinterpret_cast(XML_TAG_UID.c_str())) == 0) { + xmlChar *attrValue = xmlGetProp(currNodePtr, reinterpret_cast(XML_TAG_UID.c_str())); + if (!attrValue) { + CONCUR_LOGE("FillinUidInfo:: uid null!"); + return false; + } + int64_t uid = atoi(reinterpret_cast(attrValue)); + authProcUidConfigs_.insert(uid); + xmlFree(attrValue); + } + } + return true; +} + +bool ConfigReader::FillinBundleNameInfo(const xmlNode* currNode) +{ + if (!IsValidNode(currNode)) { + CONCUR_LOGE("FillinBundleNameInfo:: currNode is nullptr!"); + return false; + } + xmlNodePtr currNodePtr = currNode->xmlChildrenNode; + for (; currNodePtr; currNodePtr = currNodePtr->next) { + if (xmlStrcmp(currNodePtr->name, reinterpret_cast(XML_TAG_BUNDLENAME.c_str())) == 0) { + xmlChar *attrValue = xmlGetProp(currNodePtr, reinterpret_cast(XML_TAG_BUNDLENAME.c_str())); + if (!attrValue) { + CONCUR_LOGE("FillinBundleNameInfo:: bundleName null!"); + return false; + } + std::string bundleName = reinterpret_cast(attrValue); + authProcBundleNameConfigs_.insert(bundleName); + xmlFree(attrValue); + } + } + return true; +} + +void ConfigReader::ParseAuth(const xmlNode* currNode) +{ + xmlNodePtr currNodePtr = currNode->xmlChildrenNode; + for (; currNodePtr; currNodePtr = currNodePtr->next) { + if (xmlStrcmp(currNodePtr->name, reinterpret_cast(XML_TAG_UIDLIST.c_str())) == 0) { + if (!FillinUidInfo(currNodePtr)) { + CONCUR_LOGE("ParseAuth:: uid fill in authProcUidConfigs_ error!"); + continue; + } + } + + if (xmlStrcmp(currNodePtr->name, reinterpret_cast(XML_TAG_BUNDLENAMELIST.c_str())) == 0) { + if (!FillinBundleNameInfo(currNodePtr)) { + CONCUR_LOGE("ParseAuth:: bundleName fill in authProcBundleNameConfigs_ error!"); + continue; + } + } + } +} + +bool ConfigReader::LoadFromConfigFile(const std::string& configFile) +{ + // skip the empty string, else you will get empty node + xmlDocPtr xmlDocPtr = xmlReadFile(configFile.c_str(), nullptr, + XML_PARSE_NOBLANKS | XML_PARSE_NOERROR | XML_PARSE_NOWARNING); + if (!xmlDocPtr) { + CONCUR_LOGE("LoadFromConfigFile:: xmlReadFile error!"); + return false; + } + xmlNodePtr rootNodePtr = xmlDocGetRootElement(xmlDocPtr); + if (!rootNodePtr || !rootNodePtr->name || + xmlStrcmp(rootNodePtr->name, reinterpret_cast(XML_TAG_QOS_CONFIG.c_str())) != 0) { + CONCUR_LOGE("LoadFromConfigFile:: root element tag error!"); + xmlFreeDoc(xmlDocPtr); + return false; + } + xmlNodePtr currNodePtr = rootNodePtr->xmlChildrenNode; + for (; currNodePtr; currNodePtr = currNodePtr->next) { + if (!IsValidNode(currNodePtr)) { + CONCUR_LOGE("LoadFromConfigFile:: IsInvalidNode!"); + continue; + } + if (xmlStrcmp(currNodePtr->name, reinterpret_cast(XML_TAG_QOS_AUTH.c_str())) == 0) { + ParseAuth(currNodePtr); + } + } + ConfigHilog(); + xmlFreeDoc(xmlDocPtr); + return true; +} + +void ConfigReader::GetRealConfigPath(const char* configName, std::string& configPath) +{ + if (!configName) { + CONCUR_LOGE("GetRealConfigPath:: configName is nullptr!"); + return; + } + char buf[PATH_MAX] = {0}; + char* configFilePath = GetOneCfgFile(configName, buf, PATH_MAX); + char tmpPath[PATH_MAX] = {0}; + if (!configFilePath || strlen(configFilePath) == 0 || strlen(configFilePath) > PATH_MAX || + !realpath(configFilePath, tmpPath)) { + CONCUR_LOGE("GetRealConfigPath:: get config file path error!"); + configPath = ""; + return; + } + configPath = tmpPath; +} + +bool ConfigReader::IsUidAuth(pid_t uid) +{ + if (authProcUidConfigs_.find(uid) != authProcUidConfigs_.end()) { + return true; + } + return false; +} + +bool ConfigReader::IsBundleNameAuth(std::string& bundleName) +{ + if (authProcBundleNameConfigs_.find(bundleName) != authProcBundleNameConfigs_.end()) { + return true; + } + return false; +} + +void ConfigReader::ConfigHilog() +{ + bool getConfigRead = OHOS::system::GetBoolParameter("persist.qos.configreadlog", false); + if (getConfigRead) { + for (auto iter : authProcUidConfigs_) { + CONCUR_LOGI("authProcUidConfigs_ contain uid = %{public}d", (int32_t)iter); + } + for (auto iter : authProcBundleNameConfigs_) { + CONCUR_LOGI("authProcBundleNameConfigs_ contain bundleName = %{public}s", iter.c_str()); + } + } +} +} +} \ No newline at end of file diff --git a/etc/param/ffrt.para b/etc/param/ffrt.para index ec9621557e17fea4cf09ddc09b53895750302851..f00573b4e67a70fefa18802c5e110a039e9b6201 100644 --- a/etc/param/ffrt.para +++ b/etc/param/ffrt.para @@ -19,3 +19,4 @@ ffrt.interval.limit=false persist.ffrt.interval.appRate=0 persist.ffrt.interval.rsRate=0 persist.qosmanager.setQos.on=true +persist.qos.configReadLog = false diff --git a/etc/param/ffrt.para.dac b/etc/param/ffrt.para.dac index 725a42ed9f70dfa75837d6cc57a17db3695494ef..dee7fbe20e7c0c509d5a9c320442ddc794d339ee 100644 --- a/etc/param/ffrt.para.dac +++ b/etc/param/ffrt.para.dac @@ -19,3 +19,4 @@ ffrt.interval.limit = system:system:0664 persist.ffrt.interval.appRate = system:system:0664 persist.ffrt.interval.rsRate = system:system:0664 persist.qosmanager.setQos.on = system:system:0664 +persist.qos.configReadLog = system:system:0664 diff --git a/services/BUILD.gn b/services/BUILD.gn index f37216f3fceaa9bca918b16b5dfefff3ea746caf..a1c05646cc64036fd4a5fabb39bc97fa64fd94f7 100644 --- a/services/BUILD.gn +++ b/services/BUILD.gn @@ -25,6 +25,7 @@ config("concurrent_task_config") { "../include", "../frameworks/concurrent_task_client/include/", "../interfaces/inner_api/", + "../common/include", ] } @@ -37,6 +38,7 @@ ohos_shared_library("concurrentsvc") { debug = false } sources = [ + "../common/src/config_reader.cpp", "src/concurrent_task_controller.cpp", "src/concurrent_task_service.cpp", "src/concurrent_task_service_ability.cpp", @@ -55,12 +57,14 @@ ohos_shared_library("concurrentsvc") { external_deps = [ "access_token:libaccesstoken_sdk", "c_utils:utils", + "config_policy:configpolicy_util", "frame_aware_sched:rtg_interface", "hilog:libhilog", "hitrace:hitrace_meter", "init:libbegetutil", "ipc:ipc_single", "jsoncpp:jsoncpp", + "libxml2:libxml2", "safwk:system_ability_fwk", "samgr:samgr_proxy", ] diff --git a/services/include/concurrent_task_controller.h b/services/include/concurrent_task_controller.h index 7f4c321fc11d8d84fb83b893daadf65eb9ed5f6d..a2ee3080b9529df30ca5cf1122c2670ef01d04b1 100644 --- a/services/include/concurrent_task_controller.h +++ b/services/include/concurrent_task_controller.h @@ -24,6 +24,7 @@ #include #include "json/json.h" #include "concurrent_task_type.h" +#include "config_reader.h" #include "qos_policy.h" namespace OHOS { @@ -68,6 +69,7 @@ private: void ContinuousTaskProcess(int uid, int pid, int status); void FocusStatusProcess(int uid, int pid, int status); int AuthSystemProcess(int pid); + bool ConfigReaderInit(); bool ModifySystemRate(const Json::Value& payload); void SetAppRate(const Json::Value& payload); int FindRateFromInfo(int uiTid, const Json::Value& payload); @@ -99,15 +101,16 @@ private: int hardwareTid_ = -1; int systemRate_ = 0; bool rtgEnabled_ = false; + bool configEnable_ = false; bool rsAuthed_ = false; std::atomic curGamePid_ = -1; int executorNum_ = 0; std::map appBundleName; + std::unique_ptr configReader_ = nullptr; const std::string RENDER_SERVICE_PROCESS_NAME = "render_service"; const std::string RESOURCE_SCHEDULE_PROCESS_NAME = "resource_schedule_service"; const std::string GAME_ACCELERATE_SCHED_PROCESS_NAME = "game_accelerate_schedule"; - const int32_t HWF_SERVICE_UID = 7700; }; class ForegroundAppRecord { diff --git a/services/src/concurrent_task_controller.cpp b/services/src/concurrent_task_controller.cpp index 3df8bb1a456ec1e2da9dc773a331f173452b52c6..60e329959e1a468f100bdfcb073e9b01e4937e37 100644 --- a/services/src/concurrent_task_controller.cpp +++ b/services/src/concurrent_task_controller.cpp @@ -36,6 +36,7 @@ namespace { const std::string INTERVAL_DDL = "persist.ffrt.interval.renderthread"; const std::string INTERVAL_APP_RATE = "persist.ffrt.interval.appRate"; const std::string INTERVAL_RS_RATE = "persist.ffrt.interval.rsRate"; + const std::string CONFIG_FILE_NAME = "etc/qos_manager/qos_manager_config.xml"; constexpr int CURRENT_RATE = 120; constexpr int PARAM_TYPE = 1; constexpr int UNI_APP_RATE_ID = -1; @@ -56,13 +57,17 @@ TaskController& TaskController::GetInstance() void TaskController::RequestAuth(const Json::Value& payload) { + if (!configEnable_ && !ConfigReaderInit()) { + return; + } pid_t uid = IPCSkeleton::GetInstance().GetCallingUid(); - if (uid != HWF_SERVICE_UID) { - CONCUR_LOGE("Invalid uid %{public}d, only hwf service uid can call RequestAuth", uid); + auto bundleName = GetProcessNameByToken(); + if (configReader_->IsBundleNameAuth(bundleName) || configReader_->IsUidAuth(uid)) { + pid_t pid = IPCSkeleton::GetInstance().GetCallingPid(); + AuthSystemProcess(pid); return; } - pid_t pid = IPCSkeleton::GetInstance().GetCallingPid(); - AuthSystemProcess(pid); + CONCUR_LOGE("Invalid uid %{public}d, can't call RequestAuth", uid); } void TaskController::ReportData(uint32_t resType, int64_t value, const Json::Value& payload) @@ -320,6 +325,25 @@ void TaskController::Init() TypeMapInit(); qosPolicy_.Init(); TryCreateRsGroup(); + ConfigReaderInit(); +} + +bool TaskController::ConfigReaderInit() +{ + configReader_ = make_unique(); + if (!configReader_) { + CONCUR_LOGE("configReader_ initialize error!"); + return configEnable_; + } + + std::string realPath; + configReader_->GetRealConfigPath(CONFIG_FILE_NAME.c_str(), realPath); + if (realPath.empty() || !configReader_->LoadFromConfigFile(realPath)) { + CONCUR_LOGE("config load failed!"); + return configEnable_; + } + configEnable_ = true; + return configEnable_; } void TaskController::Release() @@ -333,6 +357,7 @@ void TaskController::Release() DestroyRtgGrp(renderServiceRenderGrpId_); renderServiceRenderGrpId_ = -1; } + configReader_ = nullptr; } void TaskController::TypeMapInit() diff --git a/test/BUILD.gn b/test/BUILD.gn index cc3690afa244b3b8736e1e5e6e23557a8b0ceeb9..9c0a7e3fa192c87c4d4f1cb8b98cb725af680d0e 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -22,6 +22,7 @@ gtest_public_deps = [ "//third_party/googletest:gtest_main" ] config("test_config") { include_dirs = [ "../include/", + "../common/include", "../frameworks/concurrent_task_client/include", "../interfaces/inner_api/", "../interfaces/kits/", @@ -259,6 +260,27 @@ ohos_unittest("qos_ndk_test") { part_name = "qos_manager" } +ohos_unittest("config_reader_test") { + module_out_path = module_output_path + configs = [ ":test_config" ] + + sources = [ + "../common/src/config_reader.cpp", + "unittest/phone/config_reader_test.cpp", + ] + + external_deps = [ + "c_utils:utils", + "config_policy:configpolicy_util", + "hilog:libhilog", + "init:libbegetutil", + "libxml2:libxml2", + ] + + subsystem_name = "resourceschedule" + part_name = "qos_manager" +} + group("concurrent_unittest") { testonly = true deps = [] @@ -269,6 +291,7 @@ group("concurrent_unittest") { ":concurrent_task_controller_test", ":concurrent_task_service_ability_test", ":concurrent_task_service_test", + ":config_reader_test", ":qos_interface_test", ":qos_ndk_test", ":qos_policy_test", diff --git a/test/unittest/phone/config_reader_test.cpp b/test/unittest/phone/config_reader_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7eb9119f15b1798c2d14e8de5f8d202afa35cf44 --- /dev/null +++ b/test/unittest/phone/config_reader_test.cpp @@ -0,0 +1,59 @@ +/* + * 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 +#include +#include "config_reader.h" +#include "gtest/gtest.h" + +namespace OHOS { +namespace FFRT_TEST { +using namespace testing; +using namespace testing::ext; +using namespace OHOS::ConcurrentTask; + +class ConfigReaderTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void ConfigReaderTest::SetUpTestCase() +{ +} + +void ConfigReaderTest::TearDownTestCase() +{ +} + +void ConfigReaderTest::SetUp() +{ +} + +void ConfigReaderTest::TearDown() +{ +} + +/** + * @tc.name: ConfigReaderTest + * @tc.desc: Test whether the ConfigReader interface are normal. + * @tc.type: FUNC + */ +HWTEST_F(ConfigReaderTest, ConfigReaderTest, TestSize.Level1) +{ +} +} +} \ No newline at end of file