1 /*
2 * Copyright (c) 2025 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 "rate_limiter.h"
17
18 #include "hilog_tag_wrapper.h"
19
20 namespace OHOS {
21 namespace AAFwk {
22 namespace {
23 constexpr int64_t CLEAN_INTERVAL_MS = 60000; // 60s
24 constexpr int64_t EXTENSION_LIMIT_INTERVAL_MS = 1000; // 1s
25 constexpr int32_t EXTENSION_MAX_LIMIT = 20;
26 constexpr int64_t REPORT_LIMIT_INTERVAL_MS = 5000; // 5s
27 constexpr int32_t REPORT_MAX_LIMIT = 1;
28 }
29
GetInstance()30 RateLimiter &RateLimiter::GetInstance()
31 {
32 static RateLimiter instance;
33 return instance;
34 }
35
CheckExtensionLimit(int32_t uid)36 bool RateLimiter::CheckExtensionLimit(int32_t uid)
37 {
38 CleanCallMap();
39 return CheckSingleLimit(uid, extensionCallMap_, extensionCallMapLock_, EXTENSION_LIMIT_INTERVAL_MS,
40 EXTENSION_MAX_LIMIT);
41 }
42
CheckReportLimit(int32_t uid)43 bool RateLimiter::CheckReportLimit(int32_t uid)
44 {
45 return CheckSingleLimit(uid, reportCallMap_, reportCallMapLock_, REPORT_LIMIT_INTERVAL_MS, REPORT_MAX_LIMIT);
46 }
47
CheckSingleLimit(int32_t uid,std::unordered_map<int32_t,std::vector<int64_t>> & callMap,std::mutex & mapLock,int64_t limitInterval,int32_t maxLimit)48 bool RateLimiter::CheckSingleLimit(int32_t uid, std::unordered_map<int32_t, std::vector<int64_t>> &callMap,
49 std::mutex &mapLock, int64_t limitInterval, int32_t maxLimit)
50 {
51 int64_t currentTimeMillis = CurrentTimeMillis();
52 int64_t timeBefore = currentTimeMillis - limitInterval;
53 std::lock_guard<std::mutex> guard(mapLock);
54 auto ×tamps = callMap[uid];
55
56 auto it = std::lower_bound(timestamps.begin(), timestamps.end(), timeBefore);
57 timestamps.erase(timestamps.begin(), it);
58
59 if (timestamps.size() >= static_cast<size_t>(maxLimit)) {
60 return true;
61 }
62
63 timestamps.emplace_back(currentTimeMillis);
64 return false;
65 }
66
CleanCallMap()67 void RateLimiter::CleanCallMap()
68 {
69 {
70 std::lock_guard<std::mutex> guard(lastCleanTimeMillisLock_);
71 auto currentTimeMillis = CurrentTimeMillis();
72 if (currentTimeMillis - lastCleanTimeMillis_ < CLEAN_INTERVAL_MS) {
73 return;
74 }
75 lastCleanTimeMillis_ = currentTimeMillis;
76 }
77 CleanSingleCallMap(extensionCallMap_, extensionCallMapLock_, EXTENSION_LIMIT_INTERVAL_MS);
78 CleanSingleCallMap(reportCallMap_, reportCallMapLock_, REPORT_LIMIT_INTERVAL_MS);
79 }
80
CleanSingleCallMap(std::unordered_map<int32_t,std::vector<int64_t>> & callMap,std::mutex & mapLock,int64_t limitInterval)81 void RateLimiter::CleanSingleCallMap(std::unordered_map<int32_t, std::vector<int64_t>> &callMap, std::mutex &mapLock,
82 int64_t limitInterval)
83 {
84 int64_t timeBefore = CurrentTimeMillis() - limitInterval;
85 std::lock_guard<std::mutex> guard(mapLock);
86 auto it = callMap.begin();
87 while (it != callMap.end()) {
88 bool allExpired = true;
89 for (const auto ×tamp : it->second) {
90 if (timestamp >= timeBefore) {
91 allExpired = false;
92 break;
93 }
94 }
95
96 if (allExpired) {
97 it = callMap.erase(it);
98 } else {
99 ++it;
100 }
101 }
102 TAG_LOGI(AAFwkTag::SERVICE_EXT, "CleanSingleCallMap end, size:%{public}zu", callMap.size());
103 }
104
CurrentTimeMillis()105 int64_t RateLimiter::CurrentTimeMillis()
106 {
107 auto now = std::chrono::steady_clock::now().time_since_epoch();
108 return std::chrono::duration_cast<std::chrono::milliseconds>(now).count();
109 }
110 } // namespace AAFwk
111 } // namespace OHOS
112