• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "event_query_wrapper_builder.h"
17 
18 #include <algorithm>
19 #include <cinttypes>
20 
21 #include "common_utils.h"
22 #include "data_publisher.h"
23 #include "hiview_event_common.h"
24 #include "ipc_skeleton.h"
25 #include "logger.h"
26 #include "ret_code.h"
27 #include "string_ex.h"
28 
29 using namespace OHOS::HiviewDFX::BaseEventSpace;
30 
31 namespace OHOS {
32 namespace HiviewDFX {
33 DEFINE_LOG_TAG("HiView-SysEventQueryBuilder");
34 namespace {
35 constexpr char LOGIC_AND_COND[] = "and";
36 constexpr int64_t INVALID_SEQ = -1;
37 constexpr int64_t TRANS_DEFAULT_CNT = 0;
38 constexpr int32_t IGNORED_DEFAULT_CNT = 0;
39 constexpr int MAX_QUERY_EVENTS = 1000; // The maximum number of queries is 1000 at one time
40 constexpr int MAX_TRANS_BUF = 1024 * 770;  // Max transmission at one time: 384KB * 2 + 2KB for extra fields
41 constexpr size_t U16_CHAR_SIZE = sizeof(char16_t);
42 
GetCallingProcessInfo()43 EventStore::QueryProcessInfo GetCallingProcessInfo()
44 {
45     std::string processName = CommonUtils::GetProcNameByPid(IPCSkeleton::GetCallingPid());
46     processName = processName.empty() ? "unknown" : processName;
47     return std::make_pair(IPCSkeleton::GetCallingPid(), processName);
48 }
49 }
50 
ParseCondition(const std::string & condStr,EventStore::Cond & condition)51 bool ConditionParser::ParseCondition(const std::string& condStr, EventStore::Cond& condition)
52 {
53     if (extraInfoCondCache.empty() || extraInfoCondCache.find(condStr) == extraInfoCondCache.end()) {
54         EventStore::Cond cond;
55         if (ParseQueryCondition(condStr, cond)) {
56             extraInfoCondCache[condStr] = cond;
57         }
58     }
59     auto iter = extraInfoCondCache.find(condStr);
60     if (iter != extraInfoCondCache.end()) {
61         condition = iter->second;
62         return true;
63     }
64     return false;
65 }
66 
ParseJsonString(const Json::Value & root,const std::string & key,std::string & value)67 bool ConditionParser::ParseJsonString(const Json::Value& root, const std::string& key, std::string& value)
68 {
69     if (!root.isMember(key.c_str()) || !root[key.c_str()].isString()) {
70         return false;
71     }
72     value = root[key].asString();
73     return true;
74 }
75 
GetOpEnum(const std::string & op)76 EventStore::Op ConditionParser::GetOpEnum(const std::string& op)
77 {
78     const std::unordered_map<std::string, EventStore::Op> opMap = {
79         { "=", EventStore::Op::EQ },
80         { "<", EventStore::Op::LT },
81         { ">", EventStore::Op::GT },
82         { "<=", EventStore::Op::LE },
83         { ">=", EventStore::Op::GE },
84     };
85     return opMap.find(op) == opMap.end() ? EventStore::Op::NONE : opMap.at(op);
86 }
87 
SpliceConditionByLogic(EventStore::Cond & condition,const EventStore::Cond & subCond,const std::string & logic)88 void ConditionParser::SpliceConditionByLogic(EventStore::Cond& condition, const EventStore::Cond& subCond,
89     const std::string& logic)
90 {
91     if (logic == LOGIC_AND_COND) {
92         condition.And(subCond);
93     }
94 }
95 
ParseLogicCondition(const Json::Value & root,const std::string & logic,EventStore::Cond & condition)96 bool ConditionParser::ParseLogicCondition(const Json::Value& root, const std::string& logic,
97     EventStore::Cond& condition)
98 {
99     if (!root.isMember(logic) || !root[logic].isArray()) {
100         HIVIEW_LOGE("ParseLogicCondition err1.");
101         return false;
102     }
103 
104     EventStore::Cond subCondition;
105     for (size_t i = 0; i < root[logic].size(); ++i) {
106         auto cond = root[logic][static_cast<int>(i)];
107         std::string param;
108         if (!ParseJsonString(cond, "param", param) || param.empty()) {
109             return false;
110         }
111         std::string op;
112         if (!ParseJsonString(cond, "op", op) || GetOpEnum(op) == EventStore::Op::NONE) {
113             return false;
114         }
115         const char valueKey[] = "value";
116         if (!cond.isMember(valueKey)) {
117             return false;
118         }
119         if (cond[valueKey].isString()) {
120             std::string value = cond[valueKey].asString();
121             SpliceConditionByLogic(subCondition, EventStore::Cond(param, GetOpEnum(op), value), logic);
122         } else if (cond[valueKey].isInt64()) {
123             int64_t value = cond[valueKey].asInt64();
124             SpliceConditionByLogic(subCondition, EventStore::Cond(param, GetOpEnum(op), value), logic);
125         } else {
126             return false;
127         }
128     }
129     condition.And(subCondition);
130     return true;
131 }
132 
ParseAndCondition(const Json::Value & root,EventStore::Cond & condition)133 bool ConditionParser::ParseAndCondition(const Json::Value& root, EventStore::Cond& condition)
134 {
135     return ParseLogicCondition(root, LOGIC_AND_COND, condition);
136 }
137 
ParseQueryConditionJson(const Json::Value & root,EventStore::Cond & condition)138 bool ConditionParser::ParseQueryConditionJson(const Json::Value& root, EventStore::Cond& condition)
139 {
140     const char condKey[] = "condition";
141     if (!root.isMember(condKey) || !root[condKey].isObject()) {
142         return false;
143     }
144     bool res = false;
145     if (ParseAndCondition(root[condKey], condition)) {
146         res = true;
147     }
148     return res;
149 }
150 
ParseQueryCondition(const std::string & condStr,EventStore::Cond & condition)151 bool ConditionParser::ParseQueryCondition(const std::string& condStr, EventStore::Cond& condition)
152 {
153     if (condStr.empty()) {
154         return false;
155     }
156     Json::Value root;
157     Json::CharReaderBuilder jsonRBuilder;
158     Json::CharReaderBuilder::strictMode(&jsonRBuilder.settings_);
159     std::unique_ptr<Json::CharReader> const reader(jsonRBuilder.newCharReader());
160     JSONCPP_STRING errs;
161     if (!reader->parse(condStr.data(), condStr.data() + condStr.size(), &root, &errs)) {
162         HIVIEW_LOGE("failed to parse condition string: %{public}s.", condStr.c_str());
163         return false;
164     }
165     std::string version;
166     if (!ParseJsonString(root, "version", version)) {
167         HIVIEW_LOGE("failed to parser version.");
168         return false;
169     }
170     const std::set<std::string> versionSet = { "V1" }; // set is used for future expansion
171     if (versionSet.find(version) == versionSet.end()) {
172         HIVIEW_LOGE("version is invalid.");
173         return false;
174     }
175     if (!ParseQueryConditionJson(root, condition)) {
176         HIVIEW_LOGE("condition is invalid.");
177         return false;
178     }
179     return true;
180 }
181 
Query(const OHOS::sptr<OHOS::HiviewDFX::IQueryBaseCallback> & eventQueryCallback,int32_t & queryResult)182 void BaseEventQueryWrapper::Query(const OHOS::sptr<OHOS::HiviewDFX::IQueryBaseCallback>& eventQueryCallback,
183     int32_t& queryResult)
184 {
185     if (eventQueryCallback == nullptr) {
186         queryResult = ERR_LISTENER_NOT_EXIST;
187         return;
188     }
189 
190     while (!IsQueryComplete() && NeedStartNextQuery()) {
191         BuildQuery();
192         HIVIEW_LOGD("execute query: beginTime=%{public}" PRId64
193             ", endTime=%{public}" PRId64 ", maxEvents=%{public}d, fromSeq=%{public}" PRId64
194             ", toSeq=%{public}" PRId64 ", queryLimit=%{public}d.", argument_.beginTime, argument_.endTime,
195             argument_.maxEvents, argument_.fromSeq, argument_.toSeq, queryLimit_);
196         auto resultSet = query_->Execute(queryLimit_, { false, isFirstPartialQuery_ }, GetCallingProcessInfo(),
197             [&queryResult] (EventStore::DbQueryStatus status) {
198                 std::unordered_map<EventStore::DbQueryStatus, int32_t> statusToCode {
199                     { EventStore::DbQueryStatus::CONCURRENT, ERR_TOO_MANY_CONCURRENT_QUERIES },
200                     { EventStore::DbQueryStatus::OVER_TIME, ERR_QUERY_OVER_TIME },
201                     { EventStore::DbQueryStatus::OVER_LIMIT, ERR_QUERY_OVER_LIMIT },
202                     { EventStore::DbQueryStatus::TOO_FREQENTLY, ERR_QUERY_TOO_FREQUENTLY },
203                 };
204                 queryResult = statusToCode[status];
205             });
206         if (queryResult != IPC_CALL_SUCCEED) {
207             FinishEventQuery(eventQueryCallback, queryResult);
208             return;
209         }
210         auto details = std::make_pair(TRANS_DEFAULT_CNT, IGNORED_DEFAULT_CNT);
211         TransportSysEvent(resultSet, eventQueryCallback, details);
212         transportedEventCnt_ = details.first;
213         totalEventCnt_ += transportedEventCnt_;
214         ignoredEventCnt_ = details.second;
215         SetIsFirstPartialQuery(false);
216     }
217     FinishEventQuery(eventQueryCallback, queryResult);
218 }
219 
FinishEventQuery(const OHOS::sptr<OHOS::HiviewDFX::IQueryBaseCallback> & callback,int32_t queryResult)220 void BaseEventQueryWrapper::FinishEventQuery(const OHOS::sptr<OHOS::HiviewDFX::IQueryBaseCallback>& callback,
221     int32_t queryResult)
222 {
223     if (callback == nullptr) {
224         return;
225     }
226     if (!cachedEvents_.empty()) {
227         callback->OnQuery(cachedEvents_, cachedSeqs_);
228         cachedEvents_.clear();
229         cachedSeqs_.clear();
230         cachedEventTotalSize_ = 0;
231     }
232     callback->OnComplete(queryResult, totalEventCnt_, maxSeq_);
233 }
234 
TransportCachedEvents(const OHOS::sptr<OHOS::HiviewDFX::IQueryBaseCallback> & callback)235 void BaseEventQueryWrapper::TransportCachedEvents(const OHOS::sptr<OHOS::HiviewDFX::IQueryBaseCallback>& callback)
236 {
237     if (callback == nullptr) {
238         return;
239     }
240     callback->OnQuery(cachedEvents_, cachedSeqs_);
241     cachedEvents_.clear();
242     cachedSeqs_.clear();
243     cachedEventTotalSize_ = 0;
244 }
245 
TransportSysEvent(OHOS::HiviewDFX::EventStore::ResultSet & result,const OHOS::sptr<OHOS::HiviewDFX::IQueryBaseCallback> & callback,std::pair<int64_t,int32_t> & details)246 void BaseEventQueryWrapper::TransportSysEvent(OHOS::HiviewDFX::EventStore::ResultSet& result,
247     const OHOS::sptr<OHOS::HiviewDFX::IQueryBaseCallback>& callback, std::pair<int64_t, int32_t>& details)
248 {
249     std::vector<std::u16string> events;
250     std::vector<int64_t> seqs;
251     OHOS::HiviewDFX::EventStore::ResultSet::RecordIter iter;
252     int32_t transTotalJsonSize = 0;
253     while (result.HasNext() && argument_.maxEvents > 0) {
254         iter = result.Next();
255         auto eventJsonStr = iter->AsJsonStr();
256         if (eventJsonStr.empty()) {
257             continue;
258         }
259         std::u16string curJson = Str8ToStr16(eventJsonStr);
260         int32_t eventJsonSize = static_cast<int32_t>((curJson.size() + 1) * U16_CHAR_SIZE); // 1 for '\0'
261         if (eventJsonSize > MAX_TRANS_BUF) { // too large events, drop
262             details.second++;
263             continue;
264         }
265         // the number of returned events may be greater than the limit
266         if (eventJsonSize + transTotalJsonSize > MAX_TRANS_BUF || events.size() >=
267             static_cast<size_t>(queryLimit_)) {
268             TransportCachedEvents(callback);
269             callback->OnQuery(events, seqs);
270             events.clear();
271             seqs.clear();
272             transTotalJsonSize = 0;
273         }
274         events.push_back(curJson);
275         seqs.push_back(iter->GetSeq());
276         details.first++;
277         transTotalJsonSize += eventJsonSize;
278         argument_.maxEvents--;
279     }
280     if (cachedEvents_.size() + events.size() > MAX_QUERY_EVENTS ||
281         cachedEventTotalSize_ + transTotalJsonSize > MAX_TRANS_BUF) {
282         TransportCachedEvents(callback);
283     }
284     cachedEvents_.insert(cachedEvents_.end(), events.begin(), events.end());
285     cachedSeqs_.insert(cachedSeqs_.end(), seqs.begin(), seqs.end());
286     cachedEventTotalSize_ += transTotalJsonSize;
287 }
288 
BuildCondition(const std::string & condition)289 void BaseEventQueryWrapper::BuildCondition(const std::string& condition)
290 {
291     if (condition.empty()) {
292         return;
293     }
294     EventStore::Cond extraCond;
295     if (parser_.ParseCondition(condition, extraCond)) {
296         query_->And(extraCond);
297     } else {
298         HIVIEW_LOGI("invalid query condition=%{public}s", condition.c_str());
299     }
300 }
301 
SetQueryArgument(QueryArgument argument)302 void BaseEventQueryWrapper::SetQueryArgument(QueryArgument argument)
303 {
304     HIVIEW_LOGD("set argument: beginTime=%{public} " PRId64
305         ", endTime=%{public} " PRId64 ", maxEvents=%{public}d, fromSeq=%{public} " PRId64
306         ", toSeq=%{public} " PRId64 ".", argument.beginTime, argument.endTime,
307         argument.maxEvents, argument.fromSeq, argument.toSeq);
308     argument_ = argument;
309 }
310 
GetQueryArgument()311 QueryArgument& BaseEventQueryWrapper::GetQueryArgument()
312 {
313     return argument_;
314 }
315 
SetIsFirstPartialQuery(bool isFirstPartialQuery)316 void BaseEventQueryWrapper::SetIsFirstPartialQuery(bool isFirstPartialQuery)
317 {
318     isFirstPartialQuery_ = isFirstPartialQuery;
319 }
320 
GetSysEventQueryRules()321 std::vector<SysEventQueryRule>& BaseEventQueryWrapper::GetSysEventQueryRules()
322 {
323     return queryRules_;
324 }
325 
GetMaxSequence() const326 int64_t BaseEventQueryWrapper::GetMaxSequence() const
327 {
328     return maxSeq_;
329 }
330 
GetEventTotalCount() const331 int64_t BaseEventQueryWrapper::GetEventTotalCount() const
332 {
333     return totalEventCnt_;
334 }
335 
IsValid() const336 bool BaseEventQueryWrapper::IsValid() const
337 {
338     return !queryRules_.empty();
339 }
340 
IsQueryComplete() const341 bool BaseEventQueryWrapper::IsQueryComplete() const
342 {
343     return argument_.maxEvents <= 0;
344 }
345 
SetEventTotalCount(int64_t totalCount)346 void BaseEventQueryWrapper::SetEventTotalCount(int64_t totalCount)
347 {
348     HIVIEW_LOGD("SetEventTotalCount: %{public}" PRId64 ".", totalCount);
349     totalEventCnt_ = totalCount;
350 }
351 
NeedStartNextQuery()352 bool BaseEventQueryWrapper::NeedStartNextQuery()
353 {
354     // first query
355     if (isFirstPartialQuery_) {
356         return !queryRules_.empty();
357     }
358 
359     // continue query execution based on previous query rule
360     int64_t queryEventCnt = transportedEventCnt_ + ignoredEventCnt_;
361     if (queryEventCnt > 0 && queryEventCnt >= queryLimit_) {
362         return true;
363     }
364 
365     // try to build query with next query rule
366     if (!queryRules_.empty()) {
367         queryRules_.erase(queryRules_.begin());
368     }
369     query_ = nullptr;
370     return !queryRules_.empty();
371 }
372 
BuildQuery()373 void TimeStampEventQueryWrapper::BuildQuery()
374 {
375     if (query_ != nullptr) {
376         return;
377     }
378     argument_.beginTime = argument_.beginTime < 0 ? 0 : argument_.beginTime;
379     argument_.endTime = argument_.endTime < 0 ? std::numeric_limits<int64_t>::max() : argument_.endTime;
380     argument_.maxEvents = argument_.maxEvents < 0 ? std::numeric_limits<int32_t>::max() : argument_.maxEvents;
381     queryLimit_ = argument_.maxEvents < MAX_QUERY_EVENTS ? argument_.maxEvents : MAX_QUERY_EVENTS;
382     EventStore::Cond whereCond;
383     whereCond.And(EventStore::EventCol::TS, EventStore::Op::GE, argument_.beginTime)
384         .And(EventStore::EventCol::TS, EventStore::Op::LT, argument_.endTime);
385     auto queryRule = queryRules_.front();
386     query_ = EventStore::SysEventDao::BuildQuery(queryRule.domain, queryRule.eventList,
387         queryRule.eventType, INVALID_SEQ, INVALID_SEQ);
388     query_->Where(whereCond);
389     BuildCondition(queryRule.condition);
390     Order();
391 }
392 
SetMaxSequence(int64_t maxSeq)393 void TimeStampEventQueryWrapper::SetMaxSequence(int64_t maxSeq)
394 {
395     maxSeq_ = maxSeq;
396 }
397 
Order()398 void TimeStampEventQueryWrapper::Order()
399 {
400     if (query_ == nullptr) {
401         return;
402     }
403     query_->Order(EventStore::EventCol::TS, true);
404 }
405 
BuildQuery()406 void SeqEventQueryWrapper::BuildQuery()
407 {
408     if (query_ != nullptr) {
409         return;
410     }
411     auto offset = argument_.toSeq > argument_.fromSeq ? (argument_.toSeq - argument_.fromSeq) : 0;
412     queryLimit_ = offset < MAX_QUERY_EVENTS ? offset : MAX_QUERY_EVENTS;
413     EventStore::Cond whereCond;
414     whereCond.And(EventStore::EventCol::SEQ, EventStore::Op::GE, argument_.fromSeq)
415             .And(EventStore::EventCol::SEQ, EventStore::Op::LT, argument_.toSeq);
416     auto queryRule = queryRules_.front();
417     query_ = EventStore::SysEventDao::BuildQuery(queryRule.domain, queryRule.eventList,
418         queryRule.eventType, argument_.toSeq, argument_.fromSeq);
419     query_->Where(whereCond);
420     BuildCondition(queryRule.condition);
421     Order();
422 }
423 
SetMaxSequence(int64_t maxSeq)424 void SeqEventQueryWrapper::SetMaxSequence(int64_t maxSeq)
425 {
426     maxSeq_ = maxSeq;
427     HIVIEW_LOGD("argument.toSeq is %{public}" PRId64 ", maxSeq is %{public}" PRId64 ".",
428         argument_.toSeq, maxSeq_);
429     argument_.toSeq = std::min(argument_.toSeq, maxSeq_);
430 }
431 
Order()432 void SeqEventQueryWrapper::Order()
433 {
434     if (query_ == nullptr) {
435         return;
436     }
437     query_->Order(EventStore::EventCol::SEQ, true);
438 }
439 
Append(const std::string & domain,const std::string & eventName,uint32_t eventType,const std::string & extraInfo)440 EventQueryWrapperBuilder& EventQueryWrapperBuilder::Append(const std::string& domain, const std::string& eventName,
441     uint32_t eventType, const std::string& extraInfo)
442 {
443     HIVIEW_LOGD("builder append domain=%{public}s, name=%{public}s, type=%{public}u, condition=%{public}s.",
444         domain.c_str(), eventName.c_str(), eventType, extraInfo.c_str());
445     auto& queryRules = queryWrapper_->GetSysEventQueryRules();
446     // if the query rules are the same group, combine them
447     if (any_of(queryRules.begin(), queryRules.end(), [&domain, &eventName, &eventType, &extraInfo] (auto& rule) {
448         if (rule.domain == domain && eventType == rule.eventType && extraInfo == rule.condition) {
449             auto& eventList = rule.eventList;
450             if (eventName.empty()) {
451                 eventList.clear();
452             } else {
453                 eventList.push_back(eventName);
454             }
455             return true;
456         }
457         return false;
458     })) {
459         return *shared_from_this();
460     }
461     // otherwise, create a new query rule
462     std::vector<std::string> eventList;
463     if (!eventName.empty()) {
464         eventList.push_back(eventName);
465     }
466     queryRules.push_back(SysEventQueryRule(domain, eventList, RuleType::WHOLE_WORD, eventType, extraInfo));
467     return *shared_from_this();
468 }
469 
IsValid() const470 bool EventQueryWrapperBuilder::IsValid() const
471 {
472     return queryWrapper_->IsValid();
473 }
474 
Build() const475 std::shared_ptr<BaseEventQueryWrapper> EventQueryWrapperBuilder::Build() const
476 {
477     return queryWrapper_;
478 }
479 
CreateQueryWrapperByArgument(const QueryArgument & argument,std::shared_ptr<EventStore::SysEventQuery> query)480 std::shared_ptr<BaseEventQueryWrapper> EventQueryWrapperBuilder::CreateQueryWrapperByArgument(
481     const QueryArgument& argument, std::shared_ptr<EventStore::SysEventQuery> query)
482 {
483     if (argument.fromSeq != INVALID_SEQ && argument.toSeq != INVALID_SEQ && argument.fromSeq < argument.toSeq) {
484         return std::make_shared<SeqEventQueryWrapper>(query);
485     }
486     return std::make_shared<TimeStampEventQueryWrapper>(query);
487 }
488 
InitQueryWrapper(const QueryArgument & argument)489 void EventQueryWrapperBuilder::InitQueryWrapper(const QueryArgument& argument)
490 {
491     HIVIEW_LOGD("init link list of query wrapper with argument: beginTime=%{public} " PRId64
492         ", endTime=%{public} " PRId64 ", maxEvents=%{public}d, fromSeq=%{public} " PRId64
493         ", toSeq=%{public} " PRId64 ".", argument.beginTime, argument.endTime,
494         argument.maxEvents, argument.fromSeq, argument.toSeq);
495     queryWrapper_ = CreateQueryWrapperByArgument(argument, nullptr);
496     queryWrapper_->SetQueryArgument(argument);
497 }
498 } // namespace HiviewDFX
499 } // namespace OHOS
500