• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &timestamps = 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 &timestamp : 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