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 #include "res_sched_client.h"
16 #include <string> // for to_string
17 #include <unistd.h> // for getpid
18 #include <new> // for nothrow, operator new
19 #include <unordered_map> // for unordered_map, __hash_map_con...
20 #include <utility> // for pair
21 #include "if_system_ability_manager.h" // for ISystemAbilityManager
22 #include "iremote_broker.h" // for iface_cast
23 #include "iservice_registry.h" // for SystemAbilityManagerClient
24 #include "res_sched_errors.h" // for GET_RES_SCHED_SERVICE_FAILED
25 #include "res_sched_log.h" // for RESSCHED_LOGE, RESSCHED_LOGD
26 #include "system_ability_definition.h" // for RES_SCHED_SYS_ABILITY_ID
27 #include "ffrt_inner.h" // for future
28
29 namespace OHOS {
30 namespace ResourceSchedule {
31 namespace {
32 constexpr int32_t CHECK_MUTEX_TIMEOUT = 500; // 500ms
33 bool g_isDestroyed = false;
34 }
35
GetInstance()36 ResSchedClient& ResSchedClient::GetInstance()
37 {
38 static ResSchedClient instance;
39 return instance;
40 }
~ResSchedClient()41 ResSchedClient::~ResSchedClient()
42 {
43 std::lock_guard<std::mutex> lock(mutex_);
44 g_isDestroyed = true;
45 if (rss_ && rss_->AsObject()) {
46 rss_->AsObject()->RemoveDeathRecipient(recipient_);
47 }
48 rss_ = nullptr;
49 systemloadCbRegistered_ = false;
50 registeredInnerEvents.clear();
51 }
52
StringToJsonObj(const std::string & str)53 nlohmann::json StringToJsonObj(const std::string& str)
54 {
55 nlohmann::json jsonObj = nlohmann::json::object();
56 if (str.empty()) {
57 return jsonObj;
58 }
59 nlohmann::json jsonTmp = nlohmann::json::parse(str, nullptr, false);
60 if (jsonTmp.is_discarded()) {
61 RESSCHED_LOGE("%{public}s: parse fail, str=%{public}s.", __func__, str.c_str());
62 return jsonObj;
63 }
64 if (!jsonTmp.is_object()) {
65 RESSCHED_LOGD("%{public}s: str=%{public}s is not jsonObj.", __func__, str.c_str());
66 return jsonObj;
67 }
68 return jsonTmp;
69 }
70
ReportData(uint32_t resType,int64_t value,const std::unordered_map<std::string,std::string> & mapPayload)71 void ResSchedClient::ReportData(uint32_t resType, int64_t value,
72 const std::unordered_map<std::string, std::string>& mapPayload)
73 {
74 if (TryConnect() != ERR_OK) {
75 return;
76 }
77 RESSCHED_LOGD("ResSchedClient::ReportData receive resType = %{public}u, value = %{public}lld.",
78 resType, (long long)value);
79 nlohmann::json payload;
80 for (auto it = mapPayload.begin(); it != mapPayload.end(); ++it) {
81 payload[it->first] = it->second;
82 }
83 std::lock_guard<std::mutex> lock(mutex_);
84 if (rss_ == nullptr) {
85 RESSCHED_LOGD("ResSchedClient::ReportData fail to get resource schedule service.");
86 return;
87 }
88 rss_->ReportData(resType, value, payload.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace));
89 }
90
ReportSyncEvent(const uint32_t resType,const int64_t value,const nlohmann::json & payload,nlohmann::json & reply)91 int32_t ResSchedClient::ReportSyncEvent(const uint32_t resType, const int64_t value, const nlohmann::json& payload,
92 nlohmann::json& reply)
93 {
94 RESSCHED_LOGD("%{public}s: resType=%{public}u, value=%{public}lld.", __func__, resType, (long long)value);
95
96 sptr<IResSchedService> proxy = GetProxy();
97 if (proxy == nullptr) {
98 RESSCHED_LOGD("%{public}s: fail to get rss.", __func__);
99 return RES_SCHED_CONNECT_FAIL;
100 }
101 std::string payloadValue = payload.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace);
102 if (resType == ResType::SYNC_RES_TYPE_CHECK_MUTEX_BEFORE_START) {
103 ffrt::future<std::pair<int32_t, nlohmann::json>> fut = ffrt::async([resType, value, payloadValue, proxy] {
104 nlohmann::json ffrtReply;
105 std::string replyValue;
106 if (proxy == nullptr) {
107 return std::pair<int32_t, nlohmann::json>(RES_SCHED_CONNECT_FAIL, ffrtReply);
108 }
109 int32_t ret;
110 proxy->ReportSyncEvent(resType, value, payloadValue, replyValue, ret);
111 ffrtReply = StringToJsonObj(replyValue);
112 return std::pair<int32_t, nlohmann::json>(ret, ffrtReply);
113 });
114
115 ffrt::future_status status = fut.wait_for(std::chrono::milliseconds(CHECK_MUTEX_TIMEOUT));
116 if (status == ffrt::future_status::ready) {
117 auto result = fut.get();
118 reply = std::move(result.second);
119 return result.first;
120 }
121 RESSCHED_LOGW("%{public}s: sync time out", __func__);
122 return RES_SCHED_REQUEST_FAIL;
123 } else {
124 int32_t ret;
125 std::string replyValue;
126 proxy->ReportSyncEvent(resType, value, payloadValue, replyValue, ret);
127 reply = StringToJsonObj(replyValue);
128 return ret;
129 }
130 }
131
ReportSyncEvent(const uint32_t resType,const int64_t value,const std::unordered_map<std::string,std::string> & payload,std::unordered_map<std::string,std::string> & reply)132 int32_t ResSchedClient::ReportSyncEvent(const uint32_t resType, const int64_t value,
133 const std::unordered_map<std::string, std::string>& payload, std::unordered_map<std::string, std::string>& reply)
134 {
135 nlohmann::json tmpPayload;
136 nlohmann::json tmpReply;
137 for (auto it = payload.begin(); it != payload.end(); ++it) {
138 tmpPayload[it->first] = it->second;
139 }
140 auto res = ReportSyncEvent(resType, value, tmpPayload, tmpReply);
141 for (const auto& pair : tmpReply.items()) {
142 reply[pair.key()] = pair.value().dump();
143 }
144 return res;
145 }
146
KillProcess(const std::unordered_map<std::string,std::string> & mapPayload)147 int32_t ResSchedClient::KillProcess(const std::unordered_map<std::string, std::string>& mapPayload)
148 {
149 RESSCHED_LOGD("ResSchedClient::KillProcess receive mission.");
150 nlohmann::json payload;
151 for (auto it = mapPayload.begin(); it != mapPayload.end(); ++it) {
152 payload[it->first] = it->second;
153 }
154 sptr<IResSchedService> proxy = GetProxy();
155 if (proxy == nullptr) {
156 RESSCHED_LOGD("ResSchedClient::KillProcess fail to get resource schedule service.");
157 return RES_SCHED_KILL_PROCESS_FAIL;
158 }
159 int32_t ret;
160 proxy->KillProcess(payload.dump(-1, ' ', false, nlohmann::detail::error_handler_t::replace), ret);
161 return ret;
162 }
163
RegisterSystemloadNotifier(const sptr<ResSchedSystemloadNotifierClient> & callbackObj)164 void ResSchedClient::RegisterSystemloadNotifier(const sptr<ResSchedSystemloadNotifierClient>& callbackObj)
165 {
166 RESSCHED_LOGD("ResSchedClient::RegisterSystemloadNotifier receive mission.");
167 std::lock_guard<std::mutex> lock(mutex_);
168 if (InitSystemloadListenersLocked() != ERR_OK) {
169 RESSCHED_LOGE("ResSchedClient::RegisterSystemloadNotifier init listener failed.");
170 return;
171 }
172 systemloadLevelListener_->RegisterSystemloadLevelCb(callbackObj);
173 if (!systemloadCbRegistered_ && !systemloadLevelListener_->IsSystemloadCbArrayEmpty() && rss_) {
174 rss_->RegisterSystemloadNotifier(systemloadLevelListener_);
175 systemloadCbRegistered_ = true;
176 }
177 AddResSaListenerLocked();
178 }
179
UnRegisterSystemloadNotifier(const sptr<ResSchedSystemloadNotifierClient> & callbackObj)180 void ResSchedClient::UnRegisterSystemloadNotifier(const sptr<ResSchedSystemloadNotifierClient>& callbackObj)
181 {
182 RESSCHED_LOGD("ResSchedClient::UnRegisterSystemloadNotifier receive mission.");
183 std::lock_guard<std::mutex> lock(mutex_);
184 if (systemloadLevelListener_ == nullptr) {
185 RESSCHED_LOGE("ResSchedClient::UnRegisterSystemloadNotifier systemloadLevelListener is null.");
186 return;
187 }
188 systemloadLevelListener_->UnRegisterSystemloadLevelCb(callbackObj);
189 UnRegisterSystemloadListenersLocked();
190 }
191
RegisterEventListener(const sptr<ResSchedEventListener> & eventListener,uint32_t eventType,uint32_t listenerGroup)192 void ResSchedClient::RegisterEventListener(const sptr<ResSchedEventListener>& eventListener,
193 uint32_t eventType, uint32_t listenerGroup)
194 {
195 RESSCHED_LOGD("%{public}s:receive mission.", __func__);
196 std::lock_guard<std::mutex> lock(mutex_);
197 if (InitInnerEventListenerLocked() != ERR_OK) {
198 RESSCHED_LOGE("ResSchedClient::RegisterEventListener init listener failed.");
199 return;
200 }
201 innerEventListener_->RegisterEventListener(eventListener, eventType, listenerGroup);
202 auto item = registeredInnerEvents.find(eventType);
203 if ((item == registeredInnerEvents.end() || item->second.count(listenerGroup) == 0) &&
204 !innerEventListener_->IsInnerEventMapEmpty(eventType, listenerGroup) && rss_) {
205 rss_->RegisterEventListener(innerEventListener_, eventType, listenerGroup);
206 if (item == registeredInnerEvents.end()) {
207 registeredInnerEvents.emplace(eventType, std::unordered_set<uint32_t>());
208 }
209 registeredInnerEvents[eventType].insert(listenerGroup);
210 }
211 AddResSaListenerLocked();
212 }
213
UnRegisterEventListener(const sptr<ResSchedEventListener> & eventListener,uint32_t eventType,uint32_t listenerGroup)214 void ResSchedClient::UnRegisterEventListener(const sptr<ResSchedEventListener>& eventListener,
215 uint32_t eventType, uint32_t listenerGroup)
216 {
217 RESSCHED_LOGD("%{public}s:receive mission.", __func__);
218 std::lock_guard<std::mutex> lock(mutex_);
219 if (innerEventListener_ == nullptr) {
220 RESSCHED_LOGE("%{public}s: innerEventListener_ is null.", __func__);
221 return;
222 }
223 innerEventListener_->UnRegisterEventListener(eventListener, eventType, listenerGroup);
224 UnRegisterEventListenerLocked(eventType, listenerGroup);
225 }
226
GetSystemloadLevel()227 int32_t ResSchedClient::GetSystemloadLevel()
228 {
229 if (TryConnect() != ERR_OK) {
230 return RES_SCHED_CONNECT_FAIL;
231 }
232 RESSCHED_LOGD("ResSchedClient::GetSystemloadLevel receive mission.");
233
234 std::lock_guard<std::mutex> lock(mutex_);
235 if (rss_ == nullptr) {
236 RESSCHED_LOGE("ResSchedClient::GetSystemloadLevel fail to get resource schedule service.");
237 return RES_SCHED_CONNECT_FAIL;
238 }
239 int32_t ret;
240 rss_->GetSystemloadLevel(ret);
241 return ret;
242 }
243
IsAllowedAppPreload(const std::string & bundleName,int32_t preloadMode)244 bool ResSchedClient::IsAllowedAppPreload(const std::string& bundleName, int32_t preloadMode)
245 {
246 if (TryConnect() != ERR_OK) {
247 return false;
248 }
249
250 std::lock_guard<std::mutex> lock(mutex_);
251 if (rss_ == nullptr) {
252 RESSCHED_LOGE("ResSchedClient::IsAllowedAppPreload fail to get resource schedule service.");
253 return false;
254 }
255
256 RESSCHED_LOGD("App preload bundleName %{public}s, preloadMode %{public}d", bundleName.c_str(), preloadMode);
257 bool ret;
258 rss_->IsAllowedAppPreload(bundleName, preloadMode, ret);
259 return ret;
260 }
261
IsAllowedLinkJump(bool & isAllowedLinkJump)262 int32_t ResSchedClient::IsAllowedLinkJump(bool& isAllowedLinkJump)
263 {
264 RESSCHED_LOGD("enter IsAllowedLinkJump");
265 if (TryConnect() != ERR_OK) {
266 return RES_SCHED_CONNECT_FAIL;
267 }
268
269 std::lock_guard<std::mutex> lock(mutex_);
270 if (rss_ == nullptr) {
271 RESSCHED_LOGE("ResSchedClient::IsAllowedLinkJump fail to get resource schedule service.");
272 return RES_SCHED_CONNECT_FAIL;
273 }
274 int32_t ret;
275 rss_->IsAllowedLinkJump(isAllowedLinkJump, ret);
276 return ret;
277 }
278
GetProxy()279 sptr<IResSchedService> ResSchedClient::GetProxy()
280 {
281 if (TryConnect() == ERR_OK) {
282 std::lock_guard<std::mutex> lock(mutex_);
283 return rss_;
284 }
285 return nullptr;
286 }
287
TryConnect()288 ErrCode ResSchedClient::TryConnect()
289 {
290 std::lock_guard<std::mutex> lock(mutex_);
291 if (g_isDestroyed) {
292 return GET_RES_SCHED_SERVICE_FAILED;
293 }
294 if (rss_) {
295 return ERR_OK;
296 }
297
298 sptr<ISystemAbilityManager> systemManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
299 if (!systemManager) {
300 RESSCHED_LOGE("ResSchedClient::Fail to get registry.");
301 return GET_RES_SCHED_SERVICE_FAILED;
302 }
303
304 remoteObject_ = systemManager->CheckSystemAbility(RES_SCHED_SYS_ABILITY_ID);
305 if (!remoteObject_) {
306 RESSCHED_LOGE("ResSchedClient::Fail to connect resource schedule service.");
307 return GET_RES_SCHED_SERVICE_FAILED;
308 }
309
310 rss_ = iface_cast<IResSchedService>(remoteObject_);
311 if (!rss_) {
312 return GET_RES_SCHED_SERVICE_FAILED;
313 }
314 recipient_ = new (std::nothrow) ResSchedDeathRecipient(*this);
315 if (!recipient_) {
316 RESSCHED_LOGE("ResSchedClient::New ResSchedDeathRecipient failed.");
317 return GET_RES_SCHED_SERVICE_FAILED;
318 }
319 rss_->AsObject()->AddDeathRecipient(recipient_);
320 AddResSaListenerLocked();
321 RESSCHED_LOGD("ResSchedClient::Connect resource schedule service success.");
322 return ERR_OK;
323 }
324
StopRemoteObject()325 void ResSchedClient::StopRemoteObject()
326 {
327 std::lock_guard<std::mutex> lock(mutex_);
328 if (rss_ && rss_->AsObject()) {
329 rss_->AsObject()->RemoveDeathRecipient(recipient_);
330 }
331 rss_ = nullptr;
332 systemloadCbRegistered_ = false;
333 registeredInnerEvents.clear();
334 }
335
AddResSaListenerLocked()336 void ResSchedClient::AddResSaListenerLocked()
337 {
338 if (resSchedSvcStatusListener_ != nullptr) {
339 return;
340 }
341 sptr<ISystemAbilityManager> systemManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
342 if (!systemManager) {
343 RESSCHED_LOGE("ResSchedClient::Fail to get sa mgr client.");
344 return;
345 }
346 resSchedSvcStatusListener_ = new (std::nothrow) ResSchedSvcStatusChange;
347 if (resSchedSvcStatusListener_ == nullptr) {
348 RESSCHED_LOGE("ResSchedClient::Fail to new res svc listener.");
349 return;
350 }
351 int32_t ret = systemManager->SubscribeSystemAbility(RES_SCHED_SYS_ABILITY_ID, resSchedSvcStatusListener_);
352 if (ret != ERR_OK) {
353 RESSCHED_LOGE("ResSchedClient::Register sa status change failed.");
354 resSchedSvcStatusListener_ = nullptr;
355 }
356 }
357
OnAddSystemAbility(int32_t systemAbilityId,const std::string & deviceId)358 void ResSchedClient::OnAddSystemAbility(int32_t systemAbilityId, const std::string& deviceId)
359 {
360 if (systemAbilityId != RES_SCHED_SYS_ABILITY_ID) {
361 RESSCHED_LOGE("ResSchedClient::OnAddSystemAbility is not res sa id.");
362 return;
363 }
364 if (TryConnect() != ERR_OK) {
365 return;
366 }
367 std::lock_guard<std::mutex> lock(mutex_);
368 if (InitInnerEventListenerLocked() != ERR_OK) {
369 RESSCHED_LOGE("ResSchedClient::OnAddSystemAbility init event listener failed.");
370 } else if (innerEventListener_ && rss_) {
371 RecoverEventListener();
372 }
373 if (InitSystemloadListenersLocked() != ERR_OK) {
374 RESSCHED_LOGE("ResSchedClient::OnAddSystemAbility init listener failed.");
375 return;
376 }
377 if (!systemloadCbRegistered_ && !systemloadLevelListener_->IsSystemloadCbArrayEmpty() && rss_) {
378 rss_->RegisterSystemloadNotifier(systemloadLevelListener_);
379 systemloadCbRegistered_ = true;
380 }
381 }
382
RecoverEventListener()383 void ResSchedClient::RecoverEventListener()
384 {
385 for (auto typeAndGroup : innerEventListener_->GetRegisteredTypesAndGroup()) {
386 auto type = typeAndGroup.first;
387 for (auto group : typeAndGroup.second) {
388 if (!rss_) {
389 return;
390 }
391 rss_->RegisterEventListener(innerEventListener_, type, group);
392 if (registeredInnerEvents.find(type) == registeredInnerEvents.end()) {
393 registeredInnerEvents.emplace(type, std::unordered_set<uint32_t>());
394 }
395 registeredInnerEvents[type].insert(group);
396 }
397 }
398 }
399
InitSystemloadListenersLocked()400 int32_t ResSchedClient::InitSystemloadListenersLocked()
401 {
402 if (systemloadLevelListener_ != nullptr) {
403 return ERR_OK;
404 }
405 systemloadLevelListener_ = new (std::nothrow) SystemloadLevelListener;
406 if (systemloadLevelListener_ == nullptr) {
407 RESSCHED_LOGW("ResSchedClient::InitSystemloadListenersLocked new listener error.");
408 return RES_SCHED_DATA_ERROR;
409 }
410 return ERR_OK;
411 }
412
InitInnerEventListenerLocked()413 int32_t ResSchedClient::InitInnerEventListenerLocked()
414 {
415 if (innerEventListener_ != nullptr) {
416 return ERR_OK;
417 }
418 innerEventListener_ = new (std::nothrow) InnerEventListener;
419 if (innerEventListener_ == nullptr) {
420 RESSCHED_LOGW("ResSchedClient::InitInnerEventListenerLocked new listener error.");
421 return RES_SCHED_DATA_ERROR;
422 }
423 return ERR_OK;
424 }
425
UnRegisterEventListenerLocked(uint32_t eventType,uint32_t listenerGroup)426 void ResSchedClient::UnRegisterEventListenerLocked(uint32_t eventType, uint32_t listenerGroup)
427 {
428 if (innerEventListener_->IsInnerEventMapEmpty(eventType, listenerGroup) && rss_) {
429 rss_->UnRegisterEventListener(eventType, listenerGroup);
430 auto item = registeredInnerEvents.find(eventType);
431 if (item != registeredInnerEvents.end()) {
432 item->second.erase(listenerGroup);
433 }
434 }
435 }
436
437
UnRegisterSystemloadListenersLocked()438 void ResSchedClient::UnRegisterSystemloadListenersLocked()
439 {
440 if (systemloadLevelListener_->IsSystemloadCbArrayEmpty() && rss_) {
441 rss_->UnRegisterSystemloadNotifier();
442 systemloadCbRegistered_ = false;
443 }
444 }
445
ResSchedDeathRecipient(ResSchedClient & resSchedClient)446 ResSchedClient::ResSchedDeathRecipient::ResSchedDeathRecipient(ResSchedClient &resSchedClient)
447 : resSchedClient_(resSchedClient) {}
448
~ResSchedDeathRecipient()449 ResSchedClient::ResSchedDeathRecipient::~ResSchedDeathRecipient() {}
450
OnRemoteDied(const wptr<IRemoteObject> & remote)451 void ResSchedClient::ResSchedDeathRecipient::OnRemoteDied(const wptr<IRemoteObject> &remote)
452 {
453 resSchedClient_.StopRemoteObject();
454 }
455
~SystemloadLevelListener()456 ResSchedClient::SystemloadLevelListener::~SystemloadLevelListener()
457 {
458 std::lock_guard<std::mutex> lock(listMutex_);
459 systemloadLevelCbs_.clear();
460 }
461
RegisterSystemloadLevelCb(const sptr<ResSchedSystemloadNotifierClient> & callbackObj)462 void ResSchedClient::SystemloadLevelListener::RegisterSystemloadLevelCb(
463 const sptr<ResSchedSystemloadNotifierClient>& callbackObj)
464 {
465 std::lock_guard<std::mutex> lock(listMutex_);
466 if (callbackObj != nullptr) {
467 for (auto& iter : systemloadLevelCbs_) {
468 if (iter == callbackObj) {
469 RESSCHED_LOGE("ResSchedClient register an exist callback object.");
470 return;
471 }
472 }
473 systemloadLevelCbs_.emplace_back(callbackObj);
474 }
475 RESSCHED_LOGD("Client has registered %{public}d listeners.", static_cast<int32_t>(systemloadLevelCbs_.size()));
476 }
477
UnRegisterSystemloadLevelCb(const sptr<ResSchedSystemloadNotifierClient> & callbackObj)478 void ResSchedClient::SystemloadLevelListener::UnRegisterSystemloadLevelCb(
479 const sptr<ResSchedSystemloadNotifierClient>& callbackObj)
480 {
481 std::lock_guard<std::mutex> lock(listMutex_);
482 systemloadLevelCbs_.remove(callbackObj);
483 RESSCHED_LOGD(
484 "Client left %{public}d systemload level listeners.", static_cast<int32_t>(systemloadLevelCbs_.size()));
485 }
486
IsSystemloadCbArrayEmpty()487 bool ResSchedClient::SystemloadLevelListener::IsSystemloadCbArrayEmpty()
488 {
489 std::lock_guard<std::mutex> lock(listMutex_);
490 return systemloadLevelCbs_.empty();
491 }
492
OnSystemloadLevel(int32_t level)493 ErrCode ResSchedClient::SystemloadLevelListener::OnSystemloadLevel(int32_t level)
494 {
495 std::list<sptr<ResSchedSystemloadNotifierClient>> notifyList;
496 {
497 std::lock_guard<std::mutex> lock(listMutex_);
498 for (auto& iter : systemloadLevelCbs_) {
499 notifyList.push_back(iter);
500 }
501 }
502 // copy notifiers from systemloadLevelCbs_ to revent dead lock
503 for (auto& notifier : notifyList) {
504 if (notifier != nullptr) {
505 notifier->OnSystemloadLevel(level);
506 }
507 }
508 return ERR_OK;
509 }
510
~InnerEventListener()511 ResSchedClient::InnerEventListener::~InnerEventListener()
512 {
513 std::lock_guard<std::mutex> lock(eventMutex_);
514 eventListeners_.clear();
515 }
516
RegisterEventListener(const sptr<ResSchedEventListener> & eventListener,uint32_t eventType,uint32_t listenerGroup)517 void ResSchedClient::InnerEventListener::RegisterEventListener(const sptr<ResSchedEventListener>& eventListener,
518 uint32_t eventType, uint32_t listenerGroup)
519 {
520 std::lock_guard<std::mutex> lock(eventMutex_);
521 if (eventListener == nullptr) {
522 RESSCHED_LOGE("ResSchedClient register an null eventListener object.");
523 return;
524 }
525 auto item = eventListeners_.find(eventType);
526 if (item == eventListeners_.end()) {
527 eventListeners_.emplace(eventType, std::unordered_map<uint32_t, std::list<sptr<ResSchedEventListener>>>());
528 eventListeners_[eventType].emplace(listenerGroup, std::list<sptr<ResSchedEventListener>>());
529 eventListeners_[eventType][listenerGroup].emplace_back(eventListener);
530 } else {
531 auto listenerItem = item->second.find(listenerGroup);
532 if (listenerItem == item->second.end()) {
533 item->second.emplace(listenerGroup, std::list<sptr<ResSchedEventListener>>());
534 }
535 for (auto& iter : listenerItem->second) {
536 if (iter == eventListener) {
537 RESSCHED_LOGE("ResSchedClient register an exist eventListener object.");
538 return;
539 }
540 }
541 item->second[listenerGroup].emplace_back(eventListener);
542 }
543 RESSCHED_LOGD("Client has registered %{public}d eventListener with type:%{public}d.",
544 static_cast<int32_t>(eventListeners_[eventType].size()), eventType);
545 }
546
UnRegisterEventListener(const sptr<ResSchedEventListener> & eventListener,uint32_t eventType,uint32_t listenerGroup)547 void ResSchedClient::InnerEventListener::UnRegisterEventListener(const sptr<ResSchedEventListener>& eventListener,
548 uint32_t eventType, uint32_t listenerGroup)
549 {
550 std::lock_guard<std::mutex> lock(eventMutex_);
551 auto item = eventListeners_.find(eventType);
552 if (item == eventListeners_.end()) {
553 RESSCHED_LOGE("eventListener not registered");
554 return;
555 }
556 auto listenerItem = item->second.find(listenerGroup);
557 if (listenerItem == item->second.end()) {
558 return;
559 }
560 listenerItem->second.remove(eventListener);
561 if (listenerItem->second.size() == 0) {
562 item->second.erase(listenerGroup);
563 RESSCHED_LOGD("Client left 0 listeners with type %{public}d group %{public}d", eventType, listenerGroup);
564 }
565 if (item->second.size() == 0) {
566 eventListeners_.erase(eventType);
567 RESSCHED_LOGD("Client left 0 listeners with type %{public}d.", eventType);
568 return;
569 }
570 RESSCHED_LOGD("Client left %{public}d listeners with type %{public}d.",
571 static_cast<int32_t>(item->second.size()), eventType);
572 }
573
OnReceiveEvent(uint32_t eventType,uint32_t eventValue,uint32_t listenerGroup,const std::string & extInfo)574 ErrCode ResSchedClient::InnerEventListener::OnReceiveEvent(uint32_t eventType, uint32_t eventValue,
575 uint32_t listenerGroup, const std::string& extInfo)
576 {
577 nlohmann::json extInfoJson = StringToJsonObj(extInfo);
578 std::unordered_map<std::string, std::string> extInfoMap;
579 for (auto it = extInfoJson.begin(); it != extInfoJson.end(); ++it) {
580 extInfoMap[it.key()] = it.value().get<std::string>();
581 }
582 std::list<sptr<ResSchedEventListener>> listenerList;
583 {
584 std::lock_guard<std::mutex> lock(eventMutex_);
585 auto item = eventListeners_.find(eventType);
586 if (item == eventListeners_.end()) {
587 return RES_SCHED_DATA_ERROR;
588 }
589 auto listenerItem = item->second.find(listenerGroup);
590 for (auto& iter : listenerItem->second) {
591 listenerList.push_back(iter);
592 }
593 }
594 // copy notifiers from systemloadLevelCbs_ to revent dead lock
595 for (auto& listener : listenerList) {
596 if (listener != nullptr) {
597 listener->OnReceiveEvent(eventType, eventValue, extInfoMap);
598 }
599 }
600 return ERR_OK;
601 }
602
IsInnerEventMapEmpty(uint32_t eventType,uint32_t listenerGroup)603 bool ResSchedClient::InnerEventListener::IsInnerEventMapEmpty(uint32_t eventType, uint32_t listenerGroup)
604 {
605 std::lock_guard<std::mutex> lock(eventMutex_);
606 auto item = eventListeners_.find(eventType);
607 if (item == eventListeners_.end()) {
608 return true;
609 }
610 auto listenerItem = item->second.find(listenerGroup);
611 return listenerItem == item->second.end() || listenerItem->second.empty();
612 }
613
GetRegisteredTypesAndGroup()614 std::unordered_map<uint32_t, std::list<uint32_t>> ResSchedClient::InnerEventListener::GetRegisteredTypesAndGroup()
615 {
616 std::unordered_map<uint32_t, std::list<uint32_t>> ret;
617 std::lock_guard<std::mutex> lock(eventMutex_);
618 for (auto item : eventListeners_) {
619 ret.emplace(item.first, std::list<uint32_t>());
620 for (auto listenerItem : item.second) {
621 ret[item.first].emplace_back(listenerItem.first);
622 }
623 }
624 return ret;
625 }
626
OnAddSystemAbility(int32_t systemAbilityId,const std::string & deviceId)627 void ResSchedSvcStatusChange::OnAddSystemAbility(int32_t systemAbilityId, const std::string& deviceId)
628 {
629 RESSCHED_LOGD("ResSchedSvcStatusChange::OnAddSystemAbility called, said : %{public}d.", systemAbilityId);
630 ResSchedClient::GetInstance().OnAddSystemAbility(systemAbilityId, deviceId);
631 }
632
OnRemoveSystemAbility(int32_t systemAbilityId,const std::string & deviceId)633 void ResSchedSvcStatusChange::OnRemoveSystemAbility(int32_t systemAbilityId, const std::string& deviceId)
634 {
635 RESSCHED_LOGD("ResSchedSvcStatusChange::OnRemoveSystemAbility called.");
636 }
637
ReportData(uint32_t resType,int64_t value,const std::unordered_map<std::string,std::string> & mapPayload)638 extern "C" void ReportData(uint32_t resType, int64_t value,
639 const std::unordered_map<std::string, std::string>& mapPayload)
640 {
641 ResSchedClient::GetInstance().ReportData(resType, value, mapPayload);
642 }
643
KillProcess(const std::unordered_map<std::string,std::string> & mapPayload)644 extern "C" void KillProcess(const std::unordered_map<std::string, std::string>& mapPayload)
645 {
646 ResSchedClient::GetInstance().KillProcess(mapPayload);
647 }
648
ReportSyncEvent(const uint32_t resType,const int64_t value,const std::unordered_map<std::string,std::string> & payload,std::unordered_map<std::string,std::string> & reply)649 extern "C" void ReportSyncEvent(const uint32_t resType, const int64_t value,
650 const std::unordered_map<std::string, std::string>& payload, std::unordered_map<std::string, std::string>& reply)
651 {
652 ResSchedClient::GetInstance().ReportSyncEvent(resType, value, payload, reply);
653 }
654 } // namespace ResourceSchedule
655 } // namespace OHOS
656