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 "event_read_handler.h"
17 
18 #include "event_write_handler.h"
19 #include "export_db_storage.h"
20 #include "ffrt.h"
21 #include "file_util.h"
22 #include "focused_event_util.h"
23 #include "hiview_logger.h"
24 #include "sys_event_dao.h"
25 
26 namespace OHOS {
27 namespace HiviewDFX {
28 DEFINE_LOG_TAG("HiView-EventReadHandler");
29 namespace {
30 constexpr int QUERY_LIMIT = 1000;
31 }
32 
HandleRequest(RequestPtr req)33 bool EventReadHandler::HandleRequest(RequestPtr req)
34 {
35     auto readReq = BaseRequest::DownCastTo<EventReadRequest>(req);
36     int64_t exportBeginSeq = readReq->beginSeq;
37     int64_t exportEndSeq = readReq->endSeq;
38     // split range
39     std::map<int64_t, int64_t> queryRanges;
40     while (exportBeginSeq + QUERY_LIMIT < exportEndSeq) {
41         queryRanges.emplace(exportBeginSeq, exportBeginSeq + QUERY_LIMIT);
42         exportBeginSeq += QUERY_LIMIT;
43     };
44     // query by range in order
45     queryRanges.emplace(exportBeginSeq, exportEndSeq);
46     for (const auto& queryRange : queryRanges) {
47         if (!QuerySysEventInRange(queryRange, readReq->eventList,
48             [this, &readReq] (bool isQueryCompleted) {
49                 auto writeReq = std::make_shared<EventWriteRequest>(readReq->moduleName, cachedSysEvents_,
50                     readReq->exportDir, isQueryCompleted, readReq->maxSize);
51                 auto ret = nextHandler_->HandleRequest(writeReq);
52                 cachedSysEvents_.clear();
53                 return ret;
54             })) {
55             return false;
56         }
57     }
58     return true;
59 }
60 
QuerySysEventInRange(const std::pair<int64_t,int64_t> & queryRange,const ExportEventList & eventList,QueryCallback queryCallback)61 bool EventReadHandler::QuerySysEventInRange(const std::pair<int64_t, int64_t>& queryRange,
62     const ExportEventList& eventList, QueryCallback queryCallback)
63 {
64     bool queryRet = true;
65     int retryCnt = 3; // retry 3 times if query failed
66     while (retryCnt > 0) {
67         if (QuerySysEvent(queryRange.first, queryRange.second, eventList, queryCallback)) {
68             break;
69         }
70         cachedSysEvents_.clear();
71         retryCnt--;
72         if (retryCnt == 0) {
73             HIVIEW_LOGE("failed to export events in range[%{public}" PRId64 ",%{public}" PRId64 ")",
74                 queryRange.first, queryRange.second);
75             queryRet = false;
76             break;
77         }
78         ffrt::this_task::sleep_for(std::chrono::seconds(1)); // sleep for 1 second before retry
79     }
80     if (eventExportedListener_ != nullptr) {
81         eventExportedListener_(queryRange.first, queryRange.second);
82     }
83     return queryRet;
84 }
85 
QuerySysEvent(const int64_t beginSeq,const int64_t endSeq,const ExportEventList & eventList,QueryCallback queryCallback)86 bool EventReadHandler::QuerySysEvent(const int64_t beginSeq, const int64_t endSeq, const ExportEventList& eventList,
87     QueryCallback queryCallback)
88 {
89     int64_t queryCnt = endSeq - beginSeq;
90     EventStore::Cond whereCond;
91     whereCond.And(EventStore::EventCol::SEQ, EventStore::Op::GE, beginSeq)
92         .And(EventStore::EventCol::SEQ, EventStore::Op::LT, endSeq);
93     std::shared_ptr<EventStore::SysEventQuery> query = nullptr;
94     int32_t queryRet = static_cast<int32_t>(EventStore::DbQueryStatus::SUCCEED);
95     bool isFirstPartialQuery = true;
96     auto iter = eventList.begin();
97     while (queryCnt > 0 && iter != eventList.end()) {
98         int64_t queryLimit = queryCnt < QUERY_LIMIT ? queryCnt : QUERY_LIMIT;
99         query = EventStore::SysEventDao::BuildQuery(iter->first, iter->second, 0, endSeq, beginSeq);
100         query->Where(whereCond);
101         query->Order(EventStore::EventCol::SEQ, true);
102         auto resultSet = query->Execute(queryLimit, { true, isFirstPartialQuery },
103             std::make_pair(EventStore::INNER_PROCESS_ID, ""),
104             [&queryRet] (EventStore::DbQueryStatus status) {
105                 queryRet = static_cast<int32_t>(status);
106             });
107         if (queryRet != static_cast<int32_t>(EventStore::DbQueryStatus::SUCCEED)) {
108             HIVIEW_LOGW("query control works when query with domain %{public}s, query ret is %{public}d",
109                 iter->first.c_str(), queryRet);
110         }
111         if (!HandleQueryResult(resultSet, queryCallback, queryLimit, queryCnt)) {
112             HIVIEW_LOGE("failed to export events with domain: %{public}s in range [%{public}"
113                 PRId64 ",%{publiuc}" PRId64 ")", iter->first.c_str(), beginSeq, endSeq);
114             return false;
115         }
116         iter++;
117         isFirstPartialQuery = false;
118     }
119     return queryCallback(true);
120 }
121 
HandleQueryResult(EventStore::ResultSet & resultSet,QueryCallback queryCallback,const int64_t queryLimit,int64_t & totalQueryCnt)122 bool EventReadHandler::HandleQueryResult(EventStore::ResultSet& resultSet, QueryCallback queryCallback,
123     const int64_t queryLimit, int64_t& totalQueryCnt)
124 {
125     EventStore::ResultSet::RecordIter iter;
126     while (resultSet.HasNext() && totalQueryCnt > 0) {
127         iter = resultSet.Next();
128         auto currentEventStr = iter->AsJsonStr();
129         if (currentEventStr.empty()) {
130             continue;
131         }
132         if (cachedSysEvents_.size() >= static_cast<size_t>(queryLimit) && !queryCallback(false)) {
133             HIVIEW_LOGE("failed to do query callback when handle query result");
134             return false;
135         }
136         EventVersion eventVersion {
137             .systemVersion = iter->GetSysVersion(),
138             .patchVersion = iter->GetPatchVersion()
139         };
140         auto item = std::make_shared<CachedEvent>(eventVersion, iter->domain_, iter->eventName_,
141             currentEventStr);
142         if (FocusedEventUtil::IsFocusedEvent(iter->domain_, iter->eventName_)) {
143             HIVIEW_LOGI("queried event: [%{public}s|%{public}s|%{public}" PRIu64 "]", iter->domain_.c_str(),
144                 iter->eventName_.c_str(), iter->happenTime_);
145         }
146         cachedSysEvents_.emplace_back(item);
147         totalQueryCnt--;
148     }
149     return true;
150 }
151 
SetEventExportedListener(EventExportedListener listener)152 void EventReadHandler::SetEventExportedListener(EventExportedListener listener)
153 {
154     eventExportedListener_ = listener;
155 }
156 } // HiviewDFX
157 } // OHOS