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