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