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 "directory_ex.h"
32
33 namespace OHOS {
34 namespace ResourceSchedule {
35 namespace {
36 constexpr int32_t SIGNAL_KILL = 9;
37 const int32_t MAX_CONFIG_SIZE = 1024 * 1024;
38 const std::string STR_CONFIG_READER = "config";
39 const std::string STR_PLUGIN_SWITCH = "switch";
40
41 const std::map<uint32_t, std::string> resTypeToStr = {
42 { ResExeType::RES_TYPE_COMMON_SYNC, "RES_TYPE_COMMON_SYNC" },
43 { ResExeType::RES_TYPE_COMMON_ASYNC, "RES_TYPE_COMMON_ASYNC" },
44 { ResExeType::RES_TYPE_THERMAL_AWARE_SYNC_EVENT, "THERMAL_AWARE_SYNC_EVENT" },
45 { ResExeType::RES_TYPE_THERMAL_AWARE_ASYNC_EVENT, "THERMAL_AWARE_ASYNC_EVENT" },
46 { ResExeType::RES_TYPE_SOCK_EXECUTOR_ASYNC_EVENT, "SOCK_EXECUTOR_ASYNC_EVENT" },
47 { ResExeType::RES_TYPE_DEBUG, "DEBUG_COMMAND" },
48 };
49 }
50
51 IMPLEMENT_SINGLE_INSTANCE(ResSchedExeMgr);
52
Init()53 void ResSchedExeMgr::Init()
54 {
55 PluginMgr::GetInstance().Init(true);
56 PluginMgr::GetInstance().SetResTypeStrMap(resTypeToStr);
57 }
58
Stop()59 void ResSchedExeMgr::Stop()
60 {
61 PluginMgr::GetInstance().Stop();
62 }
63
SendRequestSync(uint32_t resType,int64_t value,const nlohmann::json & payload,nlohmann::json & reply)64 int32_t ResSchedExeMgr::SendRequestSync(uint32_t resType, int64_t value,
65 const nlohmann::json& payload, nlohmann::json& reply)
66 {
67 RSSEXE_LOGD("receive resType = %{public}u, value = %{public}lld.", resType, (long long)value);
68 std::string traceStr = BuildTraceStr(__func__, resType, value);
69 HitraceScoped hitrace(HITRACE_TAG_OHOS, traceStr);
70 switch (resType) {
71 case ResExeType::RES_TYPE_EXECUTOR_PLUGIN_INIT:
72 InitPluginMgr(payload);
73 break;
74 case ResExeType::RES_TYPE_CGROUP_SYNC_EVENT:
75 case ResExeType::RES_TYPE_CGROUP_PROC_TASK_SYNC_EVENT:
76 case ResExeType::RES_TYPE_SET_THREAD_SCHED_POLICY_SYNC_EVENT:
77 case ResExeType::RES_TYPE_SET_THREAD_GROUP_SCHED_POLICY_SYNC_EVENT:
78 HandleRequestForCgroup(resType, payload, reply);
79 break;
80 default:
81 auto resData = std::make_shared<ResData>(resType, value, payload, reply);
82 int32_t ret = PluginMgr::GetInstance().DeliverResource(resData);
83 if (ret != ResIpcErrCode::RSSEXE_PLUGIN_ERROR) {
84 reply["retCode"] = std::to_string(ret);
85 }
86 break;
87 }
88 return ResErrCode::RSSEXE_NO_ERR;
89 }
90
SendRequestAsync(uint32_t resType,int64_t value,const nlohmann::json & payload)91 void ResSchedExeMgr::SendRequestAsync(uint32_t resType, int64_t value, const nlohmann::json& payload)
92 {
93 RSSEXE_LOGD("receive resType = %{public}u, value = %{public}lld.", resType, (long long)value);
94 if (resType == ResExeType::RES_TYPE_EXECUTOR_PLUGIN_INIT) {
95 InitPluginMgr(payload);
96 return;
97 }
98 std::string traceStr = BuildTraceStr(__func__, resType, value);
99 HitraceScoped hitrace(HITRACE_TAG_OHOS, traceStr);
100 PluginMgr::GetInstance().DispatchResource(std::make_shared<ResData>(resType, value, payload));
101 }
102
KillProcess(pid_t pid)103 int32_t ResSchedExeMgr::KillProcess(pid_t pid)
104 {
105 int32_t killRes = kill(pid, SIGNAL_KILL);
106 return killRes;
107 }
108
InitPluginMgr(const nlohmann::json & payload)109 void ResSchedExeMgr::InitPluginMgr(const nlohmann::json& payload)
110 {
111 if (isInit) {
112 RSSEXE_LOGE("plugin manager has init");
113 return;
114 }
115
116 if (!payload.contains(STR_CONFIG_READER) || !payload[STR_CONFIG_READER].is_array()
117 || !payload.contains(STR_PLUGIN_SWITCH) || !payload[STR_PLUGIN_SWITCH].is_array()) {
118 RSSEXE_LOGE("recieve config string error");
119 return;
120 }
121
122 isInit = true;
123 std::vector<std::string> configStrs = payload[STR_CONFIG_READER].get<std::vector<std::string>>();
124 std::vector<std::string> switchStrs = payload[STR_PLUGIN_SWITCH].get<std::vector<std::string>>();
125 for (auto configStr : configStrs) {
126 if (configStr.size() > MAX_CONFIG_SIZE) {
127 RSSEXE_LOGE("recieve config string too large");
128 return;
129 }
130 }
131 PluginMgr::GetInstance().ParseConfigReader(configStrs);
132
133 for (auto switchStr : switchStrs) {
134 if (switchStr.size() > MAX_CONFIG_SIZE) {
135 RSSEXE_LOGE("recieve switch config string too large");
136 return;
137 }
138 }
139 PluginMgr::GetInstance().ParsePluginSwitch(switchStrs, true);
140 RSSEXE_LOGD("plugin manager init succeed");
141 }
142
BuildTraceStr(const std::string & func,uint32_t resType,int64_t value)143 std::string ResSchedExeMgr::BuildTraceStr(const std::string& func, uint32_t resType, int64_t value)
144 {
145 std::string trace_str(func);
146 trace_str.append(",resType[").append(std::to_string(resType)).append("]");
147 trace_str.append(",value[").append(std::to_string(value)).append("]");
148 return trace_str;
149 }
150
HandleRequestForCgroup(uint32_t resType,const nlohmann::json & payload,nlohmann::json & reply)151 void ResSchedExeMgr::HandleRequestForCgroup(uint32_t resType, const nlohmann::json& payload, nlohmann::json& reply)
152 {
153 if (resType != ResExeType::RES_TYPE_CGROUP_SYNC_EVENT &&
154 resType != ResExeType::RES_TYPE_CGROUP_PROC_TASK_SYNC_EVENT &&
155 resType != ResExeType::RES_TYPE_SET_THREAD_SCHED_POLICY_SYNC_EVENT &&
156 resType != ResExeType::RES_TYPE_SET_THREAD_GROUP_SCHED_POLICY_SYNC_EVENT) {
157 return;
158 }
159
160 int tid;
161 CgroupSetting::SchedPolicy schedPolicy;
162 if (resType == ResExeType::RES_TYPE_SET_THREAD_SCHED_POLICY_SYNC_EVENT ||
163 resType == ResExeType::RES_TYPE_SET_THREAD_GROUP_SCHED_POLICY_SYNC_EVENT) {
164 int policy;
165 if (!(ParseValue(tid, "tid", payload)) || !(ParseValue(policy, "policy", payload))) {
166 RSSEXE_LOGE("%{public}s : ParseValue failed", __func__);
167 return;
168 }
169 schedPolicy = CgroupSetting::SchedPolicy(policy);
170 }
171
172 int ret = 0;
173 switch (resType) {
174 case ResExeType::RES_TYPE_CGROUP_SYNC_EVENT:
175 GetCgroupFileContent(resType, payload, reply);
176 break;
177 case ResExeType::RES_TYPE_CGROUP_PROC_TASK_SYNC_EVENT:
178 CheckProcTaskForCgroup(resType, payload, reply);
179 break;
180 case ResExeType::RES_TYPE_SET_THREAD_SCHED_POLICY_SYNC_EVENT:
181 ret = CgroupSetting::CgroupAction::GetInstance().SetThreadSchedPolicy(tid, schedPolicy) ? 0 : -1;
182 reply["ret"] = std::to_string(ret);
183 break;
184 case ResExeType::RES_TYPE_SET_THREAD_GROUP_SCHED_POLICY_SYNC_EVENT:
185 ret = CgroupSetting::CgroupAction::GetInstance().SetThreadGroupSchedPolicy(tid, schedPolicy) ? 0 : -1;
186 reply["ret"] = std::to_string(ret);
187 break;
188 default:
189 break;
190 }
191 return;
192 }
193
ParseValue(int32_t & value,const char * name,const nlohmann::json & payload)194 bool ResSchedExeMgr::ParseValue(int32_t& value, const char* name, const nlohmann::json& payload)
195 {
196 if (payload.contains(name) && payload.at(name).is_string()) {
197 value = atoi(payload[name].get<std::string>().c_str());
198 return true;
199 }
200 return false;
201 }
202
GetCgroupFileContent(uint32_t resType,const nlohmann::json & payload,nlohmann::json & reply)203 void ResSchedExeMgr::GetCgroupFileContent(uint32_t resType, const nlohmann::json& payload, nlohmann::json& reply)
204 {
205 if (!payload.contains("pid") || !payload["pid"].is_number_integer()) {
206 return;
207 }
208 int pid = payload["pid"];
209 std::string path = std::string("/proc/").append(std::to_string(pid)).append("/cgroup");
210 char resolvedPath[PATH_MAX] = { 0 };
211 if (path.size() > PATH_MAX || !realpath(path.c_str(), resolvedPath)) {
212 RSSEXE_LOGE("%{public}s realpath failed", __func__);
213 return;
214 }
215 auto realPath = std::string(resolvedPath);
216 std::ifstream fin(realPath.c_str(), std::ios::in);
217 if (!fin) {
218 return;
219 }
220 std::stringstream ss;
221 ss << fin.rdbuf();
222 reply["res"] = ss.str();
223 }
224
CheckProcTaskForCgroup(uint32_t resType,const nlohmann::json & payload,nlohmann::json & reply)225 void ResSchedExeMgr::CheckProcTaskForCgroup(uint32_t resType, const nlohmann::json& payload, nlohmann::json& reply)
226 {
227 if (!payload.contains("pid") || !payload["pid"].is_number_integer()) {
228 return;
229 }
230 if (!payload.contains("tid") || !payload["tid"].is_number_integer()) {
231 return;
232 }
233 int pid = payload["pid"];
234 int tid = payload["tid"];
235 std::string pathName = std::string("/proc/").append(std::to_string(pid))
236 .append("/task/").append(std::to_string(tid)).append("/comm");
237 std::string realPath;
238 reply["res"] = PathToRealPath(pathName, realPath);
239 return;
240 }
241 } // namespace ResourceSchedule
242 } // namespace OHOS
243