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