1 /*
2 * Copyright (c) 2021-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_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_query.h"
31 #include "sys_event_service_adapter.h"
32
33 namespace OHOS {
34 namespace HiviewDFX {
35 namespace {
36 constexpr uint64_t PRIME = 0x100000001B3ull;
37 constexpr uint64_t BASIS = 0xCBF29CE484222325ull;
38 constexpr int INVALID_EVENT_TYPE = 0;
39 constexpr char BASE[] = "__BASE";
40 constexpr char DOMAIN_[] = "domain_";
41 constexpr char NAME_[] = "name_";
42 constexpr char ID_[] = "id_";
43 constexpr char LEVEL[] = "level";
44 constexpr char LEVEL_[] = "level_";
45 constexpr char TAG[] = "tag";
46 constexpr char TAG_[] = "tag_";
47 constexpr char TYPE[] = "type";
48 constexpr char TYPE_[] = "type_";
49 constexpr char TEST_TYPE_PARAM_KEY[] = "persist.sys.hiview.testtype";
50 constexpr char TEST_TYPE_KEY[] = "test_type_";
51 constexpr char SEQ_[] = "seq_";
52 constexpr char SEQ_PERSISTS_FILE_NAME[] = "event_sequence";
53 const std::map<std::string, int> EVENT_TYPE_MAP = {
54 {"FAULT", 1}, {"STATISTIC", 2}, {"SECURITY", 3}, {"BEHAVIOR", 4}
55 };
56
GenerateHash(const std::string & info)57 std::string GenerateHash(const std::string& info)
58 {
59 uint64_t ret {BASIS};
60 const char* p = info.c_str();
61 size_t infoLen = info.size();
62 size_t infoLenLimit = 256;
63 size_t hashLen = (infoLen < infoLenLimit) ? infoLen : infoLenLimit;
64 size_t i = 0;
65 while (i < hashLen) {
66 ret ^= *(p + i);
67 ret *= PRIME;
68 i++;
69 }
70 size_t hashRetLenLimit = 20; // max number of digits for uint64_t type
71 std::string retStr = std::to_string(ret);
72 size_t retLen = retStr.size();
73 if (retLen < hashRetLenLimit) {
74 retStr.append(hashRetLenLimit - retLen, '0'); // fill suffix digits with '0'
75 }
76 return retStr;
77 }
78
GetConfiguredTestType(const std::string & configuredType)79 std::string GetConfiguredTestType(const std::string& configuredType)
80 {
81 std::string defaultType {""};
82 size_t maxLen = 12;
83 if (configuredType.empty() || configuredType.length() > maxLen ||
84 any_of(configuredType.cbegin(), configuredType.cend(), [] (char c) {
85 return !isalnum(c);
86 })) {
87 return defaultType;
88 }
89 return configuredType;
90 }
91
92 static std::string testTypeConfigured;
ParameterWatchCallback(const char * key,const char * value,void * context)93 void ParameterWatchCallback(const char* key, const char* value, void* context)
94 {
95 testTypeConfigured = GetConfiguredTestType(value);
96 }
97 }
98
99 DEFINE_LOG_TAG("Event-JsonParser");
100
IsDuplicateEvent(const std::string & sysEventId)101 bool DuplicateIdFilter::IsDuplicateEvent(const std::string& sysEventId)
102 {
103 for (auto iter = sysEventIds.begin(); iter != sysEventIds.end(); iter++) {
104 if (*iter == sysEventId) {
105 return true;
106 }
107 }
108 FILTER_SIZE_TYPE maxSize { 5 }; // size of queue limit to 5
109 if (sysEventIds.size() >= maxSize) {
110 sysEventIds.pop_front();
111 }
112 sysEventIds.emplace_back(sysEventId);
113 return false;
114 }
115
EventJsonParser(const std::string & path)116 EventJsonParser::EventJsonParser(const std::string& path)
117 {
118 Json::Value hiSysEventDef;
119 std::ifstream fin(path, std::ifstream::binary);
120 #ifdef JSONCPP_VERSION_STRING
121 Json::CharReaderBuilder jsonRBuilder;
122 Json::CharReaderBuilder::strictMode(&jsonRBuilder.settings_);
123 JSONCPP_STRING errs;
124 if (!parseFromStream(jsonRBuilder, fin, &hiSysEventDef, &errs)) {
125 #else
126 Json::Reader reader(Json::Features::strictMode());
127 if (!reader.parse(fin, hiSysEventDef)) {
128 #endif
129 HIVIEW_LOGE("parse json file failed, please check the style of json file: %{public}s", path.c_str());
130 }
131 ParseHiSysEventDef(hiSysEventDef);
132 if (WatchParameter(TEST_TYPE_PARAM_KEY, ParameterWatchCallback, nullptr) != 0) {
133 HIVIEW_LOGW("failed to watch the change of parameter %{public}s", TEST_TYPE_PARAM_KEY);
134 }
135
136 ReadSeqFromFile(curSeq);
137 }
138
139 std::string EventJsonParser::GetTagByDomainAndName(const std::string& domain, const std::string& name) const
140 {
141 return GetDefinedBaseInfoByDomainName(domain, name).tag;
142 }
143
144 int EventJsonParser::GetTypeByDomainAndName(const std::string& domain, const std::string& name) const
145 {
146 return GetDefinedBaseInfoByDomainName(domain, name).type;
147 }
148
149 bool EventJsonParser::HandleEventJson(const std::shared_ptr<SysEvent>& event)
150 {
151 Json::Value eventJson;
152 std::string jsonStr = event->jsonExtraInfo_;
153 #ifdef JSONCPP_VERSION_STRING
154 Json::CharReaderBuilder jsonRBuilder;
155 Json::CharReaderBuilder::strictMode(&jsonRBuilder.settings_);
156 std::unique_ptr<Json::CharReader> const reader(jsonRBuilder.newCharReader());
157 JSONCPP_STRING errs;
158 if (!reader->parse(jsonStr.data(), jsonStr.data() + jsonStr.size(), &eventJson, &errs)) {
159 #else
160 Json::Reader reader(Json::Features::strictMode());
161 if (!reader.parse(jsonStr, eventJson)) {
162 #endif
163 HIVIEW_LOGE("parse json file failed, please check the style of json file: %{public}s.", jsonStr.c_str());
164 return false;
165 }
166
167 if (!CheckEventValidity(eventJson)) {
168 HIVIEW_LOGD("domain_ or name_ not found in the event json string.");
169 return false;
170 }
171 std::string domain = eventJson[DOMAIN_].asString();
172 std::string name = eventJson[NAME_].asString();
173 auto baseInfo = GetDefinedBaseInfoByDomainName(domain, name);
174 if (baseInfo.type == INVALID_EVENT_TYPE) {
175 HIVIEW_LOGD("type defined for domain: %{public}s, name: %{public}s is invalid.",
176 domain.c_str(), name.c_str());
177 return false;
178 }
179 if (!CheckBaseInfoValidity(baseInfo, eventJson)) {
180 HIVIEW_LOGD("failed to verify the base info of the event.");
181 return false;
182 }
183 auto curSysEventId = GenerateHash(jsonStr);
184 if (filter.IsDuplicateEvent(curSysEventId)) {
185 HIVIEW_LOGW("duplicate sys event, ignore it directly.");
186 return false; // ignore duplicate sys event
187 }
188 AppendExtensiveInfo(eventJson, jsonStr, curSysEventId);
189 WriteSeqToFile(++curSeq);
190 event->jsonExtraInfo_ = jsonStr;
191 return true;
192 }
193
194 void EventJsonParser::AppendExtensiveInfo(const Json::Value& eventJson, std::string& jsonStr,
195 const std::string& sysEventId) const
196 {
197 // this customized parser would maintain the original order of JSON key-value pairs
198 FlatJsonParser parser(jsonStr);
199
200 // cJsonArr need to add "level_" and "tag_" by hisysevent.def, "level" is must-option
201 parser.AppendStringValue(LEVEL_, eventJson[LEVEL_].asString());
202 if (eventJson.isMember(TAG_)) {
203 parser.AppendStringValue(TAG_, eventJson[TAG_].asString());
204 }
205
206 // hash code need to add
207 parser.AppendStringValue(ID_, sysEventId);
208
209 // FreezeDetector needs to add
210 parser.AppendStringValue(EventStore::EventCol::INFO.c_str(), "");
211
212 // add testtype configured as system property named persist.sys.hiview.testtype
213 if (!testTypeConfigured.empty()) {
214 parser.AppendStringValue(TEST_TYPE_KEY, testTypeConfigured);
215 }
216
217 // add seq to sys event and then persist it into local file
218 parser.AppendUInt64Value(SEQ_, static_cast<uint64_t>(curSeq));
219
220 jsonStr = parser.Print();
221 }
222
223 bool EventJsonParser::CheckBaseInfoValidity(const BaseInfo& baseInfo, Json::Value& eventJson) const
224 {
225 if (!CheckTypeValidity(baseInfo, eventJson)) {
226 return false;
227 }
228 if (!baseInfo.level.empty()) {
229 eventJson[LEVEL_] = baseInfo.level;
230 }
231 if (!baseInfo.tag.empty()) {
232 eventJson[TAG_] = baseInfo.tag;
233 }
234 return true;
235 }
236
237 bool EventJsonParser::CheckEventValidity(const Json::Value& eventJson) const
238 {
239 return HasStringMember(eventJson, DOMAIN_) && HasStringMember(eventJson, NAME_);
240 }
241
242 bool EventJsonParser::CheckTypeValidity(const BaseInfo& baseInfo, const Json::Value& eventJson) const
243 {
244 if (!HasIntMember(eventJson, TYPE_)) {
245 HIVIEW_LOGD("value of type_ found in the event json string need INT type.");
246 return false;
247 }
248 return eventJson[TYPE_].asInt() == baseInfo.type;
249 }
250
251 BaseInfo EventJsonParser::GetDefinedBaseInfoByDomainName(const std::string& domain,
252 const std::string& name) const
253 {
254 BaseInfo baseInfo = {
255 .type = INVALID_EVENT_TYPE,
256 .level = "",
257 .tag = ""
258 };
259 auto domainIter = hiSysEventDef.find(domain);
260 if (domainIter == hiSysEventDef.end()) {
261 HIVIEW_LOGD("domain named %{public}s is not defined.", domain.c_str());
262 return baseInfo;
263 }
264 auto domaintNames = hiSysEventDef.at(domain);
265 auto nameIter = domaintNames.find(name);
266 if (nameIter == domaintNames.end()) {
267 HIVIEW_LOGD("%{public}s is not defined in domain named %{public}s.",
268 name.c_str(), domain.c_str());
269 return baseInfo;
270 }
271 return nameIter->second;
272 }
273
274 bool EventJsonParser::HasIntMember(const Json::Value& jsonObj, const std::string& name) const
275 {
276 return jsonObj.isMember(name.c_str()) && jsonObj[name.c_str()].isInt();
277 }
278
279 bool EventJsonParser::HasStringMember(const Json::Value& jsonObj, const std::string& name) const
280 {
281 return jsonObj.isMember(name.c_str()) && jsonObj[name.c_str()].isString();
282 }
283
284 void EventJsonParser::InitEventInfoMapRef(const Json::Value& eventJson, JSON_VALUE_LOOP_HANDLER handler) const
285 {
286 if (!eventJson.isObject()) {
287 return;
288 }
289 auto attrList = eventJson.getMemberNames();
290 for (auto it = attrList.cbegin(); it != attrList.cend(); it++) {
291 std::string key = *it;
292 if (key.empty()) {
293 continue;
294 }
295 if (handler != nullptr) {
296 handler(key, eventJson[key]);
297 }
298 }
299 }
300
301 BaseInfo EventJsonParser::ParseBaseConfig(const Json::Value& eventNameJson) const
302 {
303 BaseInfo baseInfo = {
304 .type = INVALID_EVENT_TYPE,
305 .level = "",
306 .tag = ""
307 };
308 if (!eventNameJson.isObject() || !eventNameJson[BASE].isObject()) {
309 HIVIEW_LOGD("__BASE definition is invalid.");
310 return baseInfo;
311 }
312 Json::Value baseJsonInfo = eventNameJson[BASE];
313 if (!baseJsonInfo.isObject() || !HasStringMember(baseJsonInfo, TYPE)) {
314 HIVIEW_LOGD("type is not defined in __BASE.");
315 return baseInfo;
316 }
317 std::string typeDes = baseJsonInfo[TYPE].asString();
318 if (EVENT_TYPE_MAP.find(typeDes) == EVENT_TYPE_MAP.end()) {
319 HIVIEW_LOGD("type is defined as %{public}s, but a valid type must be FAULT, STATISTIC, SECURITY, or BEHAVIOR",
320 typeDes.c_str());
321 return baseInfo;
322 }
323 baseInfo.type = EVENT_TYPE_MAP.at(typeDes);
324 if (!baseJsonInfo.isObject() || !HasStringMember(baseJsonInfo, LEVEL)) {
325 HIVIEW_LOGD("level is not defined in __BASE.");
326 return baseInfo;
327 }
328 baseInfo.level = baseJsonInfo[LEVEL].asString();
329 if (!baseJsonInfo.isObject() || !HasStringMember(baseJsonInfo, TAG)) {
330 HIVIEW_LOGD("tag is not defined in __BASE.");
331 return baseInfo;
332 }
333 baseInfo.tag = baseJsonInfo[TAG].asString();
334 return baseInfo;
335 }
336
337 void EventJsonParser::ParseHiSysEventDef(const Json::Value& hiSysEventDef)
338 {
339 InitEventInfoMapRef(hiSysEventDef, [this] (const std::string& key, const Json::Value& value) {
340 this->hiSysEventDef[key] = ParseNameConfig(value);
341 });
342 }
343
344 NAME_INFO_MAP EventJsonParser::ParseNameConfig(const Json::Value& domainJson) const
345 {
346 NAME_INFO_MAP allNames;
347 if (!domainJson.isObject()) {
348 return allNames;
349 }
350 InitEventInfoMapRef(domainJson, [this, &allNames] (const std::string& key, const Json::Value& value) {
351 allNames[key] = ParseBaseConfig(value);
352 });
353 return allNames;
354 }
355
356 std::string EventJsonParser::GetSequenceFile() const
357 {
358 std::string workPath = HiviewGlobal::GetInstance()->GetHiViewDirectory(
359 HiviewContext::DirectoryType::WORK_DIRECTORY);
360 if (workPath.back() != '/') {
361 workPath = workPath + "/";
362 }
363 return workPath + "sys_event_db/" + SEQ_PERSISTS_FILE_NAME;
364 }
365
366 void EventJsonParser::ReadSeqFromFile(int64_t& seq)
367 {
368 std::string content;
369 std::string seqFile = GetSequenceFile();
370 if (!FileUtil::LoadStringFromFile(seqFile, content) && !content.empty()) {
371 HIVIEW_LOGE("failed to read sequence value from %{public}s.", seqFile.c_str());
372 return;
373 }
374 seq = static_cast<int64_t>(strtoll(content.c_str(), nullptr, 0));
375 HIVIEW_LOGI("read max sequence from local file successful, value is %{public}" PRId64 ".", seq);
376 SysEventServiceAdapter::UpdateEventSeq(seq);
377 }
378
379 void EventJsonParser::WriteSeqToFile(int64_t seq) const
380 {
381 std::string seqFile = GetSequenceFile();
382 std::string content = std::to_string(seq);
383 if (!FileUtil::SaveStringToFile(seqFile, content, true)) {
384 HIVIEW_LOGE("failed to write sequence %{public}s to %{public}s.", content.c_str(), seqFile.c_str());
385 }
386 SysEventServiceAdapter::UpdateEventSeq(seq);
387 }
388 } // namespace HiviewDFX
389 } // namespace OHOS
390