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 <cstdint>
17 #include <dlfcn.h>
18 #include "res_sched_service.h"
19 #include <file_ex.h>
20 #include <parameters.h>
21 #include <string_ex.h>
22 #include "accesstoken_kit.h"
23 #include "ipc_skeleton.h"
24 #include "notifier_mgr.h"
25 #include "plugin_mgr.h"
26 #include "res_sched_errors.h"
27 #include "res_sched_exe_client.h"
28 #include "res_sched_log.h"
29 #include "res_sched_mgr.h"
30 #include "tokenid_kit.h"
31 #include "sched_controller.h"
32 #include "supervisor.h"
33 #include "ressched_utils.h"
34 #include "event_listener_mgr.h"
35
36 namespace OHOS {
37 namespace ResourceSchedule {
38 using namespace OHOS::Security;
39 namespace {
40 constexpr int32_t DUMP_OPTION = 0;
41 constexpr int32_t DUMP_PARAM_INDEX = 1;
42 const int32_t ENG_MODE = OHOS::system::GetIntParameter("const.debuggable", 0);
43 const std::string APP_PRELOAD_PLIGIN_NAME = "libapp_preload_plugin.z.so";
44 }
45
ReportData(uint32_t resType,int64_t value,const nlohmann::json & payload)46 void ResSchedService::ReportData(uint32_t resType, int64_t value, const nlohmann::json& payload)
47 {
48 int32_t clientPid = IPCSkeleton::GetCallingPid();
49 RESSCHED_LOGD("ResSchedService receive data from ipc resType: %{public}u, value: %{public}lld, pid: %{public}d",
50 resType, (long long)value, clientPid);
51 const nlohmann::json* payloadP = &payload;
52 int32_t callingUid = IPCSkeleton::GetCallingUid();
53 nlohmann::json* payloadM = const_cast<nlohmann::json*>(payloadP);
54 (*payloadM)["callingUid"] = std::to_string(callingUid);
55 (*payloadM)["clientPid"] = std::to_string(clientPid);
56 ResSchedMgr::GetInstance().ReportData(resType, value, *payloadM);
57 }
58
ReportSyncEvent(const uint32_t resType,const int64_t value,const nlohmann::json & payload,nlohmann::json & reply)59 int32_t ResSchedService::ReportSyncEvent(const uint32_t resType, const int64_t value, const nlohmann::json& payload,
60 nlohmann::json& reply)
61 {
62 return PluginMgr::GetInstance().DeliverResource(std::make_shared<ResData>(resType, value, payload, reply));
63 }
64
KillProcess(const nlohmann::json & payload)65 int32_t ResSchedService::KillProcess(const nlohmann::json& payload)
66 {
67 return ResSchedMgr::GetInstance().KillProcessByClient(payload);
68 }
69
RegisterSystemloadNotifier(const sptr<IRemoteObject> & notifier)70 void ResSchedService::RegisterSystemloadNotifier(const sptr<IRemoteObject>& notifier)
71 {
72 NotifierMgr::GetInstance().RegisterNotifier(IPCSkeleton::GetCallingPid(), notifier);
73 }
74
UnRegisterSystemloadNotifier()75 void ResSchedService::UnRegisterSystemloadNotifier()
76 {
77 NotifierMgr::GetInstance().UnRegisterNotifier(IPCSkeleton::GetCallingPid());
78 }
79
RegisterEventListener(const sptr<IRemoteObject> & eventListener,uint32_t eventType,uint32_t listenerGroup)80 void ResSchedService::RegisterEventListener(const sptr<IRemoteObject>& eventListener, uint32_t eventType,
81 uint32_t listenerGroup)
82 {
83 EventListenerMgr::GetInstance().RegisterEventListener(IPCSkeleton::GetCallingPid(), eventListener, eventType,
84 listenerGroup);
85 }
86
UnRegisterEventListener(uint32_t eventType,uint32_t listenerGroup)87 void ResSchedService::UnRegisterEventListener(uint32_t eventType, uint32_t listenerGroup)
88 {
89 EventListenerMgr::GetInstance().UnRegisterEventListener(IPCSkeleton::GetCallingPid(), eventType, listenerGroup);
90 }
91
GetSystemloadLevel()92 int32_t ResSchedService::GetSystemloadLevel()
93 {
94 return NotifierMgr::GetInstance().GetSystemloadLevel();
95 }
96
OnDeviceLevelChanged(int32_t type,int32_t level)97 void ResSchedService::OnDeviceLevelChanged(int32_t type, int32_t level)
98 {
99 NotifierMgr::GetInstance().OnDeviceLevelChanged(type, level);
100 nlohmann::json payload;
101 payload["systemloadLevel"] = std::to_string(level);
102 ResSchedUtils::GetInstance().ReportDataInProcess(type, level, payload);
103 }
104
IsAllowedAppPreload(const std::string & bundleName,int32_t preloadMode)105 bool ResSchedService::IsAllowedAppPreload(const std::string& bundleName, int32_t preloadMode)
106 {
107 LoadAppPreloadPlugin();
108 if (!appPreloadFunc_) {
109 RESSCHED_LOGE("%{public}s, no allow AppPreload !", __func__, errno);
110 return false;
111 }
112 return appPreloadFunc_(bundleName, preloadMode);
113 }
114
LoadAppPreloadPlugin()115 void ResSchedService::LoadAppPreloadPlugin()
116 {
117 std::shared_ptr<PluginLib> libInfoPtr = PluginMgr::GetInstance().GetPluginLib(APP_PRELOAD_PLIGIN_NAME);
118 if (libInfoPtr == nullptr) {
119 RESSCHED_LOGE("ResSchedService::LoadAppPreloadPlugin libInfoPtr nullptr");
120 isLoadAppPreloadPlugin_ = false;
121 return;
122 }
123
124 if (isLoadAppPreloadPlugin_) {
125 RESSCHED_LOGI("ResSchedService::LoadAppPreloadPlugin, already loaded AppPreloadPlugin");
126 return;
127 }
128
129 appPreloadFunc_ = reinterpret_cast<OnIsAllowedAppPreloadFunc>(dlsym(libInfoPtr->handle.get(),
130 "OnIsAllowedAppPreload"));
131 isLoadAppPreloadPlugin_ = true;
132 }
133
AllowDump()134 bool ResSchedService::AllowDump()
135 {
136 if (ENG_MODE == 0) {
137 RESSCHED_LOGE("Not eng mode");
138 return false;
139 }
140 Security::AccessToken::AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
141 int32_t ret = Security::AccessToken::AccessTokenKit::VerifyAccessToken(tokenId, "ohos.permission.DUMP");
142 if (ret != Security::AccessToken::PermissionState::PERMISSION_GRANTED) {
143 RESSCHED_LOGE("CheckPermission failed");
144 return false;
145 }
146 return true;
147 }
148
Dump(int32_t fd,const std::vector<std::u16string> & args)149 int32_t ResSchedService::Dump(int32_t fd, const std::vector<std::u16string>& args)
150 {
151 if (!AllowDump()) {
152 return ERR_RES_SCHED_PERMISSION_DENIED;
153 }
154 RESSCHED_LOGI("%{public}s Dump service.", __func__);
155 std::vector<std::string> argsInStr;
156 std::transform(args.begin(), args.end(), std::back_inserter(argsInStr),
157 [](const std::u16string &arg) {
158 std::string ret = Str16ToStr8(arg);
159 RESSCHED_LOGI("%{public}s arg: %{public}s.", __func__, ret.c_str());
160 return ret;
161 });
162 std::string result;
163 if (argsInStr.size() == 0) {
164 // hidumper -s said '-h'
165 DumpUsage(result);
166 } else if (argsInStr.size() == DUMP_OPTION + 1) {
167 // hidumper -s said '-h' or hidumper -s said '-a'
168 DumpExt(argsInStr, result);
169 } else if (argsInStr.size() >= DUMP_PARAM_INDEX + 1) {
170 if (argsInStr[DUMP_OPTION] == "-p") {
171 std::vector<std::string> argsInStrToPlugin;
172 argsInStrToPlugin.assign(argsInStr.begin() + DUMP_PARAM_INDEX + 1, argsInStr.end());
173 PluginMgr::GetInstance().DumpOnePlugin(result, argsInStr[DUMP_PARAM_INDEX], argsInStrToPlugin);
174 } else if (argsInStr[DUMP_OPTION] == "sendDebugToExecutor") {
175 DumpExecutorDebugCommand(argsInStr, result);
176 }
177 }
178
179 if (!SaveStringToFd(fd, result)) {
180 RESSCHED_LOGE("%{public}s save to fd failed.", __func__);
181 }
182 return ERR_OK;
183 }
184
185
DumpExt(const std::vector<std::string> & argsInStr,std::string & result)186 void ResSchedService::DumpExt(const std::vector<std::string>& argsInStr, std::string &result)
187 {
188 if (argsInStr[DUMP_OPTION] == "-h") {
189 DumpUsage(result);
190 } else if (argsInStr[DUMP_OPTION] == "-a") {
191 DumpAllInfo(result);
192 } else if (argsInStr[DUMP_OPTION] == "-p") {
193 PluginMgr::GetInstance().DumpAllPlugin(result);
194 } else if (argsInStr[DUMP_OPTION] == "getRunningLockInfo") {
195 DumpProcessRunningLock(result);
196 } else if (argsInStr[DUMP_OPTION] == "getProcessEventInfo") {
197 DumpProcessEventState(result);
198 } else if (argsInStr[DUMP_OPTION] == "getProcessWindowInfo") {
199 DumpProcessWindowInfo(result);
200 } else if (argsInStr[DUMP_OPTION] == "getSystemloadInfo") {
201 DumpSystemLoadInfo(result);
202 } else if (argsInStr[DUMP_OPTION] == "sendDebugToExecutor") {
203 DumpExecutorDebugCommand(argsInStr, result);
204 } else if (argsInStr[DUMP_OPTION] == "PluginConfig") {
205 DumpAllPluginConfig(result);
206 } else {
207 result.append("Error params.");
208 }
209 }
210
DumpProcessRunningLock(std::string & result)211 void ResSchedService::DumpProcessRunningLock(std::string &result)
212 {
213 auto supervisor = SchedController::GetInstance().GetSupervisor();
214 if (supervisor == nullptr) {
215 result.append("get supervisor failed");
216 return;
217 }
218
219 std::map<int32_t, std::shared_ptr<Application>> uidMap = supervisor->GetUidsMap();
220 for (auto it = uidMap.begin(); it != uidMap.end(); it++) {
221 int32_t uid = it->first;
222 std::shared_ptr<Application> app = it->second;
223 std::map<pid_t, std::shared_ptr<ProcessRecord>> pidMap = app->GetPidsMap();
224 for (auto pidIt = pidMap.begin(); pidIt != pidMap.end(); pidIt++) {
225 int32_t pid = pidIt->first;
226 std::shared_ptr<ProcessRecord> process = pidIt->second;
227 for (auto lockIt = process->runningLockState_.begin();
228 lockIt != process->runningLockState_.end(); lockIt++) {
229 uint32_t lockType = lockIt->first;
230 bool lockState = lockIt->second;
231 result.append("uid:").append(ToString(uid))
232 .append(", pid:").append(ToString(pid))
233 .append(", lockType:").append(ToString(lockType))
234 .append(", lockState:").append(ToString(lockState)).append("\n");
235 }
236 }
237 }
238 }
239
DumpProcessWindowInfo(std::string & result)240 void ResSchedService::DumpProcessWindowInfo(std::string &result)
241 {
242 auto supervisor = SchedController::GetInstance().GetSupervisor();
243 if (supervisor == nullptr) {
244 result.append("get supervisor failed");
245 return;
246 }
247
248 std::map<int32_t, std::shared_ptr<Application>> uidMap = supervisor->GetUidsMap();
249 for (auto it = uidMap.begin(); it != uidMap.end(); it++) {
250 int32_t uid = it->first;
251 std::shared_ptr<Application> app = it->second;
252 std::map<pid_t, std::shared_ptr<ProcessRecord>> pidMap = app->GetPidsMap();
253 std::string bundleName = app->GetName();
254 for (auto pidIt = pidMap.begin(); pidIt != pidMap.end(); pidIt++) {
255 int32_t pid = pidIt->first;
256 std::shared_ptr<ProcessRecord> process = pidIt->second;
257 if (process->windows_.size() == 0) {
258 continue;
259 }
260 result.append("uid:").append(ToString(uid))
261 .append(", pid:").append(ToString(pid))
262 .append(", bundleName:").append(bundleName)
263 .append(", processDrawingState:").append(ToString(process->processDrawingState_))
264 .append(", windowInfo:").append("\n");
265 for (auto &windows : process->windows_) {
266 result.append(" windowId:").append(ToString(windows->windowId_))
267 .append(", visibilityState:").append(ToString(windows->visibilityState_))
268 .append(", isVisible:").append(ToString(windows->isVisible_))
269 .append(", isFocus:").append(ToString(windows->isFocused_))
270 .append(", topWebRenderUid:").append(ToString(windows->topWebviewRenderUid_))
271 .append("\n");
272 }
273 }
274 }
275 }
276
DumpProcessEventState(std::string & result)277 void ResSchedService::DumpProcessEventState(std::string &result)
278 {
279 auto supervisor = SchedController::GetInstance().GetSupervisor();
280 if (supervisor == nullptr) {
281 result.append("get supervisor failed");
282 return;
283 }
284
285 std::map<int32_t, std::shared_ptr<Application>> uidMap = supervisor->GetUidsMap();
286 for (auto it = uidMap.begin(); it != uidMap.end(); it++) {
287 int32_t uid = it->first;
288 std::shared_ptr<Application> app = it->second;
289 std::map<pid_t, std::shared_ptr<ProcessRecord>> pidMap = app->GetPidsMap();
290 for (auto pidIt = pidMap.begin(); pidIt != pidMap.end(); pidIt++) {
291 int32_t pid = pidIt->first;
292 std::shared_ptr<ProcessRecord> process = pidIt->second;
293 result.append("uid:").append(ToString(uid))
294 .append(", pid:").append(ToString(pid))
295 .append(", processState:").append(ToString(process->processState_))
296 .append(", napState:").append(ToString(process->isNapState_))
297 .append(", processDrawingState:").append(ToString(process->processDrawingState_))
298 .append(", mmiState:").append(ToString(process->mmiStatus_))
299 .append(", camearaStatus:").append(ToString(process->cameraState_))
300 .append(", bluetoothStatus:").append(ToString(process->bluetoothState_))
301 .append(", wifiStatus:").append(ToString(process->wifiState_))
302 .append(", screenCaptureState:").append(ToString(process->screenCaptureState_))
303 .append(", videoState:").append(ToString(process->videoState_))
304 .append(", audioPlayingState:").append(ToString(process->audioPlayingState_))
305 .append(", isActive:").append(ToString(process->isActive_))
306 .append(", linkedWindowId:").append(ToString(process->linkedWindowId_))
307 .append("\n");
308 }
309 }
310 }
311
DumpSystemLoadInfo(std::string & result)312 void ResSchedService::DumpSystemLoadInfo(std::string &result)
313 {
314 result.append("systemloadLevel:")
315 .append(ToString(NotifierMgr::GetInstance().GetSystemloadLevel()))
316 .append("\n");
317 auto notifierInfo = NotifierMgr::GetInstance().DumpRegisterInfo();
318 std::string native("natives:");
319 std::string hap("apps:");
320 for (auto& info : notifierInfo) {
321 std::string str = ToString(info.first).append(" ");
322 if (info.second) {
323 hap.append(str);
324 } else {
325 native.append(str);
326 }
327 }
328 hap.append("\n");
329 native.append("\n");
330 result.append(native).append(hap);
331 }
332
DumpUsage(std::string & result)333 void ResSchedService::DumpUsage(std::string &result)
334 {
335 result.append("usage: resource schedule service dump [<options>]\n")
336 .append(" -h: show the help.\n")
337 .append(" -a: show all info.\n")
338 .append(" -p: show the all plugin info.\n")
339 .append(" -p (plugin name): show one plugin info.\n");
340 PluginMgr::GetInstance().DumpHelpFromPlugin(result);
341 }
342
DumpAllInfo(std::string & result)343 void ResSchedService::DumpAllInfo(std::string &result)
344 {
345 result.append("================Resource Schedule Service Infos================\n");
346 PluginMgr::GetInstance().DumpAllPlugin(result);
347 }
348
DumpExecutorDebugCommand(const std::vector<std::string> & args,std::string & result)349 void ResSchedService::DumpExecutorDebugCommand(const std::vector<std::string>& args, std::string& result)
350 {
351 // hidumper -s said 'sendDebugToExecutor [isSync times]' isSync - 0/1(default 0), times - 1~...(default 1)
352 result.append("Send debug command to resource_schedule_executor.\n");
353 bool isSync = true;
354 int times = 1;
355 if (args.size() > DUMP_PARAM_INDEX + 1) {
356 int arg = atoi(args[DUMP_PARAM_INDEX + 1].c_str());
357 times = arg > 0 ? arg : times;
358 }
359 if (args.size() > DUMP_PARAM_INDEX) {
360 isSync = atoi(args[DUMP_PARAM_INDEX].c_str()) == 0;
361 }
362 uint32_t internal = 200;
363 for (int i = 0; i < times; i++) {
364 ResSchedExeClient::GetInstance().SendDebugCommand(isSync);
365 usleep(internal);
366 }
367 }
368
DumpAllPluginConfig(std::string & result)369 void ResSchedService::DumpAllPluginConfig(std::string &result)
370 {
371 result.append("================Resource Schedule Plugin Config================\n");
372 PluginMgr::GetInstance().DumpAllPluginConfig(result);
373 }
374 } // namespace ResourceSchedule
375 } // namespace OHOS
376
377