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 }
101
IsAllowedAppPreload(const std::string & bundleName,int32_t preloadMode)102 bool ResSchedService::IsAllowedAppPreload(const std::string& bundleName, int32_t preloadMode)
103 {
104 LoadAppPreloadPlugin();
105 if (!appPreloadFunc_) {
106 RESSCHED_LOGE("%{public}s, no allow AppPreload !", __func__, errno);
107 return false;
108 }
109 return appPreloadFunc_(bundleName, preloadMode);
110 }
111
LoadAppPreloadPlugin()112 void ResSchedService::LoadAppPreloadPlugin()
113 {
114 std::shared_ptr<PluginLib> libInfoPtr = PluginMgr::GetInstance().GetPluginLib(APP_PRELOAD_PLIGIN_NAME);
115 if (libInfoPtr == nullptr) {
116 RESSCHED_LOGE("ResSchedService::LoadAppPreloadPlugin libInfoPtr nullptr");
117 isLoadAppPreloadPlugin_ = false;
118 return;
119 }
120
121 if (isLoadAppPreloadPlugin_) {
122 RESSCHED_LOGI("ResSchedService::LoadAppPreloadPlugin, already loaded AppPreloadPlugin");
123 return;
124 }
125
126 appPreloadFunc_ = reinterpret_cast<OnIsAllowedAppPreloadFunc>(dlsym(libInfoPtr->handle.get(),
127 "OnIsAllowedAppPreload"));
128 isLoadAppPreloadPlugin_ = true;
129 }
130
AllowDump()131 bool ResSchedService::AllowDump()
132 {
133 if (ENG_MODE == 0) {
134 RESSCHED_LOGE("Not eng mode");
135 return false;
136 }
137 Security::AccessToken::AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
138 int32_t ret = Security::AccessToken::AccessTokenKit::VerifyAccessToken(tokenId, "ohos.permission.DUMP");
139 if (ret != Security::AccessToken::PermissionState::PERMISSION_GRANTED) {
140 RESSCHED_LOGE("CheckPermission failed");
141 return false;
142 }
143 return true;
144 }
145
Dump(int32_t fd,const std::vector<std::u16string> & args)146 int32_t ResSchedService::Dump(int32_t fd, const std::vector<std::u16string>& args)
147 {
148 if (!AllowDump()) {
149 return ERR_RES_SCHED_PERMISSION_DENIED;
150 }
151 RESSCHED_LOGI("%{public}s Dump service.", __func__);
152 std::vector<std::string> argsInStr;
153 std::transform(args.begin(), args.end(), std::back_inserter(argsInStr),
154 [](const std::u16string &arg) {
155 std::string ret = Str16ToStr8(arg);
156 RESSCHED_LOGI("%{public}s arg: %{public}s.", __func__, ret.c_str());
157 return ret;
158 });
159 std::string result;
160 if (argsInStr.size() == 0) {
161 // hidumper -s said '-h'
162 DumpUsage(result);
163 } else if (argsInStr.size() == DUMP_OPTION + 1) {
164 // hidumper -s said '-h' or hidumper -s said '-a'
165 DumpExt(argsInStr, result);
166 } else if (argsInStr.size() >= DUMP_PARAM_INDEX + 1) {
167 if (argsInStr[DUMP_OPTION] == "-p") {
168 std::vector<std::string> argsInStrToPlugin;
169 argsInStrToPlugin.assign(argsInStr.begin() + DUMP_PARAM_INDEX + 1, argsInStr.end());
170 PluginMgr::GetInstance().DumpOnePlugin(result, argsInStr[DUMP_PARAM_INDEX], argsInStrToPlugin);
171 } else if (argsInStr[DUMP_OPTION] == "sendDebugToExecutor") {
172 DumpExecutorDebugCommand(argsInStr, result);
173 }
174 }
175
176 if (!SaveStringToFd(fd, result)) {
177 RESSCHED_LOGE("%{public}s save to fd failed.", __func__);
178 }
179 return ERR_OK;
180 }
181
182
DumpExt(const std::vector<std::string> & argsInStr,std::string & result)183 void ResSchedService::DumpExt(const std::vector<std::string>& argsInStr, std::string &result)
184 {
185 if (argsInStr[DUMP_OPTION] == "-h") {
186 DumpUsage(result);
187 } else if (argsInStr[DUMP_OPTION] == "-a") {
188 DumpAllInfo(result);
189 } else if (argsInStr[DUMP_OPTION] == "-p") {
190 PluginMgr::GetInstance().DumpAllPlugin(result);
191 } else if (argsInStr[DUMP_OPTION] == "getRunningLockInfo") {
192 DumpProcessRunningLock(result);
193 } else if (argsInStr[DUMP_OPTION] == "getProcessEventInfo") {
194 DumpProcessEventState(result);
195 } else if (argsInStr[DUMP_OPTION] == "getProcessWindowInfo") {
196 DumpProcessWindowInfo(result);
197 } else if (argsInStr[DUMP_OPTION] == "getSystemloadInfo") {
198 DumpSystemLoadInfo(result);
199 } else if (argsInStr[DUMP_OPTION] == "sendDebugToExecutor") {
200 DumpExecutorDebugCommand(argsInStr, result);
201 } else if (argsInStr[DUMP_OPTION] == "PluginConfig") {
202 DumpAllPluginConfig(result);
203 } else {
204 result.append("Error params.");
205 }
206 }
207
DumpProcessRunningLock(std::string & result)208 void ResSchedService::DumpProcessRunningLock(std::string &result)
209 {
210 auto supervisor = SchedController::GetInstance().GetSupervisor();
211 if (supervisor == nullptr) {
212 result.append("get supervisor failed");
213 return;
214 }
215
216 std::map<int32_t, std::shared_ptr<Application>> uidMap = supervisor->GetUidsMap();
217 for (auto it = uidMap.begin(); it != uidMap.end(); it++) {
218 int32_t uid = it->first;
219 std::shared_ptr<Application> app = it->second;
220 std::map<pid_t, std::shared_ptr<ProcessRecord>> pidMap = app->GetPidsMap();
221 for (auto pidIt = pidMap.begin(); pidIt != pidMap.end(); pidIt++) {
222 int32_t pid = pidIt->first;
223 std::shared_ptr<ProcessRecord> process = pidIt->second;
224 for (auto lockIt = process->runningLockState_.begin();
225 lockIt != process->runningLockState_.end(); lockIt++) {
226 uint32_t lockType = lockIt->first;
227 bool lockState = lockIt->second;
228 result.append("uid:").append(ToString(uid))
229 .append(", pid:").append(ToString(pid))
230 .append(", lockType:").append(ToString(lockType))
231 .append(", lockState:").append(ToString(lockState)).append("\n");
232 }
233 }
234 }
235 }
236
DumpProcessWindowInfo(std::string & result)237 void ResSchedService::DumpProcessWindowInfo(std::string &result)
238 {
239 auto supervisor = SchedController::GetInstance().GetSupervisor();
240 if (supervisor == nullptr) {
241 result.append("get supervisor failed");
242 return;
243 }
244
245 std::map<int32_t, std::shared_ptr<Application>> uidMap = supervisor->GetUidsMap();
246 for (auto it = uidMap.begin(); it != uidMap.end(); it++) {
247 int32_t uid = it->first;
248 std::shared_ptr<Application> app = it->second;
249 std::map<pid_t, std::shared_ptr<ProcessRecord>> pidMap = app->GetPidsMap();
250 std::string bundleName = app->GetName();
251 for (auto pidIt = pidMap.begin(); pidIt != pidMap.end(); pidIt++) {
252 int32_t pid = pidIt->first;
253 std::shared_ptr<ProcessRecord> process = pidIt->second;
254 if (process->windows_.size() == 0) {
255 continue;
256 }
257 result.append("uid:").append(ToString(uid))
258 .append(", pid:").append(ToString(pid))
259 .append(", bundleName:").append(bundleName)
260 .append(", processDrawingState:").append(ToString(process->processDrawingState_))
261 .append(", windowInfo:").append("\n");
262 for (auto &windows : process->windows_) {
263 result.append(" windowId:").append(ToString(windows->windowId_))
264 .append(", visibilityState:").append(ToString(windows->visibilityState_))
265 .append(", isVisible:").append(ToString(windows->isVisible_))
266 .append(", isFocus:").append(ToString(windows->isFocused_))
267 .append(", topWebRenderUid:").append(ToString(windows->topWebviewRenderUid_))
268 .append("\n");
269 }
270 }
271 }
272 }
273
DumpProcessEventState(std::string & result)274 void ResSchedService::DumpProcessEventState(std::string &result)
275 {
276 auto supervisor = SchedController::GetInstance().GetSupervisor();
277 if (supervisor == nullptr) {
278 result.append("get supervisor failed");
279 return;
280 }
281
282 std::map<int32_t, std::shared_ptr<Application>> uidMap = supervisor->GetUidsMap();
283 for (auto it = uidMap.begin(); it != uidMap.end(); it++) {
284 int32_t uid = it->first;
285 std::shared_ptr<Application> app = it->second;
286 std::map<pid_t, std::shared_ptr<ProcessRecord>> pidMap = app->GetPidsMap();
287 for (auto pidIt = pidMap.begin(); pidIt != pidMap.end(); pidIt++) {
288 int32_t pid = pidIt->first;
289 std::shared_ptr<ProcessRecord> process = pidIt->second;
290 result.append("uid:").append(ToString(uid))
291 .append(", pid:").append(ToString(pid))
292 .append(", processState:").append(ToString(process->processState_))
293 .append(", napState:").append(ToString(process->isNapState_))
294 .append(", processDrawingState:").append(ToString(process->processDrawingState_))
295 .append(", mmiState:").append(ToString(process->mmiStatus_))
296 .append(", camearaStatus:").append(ToString(process->cameraState_))
297 .append(", bluetoothStatus:").append(ToString(process->bluetoothState_))
298 .append(", wifiStatus:").append(ToString(process->wifiState_))
299 .append(", screenCaptureState:").append(ToString(process->screenCaptureState_))
300 .append(", videoState:").append(ToString(process->videoState_))
301 .append(", audioPlayingState:").append(ToString(process->audioPlayingState_))
302 .append(", isActive:").append(ToString(process->isActive_))
303 .append(", linkedWindowId:").append(ToString(process->linkedWindowId_))
304 .append("\n");
305 }
306 }
307 }
308
DumpSystemLoadInfo(std::string & result)309 void ResSchedService::DumpSystemLoadInfo(std::string &result)
310 {
311 result.append("systemloadLevel:")
312 .append(ToString(NotifierMgr::GetInstance().GetSystemloadLevel()))
313 .append("\n");
314 auto notifierInfo = NotifierMgr::GetInstance().DumpRegisterInfo();
315 std::string native("natives:");
316 std::string hap("apps:");
317 for (auto& info : notifierInfo) {
318 std::string str = ToString(info.first).append(" ");
319 if (info.second) {
320 hap.append(str);
321 } else {
322 native.append(str);
323 }
324 }
325 hap.append("\n");
326 native.append("\n");
327 result.append(native).append(hap);
328 }
329
DumpUsage(std::string & result)330 void ResSchedService::DumpUsage(std::string &result)
331 {
332 result.append("usage: resource schedule service dump [<options>]\n")
333 .append(" -h: show the help.\n")
334 .append(" -a: show all info.\n")
335 .append(" -p: show the all plugin info.\n")
336 .append(" -p (plugin name): show one plugin info.\n");
337 PluginMgr::GetInstance().DumpHelpFromPlugin(result);
338 }
339
DumpAllInfo(std::string & result)340 void ResSchedService::DumpAllInfo(std::string &result)
341 {
342 result.append("================Resource Schedule Service Infos================\n");
343 PluginMgr::GetInstance().DumpAllPlugin(result);
344 }
345
DumpExecutorDebugCommand(const std::vector<std::string> & args,std::string & result)346 void ResSchedService::DumpExecutorDebugCommand(const std::vector<std::string>& args, std::string& result)
347 {
348 // hidumper -s said 'sendDebugToExecutor [isSync times]' isSync - 0/1(default 0), times - 1~...(default 1)
349 result.append("Send debug command to resource_schedule_executor.\n");
350 bool isSync = true;
351 int times = 1;
352 if (args.size() > DUMP_PARAM_INDEX + 1) {
353 int arg = atoi(args[DUMP_PARAM_INDEX + 1].c_str());
354 times = arg > 0 ? arg : times;
355 }
356 if (args.size() > DUMP_PARAM_INDEX) {
357 isSync = atoi(args[DUMP_PARAM_INDEX].c_str()) == 0;
358 }
359 uint32_t internal = 200;
360 for (int i = 0; i < times; i++) {
361 ResSchedExeClient::GetInstance().SendDebugCommand(isSync);
362 usleep(internal);
363 }
364 }
365
DumpAllPluginConfig(std::string & result)366 void ResSchedService::DumpAllPluginConfig(std::string &result)
367 {
368 result.append("================Resource Schedule Plugin Config================\n");
369 PluginMgr::GetInstance().DumpAllPluginConfig(result);
370 }
371 } // namespace ResourceSchedule
372 } // namespace OHOS
373
374