1 /*
2 * Copyright (c) 2023-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 #include "sys_event_doc_reader.h"
16
17 #include <cinttypes>
18
19 #include "hiview_logger.h"
20 #include "securec.h"
21 #include "string_util.h"
22 #include "sys_event_query.h"
23
24 namespace OHOS {
25 namespace HiviewDFX {
26 namespace EventStore {
27 DEFINE_LOG_TAG("HiView-SysEventDocReader");
28 using OHOS::HiviewDFX::EventRaw::RawData;
29 namespace {
30 template<typename T>
GetNegativeNum(T num)31 int32_t GetNegativeNum(T num)
32 {
33 return static_cast<int32_t>(~(num - 1)); // 1 for binary conversion
34 }
35
36 template<typename T>
ReadValueAndReset(std::ifstream & in,T & value)37 void ReadValueAndReset(std::ifstream& in, T& value)
38 {
39 in.read(reinterpret_cast<char*>(&value), sizeof(T));
40 in.seekg(GetNegativeNum(sizeof(T)), std::ios::cur);
41 }
42 }
43
SysEventDocReader(const std::string & path)44 SysEventDocReader::SysEventDocReader(const std::string& path): EventDocReader(path)
45 {
46 Init(path);
47 }
48
~SysEventDocReader()49 SysEventDocReader::~SysEventDocReader()
50 {
51 if (in_.is_open()) {
52 in_.close();
53 }
54 }
55
Init(const std::string & path)56 void SysEventDocReader::Init(const std::string& path)
57 {
58 in_.open(path, std::ios::binary);
59
60 // get domain, name and level from file path
61 InitEventInfo(path);
62
63 // get file size and data format version
64 if (in_.is_open()) {
65 auto curPos = in_.tellg();
66 in_.seekg(0, std::ios::end);
67 fileSize_ = in_.tellg();
68 in_.seekg(curPos, std::ios::beg);
69
70 dataFmtVersion_ = ContentReader::ReadFmtVersion(in_);
71 }
72 }
73
InitEventInfo(const std::string & path)74 void SysEventDocReader::InitEventInfo(const std::string& path)
75 {
76 std::vector<std::string> dirNames;
77 StringUtil::SplitStr(path, "/", dirNames);
78 constexpr size_t domainOffset = 2;
79 if (dirNames.size() < domainOffset) {
80 HIVIEW_LOGW("invalid size=%{public}zu of dir names", dirNames.size());
81 return;
82 }
83
84 // init domain
85 const std::string domainStr = dirNames[dirNames.size() - domainOffset];
86 if (memcpy_s(info_.domain, MAX_DOMAIN_LEN, domainStr.c_str(), domainStr.length()) != EOK) {
87 HIVIEW_LOGE("failed to copy domain to EventInfo");
88 return;
89 }
90 std::string file = dirNames.back();
91 std::vector<std::string> fileNames;
92 StringUtil::SplitStr(file, "-", fileNames);
93 if (fileNames.size() != FILE_NAME_SPLIT_SIZE) {
94 HIVIEW_LOGW("invalid size=%{public}zu of file names", fileNames.size());
95 return;
96 }
97
98 // init name
99 const std::string nameStr = fileNames[EVENT_NAME_INDEX];
100 if (memcpy_s(info_.name, MAX_EVENT_NAME_LEN, nameStr.c_str(), nameStr.length()) != EOK) {
101 HIVIEW_LOGE("failed to copy name to EventInfo");
102 return;
103 }
104
105 // init level
106 info_.level = fileNames[EVENT_LEVEL_INDEX];
107 }
108
Read(const DocQuery & query,EntryQueue & entries,int & num)109 int SysEventDocReader::Read(const DocQuery& query, EntryQueue& entries, int& num)
110 {
111 auto saveFunc = [this, &query, &entries, &num](uint8_t* content, uint32_t& contentSize) {
112 if (content == nullptr) {
113 return false;
114 }
115 TryToAddEntry(content, contentSize, query, entries, num);
116 return true;
117 };
118 return Read(saveFunc);
119 }
120
Read(ReadCallback callback)121 int SysEventDocReader::Read(ReadCallback callback)
122 {
123 // read the header
124 DocHeader header;
125 if (auto ret = ReadHeader(header); ret != DOC_STORE_SUCCESS) {
126 return ret;
127 }
128
129 if (!IsValidHeader(header)) {
130 return DOC_STORE_ERROR_INVALID;
131 }
132
133 // set event tag if have
134 if (info_.tag.empty() && strlen(header.tag) != 0) {
135 info_.tag = header.tag;
136 }
137
138 // set page size
139 pageSize_ = header.pageSize * NUM_OF_BYTES_IN_KB;
140
141 // read the events
142 if (pageSize_ == 0) {
143 uint8_t* content = nullptr;
144 uint32_t contentSize = 0;
145 if (auto ret = ReadContent(&content, contentSize); ret != DOC_STORE_SUCCESS) {
146 return ret;
147 }
148 callback(content, contentSize);
149 delete[] content;
150 return DOC_STORE_SUCCESS;
151 }
152 return ReadPages(callback);
153 }
154
ReadHeader(DocHeader & header)155 int SysEventDocReader::ReadHeader(DocHeader& header)
156 {
157 auto reader = ContentReaderFactory::GetInstance().Get(dataFmtVersion_);
158 if (reader == nullptr) {
159 HIVIEW_LOGE("reader is nullptr, version:%{public}d", dataFmtVersion_);
160 return DOC_STORE_ERROR_IO;
161 }
162 return reader->ReadDocDetails(in_, header, docHeaderSize_, sysVersion_);
163 }
164
ReadHeader(DocHeader & header,std::string & sysVersion)165 int SysEventDocReader::ReadHeader(DocHeader& header, std::string& sysVersion)
166 {
167 ReadHeader(header);
168 sysVersion = sysVersion_;
169 return DOC_STORE_SUCCESS;
170 }
171
ReadPages(ReadCallback callback)172 int SysEventDocReader::ReadPages(ReadCallback callback)
173 {
174 uint32_t pageIndex = 0;
175 while (!HasReadFileEnd()) {
176 uint8_t* content = nullptr;
177 uint32_t contentSize = 0;
178 if (ReadContent(&content, contentSize) != DOC_STORE_SUCCESS) {
179 pageIndex++;
180 if (SeekgPage(pageIndex) != DOC_STORE_SUCCESS) {
181 HIVIEW_LOGD("end to seekg the next page index=%{public}" PRIu32 ", file=%{public}s",
182 pageIndex, docPath_.c_str());
183 break;
184 }
185 HIVIEW_LOGD("read the next page index=%{public}" PRIu32 ", file=%{public}s", pageIndex, docPath_.c_str());
186 continue;
187 }
188 callback(content, contentSize);
189 delete[] content;
190 }
191 return DOC_STORE_SUCCESS;
192 }
193
HasReadFileEnd()194 bool SysEventDocReader::HasReadFileEnd()
195 {
196 if (!in_.is_open()) {
197 return true;
198 }
199 return (static_cast<int>(in_.tellg()) < 0) || in_.eof();
200 }
201
HasReadPageEnd()202 bool SysEventDocReader::HasReadPageEnd()
203 {
204 if (HasReadFileEnd()) {
205 return true;
206 }
207 uint32_t curPos = static_cast<uint32_t>(in_.tellg());
208 if (curPos <= docHeaderSize_) {
209 return false;
210 }
211 return ((curPos - docHeaderSize_) % pageSize_ + BLOCK_SIZE) >= pageSize_;
212 }
213
ReadContent(uint8_t ** content,uint32_t & contentSize)214 int SysEventDocReader::ReadContent(uint8_t** content, uint32_t& contentSize)
215 {
216 if (HasReadPageEnd()) {
217 HIVIEW_LOGD("end to read the page, file=%{public}s", docPath_.c_str());
218 return DOC_STORE_READ_EMPTY;
219 }
220 ReadValueAndReset(in_, contentSize);
221 constexpr uint32_t minContentSize = BLOCK_SIZE + sizeof(ContentHeader) + CRC_SIZE;
222 if (contentSize < minContentSize) {
223 HIVIEW_LOGD("invalid content size=%{public}u, file=%{public}s", contentSize, docPath_.c_str());
224 return DOC_STORE_READ_EMPTY;
225 }
226 if (contentSize > MAX_NEW_SIZE) {
227 HIVIEW_LOGE("invalid content size=%{public}u", contentSize);
228 return DOC_STORE_ERROR_MEMORY;
229 }
230 *content = new(std::nothrow) uint8_t[contentSize];
231 if (*content == nullptr) {
232 HIVIEW_LOGE("failed to new memory for content, size=%{public}u", contentSize);
233 return DOC_STORE_ERROR_MEMORY;
234 }
235 in_.read(reinterpret_cast<char*>(*content), contentSize);
236 return DOC_STORE_SUCCESS;
237 }
238
ReadFileSize()239 int SysEventDocReader::ReadFileSize()
240 {
241 return fileSize_;
242 }
243
ReadPageSize(uint32_t & pageSize)244 int SysEventDocReader::ReadPageSize(uint32_t& pageSize)
245 {
246 DocHeader header;
247 if (int ret = ReadHeader(header); ret != DOC_STORE_SUCCESS) {
248 return ret;
249 }
250 pageSize = header.pageSize * NUM_OF_BYTES_IN_KB;
251 return DOC_STORE_SUCCESS;
252 }
253
IsValidHeader(const DocHeader & header)254 bool SysEventDocReader::IsValidHeader(const DocHeader& header)
255 {
256 auto reader = ContentReaderFactory::GetInstance().Get(dataFmtVersion_);
257 if (reader == nullptr) {
258 HIVIEW_LOGE("reader nullptr, version:%{public}d", dataFmtVersion_);
259 return false;
260 }
261 if (!reader->IsValidMagicNum(header.magicNum)) {
262 HIVIEW_LOGE("invalid magic number of file=%{public}s", docPath_.c_str());
263 return false;
264 }
265 return true;
266 }
267
SeekgPage(uint32_t pageIndex)268 int SysEventDocReader::SeekgPage(uint32_t pageIndex)
269 {
270 if (HasReadFileEnd()) {
271 return DOC_STORE_ERROR_IO;
272 }
273 auto seekSize = docHeaderSize_ + pageSize_ * pageIndex;
274 if (static_cast<int>(seekSize) < ReadFileSize()) {
275 in_.seekg(seekSize, std::ios::beg);
276 return DOC_STORE_SUCCESS;
277 }
278 in_.setstate(std::ios::eofbit);
279 return DOC_STORE_ERROR_IO;
280 }
281
BuildRawData(uint8_t * content,uint32_t contentSize)282 std::shared_ptr<RawData> SysEventDocReader::BuildRawData(uint8_t* content, uint32_t contentSize)
283 {
284 auto reader = ContentReaderFactory::GetInstance().Get(dataFmtVersion_);
285 if (reader == nullptr) {
286 HIVIEW_LOGE("reader nullptr, version:%{public}d", dataFmtVersion_);
287 return nullptr;
288 }
289 return reader->ReadRawData(info_, content, contentSize);
290 }
291
TryToAddEntry(uint8_t * content,uint32_t contentSize,const DocQuery & query,EntryQueue & entries,int & num)292 void SysEventDocReader::TryToAddEntry(uint8_t* content, uint32_t contentSize, const DocQuery& query,
293 EntryQueue& entries, int& num)
294 {
295 if (!CheckEventInfo(content)) {
296 return;
297 }
298
299 // check inner condition
300 if (!query.IsContainInnerConds(content)) {
301 return;
302 }
303 // build raw data
304 auto rawData = BuildRawData(content, contentSize);
305 if (rawData == nullptr) {
306 return;
307 }
308 // check extra condition
309 if (!query.IsContainExtraConds(rawData->GetData())) {
310 return;
311 }
312 // add to entry queue
313 num++;
314 entries.emplace(info_.seq, info_.timestamp, rawData, sysVersion_);
315 }
316
CheckEventInfo(uint8_t * content)317 bool SysEventDocReader::CheckEventInfo(uint8_t* content)
318 {
319 if (strlen(info_.domain) == 0 || strlen(info_.name) == 0 || info_.level.empty()) {
320 HIVIEW_LOGE("domain=%{public}s or name=%{public}s or level=%{public}s is empty",
321 info_.domain, info_.name, info_.level.c_str());
322 return false;
323 }
324
325 int64_t seq = *(reinterpret_cast<int64_t*>(content + BLOCK_SIZE));
326 if (seq < 0) {
327 HIVIEW_LOGE("event seq is invalid, seq=%{public}" PRId64, seq);
328 return false;
329 }
330 info_.seq = seq;
331
332 int64_t timestamp = *(reinterpret_cast<int64_t*>(content + BLOCK_SIZE + SEQ_SIZE));
333 if (timestamp < 0) {
334 HIVIEW_LOGE("event seq is invalid, timestamp=%{public}" PRId64, timestamp);
335 return false;
336 }
337 info_.timestamp = timestamp;
338
339 return true;
340 }
341 } // EventStore
342 } // HiviewDFX
343 } // OHOS
344