1 /*
2 * Copyright (c) 2021-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_json_parser.h"
17
18 #include <algorithm>
19 #include <cctype>
20 #include <cinttypes>
21 #include <fstream>
22 #include <map>
23 #include <cstdlib>
24
25 #include "file_util.h"
26 #include "flat_json_parser.h"
27 #include "hiview_global.h"
28 #include "logger.h"
29 #include "parameter.h"
30 #include "sys_event_service_adapter.h"
31
32 namespace OHOS {
33 namespace HiviewDFX {
34 namespace {
35 constexpr uint64_t PRIME = 0x100000001B3ull;
36 constexpr uint64_t BASIS = 0xCBF29CE484222325ull;
37 constexpr int INVALID_EVENT_TYPE = 0;
38 constexpr char BASE[] = "__BASE";
39 constexpr char LEVEL[] = "level";
40 constexpr char TAG[] = "tag";
41 constexpr char TYPE[] = "type";
42 constexpr char PRESERVE[] = "preserve";
43 constexpr char TEST_TYPE_PARAM_KEY[] = "persist.sys.hiview.testtype";
44 constexpr char TEST_TYPE_KEY[] = "test_type_";
45 constexpr char SEQ_PERSISTS_FILE_NAME[] = "event_sequence";
46 const std::map<std::string, uint8_t> EVENT_TYPE_MAP = {
47 {"FAULT", 1}, {"STATISTIC", 2}, {"SECURITY", 3}, {"BEHAVIOR", 4}
48 };
49
GenerateHash(const std::string & info)50 uint64_t GenerateHash(const std::string& info)
51 {
52 uint64_t ret {BASIS};
53 const char* p = info.c_str();
54 size_t infoLen = info.size();
55 size_t infoLenLimit = 256;
56 size_t hashLen = (infoLen < infoLenLimit) ? infoLen : infoLenLimit;
57 size_t i = 0;
58 while (i < hashLen) {
59 ret ^= *(p + i);
60 ret *= PRIME;
61 i++;
62 }
63 return ret;
64 }
65
GetConfiguredTestType(const std::string & configuredType)66 std::string GetConfiguredTestType(const std::string& configuredType)
67 {
68 std::string defaultType {""};
69 size_t maxLen = 12;
70 if (configuredType.empty() || configuredType.length() > maxLen ||
71 any_of(configuredType.cbegin(), configuredType.cend(), [] (char c) {
72 return !isalnum(c);
73 })) {
74 return defaultType;
75 }
76 return configuredType;
77 }
78
79 static std::string testTypeConfigured;
ParameterWatchCallback(const char * key,const char * value,void * context)80 void ParameterWatchCallback(const char* key, const char* value, void* context)
81 {
82 testTypeConfigured = GetConfiguredTestType(value);
83 }
84
ReadSysEventDefFromFile(const std::string & path,Json::Value & hiSysEventDef)85 bool ReadSysEventDefFromFile(const std::string& path, Json::Value& hiSysEventDef)
86 {
87 std::ifstream fin(path, std::ifstream::binary);
88 Json::CharReaderBuilder jsonRBuilder;
89 Json::CharReaderBuilder::strictMode(&jsonRBuilder.settings_);
90 JSONCPP_STRING errs;
91 return parseFromStream(jsonRBuilder, fin, &hiSysEventDef, &errs);
92 }
93 }
94
95 DEFINE_LOG_TAG("Event-JsonParser");
96
IsDuplicateEvent(const uint64_t sysEventId)97 bool DuplicateIdFilter::IsDuplicateEvent(const uint64_t sysEventId)
98 {
99 for (auto iter = sysEventIds.begin(); iter != sysEventIds.end(); iter++) {
100 if (*iter == sysEventId) {
101 return true;
102 }
103 }
104 FILTER_SIZE_TYPE maxSize { 5 }; // size of queue limit to 5
105 if (sysEventIds.size() >= maxSize) {
106 sysEventIds.pop_front();
107 }
108 sysEventIds.emplace_back(sysEventId);
109 return false;
110 }
111
EventJsonParser(std::vector<std::string> & paths)112 EventJsonParser::EventJsonParser(std::vector<std::string>& paths)
113 {
114 Json::Value hiSysEventDef;
115 for (auto path : paths) {
116 if (!ReadSysEventDefFromFile(path, hiSysEventDef)) {
117 HIVIEW_LOGE("parse json file failed, please check the style of json file: %{public}s", path.c_str());
118 }
119 ParseHiSysEventDef(hiSysEventDef);
120 }
121 WatchParameterAndReadLatestSeq();
122 }
123
WatchParameterAndReadLatestSeq()124 void EventJsonParser::WatchParameterAndReadLatestSeq()
125 {
126 if (WatchParameter(TEST_TYPE_PARAM_KEY, ParameterWatchCallback, nullptr) != 0) {
127 HIVIEW_LOGW("failed to watch the change of parameter %{public}s", TEST_TYPE_PARAM_KEY);
128 }
129 ReadSeqFromFile(curSeq_);
130 }
131
GetTagByDomainAndName(const std::string & domain,const std::string & name) const132 std::string EventJsonParser::GetTagByDomainAndName(const std::string& domain, const std::string& name) const
133 {
134 return GetDefinedBaseInfoByDomainName(domain, name).tag;
135 }
136
GetTypeByDomainAndName(const std::string & domain,const std::string & name) const137 int EventJsonParser::GetTypeByDomainAndName(const std::string& domain, const std::string& name) const
138 {
139 return GetDefinedBaseInfoByDomainName(domain, name).type;
140 }
141
GetPreserveByDomainAndName(const std::string & domain,const std::string & name) const142 bool EventJsonParser::GetPreserveByDomainAndName(const std::string& domain, const std::string& name) const
143 {
144 return GetDefinedBaseInfoByDomainName(domain, name).preserve;
145 }
146
HandleEventJson(const std::shared_ptr<SysEvent> & event)147 bool EventJsonParser::HandleEventJson(const std::shared_ptr<SysEvent>& event)
148 {
149 if (!CheckEventValidity(event)) {
150 HIVIEW_LOGI("invalid event or event with empty domain or empty name.");
151 return false;
152 }
153
154 auto baseInfo = GetDefinedBaseInfoByDomainName(event->domain_, event->eventName_);
155 if (baseInfo.type == INVALID_EVENT_TYPE) {
156 HIVIEW_LOGI("type defined for event[%{public}s|%{public}s|%{public}" PRIu64 "] is invalid.",
157 event->domain_.c_str(), event->eventName_.c_str(), event->GetEventUintValue("time_"));
158 return false;
159 }
160 if (!CheckBaseInfoValidity(baseInfo, event)) {
161 HIVIEW_LOGI("failed to verify the base info of event[%{public}s|%{public}s|%{public}" PRIu64 "].",
162 event->domain_.c_str(), event->eventName_.c_str(), event->GetEventUintValue("time_"));
163 return false;
164 }
165
166 auto curSysEventId = GenerateHash(event->AsJsonStr());
167 if (filter_.IsDuplicateEvent(curSysEventId)) {
168 HIVIEW_LOGI(
169 "ignore duplicate event[%{public}s|%{public}s|%{public}" PRIu64 "].", event->domain_.c_str(),
170 event->eventName_.c_str(), event->GetEventUintValue("time_"));
171 return false; // ignore duplicate sys event
172 }
173
174 AppendExtensiveInfo(event, curSysEventId);
175 WriteSeqToFile(++curSeq_);
176
177 return true;
178 }
179
AppendExtensiveInfo(std::shared_ptr<SysEvent> event,const uint64_t sysEventId) const180 void EventJsonParser::AppendExtensiveInfo(std::shared_ptr<SysEvent> event, const uint64_t sysEventId) const
181 {
182 if (event == nullptr) {
183 return;
184 }
185
186 // hash code need to add
187 event->SetId(sysEventId);
188
189 // FreezeDetector needs to add
190 event->SetEventValue(EventStore::EventCol::INFO, "");
191
192 // add testtype configured as system property named persist.sys.hiview.testtype
193 if (!testTypeConfigured.empty()) {
194 event->SetEventValue(TEST_TYPE_KEY, testTypeConfigured);
195 }
196
197 // add seq to sys event and then persist it into local file
198 event->SetEventSeq(curSeq_);
199 }
200
CheckBaseInfoValidity(const BaseInfo & baseInfo,std::shared_ptr<SysEvent> event) const201 bool EventJsonParser::CheckBaseInfoValidity(const BaseInfo& baseInfo, std::shared_ptr<SysEvent> event) const
202 {
203 if (!CheckTypeValidity(baseInfo, event)) {
204 return false;
205 }
206 if (!baseInfo.level.empty()) {
207 event->SetLevel(baseInfo.level);
208 }
209 if (!baseInfo.tag.empty()) {
210 event->SetTag(baseInfo.tag);
211 }
212 return true;
213 }
214
CheckEventValidity(std::shared_ptr<SysEvent> event) const215 bool EventJsonParser::CheckEventValidity(std::shared_ptr<SysEvent> event) const
216 {
217 if (event == nullptr) {
218 return false;
219 }
220 return !(event->domain_.empty()) && !(event->eventName_.empty());
221 }
222
CheckTypeValidity(const BaseInfo & baseInfo,std::shared_ptr<SysEvent> event) const223 bool EventJsonParser::CheckTypeValidity(const BaseInfo& baseInfo, std::shared_ptr<SysEvent> event) const
224 {
225 if (event == nullptr) {
226 return false;
227 }
228 HIVIEW_LOGD("base info type is %{public}d, event type is %{public}d", baseInfo.type, event->GetEventType());
229 return event->GetEventType() == baseInfo.type;
230 }
231
GetDefinedBaseInfoByDomainName(const std::string & domain,const std::string & name) const232 BaseInfo EventJsonParser::GetDefinedBaseInfoByDomainName(const std::string& domain,
233 const std::string& name) const
234 {
235 BaseInfo baseInfo = {
236 .type = INVALID_EVENT_TYPE,
237 .level = "",
238 .tag = "",
239 .preserve = true
240 };
241 auto domainIter = hiSysEventDef_.find(domain);
242 if (domainIter == hiSysEventDef_.end()) {
243 HIVIEW_LOGD("domain named %{public}s is not defined.", domain.c_str());
244 return baseInfo;
245 }
246 auto domainNames = hiSysEventDef_.at(domain);
247 auto nameIter = domainNames.find(name);
248 if (nameIter == domainNames.end()) {
249 HIVIEW_LOGD("%{public}s is not defined in domain named %{public}s.",
250 name.c_str(), domain.c_str());
251 return baseInfo;
252 }
253 return nameIter->second;
254 }
255
HasIntMember(const Json::Value & jsonObj,const std::string & name) const256 bool EventJsonParser::HasIntMember(const Json::Value& jsonObj, const std::string& name) const
257 {
258 return jsonObj.isMember(name.c_str()) && jsonObj[name.c_str()].isInt();
259 }
260
HasStringMember(const Json::Value & jsonObj,const std::string & name) const261 bool EventJsonParser::HasStringMember(const Json::Value& jsonObj, const std::string& name) const
262 {
263 return jsonObj.isMember(name.c_str()) && jsonObj[name.c_str()].isString();
264 }
265
HasBoolMember(const Json::Value & jsonObj,const std::string & name) const266 bool EventJsonParser::HasBoolMember(const Json::Value& jsonObj, const std::string& name) const
267 {
268 return jsonObj.isMember(name.c_str()) && jsonObj[name.c_str()].isBool();
269 }
270
InitEventInfoMapRef(const Json::Value & eventJson,JSON_VALUE_LOOP_HANDLER handler) const271 void EventJsonParser::InitEventInfoMapRef(const Json::Value& eventJson, JSON_VALUE_LOOP_HANDLER handler) const
272 {
273 if (!eventJson.isObject()) {
274 return;
275 }
276 auto attrList = eventJson.getMemberNames();
277 for (auto it = attrList.cbegin(); it != attrList.cend(); it++) {
278 std::string key = *it;
279 if (key.empty()) {
280 continue;
281 }
282 if (handler != nullptr) {
283 handler(key, eventJson[key]);
284 }
285 }
286 }
287
ParseBaseConfig(const Json::Value & eventNameJson) const288 BaseInfo EventJsonParser::ParseBaseConfig(const Json::Value& eventNameJson) const
289 {
290 BaseInfo baseInfo = {
291 .type = INVALID_EVENT_TYPE,
292 .level = "",
293 .tag = "",
294 .preserve = true
295 };
296 if (!eventNameJson.isObject() || !eventNameJson[BASE].isObject()) {
297 HIVIEW_LOGD("__BASE definition is invalid.");
298 return baseInfo;
299 }
300 Json::Value baseJsonInfo = eventNameJson[BASE];
301 if (!baseJsonInfo.isObject() || !HasStringMember(baseJsonInfo, TYPE)) {
302 HIVIEW_LOGD("type is not defined in __BASE.");
303 return baseInfo;
304 }
305 std::string typeDes = baseJsonInfo[TYPE].asString();
306 if (EVENT_TYPE_MAP.find(typeDes) == EVENT_TYPE_MAP.end()) {
307 HIVIEW_LOGD("type is defined as %{public}s, but a valid type must be FAULT, STATISTIC, SECURITY, or BEHAVIOR",
308 typeDes.c_str());
309 return baseInfo;
310 }
311 baseInfo.type = EVENT_TYPE_MAP.at(typeDes);
312 if (!baseJsonInfo.isObject() || !HasStringMember(baseJsonInfo, LEVEL)) {
313 HIVIEW_LOGD("level is not defined in __BASE.");
314 return baseInfo;
315 }
316 baseInfo.level = baseJsonInfo[LEVEL].asString();
317 if (baseJsonInfo.isObject() && HasStringMember(baseJsonInfo, TAG)) {
318 baseInfo.tag = baseJsonInfo[TAG].asString();
319 }
320 if (baseJsonInfo.isObject() && HasBoolMember(baseJsonInfo, PRESERVE)) {
321 baseInfo.preserve = baseJsonInfo[PRESERVE].asBool();
322 return baseInfo;
323 }
324 return baseInfo;
325 }
326
ParseHiSysEventDef(const Json::Value & hiSysEventDef)327 void EventJsonParser::ParseHiSysEventDef(const Json::Value& hiSysEventDef)
328 {
329 InitEventInfoMapRef(hiSysEventDef, [this] (const std::string& key, const Json::Value& value) {
330 hiSysEventDef_[key] = ParseNameConfig(value);
331 });
332 }
333
ParseNameConfig(const Json::Value & domainJson) const334 NAME_INFO_MAP EventJsonParser::ParseNameConfig(const Json::Value& domainJson) const
335 {
336 NAME_INFO_MAP allNames;
337 if (!domainJson.isObject()) {
338 return allNames;
339 }
340 InitEventInfoMapRef(domainJson, [this, &allNames] (const std::string& key, const Json::Value& value) {
341 allNames[key] = ParseBaseConfig(value);
342 });
343 return allNames;
344 }
345
GetSequenceFile() const346 std::string EventJsonParser::GetSequenceFile() const
347 {
348 std::string workPath = HiviewGlobal::GetInstance()->GetHiViewDirectory(
349 HiviewContext::DirectoryType::WORK_DIRECTORY);
350 if (workPath.back() != '/') {
351 workPath = workPath + "/";
352 }
353 return workPath + "sys_event_db/" + SEQ_PERSISTS_FILE_NAME;
354 }
355
ReadSeqFromFile(int64_t & seq)356 void EventJsonParser::ReadSeqFromFile(int64_t& seq)
357 {
358 std::string content;
359 std::string seqFile = GetSequenceFile();
360 if (!FileUtil::LoadStringFromFile(seqFile, content) && !content.empty()) {
361 HIVIEW_LOGE("failed to read sequence value from %{public}s.", seqFile.c_str());
362 return;
363 }
364 seq = static_cast<int64_t>(strtoll(content.c_str(), nullptr, 0));
365 HIVIEW_LOGI("read max sequence from local file successful, value is %{public}" PRId64 ".", seq);
366 SysEventServiceAdapter::UpdateEventSeq(seq);
367 }
368
WriteSeqToFile(int64_t seq) const369 void EventJsonParser::WriteSeqToFile(int64_t seq) const
370 {
371 std::string seqFile = GetSequenceFile();
372 std::string content = std::to_string(seq);
373 if (!SaveStringToFile(seqFile, content)) {
374 HIVIEW_LOGE("failed to write sequence %{public}s to %{public}s.", content.c_str(), seqFile.c_str());
375 }
376 SysEventServiceAdapter::UpdateEventSeq(seq);
377 }
378
SaveStringToFile(const std::string & filePath,const std::string & content) const379 bool EventJsonParser::SaveStringToFile(const std::string& filePath, const std::string& content) const
380 {
381 std::ofstream file;
382 file.open(filePath.c_str(), std::ios::in | std::ios::out);
383 if (!file.is_open()) {
384 file.open(filePath.c_str(), std::ios::out);
385 if (!file.is_open()) {
386 return false;
387 }
388 }
389 file.seekp(0);
390 file.write(content.c_str(), content.length() + 1);
391 bool ret = true;
392 if (file.fail()) {
393 ret = false;
394 }
395 file.close();
396 return ret;
397 }
398 } // namespace HiviewDFX
399 } // namespace OHOS
400