1 /*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "advanced_notification_flow_control_service.h"
17
18 #include "ans_inner_errors.h"
19 #include "notification_config_parse.h"
20 #include "notification_analytics_util.h"
21
22 namespace OHOS {
23 namespace Notification {
24 std::mutex FlowControlService::flowControlMutex_;
25 std::mutex FlowControlService::systemFlowControlMutex_;
26 std::mutex FlowControlService::singleAppFlowControlMutex_;
27
FlowControlService()28 FlowControlService::FlowControlService()
29 {
30 DelayedSingleton<NotificationConfigParse>::GetInstance()->GetFlowCtrlConfigFromCCM(threshold_);
31 }
32
FlowControl(const std::shared_ptr<NotificationRecord> & record,const int32_t callingUid,bool isNotificationExists)33 ErrCode FlowControlService::FlowControl(const std::shared_ptr<NotificationRecord> &record,
34 const int32_t callingUid, bool isNotificationExists)
35 {
36 if (record->isNeedFlowCtrl == false) {
37 return ERR_OK;
38 }
39
40 ErrCode result = ERR_OK;
41 if (!isNotificationExists) {
42 if (record->request->IsUpdateOnly()) {
43 ANS_LOGW("Notification not exists when update");
44 return ERR_ANS_NOTIFICATION_NOT_EXISTS;
45 }
46 result = PublishFlowCtrl(record, callingUid);
47 } else {
48 result = UpdateFlowCtrl(record, callingUid);
49 }
50
51 return result;
52 }
53
PublishFlowCtrl(const std::shared_ptr<NotificationRecord> & record,const int32_t callingUid)54 ErrCode FlowControlService::PublishFlowCtrl(const std::shared_ptr<NotificationRecord> &record,
55 const int32_t callingUid)
56 {
57 if (record->isNeedFlowCtrl == false) {
58 return ERR_OK;
59 }
60 std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
61 ErrCode result = ERR_OK;
62 result = PublishSingleAppFlowCtrl(record, now, callingUid);
63 if (result != ERR_OK) {
64 return result;
65 }
66 result = PublishGlobalFlowCtrl(record, now);
67 if (result != ERR_OK) {
68 return result;
69 }
70 PublishRecordTimestamp(record, now, callingUid);
71 PublishSingleAppFlowCtrlRemoveExpire(now);
72 return ERR_OK;
73 }
74
PublishGlobalFlowCtrl(const std::shared_ptr<NotificationRecord> & record,std::chrono::system_clock::time_point now)75 ErrCode FlowControlService::PublishGlobalFlowCtrl(const std::shared_ptr<NotificationRecord> &record,
76 std::chrono::system_clock::time_point now)
77 {
78 ANS_LOGD("PublishGlobalFlowCtrl size %{public}zu,%{public}zu",
79 flowControlPublishTimestampList_.size(), systemFlowControlPublishTimestampList_.size());
80 if (record->isThirdparty == true) {
81 // Third-part flow control
82 std::lock_guard<std::mutex> lock(flowControlMutex_);
83 NotificationAnalyticsUtil::RemoveExpired(flowControlPublishTimestampList_, now);
84 if (flowControlPublishTimestampList_.size() >= threshold_.maxCreateNumPerSecond) {
85 ANS_LOGE("Third-part PublishGlobalFlowCtrl failed");
86 HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_3, EventBranchId::BRANCH_2)
87 .ErrorCode(ERR_ANS_OVER_MAX_ACTIVE_PERSECOND).Message("Third-part PublishGlobalFlowCtrl failed");
88 if (record != nullptr) {
89 NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message);
90 }
91 return ERR_ANS_OVER_MAX_ACTIVE_PERSECOND;
92 }
93 } else {
94 // System flow control
95 std::lock_guard<std::mutex> lock(systemFlowControlMutex_);
96 NotificationAnalyticsUtil::RemoveExpired(systemFlowControlPublishTimestampList_, now);
97 if (systemFlowControlPublishTimestampList_.size() >= threshold_.maxCreateNumPerSecond) {
98 ANS_LOGE("System PublishGlobalFlowCtrl failed");
99 HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_3, EventBranchId::BRANCH_3)
100 .ErrorCode(ERR_ANS_OVER_MAX_ACTIVE_PERSECOND).Message("System PublishGlobalFlowCtrl failed");
101 if (record != nullptr) {
102 NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message);
103 }
104 return ERR_ANS_OVER_MAX_ACTIVE_PERSECOND;
105 }
106 }
107 return ERR_OK;
108 }
109
PublishSingleAppFlowCtrl(const std::shared_ptr<NotificationRecord> & record,std::chrono::system_clock::time_point now,const int32_t callingUid)110 ErrCode FlowControlService::PublishSingleAppFlowCtrl(const std::shared_ptr<NotificationRecord> &record,
111 std::chrono::system_clock::time_point now, const int32_t callingUid)
112 {
113 std::lock_guard<std::mutex> lock(singleAppFlowControlMutex_);
114 auto singleAppFlowControlIter = singleAppFlowControlPublishTimestampMap_.find(callingUid);
115 if (singleAppFlowControlIter == singleAppFlowControlPublishTimestampMap_.end()) {
116 return ERR_OK;
117 }
118 NotificationAnalyticsUtil::RemoveExpired(*(singleAppFlowControlIter->second), now);
119 if (singleAppFlowControlIter->second->size() >= threshold_.maxCreateNumPerSecondPerApp) {
120 ANS_LOGE("SingleAppPublishFlowControl failed");
121 HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_3, EventBranchId::BRANCH_4)
122 .ErrorCode(ERR_ANS_OVER_MAX_ACTIVE_PERSECOND).Message("SingleAppPublishFlowControl failed");
123 if (record != nullptr) {
124 NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message);
125 }
126 return ERR_ANS_OVER_MAX_ACTIVE_PERSECOND;
127 }
128 return ERR_OK;
129 }
130
PublishRecordTimestamp(const std::shared_ptr<NotificationRecord> & record,std::chrono::system_clock::time_point now,const int32_t callingUid)131 void FlowControlService::PublishRecordTimestamp(const std::shared_ptr<NotificationRecord> &record,
132 std::chrono::system_clock::time_point now, const int32_t callingUid)
133 {
134 if (record->isThirdparty == true) {
135 std::lock_guard<std::mutex> lock(flowControlMutex_);
136 flowControlPublishTimestampList_.push_back(now);
137 } else {
138 std::lock_guard<std::mutex> lock(systemFlowControlMutex_);
139 systemFlowControlPublishTimestampList_.push_back(now);
140 }
141
142 std::lock_guard<std::mutex> lock(singleAppFlowControlMutex_);
143 auto singleAppFlowControlIter = singleAppFlowControlPublishTimestampMap_.find(callingUid);
144 if (singleAppFlowControlIter == singleAppFlowControlPublishTimestampMap_.end()) {
145 singleAppFlowControlPublishTimestampMap_[callingUid] =
146 std::make_shared<std::list<std::chrono::system_clock::time_point>>();
147 singleAppFlowControlIter = singleAppFlowControlPublishTimestampMap_.find(callingUid);
148 }
149 singleAppFlowControlIter->second->push_back(now);
150 }
151
PublishSingleAppFlowCtrlRemoveExpire(std::chrono::system_clock::time_point now)152 void FlowControlService::PublishSingleAppFlowCtrlRemoveExpire(std::chrono::system_clock::time_point now)
153 {
154 std::lock_guard<std::mutex> lock(singleAppFlowControlMutex_);
155 for (auto iter = singleAppFlowControlPublishTimestampMap_.begin();
156 iter != singleAppFlowControlPublishTimestampMap_.end();) {
157 auto latest = iter->second->back();
158 if (std::chrono::abs(now - latest) > SINGLE_APP_FLOW_CONTRL_EXPIRE_TIME) {
159 iter = singleAppFlowControlPublishTimestampMap_.erase(iter);
160 } else {
161 ++iter;
162 }
163 }
164 }
165
UpdateFlowCtrl(const std::shared_ptr<NotificationRecord> & record,const int32_t callingUid)166 ErrCode FlowControlService::UpdateFlowCtrl(const std::shared_ptr<NotificationRecord> &record,
167 const int32_t callingUid)
168 {
169 if (record->isNeedFlowCtrl == false) {
170 return ERR_OK;
171 }
172 std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
173 ErrCode result = ERR_OK;
174 result = UpdateSingleAppFlowCtrl(record, now, callingUid);
175 if (result != ERR_OK) {
176 return result;
177 }
178 result = UpdateGlobalFlowCtrl(record, now);
179 if (result != ERR_OK) {
180 return result;
181 }
182 UpdateRecordTimestamp(record, now, callingUid);
183 UpdateSingleAppFlowCtrlRemoveExpire(now);
184 return result;
185 }
186
UpdateGlobalFlowCtrl(const std::shared_ptr<NotificationRecord> & record,std::chrono::system_clock::time_point now)187 ErrCode FlowControlService::UpdateGlobalFlowCtrl(const std::shared_ptr<NotificationRecord> &record,
188 std::chrono::system_clock::time_point now)
189 {
190 ANS_LOGD("UpdateGlobalFlowCtrl size %{public}zu,%{public}zu",
191 flowControlUpdateTimestampList_.size(), systemFlowControlUpdateTimestampList_.size());
192 if (record->isThirdparty == true) {
193 // Third-part flow control
194 std::lock_guard<std::mutex> lock(flowControlMutex_);
195 NotificationAnalyticsUtil::RemoveExpired(flowControlUpdateTimestampList_, now);
196 if (flowControlUpdateTimestampList_.size() >= threshold_.maxUpdateNumPerSecond) {
197 ANS_LOGE("Third-part UpdateGlobalFlowCtrl failed");
198 HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_4, EventBranchId::BRANCH_3)
199 .ErrorCode(ERR_ANS_OVER_MAX_UPDATE_PERSECOND).Message("Third-part updateGlobalFlowCtrl failed");
200 if (record != nullptr) {
201 NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message);
202 }
203 return ERR_ANS_OVER_MAX_UPDATE_PERSECOND;
204 }
205 } else {
206 // System flow control
207 std::lock_guard<std::mutex> lock(systemFlowControlMutex_);
208 NotificationAnalyticsUtil::RemoveExpired(systemFlowControlUpdateTimestampList_, now);
209 if (systemFlowControlUpdateTimestampList_.size() >= threshold_.maxUpdateNumPerSecond) {
210 ANS_LOGE("System UpdateGlobalFlowCtrl failed");
211 HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_4, EventBranchId::BRANCH_4)
212 .ErrorCode(ERR_ANS_OVER_MAX_UPDATE_PERSECOND).Message("System updateGlobalFlowCtrl failed");
213 if (record != nullptr) {
214 NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message);
215 }
216 return ERR_ANS_OVER_MAX_UPDATE_PERSECOND;
217 }
218 }
219 return ERR_OK;
220 }
221
UpdateSingleAppFlowCtrl(const std::shared_ptr<NotificationRecord> & record,std::chrono::system_clock::time_point now,const int32_t callingUid)222 ErrCode FlowControlService::UpdateSingleAppFlowCtrl(const std::shared_ptr<NotificationRecord> &record,
223 std::chrono::system_clock::time_point now, const int32_t callingUid)
224 {
225 std::lock_guard<std::mutex> lock(singleAppFlowControlMutex_);
226 auto singleAppFlowControlIter = singleAppFlowControlUpdateTimestampMap_.find(callingUid);
227 if (singleAppFlowControlIter == singleAppFlowControlUpdateTimestampMap_.end()) {
228 return ERR_OK;
229 }
230 NotificationAnalyticsUtil::RemoveExpired(*(singleAppFlowControlIter->second), now);
231 if (singleAppFlowControlIter->second->size() >= threshold_.maxUpdateNumPerSecondPerApp) {
232 ANS_LOGE("SingleAppUpdateFlowControl failed");
233 HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_4, EventBranchId::BRANCH_5)
234 .ErrorCode(ERR_ANS_OVER_MAX_UPDATE_PERSECOND).Message("SingleAppUpdateFlowControl failed");
235 if (record != nullptr) {
236 NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message);
237 }
238 return ERR_ANS_OVER_MAX_UPDATE_PERSECOND;
239 }
240 return ERR_OK;
241 }
242
UpdateRecordTimestamp(const std::shared_ptr<NotificationRecord> & record,std::chrono::system_clock::time_point now,const int32_t callingUid)243 void FlowControlService::UpdateRecordTimestamp(const std::shared_ptr<NotificationRecord> &record,
244 std::chrono::system_clock::time_point now, const int32_t callingUid)
245 {
246 if (record->isThirdparty == true) {
247 std::lock_guard<std::mutex> lock(flowControlMutex_);
248 flowControlUpdateTimestampList_.push_back(now);
249 } else {
250 std::lock_guard<std::mutex> lock(systemFlowControlMutex_);
251 systemFlowControlUpdateTimestampList_.push_back(now);
252 }
253
254 std::lock_guard<std::mutex> lock(singleAppFlowControlMutex_);
255 auto singleAppFlowControlIter = singleAppFlowControlUpdateTimestampMap_.find(callingUid);
256 if (singleAppFlowControlIter == singleAppFlowControlUpdateTimestampMap_.end()) {
257 singleAppFlowControlUpdateTimestampMap_[callingUid] =
258 std::make_shared<std::list<std::chrono::system_clock::time_point>>();
259 singleAppFlowControlIter = singleAppFlowControlUpdateTimestampMap_.find(callingUid);
260 }
261 singleAppFlowControlIter->second->push_back(now);
262 }
263
UpdateSingleAppFlowCtrlRemoveExpire(std::chrono::system_clock::time_point now)264 void FlowControlService::UpdateSingleAppFlowCtrlRemoveExpire(std::chrono::system_clock::time_point now)
265 {
266 std::lock_guard<std::mutex> lock(singleAppFlowControlMutex_);
267 for (auto iter = singleAppFlowControlUpdateTimestampMap_.begin();
268 iter != singleAppFlowControlUpdateTimestampMap_.end();) {
269 auto latest = iter->second->back();
270 if (std::chrono::abs(now - latest) > SINGLE_APP_FLOW_CONTRL_EXPIRE_TIME) {
271 iter = singleAppFlowControlUpdateTimestampMap_.erase(iter);
272 } else {
273 ++iter;
274 }
275 }
276 }
277 } // namespace Notification
278 } // namespace OHOS