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 "unified_collector.h"
16
17 #include <ctime>
18 #include <memory>
19
20 #include "collect_event.h"
21 #include "ffrt.h"
22 #include "file_util.h"
23 #include "hiview_logger.h"
24 #include "io_collector.h"
25 #include "memory_collector.h"
26 #include "parameter_ex.h"
27 #include "plugin_factory.h"
28 #include "process_status.h"
29 #include "sys_event.h"
30 #include "time_util.h"
31 #include "uc_observer_mgr.h"
32 #include "unified_collection_stat.h"
33 #ifdef UNIFIED_COLLECTOR_TRACE_ENABLE
34 #include "app_caller_event.h"
35 #include "event_publish.h"
36 #include "hisysevent.h"
37 #include "trace_utils.h"
38 #include "trace_state_machine.h"
39 #include "trace_flow_controller.h"
40 #include "uc_telemetry_listener.h"
41 #include "unified_common.h"
42 #endif
43
44 namespace OHOS {
45 namespace HiviewDFX {
46 REGISTER(UnifiedCollector);
47 DEFINE_LOG_TAG("HiView-UnifiedCollector");
48 using namespace OHOS::HiviewDFX::UCollectUtil;
49 using namespace std::literals::chrono_literals;
50 namespace {
51 const std::string HIPERF_LOG_PATH = "/data/log/hiperf";
52 const std::string COLLECTION_IO_PATH = "/data/log/hiview/unified_collection/io/";
53 const std::string HIVIEW_UCOLLECTION_STATE_TRUE = "true";
54 const std::string HIVIEW_UCOLLECTION_STATE_FALSE = "false";
55 #ifdef UNIFIED_COLLECTOR_TRACE_ENABLE
56 const std::string UNIFIED_SHARE_PATH = "/data/log/hiview/unified_collection/trace/share/";
57 const std::string UNIFIED_SPECIAL_PATH = "/data/log/hiview/unified_collection/trace/special/";
58 const std::string UNIFIED_TELEMETRY_PATH = "/data/log/hiview/unified_collection/trace/telemetry/";
59 const std::string UNIFIED_SHARE_TEMP_PATH = UNIFIED_SHARE_PATH + "temp/";
60 const std::string DEVELOP_TRACE_RECORDER_FALSE = "false";
61 constexpr char KEY_FREEZE_DETECTOR_STATE[] = "persist.hiview.freeze_detector";
62 const std::string OTHER = "Other";
63 using namespace OHOS::HiviewDFX::Hitrace;
64 constexpr int32_t DURATION_TRACE = 10; // unit second
65
CreateTracePathInner(const std::string & filePath)66 void CreateTracePathInner(const std::string &filePath)
67 {
68 if (FileUtil::FileExists(filePath)) {
69 return;
70 }
71 if (!CreateMultiDirectory(filePath)) {
72 HIVIEW_LOGE("failed to create multidirectory %{public}s.", filePath.c_str());
73 return;
74 }
75 }
76
CreateTracePath()77 void CreateTracePath()
78 {
79 CreateTracePathInner(UNIFIED_SHARE_PATH);
80 CreateTracePathInner(UNIFIED_SPECIAL_PATH);
81 CreateTracePathInner(UNIFIED_TELEMETRY_PATH);
82 }
83 #endif
84 }
85
OnLoad()86 void UnifiedCollector::OnLoad()
87 {
88 HIVIEW_LOGI("start to load UnifiedCollector plugin");
89 Init();
90 }
91
OnUnload()92 void UnifiedCollector::OnUnload()
93 {
94 HIVIEW_LOGI("start to unload UnifiedCollector plugin");
95 UcObserverManager::GetInstance().UnregisterObservers();
96 }
97
98 #ifdef UNIFIED_COLLECTOR_TRACE_ENABLE
OnFreezeDetectorParamChanged(const char * key,const char * value,void * context)99 void UnifiedCollector::OnFreezeDetectorParamChanged(const char* key, const char* value, void* context)
100 {
101 if (key == nullptr || value == nullptr) {
102 HIVIEW_LOGW("key or value is null");
103 return;
104 }
105 if (strncmp(key, KEY_FREEZE_DETECTOR_STATE, strlen(KEY_FREEZE_DETECTOR_STATE)) != 0) {
106 HIVIEW_LOGW("key is not wanted, key: %{public}s", key);
107 return;
108 }
109 HIVIEW_LOGI("freeze detector param changed, value: %{public}s", value);
110 if (strncmp(value, "true", strlen("true")) == 0) {
111 TraceStateMachine::GetInstance().SetTraceSwitchFreezeOn();
112 } else {
113 TraceStateMachine::GetInstance().SetTraceSwitchFreezeOff();
114 }
115 }
116
OnSwitchRecordTraceStateChanged(const char * key,const char * value,void * context)117 void UnifiedCollector::OnSwitchRecordTraceStateChanged(const char* key, const char* value, void* context)
118 {
119 if (key == nullptr || value == nullptr) {
120 HIVIEW_LOGE("record trace switch input ptr null");
121 return;
122 }
123 if (strncmp(key, DEVELOP_HIVIEW_TRACE_RECORDER, strlen(DEVELOP_HIVIEW_TRACE_RECORDER)) != 0) {
124 HIVIEW_LOGE("record trace switch param key error");
125 return;
126 }
127 if (strncmp(value, "true", strlen("true")) == 0) {
128 TraceStateMachine::GetInstance().SetTraceSwitchDevOn();
129 } else {
130 TraceStateMachine::GetInstance().SetTraceSwitchDevOff();
131 }
132 }
133
LoadTraceSwitch()134 void UnifiedCollector::LoadTraceSwitch()
135 {
136 if (Parameter::IsBetaVersion()) {
137 TraceStateMachine::GetInstance().SetTraceVersionBeta();
138 } else {
139 int watchFreezeRet = Parameter::WatchParamChange(KEY_FREEZE_DETECTOR_STATE,
140 OnFreezeDetectorParamChanged, nullptr);
141 HIVIEW_LOGI("watchFreezeRet:%{public}d", watchFreezeRet);
142 }
143 if (Parameter::IsUCollectionSwitchOn()) {
144 TraceStateMachine::GetInstance().SetTraceSwitchUcOn();
145 }
146 if (Parameter::GetBoolean(KEY_FREEZE_DETECTOR_STATE, false)) {
147 TraceStateMachine::GetInstance().SetTraceSwitchFreezeOn();
148 }
149 if (Parameter::IsDeveloperMode()) {
150 if (Parameter::IsTraceCollectionSwitchOn()) {
151 TraceStateMachine::GetInstance().SetTraceSwitchDevOn();
152 }
153 int ret = Parameter::WatchParamChange(DEVELOP_HIVIEW_TRACE_RECORDER, OnSwitchRecordTraceStateChanged, this);
154 HIVIEW_LOGI("add ucollection trace switch param watcher ret: %{public}d", ret);
155 }
156 }
157
OnMainThreadJank(SysEvent & sysEvent)158 void UnifiedCollector::OnMainThreadJank(SysEvent& sysEvent)
159 {
160 if (sysEvent.GetEventIntValue(UCollectUtil::SYS_EVENT_PARAM_JANK_LEVEL) <
161 UCollectUtil::SYS_EVENT_JANK_LEVEL_VALUE_TRACE) {
162 // hicollie capture stack in application process, only need to share app event to application by hiview
163 Json::Value eventJson;
164 eventJson[UCollectUtil::APP_EVENT_PARAM_UID] = sysEvent.GetUid();
165 eventJson[UCollectUtil::APP_EVENT_PARAM_PID] = sysEvent.GetPid();
166 eventJson[UCollectUtil::APP_EVENT_PARAM_TIME] = sysEvent.happenTime_;
167 eventJson[UCollectUtil::APP_EVENT_PARAM_BUNDLE_NAME] = sysEvent.GetEventValue(
168 UCollectUtil::SYS_EVENT_PARAM_BUNDLE_NAME);
169 eventJson[UCollectUtil::APP_EVENT_PARAM_BUNDLE_VERSION] = sysEvent.GetEventValue(
170 UCollectUtil::SYS_EVENT_PARAM_BUNDLE_VERSION);
171 eventJson[UCollectUtil::APP_EVENT_PARAM_BEGIN_TIME] = sysEvent.GetEventIntValue(
172 UCollectUtil::SYS_EVENT_PARAM_BEGIN_TIME);
173 eventJson[UCollectUtil::APP_EVENT_PARAM_END_TIME] = sysEvent.GetEventIntValue(
174 UCollectUtil::SYS_EVENT_PARAM_END_TIME);
175 eventJson[UCollectUtil::APP_EVENT_PARAM_APP_START_JIFFIES_TIME] = sysEvent.GetEventIntValue(
176 UCollectUtil::SYS_EVENT_PARAM_APP_START_JIFFIES_TIME);
177 eventJson[UCollectUtil::APP_EVENT_PARAM_HEAVIEST_STACK] = sysEvent.GetEventValue(
178 UCollectUtil::SYS_EVENT_PARAM_HEAVIEST_STACK);
179 Json::Value externalLog;
180 externalLog.append(sysEvent.GetEventValue(UCollectUtil::SYS_EVENT_PARAM_EXTERNAL_LOG));
181 eventJson[UCollectUtil::APP_EVENT_PARAM_EXTERNAL_LOG] = externalLog;
182 std::string param = Json::FastWriter().write(eventJson);
183
184 HIVIEW_LOGI("send as stack trigger for uid=%{public}d pid=%{public}d", sysEvent.GetUid(), sysEvent.GetPid());
185 EventPublish::GetInstance().PushEvent(sysEvent.GetUid(), UCollectUtil::MAIN_THREAD_JANK,
186 HiSysEvent::EventType::FAULT, param);
187 }
188 }
189
OnEvent(std::shared_ptr<Event> & event)190 bool UnifiedCollector::OnEvent(std::shared_ptr<Event>& event)
191 {
192 if (event == nullptr || workLoop_ == nullptr) {
193 return true;
194 }
195 HIVIEW_LOGI("Receive Event %{public}s", event->GetEventName().c_str());
196 if (event->eventName_ == UCollectUtil::START_APP_TRACE) {
197 event->eventName_ = UCollectUtil::STOP_APP_TRACE;
198 DelayProcessEvent(event, DURATION_TRACE);
199 return true;
200 }
201 if (event->eventName_ == UCollectUtil::STOP_APP_TRACE) {
202 auto ret = TraceStateMachine::GetInstance().CloseTrace(TraceScenario::TRACE_DYNAMIC);
203 if (!ret.IsSuccess()) {
204 HIVIEW_LOGW("CloseTrace app trace fail");
205 }
206 return true;
207 }
208 if (event->eventName_ == TelemetryEvent::TELEMETRY_START) {
209 HandleTeleMetryStart(event);
210 return true;
211 }
212 if (event->eventName_ == TelemetryEvent::TELEMETRY_STOP) {
213 HandleTeleMetryStop();
214 return true;
215 }
216 if (event->eventName_ == TelemetryEvent::TELEMETRY_TIMEOUT) {
217 HandleTeleMetryTimeout();
218 return true;
219 }
220 return true;
221 }
222
HandleTeleMetryStart(std::shared_ptr<Event> & event)223 void UnifiedCollector::HandleTeleMetryStart(std::shared_ptr<Event> &event)
224 {
225 int32_t delay = event->GetIntValue(Telemetry::KEY_DELAY_TIME);
226 if (delay > 0) {
227 HIVIEW_LOGI("delay:%{public}d", delay);
228 event->SetValue(Telemetry::KEY_DELAY_TIME, 0);
229 auto seqId = workLoop_->AddTimerEvent(shared_from_this(), event, nullptr, static_cast<uint64_t>(delay), false);
230 telemetryList_.push_back(seqId);
231 return;
232 }
233 std::string tag = event->GetValue(Telemetry::KEY_TELEMETRY_TRACE_TAG);
234 int32_t traceDuration = event->GetIntValue(Telemetry::KEY_REMAIN_TIME);
235 std::string telemetryId = event->GetValue(Telemetry::KEY_ID);
236 std::string bundleName = event->GetValue(Telemetry::KEY_BUNDLE_NAME);
237 if (traceDuration <= 0) {
238 HIVIEW_LOGE("system error traceDuration:%{public}d", traceDuration);
239 return;
240 }
241 auto ret = TraceStateMachine::GetInstance().OpenTelemetryTrace(tag);
242 HiSysEventWrite(Telemetry::TELEMETRY_DOMAIN, "TASK_INFO", HiSysEvent::EventType::STATISTIC,
243 "ID", telemetryId,
244 "STAGE", "TRACE_BEGIN",
245 "ERROR", std::to_string(GetUcError(ret)),
246 "BUNDLE_NAME", bundleName);
247 event->eventName_ = TelemetryEvent::TELEMETRY_TIMEOUT;
248 if (ret.IsSuccess()) {
249 bool isSuccess = TraceStateMachine::GetInstance().RegisterTelemetryCallback([telemetryId, bundleName]() {
250 HiSysEventWrite(Telemetry::TELEMETRY_DOMAIN, "TASK_INFO", HiSysEvent::EventType::STATISTIC,
251 "ID", telemetryId,
252 "STAGE", "TRACE_END",
253 "ERROR", 0,
254 "BUNDLE_NAME", bundleName);
255 });
256 HIVIEW_LOGE("RegisterTelemetryCallback:%{public}d", isSuccess);
257 }
258 auto seqId = workLoop_->AddTimerEvent(shared_from_this(), event, nullptr, static_cast<uint64_t>(traceDuration),
259 false);
260 telemetryList_.push_back(seqId);
261 }
262
HandleTeleMetryStop()263 void UnifiedCollector::HandleTeleMetryStop()
264 {
265 TraceStateMachine::GetInstance().CloseTrace(TraceScenario::TRACE_TELEMETRY);
266 TraceFlowController controller(BusinessName::TELEMETRY);
267 controller.ClearTelemetryData();
268 for (auto it : telemetryList_) {
269 workLoop_->RemoveEvent(it);
270 }
271 telemetryList_.clear();
272 }
273
HandleTeleMetryTimeout()274 void UnifiedCollector::HandleTeleMetryTimeout()
275 {
276 TraceStateMachine::GetInstance().CloseTrace(TraceScenario::TRACE_TELEMETRY);
277 }
278
OnEventListeningCallback(const Event & event)279 void UnifiedCollector::OnEventListeningCallback(const Event& event)
280 {
281 SysEvent& sysEvent = static_cast<SysEvent&>(const_cast<Event&>(event));
282 HIVIEW_LOGI("sysevent %{public}s", sysEvent.eventName_.c_str());
283
284 if (sysEvent.eventName_ == UCollectUtil::MAIN_THREAD_JANK) {
285 OnMainThreadJank(sysEvent);
286 return;
287 }
288 }
289
Dump(int fd,const std::vector<std::string> & cmds)290 void UnifiedCollector::Dump(int fd, const std::vector<std::string>& cmds)
291 {
292 dprintf(fd, "device beta state is %s.\n", Parameter::IsBetaVersion() ? "beta" : "is not beta");
293
294 std::string remoteLogState = Parameter::GetString(HIVIEW_UCOLLECTION_STATE, HIVIEW_UCOLLECTION_STATE_FALSE);
295 dprintf(fd, "remote log state is %s.\n", remoteLogState.c_str());
296
297 std::string traceRecorderState = Parameter::GetString(DEVELOP_HIVIEW_TRACE_RECORDER, DEVELOP_TRACE_RECORDER_FALSE);
298 dprintf(fd, "trace recorder state is %s.\n", traceRecorderState.c_str());
299
300 dprintf(fd, "develop state is %s.\n", Parameter::IsDeveloperMode() ? "true" : "false");
301 }
302
303 #ifdef HIVIEW_LOW_MEM_THRESHOLD
RunCacheMonitorLoop()304 void UnifiedCollector::RunCacheMonitorLoop()
305 {
306 if (traceCacheMonitor_ == nullptr) {
307 traceCacheMonitor_ = std::make_shared<TraceCacheMonitor>();
308 }
309 traceCacheMonitor_->RunMonitorLoop();
310 }
311
ExitCacheMonitorLoop()312 void UnifiedCollector::ExitCacheMonitorLoop()
313 {
314 if (traceCacheMonitor_ != nullptr) {
315 traceCacheMonitor_->ExitMonitorLoop();
316 }
317 }
318 #endif
319 #endif
320
Init()321 void UnifiedCollector::Init()
322 {
323 auto context = GetHiviewContext();
324 if (context == nullptr) {
325 HIVIEW_LOGE("hiview context is null");
326 return;
327 }
328 workLoop_ = context->GetSharedWorkLoop();
329 if (workLoop_ == nullptr) {
330 HIVIEW_LOGE("workLoop is null");
331 return;
332 }
333 InitWorkPath();
334 #ifdef UNIFIED_COLLECTOR_TRACE_ENABLE
335 CreateTracePath();
336 LoadTraceSwitch();
337 telemetryListener_ = std::make_shared<TelemetryListener>(shared_from_this());
338 context->AddListenerInfo(Event::MessageType::TELEMETRY_EVENT, telemetryListener_->GetListenerName());
339 context->RegisterUnorderedEventListener(telemetryListener_);
340 RecoverTmpTrace();
341 #endif
342 if (Parameter::IsBetaVersion() || Parameter::IsUCollectionSwitchOn()) {
343 RunIoCollectionTask();
344 RunUCollectionStatTask();
345 }
346 if (Parameter::IsBetaVersion() || Parameter::IsUCollectionSwitchOn() || Parameter::IsDeveloperMode()) {
347 RunCpuCollectionTask();
348 #ifdef HIVIEW_LOW_MEM_THRESHOLD
349 RunCacheMonitorLoop();
350 #endif
351 }
352 if (!Parameter::IsBetaVersion()) {
353 int watchUcollectionRet = Parameter::WatchParamChange(HIVIEW_UCOLLECTION_STATE, OnSwitchStateChanged, this);
354 HIVIEW_LOGI("watchUcollectionRet:%{public}d", watchUcollectionRet);
355 }
356 UcObserverManager::GetInstance().RegisterObservers();
357 }
358
CleanDataFiles()359 void UnifiedCollector::CleanDataFiles()
360 {
361 #ifdef UNIFIED_COLLECTOR_TRACE_ENABLE
362 std::vector<std::string> files;
363 FileUtil::GetDirFiles(UNIFIED_SPECIAL_PATH, files);
364 for (const auto& file : files) {
365 if (file.find(OTHER) != std::string::npos) {
366 FileUtil::RemoveFile(file);
367 }
368 }
369 #endif
370 FileUtil::ForceRemoveDirectory(COLLECTION_IO_PATH, false);
371 FileUtil::ForceRemoveDirectory(HIPERF_LOG_PATH, false);
372 }
373
OnSwitchStateChanged(const char * key,const char * value,void * context)374 void UnifiedCollector::OnSwitchStateChanged(const char* key, const char* value, void* context)
375 {
376 if (context == nullptr || key == nullptr || value == nullptr) {
377 HIVIEW_LOGE("input ptr null");
378 return;
379 }
380 if (strncmp(key, HIVIEW_UCOLLECTION_STATE, strlen(HIVIEW_UCOLLECTION_STATE)) != 0) {
381 HIVIEW_LOGE("param key error");
382 return;
383 }
384 HIVIEW_LOGI("ucollection switch state changed, ret: %{public}s", value);
385 auto* unifiedCollectorPtr = static_cast<UnifiedCollector*>(context);
386 if (unifiedCollectorPtr == nullptr) {
387 HIVIEW_LOGE("unifiedCollectorPtr is null");
388 return;
389 }
390 if (value == HIVIEW_UCOLLECTION_STATE_TRUE) {
391 unifiedCollectorPtr->RunCpuCollectionTask();
392 unifiedCollectorPtr->RunIoCollectionTask();
393 unifiedCollectorPtr->RunUCollectionStatTask();
394 #ifdef UNIFIED_COLLECTOR_TRACE_ENABLE
395 TraceStateMachine::GetInstance().SetTraceSwitchUcOn();
396 #ifdef HIVIEW_LOW_MEM_THRESHOLD
397 unifiedCollectorPtr->RunCacheMonitorLoop();
398 #endif
399 #endif
400 } else {
401 if (!Parameter::IsDeveloperMode()) {
402 unifiedCollectorPtr->isCpuTaskRunning_ = false;
403 }
404 for (const auto &it : unifiedCollectorPtr->taskList_) {
405 unifiedCollectorPtr->workLoop_->RemoveEvent(it);
406 }
407 unifiedCollectorPtr->taskList_.clear();
408 #ifdef UNIFIED_COLLECTOR_TRACE_ENABLE
409 TraceStateMachine::GetInstance().SetTraceSwitchUcOff();
410 #ifdef HIVIEW_LOW_MEM_THRESHOLD
411 unifiedCollectorPtr->ExitCacheMonitorLoop();
412 #endif
413 #endif
414 unifiedCollectorPtr->CleanDataFiles();
415 }
416 }
417
InitWorkPath()418 void UnifiedCollector::InitWorkPath()
419 {
420 std::string hiviewWorkDir = GetHiviewContext()->GetHiViewDirectory(HiviewContext::DirectoryType::WORK_DIRECTORY);
421 const std::string uCollectionDirName = "unified_collection";
422 std::string tempWorkPath = FileUtil::IncludeTrailingPathDelimiter(hiviewWorkDir.append(uCollectionDirName));
423 if (!FileUtil::IsDirectory(tempWorkPath) && !FileUtil::ForceCreateDirectory(tempWorkPath)) {
424 HIVIEW_LOGE("failed to create dir=%{public}s", tempWorkPath.c_str());
425 return;
426 }
427 workPath_ = tempWorkPath;
428 }
429
RunCpuCollectionTask()430 void UnifiedCollector::RunCpuCollectionTask()
431 {
432 if (workPath_.empty() || isCpuTaskRunning_) {
433 HIVIEW_LOGE("workPath is null or task is running");
434 return;
435 }
436 isCpuTaskRunning_ = true;
437 auto task = [this] { this->CpuCollectionFfrtTask(); };
438 ffrt::submit(task, {}, {}, ffrt::task_attr().name("dft_uc_cpu").qos(ffrt::qos_default));
439 }
440
CpuCollectionFfrtTask()441 void UnifiedCollector::CpuCollectionFfrtTask()
442 {
443 cpuCollectionTask_ = std::make_shared<CpuCollectionTask>(workPath_);
444 while (true) {
445 if (!isCpuTaskRunning_) {
446 HIVIEW_LOGE("exit cpucollection task");
447 break;
448 }
449 ffrt::this_task::sleep_for(10s); // 10s: collect period
450 cpuCollectionTask_->Collect();
451 }
452 }
453
RunIoCollectionTask()454 void UnifiedCollector::RunIoCollectionTask()
455 {
456 if (workLoop_ == nullptr) {
457 HIVIEW_LOGE("workLoop is null");
458 return;
459 }
460 auto ioCollectionTask = [this] { this->IoCollectionTask(); };
461 const uint64_t taskInterval = 30; // 30s
462 auto ioSeqId = workLoop_->AddTimerEvent(nullptr, nullptr, ioCollectionTask, taskInterval, true);
463 taskList_.push_back(ioSeqId);
464 }
465
IoCollectionTask()466 void UnifiedCollector::IoCollectionTask()
467 {
468 auto ioCollector = UCollectUtil::IoCollector::Create();
469 (void)ioCollector->CollectDiskStats([](const DiskStats &stats) { return false; }, true);
470 (void)ioCollector->CollectAllProcIoStats(true);
471 }
472
RunUCollectionStatTask()473 void UnifiedCollector::RunUCollectionStatTask()
474 {
475 if (workLoop_ == nullptr) {
476 HIVIEW_LOGE("workLoop is null");
477 return;
478 }
479 auto statTask = [this] { this->UCollectionStatTask(); };
480 const uint64_t taskInterval = 600; // 600s
481 auto statSeqId = workLoop_->AddTimerEvent(nullptr, nullptr, statTask, taskInterval, true);
482 taskList_.push_back(statSeqId);
483 }
484
UCollectionStatTask()485 void UnifiedCollector::UCollectionStatTask()
486 {
487 UnifiedCollectionStat stat;
488 stat.Report();
489 }
490 } // namespace HiviewDFX
491 } // namespace OHOS
492