• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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