From 92ada8d25a3a719496ddbe49e8cb12bf1c1e4e14 Mon Sep 17 00:00:00 2001 From: yangjun Date: Fri, 3 Jan 2025 11:34:13 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=BA=94=E7=94=A8=E7=BA=A7?= =?UTF-8?q?=E6=B5=81=E6=8E=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yangjun Change-Id: I0551bccd7a5a4a73a3a3e2a33ef48353a716433c Signed-off-by: yangjun --- .../core/common/include/ans_const_define.h | 7 +- services/ans/BUILD.gn | 1 + ...vanced_notification_flow_control_service.h | 81 ++++++ .../include/advanced_notification_service.h | 13 +- .../ans/include/notification_config_parse.h | 6 + ...nced_notification_flow_control_service.cpp | 274 ++++++++++++++++++ ...dvanced_notification_live_view_service.cpp | 5 - .../advanced_notification_publish_service.cpp | 19 +- .../ans/src/advanced_notification_service.cpp | 137 +-------- .../ans/src/advanced_notification_utils.cpp | 20 +- .../src/common/notification_config_parse.cpp | 37 +++ services/ans/test/unittest/BUILD.gn | 1 + ...notification_flow_control_service_test.cpp | 103 +++++++ .../advanced_notification_service_test.cpp | 10 +- 14 files changed, 551 insertions(+), 163 deletions(-) create mode 100644 services/ans/include/advanced_notification_flow_control_service.h create mode 100644 services/ans/src/advanced_notification_flow_control_service.cpp create mode 100644 services/ans/test/unittest/advanced_notification_flow_control_service_test.cpp diff --git a/frameworks/core/common/include/ans_const_define.h b/frameworks/core/common/include/ans_const_define.h index 24135987d..f58eea322 100644 --- a/frameworks/core/common/include/ans_const_define.h +++ b/frameworks/core/common/include/ans_const_define.h @@ -27,8 +27,11 @@ namespace Notification { // Max active notification number constexpr size_t MAX_ACTIVE_NUM = 1000; constexpr uint32_t MAX_ACTIVE_NUM_PERAPP = 100; -constexpr uint32_t MAX_ACTIVE_NUM_PERSECOND = 10; -constexpr uint32_t MAX_UPDATE_NUM_PERSECOND = 20; +constexpr uint32_t MAX_CREATE_NUM_PERSECOND = 15; +constexpr uint32_t MAX_UPDATE_NUM_PERSECOND = 30; +constexpr uint32_t MAX_CREATE_NUM_PERSECOND_PERAPP = 10; +constexpr uint32_t MAX_UPDATE_NUM_PERSECOND_PERAPP = 20; +constexpr std::chrono::seconds SINGLE_APP_FLOW_CONTRL_EXPIRE_TIME = std::chrono::seconds(1); constexpr size_t MAX_SLOT_NUM = 5; constexpr uint32_t MAX_ICON_SIZE = 192 * 1024; constexpr uint32_t MAX_PICTURE_SIZE = 2 * 1024 * 1024; diff --git a/services/ans/BUILD.gn b/services/ans/BUILD.gn index db7951874..9c2059a1a 100644 --- a/services/ans/BUILD.gn +++ b/services/ans/BUILD.gn @@ -51,6 +51,7 @@ ohos_shared_library("libans") { "src/advanced_datashare_observer.cpp", "src/advanced_notification_clone_service.cpp", "src/advanced_notification_event_service.cpp", + "src/advanced_notification_flow_control_service.cpp", "src/advanced_notification_inline.cpp", "src/advanced_notification_live_view_service.cpp", "src/advanced_notification_publish/base_publish_process.cpp", diff --git a/services/ans/include/advanced_notification_flow_control_service.h b/services/ans/include/advanced_notification_flow_control_service.h new file mode 100644 index 000000000..cb182f817 --- /dev/null +++ b/services/ans/include/advanced_notification_flow_control_service.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2021-2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BASE_NOTIFICATION_DISTRIBUTED_NOTIFICATION_SERVICE_SERVICES_ANS_INCLUDE_NOTIFICATION_FLOW_CONTROL_SERVICE_H +#define BASE_NOTIFICATION_DISTRIBUTED_NOTIFICATION_SERVICE_SERVICES_ANS_INCLUDE_NOTIFICATION_FLOW_CONTROL_SERVICE_H + +#include +#include +#include +#include + +#include "errors.h" +#include "singleton.h" +#include "ans_const_define.h" +#include "notification_record.h" + +namespace OHOS { +namespace Notification { +struct FlowControlThreshold { + uint32_t maxCreateNumPerSecond = MAX_CREATE_NUM_PERSECOND; + uint32_t maxUpdateNumPerSecond = MAX_UPDATE_NUM_PERSECOND; + uint32_t maxCreateNumPerSecondPerApp = MAX_CREATE_NUM_PERSECOND_PERAPP; + uint32_t maxUpdateNumPerSecondPerApp = MAX_UPDATE_NUM_PERSECOND_PERAPP; +}; + +class FlowControlService : public DelayedSingleton { +public: + FlowControlService(); + ErrCode FlowControl(const std::shared_ptr &record, + const int32_t callingUid, bool isNotificationExists); + +private: + ErrCode PublishFlowCtrl(const std::shared_ptr &record, const int32_t callingUid); + ErrCode PublishGlobalFlowCtrl(const std::shared_ptr &record, + std::chrono::system_clock::time_point now); + ErrCode PublishSingleAppFlowCtrl(const std::shared_ptr &record, + std::chrono::system_clock::time_point now, const int32_t callingUid); + void PublishRecordTimestamp(const std::shared_ptr &record, + std::chrono::system_clock::time_point now, const int32_t callingUid); + void PublishSingleAppFlowCtrlRemoveExpire(std::chrono::system_clock::time_point now); + + ErrCode UpdateFlowCtrl(const std::shared_ptr &record, const int32_t callingUid); + ErrCode UpdateGlobalFlowCtrl(const std::shared_ptr &record, + std::chrono::system_clock::time_point now); + ErrCode UpdateSingleAppFlowCtrl(const std::shared_ptr &record, + std::chrono::system_clock::time_point now, const int32_t callingUid); + void UpdateRecordTimestamp(const std::shared_ptr &record, + std::chrono::system_clock::time_point now, const int32_t callingUid); + void UpdateSingleAppFlowCtrlRemoveExpire(std::chrono::system_clock::time_point now); + +private: + static std::mutex flowControlMutex_; + std::list flowControlUpdateTimestampList_; + std::list flowControlPublishTimestampList_; + static std::mutex systemFlowControlMutex_; + std::list systemFlowControlUpdateTimestampList_; + std::list systemFlowControlPublishTimestampList_; + static std::mutex singleAppFlowControlMutex_; + std::map>> singleAppFlowControlUpdateTimestampMap_; + std::map>> singleAppFlowControlPublishTimestampMap_; + + FlowControlThreshold threshold_; +}; +} // namespace Notification +} // namespace OHOS + +#endif // BASE_NOTIFICATION_DISTRIBUTED_NOTIFICATION_SERVICE_SERVICES_ANS_INCLUDE_NOTIFICATION_FLOW_CONTROL_SERVICE_H \ No newline at end of file diff --git a/services/ans/include/advanced_notification_service.h b/services/ans/include/advanced_notification_service.h index 4e7890bf7..cd4b2d0c1 100644 --- a/services/ans/include/advanced_notification_service.h +++ b/services/ans/include/advanced_notification_service.h @@ -1231,8 +1231,7 @@ private: void SortNotificationList(); static bool NotificationCompare( const std::shared_ptr &first, const std::shared_ptr &second); - ErrCode FlowControl(const std::shared_ptr &record); - ErrCode PublishFlowControl(const std::shared_ptr &record); + ErrCode PublishInNotificationList(const std::shared_ptr &record); ErrCode RemoveNotificationBySlot(const sptr &bundleOption, const sptr &slot, const int reason); @@ -1429,8 +1428,6 @@ private: uint32_t GetDefaultSlotFlags(const sptr &request); ErrCode OnRecoverLiveView(const std::vector &keys); bool IsSystemUser(int32_t userId); - ErrCode UpdateFlowCtrl(const std::shared_ptr &record); - ErrCode PublishFlowControlInner(const std::shared_ptr &record); private: static sptr instance_; static std::mutex instanceMutex_; @@ -1441,14 +1438,6 @@ private: std::shared_ptr runner_ = nullptr; std::shared_ptr handler_ = nullptr; std::list> notificationList_; - static std::mutex flowControlMutex_; - std::list flowControlTimestampList_; - std::list flowControlUpdateTimestampList_; - std::list flowControlPublishTimestampList_; - static std::mutex systemFlowControlMutex_; - std::list systemFlowControlTimestampList_; - std::list systemFlowControlUpdateTimestampList_; - std::list systemFlowControlPublishTimestampList_; std::shared_ptr recentInfo_ = nullptr; std::shared_ptr distributedKvStoreDeathRecipient_ = nullptr; std::shared_ptr systemEventObserver_ = nullptr; diff --git a/services/ans/include/notification_config_parse.h b/services/ans/include/notification_config_parse.h index 04c06d6e9..18d1bdc2c 100644 --- a/services/ans/include/notification_config_parse.h +++ b/services/ans/include/notification_config_parse.h @@ -28,6 +28,7 @@ #include "notification_bundle_option.h" #include "notification_constant.h" #include "notification_flags.h" +#include "advanced_notification_flow_control_service.h" namespace OHOS { namespace Notification { @@ -42,6 +43,7 @@ public: uint32_t GetConfigSlotReminderModeByType(NotificationConstant::SlotType slotType) const; uint32_t GetConfigSlotReminderModeByType(NotificationConstant::SlotType slotType, const sptr &bundleOption) const; + void GetFlowCtrlConfigFromCCM(FlowControlThreshold &threshold); private: std::map defaultCurrentSlotReminder_; @@ -53,6 +55,10 @@ public: constexpr static const char* CFG_KEY_NAME = "name"; constexpr static const char* CFG_KEY_REMINDER_FLAGS = "reminderFlags"; constexpr static const char* APP_PRIVILEGES = "appPrivileges"; + constexpr static const char* CFG_KEY_MAX_CREATE_NUM_PERSECOND = "MaxCreateNumPerSecond"; + constexpr static const char* CFG_KEY_MAX_UPDATE_NUM_PERSECOND = "MaxUpdateNumPerSecond"; + constexpr static const char* CFG_KEY_MAX_CREATE_NUM_PERSECOND_PERAPP = "MaxCreateNumPerSecondPerApp"; + constexpr static const char* CFG_KEY_MAX_UPDATE_NUM_PERSECOND_PERAPP = "MaxUpdateNumPerSecondPerApp"; #ifdef CONFIG_POLICY_ENABLE constexpr static const char* NOTIFICAITON_CONFIG_FILE = "etc/notification/notification_config.json"; # else diff --git a/services/ans/src/advanced_notification_flow_control_service.cpp b/services/ans/src/advanced_notification_flow_control_service.cpp new file mode 100644 index 000000000..79b23e060 --- /dev/null +++ b/services/ans/src/advanced_notification_flow_control_service.cpp @@ -0,0 +1,274 @@ +/* + * Copyright (c) 2021-2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "advanced_notification_flow_control_service.h" + +#include "ans_inner_errors.h" +#include "notification_config_parse.h" +#include "notification_analytics_util.h" + +namespace OHOS { +namespace Notification { +std::mutex FlowControlService::flowControlMutex_; +std::mutex FlowControlService::systemFlowControlMutex_; +std::mutex FlowControlService::singleAppFlowControlMutex_; + +FlowControlService::FlowControlService() +{ + DelayedSingleton::GetInstance()->GetFlowCtrlConfigFromCCM(threshold_); +} + +ErrCode FlowControlService::FlowControl(const std::shared_ptr &record, + const int32_t callingUid, bool isNotificationExists) +{ + if (record->isNeedFlowCtrl == false) { + return ERR_OK; + } + + ErrCode result = ERR_OK; + if (!isNotificationExists) { + result = PublishFlowCtrl(record, callingUid); + } else { + result = UpdateFlowCtrl(record, callingUid); + } + + return result; +} + +ErrCode FlowControlService::PublishFlowCtrl(const std::shared_ptr &record, + const int32_t callingUid) +{ + if (record->isNeedFlowCtrl == false) { + return ERR_OK; + } + std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + ErrCode result = ERR_OK; + result = PublishSingleAppFlowCtrl(record, now, callingUid); + if (result != ERR_OK) { + return result; + } + result = PublishGlobalFlowCtrl(record, now); + if (result != ERR_OK) { + return result; + } + PublishRecordTimestamp(record, now, callingUid); + PublishSingleAppFlowCtrlRemoveExpire(now); + return ERR_OK; +} + +ErrCode FlowControlService::PublishGlobalFlowCtrl(const std::shared_ptr &record, + std::chrono::system_clock::time_point now) +{ + ANS_LOGD("PublishGlobalFlowCtrl size %{public}zu,%{public}zu", + flowControlPublishTimestampList_.size(), systemFlowControlPublishTimestampList_.size()); + if (record->isThirdparty == true) { + // Third-part flow control + std::lock_guard lock(flowControlMutex_); + NotificationAnalyticsUtil::RemoveExpired(flowControlPublishTimestampList_, now); + if (flowControlPublishTimestampList_.size() >= threshold_.maxCreateNumPerSecond) { + ANS_LOGE("Third-part PublishGlobalFlowCtrl failed"); + HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_3, EventBranchId::BRANCH_2) + .ErrorCode(ERR_ANS_OVER_MAX_ACTIVE_PERSECOND).Message("Third-part PublishGlobalFlowCtrl failed"); + if (record != nullptr) { + NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); + } + return ERR_ANS_OVER_MAX_ACTIVE_PERSECOND; + } + } else { + // System flow control + std::lock_guard lock(systemFlowControlMutex_); + NotificationAnalyticsUtil::RemoveExpired(systemFlowControlPublishTimestampList_, now); + if (systemFlowControlPublishTimestampList_.size() >= threshold_.maxCreateNumPerSecond) { + ANS_LOGE("System PublishGlobalFlowCtrl failed"); + HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_3, EventBranchId::BRANCH_3) + .ErrorCode(ERR_ANS_OVER_MAX_ACTIVE_PERSECOND).Message("System PublishGlobalFlowCtrl failed"); + if (record != nullptr) { + NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); + } + return ERR_ANS_OVER_MAX_ACTIVE_PERSECOND; + } + } + return ERR_OK; +} + +ErrCode FlowControlService::PublishSingleAppFlowCtrl(const std::shared_ptr &record, + std::chrono::system_clock::time_point now, const int32_t callingUid) +{ + std::lock_guard lock(singleAppFlowControlMutex_); + auto singleAppFlowControlIter = singleAppFlowControlPublishTimestampMap_.find(callingUid); + if (singleAppFlowControlIter == singleAppFlowControlPublishTimestampMap_.end()) { + return ERR_OK; + } + NotificationAnalyticsUtil::RemoveExpired(*(singleAppFlowControlIter->second), now); + if (singleAppFlowControlIter->second->size() >= threshold_.maxCreateNumPerSecondPerApp) { + ANS_LOGE("SingleAppPublishFlowControl failed"); + HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_3, EventBranchId::BRANCH_4) + .ErrorCode(ERR_ANS_OVER_MAX_ACTIVE_PERSECOND).Message("SingleAppPublishFlowControl failed"); + if (record != nullptr) { + NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); + } + return ERR_ANS_OVER_MAX_ACTIVE_PERSECOND; + } + return ERR_OK; +} + +void FlowControlService::PublishRecordTimestamp(const std::shared_ptr &record, + std::chrono::system_clock::time_point now, const int32_t callingUid) +{ + if (record->isThirdparty == true) { + std::lock_guard lock(flowControlMutex_); + flowControlPublishTimestampList_.push_back(now); + } else { + std::lock_guard lock(systemFlowControlMutex_); + systemFlowControlPublishTimestampList_.push_back(now); + } + + std::lock_guard lock(singleAppFlowControlMutex_); + auto singleAppFlowControlIter = singleAppFlowControlPublishTimestampMap_.find(callingUid); + if (singleAppFlowControlIter == singleAppFlowControlPublishTimestampMap_.end()) { + singleAppFlowControlPublishTimestampMap_[callingUid] = + std::make_shared>(); + singleAppFlowControlIter = singleAppFlowControlPublishTimestampMap_.find(callingUid); + } + singleAppFlowControlIter->second->push_back(now); +} + +void FlowControlService::PublishSingleAppFlowCtrlRemoveExpire(std::chrono::system_clock::time_point now) +{ + std::lock_guard lock(singleAppFlowControlMutex_); + for (auto iter = singleAppFlowControlPublishTimestampMap_.begin(); + iter != singleAppFlowControlPublishTimestampMap_.end();) { + auto latest = iter->second->back(); + if (std::chrono::abs(now - latest) > SINGLE_APP_FLOW_CONTRL_EXPIRE_TIME) { + iter = singleAppFlowControlPublishTimestampMap_.erase(iter); + } else { + ++iter; + } + } +} + +ErrCode FlowControlService::UpdateFlowCtrl(const std::shared_ptr &record, + const int32_t callingUid) +{ + if (record->isNeedFlowCtrl == false) { + return ERR_OK; + } + std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + ErrCode result = ERR_OK; + result = UpdateSingleAppFlowCtrl(record, now, callingUid); + if (result != ERR_OK) { + return result; + } + result = UpdateGlobalFlowCtrl(record, now); + if (result != ERR_OK) { + return result; + } + UpdateRecordTimestamp(record, now, callingUid); + UpdateSingleAppFlowCtrlRemoveExpire(now); + return result; +} + +ErrCode FlowControlService::UpdateGlobalFlowCtrl(const std::shared_ptr &record, + std::chrono::system_clock::time_point now) +{ + ANS_LOGD("UpdateGlobalFlowCtrl size %{public}zu,%{public}zu", + flowControlUpdateTimestampList_.size(), systemFlowControlUpdateTimestampList_.size()); + if (record->isThirdparty == true) { + // Third-part flow control + std::lock_guard lock(flowControlMutex_); + NotificationAnalyticsUtil::RemoveExpired(flowControlUpdateTimestampList_, now); + if (flowControlUpdateTimestampList_.size() >= threshold_.maxUpdateNumPerSecond) { + ANS_LOGE("Third-part UpdateGlobalFlowCtrl failed"); + HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_4, EventBranchId::BRANCH_3) + .ErrorCode(ERR_ANS_OVER_MAX_UPDATE_PERSECOND).Message("Third-part updateGlobalFlowCtrl failed"); + if (record != nullptr) { + NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); + } + return ERR_ANS_OVER_MAX_UPDATE_PERSECOND; + } + } else { + // System flow control + std::lock_guard lock(systemFlowControlMutex_); + NotificationAnalyticsUtil::RemoveExpired(systemFlowControlUpdateTimestampList_, now); + if (systemFlowControlUpdateTimestampList_.size() >= threshold_.maxUpdateNumPerSecond) { + ANS_LOGE("System UpdateGlobalFlowCtrl failed"); + HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_4, EventBranchId::BRANCH_4) + .ErrorCode(ERR_ANS_OVER_MAX_UPDATE_PERSECOND).Message("System updateGlobalFlowCtrl failed"); + if (record != nullptr) { + NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); + } + return ERR_ANS_OVER_MAX_UPDATE_PERSECOND; + } + } + return ERR_OK; +} + +ErrCode FlowControlService::UpdateSingleAppFlowCtrl(const std::shared_ptr &record, + std::chrono::system_clock::time_point now, const int32_t callingUid) +{ + std::lock_guard lock(singleAppFlowControlMutex_); + auto singleAppFlowControlIter = singleAppFlowControlUpdateTimestampMap_.find(callingUid); + if (singleAppFlowControlIter == singleAppFlowControlUpdateTimestampMap_.end()) { + return ERR_OK; + } + NotificationAnalyticsUtil::RemoveExpired(*(singleAppFlowControlIter->second), now); + if (singleAppFlowControlIter->second->size() >= threshold_.maxUpdateNumPerSecondPerApp) { + ANS_LOGE("SingleAppUpdateFlowControl failed"); + HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_4, EventBranchId::BRANCH_5) + .ErrorCode(ERR_ANS_OVER_MAX_UPDATE_PERSECOND).Message("SingleAppUpdateFlowControl failed"); + if (record != nullptr) { + NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); + } + return ERR_ANS_OVER_MAX_UPDATE_PERSECOND; + } + return ERR_OK; +} + +void FlowControlService::UpdateRecordTimestamp(const std::shared_ptr &record, + std::chrono::system_clock::time_point now, const int32_t callingUid) +{ + if (record->isThirdparty == true) { + std::lock_guard lock(flowControlMutex_); + flowControlUpdateTimestampList_.push_back(now); + } else { + std::lock_guard lock(systemFlowControlMutex_); + systemFlowControlUpdateTimestampList_.push_back(now); + } + + std::lock_guard lock(singleAppFlowControlMutex_); + auto singleAppFlowControlIter = singleAppFlowControlUpdateTimestampMap_.find(callingUid); + if (singleAppFlowControlIter == singleAppFlowControlUpdateTimestampMap_.end()) { + singleAppFlowControlUpdateTimestampMap_[callingUid] = + std::make_shared>(); + singleAppFlowControlIter = singleAppFlowControlUpdateTimestampMap_.find(callingUid); + } + singleAppFlowControlIter->second->push_back(now); +} + +void FlowControlService::UpdateSingleAppFlowCtrlRemoveExpire(std::chrono::system_clock::time_point now) +{ + std::lock_guard lock(singleAppFlowControlMutex_); + for (auto iter = singleAppFlowControlUpdateTimestampMap_.begin(); + iter != singleAppFlowControlUpdateTimestampMap_.end();) { + auto latest = iter->second->back(); + if (std::chrono::abs(now - latest) > SINGLE_APP_FLOW_CONTRL_EXPIRE_TIME) { + iter = singleAppFlowControlUpdateTimestampMap_.erase(iter); + } else { + ++iter; + } + } +} +} // namespace Notification +} // namespace OHOS \ No newline at end of file diff --git a/services/ans/src/advanced_notification_live_view_service.cpp b/services/ans/src/advanced_notification_live_view_service.cpp index 5032e2b0d..090a52e18 100644 --- a/services/ans/src/advanced_notification_live_view_service.cpp +++ b/services/ans/src/advanced_notification_live_view_service.cpp @@ -79,11 +79,6 @@ void AdvancedNotificationService::RecoverLiveViewFromDb(int32_t userId) continue; } - if (FlowControl(record) != ERR_OK) { - ANS_LOGE("Flow control failed."); - continue; - } - // Turn off ringtone and vibration during recovery process auto notificationFlags = record->request->GetFlags(); notificationFlags->SetSoundEnabled(NotificationConstant::FlagStatus::CLOSE); diff --git a/services/ans/src/advanced_notification_publish_service.cpp b/services/ans/src/advanced_notification_publish_service.cpp index 35e5ea9ca..d6e313e04 100644 --- a/services/ans/src/advanced_notification_publish_service.cpp +++ b/services/ans/src/advanced_notification_publish_service.cpp @@ -50,6 +50,7 @@ #include "if_system_ability_manager.h" #include "iservice_registry.h" #include "datashare_predicates.h" +#include "advanced_notification_flow_control_service.h" namespace OHOS { namespace Notification { @@ -230,7 +231,11 @@ ErrCode AdvancedNotificationService::PublishNotificationForIndirectProxy(const s } return; } - + bool isNotificationExists = IsNotificationExists(record->notification->GetKey()); + result = FlowControlService::GetInstance()->FlowControl(record, ipcUid, isNotificationExists); + if (result != ERR_OK) { + return; + } if (AssignToNotificationList(record) != ERR_OK) { ANS_LOGE("Failed to assign notification list"); return; @@ -2401,16 +2406,12 @@ ErrCode AdvancedNotificationService::PublishNotificationBySa(const sptrrequest, bundleOption); #ifdef ENABLE_ANS_EXT_WRAPPER EXTENTION_WRAPPER->GetUnifiedGroupInfo(request); #endif - auto ipcUid = IPCSkeleton::GetCallingUid(); + const int32_t ipcUid = IPCSkeleton::GetCallingUid(); ffrt::task_handle handler = notificationSvrQueue_->submit_h([&]() { if (!bundleOption->GetBundleName().empty()) { ErrCode ret = AssignValidNotificationSlot(record, bundleOption); @@ -2429,7 +2430,11 @@ ErrCode AdvancedNotificationService::PublishNotificationBySa(const sptrnotification->GetKey()); + result = FlowControlService::GetInstance()->FlowControl(record, ipcUid, isNotificationExists); + if (result != ERR_OK) { + return; + } if (AssignToNotificationList(record) != ERR_OK) { ANS_LOGE("Failed to assign notification list"); return; diff --git a/services/ans/src/advanced_notification_service.cpp b/services/ans/src/advanced_notification_service.cpp index 891e6858c..07f886bfb 100644 --- a/services/ans/src/advanced_notification_service.cpp +++ b/services/ans/src/advanced_notification_service.cpp @@ -74,6 +74,7 @@ #include "advanced_notification_inline.cpp" #include "advanced_datashare_helper_ext.h" #include "notification_analytics_util.h" +#include "advanced_notification_flow_control_service.h" namespace OHOS { namespace Notification { @@ -97,8 +98,6 @@ constexpr const char *KEY_UNIFIED_GROUP_ENABLE = "unified_group_enable"; sptr AdvancedNotificationService::instance_; std::mutex AdvancedNotificationService::instanceMutex_; std::mutex AdvancedNotificationService::pushMutex_; -std::mutex AdvancedNotificationService::flowControlMutex_; -std::mutex AdvancedNotificationService::systemFlowControlMutex_; std::mutex AdvancedNotificationService::doNotDisturbMutex_; std::map slotFlagsDefaultMap_; @@ -365,7 +364,7 @@ ErrCode AdvancedNotificationService::AssignToNotificationList(const std::shared_ ErrCode result = ERR_OK; if (!IsNotificationExists(record->notification->GetKey())) { record->request->SetCreateTime(GetCurrentTime()); - result = PublishFlowControl(record); + result = PublishInNotificationList(record); } else { if (record->request->IsAlertOneTime()) { CloseAlert(record); @@ -654,15 +653,10 @@ ErrCode AdvancedNotificationService::PublishPreparedNotification(const sptrGetUnifiedGroupInfo(request); #endif - int32_t uid = IPCSkeleton::GetCallingUid(); + const int32_t uid = IPCSkeleton::GetCallingUid(); ffrt::task_handle handler = notificationSvrQueue_->submit_h(std::bind([&]() { ANS_LOGD("ffrt enter!"); if (record->request->GetSlotType() == NotificationConstant::SlotType::LIVE_VIEW && @@ -675,7 +669,11 @@ ErrCode AdvancedNotificationService::PublishPreparedNotification(const sptrnotification->GetKey()); + result = FlowControlService::GetInstance()->FlowControl(record, uid, isNotificationExists); + if (result != ERR_OK) { + return; + } result = AddRecordToMemory(record, isSystemApp, isUpdateByOwner, isAgentController); if (result != ERR_OK) { return; @@ -997,50 +995,8 @@ void AdvancedNotificationService::AddToNotificationList(const std::shared_ptr &record) -{ - if (record->isNeedFlowCtrl == false) { - return ERR_OK; - } - std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); - ANS_LOGD("UpdateInNotificationList size %{public}zu,%{public}zu", - flowControlUpdateTimestampList_.size(), systemFlowControlUpdateTimestampList_.size()); - if (record->isThirdparty == true) { - // 三方流控 - std::lock_guard lock(flowControlMutex_); - NotificationAnalyticsUtil::RemoveExpired(flowControlUpdateTimestampList_, now); - if (flowControlUpdateTimestampList_.size() >= MAX_UPDATE_NUM_PERSECOND) { - HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_2, EventBranchId::BRANCH_4) - .ErrorCode(ERR_ANS_OVER_MAX_UPDATE_PERSECOND).Message("UpdateInNotificationList failed"); - if (record != nullptr) { - NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); - } - return ERR_ANS_OVER_MAX_UPDATE_PERSECOND; - } - flowControlUpdateTimestampList_.push_back(now); - } else { - // 系统流控 - std::lock_guard lock(systemFlowControlMutex_); - NotificationAnalyticsUtil::RemoveExpired(systemFlowControlUpdateTimestampList_, now); - if (systemFlowControlUpdateTimestampList_.size() >= MAX_UPDATE_NUM_PERSECOND) { - HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_2, EventBranchId::BRANCH_4) - .ErrorCode(ERR_ANS_OVER_MAX_UPDATE_PERSECOND).Message("UpdateInNotificationList failed"); - if (record != nullptr) { - NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); - } - return ERR_ANS_OVER_MAX_UPDATE_PERSECOND; - } - systemFlowControlUpdateTimestampList_.push_back(now); - } - return ERR_OK; -} - ErrCode AdvancedNotificationService::UpdateInNotificationList(const std::shared_ptr &record) { - ErrCode result = UpdateFlowCtrl(record); - if (result != ERR_OK) { - return result; - } auto iter = notificationList_.begin(); while (iter != notificationList_.end()) { if ((*iter)->notification->GetKey() == record->notification->GetKey()) { @@ -1523,89 +1479,14 @@ static bool SortNotificationsByLevelAndTime( } return (first->slot->GetLevel() < second->slot->GetLevel()); } - - -ErrCode AdvancedNotificationService::FlowControl(const std::shared_ptr &record) -{ - if (record->isNeedFlowCtrl == false) { - return ERR_OK; - } - HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_4, EventBranchId::BRANCH_2); - std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); - ANS_LOGD("FlowControl size %{public}zu,%{public}zu", - flowControlTimestampList_.size(), systemFlowControlTimestampList_.size()); - if (record->isThirdparty == true) { - std::lock_guard lock(flowControlMutex_); - NotificationAnalyticsUtil::RemoveExpired(flowControlTimestampList_, now); - if (flowControlTimestampList_.size() >= MAX_ACTIVE_NUM_PERSECOND + MAX_UPDATE_NUM_PERSECOND) { - message.ErrorCode(ERR_ANS_OVER_MAX_ACTIVE_PERSECOND); - NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); - return ERR_ANS_OVER_MAX_ACTIVE_PERSECOND; - } - flowControlTimestampList_.push_back(now); - } else { - std::lock_guard lock(systemFlowControlMutex_); - NotificationAnalyticsUtil::RemoveExpired(systemFlowControlTimestampList_, now); - if (systemFlowControlTimestampList_.size() >= MAX_ACTIVE_NUM_PERSECOND + MAX_UPDATE_NUM_PERSECOND) { - message.ErrorCode(ERR_ANS_OVER_MAX_ACTIVE_PERSECOND); - NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); - return ERR_ANS_OVER_MAX_ACTIVE_PERSECOND; - } - systemFlowControlTimestampList_.push_back(now); - } - - return ERR_OK; -} bool AdvancedNotificationService::IsSystemUser(int32_t userId) { return ((userId >= SUBSCRIBE_USER_SYSTEM_BEGIN) && (userId <= SUBSCRIBE_USER_SYSTEM_END)); } -ErrCode AdvancedNotificationService::PublishFlowControlInner(const std::shared_ptr &record) -{ - if (record->isNeedFlowCtrl == false) { - return ERR_OK; - } - std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); - ANS_LOGD("PublishFlowControl size %{public}zu,%{public}zu", - flowControlPublishTimestampList_.size(), systemFlowControlPublishTimestampList_.size()); - if (record->isThirdparty == true) { - // 三方流控 - std::lock_guard lock(flowControlMutex_); - NotificationAnalyticsUtil::RemoveExpired(flowControlPublishTimestampList_, now); - if (flowControlPublishTimestampList_.size() >= MAX_ACTIVE_NUM_PERSECOND) { - HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_2, EventBranchId::BRANCH_3) - .ErrorCode(ERR_ANS_OVER_MAX_ACTIVE_PERSECOND).Message("PublishFlowControl failed"); - if (record != nullptr) { - NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); - } - return ERR_ANS_OVER_MAX_ACTIVE_PERSECOND; - } - flowControlPublishTimestampList_.push_back(now); - } else { - // 系统流控 - std::lock_guard lock(systemFlowControlMutex_); - NotificationAnalyticsUtil::RemoveExpired(systemFlowControlPublishTimestampList_, now); - if (systemFlowControlPublishTimestampList_.size() >= MAX_ACTIVE_NUM_PERSECOND) { - HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_2, EventBranchId::BRANCH_3) - .ErrorCode(ERR_ANS_OVER_MAX_ACTIVE_PERSECOND).Message("PublishFlowControl failed"); - if (record != nullptr) { - NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message); - } - return ERR_ANS_OVER_MAX_ACTIVE_PERSECOND; - } - systemFlowControlPublishTimestampList_.push_back(now); - } - return ERR_OK; -} - -ErrCode AdvancedNotificationService::PublishFlowControl(const std::shared_ptr &record) +ErrCode AdvancedNotificationService::PublishInNotificationList(const std::shared_ptr &record) { - ErrCode result = PublishFlowControlInner(record); - if (result != ERR_OK) { - return result; - } std::list> bundleList; for (auto item : notificationList_) { if (record->notification->GetBundleName() == item->notification->GetBundleName()) { diff --git a/services/ans/src/advanced_notification_utils.cpp b/services/ans/src/advanced_notification_utils.cpp index 22f669fc1..d2735d80c 100644 --- a/services/ans/src/advanced_notification_utils.cpp +++ b/services/ans/src/advanced_notification_utils.cpp @@ -50,6 +50,7 @@ #include "notification_analytics_util.h" #include "notification_clone_disturb_service.h" #include "notification_clone_bundle_service.h" +#include "advanced_notification_flow_control_service.h" #define CHECK_BUNDLE_OPTION_IS_INVALID(option) \ if (option == nullptr || option->GetBundleName().empty()) { \ @@ -915,7 +916,8 @@ void AdvancedNotificationService::OnDistributedPublish( ANS_LOGE("notificationSvrQueue_ is nullptr."); return; } - notificationSvrQueue_->submit(std::bind([this, deviceId, bundleName, request, activeUserId]() { + const int32_t callingUid = IPCSkeleton::GetCallingUid(); + notificationSvrQueue_->submit(std::bind([this, deviceId, bundleName, request, activeUserId, callingUid]() { ANS_LOGD("ffrt enter!"); if (!CheckDistributedNotificationType(request)) { ANS_LOGD("CheckDistributedNotificationType is false."); @@ -965,7 +967,12 @@ void AdvancedNotificationService::OnDistributedPublish( return; } - result = PublishFlowControl(record); + bool isNotificationExists = IsNotificationExists(record->notification->GetKey()); + result = FlowControlService::GetInstance()->FlowControl(record, callingUid, isNotificationExists); + if (result != ERR_OK) { + return; + } + result = PublishInNotificationList(record); if (result != ERR_OK) { return; } @@ -990,7 +997,8 @@ void AdvancedNotificationService::OnDistributedUpdate( ANS_LOGE("Serial queue is invalid."); return; } - notificationSvrQueue_->submit(std::bind([this, deviceId, bundleName, request, activeUserId]() { + const int32_t callingUid = IPCSkeleton::GetCallingUid(); + notificationSvrQueue_->submit(std::bind([this, deviceId, bundleName, request, activeUserId, callingUid]() { ANS_LOGD("ffrt enter!"); if (!CheckDistributedNotificationType(request)) { ANS_LOGD("device type not support display."); @@ -1038,7 +1046,11 @@ void AdvancedNotificationService::OnDistributedUpdate( ANS_LOGE("Reject by filters: %{public}d", result); return; } - + bool isNotificationExists = IsNotificationExists(record->notification->GetKey()); + result = FlowControlService::GetInstance()->FlowControl(record, callingUid, isNotificationExists); + if (result != ERR_OK) { + return; + } if (IsNotificationExists(record->notification->GetKey())) { if (record->request->IsAlertOneTime()) { CloseAlert(record); diff --git a/services/ans/src/common/notification_config_parse.cpp b/services/ans/src/common/notification_config_parse.cpp index af14a94fe..10a25b10d 100644 --- a/services/ans/src/common/notification_config_parse.cpp +++ b/services/ans/src/common/notification_config_parse.cpp @@ -144,5 +144,42 @@ uint32_t NotificationConfigParse::GetConfigSlotReminderModeByType(NotificationCo } return reminderFlags; } + +void NotificationConfigParse::GetFlowCtrlConfigFromCCM(FlowControlThreshold &threshold) +{ + nlohmann::json root; + std::string JsonPoint = "/"; + JsonPoint.append(CFG_KEY_NOTIFICATION_SERVICE); + if (!GetConfigJson(JsonPoint, root)) { + ANS_LOGE("Failed to get JsonPoint CCM config file"); + return; + } + if (!root.contains(CFG_KEY_NOTIFICATION_SERVICE)) { + ANS_LOGW("GetFlowCtrlConfigFromCCM not found jsonKey"); + return; + } + nlohmann::json affects = root[CFG_KEY_NOTIFICATION_SERVICE]; + if (affects.is_null() || affects.empty()) { + ANS_LOGE("GetFlowCtrlConfigFromCCM failed as invalid ccmFlowCtrlConfig json"); + return; + } + if (affects.contains(CFG_KEY_MAX_CREATE_NUM_PERSECOND)) { + threshold.maxCreateNumPerSecond = affects[CFG_KEY_MAX_CREATE_NUM_PERSECOND]; + } + + if (affects.contains(CFG_KEY_MAX_UPDATE_NUM_PERSECOND)) { + threshold.maxUpdateNumPerSecond = affects[CFG_KEY_MAX_UPDATE_NUM_PERSECOND]; + } + + if (affects.contains(CFG_KEY_MAX_CREATE_NUM_PERSECOND_PERAPP)) { + threshold.maxCreateNumPerSecondPerApp = affects[CFG_KEY_MAX_CREATE_NUM_PERSECOND_PERAPP]; + } + + if (affects.contains(CFG_KEY_MAX_UPDATE_NUM_PERSECOND_PERAPP)) { + threshold.maxUpdateNumPerSecondPerApp = affects[CFG_KEY_MAX_UPDATE_NUM_PERSECOND_PERAPP]; + } + + ANS_LOGI("GetFlowCtrlConfigFromCCM success"); +} } // namespace Notification } // namespace OHOS diff --git a/services/ans/test/unittest/BUILD.gn b/services/ans/test/unittest/BUILD.gn index e626898bf..f088f19bc 100644 --- a/services/ans/test/unittest/BUILD.gn +++ b/services/ans/test/unittest/BUILD.gn @@ -467,6 +467,7 @@ ohos_unittest("notification_publish_service_test") { sources = [ "${test_path}/mock/mock_tokenid_kit.cpp", + "advanced_notification_flow_control_service_test.cpp", "advanced_notification_publish_service_test.cpp", "mock/blob.cpp", "mock/distributed_kv_data_manager.cpp", diff --git a/services/ans/test/unittest/advanced_notification_flow_control_service_test.cpp b/services/ans/test/unittest/advanced_notification_flow_control_service_test.cpp new file mode 100644 index 000000000..5cdebef47 --- /dev/null +++ b/services/ans/test/unittest/advanced_notification_flow_control_service_test.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "advanced_notification_flow_control_service.h" + +#include "gtest/gtest.h" + +#include "ans_const_define.h" +#include "ans_inner_errors.h" + +using namespace testing::ext; + +namespace OHOS { +namespace Notification { +namespace { + constexpr int32_t NON_SYSTEM_APP_UID = 1000; +} +class FlowControlServiceTest : public testing::Test { +public: + static void SetUpTestCase(); + static void TearDownTestCase(); + void SetUp(); + void TearDown(); +}; + +void FlowControlServiceTest::SetUpTestCase() {} + +void FlowControlServiceTest::TearDownTestCase() {} + +void FlowControlServiceTest::SetUp() {} + +void FlowControlServiceTest::TearDown() {} + +/** + * @tc.number : FlowControl_00001 + * @tc.name : Test FlowControl + * @tc.desc : Test FlowControl + */ +HWTEST_F(FlowControlServiceTest, FlowControl_00001, Function | SmallTest | Level1) +{ + sptr request = new (std::nothrow) NotificationRequest(); + sptr notification = new (std::nothrow) Notification(request); + auto record = std::make_shared(); + record->request = request; + record->notification = notification; + record->isThirdparty = false; + record->isNeedFlowCtrl = true; + ErrCode result = ERR_OK; + int32_t callingUid = DEFAULT_UID; + + // create flow control + // single app flow control test + for (int i = 0; i < MAX_CREATE_NUM_PERSECOND_PERAPP; i++) { + result = FlowControlService::GetInstance()->FlowControl(record, callingUid, false); + } + ASSERT_EQ(result, (int)ERR_OK); + result = FlowControlService::GetInstance()->FlowControl(record, callingUid, false); + ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_ACTIVE_PERSECOND); + + // global flow control test + int gap = MAX_CREATE_NUM_PERSECOND - MAX_CREATE_NUM_PERSECOND_PERAPP; + callingUid = NON_SYSTEM_APP_UID; + for (int i = 0; i < gap; i++) { + result = FlowControlService::GetInstance()->FlowControl(record, callingUid, false); + } + ASSERT_EQ(result, (int)ERR_OK); + result = FlowControlService::GetInstance()->FlowControl(record, callingUid, false); + ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_ACTIVE_PERSECOND); + + // update flow control + // single app flow control test + callingUid = DEFAULT_UID; + for (int i = 0; i < MAX_UPDATE_NUM_PERSECOND_PERAPP; i++) { + result = FlowControlService::GetInstance()->FlowControl(record, callingUid, true); + } + ASSERT_EQ(result, (int)ERR_OK); + result = FlowControlService::GetInstance()->FlowControl(record, callingUid, true); + ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_UPDATE_PERSECOND); + + // global flow control test + gap = MAX_UPDATE_NUM_PERSECOND - MAX_UPDATE_NUM_PERSECOND_PERAPP; + callingUid = NON_SYSTEM_APP_UID; + for (int i = 0; i < gap; i++) { + result = FlowControlService::GetInstance()->FlowControl(record, callingUid, true); + } + ASSERT_EQ(result, (int)ERR_OK); + result = FlowControlService::GetInstance()->FlowControl(record, callingUid, true); + ASSERT_EQ(result, (int)ERR_ANS_OVER_MAX_UPDATE_PERSECOND); +} +} // namespace Notification +} // namespace OHOS \ No newline at end of file diff --git a/services/ans/test/unittest/advanced_notification_service_test.cpp b/services/ans/test/unittest/advanced_notification_service_test.cpp index 19a1d18a5..bcd5e50f4 100644 --- a/services/ans/test/unittest/advanced_notification_service_test.cpp +++ b/services/ans/test/unittest/advanced_notification_service_test.cpp @@ -3762,12 +3762,12 @@ HWTEST_F(AdvancedNotificationServiceTest, GetExcludeDates_00001, Function | Smal } /** - * @tc.number : PublishFlowControl_00001 - * @tc.name : Test PublishFlowControl - * @tc.desc : Test PublishFlowControl function when the record->slot is nullptr + * @tc.number : PublishInNotificationList_00001 + * @tc.name : Test PublishInNotificationList + * @tc.desc : Test PublishInNotificationList function when the record->slot is nullptr * @tc.require : issueI5S4VP */ -HWTEST_F(AdvancedNotificationServiceTest, PublishFlowControl_00001, Function | SmallTest | Level1) +HWTEST_F(AdvancedNotificationServiceTest, PublishInNotificationList_00001, Function | SmallTest | Level1) { for (int i = 0; i < 100; i++) { sptr request = new (std::nothrow) NotificationRequest(); @@ -3783,7 +3783,7 @@ HWTEST_F(AdvancedNotificationServiceTest, PublishFlowControl_00001, Function | S auto record = std::make_shared(); record->request = request; record->notification = notification; - advancedNotificationService_->PublishFlowControl(record); + advancedNotificationService_->PublishInNotificationList(record); ASSERT_EQ(advancedNotificationService_->notificationList_.size(), 100); } } // namespace Notification -- Gitee