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