• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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