• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (c) 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 "call_reporter.h"
17 
18 #include <cinttypes>
19 #include "datashare_log.h"
20 #include "datashare_string_utils.h"
21 
22 namespace OHOS {
23 namespace DataShare {
24 // count the func call and check if the funcCount exceeds the threshold
Count(const std::string & funcName,const std::string & uri)25 bool DataShareCallReporter::Count(const std::string &funcName, const std::string &uri)
26 {
27     int overCount = 0;
28     int64_t firstCallTime = 0;
29     // isOverThreshold means that the call count of the funcName over threshold, true means exceeded
30     // if exceeds the threshold, the current 30s time window will return 'true'
31     // and the funcCount will be reseted in the next 30s time window
32     bool isOverThreshold = false;
33 
34     UpdateCallCounts(funcName, overCount, firstCallTime, isOverThreshold);
35 
36     int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
37         std::chrono::system_clock::now().time_since_epoch()).count();
38     if (overCount > 0) {
39         LOG_WARN("Call the threshold, func: %{public}s, first:%{public}" PRIi64 "ms, now:%{public}" PRIi64
40             "ms, uri:%{public}s", funcName.c_str(), firstCallTime, now, DataShareStringUtils::Anonymous(uri).c_str());
41     }
42     if (overCount > 1) {
43         LOG_WARN("Call too frequently, func: %{public}s, first:%{public}" PRIi64 "ms, now:%{public}" PRIi64
44             "ms, uri:%{public}s", funcName.c_str(), firstCallTime, now, DataShareStringUtils::Anonymous(uri).c_str());
45     }
46     // error log for over threshold and only print once
47     if (isOverThreshold) {
48         callCounts_.Compute(funcName, [funcName, now, uri](auto &key, CallInfo &callInfo) {
49             if (!callInfo.logPrintFlag) {
50                 int64_t thresholdStartTime = std::chrono::duration_cast<std::chrono::milliseconds>(
51                     callInfo.startTime.time_since_epoch()).count();
52 
53                 callInfo.logPrintFlag = true;
54                 LOG_ERROR("Over threshold, func: %{public}s, first:%{public}" PRIi64 "ms, now:%{public}" PRIi64
55                     "ms, uri:%{public}s", funcName.c_str(), thresholdStartTime, now,
56                     DataShareStringUtils::Anonymous(uri).c_str());
57             }
58             return true;
59         });
60     }
61     return isOverThreshold;
62 }
63 
UpdateCallCounts(const std::string & funcName,int & overCount,int64_t & firstCallTime,bool & isOverThreshold)64 void DataShareCallReporter::UpdateCallCounts(const std::string &funcName, int &overCount, int64_t &firstCallTime,
65     bool &isOverThreshold)
66 {
67     callCounts_.Compute(funcName, [&overCount, &firstCallTime, &isOverThreshold](auto &key, CallInfo &callInfo) {
68         int callCount = callInfo.count;
69         // totalCallCount is the call count of funcName in 30s
70         int totalCallCount = callInfo.totalCount;
71         std::chrono::system_clock::time_point nowTimeStamp = std::chrono::system_clock::now();
72         int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(
73             nowTimeStamp.time_since_epoch()).count();
74         if (callCount == 0) {
75             callInfo.firstTime = nowTimeStamp;
76         }
77         if (++callCount % RESET_COUNT_THRESHOLD == 0) {
78             int64_t first = std::chrono::duration_cast<std::chrono::milliseconds>(
79                 callInfo.firstTime.time_since_epoch()).count();
80             ++overCount;
81             firstCallTime = first;
82             if (now - first <= TIME_THRESHOLD.count()) {
83                 ++overCount;
84             }
85             callCount = 0;
86         }
87         callInfo.count = callCount;
88 
89         // update access control count
90         if (totalCallCount == 0) {
91             callInfo.startTime = nowTimeStamp;
92         }
93         int64_t thresholdStartTime = std::chrono::duration_cast<std::chrono::milliseconds>(
94             callInfo.startTime.time_since_epoch()).count();
95         // reset callInfo when time >= 30s
96         if (now - thresholdStartTime >= TIME_THRESHOLD.count()) {
97             callInfo.startTime = nowTimeStamp;
98             callInfo.totalCount = 0;
99             callInfo.logPrintFlag = false;
100             totalCallCount = 0;
101         }
102         // isOverThreshold return true when callCount >= 3000 in 30s
103         if (++totalCallCount >= ACCESS_COUNT_THRESHOLD) {
104             isOverThreshold = true;
105         }
106         callInfo.totalCount = totalCallCount;
107         return true;
108     });
109 }
110 } // namespace DataShare
111 } // namespace OHOS