1 /*
2 * Copyright (c) 2022 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 "sys_event_query_wrapper.h"
17
18 #include "data_query.h"
19 #include "running_status_logger.h"
20
21 namespace OHOS {
22 namespace HiviewDFX {
23 namespace {
24 constexpr char SPACE_CONCAT[] = " ";
25 constexpr int DEFAULT_CONCURRENT_CNT = 0;
GetCurTime()26 time_t GetCurTime()
27 {
28 time_t current;
29 (void)time(¤t);
30 return current;
31 }
32
GetSubStrCount(const std::string & content,const std::string & sub)33 int GetSubStrCount(const std::string& content, const std::string& sub)
34 {
35 int cnt = 0;
36 if (content.empty() || sub.empty()) {
37 return cnt;
38 }
39 size_t start = 0;
40 while ((start = content.find(sub, start)) != std::string::npos) {
41 start += sub.size();
42 cnt++;
43 }
44 return cnt;
45 }
46 }
47
48 namespace EventStore {
LogTooManyQueryRules(const std::string sql)49 void QueryStatusLogUtil::LogTooManyQueryRules(const std::string sql)
50 {
51 std::string info { "PLUGIN TOOMANYQUERYCONDITION SQL=" };
52 info.append(sql);
53 Logging(info);
54 }
55
LogTooManyConcurrentQueries(const int limit,bool innerQuery)56 void QueryStatusLogUtil::LogTooManyConcurrentQueries(const int limit, bool innerQuery)
57 {
58 std::string info { innerQuery ? "HIVIEW TOOMANYCOCURRENTQUERIES " : "TOOMANYCOCURRENTQUERIES " };
59 info.append("COUNT > ");
60 info.append(std::to_string(limit));
61 Logging(info);
62 }
63
LogQueryOverTime(time_t costTime,const std::string sql,bool innerQuery)64 void QueryStatusLogUtil::LogQueryOverTime(time_t costTime, const std::string sql, bool innerQuery)
65 {
66 std::string info { innerQuery ? "PLUGIN QUERYOVERTIME " : "QUERYOVERTIME " };
67 info.append(std::to_string(costTime)).append(SPACE_CONCAT).append("SQL=").append(sql);
68 Logging(info);
69 }
70
LogQueryCountOverLimit(const int32_t queryCount,const std::string & sql,bool innerQuery)71 void QueryStatusLogUtil::LogQueryCountOverLimit(const int32_t queryCount, const std::string& sql,
72 bool innerQuery)
73 {
74 std::string info { innerQuery ? "PLUGIN QUERYCOUNTOVERLIMIT " : "QUERYCOUNTOVERLIMIT " };
75 info.append(std::to_string(queryCount)).append(SPACE_CONCAT).append("SQL=").append(sql);
76 Logging(info);
77 }
78
LogQueryTooFrequently(const std::string & sql,const std::string & processName,bool innerQuery)79 void QueryStatusLogUtil::LogQueryTooFrequently(const std::string& sql, const std::string& processName,
80 bool innerQuery)
81 {
82 std::string info { innerQuery ? "HIVIEW QUERYTOOFREQUENTLY " : "QUERYTOOFREQUENTLY " };
83 if (!processName.empty()) {
84 info.append(processName).append(SPACE_CONCAT);
85 }
86 info.append("SQL=").append(sql);
87 Logging(info);
88 }
89
Logging(const std::string & detail)90 void QueryStatusLogUtil::Logging(const std::string& detail)
91 {
92 std::string info = RunningStatusLogger::GetInstance().FormatTimeStamp();
93 info.append(SPACE_CONCAT).append(detail);
94 RunningStatusLogger::GetInstance().Log(info);
95 }
96
97 ConcurrentQueries SysEventQueryWrapper::concurrentQueries_;
98 LastQueries SysEventQueryWrapper::lastQueries_;
99 std::mutex SysEventQueryWrapper::lastQueriesMutex_;
100 std::mutex SysEventQueryWrapper::concurrentQueriesMutex_;
Execute(int limit,DbQueryTag tag,QueryProcessInfo callerInfo,DbQueryCallback queryCallback)101 ResultSet SysEventQueryWrapper::Execute(int limit, DbQueryTag tag, QueryProcessInfo callerInfo,
102 DbQueryCallback queryCallback)
103 {
104 DataQuery dataQuery;
105 SysEventQuery::BuildDataQuery(dataQuery, limit);
106 ResultSet resultSet;
107 int queryErrorCode = -1;
108 (void)IsConditionCntValid(dataQuery, tag);
109 if (!IsQueryCntLimitValid(dataQuery, tag, limit, queryCallback) ||
110 !IsConcurrentQueryCntValid(GetDbFile(), tag, queryCallback) ||
111 !IsQueryFrequenceValid(dataQuery, tag, GetDbFile(), callerInfo, queryCallback)) {
112 resultSet.Set(queryErrorCode, false);
113 return resultSet;
114 }
115 time_t beforeExecute = GetCurTime();
116 IncreaseConcurrentCnt(GetDbFile(), tag);
117 resultSet = SysEventQuery::Execute(limit, tag, callerInfo, queryCallback);
118 DecreaseConcurrentCnt(GetDbFile(), tag);
119 time_t afterExecute = GetCurTime();
120 if (!IsQueryCostTimeValid(dataQuery, tag, beforeExecute, afterExecute, queryCallback)) {
121 resultSet.Set(queryErrorCode, false);
122 return resultSet;
123 }
124 if (queryCallback != nullptr) {
125 queryCallback(DbQueryStatus::SUCCEED);
126 }
127 return resultSet;
128 }
129
IsConditionCntValid(const DataQuery & query,const DbQueryTag & tag)130 bool SysEventQueryWrapper::IsConditionCntValid(const DataQuery& query, const DbQueryTag& tag)
131 {
132 int conditionCntLimit = 8;
133 if (tag.isInnerQuery && GetSubStrCount(query.ToString(), "domain_=") > conditionCntLimit) {
134 QueryStatusLogUtil::LogTooManyQueryRules(query.ToString());
135 return false;
136 }
137 return true;
138 }
139
IsQueryCntLimitValid(const DataQuery & query,const DbQueryTag & tag,const int limit,const DbQueryCallback & callback)140 bool SysEventQueryWrapper::IsQueryCntLimitValid(const DataQuery& query, const DbQueryTag& tag, const int limit,
141 const DbQueryCallback& callback)
142 {
143 int queryLimit = tag.isInnerQuery ? 50 : 1000;
144 if (limit > queryLimit) {
145 QueryStatusLogUtil::LogQueryCountOverLimit(limit, query.ToString(), tag.isInnerQuery);
146 if (callback != nullptr) {
147 callback(DbQueryStatus::OVER_LIMIT);
148 }
149 return tag.isInnerQuery;
150 }
151 return true;
152 }
153
IsQueryCostTimeValid(const DataQuery & query,const DbQueryTag & tag,const time_t before,const time_t after,const DbQueryCallback & callback)154 bool SysEventQueryWrapper::IsQueryCostTimeValid(const DataQuery& query, const DbQueryTag& tag, const time_t before,
155 const time_t after, const DbQueryCallback& callback)
156 {
157 time_t maxQueryTime = 20;
158 time_t duration = after - before;
159 if (duration < maxQueryTime) {
160 return true;
161 }
162 QueryStatusLogUtil::LogQueryOverTime(duration, query.ToString(), tag.isInnerQuery);
163 if (callback != nullptr) {
164 callback(DbQueryStatus::OVER_TIME);
165 }
166 return tag.isInnerQuery;
167 }
168
IsConcurrentQueryCntValid(const std::string & dbFile,const DbQueryTag & tag,const DbQueryCallback & callback)169 bool SysEventQueryWrapper::IsConcurrentQueryCntValid(const std::string& dbFile, const DbQueryTag& tag,
170 const DbQueryCallback& callback)
171 {
172 std::lock_guard<std::mutex> lock(concurrentQueriesMutex_);
173 auto iter = concurrentQueries_.find(dbFile);
174 if (iter != concurrentQueries_.end()) {
175 auto& concurrentQueryCnt = tag.isInnerQuery ? iter->second.first : iter->second.second;
176 int conCurrentQueryCntLimit = 4;
177 if (concurrentQueryCnt < conCurrentQueryCntLimit) {
178 return true;
179 }
180 QueryStatusLogUtil::LogTooManyConcurrentQueries(conCurrentQueryCntLimit, tag.isInnerQuery);
181 if (callback != nullptr) {
182 callback(DbQueryStatus::CONCURRENT);
183 }
184 return tag.isInnerQuery;
185 }
186 concurrentQueries_[dbFile] = { DEFAULT_CONCURRENT_CNT, DEFAULT_CONCURRENT_CNT };
187 return true;
188 }
189
IsQueryFrequenceValid(const DataQuery & query,const DbQueryTag & tag,const std::string & dbFile,const QueryProcessInfo & processInfo,const DbQueryCallback & callback)190 bool SysEventQueryWrapper::IsQueryFrequenceValid(const DataQuery& query, const DbQueryTag& tag,
191 const std::string& dbFile, const QueryProcessInfo& processInfo, const DbQueryCallback& callback)
192 {
193 std::lock_guard<std::mutex> lock(lastQueriesMutex_);
194 if (!tag.needFrequenceCheck) {
195 return true;
196 }
197 time_t current;
198 (void)time(¤t);
199 auto execIter = lastQueries_.find(dbFile);
200 auto queryProcessId = processInfo.first;
201 if (execIter == lastQueries_.end()) {
202 lastQueries_[dbFile].insert(std::make_pair(queryProcessId, current));
203 return true;
204 }
205 auto processIter = execIter->second.find(queryProcessId);
206 if (processIter == execIter->second.end()) {
207 execIter->second[queryProcessId] = current;
208 return true;
209 }
210 time_t queryFrequent = 1;
211 if (abs(current - processIter->second) > queryFrequent) {
212 execIter->second[queryProcessId] = current;
213 return true;
214 }
215 QueryStatusLogUtil::LogQueryTooFrequently(query.ToString(), processInfo.second, tag.isInnerQuery);
216 if (callback != nullptr) {
217 callback(DbQueryStatus::TOO_FREQENTLY);
218 }
219 return tag.isInnerQuery;
220 }
221
IncreaseConcurrentCnt(const std::string & dbFile,const DbQueryTag & tag)222 void SysEventQueryWrapper::IncreaseConcurrentCnt(const std::string& dbFile, const DbQueryTag& tag)
223 {
224 std::lock_guard<std::mutex> lock(concurrentQueriesMutex_);
225 auto iter = concurrentQueries_.find(dbFile);
226 if (iter != concurrentQueries_.end()) {
227 auto& concurrentQueryCnt = tag.isInnerQuery ? iter->second.first : iter->second.second;
228 concurrentQueryCnt++;
229 return;
230 }
231 concurrentQueries_[dbFile] = std::make_pair(DEFAULT_CONCURRENT_CNT, DEFAULT_CONCURRENT_CNT);
232 }
233
DecreaseConcurrentCnt(const std::string & dbFile,const DbQueryTag & tag)234 void SysEventQueryWrapper::DecreaseConcurrentCnt(const std::string& dbFile, const DbQueryTag& tag)
235 {
236 std::lock_guard<std::mutex> lock(concurrentQueriesMutex_);
237 auto iter = concurrentQueries_.find(dbFile);
238 if (iter != concurrentQueries_.end()) {
239 auto& concurrentQueryCnt = tag.isInnerQuery ? iter->second.first : iter->second.second;
240 concurrentQueryCnt--;
241 }
242 }
243 } // namespace EventStore
244 } // namespace HiviewDFX
245 } // namespace OHOS
246