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