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