• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 #include "cgroup_action.h"
16 #include <algorithm>              // for replace
17 #include <vector>                 // for vector
18 #include <climits>                // for PATH_MAX
19 #include <memory>                 // for unique_ptr
20 #include <cstdlib>                // for realpath
21 #include <cstring>                // for strlen
22 #include <utility>                // for pair
23 #include "cgroup_controller.h"    // for CgroupController
24 #include "cgroup_map.h"           // for CgroupMap
25 #include "cgroup_sched_log.h"
26 #include "config_policy_utils.h"  // for GetOneCfgFile
27 #include "nlohmann/json.hpp"           // for Value
28 #include "process_group_util.h"   // for ReadFileToString
29 #include "res_common_util.h"
30 #include "res_sched_exe_client.h" // for ResSchedExeClient
31 #include "sched_policy.h"         // for SchedPolicy, SP_UPPER_LIMIT, SP_DEF...
32 
33 namespace OHOS {
34 namespace ResourceSchedule {
35 namespace CgroupSetting {
36 namespace {
37     static constexpr const char* CGROUP_SETTING_CONFIG_FILE = "etc/cgroup_sched/cgroup_action_config.json";
38 
39     static const std::string STR_SP_DEFAULT = "sp_default";
40     static const std::string STR_SP_BACKGROUND = "sp_background";
41     static const std::string STR_SP_FOREGROUND = "sp_foreground";
42     static const std::string STR_SP_SYSTEM_BACKGROUND = "sp_system_background";
43     static const std::string STR_SP_TOP_APP = "sp_top_app";
44 
45     static const std::string ABBR_SP_DEFAULT = "df";
46     static const std::string ABBR_SP_BACKGROUND = "bg";
47     static const std::string ABBR_SP_FOREGROUND = "fg";
48     static const std::string ABBR_SP_SYSTEM_BACKGROUND = "sy";
49     static const std::string ABBR_SP_TOP_APP = "ta";
50     constexpr const char * const JSON_KEY_CGROUPS = "Cgroups";
51 }
52 
GetInstance()53 CgroupAction& CgroupAction::GetInstance()
54 {
55     static CgroupAction instance;
56     return instance;
57 }
58 
CgroupAction()59 CgroupAction::CgroupAction()
60 {
61     AddSchedPolicyDeclaration(SP_DEFAULT, STR_SP_DEFAULT, ABBR_SP_DEFAULT);
62     AddSchedPolicyDeclaration(SP_BACKGROUND, STR_SP_BACKGROUND, ABBR_SP_BACKGROUND);
63     AddSchedPolicyDeclaration(SP_FOREGROUND, STR_SP_FOREGROUND, ABBR_SP_FOREGROUND);
64     AddSchedPolicyDeclaration(SP_SYSTEM_BACKGROUND, STR_SP_SYSTEM_BACKGROUND, ABBR_SP_SYSTEM_BACKGROUND);
65     AddSchedPolicyDeclaration(SP_TOP_APP, STR_SP_TOP_APP, ABBR_SP_TOP_APP);
66 }
67 
AddSchedPolicyDeclaration(const SchedPolicy policy,const std::string & fullName,const std::string & abbrName)68 void CgroupAction::AddSchedPolicyDeclaration(const SchedPolicy policy,
69     const std::string& fullName, const std::string& abbrName)
70 {
71     std::lock_guard<ffrt::mutex> lock(mutex_);
72     if (!allowToAdd_) {
73         CGS_LOGI("%{public}s not allowed: %{public}u, %{public}s, %{public}s",
74             __func__, policy, fullName.c_str(), abbrName.c_str());
75         return;
76     }
77     if (policy >= SP_UPPER_LIMIT) {
78         CGS_LOGI("%{public}s out of range: %{public}u, %{public}s, %{public}s",
79             __func__, policy, fullName.c_str(), abbrName.c_str());
80         return;
81     }
82     if (fullName.empty() || abbrName.empty()) {
83         return;
84     }
85     if (fullNames_.find(policy) != fullNames_.end()) {
86         return;
87     }
88     if (std::any_of(fullNames_.begin(), fullNames_.end(),
89         [ &fullName ] (const auto& kv) { return kv.second == fullName; })) {
90         return;
91     }
92     CGS_LOGI("%{public}s add sched policy: %{public}u, %{public}s, %{public}s",
93         __func__, policy, fullName.c_str(), abbrName.c_str());
94     fullNames_[policy] = fullName;
95     abbrNames_[policy] = abbrName;
96 }
97 
GetSchedPolicyList()98 std::vector<SchedPolicy> CgroupAction::GetSchedPolicyList()
99 {
100     std::lock_guard<ffrt::mutex> lock(mutex_);
101     std::vector<SchedPolicy> policyList;
102     std::transform(fullNames_.begin(), fullNames_.end(), std::back_inserter(policyList),
103         [] (const auto& kv) { return kv.first; });
104     return policyList;
105 }
106 
IsSchedPolicyValid(SchedPolicy policy)107 bool CgroupAction::IsSchedPolicyValid(SchedPolicy policy)
108 {
109     std::lock_guard<ffrt::mutex> lock(mutex_);
110     return fullNames_.find(policy) != fullNames_.end();
111 }
112 
GetSchedPolicyFullName(SchedPolicy policy)113 const char* CgroupAction::GetSchedPolicyFullName(SchedPolicy policy)
114 {
115     std::lock_guard<ffrt::mutex> lock(mutex_);
116     if (fullNames_.find(policy) != fullNames_.end()) {
117         return fullNames_[policy].c_str();
118     }
119     return "error";
120 }
121 
GetSchedPolicyAbbrName(SchedPolicy policy)122 const char* CgroupAction::GetSchedPolicyAbbrName(SchedPolicy policy)
123 {
124     std::lock_guard<ffrt::mutex> lock(mutex_);
125     if (abbrNames_.find(policy) != abbrNames_.end()) {
126         return abbrNames_[policy].c_str();
127     }
128     return "error";
129 }
130 
SetThreadSchedPolicy(int tid,SchedPolicy policy)131 bool CgroupAction::SetThreadSchedPolicy(int tid, SchedPolicy policy)
132 {
133     if (!IsSchedPolicyValid(policy)) {
134         return false;
135     }
136     if (!IsEnabled()) {
137         return false;
138     }
139     return CgroupMap::GetInstance().SetThreadSchedPolicy(tid, policy, false);
140 }
141 
SetThreadGroupSchedPolicy(int tid,SchedPolicy policy)142 bool CgroupAction::SetThreadGroupSchedPolicy(int tid, SchedPolicy policy)
143 {
144     if (!IsSchedPolicyValid(policy)) {
145         return false;
146     }
147     if (!IsEnabled()) {
148         return false;
149     }
150     return CgroupMap::GetInstance().SetThreadSchedPolicy(tid, policy, true);
151 }
152 
SetSchedPolicyByExecutor(int tid,int policy,uint32_t resType)153 int CgroupAction::SetSchedPolicyByExecutor(int tid, int policy, uint32_t resType)
154 {
155     int ret = 0;
156     nlohmann::json payload;
157     payload["tid"] = std::to_string(tid);
158     payload["policy"] = std::to_string(policy);
159     nlohmann::json reply;
160     ret = ResourceSchedule::ResSchedExeClient::GetInstance().SendRequestSync(resType, 0, payload, reply);
161     if (ret != 0) {
162         CGS_LOGE("%{public}s SendRequestSync %{public}d failed", __func__, resType);
163         return ret;
164     }
165     if (reply.contains("ret") && reply.at("ret").is_string()) {
166         ret = atoi(reply["ret"].get<std::string>().c_str());
167     }
168     return ret;
169 }
170 
LoadConfigFile()171 bool CgroupAction::LoadConfigFile()
172 {
173     CGS_LOGI("%{public}s CgroupAction::LoadConfigFile loading config file", __func__);
174     nlohmann::json jsonObjRoot;
175     if (!ParseConfigFileToJsonObj(jsonObjRoot)) {
176         return false;
177     }
178     return CgroupMap::GetInstance().LoadConfigFromJsonObj(jsonObjRoot);
179 }
180 
IsEnabled()181 bool CgroupAction::IsEnabled()
182 {
183     {
184         std::lock_guard<ffrt::mutex> lock(mutex_);
185         allowToAdd_ = false;
186     }
187     static bool enable = LoadConfigFile();
188     return enable;
189 }
190 
GetSchedPolicy(int tid,SchedPolicy * policy)191 int CgroupAction::GetSchedPolicy(int tid, SchedPolicy* policy)
192 {
193     if (!IsEnabled()) {
194         *policy = SP_UPPER_LIMIT;
195         return -1;
196     }
197     std::string subgroup;
198     std::vector<CgroupController *> controllers;
199     bool getTaskGroup = false;
200     CgroupMap& instance = CgroupMap::GetInstance();
201     if (instance.FindAllEnableCgroupControllers(controllers)) {
202         for (const auto controller : controllers) {
203             if (controller->GetTaskGroup(tid, subgroup)) {
204                 getTaskGroup = true;
205                 break;
206             }
207         }
208     }
209     if (!getTaskGroup) {
210         *policy = SP_UPPER_LIMIT;
211         return -1;
212     }
213     if (subgroup.empty()) {
214         *policy = SP_DEFAULT;
215         return 0;
216     }
217 
218     replace(subgroup.begin(), subgroup.end(), '-', '_');
219     subgroup = "sp_" + subgroup;
220     return GetSchedPolicyByName(subgroup, policy);
221 }
222 
GetSchedPolicyByName(const std::string & name,SchedPolicy * policy)223 int CgroupAction::GetSchedPolicyByName(const std::string& name, SchedPolicy* policy)
224 {
225     const auto& result = std::find_if(fullNames_.begin(), fullNames_.end(),
226         [ &name ] (const auto& kv) { return kv.second == name; });
227     if (result != fullNames_.end()) {
228         *policy = result->first;
229         return 0;
230     }
231     *policy = SP_UPPER_LIMIT;
232     return -1;
233 }
234 
ParseConfigFileToJsonObj(nlohmann::json & jsonObjRoot)235 bool CgroupAction::ParseConfigFileToJsonObj(nlohmann::json& jsonObjRoot)
236 {
237     bool result = false;
238     auto cfgFilePaths = GetCfgFiles(CGROUP_SETTING_CONFIG_FILE);
239     if (!cfgFilePaths) {
240         return result;
241     }
242     for (const auto& configFilePath : cfgFilePaths->paths) {
243         char tmpPath[PATH_MAX + 1] = {0};
244         if (!configFilePath || strlen(configFilePath) == 0 || strlen(configFilePath) > PATH_MAX ||
245             !realpath(configFilePath, tmpPath)) {
246             continue;
247         }
248         std::string realConfigFile(tmpPath);
249         nlohmann::json jsonTemp;
250         if (!ResCommonUtil::LoadFileToJsonObj(realConfigFile, jsonTemp)) {
251             continue;
252         }
253         if (jsonTemp.contains(JSON_KEY_CGROUPS)) {
254             jsonObjRoot = jsonTemp;
255             result = true;
256         }
257     }
258     FreeCfgFiles(cfgFilePaths);
259     return result;
260 }
261 } // namespace CgroupSetting
262 } // namespace ResourceSchedule
263 } // namespace OHOS
264