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