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 "hiview_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.isObject() || !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
ClearCachedEvents()220 void BaseEventQueryWrapper::ClearCachedEvents()
221 {
222 std::vector<std::u16string> tmpCachedEvents;
223 cachedEvents_.swap(tmpCachedEvents); // free memories allocated for cached events immediately
224 std::vector<int64_t> tmpCachedSeqs;
225 cachedSeqs_.swap(tmpCachedSeqs); // free memories allocated for cached events' sequence immediately
226 cachedEventTotalSize_ = 0;
227 }
228
FinishEventQuery(const OHOS::sptr<OHOS::HiviewDFX::IQueryBaseCallback> & callback,int32_t queryResult)229 void BaseEventQueryWrapper::FinishEventQuery(const OHOS::sptr<OHOS::HiviewDFX::IQueryBaseCallback>& callback,
230 int32_t queryResult)
231 {
232 if (callback == nullptr) {
233 return;
234 }
235 TransportCachedEvents(callback);
236 callback->OnComplete(queryResult, totalEventCnt_, maxSeq_);
237 }
238
TransportCachedEvents(const OHOS::sptr<OHOS::HiviewDFX::IQueryBaseCallback> & callback)239 void BaseEventQueryWrapper::TransportCachedEvents(const OHOS::sptr<OHOS::HiviewDFX::IQueryBaseCallback>& callback)
240 {
241 if (callback == nullptr) {
242 return;
243 }
244 if (!cachedEvents_.empty()) {
245 callback->OnQuery(cachedEvents_, cachedSeqs_);
246 ClearCachedEvents();
247 }
248 }
249
TransportSysEvent(OHOS::HiviewDFX::EventStore::ResultSet & result,const OHOS::sptr<OHOS::HiviewDFX::IQueryBaseCallback> & callback,std::pair<int64_t,int32_t> & details)250 void BaseEventQueryWrapper::TransportSysEvent(OHOS::HiviewDFX::EventStore::ResultSet& result,
251 const OHOS::sptr<OHOS::HiviewDFX::IQueryBaseCallback>& callback, std::pair<int64_t, int32_t>& details)
252 {
253 OHOS::HiviewDFX::EventStore::ResultSet::RecordIter iter;
254 while (result.HasNext() && argument_.maxEvents > 0) {
255 iter = result.Next();
256 auto eventJsonStr = iter->AsJsonStr();
257 if (eventJsonStr.empty()) {
258 continue;
259 }
260 std::u16string curJson = Str8ToStr16(eventJsonStr);
261 int32_t eventJsonSize = static_cast<int32_t>((curJson.size() + 1) * U16_CHAR_SIZE); // 1 for '\0'
262 if (eventJsonSize > MAX_TRANS_BUF) { // too large events, drop
263 details.second++;
264 continue;
265 }
266 if (cachedEvents_.size() >= static_cast<size_t> (queryLimit_) ||
267 cachedEventTotalSize_ + eventJsonSize >= MAX_TRANS_BUF) {
268 TransportCachedEvents(callback);
269 }
270 cachedEvents_.push_back(curJson);
271 cachedSeqs_.push_back(iter->GetSeq());
272 cachedEventTotalSize_ += eventJsonSize;
273 details.first++;
274 argument_.maxEvents--;
275 }
276 }
277
BuildCondition(const std::string & condition)278 void BaseEventQueryWrapper::BuildCondition(const std::string& condition)
279 {
280 if (condition.empty()) {
281 return;
282 }
283 EventStore::Cond extraCond;
284 if (parser_.ParseCondition(condition, extraCond)) {
285 query_->And(extraCond);
286 } else {
287 HIVIEW_LOGI("invalid query condition=%{public}s", condition.c_str());
288 }
289 }
290
SetQueryArgument(QueryArgument argument)291 void BaseEventQueryWrapper::SetQueryArgument(QueryArgument argument)
292 {
293 HIVIEW_LOGD("set argument: beginTime=%{public} " PRId64
294 ", endTime=%{public} " PRId64 ", maxEvents=%{public}d, fromSeq=%{public} " PRId64
295 ", toSeq=%{public} " PRId64 ".", argument.beginTime, argument.endTime,
296 argument.maxEvents, argument.fromSeq, argument.toSeq);
297 argument_ = argument;
298 }
299
GetQueryArgument()300 QueryArgument& BaseEventQueryWrapper::GetQueryArgument()
301 {
302 return argument_;
303 }
304
SetIsFirstPartialQuery(bool isFirstPartialQuery)305 void BaseEventQueryWrapper::SetIsFirstPartialQuery(bool isFirstPartialQuery)
306 {
307 isFirstPartialQuery_ = isFirstPartialQuery;
308 }
309
GetSysEventQueryRules()310 std::vector<SysEventQueryRule>& BaseEventQueryWrapper::GetSysEventQueryRules()
311 {
312 return queryRules_;
313 }
314
GetMaxSequence() const315 int64_t BaseEventQueryWrapper::GetMaxSequence() const
316 {
317 return maxSeq_;
318 }
319
GetEventTotalCount() const320 int64_t BaseEventQueryWrapper::GetEventTotalCount() const
321 {
322 return totalEventCnt_;
323 }
324
IsValid() const325 bool BaseEventQueryWrapper::IsValid() const
326 {
327 return !queryRules_.empty();
328 }
329
IsQueryComplete() const330 bool BaseEventQueryWrapper::IsQueryComplete() const
331 {
332 return argument_.maxEvents <= 0;
333 }
334
SetEventTotalCount(int64_t totalCount)335 void BaseEventQueryWrapper::SetEventTotalCount(int64_t totalCount)
336 {
337 HIVIEW_LOGD("SetEventTotalCount: %{public}" PRId64 ".", totalCount);
338 totalEventCnt_ = totalCount;
339 }
340
NeedStartNextQuery()341 bool BaseEventQueryWrapper::NeedStartNextQuery()
342 {
343 // first query
344 if (isFirstPartialQuery_) {
345 return !queryRules_.empty();
346 }
347
348 // continue query execution based on previous query rule
349 int64_t queryEventCnt = transportedEventCnt_ + ignoredEventCnt_;
350 if (queryEventCnt > 0 && queryEventCnt >= queryLimit_) {
351 return true;
352 }
353
354 // try to build query with next query rule
355 if (!queryRules_.empty()) {
356 queryRules_.erase(queryRules_.begin());
357 }
358 query_ = nullptr;
359 return !queryRules_.empty();
360 }
361
BuildQuery()362 void TimeStampEventQueryWrapper::BuildQuery()
363 {
364 if (query_ != nullptr) {
365 return;
366 }
367 argument_.beginTime = argument_.beginTime < 0 ? 0 : argument_.beginTime;
368 argument_.endTime = argument_.endTime < 0 ? std::numeric_limits<int64_t>::max() : argument_.endTime;
369 argument_.maxEvents = argument_.maxEvents < 0 ? std::numeric_limits<int32_t>::max() : argument_.maxEvents;
370 queryLimit_ = argument_.maxEvents < MAX_QUERY_EVENTS ? argument_.maxEvents : MAX_QUERY_EVENTS;
371 EventStore::Cond whereCond;
372 whereCond.And(EventStore::EventCol::TS, EventStore::Op::GE, argument_.beginTime)
373 .And(EventStore::EventCol::TS, EventStore::Op::LT, argument_.endTime);
374 auto queryRule = queryRules_.front();
375 query_ = EventStore::SysEventDao::BuildQuery(queryRule.domain, queryRule.eventList,
376 queryRule.eventType, INVALID_SEQ, INVALID_SEQ);
377 query_->Where(whereCond);
378 BuildCondition(queryRule.condition);
379 Order();
380 }
381
SetMaxSequence(int64_t maxSeq)382 void TimeStampEventQueryWrapper::SetMaxSequence(int64_t maxSeq)
383 {
384 maxSeq_ = maxSeq;
385 }
386
Order()387 void TimeStampEventQueryWrapper::Order()
388 {
389 if (query_ == nullptr) {
390 return;
391 }
392 query_->Order(EventStore::EventCol::TS, true);
393 }
394
BuildQuery()395 void SeqEventQueryWrapper::BuildQuery()
396 {
397 if (query_ != nullptr) {
398 return;
399 }
400 auto offset = argument_.toSeq > argument_.fromSeq ? (argument_.toSeq - argument_.fromSeq) : 0;
401 queryLimit_ = offset < MAX_QUERY_EVENTS ? offset : MAX_QUERY_EVENTS;
402 EventStore::Cond whereCond;
403 whereCond.And(EventStore::EventCol::SEQ, EventStore::Op::GE, argument_.fromSeq)
404 .And(EventStore::EventCol::SEQ, EventStore::Op::LT, argument_.toSeq);
405 auto queryRule = queryRules_.front();
406 query_ = EventStore::SysEventDao::BuildQuery(queryRule.domain, queryRule.eventList,
407 queryRule.eventType, argument_.toSeq, argument_.fromSeq);
408 query_->Where(whereCond);
409 BuildCondition(queryRule.condition);
410 Order();
411 }
412
SetMaxSequence(int64_t maxSeq)413 void SeqEventQueryWrapper::SetMaxSequence(int64_t maxSeq)
414 {
415 maxSeq_ = maxSeq;
416 HIVIEW_LOGD("argument.toSeq is %{public}" PRId64 ", maxSeq is %{public}" PRId64 ".",
417 argument_.toSeq, maxSeq_);
418 argument_.toSeq = std::min(argument_.toSeq, maxSeq_);
419 }
420
Order()421 void SeqEventQueryWrapper::Order()
422 {
423 if (query_ == nullptr) {
424 return;
425 }
426 query_->Order(EventStore::EventCol::SEQ, true);
427 }
428
Append(const std::string & domain,const std::string & eventName,uint32_t eventType,const std::string & extraInfo)429 EventQueryWrapperBuilder& EventQueryWrapperBuilder::Append(const std::string& domain, const std::string& eventName,
430 uint32_t eventType, const std::string& extraInfo)
431 {
432 HIVIEW_LOGD("builder append domain=%{public}s, name=%{public}s, type=%{public}u, condition=%{public}s.",
433 domain.c_str(), eventName.c_str(), eventType, extraInfo.c_str());
434 auto& queryRules = queryWrapper_->GetSysEventQueryRules();
435 // if the query rules are the same group, combine them
436 if (any_of(queryRules.begin(), queryRules.end(), [&domain, &eventName, &eventType, &extraInfo] (auto& rule) {
437 if (rule.domain == domain && eventType == rule.eventType && extraInfo == rule.condition) {
438 auto& eventList = rule.eventList;
439 if (eventName.empty()) {
440 eventList.clear();
441 } else {
442 eventList.push_back(eventName);
443 }
444 return true;
445 }
446 return false;
447 })) {
448 return *shared_from_this();
449 }
450 // otherwise, create a new query rule
451 std::vector<std::string> eventList;
452 if (!eventName.empty()) {
453 eventList.push_back(eventName);
454 }
455 queryRules.push_back(SysEventQueryRule(domain, eventList, RuleType::WHOLE_WORD, eventType, extraInfo));
456 return *shared_from_this();
457 }
458
IsValid() const459 bool EventQueryWrapperBuilder::IsValid() const
460 {
461 return queryWrapper_->IsValid();
462 }
463
Build() const464 std::shared_ptr<BaseEventQueryWrapper> EventQueryWrapperBuilder::Build() const
465 {
466 return queryWrapper_;
467 }
468
CreateQueryWrapperByArgument(const QueryArgument & argument,std::shared_ptr<EventStore::SysEventQuery> query)469 std::shared_ptr<BaseEventQueryWrapper> EventQueryWrapperBuilder::CreateQueryWrapperByArgument(
470 const QueryArgument& argument, std::shared_ptr<EventStore::SysEventQuery> query)
471 {
472 if (argument.fromSeq != INVALID_SEQ && argument.toSeq != INVALID_SEQ && argument.fromSeq < argument.toSeq) {
473 return std::make_shared<SeqEventQueryWrapper>(query);
474 }
475 return std::make_shared<TimeStampEventQueryWrapper>(query);
476 }
477
InitQueryWrapper(const QueryArgument & argument)478 void EventQueryWrapperBuilder::InitQueryWrapper(const QueryArgument& argument)
479 {
480 HIVIEW_LOGD("init link list of query wrapper with argument: beginTime=%{public} " PRId64
481 ", endTime=%{public} " PRId64 ", maxEvents=%{public}d, fromSeq=%{public} " PRId64
482 ", toSeq=%{public} " PRId64 ".", argument.beginTime, argument.endTime,
483 argument.maxEvents, argument.fromSeq, argument.toSeq);
484 queryWrapper_ = CreateQueryWrapperByArgument(argument, nullptr);
485 queryWrapper_->SetQueryArgument(argument);
486 }
487 } // namespace HiviewDFX
488 } // namespace OHOS
489