1 /*
2 * Copyright (c) 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_service.h"
17
18 #include <file_ex.h>
19 #include <parameters.h>
20 #include <string_ex.h>
21
22 #include "accesstoken_kit.h"
23 #include "ipc_skeleton.h"
24 #include "system_ability_definition.h"
25
26 #include "plugin_mgr.h"
27 #include "executor_hitrace_chain.h"
28 #include "res_common_util.h"
29 #include "res_exe_type.h"
30 #include "res_sched_exe_constants.h"
31 #include "res_sched_exe_log.h"
32 #include "res_sched_exe_mgr.h"
33
34 namespace OHOS {
35 namespace ResourceSchedule {
36 namespace {
37 constexpr int32_t DUMP_OPTION = 0;
38 constexpr int32_t DUMP_PARAM_INDEX = 1;
39 const int32_t ENG_MODE = OHOS::system::GetIntParameter("const.debuggable", 0);
40 const std::string DUMP_PERMISSION = "ohos.permission.DUMP";
41 constexpr int32_t PAYLOAD_MAX_SIZE = 4096;
42 constexpr int32_t KILL_PROCESS_FAILED = -1;
43 constexpr int32_t RSS_UID = 1096;
44 const std::string RES_TYPE_EXT = "extType";
45
IsTypeVaild(uint32_t type)46 bool IsTypeVaild(uint32_t type)
47 {
48 return type >= ResExeType::RES_TYPE_FIRST && type < ResExeType::RES_TYPE_LAST;
49 }
50
IsCallingClientRss()51 bool IsCallingClientRss()
52 {
53 int32_t clientUid = IPCSkeleton::GetCallingUid();
54 RSSEXE_LOGD("calling client uid is %{public}d, allowed uid is %{public}d", clientUid, RSS_UID);
55 return RSS_UID == clientUid;
56 }
57
GetExtResType(uint32_t & resType,const nlohmann::json & context)58 bool GetExtResType(uint32_t& resType, const nlohmann::json& context)
59 {
60 if (resType != ResExeType::RES_TYPE_COMMON_SYNC && resType != ResExeType::RES_TYPE_COMMON_ASYNC) {
61 return true;
62 }
63 int type = 0;
64 if (!context.contains(RES_TYPE_EXT) || !context[RES_TYPE_EXT].is_string()
65 || !StrToInt(context[RES_TYPE_EXT], type)) {
66 RSSEXE_LOGE("use extend resType, but not send resTypeExt with payload");
67 return false;
68 }
69 resType = (uint32_t)type;
70 RSSEXE_LOGD("use extend resType = %{public}d.", resType);
71 return true;
72 }
73 }
74
75 const bool REGISTER_RESULT =
76 SystemAbility::MakeAndRegisterAbility(DelayedSingleton<ResSchedExeService>::GetInstance().get());
77
ResSchedExeService()78 ResSchedExeService::ResSchedExeService() : SystemAbility(RES_SCHED_EXE_ABILITY_ID, true)
79 {
80 }
81
~ResSchedExeService()82 ResSchedExeService::~ResSchedExeService()
83 {
84 }
85
OnStart()86 void ResSchedExeService::OnStart()
87 {
88 ExecutorHiTraceChain traceChain(__func__);
89 ResSchedExeMgr::GetInstance().Init();
90 if (!Publish(DelayedSingleton<ResSchedExeService>::GetInstance().get())) {
91 RSSEXE_LOGE("ResSchedExeService::Register service failed.");
92 return;
93 }
94 AddSystemAbilityListener(SUSPEND_MANAGER_SYSTEM_ABILITY_ID);
95 RSSEXE_LOGI("ResSchedExeService::OnStart.");
96 }
97
OnStop()98 void ResSchedExeService::OnStop()
99 {
100 ExecutorHiTraceChain traceChain(__func__);
101 ResSchedExeMgr::GetInstance().Stop();
102 RSSEXE_LOGI("ResSchedExeService::OnStop!");
103 }
104
OnRemoveSystemAbility(int32_t systemAbilityId,const std::string & deviceId)105 void ResSchedExeService::OnRemoveSystemAbility(int32_t systemAbilityId, const std::string &deviceId)
106 {
107 if (systemAbilityId == SUSPEND_MANAGER_SYSTEM_ABILITY_ID) {
108 RSSEXE_LOGI("ResSchedExeService::OnRemoveSystemAbility SUSPEND_MANAGER_SYSTEM_ABILITY_ID.");
109 nlohmann::json jsonContext;
110 ResSchedExeMgr::GetInstance().SendRequestAsync(ResExeType::RES_TYPE_EXT_SUSPEND_MANAGER_SA_CHANGED,
111 static_cast<int64_t>(false), jsonContext);
112 }
113 }
114
SendRequestSync(uint32_t resType,int64_t value,const ResJsonType & context,ResJsonType & response,int32_t & funcResult)115 ErrCode ResSchedExeService::SendRequestSync(uint32_t resType, int64_t value,
116 const ResJsonType &context, ResJsonType &response, int32_t &funcResult)
117 {
118 ExecutorHiTraceChain traceChain(__func__);
119 RSSEXE_LOGD("ResSchedExeService start to exec SendRequestSync, restType: %{public}u", resType);
120 if (!IsCallingClientRss()) {
121 RSSEXE_LOGE("calling process has no permission!");
122 return ERR_INVALID_OPERATION;
123 }
124 if (!IsTypeVaild(resType)) {
125 RSSEXE_LOGE("The resType is invalid. Dos");
126 return ERR_INVALID_VALUE;
127 }
128
129 nlohmann::json jsonContext = context.jsonContext;
130 if (jsonContext.size() > PAYLOAD_MAX_SIZE) {
131 RSSEXE_LOGE("The payload is too long. DoS.");
132 return ERR_INVALID_VALUE;
133 }
134 if (!GetExtResType(resType, jsonContext)) {
135 RSSEXE_LOGE("Get ResType Error DoS.");
136 return ERR_INVALID_VALUE;
137 }
138
139 nlohmann::json jsonResponse;
140 funcResult = ResSchedExeMgr::GetInstance().SendRequestSync(resType, value, jsonContext, jsonResponse);
141 response.jsonContext = jsonResponse;
142 return ERR_OK;
143 }
144
SendRequestAsync(uint32_t resType,int64_t value,const ResJsonType & context)145 ErrCode ResSchedExeService::SendRequestAsync(uint32_t resType, int64_t value, const ResJsonType& context)
146 {
147 ExecutorHiTraceChain traceChain(__func__);
148 RSSEXE_LOGD("ResSchedExeService start to exec SendRequestAsync, restType: %{public}u", resType);
149 if (!IsCallingClientRss()) {
150 RSSEXE_LOGE("calling process has no permission!");
151 return ERR_INVALID_OPERATION;
152 }
153 if (!IsTypeVaild(resType)) {
154 RSSEXE_LOGE("The resType is invalid. Dos");
155 return ERR_INVALID_VALUE;
156 }
157
158 nlohmann::json jsonContext = context.jsonContext;
159 if (jsonContext.size() > PAYLOAD_MAX_SIZE) {
160 RSSEXE_LOGE("The payload is too long. DoS.");
161 return ERR_INVALID_VALUE;
162 }
163 if (!GetExtResType(resType, jsonContext)) {
164 RSSEXE_LOGE("Get ResType Error DoS.");
165 return ERR_INVALID_VALUE;
166 }
167
168 ResSchedExeMgr::GetInstance().SendRequestAsync(resType, value, jsonContext);
169 return ERR_OK;
170 }
171
KillProcess(uint32_t pid,int32_t & funcResult)172 ErrCode ResSchedExeService::KillProcess(uint32_t pid, int32_t& funcResult)
173 {
174 ExecutorHiTraceChain traceChain(__func__);
175 RSSEXE_LOGD("ResSchedExeService start to exec KillProcess, pid: %{public}u", pid);
176 if (!IsCallingClientRss()) {
177 RSSEXE_LOGE("Calling process has no permission!");
178 return ERR_INVALID_OPERATION;
179 }
180 if (pid <= 0) {
181 RSSEXE_LOGE("Pid should be more than 0.");
182 return ERR_INVALID_VALUE;
183 }
184
185 funcResult = ResSchedExeMgr::GetInstance().KillProcess(static_cast<pid_t>(pid));
186 return ERR_OK;
187 }
188
AllowDump()189 bool ResSchedExeService::AllowDump()
190 {
191 if (ENG_MODE == 0) {
192 RSSEXE_LOGE("Not eng mode");
193 return false;
194 }
195 Security::AccessToken::AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
196 int32_t ret = Security::AccessToken::AccessTokenKit::VerifyAccessToken(tokenId, DUMP_PERMISSION);
197 if (ret != Security::AccessToken::PermissionState::PERMISSION_GRANTED) {
198 RSSEXE_LOGE("CheckPermission failed");
199 return false;
200 }
201 return true;
202 }
203
Dump(int32_t fd,const std::vector<std::u16string> & args)204 int32_t ResSchedExeService::Dump(int32_t fd, const std::vector<std::u16string>& args)
205 {
206 if (!AllowDump()) {
207 return ResErrCode::RSSEXE_PERMISSION_DENIED;
208 }
209 RSSEXE_LOGI("Dump service.");
210 std::vector<std::string> argsInStr;
211 std::transform(args.begin(), args.end(), std::back_inserter(argsInStr),
212 [](const std::u16string &arg) {
213 std::string ret = Str16ToStr8(arg);
214 RSSEXE_LOGI("arg: %{public}s.", ret.c_str());
215 return ret;
216 });
217 std::string result;
218 if (argsInStr.size() == 0) {
219 // hidumper -s said '-h'
220 DumpUsage(result);
221 } else if (argsInStr.size() == DUMP_OPTION + 1) {
222 // hidumper -s said '-h' or hidumper -s said '-a'
223 if (argsInStr[DUMP_OPTION] == "-h") {
224 DumpUsage(result);
225 } else if (argsInStr[DUMP_OPTION] == "-a") {
226 DumpAllInfo(result);
227 } else if (argsInStr[DUMP_OPTION] == "-p") {
228 PluginMgr::GetInstance().DumpAllPlugin(result);
229 } else {
230 result.append("Error params.");
231 }
232 } else if (argsInStr.size() >= DUMP_PARAM_INDEX + 1) {
233 if (argsInStr[DUMP_OPTION] == "-p") {
234 std::vector<std::string> argsInStrToPlugin;
235 argsInStrToPlugin.assign(argsInStr.begin() + DUMP_PARAM_INDEX + 1, argsInStr.end());
236 PluginMgr::GetInstance().DumpOnePlugin(result, argsInStr[DUMP_PARAM_INDEX], argsInStrToPlugin);
237 }
238 }
239
240 if (!SaveStringToFd(fd, result)) {
241 RSSEXE_LOGE("save to fd failed.");
242 }
243 return ResErrCode::RSSEXE_NO_ERR;
244 }
245
DumpUsage(std::string & result)246 void ResSchedExeService::DumpUsage(std::string &result)
247 {
248 result.append("usage: resource schedule executor dump [<options>]\n")
249 .append(" -h: show the help.\n")
250 .append(" -a: show all info.\n")
251 .append(" -p: show the all plugin info.\n")
252 .append(" -p (plugin name): show one plugin info.\n");
253 PluginMgr::GetInstance().DumpHelpFromPlugin(result);
254 }
255
DumpAllInfo(std::string & result)256 void ResSchedExeService::DumpAllInfo(std::string &result)
257 {
258 result.append("================Resource Schedule Executor Infos================\n");
259 PluginMgr::GetInstance().DumpAllPlugin(result);
260 }
261 } // namespace ResourceSchedule
262 } // namespace OHOS
263