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