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 "event_listener_mgr.h"
32 
33 namespace OHOS {
34 namespace ResourceSchedule {
35 using namespace OHOS::Security;
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 APP_PRELOAD_PLIGIN_NAME = "libapp_preload_plugin.z.so";
41 }
42 
ReportData(uint32_t resType, int64_t value, const nlohmann::json& payload)43 void ResSchedService::ReportData(uint32_t resType, int64_t value, const nlohmann::json& payload)
44 {
45     int32_t clientPid = IPCSkeleton::GetCallingPid();
46     RESSCHED_LOGD("ResSchedService receive data from ipc resType: %{public}u, value: %{public}lld, pid: %{public}d",
47                   resType, (long long)value, clientPid);
48     const nlohmann::json* payloadP = &payload;
49     int32_t callingUid = IPCSkeleton::GetCallingUid();
50     nlohmann::json* payloadM = const_cast<nlohmann::json*>(payloadP);
51     (*payloadM)["callingUid"] = std::to_string(callingUid);
52     (*payloadM)["clientPid"] = std::to_string(clientPid);
53     ResSchedMgr::GetInstance().ReportData(resType, value, *payloadM);
54 }
55 
ReportSyncEvent(const uint32_t resType, const int64_t value, const nlohmann::json& payload, nlohmann::json& reply)56 int32_t ResSchedService::ReportSyncEvent(const uint32_t resType, const int64_t value, const nlohmann::json& payload,
57     nlohmann::json& reply)
58 {
59     return PluginMgr::GetInstance().DeliverResource(std::make_shared<ResData>(resType, value, payload, reply));
60 }
61 
KillProcess(const nlohmann::json& payload)62 int32_t ResSchedService::KillProcess(const nlohmann::json& payload)
63 {
64     return ResSchedMgr::GetInstance().KillProcessByClient(payload);
65 }
66 
RegisterSystemloadNotifier(const sptr<IRemoteObject>& notifier)67 void ResSchedService::RegisterSystemloadNotifier(const sptr<IRemoteObject>& notifier)
68 {
69     NotifierMgr::GetInstance().RegisterNotifier(IPCSkeleton::GetCallingPid(), notifier);
70 }
71 
UnRegisterSystemloadNotifier()72 void ResSchedService::UnRegisterSystemloadNotifier()
73 {
74     NotifierMgr::GetInstance().UnRegisterNotifier(IPCSkeleton::GetCallingPid());
75 }
76 
RegisterEventListener(const sptr<IRemoteObject>& eventListener, uint32_t eventType, uint32_t listenerGroup)77 void ResSchedService::RegisterEventListener(const sptr<IRemoteObject>& eventListener, uint32_t eventType,
78     uint32_t listenerGroup)
79 {
80     EventListenerMgr::GetInstance().RegisterEventListener(IPCSkeleton::GetCallingPid(), eventListener, eventType,
81         listenerGroup);
82 }
83 
UnRegisterEventListener(uint32_t eventType, uint32_t listenerGroup)84 void ResSchedService::UnRegisterEventListener(uint32_t eventType, uint32_t listenerGroup)
85 {
86     EventListenerMgr::GetInstance().UnRegisterEventListener(IPCSkeleton::GetCallingPid(), eventType, listenerGroup);
87 }
88 
GetSystemloadLevel()89 int32_t ResSchedService::GetSystemloadLevel()
90 {
91     return NotifierMgr::GetInstance().GetSystemloadLevel();
92 }
93 
OnDeviceLevelChanged(int32_t type, int32_t level)94 void ResSchedService::OnDeviceLevelChanged(int32_t type, int32_t level)
95 {
96     NotifierMgr::GetInstance().OnDeviceLevelChanged(type, level);
97 }
98 
IsAllowedAppPreload(const std::string& bundleName, int32_t preloadMode)99 bool ResSchedService::IsAllowedAppPreload(const std::string& bundleName, int32_t preloadMode)
100 {
101     LoadAppPreloadPlugin();
102     if (!appPreloadFunc_) {
103         RESSCHED_LOGE("%{public}s, no allow AppPreload !", __func__, errno);
104         return false;
105     }
106     return appPreloadFunc_(bundleName, preloadMode);
107 }
108 
LoadAppPreloadPlugin()109 void ResSchedService::LoadAppPreloadPlugin()
110 {
111     std::shared_ptr<PluginLib> libInfoPtr = PluginMgr::GetInstance().GetPluginLib(APP_PRELOAD_PLIGIN_NAME);
112     if (libInfoPtr == nullptr) {
113         RESSCHED_LOGE("ResSchedService::LoadAppPreloadPlugin libInfoPtr nullptr");
114         isLoadAppPreloadPlugin_ = false;
115         return;
116     }
117 
118     if (isLoadAppPreloadPlugin_) {
119         RESSCHED_LOGI("ResSchedService::LoadAppPreloadPlugin, already loaded AppPreloadPlugin");
120         return;
121     }
122 
123     appPreloadFunc_ = reinterpret_cast<OnIsAllowedAppPreloadFunc>(dlsym(libInfoPtr->handle.get(),
124         "OnIsAllowedAppPreload"));
125     isLoadAppPreloadPlugin_ = true;
126 }
127 
AllowDump()128 bool ResSchedService::AllowDump()
129 {
130     if (ENG_MODE == 0) {
131         RESSCHED_LOGE("Not eng mode");
132         return false;
133     }
134     Security::AccessToken::AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
135     int32_t ret = Security::AccessToken::AccessTokenKit::VerifyAccessToken(tokenId, "ohos.permission.DUMP");
136     if (ret != Security::AccessToken::PermissionState::PERMISSION_GRANTED) {
137         RESSCHED_LOGE("CheckPermission failed");
138         return false;
139     }
140     return true;
141 }
142 
Dump(int32_t fd, const std::vector<std::u16string>& args)143 int32_t ResSchedService::Dump(int32_t fd, const std::vector<std::u16string>& args)
144 {
145     if (!AllowDump()) {
146         return ERR_RES_SCHED_PERMISSION_DENIED;
147     }
148     RESSCHED_LOGI("%{public}s Dump service.", __func__);
149     std::vector<std::string> argsInStr;
150     std::transform(args.begin(), args.end(), std::back_inserter(argsInStr),
151         [](const std::u16string &arg) {
152         std::string ret = Str16ToStr8(arg);
153         RESSCHED_LOGI("%{public}s arg: %{public}s.", __func__, ret.c_str());
154         return ret;
155     });
156     std::string result;
157     if (argsInStr.size() == 0) {
158         // hidumper -s said '-h'
159         DumpUsage(result);
160     } else if (argsInStr.size() == DUMP_OPTION + 1) {
161         // hidumper -s said '-h' or hidumper -s said '-a'
162         DumpExt(argsInStr, result);
163     } else if (argsInStr.size() >= DUMP_PARAM_INDEX + 1) {
164         if (argsInStr[DUMP_OPTION] == "-p") {
165             std::vector<std::string> argsInStrToPlugin;
166             argsInStrToPlugin.assign(argsInStr.begin() + DUMP_PARAM_INDEX + 1, argsInStr.end());
167             PluginMgr::GetInstance().DumpOnePlugin(result, argsInStr[DUMP_PARAM_INDEX], argsInStrToPlugin);
168         } else if (argsInStr[DUMP_OPTION] == "sendDebugToExecutor") {
169             DumpExecutorDebugCommand(argsInStr, result);
170         }
171     }
172 
173     if (!SaveStringToFd(fd, result)) {
174         RESSCHED_LOGE("%{public}s save to fd failed.", __func__);
175     }
176     return ERR_OK;
177 }
178 
179 
DumpExt(const std::vector<std::string>& argsInStr, std::string &result)180 void ResSchedService::DumpExt(const std::vector<std::string>& argsInStr, std::string &result)
181 {
182     if (argsInStr[DUMP_OPTION] == "-h") {
183         DumpUsage(result);
184     } else if (argsInStr[DUMP_OPTION] == "-a") {
185         DumpAllInfo(result);
186     } else if (argsInStr[DUMP_OPTION] == "-p") {
187         PluginMgr::GetInstance().DumpAllPlugin(result);
188     } else if (argsInStr[DUMP_OPTION] == "getSystemloadInfo") {
189         DumpSystemLoadInfo(result);
190     } else if (argsInStr[DUMP_OPTION] == "sendDebugToExecutor") {
191         DumpExecutorDebugCommand(argsInStr, result);
192     } else if (argsInStr[DUMP_OPTION] == "PluginConfig") {
193         DumpAllPluginConfig(result);
194     } else {
195         result.append("Error params.");
196     }
197 }
198 
DumpSystemLoadInfo(std::string &result)199 void ResSchedService::DumpSystemLoadInfo(std::string &result)
200 {
201     result.append("systemloadLevel:")
202         .append(ToString(NotifierMgr::GetInstance().GetSystemloadLevel()))
203         .append("\n");
204     auto notifierInfo = NotifierMgr::GetInstance().DumpRegisterInfo();
205     std::string native("natives:");
206     std::string hap("apps:");
207     for (auto& info : notifierInfo) {
208         std::string str = ToString(info.first).append(" ");
209         if (info.second) {
210             hap.append(str);
211         } else {
212             native.append(str);
213         }
214     }
215     hap.append("\n");
216     native.append("\n");
217     result.append(native).append(hap);
218 }
219 
DumpUsage(std::string &result)220 void ResSchedService::DumpUsage(std::string &result)
221 {
222     result.append("usage: resource schedule service dump [<options>]\n")
223         .append("    -h: show the help.\n")
224         .append("    -a: show all info.\n")
225         .append("    -p: show the all plugin info.\n")
226         .append("    -p (plugin name): show one plugin info.\n");
227     PluginMgr::GetInstance().DumpHelpFromPlugin(result);
228 }
229 
DumpAllInfo(std::string &result)230 void ResSchedService::DumpAllInfo(std::string &result)
231 {
232     result.append("================Resource Schedule Service Infos================\n");
233     PluginMgr::GetInstance().DumpAllPlugin(result);
234 }
235 
DumpExecutorDebugCommand(const std::vector<std::string>& args, std::string& result)236 void ResSchedService::DumpExecutorDebugCommand(const std::vector<std::string>& args, std::string& result)
237 {
238     // hidumper -s said 'sendDebugToExecutor [isSync times]' isSync - 0/1(default 0), times - 1~...(default 1)
239     result.append("Send debug command to resource_schedule_executor.\n");
240     bool isSync = true;
241     int times = 1;
242     if (args.size() > DUMP_PARAM_INDEX + 1) {
243         int arg = atoi(args[DUMP_PARAM_INDEX + 1].c_str());
244         times = arg > 0 ? arg : times;
245     }
246     if (args.size() > DUMP_PARAM_INDEX) {
247         isSync = atoi(args[DUMP_PARAM_INDEX].c_str()) == 0;
248     }
249     uint32_t internal = 200;
250     for (int i = 0; i < times; i++) {
251         ResSchedExeClient::GetInstance().SendDebugCommand(isSync);
252         usleep(internal);
253     }
254 }
255 
DumpAllPluginConfig(std::string &result)256 void ResSchedService::DumpAllPluginConfig(std::string &result)
257 {
258     result.append("================Resource Schedule Plugin Config================\n");
259     PluginMgr::GetInstance().DumpAllPluginConfig(result);
260 }
261 } // namespace ResourceSchedule
262 } // namespace OHOS
263 
264