1 /*
2 * Copyright (c) 2022-2024 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
16 #include "res_sched_exe_mgr.h"
17
18 #include <cinttypes>
19 #include <csignal>
20 #include <fstream>
21 #include <map>
22 #include <sstream>
23
24 #include "cgroup_action.h"
25 #include "hitrace_meter.h"
26
27 #include "plugin_mgr.h"
28 #include "res_exe_type.h"
29 #include "res_sched_exe_constants.h"
30 #include "res_sched_exe_log.h"
31 #include "res_sched_string_util.h"
32 #include "directory_ex.h"
33
34 namespace OHOS {
35 namespace ResourceSchedule {
36 namespace {
37 constexpr int32_t SIGNAL_KILL = 9;
38 const int32_t MAX_CONFIG_SIZE = 1024 * 1024;
39 const std::string STR_CONFIG_READER = "config";
40 const std::string STR_PLUGIN_SWITCH = "switch";
41 const std::string STR_MESSAGE_INDEX = "MESSAGE_INDEX";
42 const std::string STR_MESSAGE_NUMBER = "MESSAGE_NUMBER";
43 const std::string STR_IPC_MESSAGE = "IPC_MESSAGE";
44
45 const std::map<uint32_t, std::string> resTypeToStr = {
46 { ResExeType::RES_TYPE_COMMON_SYNC, "RES_TYPE_COMMON_SYNC" },
47 { ResExeType::RES_TYPE_COMMON_ASYNC, "RES_TYPE_COMMON_ASYNC" },
48 { ResExeType::RES_TYPE_THERMAL_AWARE_SYNC_EVENT, "THERMAL_AWARE_SYNC_EVENT" },
49 { ResExeType::RES_TYPE_THERMAL_AWARE_ASYNC_EVENT, "THERMAL_AWARE_ASYNC_EVENT" },
50 { ResExeType::RES_TYPE_SOCK_EXECUTOR_ASYNC_EVENT, "SOCK_EXECUTOR_ASYNC_EVENT" },
51 { ResExeType::RES_TYPE_DEBUG, "DEBUG_COMMAND" },
52 };
53 }
54
55 IMPLEMENT_SINGLE_INSTANCE(ResSchedExeMgr);
56
Init()57 void ResSchedExeMgr::Init()
58 {
59 PluginMgr::GetInstance().Init(true);
60 PluginMgr::GetInstance().SetResTypeStrMap(resTypeToStr);
61 }
62
Stop()63 void ResSchedExeMgr::Stop()
64 {
65 PluginMgr::GetInstance().Stop();
66 }
67
SendRequestSync(uint32_t resType,int64_t value,const nlohmann::json & payload,nlohmann::json & reply)68 int32_t ResSchedExeMgr::SendRequestSync(uint32_t resType, int64_t value,
69 const nlohmann::json& payload, nlohmann::json& reply)
70 {
71 RSSEXE_LOGD("ResSchedExeMgr receive sync request resType = %{public}u, value = %{public}lld.",
72 resType, (long long)value);
73 std::string traceStr = BuildTraceStr(__func__, resType, value);
74 HitraceScoped hitrace(HITRACE_TAG_OHOS, traceStr);
75 switch (resType) {
76 case ResExeType::RES_TYPE_EXECUTOR_PLUGIN_INIT:
77 InitPluginMgrPretreatment(payload);
78 break;
79 case ResExeType::RES_TYPE_CGROUP_SYNC_EVENT:
80 case ResExeType::RES_TYPE_CGROUP_PROC_TASK_SYNC_EVENT:
81 case ResExeType::RES_TYPE_SET_THREAD_SCHED_POLICY_SYNC_EVENT:
82 case ResExeType::RES_TYPE_SET_THREAD_GROUP_SCHED_POLICY_SYNC_EVENT:
83 HandleRequestForCgroup(resType, payload, reply);
84 break;
85 default:
86 auto resData = std::make_shared<ResData>(resType, value, payload, reply);
87 int32_t ret = PluginMgr::GetInstance().DeliverResource(resData);
88 if (ret != ResIpcErrCode::RSSEXE_PLUGIN_ERROR) {
89 reply["retCode"] = std::to_string(ret);
90 }
91 break;
92 }
93 if (reply.empty()) {
94 reply["retCode"] = std::to_string(ResIpcErrCode::RSSEXE_REPLY_EMPTY);
95 }
96 return ResErrCode::RSSEXE_NO_ERR;
97 }
98
SendRequestAsync(uint32_t resType,int64_t value,const nlohmann::json & payload)99 void ResSchedExeMgr::SendRequestAsync(uint32_t resType, int64_t value, const nlohmann::json& payload)
100 {
101 RSSEXE_LOGD("ResSchedExeMgr receive async request resType = %{public}u, value = %{public}lld.",
102 resType, (long long)value);
103 if (resType == ResExeType::RES_TYPE_EXECUTOR_PLUGIN_INIT) {
104 InitPluginMgrPretreatment(payload);
105 return;
106 }
107 std::string traceStr = BuildTraceStr(__func__, resType, value);
108 HitraceScoped hitrace(HITRACE_TAG_OHOS, traceStr);
109 PluginMgr::GetInstance().DispatchResource(std::make_shared<ResData>(resType, value, payload));
110 }
111
KillProcess(pid_t pid)112 int32_t ResSchedExeMgr::KillProcess(pid_t pid)
113 {
114 RSSEXE_LOGD("ResSchedExeMgr receive kill request pid = %{public}d", pid);
115 int32_t killRes = kill(pid, SIGNAL_KILL);
116 return killRes;
117 }
118
InitPluginMgrPretreatment(const nlohmann::json & payload)119 void ResSchedExeMgr::InitPluginMgrPretreatment(const nlohmann::json& payload)
120 {
121 if (isInit) {
122 RSSEXE_LOGE("plugin manager has init");
123 return;
124 }
125
126 if (payload.contains(STR_MESSAGE_INDEX) && payload[STR_MESSAGE_INDEX].is_number() &&
127 payload.contains(STR_MESSAGE_NUMBER) && payload[STR_MESSAGE_NUMBER].is_number()) {
128 ipcMessage_.insert(std::make_pair(payload[STR_MESSAGE_INDEX].get<int>(),
129 payload[STR_IPC_MESSAGE].get<std::string>()));
130 ipcNumber_++;
131 RSSEXE_LOGD("ipc message number: %{public}d, current number: %{public}d",
132 payload[STR_MESSAGE_NUMBER].get<int>(), ipcNumber_);
133 if (payload[STR_MESSAGE_NUMBER].get<int>() == ipcNumber_) {
134 std::string ipcMessage = "";
135 for (const auto& pair : ipcMessage_) {
136 ipcMessage += pair.second;
137 }
138 nlohmann::json initPayload;
139 if (!ResCommonUtil::StringToJson(ipcMessage, initPayload)) {
140 RSSEXE_LOGE("executor plugin manager has init failed in batches ipc.");
141 }
142 InitPluginMgr(initPayload);
143 ipcNumber_ = 0;
144 ipcMessage_.clear();
145 return;
146 }
147 return;
148 }
149 InitPluginMgr(payload);
150 }
151
InitPluginMgr(const nlohmann::json & payload)152 void ResSchedExeMgr::InitPluginMgr(const nlohmann::json& payload)
153 {
154 if (!payload.contains(STR_CONFIG_READER) || !payload[STR_CONFIG_READER].is_array()
155 || !payload.contains(STR_PLUGIN_SWITCH) || !payload[STR_PLUGIN_SWITCH].is_array()) {
156 RSSEXE_LOGE("recieve config string error");
157 return;
158 }
159
160 isInit = true;
161 std::vector<std::string> configStrs = payload[STR_CONFIG_READER].get<std::vector<std::string>>();
162 std::vector<std::string> switchStrs = payload[STR_PLUGIN_SWITCH].get<std::vector<std::string>>();
163 for (auto configStr : configStrs) {
164 if (configStr.size() > MAX_CONFIG_SIZE) {
165 RSSEXE_LOGE("recieve config string too large");
166 return;
167 }
168 }
169 PluginMgr::GetInstance().ParseConfigReader(configStrs);
170
171 for (auto switchStr : switchStrs) {
172 if (switchStr.size() > MAX_CONFIG_SIZE) {
173 RSSEXE_LOGE("recieve switch config string too large");
174 return;
175 }
176 }
177 PluginMgr::GetInstance().ParsePluginSwitch(switchStrs, true);
178 RSSEXE_LOGD("plugin manager init succeed");
179 }
180
BuildTraceStr(const std::string & func,uint32_t resType,int64_t value)181 std::string ResSchedExeMgr::BuildTraceStr(const std::string& func, uint32_t resType, int64_t value)
182 {
183 std::string trace_str(func);
184 trace_str.append(",resType[").append(std::to_string(resType)).append("]");
185 trace_str.append(",value[").append(std::to_string(value)).append("]");
186 return trace_str;
187 }
188
HandleRequestForCgroup(uint32_t resType,const nlohmann::json & payload,nlohmann::json & reply)189 void ResSchedExeMgr::HandleRequestForCgroup(uint32_t resType, const nlohmann::json& payload, nlohmann::json& reply)
190 {
191 if (resType != ResExeType::RES_TYPE_CGROUP_SYNC_EVENT &&
192 resType != ResExeType::RES_TYPE_CGROUP_PROC_TASK_SYNC_EVENT &&
193 resType != ResExeType::RES_TYPE_SET_THREAD_SCHED_POLICY_SYNC_EVENT &&
194 resType != ResExeType::RES_TYPE_SET_THREAD_GROUP_SCHED_POLICY_SYNC_EVENT) {
195 return;
196 }
197
198 int tid;
199 CgroupSetting::SchedPolicy schedPolicy;
200 if (resType == ResExeType::RES_TYPE_SET_THREAD_SCHED_POLICY_SYNC_EVENT ||
201 resType == ResExeType::RES_TYPE_SET_THREAD_GROUP_SCHED_POLICY_SYNC_EVENT) {
202 int policy;
203 if (!(ParseValue(tid, "tid", payload)) || !(ParseValue(policy, "policy", payload))) {
204 RSSEXE_LOGE("%{public}s : ParseValue failed", __func__);
205 return;
206 }
207 schedPolicy = CgroupSetting::SchedPolicy(policy);
208 }
209
210 int ret = 0;
211 switch (resType) {
212 case ResExeType::RES_TYPE_CGROUP_SYNC_EVENT:
213 GetCgroupFileContent(resType, payload, reply);
214 break;
215 case ResExeType::RES_TYPE_CGROUP_PROC_TASK_SYNC_EVENT:
216 CheckProcTaskForCgroup(resType, payload, reply);
217 break;
218 case ResExeType::RES_TYPE_SET_THREAD_SCHED_POLICY_SYNC_EVENT:
219 ret = CgroupSetting::CgroupAction::GetInstance().SetThreadSchedPolicy(tid, schedPolicy) ? 0 : -1;
220 reply["ret"] = std::to_string(ret);
221 break;
222 case ResExeType::RES_TYPE_SET_THREAD_GROUP_SCHED_POLICY_SYNC_EVENT:
223 ret = CgroupSetting::CgroupAction::GetInstance().SetThreadGroupSchedPolicy(tid, schedPolicy) ? 0 : -1;
224 reply["ret"] = std::to_string(ret);
225 break;
226 default:
227 break;
228 }
229 return;
230 }
231
ParseValue(int32_t & value,const char * name,const nlohmann::json & payload)232 bool ResSchedExeMgr::ParseValue(int32_t& value, const char* name, const nlohmann::json& payload)
233 {
234 if (payload.contains(name) && payload.at(name).is_string()) {
235 value = atoi(payload[name].get<std::string>().c_str());
236 return true;
237 }
238 return false;
239 }
240
GetCgroupFileContent(uint32_t resType,const nlohmann::json & payload,nlohmann::json & reply)241 void ResSchedExeMgr::GetCgroupFileContent(uint32_t resType, const nlohmann::json& payload, nlohmann::json& reply)
242 {
243 if (!payload.contains("pid") || !payload["pid"].is_number_integer()) {
244 return;
245 }
246 int pid = payload["pid"];
247 std::string path = std::string("/proc/").append(std::to_string(pid)).append("/cgroup");
248 char resolvedPath[PATH_MAX] = { 0 };
249 if (path.size() > PATH_MAX || !realpath(path.c_str(), resolvedPath)) {
250 RSSEXE_LOGE("%{public}s realpath failed, pid = %{public}d.", __func__, pid);
251 return;
252 }
253 auto realPath = std::string(resolvedPath);
254 std::ifstream fin(realPath.c_str(), std::ios::in);
255 if (!fin) {
256 return;
257 }
258 std::stringstream ss;
259 ss << fin.rdbuf();
260 reply["res"] = ss.str();
261 }
262
CheckProcTaskForCgroup(uint32_t resType,const nlohmann::json & payload,nlohmann::json & reply)263 void ResSchedExeMgr::CheckProcTaskForCgroup(uint32_t resType, const nlohmann::json& payload, nlohmann::json& reply)
264 {
265 if (!payload.contains("pid") || !payload["pid"].is_number_integer()) {
266 return;
267 }
268 if (!payload.contains("tid") || !payload["tid"].is_number_integer()) {
269 return;
270 }
271 int pid = payload["pid"];
272 int tid = payload["tid"];
273 std::string pathName = std::string("/proc/").append(std::to_string(pid))
274 .append("/task/").append(std::to_string(tid)).append("/comm");
275 std::string realPath;
276 reply["res"] = PathToRealPath(pathName, realPath);
277 return;
278 }
279 } // namespace ResourceSchedule
280 } // namespace OHOS
281