1 /*
2 * Copyright (c) 2022-2025 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 "ipc_skeleton.h"
23 #include "notifier_mgr.h"
24 #include "plugin_mgr.h"
25 #include "res_sched_errors.h"
26 #include "res_sched_exe_client.h"
27 #include "res_sched_log.h"
28 #include "res_sched_mgr.h"
29 #include "event_listener_mgr.h"
30 #include "hisysevent.h"
31 #include "res_common_util.h"
32 #include "res_sa_init.h"
33 #include "res_sched_hitrace_chain.h"
34
35 namespace OHOS {
36 namespace ResourceSchedule {
37 namespace {
38 #define PAYLOAD_MAX_SIZE 4096
39 static constexpr int32_t DUMP_OPTION = 0;
40 static constexpr int32_t DUMP_PARAM_INDEX = 1;
41 static const int32_t ENG_MODE = OHOS::system::GetIntParameter("const.debuggable", 0);
42 static const char* APP_PRELOAD_PLIGIN_NAME = "libapp_preload_plugin.z.so";
43 static const char* NEEDED_PERMISSION = "ohos.permission.REPORT_RESOURCE_SCHEDULE_EVENT";
44 static const char* SCENEBOARD_BUNDLE_NAME = "com.ohos.sceneboard";
45 static constexpr int32_t MEMMGR_UID = 1111;
46 static constexpr int32_t SAMGR_UID = 5555;
47 static constexpr int32_t FOUNDATION_UID = 5523;
48 static constexpr int32_t GRAPHIC_UID = 1003;
49 static constexpr int32_t HIVIEW_UID = 1201;
50 static constexpr int32_t SINGLE_UID_REQUEST_LIMIT_COUNT = 250;
51 static constexpr int32_t ALL_UID_REQUEST_LIMIT_COUNT = 650;
52 static constexpr int32_t LIMIT_REQUEST_TIME = 1000;
53 static constexpr int64_t FOUR_HOUR_TIME = 4 * 60 * 60 * 1000;
54 #ifdef RESOURCE_SCHEDULE_SERVICE_WITH_EXT_RES_ENABLE
55 static const int32_t DEFAULT_VALUE = -1;
56 static const char* EXT_RES_KEY = "extType";
57 #endif
58 static const std::unordered_set<uint32_t> SCB_RES = {
59 ResType::SYNC_RES_TYPE_THAW_ONE_APP,
60 ResType::RES_TYPE_REPORT_SCENE_BOARD,
61 ResType::RES_TYPE_SHOW_REMOTE_ANIMATION,
62 ResType::RES_TYPE_KEY_PERF_SCENE,
63 ResType::RES_TYPE_MOVE_WINDOW,
64 ResType::RES_TYPE_RESIZE_WINDOW,
65 ResType::RES_TYPE_ONLY_PERF_APP_COLD_START,
66 ResType::RES_TYPE_SCENE_ROTATION,
67 ResType::SYNC_RES_TYPE_CHECK_MUTEX_BEFORE_START,
68 ResType::RES_TYPE_COSMIC_CUBE_STATE_CHANGE,
69 ResType::RES_TYPE_GESTURE_ANIMATION,
70 ResType::RES_TYPE_RAISE_WORKER_THREAD_PRIORITY,
71 ResType::RES_TYPE_RECENT_BUILD,
72 ResType::RES_TYPE_APP_OPT_FROM_RECENT,
73 ResType::RES_TYPE_SWIPE_DIRECTION_UP,
74 ResType::RES_TYPE_WINDOW_PANEL,
75 ResType::RES_TYPE_WINDOW_SPLIT_SCREEN,
76 };
77 static const std::unordered_set<uint32_t> THIRDPART_RES = {
78 ResType::RES_TYPE_CLICK_RECOGNIZE,
79 ResType::RES_TYPE_KEY_EVENT,
80 ResType::RES_TYPE_PUSH_PAGE,
81 ResType::RES_TYPE_SLIDE_RECOGNIZE,
82 ResType::RES_TYPE_POP_PAGE,
83 ResType::RES_TYPE_LOAD_PAGE,
84 ResType::RES_TYPE_WEB_GESTURE,
85 ResType::RES_TYPE_REPORT_KEY_THREAD,
86 ResType::RES_TYPE_REPORT_WINDOW_STATE,
87 ResType::RES_TYPE_REPORT_SCENE_SCHED,
88 ResType::RES_TYPE_WEB_GESTURE_MOVE,
89 ResType::RES_TYPE_WEB_SLIDE_NORMAL,
90 ResType::RES_TYPE_LOAD_URL,
91 ResType::RES_TYPE_MOUSEWHEEL,
92 ResType::RES_TYPE_WEBVIEW_AUDIO_STATUS_CHANGE,
93 ResType::RES_TYPE_REPORT_RENDER_THREAD,
94 ResType::RES_TYPE_LONG_FRAME,
95 ResType::RES_TYPE_REPORT_VSYNC_TID,
96 ResType::RES_TYPE_WEB_DRAG_RESIZE,
97 ResType::RES_TYPE_WEBVIEW_SCREEN_CAPTURE,
98 ResType::RES_TYPE_WEBVIEW_VIDEO_STATUS_CHANGE,
99 ResType::RES_TYPE_BT_SERVICE_EVENT,
100 ResType::RES_TYPE_APP_FRAME_DROP,
101 ResType::RES_TYPE_REPORT_DISTRIBUTE_TID,
102 ResType::RES_TYPE_AXIS_EVENT,
103 ResType::RES_TYPE_CROWN_ROTATION_STATUS,
104 ResType::RES_TYPE_RED_ENVELOPE,
105 ResType::RES_TYPE_RECV_ABC_LOAD_COMPLETED,
106 ResType::RES_TYPE_SET_BACKGROUND_PROCESS_PRIORITY,
107 ResType::RES_TYPE_CHECK_APP_IS_IN_SCHEDULE_LIST,
108 ResType::RES_TYPE_SHORT_TERM_LOAD,
109 ResType::RES_TYPE_PAGE_TRANSITION,
110 ResType::RES_TYPE_VOICE_RECOGNIZE_WAKE,
111 ResType::RES_TYPE_WEB_SLIDE_SCROLL,
112 ResType::RES_TYPE_KEY_PERF_SCENE,
113 ResType::RES_TYPE_ABILITY_OR_PAGE_SWITCH,
114 ResType::RES_TYPE_GC_THREAD_QOS_STATUS_CHANGE,
115 };
116 static const std::unordered_set<uint32_t> FG_THIRDPART_RES = {
117 ResType::RES_TYPE_CLICK_RECOGNIZE,
118 ResType::RES_TYPE_KEY_EVENT,
119 ResType::RES_TYPE_SLIDE_RECOGNIZE,
120 ResType::RES_TYPE_LOAD_URL,
121 ResType::RES_TYPE_MOUSEWHEEL,
122 ResType::RES_TYPE_LONG_FRAME,
123 ResType::RES_TYPE_WEB_DRAG_RESIZE,
124 ResType::RES_TYPE_APP_FRAME_DROP,
125 ResType::RES_TYPE_AXIS_EVENT,
126 ResType::RES_TYPE_WEB_SLIDE_SCROLL,
127 ResType::RES_TYPE_OVERLAY_EVENT,
128 };
129 static const std::unordered_set<uint32_t> SA_RES = {
130 ResType::SYNC_RES_TYPE_THAW_ONE_APP,
131 ResType::SYNC_RES_TYPE_GET_ALL_SUSPEND_STATE,
132 ResType::SYNC_RES_TYPE_GET_THERMAL_DATA,
133 ResType::RES_TYPE_BLUETOOTH_A2DP_CONNECT_STATE_CHANGE,
134 ResType::RES_TYPE_NETWORK_LATENCY_REQUEST,
135 ResType::RES_TYPE_THREAD_QOS_CHANGE,
136 ResType::RES_TYPE_MOVE_WINDOW,
137 ResType::RES_TYPE_ANCO_CUST,
138 ResType::RES_TYPE_SOCPERF_CUST_ACTION,
139 ResType::RES_TYPE_REPORT_SCREEN_CAPTURE,
140 ResType::RES_TYPE_SA_CONTROL_APP_EVENT,
141 ResType::RES_TYPE_UPLOAD_DOWNLOAD,
142 ResType::RES_TYPE_SPLIT_SCREEN,
143 ResType::RES_TYPE_FLOATING_WINDOW,
144 ResType::RES_TYPE_FRAME_RATE_REPORT,
145 ResType::RES_TYPE_REPORT_DISTRIBUTE_COMPONENT_CHANGE,
146 ResType::RES_TYPE_THERMAL_SCENARIO_REPORT,
147 ResType::RES_TYPE_AUDIO_RENDERER_SILENT_PLAYBACK,
148 ResType::RES_TYPE_CLOUD_CONFIG_UPDATE,
149 ResType::RES_TYPE_BT_SERVICE_EVENT,
150 ResType::RES_TYPE_REPORT_BOKER_GATT_CONNECT,
151 ResType::SYNC_RES_TYPE_REQUEST_MUTEX_STATUS,
152 ResType::SYNC_RES_TYPE_GET_NWEB_PRELOAD_SET,
153 ResType::RES_TYPE_AUDIO_RENDERER_STANDBY,
154 ResType::RES_TYPE_DISPLAY_MULTI_SCREEN,
155 ResType::RES_TYPE_INTENT_CTRL_APP,
156 ResType::RES_TYPE_SHORT_TERM_LOAD,
157 ResType::RES_TYPE_DYNAMICALLY_SET_SUSPEND_EXEMPT,
158 ResType::SYNC_RES_TYPE_GET_SUSPEND_STATE_BY_UID,
159 ResType::SYNC_RES_TYPE_GET_SUSPEND_STATE_BY_PID,
160 #ifdef RESSCHED_RESOURCESCHEDULE_FILE_COPY_SOC_PERF_ENABLE
161 ResType::RES_TYPE_FILE_COPY_STATUS,
162 #endif
163 ResType::RES_TYPE_PARAM_UPADTE_EVENT,
164 ResType::RES_TYPE_CAMERA_PRELAUNCH,
165 ResType::RES_TYPE_CAMERA_RESET_PRIORITY,
166 ResType::RES_TYPE_DEVICE_MODE_STATUS,
167 ResType::RES_TYPE_TDP_TURBO,
168 };
169 static const std::unordered_map<uint32_t, std::unordered_set<int32_t>> ALLOW_SOME_UID_REPORT_RES = {
170 { ResType::RES_TYPE_MODEM_PA_HIGH_POWER_ABNORMAL, { 1201 } },
171 { ResType::RES_TYPE_APP_HIGH_POWER_CONSUMPTION, { 1201 } },
172 { ResType::RES_TYPE_APP_ABILITY_START, { 5523 } },
173 { ResType::RES_TYPE_PRELOAD_APPLICATION, { 5523 } },
174 { ResType::RES_TYPE_APP_ASSOCIATED_START, { 5523 } },
175 { ResType::RES_TYPE_REPORT_SCREEN_CAPTURE, { 1013 } },
176 { ResType::RES_TYPE_LOCATION_STATUS_CHANGE, { 1021 } },
177 { ResType::RES_TYPE_SYSTEM_CPU_LOAD, { 1201 } },
178 { ResType::RES_TYPE_FRAME_RATE_REPORT, { 1003 } },
179 { ResType::RES_TYPE_FORM_STATE_CHANGE_EVENT, { 5523 } },
180 { ResType::RES_TYPE_SEND_FRAME_EVENT, { 1003 } },
181 { ResType::RES_TYPE_CLICK_RECOGNIZE, { 6696 } },
182 { ResType::RES_TYPE_REPORT_GAME_SCHED, { 7800 } },
183 { ResType::RES_TYPE_DEVICE_IDLE, { 3051 } },
184 { ResType::RES_TYPE_GAME_INFO_NOTIFY, { 7011 } },
185 { ResType::SYNC_RES_TYPE_SHOULD_FORCE_KILL_PROCESS, { 5523 } },
186 { ResType::RES_TYPE_GET_GAME_SCENE_INFO, { 7800 } },
187 { ResType::RES_TYPE_APP_GAME_BOOST_EVENT, { 7800 } },
188 { ResType::RES_TYPE_FRAME_RATE_REPORT_FROM_RS, { 1003 } },
189 { ResType::RES_TRPE_GAME_SUSPEND_MODE, { 7800 } },
190 { ResType::RES_TYPE_STANDBY_FREEZE_FAILED, { 1201 } },
191 { ResType::RES_TYPE_ADJUST_PROTECTLRU_RECLAIM_RATIO, { 1111 } },
192 };
193 enum SYSTEM_LOAD_LEVEL_DEBUG_DUMP_SIGNAL : int32_t {
194 DEBUG_LEVEL_MINIMUM = 0,
195 DEBUG_LEVEL_MAXIMUM = 7,
196 };
197 }
198
IsThirdPartType(const uint32_t type)199 bool ResSchedService::IsThirdPartType(const uint32_t type)
200 {
201 if (allowAllAppReportRes_.find(type) == allowAllAppReportRes_.end()) {
202 RESSCHED_LOGD("resType:%{public}d not hap app report", type);
203 return false;
204 }
205 if (allowFgAppReportRes_.find(type) != allowFgAppReportRes_.end() &&
206 !ResSchedMgr::GetInstance().IsForegroundApp(IPCSkeleton::GetCallingPid())) {
207 RESSCHED_LOGD("not foreground app");
208 return false;
209 }
210 AccessToken::AccessTokenID tokenId = OHOS::IPCSkeleton::GetCallingTokenID();
211 auto tokenType = Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId);
212 if (tokenType != Security::AccessToken::ATokenTypeEnum::TOKEN_HAP) {
213 RESSCHED_LOGD("not hap app");
214 return false;
215 }
216 return true;
217 }
218
IsSBDResType(uint32_t type)219 bool ResSchedService::IsSBDResType(uint32_t type)
220 {
221 if (allowSCBReportRes_.find(type) == allowSCBReportRes_.end()) {
222 return false;
223 }
224 AccessToken::AccessTokenID tokenId = OHOS::IPCSkeleton::GetCallingTokenID();
225 auto tokenType = Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId);
226 if (tokenType != Security::AccessToken::ATokenTypeEnum::TOKEN_HAP) {
227 return false;
228 }
229 AccessToken::HapTokenInfo callingTokenInfo;
230 AccessToken::AccessTokenKit::GetHapTokenInfo(tokenId, callingTokenInfo);
231 if (callingTokenInfo.bundleName == SCENEBOARD_BUNDLE_NAME) {
232 return true;
233 }
234 RESSCHED_LOGD("%{public}s is not sceneboard bundle name", callingTokenInfo.bundleName.c_str());
235 return false;
236 }
237
IsHasPermission(const uint32_t type,int32_t uid)238 bool ResSchedService::IsHasPermission(const uint32_t type, int32_t uid)
239 {
240 const auto& item = allowSomeSAReportRes_.find(type);
241 if (item != allowSomeSAReportRes_.end()) {
242 if (item->second.find(uid) == item->second.end()) {
243 RESSCHED_LOGE("resType:%{public}d not allow uid:%{public}d report", type, uid);
244 return false;
245 }
246 } else if (allowAllSAReportRes_.find(type) == allowAllSAReportRes_.end()) {
247 RESSCHED_LOGE("resType:%{public}d not sa report", type);
248 return false;
249 }
250 AccessToken::AccessTokenID tokenId = OHOS::IPCSkeleton::GetCallingTokenID();
251 auto tokenType = Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId);
252 if (tokenType != Security::AccessToken::ATokenTypeEnum::TOKEN_NATIVE) {
253 RESSCHED_LOGD("not native sa");
254 return false;
255 }
256 int32_t hasPermission = -1;
257 std::lock_guard<std::mutex> lock(permissionCacheMutex_);
258 if (permissionCache_.get(tokenId, hasPermission)) {
259 return hasPermission == 0;
260 }
261 hasPermission = AccessToken::AccessTokenKit::VerifyAccessToken(tokenId, NEEDED_PERMISSION);
262 permissionCache_.put(tokenId, hasPermission);
263 if (hasPermission != 0) {
264 RESSCHED_LOGE("not have permission");
265 return false;
266 }
267 return true;
268 }
269
StringToJsonObj(const std::string & str)270 nlohmann::json ResSchedService::StringToJsonObj(const std::string& str)
271 {
272 nlohmann::json jsonObj = nlohmann::json::object();
273 if (str.empty()) {
274 return jsonObj;
275 }
276 nlohmann::json jsonTmp = nlohmann::json::parse(str, nullptr, false);
277 if (jsonTmp.is_discarded()) {
278 RESSCHED_LOGE("%{public}s: parse fail, str=%{public}s.", __func__, str.c_str());
279 return jsonObj;
280 }
281 if (!jsonTmp.is_object()) {
282 RESSCHED_LOGD("%{public}s: str=%{public}s is not jsonObj.", __func__, str.c_str());
283 return jsonObj;
284 }
285 return jsonTmp;
286 }
287
288 #ifdef RESOURCE_SCHEDULE_SERVICE_WITH_EXT_RES_ENABLE
GetExtTypeByResPayload(const std::string & payload)289 int32_t ResSchedService::GetExtTypeByResPayload(const std::string& payload)
290 {
291 auto jsonPayload = StringToJsonObj(payload);
292 if (!jsonPayload.contains(EXT_RES_KEY) || !jsonPayload[EXT_RES_KEY].is_string()) {
293 return DEFAULT_VALUE;
294 }
295 int type = DEFAULT_VALUE;
296 if (StrToInt(jsonPayload[EXT_RES_KEY], type)) {
297 return type;
298 } else {
299 return DEFAULT_VALUE;
300 }
301 }
302 #endif
303
ReportData(uint32_t resType,int64_t value,const std::string & payload)304 ErrCode ResSchedService::ReportData(uint32_t resType, int64_t value, const std::string& payload)
305 {
306 ResSchedHiTraceChain traceChain(__func__);
307 int32_t checkResult = RemoteRequestCheck();
308 if (checkResult != ERR_OK) {
309 RESSCHED_LOGD("check remote request fail.");
310 return checkResult;
311 }
312 #ifdef RESOURCE_SCHEDULE_SERVICE_WITH_EXT_RES_ENABLE
313 if (resType == ResType::RES_TYPE_KEY_PERF_SCENE) {
314 int32_t extType = GetExtTypeByResPayload(payload);
315 if (extType != DEFAULT_VALUE) {
316 resType = (uint32_t)extType;
317 }
318 }
319 #endif
320 int32_t callingUid = IPCSkeleton::GetCallingUid();
321 int32_t ret = CheckReportDataParcel(resType, value, payload, callingUid);
322 if (ret != ERR_OK) {
323 RESSCHED_LOGE("%{public}s: check report data parcel fail ret=%{public}d, type=%{public}u.",
324 __func__, ret, resType);
325 return ret;
326 }
327
328 int32_t clientPid = IPCSkeleton::GetCallingPid();
329 RESSCHED_LOGD("ResSchedService receive data from ipc resType: %{public}u, value: %{public}lld, pid: %{public}d",
330 resType, (long long)value, clientPid);
331 nlohmann::json reportDataPayload = StringToJsonObj(payload);
332 reportDataPayload["callingUid"] = std::to_string(callingUid);
333 reportDataPayload["clientPid"] = std::to_string(clientPid);
334 ResSchedMgr::GetInstance().ReportData(resType, value, reportDataPayload);
335 ResSchedIpcThread::GetInstance().SetQos(clientPid);
336 return ERR_OK;
337 }
338
ReportSyncEvent(const uint32_t resType,const int64_t value,const std::string & payload,std::string & reply,int32_t & resultValue)339 ErrCode ResSchedService::ReportSyncEvent(const uint32_t resType, const int64_t value, const std::string& payload,
340 std::string& reply, int32_t& resultValue)
341 {
342 ResSchedHiTraceChain traceChain(__func__);
343 int32_t checkResult = RemoteRequestCheck();
344 if (checkResult != ERR_OK) {
345 RESSCHED_LOGD("check remote request fail.");
346 resultValue = checkResult;
347 return ERR_OK;
348 }
349 int32_t callingUid = IPCSkeleton::GetCallingUid();
350 int32_t ret = CheckReportDataParcel(resType, value, payload, callingUid);
351 if (ret != ERR_OK) {
352 RESSCHED_LOGE("%{public}s: check report data parcel fail ret=%{public}d, type=%{public}u.",
353 __func__, ret, resType);
354 resultValue = ret;
355 return ERR_OK;
356 }
357 nlohmann::json payloadJsonValue;
358 nlohmann::json replyValue;
359 payloadJsonValue = StringToJsonObj(payload);
360 int32_t clientPid = IPCSkeleton::GetCallingPid();
361 payloadJsonValue["clientPid"] = std::to_string(clientPid);
362 payloadJsonValue["callingUid"] = std::to_string(callingUid);
363 resultValue = PluginMgr::GetInstance().DeliverResource(
364 std::make_shared<ResData>(resType, value, payloadJsonValue, replyValue));
365 reply = replyValue.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace);
366 ResSchedIpcThread::GetInstance().SetQos(clientPid);
367 return ERR_OK;
368 }
369
KillProcess(const std::string & payload,int32_t & resultValue)370 ErrCode ResSchedService::KillProcess(const std::string& payload, int32_t& resultValue)
371 {
372 uint32_t accessToken = IPCSkeleton::GetCallingTokenID();
373 int32_t uid = IPCSkeleton::GetCallingUid();
374 Security::AccessToken::ATokenTypeEnum tokenTypeFlag =
375 Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(accessToken);
376 if ((uid != MEMMGR_UID && uid != SAMGR_UID && uid != HIVIEW_UID && uid != GRAPHIC_UID)
377 || tokenTypeFlag != Security::AccessToken::ATokenTypeEnum::TOKEN_NATIVE) {
378 RESSCHED_LOGE("no permission, kill process fail");
379 resultValue = RES_SCHED_KILL_PROCESS_FAIL;
380 return ERR_OK;
381 }
382
383 if (payload.size() > PAYLOAD_MAX_SIZE) {
384 RESSCHED_LOGE("The payload is too long. DoS.");
385 resultValue = RES_SCHED_KILL_PROCESS_FAIL;
386 return ERR_OK;
387 }
388
389 resultValue = ResSchedMgr::GetInstance().KillProcessByClient(StringToJsonObj(payload));
390 return ERR_OK;
391 }
392
RegisterSystemloadNotifier(const sptr<IRemoteObject> & notifier)393 ErrCode ResSchedService::RegisterSystemloadNotifier(const sptr<IRemoteObject>& notifier)
394 {
395 if (notifier == nullptr) {
396 RESSCHED_LOGE("ResSchedService notifier is nullptr.");
397 return RES_SCHED_DATA_ERROR;
398 }
399
400 NotifierMgr::GetInstance().RegisterNotifier(IPCSkeleton::GetCallingPid(), notifier);
401 return ERR_OK;
402 }
403
UnRegisterSystemloadNotifier()404 ErrCode ResSchedService::UnRegisterSystemloadNotifier()
405 {
406 NotifierMgr::GetInstance().UnRegisterNotifier(IPCSkeleton::GetCallingPid());
407 return ERR_OK;
408 }
409
RegisterEventListener(const sptr<IRemoteObject> & eventListener,uint32_t eventType,uint32_t listenerGroup)410 ErrCode ResSchedService::RegisterEventListener(const sptr<IRemoteObject>& eventListener, uint32_t eventType,
411 uint32_t listenerGroup)
412 {
413 EventListenerMgr::GetInstance().RegisterEventListener(IPCSkeleton::GetCallingPid(), eventListener, eventType,
414 listenerGroup);
415 return ERR_OK;
416 }
417
UnRegisterEventListener(uint32_t eventType,uint32_t listenerGroup)418 ErrCode ResSchedService::UnRegisterEventListener(uint32_t eventType, uint32_t listenerGroup)
419 {
420 EventListenerMgr::GetInstance().UnRegisterEventListener(IPCSkeleton::GetCallingPid(), eventType, listenerGroup);
421 return ERR_OK;
422 }
423
GetSystemloadLevel(int32_t & resultValue)424 ErrCode ResSchedService::GetSystemloadLevel(int32_t& resultValue)
425 {
426 if (systemLoadLevelDebugEnable_) {
427 resultValue = debugSystemLoadLevel_;
428 } else {
429 resultValue = NotifierMgr::GetInstance().GetSystemloadLevel();
430 }
431 return ERR_OK;
432 }
433
GetResTypeList(std::set<uint32_t> & resTypeList)434 ErrCode ResSchedService::GetResTypeList(std::set<uint32_t>& resTypeList)
435 {
436 PluginMgr::GetInstance().GetResTypeList(resTypeList);
437 return ERR_OK;
438 }
439
OnDeviceLevelChanged(int32_t type,int32_t level,bool debugReport)440 void ResSchedService::OnDeviceLevelChanged(int32_t type, int32_t level, bool debugReport)
441 {
442 if (type == static_cast<int32_t>(ResType::DeviceStatus::SYSTEMLOAD_LEVEL)) {
443 if (!debugReport) {
444 actualSystemLoadLevel_ = level;
445 }
446 if (systemLoadLevelDebugEnable_) {
447 level = debugSystemLoadLevel_;
448 }
449 }
450 NotifierMgr::GetInstance().OnDeviceLevelChanged(type, level);
451 }
452
IsAllowedAppPreload(const std::string & bundleName,int32_t preloadMode,bool & resultValue)453 ErrCode ResSchedService::IsAllowedAppPreload(const std::string& bundleName, int32_t preloadMode, bool& resultValue)
454 {
455 AccessToken::AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
456 int32_t uid = IPCSkeleton::GetCallingUid();
457 AccessToken::ATokenTypeEnum tokenTypeFlag = AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId);
458 if (uid != FOUNDATION_UID || tokenTypeFlag != AccessToken::ATokenTypeEnum::TOKEN_NATIVE) {
459 RESSCHED_LOGE("Invalid calling token");
460 resultValue = false;
461 return ERR_OK;
462 }
463
464 LoadAppPreloadPlugin();
465 if (!appPreloadFunc_) {
466 RESSCHED_LOGE("%{public}s, no allow AppPreload !", __func__);
467 resultValue = false;
468 return ERR_OK;
469 }
470 resultValue = appPreloadFunc_(bundleName, preloadMode);
471 return ERR_OK;
472 }
473
LoadAppPreloadPlugin()474 void ResSchedService::LoadAppPreloadPlugin()
475 {
476 std::shared_ptr<PluginLib> libInfoPtr = PluginMgr::GetInstance().GetPluginLib(APP_PRELOAD_PLIGIN_NAME);
477 if (libInfoPtr == nullptr) {
478 RESSCHED_LOGE("ResSchedService::LoadAppPreloadPlugin libInfoPtr nullptr");
479 isLoadAppPreloadPlugin_ = false;
480 return;
481 }
482
483 if (isLoadAppPreloadPlugin_) {
484 return;
485 }
486
487 appPreloadFunc_ = reinterpret_cast<OnIsAllowedAppPreloadFunc>(dlsym(libInfoPtr->handle.get(),
488 "OnIsAllowedAppPreload"));
489 isLoadAppPreloadPlugin_ = true;
490 }
491
IsAllowedLinkJump(bool isAllowedLinkJump,int32_t & resultValue)492 ErrCode ResSchedService::IsAllowedLinkJump(bool isAllowedLinkJump, int32_t& resultValue)
493 {
494 AccessToken::AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
495 AccessToken::ATokenTypeEnum tokenTypeFlag = AccessToken::AccessTokenKit::GetTokenTypeFlag(tokenId);
496 if (tokenTypeFlag != AccessToken::ATokenTypeEnum::TOKEN_HAP) {
497 RESSCHED_LOGE("Invalid calling token");
498 resultValue = RES_SCHED_ACCESS_TOKEN_FAIL;
499 return ERR_OK;
500 }
501
502 AccessToken::HapTokenInfo callingTokenInfo;
503 AccessToken::AccessTokenKit::GetHapTokenInfo(tokenId, callingTokenInfo);
504 std::string callingBundleName = callingTokenInfo.bundleName;
505 if (!PluginMgr::GetInstance().GetLinkJumpOptConfig(callingBundleName, isAllowedLinkJump)) {
506 RESSCHED_LOGE("Invalid callingBundleName");
507 resultValue = ERR_RES_SCHED_INVALID_PARAM;
508 return ERR_OK;
509 }
510 resultValue = ERR_OK;
511 return ERR_OK;
512 }
513
CheckDumpPermission()514 bool ResSchedService::CheckDumpPermission()
515 {
516 Security::AccessToken::AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
517 int32_t ret = Security::AccessToken::AccessTokenKit::VerifyAccessToken(tokenId, "ohos.permission.DUMP");
518 if (ret != Security::AccessToken::PermissionState::PERMISSION_GRANTED) {
519 RESSCHED_LOGE("CheckPermission failed");
520 return false;
521 }
522 return true;
523 }
524
CheckENGMode()525 bool ResSchedService::CheckENGMode()
526 {
527 if (ENG_MODE == 0) {
528 RESSCHED_LOGE("Not eng mode");
529 return false;
530 }
531 return true;
532 }
533
Dump(int32_t fd,const std::vector<std::u16string> & args)534 int32_t ResSchedService::Dump(int32_t fd, const std::vector<std::u16string>& args)
535 {
536 std::vector<std::string> argsInStr;
537 std::transform(args.begin(), args.end(), std::back_inserter(argsInStr),
538 [](const std::u16string &arg) {
539 std::string ret = Str16ToStr8(arg);
540 RESSCHED_LOGI("%{public}s arg: %{public}s.", __func__, ret.c_str());
541 return ret;
542 });
543 #ifdef SET_SYSTEM_LOAD_LEVEL_2D_ENABLE
544 if (!CheckDumpPermission() ||
545 (!CheckENGMode() && argsInStr.size() > 0 && argsInStr[DUMP_OPTION] != "setSystemLoadLevel")) {
546 return ERR_RES_SCHED_PERMISSION_DENIED;
547 }
548 #else
549 if (!CheckDumpPermission() || !CheckENGMode()) {
550 return ERR_RES_SCHED_PERMISSION_DENIED;
551 }
552 #endif //SET_SYSTEM_LOAD_LEVEL_2D_ENABLE
553 RESSCHED_LOGI("%{public}s Dump service.", __func__);
554 std::string result;
555 if (argsInStr.size() == 0) {
556 // hidumper -s said '-h'
557 DumpUsage(result);
558 } else if (argsInStr.size() == DUMP_OPTION + 1) {
559 // hidumper -s said '-h' or hidumper -s said '-a'
560 DumpExt(argsInStr, result);
561 } else if (argsInStr.size() >= DUMP_PARAM_INDEX + 1) {
562 if (argsInStr[DUMP_OPTION] == "-p") {
563 std::vector<std::string> argsInStrToPlugin;
564 argsInStrToPlugin.assign(argsInStr.begin() + DUMP_PARAM_INDEX + 1, argsInStr.end());
565 PluginMgr::GetInstance().DumpOnePlugin(result, argsInStr[DUMP_PARAM_INDEX], argsInStrToPlugin);
566 } else if (argsInStr[DUMP_OPTION] == "sendDebugToExecutor") {
567 DumpExecutorDebugCommand(argsInStr, result);
568 } else if (argsInStr[DUMP_OPTION] == "setSystemLoadLevel") {
569 DumpSetSystemLoad(argsInStr, result);
570 }
571 }
572
573 if (!SaveStringToFd(fd, result)) {
574 RESSCHED_LOGE("%{public}s save to fd failed.", __func__);
575 }
576 return ERR_OK;
577 }
578
579
DumpExt(const std::vector<std::string> & argsInStr,std::string & result)580 void ResSchedService::DumpExt(const std::vector<std::string>& argsInStr, std::string &result)
581 {
582 if (argsInStr[DUMP_OPTION] == "-h") {
583 DumpUsage(result);
584 } else if (argsInStr[DUMP_OPTION] == "-a") {
585 DumpAllInfo(result);
586 } else if (argsInStr[DUMP_OPTION] == "-p") {
587 PluginMgr::GetInstance().DumpAllPlugin(result);
588 } else if (argsInStr[DUMP_OPTION] == "getSystemloadInfo") {
589 DumpSystemLoadInfo(result);
590 } else if (argsInStr[DUMP_OPTION] == "sendDebugToExecutor") {
591 DumpExecutorDebugCommand(argsInStr, result);
592 } else if (argsInStr[DUMP_OPTION] == "PluginConfig") {
593 DumpAllPluginConfig(result);
594 } else {
595 result.append("Error params.");
596 }
597 }
598
DumpSystemLoadInfo(std::string & result)599 void ResSchedService::DumpSystemLoadInfo(std::string &result)
600 {
601 result.append("systemloadLevel:")
602 .append(ToString(NotifierMgr::GetInstance().GetSystemloadLevel()))
603 .append("\n");
604 auto notifierInfo = NotifierMgr::GetInstance().DumpRegisterInfo();
605 std::string native("natives:");
606 std::string hap("apps:");
607 for (auto& info : notifierInfo) {
608 std::string str = ToString(info.first).append(" ");
609 if (info.second) {
610 hap.append(str);
611 } else {
612 native.append(str);
613 }
614 }
615 hap.append("\n");
616 native.append("\n");
617 result.append(native).append(hap);
618 }
619
DumpUsage(std::string & result)620 void ResSchedService::DumpUsage(std::string &result)
621 {
622 result.append("usage: resource schedule service dump [<options>]\n")
623 .append(" -h: show the help.\n")
624 .append(" -a: show all info.\n")
625 .append(" -p: show the all plugin info.\n")
626 .append(" -p (plugin name): show one plugin info.\n");
627 PluginMgr::GetInstance().DumpHelpFromPlugin(result);
628 }
629
DumpAllInfo(std::string & result)630 void ResSchedService::DumpAllInfo(std::string &result)
631 {
632 result.append("================Resource Schedule Service Infos================\n");
633 PluginMgr::GetInstance().DumpAllPlugin(result);
634 }
635
DumpExecutorDebugCommand(const std::vector<std::string> & args,std::string & result)636 void ResSchedService::DumpExecutorDebugCommand(const std::vector<std::string>& args, std::string& result)
637 {
638 // hidumper -s said 'sendDebugToExecutor [isSync times]' isSync - 0/1(default 0), times - 1~...(default 1)
639 result.append("Send debug command to resource_schedule_executor.\n");
640 bool isSync = true;
641 int times = 1;
642 if (args.size() > DUMP_PARAM_INDEX + 1) {
643 int arg = atoi(args[DUMP_PARAM_INDEX + 1].c_str());
644 times = arg > 0 ? arg : times;
645 }
646 if (args.size() > DUMP_PARAM_INDEX) {
647 isSync = atoi(args[DUMP_PARAM_INDEX].c_str()) == 0;
648 }
649 uint32_t internal = 200;
650 for (int i = 0; i < times; i++) {
651 ResSchedExeClient::GetInstance().SendDebugCommand(isSync);
652 usleep(internal);
653 }
654 }
655
DumpSetSystemLoad(const std::vector<std::string> & args,std::string & result)656 void ResSchedService::DumpSetSystemLoad(const std::vector<std::string>& args, std::string& result)
657 {
658 //hidumper -s 1901 -a "setSystemLoadLevel (LevelNum/reset)"
659 if (args.size() == DUMP_PARAM_INDEX + 1) {
660 const std::string& switchStr = args[DUMP_PARAM_INDEX];
661 if (switchStr == "reset") {
662 systemLoadLevelDebugEnable_ = false;
663 debugSystemLoadLevel_ = 0;
664 result.append("Set SystemLoad Close\n");
665 OnDeviceLevelChanged(ResType::DeviceStatus::SYSTEMLOAD_LEVEL, actualSystemLoadLevel_, false);
666 return;
667 }
668 int32_t switchInfo;
669 if (!StrToInt(switchStr, switchInfo)) {
670 result.append("Err setSystemLoadLevel param. Please insert 0-7 to start debug, \"reset\" to close debug");
671 return;
672 }
673 if (switchInfo <= SYSTEM_LOAD_LEVEL_DEBUG_DUMP_SIGNAL::DEBUG_LEVEL_MAXIMUM &&
674 switchInfo >= SYSTEM_LOAD_LEVEL_DEBUG_DUMP_SIGNAL::DEBUG_LEVEL_MINIMUM) {
675 systemLoadLevelDebugEnable_ = true;
676 debugSystemLoadLevel_ = switchInfo;
677 result.append("setSystemLoadLevel Debug On with Level: ").append(ToString(switchInfo)).append("\n");
678 OnDeviceLevelChanged(ResType::DeviceStatus::SYSTEMLOAD_LEVEL, debugSystemLoadLevel_, true);
679 } else {
680 result.append("Err setSystemLoadLevel param. Please insert 0-7 to start debug, \"reset\" to close debug");
681 }
682 return;
683 }
684 result.append("Err setSystemLoadLevel param num. Please insert one param after \"setSystemLoadLevel\"");
685 }
686
DumpAllPluginConfig(std::string & result)687 void ResSchedService::DumpAllPluginConfig(std::string &result)
688 {
689 result.append("================Resource Schedule Plugin Config================\n");
690 PluginMgr::GetInstance().DumpAllPluginConfig(result);
691 }
692
CheckReportDataParcel(const uint32_t & type,const int64_t & value,const std::string & payload,int32_t uid)693 int32_t ResSchedService::CheckReportDataParcel(const uint32_t& type, const int64_t& value,
694 const std::string& payload, int32_t uid)
695 {
696 if (!IsSBDResType(type) && !IsThirdPartType(type) && !IsHasPermission(type, uid)) {
697 RESSCHED_LOGD("type:%{public}u, no permission", type);
698 return ERR_RES_SCHED_PERMISSION_DENIED;
699 }
700
701 if (payload.size() > PAYLOAD_MAX_SIZE) {
702 RESSCHED_LOGE("too long payload.size:%{public}u", (uint32_t)payload.size());
703 return ERR_RES_SCHED_PARCEL_ERROR;
704 }
705 return ERR_OK;
706 }
707
PrintLimitLog(int32_t uid)708 void ResSchedService::PrintLimitLog(int32_t uid)
709 {
710 if (isPrintLimitLog_.load()) {
711 isPrintLimitLog_.store(false);
712 RESSCHED_LOGI("request limit, allRequestCount_:%{public}d, cur report uid:%{public}d",
713 allRequestCount_.load(), uid);
714 }
715 }
716
ReportBigData()717 void ResSchedService::ReportBigData()
718 {
719 if (!isReportBigData_.load()) {
720 return;
721 }
722 if (ResCommonUtil::GetNowMillTime(true) < nextReportBigDataTime_) {
723 return;
724 }
725 HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::RSS, "SERVICE_REQUEST_LIMIT",
726 HiviewDFX::HiSysEvent::EventType::FAULT, "REQUEST_LIMIT_COUNT", bigDataReportCount_.load());
727 isReportBigData_.store(false);
728 bigDataReportCount_.store(0);
729 }
730
InreaseBigDataCount()731 void ResSchedService::InreaseBigDataCount()
732 {
733 if (!isReportBigData_.load()) {
734 isReportBigData_.store(true);
735 nextReportBigDataTime_ = ResCommonUtil::GetNowMillTime(true) + FOUR_HOUR_TIME;
736 }
737 bigDataReportCount_.fetch_add(1, std::memory_order_relaxed);
738 }
739
IsLimitRequest(int32_t uid)740 bool ResSchedService::IsLimitRequest(int32_t uid)
741 {
742 std::lock_guard<std::mutex> lock(mutex_);
743 int64_t nowTime = ResCommonUtil::GetNowMillTime(true);
744 CheckAndUpdateLimitData(nowTime);
745 if (allRequestCount_.load() >= ALL_UID_REQUEST_LIMIT_COUNT) {
746 RESSCHED_LOGD("all uid request is limit, %{public}d request fail", uid);
747 return true;
748 }
749 auto iter = appRequestCountMap_.find(uid);
750 if (iter == appRequestCountMap_.end()) {
751 appRequestCountMap_[uid] = 1;
752 allRequestCount_.fetch_add(1, std::memory_order_relaxed);
753 return false;
754 }
755 if (appRequestCountMap_[uid] >= SINGLE_UID_REQUEST_LIMIT_COUNT) {
756 RESSCHED_LOGD("uid:%{public}d request is limit, request fail", uid);
757 return true;
758 }
759 appRequestCountMap_[uid] ++;
760 allRequestCount_.fetch_add(1, std::memory_order_relaxed);
761 return false;
762 }
763
CheckAndUpdateLimitData(int64_t nowTime)764 void ResSchedService::CheckAndUpdateLimitData(int64_t nowTime)
765 {
766 if (nowTime - nextCheckTime_.load() >= 0) {
767 nextCheckTime_.store(nowTime + LIMIT_REQUEST_TIME);
768 appRequestCountMap_.clear();
769 allRequestCount_.store(0);
770 isPrintLimitLog_.store(true);
771 }
772 }
773
RemoteRequestCheck()774 int32_t ResSchedService::RemoteRequestCheck()
775 {
776 ReportBigData();
777 auto uid = IPCSkeleton::GetCallingUid();
778 if (IsLimitRequest(uid)) {
779 RESSCHED_LOGD("%{public}d is limit request, cur request fail", uid);
780 InreaseBigDataCount();
781 PrintLimitLog(uid);
782 return RES_SCHED_REQUEST_FAIL;
783 }
784 return ERR_OK;
785 }
786
InitAllowIpcReportRes()787 void ResSchedService::InitAllowIpcReportRes()
788 {
789 AddSCBRes(SCB_RES);
790 AddAllSARes(SA_RES);
791 AddSomeSARes(ALLOW_SOME_UID_REPORT_RES);
792 AddAllAppRes(THIRDPART_RES);
793 AddFgAppRes(FG_THIRDPART_RES);
794 AddSCBRes(ResSchedMgr::GetInstance().GetAllowSCBReportResExt());
795 AddAllSARes(ResSchedMgr::GetInstance().GetAllowAllSAReportResExt());
796 AddSomeSARes(ResSchedMgr::GetInstance().GetAllowSomeSAReportResExt());
797 AddAllAppRes(ResSchedMgr::GetInstance().GetAllowAllAppReportResExt());
798 AddFgAppRes(ResSchedMgr::GetInstance().GetAllowFgAppReportResExt());
799 }
800
801 template <typename T>
AddAll(T & to,const T & from)802 inline void AddAll(T& to, const T& from)
803 {
804 if (!from.empty()) {
805 to.insert(from.begin(), from.end());
806 }
807 }
808
AddSCBRes(const std::unordered_set<uint32_t> & allowSCBReportRes)809 void ResSchedService::AddSCBRes(const std::unordered_set<uint32_t>& allowSCBReportRes)
810 {
811 AddAll(allowSCBReportRes_, allowSCBReportRes);
812 }
813
AddAllSARes(const std::unordered_set<uint32_t> & allowAllSAReportRes)814 void ResSchedService::AddAllSARes(const std::unordered_set<uint32_t>& allowAllSAReportRes)
815 {
816 AddAll(allowAllSAReportRes_, allowAllSAReportRes);
817 }
818
AddSomeSARes(const std::unordered_map<uint32_t,std::unordered_set<int32_t>> & allowSomeSAReportRes)819 void ResSchedService::AddSomeSARes(const std::unordered_map<uint32_t, std::unordered_set<int32_t>>&
820 allowSomeSAReportRes)
821 {
822 AddAll(allowSomeSAReportRes_, allowSomeSAReportRes);
823 }
AddAllAppRes(const std::unordered_set<uint32_t> & allowAllAppReportRes)824 void ResSchedService::AddAllAppRes(const std::unordered_set<uint32_t>& allowAllAppReportRes)
825 {
826 AddAll(allowAllAppReportRes_, allowAllAppReportRes);
827 }
AddFgAppRes(const std::unordered_set<uint32_t> & allowFgAppReportRes)828 void ResSchedService::AddFgAppRes(const std::unordered_set<uint32_t>& allowFgAppReportRes)
829 {
830 AddAll(allowFgAppReportRes_, allowFgAppReportRes);
831 }
832 } // namespace ResourceSchedule
833 } // namespace OHOS
834
835