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