• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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