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 result = PublishFlowCtrl(record, callingUid);
43 } else {
44 result = UpdateFlowCtrl(record, callingUid);
45 }
46
47 return result;
48 }
49
PublishFlowCtrl(const std::shared_ptr<NotificationRecord> & record,const int32_t callingUid)50 ErrCode FlowControlService::PublishFlowCtrl(const std::shared_ptr<NotificationRecord> &record,
51 const int32_t callingUid)
52 {
53 if (record->isNeedFlowCtrl == false) {
54 return ERR_OK;
55 }
56 std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
57 ErrCode result = ERR_OK;
58 result = PublishSingleAppFlowCtrl(record, now, callingUid);
59 if (result != ERR_OK) {
60 return result;
61 }
62 result = PublishGlobalFlowCtrl(record, now);
63 if (result != ERR_OK) {
64 return result;
65 }
66 PublishRecordTimestamp(record, now, callingUid);
67 PublishSingleAppFlowCtrlRemoveExpire(now);
68 return ERR_OK;
69 }
70
PublishGlobalFlowCtrl(const std::shared_ptr<NotificationRecord> & record,std::chrono::system_clock::time_point now)71 ErrCode FlowControlService::PublishGlobalFlowCtrl(const std::shared_ptr<NotificationRecord> &record,
72 std::chrono::system_clock::time_point now)
73 {
74 ANS_LOGD("PublishGlobalFlowCtrl size %{public}zu,%{public}zu",
75 flowControlPublishTimestampList_.size(), systemFlowControlPublishTimestampList_.size());
76 if (record->isThirdparty == true) {
77 // Third-part flow control
78 std::lock_guard<std::mutex> lock(flowControlMutex_);
79 NotificationAnalyticsUtil::RemoveExpired(flowControlPublishTimestampList_, now);
80 if (flowControlPublishTimestampList_.size() >= threshold_.maxCreateNumPerSecond) {
81 ANS_LOGE("Third-part PublishGlobalFlowCtrl failed");
82 HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_3, EventBranchId::BRANCH_2)
83 .ErrorCode(ERR_ANS_OVER_MAX_ACTIVE_PERSECOND).Message("Third-part PublishGlobalFlowCtrl failed");
84 if (record != nullptr) {
85 NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message);
86 }
87 return ERR_ANS_OVER_MAX_ACTIVE_PERSECOND;
88 }
89 } else {
90 // System flow control
91 std::lock_guard<std::mutex> lock(systemFlowControlMutex_);
92 NotificationAnalyticsUtil::RemoveExpired(systemFlowControlPublishTimestampList_, now);
93 if (systemFlowControlPublishTimestampList_.size() >= threshold_.maxCreateNumPerSecond) {
94 ANS_LOGE("System PublishGlobalFlowCtrl failed");
95 HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_3, EventBranchId::BRANCH_3)
96 .ErrorCode(ERR_ANS_OVER_MAX_ACTIVE_PERSECOND).Message("System PublishGlobalFlowCtrl failed");
97 if (record != nullptr) {
98 NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message);
99 }
100 return ERR_ANS_OVER_MAX_ACTIVE_PERSECOND;
101 }
102 }
103 return ERR_OK;
104 }
105
PublishSingleAppFlowCtrl(const std::shared_ptr<NotificationRecord> & record,std::chrono::system_clock::time_point now,const int32_t callingUid)106 ErrCode FlowControlService::PublishSingleAppFlowCtrl(const std::shared_ptr<NotificationRecord> &record,
107 std::chrono::system_clock::time_point now, const int32_t callingUid)
108 {
109 std::lock_guard<std::mutex> lock(singleAppFlowControlMutex_);
110 auto singleAppFlowControlIter = singleAppFlowControlPublishTimestampMap_.find(callingUid);
111 if (singleAppFlowControlIter == singleAppFlowControlPublishTimestampMap_.end()) {
112 return ERR_OK;
113 }
114 NotificationAnalyticsUtil::RemoveExpired(*(singleAppFlowControlIter->second), now);
115 if (singleAppFlowControlIter->second->size() >= threshold_.maxCreateNumPerSecondPerApp) {
116 ANS_LOGE("SingleAppPublishFlowControl failed");
117 HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_3, EventBranchId::BRANCH_4)
118 .ErrorCode(ERR_ANS_OVER_MAX_ACTIVE_PERSECOND).Message("SingleAppPublishFlowControl failed");
119 if (record != nullptr) {
120 NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message);
121 }
122 return ERR_ANS_OVER_MAX_ACTIVE_PERSECOND;
123 }
124 return ERR_OK;
125 }
126
PublishRecordTimestamp(const std::shared_ptr<NotificationRecord> & record,std::chrono::system_clock::time_point now,const int32_t callingUid)127 void FlowControlService::PublishRecordTimestamp(const std::shared_ptr<NotificationRecord> &record,
128 std::chrono::system_clock::time_point now, const int32_t callingUid)
129 {
130 if (record->isThirdparty == true) {
131 std::lock_guard<std::mutex> lock(flowControlMutex_);
132 flowControlPublishTimestampList_.push_back(now);
133 } else {
134 std::lock_guard<std::mutex> lock(systemFlowControlMutex_);
135 systemFlowControlPublishTimestampList_.push_back(now);
136 }
137
138 std::lock_guard<std::mutex> lock(singleAppFlowControlMutex_);
139 auto singleAppFlowControlIter = singleAppFlowControlPublishTimestampMap_.find(callingUid);
140 if (singleAppFlowControlIter == singleAppFlowControlPublishTimestampMap_.end()) {
141 singleAppFlowControlPublishTimestampMap_[callingUid] =
142 std::make_shared<std::list<std::chrono::system_clock::time_point>>();
143 singleAppFlowControlIter = singleAppFlowControlPublishTimestampMap_.find(callingUid);
144 }
145 singleAppFlowControlIter->second->push_back(now);
146 }
147
PublishSingleAppFlowCtrlRemoveExpire(std::chrono::system_clock::time_point now)148 void FlowControlService::PublishSingleAppFlowCtrlRemoveExpire(std::chrono::system_clock::time_point now)
149 {
150 std::lock_guard<std::mutex> lock(singleAppFlowControlMutex_);
151 for (auto iter = singleAppFlowControlPublishTimestampMap_.begin();
152 iter != singleAppFlowControlPublishTimestampMap_.end();) {
153 auto latest = iter->second->back();
154 if (std::chrono::abs(now - latest) > SINGLE_APP_FLOW_CONTRL_EXPIRE_TIME) {
155 iter = singleAppFlowControlPublishTimestampMap_.erase(iter);
156 } else {
157 ++iter;
158 }
159 }
160 }
161
UpdateFlowCtrl(const std::shared_ptr<NotificationRecord> & record,const int32_t callingUid)162 ErrCode FlowControlService::UpdateFlowCtrl(const std::shared_ptr<NotificationRecord> &record,
163 const int32_t callingUid)
164 {
165 if (record->isNeedFlowCtrl == false) {
166 return ERR_OK;
167 }
168 std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
169 ErrCode result = ERR_OK;
170 result = UpdateSingleAppFlowCtrl(record, now, callingUid);
171 if (result != ERR_OK) {
172 return result;
173 }
174 result = UpdateGlobalFlowCtrl(record, now);
175 if (result != ERR_OK) {
176 return result;
177 }
178 UpdateRecordTimestamp(record, now, callingUid);
179 UpdateSingleAppFlowCtrlRemoveExpire(now);
180 return result;
181 }
182
UpdateGlobalFlowCtrl(const std::shared_ptr<NotificationRecord> & record,std::chrono::system_clock::time_point now)183 ErrCode FlowControlService::UpdateGlobalFlowCtrl(const std::shared_ptr<NotificationRecord> &record,
184 std::chrono::system_clock::time_point now)
185 {
186 ANS_LOGD("UpdateGlobalFlowCtrl size %{public}zu,%{public}zu",
187 flowControlUpdateTimestampList_.size(), systemFlowControlUpdateTimestampList_.size());
188 if (record->isThirdparty == true) {
189 // Third-part flow control
190 std::lock_guard<std::mutex> lock(flowControlMutex_);
191 NotificationAnalyticsUtil::RemoveExpired(flowControlUpdateTimestampList_, now);
192 if (flowControlUpdateTimestampList_.size() >= threshold_.maxUpdateNumPerSecond) {
193 ANS_LOGE("Third-part UpdateGlobalFlowCtrl failed");
194 HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_4, EventBranchId::BRANCH_3)
195 .ErrorCode(ERR_ANS_OVER_MAX_UPDATE_PERSECOND).Message("Third-part updateGlobalFlowCtrl failed");
196 if (record != nullptr) {
197 NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message);
198 }
199 return ERR_ANS_OVER_MAX_UPDATE_PERSECOND;
200 }
201 } else {
202 // System flow control
203 std::lock_guard<std::mutex> lock(systemFlowControlMutex_);
204 NotificationAnalyticsUtil::RemoveExpired(systemFlowControlUpdateTimestampList_, now);
205 if (systemFlowControlUpdateTimestampList_.size() >= threshold_.maxUpdateNumPerSecond) {
206 ANS_LOGE("System UpdateGlobalFlowCtrl failed");
207 HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_4, EventBranchId::BRANCH_4)
208 .ErrorCode(ERR_ANS_OVER_MAX_UPDATE_PERSECOND).Message("System updateGlobalFlowCtrl failed");
209 if (record != nullptr) {
210 NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message);
211 }
212 return ERR_ANS_OVER_MAX_UPDATE_PERSECOND;
213 }
214 }
215 return ERR_OK;
216 }
217
UpdateSingleAppFlowCtrl(const std::shared_ptr<NotificationRecord> & record,std::chrono::system_clock::time_point now,const int32_t callingUid)218 ErrCode FlowControlService::UpdateSingleAppFlowCtrl(const std::shared_ptr<NotificationRecord> &record,
219 std::chrono::system_clock::time_point now, const int32_t callingUid)
220 {
221 std::lock_guard<std::mutex> lock(singleAppFlowControlMutex_);
222 auto singleAppFlowControlIter = singleAppFlowControlUpdateTimestampMap_.find(callingUid);
223 if (singleAppFlowControlIter == singleAppFlowControlUpdateTimestampMap_.end()) {
224 return ERR_OK;
225 }
226 NotificationAnalyticsUtil::RemoveExpired(*(singleAppFlowControlIter->second), now);
227 if (singleAppFlowControlIter->second->size() >= threshold_.maxUpdateNumPerSecondPerApp) {
228 ANS_LOGE("SingleAppUpdateFlowControl failed");
229 HaMetaMessage message = HaMetaMessage(EventSceneId::SCENE_4, EventBranchId::BRANCH_5)
230 .ErrorCode(ERR_ANS_OVER_MAX_UPDATE_PERSECOND).Message("SingleAppUpdateFlowControl failed");
231 if (record != nullptr) {
232 NotificationAnalyticsUtil::ReportPublishFailedEvent(record->request, message);
233 }
234 return ERR_ANS_OVER_MAX_UPDATE_PERSECOND;
235 }
236 return ERR_OK;
237 }
238
UpdateRecordTimestamp(const std::shared_ptr<NotificationRecord> & record,std::chrono::system_clock::time_point now,const int32_t callingUid)239 void FlowControlService::UpdateRecordTimestamp(const std::shared_ptr<NotificationRecord> &record,
240 std::chrono::system_clock::time_point now, const int32_t callingUid)
241 {
242 if (record->isThirdparty == true) {
243 std::lock_guard<std::mutex> lock(flowControlMutex_);
244 flowControlUpdateTimestampList_.push_back(now);
245 } else {
246 std::lock_guard<std::mutex> lock(systemFlowControlMutex_);
247 systemFlowControlUpdateTimestampList_.push_back(now);
248 }
249
250 std::lock_guard<std::mutex> lock(singleAppFlowControlMutex_);
251 auto singleAppFlowControlIter = singleAppFlowControlUpdateTimestampMap_.find(callingUid);
252 if (singleAppFlowControlIter == singleAppFlowControlUpdateTimestampMap_.end()) {
253 singleAppFlowControlUpdateTimestampMap_[callingUid] =
254 std::make_shared<std::list<std::chrono::system_clock::time_point>>();
255 singleAppFlowControlIter = singleAppFlowControlUpdateTimestampMap_.find(callingUid);
256 }
257 singleAppFlowControlIter->second->push_back(now);
258 }
259
UpdateSingleAppFlowCtrlRemoveExpire(std::chrono::system_clock::time_point now)260 void FlowControlService::UpdateSingleAppFlowCtrlRemoveExpire(std::chrono::system_clock::time_point now)
261 {
262 std::lock_guard<std::mutex> lock(singleAppFlowControlMutex_);
263 for (auto iter = singleAppFlowControlUpdateTimestampMap_.begin();
264 iter != singleAppFlowControlUpdateTimestampMap_.end();) {
265 auto latest = iter->second->back();
266 if (std::chrono::abs(now - latest) > SINGLE_APP_FLOW_CONTRL_EXPIRE_TIME) {
267 iter = singleAppFlowControlUpdateTimestampMap_.erase(iter);
268 } else {
269 ++iter;
270 }
271 }
272 }
273 } // namespace Notification
274 } // namespace OHOS