1 /*
2 * Copyright (c) 2021-2025 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 "sysevent_source.h"
17
18 #include <functional>
19 #include <memory>
20
21 #include "daily_controller.h"
22 #include "decoded/decoded_event.h"
23 #include "defines.h"
24 #include "file_util.h"
25 #include "focused_event_util.h"
26 #include "hiview_logger.h"
27 #include "hiview_platform.h"
28 #include "param_const_common.h"
29 #include "parameter.h"
30 #include "parameter_ex.h"
31 #include "plugin_factory.h"
32 #include "raw_data_base_def.h"
33 #include "running_status_logger.h"
34 #include "string_util.h"
35 #include "sys_event.h"
36 #include "sys_event_dao.h"
37 #include "sys_event_service_adapter.h"
38 #include "time_util.h"
39
40 namespace OHOS {
41 namespace HiviewDFX {
42 REGISTER(SysEventSource);
43 namespace {
44 DEFINE_LOG_TAG("HiView-SysEventSource");
45 constexpr char TEST_TYPE_PARAM_KEY[] = "hiviewdfx.hiview.testtype";
46 constexpr char TEST_TYPE_KEY[] = "test_type_";
47 constexpr char SOURCE_PERIOD_CNT_ITEM_CONCATE[] = " ";
48 constexpr size_t SOURCE_PERIOD_INFO_ITEM_CNT = 3;
49 constexpr size_t PERIOD_FILE_WROTE_STEP = 100;
50
GenerateHash(std::shared_ptr<SysEvent> event)51 uint64_t GenerateHash(std::shared_ptr<SysEvent> event)
52 {
53 if (event == nullptr) {
54 return 0;
55 }
56 constexpr size_t infoLenLimit = 256;
57 size_t infoLen = event->rawData_->GetDataLength();
58 size_t hashLen = (infoLen < infoLenLimit) ? infoLen : infoLenLimit;
59 const uint8_t* p = event->rawData_->GetData();
60 uint64_t ret { 0xCBF29CE484222325ULL }; // basis value
61 size_t i = 0;
62 while (i < hashLen) {
63 ret ^= *(p + i);
64 ret *= 0x100000001B3ULL; // prime value
65 i++;
66 }
67 return ret;
68 }
69
ParameterWatchCallback(const char * key,const char * value,void * context)70 void ParameterWatchCallback(const char* key, const char* value, void* context)
71 {
72 if (context == nullptr) {
73 HIVIEW_LOGE("context is null");
74 return;
75 }
76 auto eventSourcePlugin = reinterpret_cast<SysEventSource*>(context);
77 if (eventSourcePlugin == nullptr) {
78 HIVIEW_LOGE("eventsource plugin is null");
79 return;
80 }
81 size_t testTypeStrMaxLen = 256;
82 std::string testTypeStr(value);
83 if (testTypeStr.size() > testTypeStrMaxLen) {
84 HIVIEW_LOGE("length of the test type string set exceeds the limit");
85 return;
86 }
87 HIVIEW_LOGI("test_type is set to be \"%{public}s\"", testTypeStr.c_str());
88 eventSourcePlugin->UpdateTestType(testTypeStr);
89 }
90
LogEventDelayedInfo(bool & isLastEventDelayed,bool isCurEventDelayed,uint64_t happenTime,uint64_t createTime)91 void LogEventDelayedInfo(bool& isLastEventDelayed, bool isCurEventDelayed, uint64_t happenTime,
92 uint64_t createTime)
93 {
94 if (isLastEventDelayed == isCurEventDelayed) {
95 return;
96 }
97 // reset delay info of the last event by delay info of current event
98 isLastEventDelayed = isCurEventDelayed;
99 std::string info { "event delay " };
100 if (isCurEventDelayed) {
101 info.append("start;");
102 } else {
103 info.append("end;");
104 }
105 info.append("happen_time=[").append(std::to_string(happenTime)).append("]; ");
106 info.append("create_time=[").append(std::to_string(createTime)).append("]");
107 RunningStatusLogger::GetInstance().LogEventRunningLogInfo(info);
108 }
109
CheckIfEventDelayed(bool & isLastEventDelayed,std::shared_ptr<SysEvent> event)110 void CheckIfEventDelayed(bool& isLastEventDelayed, std::shared_ptr<SysEvent> event)
111 {
112 uint64_t happenTime = event->happenTime_;
113 uint64_t createTime = event->createTime_ / 1000; // 1000: us->ms
114 if (createTime < happenTime) { // for the time jump scene
115 LogEventDelayedInfo(isLastEventDelayed, false, happenTime, createTime);
116 return;
117 }
118 constexpr uint64_t delayDetectLimit = 5 * 1000; // 5s
119 if (uint64_t delayTime = createTime - happenTime; delayTime > delayDetectLimit) {
120 HIVIEW_LOGI("event[%{public}s|%{public}s|%{public}" PRIu64 "] delayed by %{public}" PRIu64 "ms",
121 event->domain_.c_str(), event->eventName_.c_str(), happenTime, delayTime);
122 LogEventDelayedInfo(isLastEventDelayed, true, happenTime, createTime);
123 return;
124 }
125 LogEventDelayedInfo(isLastEventDelayed, false, happenTime, createTime);
126 }
127
LogSourcePeriodInfo(std::shared_ptr<SourcePeriodInfo> info)128 void LogSourcePeriodInfo(std::shared_ptr<SourcePeriodInfo> info)
129 {
130 if (info == nullptr) {
131 HIVIEW_LOGE("info is null");
132 return;
133 }
134 std::string logInfo;
135 // append period
136 logInfo.append("period=[").append(info->timeStamp).append("]; ");
137 // append num of the event which is need to be stored;
138 logInfo.append("need_store_event_num=[").append(std::to_string(info->preserveCnt)).append("]; ");
139 // append num of the event which is need to be exported;
140 logInfo.append("need_export_event_num=[").append(std::to_string(info->exportCnt)).append("]");
141 RunningStatusLogger::GetInstance().LogEventCountStatisticInfo(logInfo);
142 }
143 }
144
HandlerEvent(std::shared_ptr<EventRaw::RawData> rawData)145 void SysEventReceiver::HandlerEvent(std::shared_ptr<EventRaw::RawData> rawData)
146 {
147 if (rawData == nullptr || rawData->GetData() == nullptr) {
148 HIVIEW_LOGW("raw data of sys event is null");
149 return;
150 }
151 std::shared_ptr<PipelineEvent> event = std::make_shared<SysEvent>("SysEventSource",
152 static_cast<PipelineEventProducer*>(&eventSource), rawData);
153 if (eventSource.CheckEvent(event)) {
154 eventSource.PublishPipelineEvent(event);
155 }
156 }
157
OnLoad()158 void SysEventSource::OnLoad()
159 {
160 HIVIEW_LOGI("SysEventSource load ");
161 std::shared_ptr<EventLoop> looper = GetHiviewContext()->GetSharedWorkLoop();
162 platformMonitor_.StartMonitor(looper);
163
164 sysEventStat_ = std::make_unique<SysEventStat>();
165 InitController();
166
167 // start sys event service
168 SysEventServiceAdapter::StartService(this);
169 SysEventServiceAdapter::SetWorkLoop(looper);
170
171 // watch parameter
172 if (WatchParameter(TEST_TYPE_PARAM_KEY, ParameterWatchCallback, this) != 0) {
173 HIVIEW_LOGW("failed to watch the change of parameter %{public}s", TEST_TYPE_PARAM_KEY);
174 }
175
176 periodFileOpt_ = std::make_unique<PeriodInfoFileOperator>(GetHiviewContext(), "event_source_period_count");
177 periodFileOpt_->ReadPeriodInfoFromFile(SOURCE_PERIOD_INFO_ITEM_CNT,
178 [this] (const std::vector<std::string>& infoDetails) {
179 uint64_t preserveCnt = 0;
180 StringUtil::ConvertStringTo(infoDetails[1], preserveCnt); // 1 is the index of preserve count
181 uint64_t exportCnt = 0;
182 StringUtil::ConvertStringTo(infoDetails[2], exportCnt); // 2 is the index of export count
183 periodInfoList_.emplace_back(std::make_shared<SourcePeriodInfo>(infoDetails[0], preserveCnt,
184 exportCnt));
185 });
186 }
187
InitController()188 void SysEventSource::InitController()
189 {
190 auto context = GetHiviewContext();
191 if (context == nullptr) {
192 HIVIEW_LOGW("context is null");
193 return;
194 }
195
196 std::string workPath = context->GetHiViewDirectory(HiviewContext::DirectoryType::WORK_DIRECTORY);
197 std::string configPath = context->GetHiViewDirectory(HiviewContext::DirectoryType::CONFIG_DIRECTORY);
198 const std::string configFileName = "event_threshold.json";
199 controller_ = std::make_unique<DailyController>(workPath, configPath.append(configFileName));
200 }
201
OnUnload()202 void SysEventSource::OnUnload()
203 {
204 eventServer_.Stop();
205 HIVIEW_LOGI("SysEventSource unload");
206 }
207
StartEventSource()208 void SysEventSource::StartEventSource()
209 {
210 HIVIEW_LOGI("SysEventSource start");
211 EventJsonParser::GetInstance()->ReadDefFile();
212 std::shared_ptr<EventReceiver> sysEventReceiver = std::make_shared<SysEventReceiver>(*this);
213 eventServer_.AddReceiver(sysEventReceiver);
214 eventServer_.Start();
215 }
216
Recycle(PipelineEvent * event)217 void SysEventSource::Recycle(PipelineEvent *event)
218 {
219 platformMonitor_.CollectCostTime(event);
220 }
221
PauseDispatch(std::weak_ptr<Plugin> plugin)222 void SysEventSource::PauseDispatch(std::weak_ptr<Plugin> plugin)
223 {
224 auto requester = plugin.lock();
225 if (requester != nullptr) {
226 HIVIEW_LOGI("process pause dispatch event from plugin:%s.\n", requester->GetName().c_str());
227 }
228 }
229
PublishPipelineEvent(std::shared_ptr<PipelineEvent> event)230 bool SysEventSource::PublishPipelineEvent(std::shared_ptr<PipelineEvent> event)
231 {
232 platformMonitor_.CollectEvent(event);
233 platformMonitor_.Breaking();
234 auto context = GetHiviewContext();
235 HiviewPlatform* hiviewPlatform = static_cast<HiviewPlatform*>(context);
236 if (hiviewPlatform == nullptr) {
237 HIVIEW_LOGW("hiviewPlatform is null");
238 return false;
239 }
240 auto const &pipelineRules = hiviewPlatform->GetPipelineConfigMap();
241 auto const &pipelineMap = hiviewPlatform->GetPipelineMap();
242 for (auto it = pipelineRules.begin(); it != pipelineRules.end(); it++) {
243 std::string pipelineName = it->first;
244 auto dispathRule = it->second;
245 if (dispathRule->FindEvent(event->domain_, event->eventName_)) {
246 pipelineMap.at(pipelineName)->ProcessEvent(event);
247 return true;
248 }
249 }
250 pipelineMap.at("SysEventPipeline")->ProcessEvent(event);
251 return true;
252 }
253
CheckEvent(std::shared_ptr<Event> event)254 bool SysEventSource::CheckEvent(std::shared_ptr<Event> event)
255 {
256 if (isConfigUpdated_) {
257 EventJsonParser::GetInstance()->OnConfigUpdate();
258 isConfigUpdated_.store(false);
259 }
260 std::shared_ptr<SysEvent> sysEvent = Convert2SysEvent(event);
261 if (sysEvent == nullptr) {
262 HIVIEW_LOGE("event or event parser is null.");
263 sysEventStat_->AccumulateEvent(false);
264 return false;
265 }
266 CheckIfEventDelayed(isLastEventDelayed_, sysEvent);
267 if (controller_ != nullptr && !controller_->CheckThreshold(sysEvent)) {
268 sysEventStat_->AccumulateEvent(false);
269 return false;
270 }
271 if (!IsValidSysEvent(sysEvent)) {
272 sysEventStat_->AccumulateEvent(sysEvent->domain_, sysEvent->eventName_, false);
273 return false;
274 }
275 if (FocusedEventUtil::IsFocusedEvent(sysEvent->domain_, sysEvent->eventName_)) {
276 HIVIEW_LOGI("event[%{public}s|%{public}s|%{public}" PRIu64 "] is valid.",
277 sysEvent->domain_.c_str(), sysEvent->eventName_.c_str(), event->happenTime_);
278 } else {
279 HIVIEW_LOGD("event[%{public}s|%{public}s|%{public}" PRIu64 "] is valid.",
280 sysEvent->domain_.c_str(), sysEvent->eventName_.c_str(), event->happenTime_);
281 }
282 StatisticSourcePeriodInfo(sysEvent);
283 sysEventStat_->AccumulateEvent();
284 return true;
285 }
286
Convert2SysEvent(std::shared_ptr<Event> & event)287 std::shared_ptr<SysEvent> SysEventSource::Convert2SysEvent(std::shared_ptr<Event>& event)
288 {
289 if (event == nullptr) {
290 HIVIEW_LOGE("event is null");
291 return nullptr;
292 }
293 if (event->messageType_ != Event::MessageType::SYS_EVENT) {
294 HIVIEW_LOGE("receive out of sys event type");
295 return nullptr;
296 }
297 return Event::DownCastTo<SysEvent>(event);
298 }
299
ShowUsage(int fd,const std::vector<std::string> & cmds)300 static void ShowUsage(int fd, const std::vector<std::string>& cmds)
301 {
302 dprintf(fd, "invalid cmd:");
303 for (auto it = cmds.begin(); it != cmds.end(); it++) {
304 dprintf(fd, "%s ", it->c_str());
305 }
306 dprintf(fd, "\n");
307 dprintf(fd, "usage: SysEventService [sum|detail|invalid|clear]\n");
308 }
309
Dump(int fd,const std::vector<std::string> & cmds)310 void SysEventSource::Dump(int fd, const std::vector<std::string>& cmds)
311 {
312 if (cmds.size() >= 2) { // 2: args from the second item
313 std::string arg1 = cmds[1];
314 if (arg1 == "sum") {
315 sysEventStat_->StatSummary(fd);
316 } else if (arg1 == "detail") {
317 sysEventStat_->StatDetail(fd);
318 } else if (arg1 == "invalid") {
319 sysEventStat_->StatInvalidDetail(fd);
320 } else if (arg1 == "clear") {
321 sysEventStat_->Clear(fd);
322 } else {
323 ShowUsage(fd, cmds);
324 }
325 } else {
326 sysEventStat_->StatSummary(fd);
327 }
328 }
329
OnConfigUpdate(const std::string & localCfgPath,const std::string & cloudCfgPath)330 void SysEventSource::OnConfigUpdate(const std::string& localCfgPath, const std::string& cloudCfgPath)
331 {
332 this->isConfigUpdated_.store(true);
333 }
334
IsValidSysEvent(const std::shared_ptr<SysEvent> event)335 bool SysEventSource::IsValidSysEvent(const std::shared_ptr<SysEvent> event)
336 {
337 if (event->domain_.empty() || event->eventName_.empty()) {
338 HIVIEW_LOGW("domain=%{public}s or name=%{public}s is empty.",
339 event->domain_.c_str(), event->eventName_.c_str());
340 return false;
341 }
342 auto baseInfo = EventJsonParser::GetInstance()->GetDefinedBaseInfoByDomainName(event->domain_, event->eventName_);
343 if (baseInfo.keyConfig.type == INVALID_EVENT_TYPE) {
344 HIVIEW_LOGW("type defined for event[%{public}s|%{public}s|%{public}" PRIu64 "] invalid, or privacy dismatch.",
345 event->domain_.c_str(), event->eventName_.c_str(), event->happenTime_);
346 return false;
347 }
348 if (event->GetEventType() != baseInfo.keyConfig.type) {
349 HIVIEW_LOGW("type=%{public}d of event[%{public}s|%{public}s|%{public}" PRIu64 "] is invalid.",
350 event->GetEventType(), event->domain_.c_str(), event->eventName_.c_str(), event->happenTime_);
351 return false;
352 }
353 // append id
354 auto eventId = GenerateHash(event);
355 if (IsDuplicateEvent(eventId)) {
356 HIVIEW_LOGW("ignore duplicate event[%{public}s|%{public}s|%{public}" PRIu64 "].",
357 event->domain_.c_str(), event->eventName_.c_str(), eventId);
358 return false;
359 }
360 DecorateSysEvent(event, baseInfo, eventId);
361 return true;
362 }
363
UpdateTestType(const std::string & testType)364 void SysEventSource::UpdateTestType(const std::string& testType)
365 {
366 testType_ = testType;
367 }
368
DecorateSysEvent(const std::shared_ptr<SysEvent> event,const BaseInfo & baseInfo,uint64_t id)369 void SysEventSource::DecorateSysEvent(const std::shared_ptr<SysEvent> event, const BaseInfo& baseInfo, uint64_t id)
370 {
371 if (!baseInfo.level.empty()) {
372 event->SetLevel(baseInfo.level);
373 }
374 if (!baseInfo.tag.empty()) {
375 event->SetTag(baseInfo.tag);
376 }
377 event->SetPrivacy(baseInfo.keyConfig.privacy);
378 if (!testType_.empty()) {
379 event->SetEventValue(TEST_TYPE_KEY, testType_);
380 }
381 event->preserve_ = baseInfo.keyConfig.preserve;
382 event->collect_ = baseInfo.keyConfig.collect;
383 // add hashcode id
384 event->SetId(id);
385 event->SetInvalidParams(baseInfo.disallowParams);
386 }
387
IsDuplicateEvent(const uint64_t eventId)388 bool SysEventSource::IsDuplicateEvent(const uint64_t eventId)
389 {
390 for (auto iter = eventIdList_.rbegin(); iter != eventIdList_.rend(); ++iter) {
391 if (*iter == eventId) {
392 return true;
393 }
394 }
395 std::list<uint64_t>::size_type maxSize { 25 }; // size of queue limit to 25
396 if (eventIdList_.size() >= maxSize) {
397 eventIdList_.pop_front();
398 }
399 eventIdList_.emplace_back(eventId);
400 return false;
401 }
402
GetEventExportConfigFilePath()403 std::string SysEventSource::GetEventExportConfigFilePath()
404 {
405 auto context = GetHiviewContext();
406 if (context == nullptr) {
407 HIVIEW_LOGW("context is null");
408 return "";
409 }
410 std::string configPath = context->GetHiViewDirectory(HiviewContext::DirectoryType::CONFIG_DIRECTORY);
411 return configPath.append("hiviewx_events.json");
412 }
413
StatisticSourcePeriodInfo(const std::shared_ptr<SysEvent> event)414 void SysEventSource::StatisticSourcePeriodInfo(const std::shared_ptr<SysEvent> event)
415 {
416 if (!Parameter::IsBetaVersion()) {
417 return;
418 }
419 auto curTimeStamp = TimeUtil::TimestampFormatToDate(TimeUtil::GetSeconds(), "%Y%m%d%H");
420 std::shared_ptr<SourcePeriodInfo> recentPeriodInfo = nullptr;
421 if (!periodInfoList_.empty()) {
422 recentPeriodInfo = periodInfoList_.back();
423 }
424 EventPeriodSeqInfo eventPeriodSeqInfo;
425 eventPeriodSeqInfo.timeStamp = curTimeStamp;
426 if (recentPeriodInfo != nullptr && recentPeriodInfo->timeStamp == curTimeStamp) {
427 periodSeq_++;
428 eventPeriodSeqInfo.periodSeq = periodSeq_;
429 if (event->collect_) {
430 ++(recentPeriodInfo->exportCnt);
431 eventPeriodSeqInfo.isNeedExport = true;
432 }
433 if (event->preserve_) {
434 ++(recentPeriodInfo->preserveCnt);
435 }
436 event->SetEventPeriodSeqInfo(eventPeriodSeqInfo);
437 RecordSourcePeriodInfo();
438 return;
439 }
440
441 // clear and log historical info
442 while (!periodInfoList_.empty()) {
443 auto infoItem = periodInfoList_.front();
444 LogSourcePeriodInfo(infoItem);
445 periodInfoList_.pop_front();
446 }
447
448 periodSeq_ = DEFAULT_PERIOD_SEQ;
449 eventPeriodSeqInfo.isNeedExport = event->collect_;
450 eventPeriodSeqInfo.periodSeq = periodSeq_;
451 event->SetEventPeriodSeqInfo(eventPeriodSeqInfo);
452 recentPeriodInfo = std::make_shared<SourcePeriodInfo>(curTimeStamp, static_cast<uint64_t>(event->preserve_),
453 static_cast<uint64_t>(event->collect_));
454 periodInfoList_.emplace_back(recentPeriodInfo);
455 RecordSourcePeriodInfo();
456 }
457
RecordSourcePeriodInfo()458 void SysEventSource::RecordSourcePeriodInfo()
459 {
460 periodFileOpt_->WritePeriodInfoToFile([this] () {
461 std::string periodInfoContent;
462 for (const auto& periodInfo : periodInfoList_) {
463 if (periodInfo == nullptr) {
464 HIVIEW_LOGE("event source info item is null");
465 continue;
466 }
467 periodInfoContent.append(periodInfo->timeStamp).append(SOURCE_PERIOD_CNT_ITEM_CONCATE);
468 periodInfoContent.append(std::to_string(periodInfo->preserveCnt)).append(SOURCE_PERIOD_CNT_ITEM_CONCATE);
469 periodInfoContent.append(std::to_string(periodInfo->exportCnt)).append("\n");
470 }
471 return periodInfoContent;
472 });
473 }
474 } // namespace HiviewDFX
475 } // namespace OHOS
476