• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 "app_trace_context.h"
16 
17 #include <cinttypes>
18 #include <memory>
19 #include <mutex>
20 
21 #include "app_caller_event.h"
22 #include "collect_event.h"
23 #include "event_publish.h"
24 #include "file_util.h"
25 #include "hisysevent.h"
26 #include "hiview_logger.h"
27 #include "json/json.h"
28 #include "time_util.h"
29 #include "trace_flow_controller.h"
30 #include "trace_manager.h"
31 #include "utility/trace_collector.h"
32 
33 namespace OHOS {
34 namespace HiviewDFX {
35 DEFINE_LOG_TAG("HiView-AppTrace");
36 namespace {
37 std::recursive_mutex g_traceMutex;
38 // start => dump, start => stop, dump => stop, stop -> start
39 constexpr int32_t TRACE_STATE_START_APP_TRACE = 1;
40 constexpr int32_t TRACE_STATE_DUMP_APP_TRACE = 2;
41 constexpr int32_t TRACE_STATE_STOP_APP_TRACE = 3;
42 constexpr int32_t DURATION_TRACE = 10; // unit second
43 const std::string UNIFIED_SHARE_PATH = "/data/log/hiview/unified_collection/trace/share/";
44 
InnerMakeTraceFileName(std::shared_ptr<AppCallerEvent> appCallerEvent)45 std::string InnerMakeTraceFileName(std::shared_ptr<AppCallerEvent> appCallerEvent)
46 {
47     std::string &bundleName = appCallerEvent->bundleName_;
48     int32_t pid = appCallerEvent->pid_;
49     int64_t beginTime = appCallerEvent->taskBeginTime_;
50     int64_t endTime = appCallerEvent->taskEndTime_;
51     int32_t costTime = (appCallerEvent->taskEndTime_ - appCallerEvent->taskBeginTime_);
52 
53     std::string d1 = TimeUtil::TimestampFormatToDate(beginTime/ TimeUtil::SEC_TO_MILLISEC, "%Y%m%d%H%M%S");
54     std::string d2 = TimeUtil::TimestampFormatToDate(endTime/ TimeUtil::SEC_TO_MILLISEC, "%Y%m%d%H%M%S");
55 
56     std::string name;
57     name.append(UNIFIED_SHARE_PATH).append("APP_").append(bundleName).append("_").append(std::to_string(pid));
58     name.append("_").append(d1).append("_").append(d2).append("_").append(std::to_string(costTime)).append(".sys");
59     return name;
60 }
61 
InnerStartAppTrace(std::shared_ptr<AppCallerEvent> appCallerEvent,bool & isOpenTrace,bool & isTraceOn)62 bool InnerStartAppTrace(std::shared_ptr<AppCallerEvent> appCallerEvent, bool &isOpenTrace, bool &isTraceOn)
63 {
64     TraceManager manager;
65     std::string appArgs = "tags:graphic,ace,app clockType:boot bufferSize:1024 overwrite:1 fileLimit:20 ";
66     appArgs.append("appPid:").append(std::to_string(appCallerEvent->pid_));
67     int32_t retCode = manager.OpenRecordingTrace(appArgs);
68     if (retCode != UCollect::UcError::SUCCESS) {
69         HIVIEW_LOGE("failed to open trace for uid=%{public}d, pid=%{public}d, error code %{public}d",
70             appCallerEvent->uid_, appCallerEvent->pid_, retCode);
71         appCallerEvent->resultCode_ = retCode;
72         return false;
73     }
74     isOpenTrace = true;
75 
76     std::shared_ptr<UCollectUtil::TraceCollector> traceCollector = UCollectUtil::TraceCollector::Create();
77     CollectResult<int32_t> result = traceCollector->TraceOn();
78     if (result.retCode != UCollect::UcError::SUCCESS) {
79         HIVIEW_LOGE("failed to traceon for uid=%{public}d, pid=%{public}d, error code %{public}d",
80             appCallerEvent->uid_, appCallerEvent->pid_, retCode);
81         appCallerEvent->resultCode_ = result.retCode;
82         return false;
83     }
84     isTraceOn = true;
85     return true;
86 }
87 
InnerDumpAppTrace(std::shared_ptr<AppCallerEvent> appCallerEvent,bool & isDumpTrace,bool & isTraceOn)88 void InnerDumpAppTrace(std::shared_ptr<AppCallerEvent> appCallerEvent, bool &isDumpTrace, bool &isTraceOn)
89 {
90     std::shared_ptr<UCollectUtil::TraceCollector> traceCollector = UCollectUtil::TraceCollector::Create();
91     CollectResult<std::vector<std::string>> result = traceCollector->TraceOff();
92     if (result.retCode != UCollect::UcError::SUCCESS) {
93         HIVIEW_LOGE("trace off for uid=%{public}d pid=%{public}d error code=%{public}d",
94             appCallerEvent->uid_, appCallerEvent->pid_, result.retCode);
95         appCallerEvent->resultCode_ = result.retCode;
96         return;
97     }
98 
99     isTraceOn = false;
100     appCallerEvent->taskEndTime_ = static_cast<int64_t>(TimeUtil::GetMilliseconds());
101     if (result.data.empty()) {
102         HIVIEW_LOGE("failed to collect app trace for uid=%{public}d pid=%{public}d",
103             appCallerEvent->uid_, appCallerEvent->pid_);
104     } else {
105         isDumpTrace = true;
106         std::string traceFileName = InnerMakeTraceFileName(appCallerEvent);
107         FileUtil::RenameFile(result.data[0], traceFileName);
108         appCallerEvent->externalLog_ = traceFileName;
109     }
110 }
111 
InnerShareAppEvent(std::shared_ptr<AppCallerEvent> appCallerEvent)112 void InnerShareAppEvent(std::shared_ptr<AppCallerEvent> appCallerEvent)
113 {
114     Json::Value eventJson;
115     eventJson[UCollectUtil::APP_EVENT_PARAM_UID] = appCallerEvent->uid_;
116     eventJson[UCollectUtil::APP_EVENT_PARAM_PID] = appCallerEvent->pid_;
117     eventJson[UCollectUtil::APP_EVENT_PARAM_TIME] = appCallerEvent->happenTime_;
118     eventJson[UCollectUtil::APP_EVENT_PARAM_BUNDLE_NAME] = appCallerEvent->bundleName_;
119     eventJson[UCollectUtil::APP_EVENT_PARAM_BUNDLE_VERSION] = appCallerEvent->bundleVersion_;
120     eventJson[UCollectUtil::APP_EVENT_PARAM_BEGIN_TIME] = appCallerEvent->beginTime_;
121     eventJson[UCollectUtil::APP_EVENT_PARAM_END_TIME] = appCallerEvent->endTime_;
122     if (appCallerEvent->isBusinessJank_) {
123         eventJson[UCollectUtil::APP_EVENT_PARAM_ISBUSINESSJANK] = appCallerEvent->isBusinessJank_;
124     }
125     Json::Value externalLog;
126     externalLog.append(appCallerEvent->externalLog_);
127     eventJson[UCollectUtil::APP_EVENT_PARAM_EXTERNAL_LOG] = externalLog;
128     std::string param = Json::FastWriter().write(eventJson);
129 
130     HIVIEW_LOGI("send for uid=%{public}d pid=%{public}d", appCallerEvent->uid_, appCallerEvent->pid_);
131     EventPublish::GetInstance().PushEvent(appCallerEvent->uid_, UCollectUtil::MAIN_THREAD_JANK,
132         HiSysEvent::EventType::FAULT, param);
133 }
134 
InnerReportMainThreadJankForTrace(std::shared_ptr<AppCallerEvent> appCallerEvent)135 void InnerReportMainThreadJankForTrace(std::shared_ptr<AppCallerEvent> appCallerEvent)
136 {
137     HiSysEventWrite(HiSysEvent::Domain::FRAMEWORK, UCollectUtil::MAIN_THREAD_JANK, HiSysEvent::EventType::FAULT,
138         UCollectUtil::SYS_EVENT_PARAM_BUNDLE_NAME, appCallerEvent->bundleName_,
139         UCollectUtil::SYS_EVENT_PARAM_BUNDLE_VERSION, appCallerEvent->bundleVersion_,
140         UCollectUtil::SYS_EVENT_PARAM_BEGIN_TIME, appCallerEvent->beginTime_,
141         UCollectUtil::SYS_EVENT_PARAM_END_TIME, appCallerEvent->endTime_,
142         UCollectUtil::SYS_EVENT_PARAM_THREAD_NAME, appCallerEvent->threadName_,
143         UCollectUtil::SYS_EVENT_PARAM_FOREGROUND, appCallerEvent->foreground_,
144         UCollectUtil::SYS_EVENT_PARAM_LOG_TIME, appCallerEvent->taskEndTime_,
145         UCollectUtil::SYS_EVENT_PARAM_JANK_LEVEL, 1); // 1: over 450ms
146 }
147 
InnerHasCallAppTrace(std::shared_ptr<AppCallerEvent> appCallerEvent)148 bool InnerHasCallAppTrace(std::shared_ptr<AppCallerEvent> appCallerEvent)
149 {
150     std::shared_ptr<TraceFlowController> traceController = std::make_shared<TraceFlowController>();
151     if (traceController->HasCallOnceToday(appCallerEvent->uid_, appCallerEvent->happenTime_)) {
152         HIVIEW_LOGE("already capture trace uid=%{public}d pid=%{public}d",
153             appCallerEvent->uid_, appCallerEvent->pid_);
154         appCallerEvent->resultCode_ = UCollect::UcError::HAD_CAPTURED_TRACE;
155         return true;
156     }
157     return false;
158 }
159 }
160 
AppTraceContext(std::shared_ptr<AppTraceState> state)161 AppTraceContext::AppTraceContext(std::shared_ptr<AppTraceState> state)
162     : pid_(0), traceBegin_(0), isOpenTrace_(false), isTraceOn_(false), isDumpTrace_(false), state_(state)
163 {}
164 
TransferTo(std::shared_ptr<AppTraceState> state)165 int32_t AppTraceContext::TransferTo(std::shared_ptr<AppTraceState> state)
166 {
167     std::lock_guard<std::recursive_mutex> guard(g_traceMutex);
168     if (state_ == nullptr) {
169         state_ = state;
170         return state_->CaptureTrace();
171     }
172 
173     if (!state->Accept(state_)) {
174         return -1;
175     }
176 
177     state_ = state;
178     return state_->CaptureTrace();
179 }
180 
PublishStackEvent(SysEvent & sysEvent)181 void AppTraceContext::PublishStackEvent(SysEvent& sysEvent)
182 {
183     if (sysEvent.GetEventIntValue(UCollectUtil::SYS_EVENT_PARAM_JANK_LEVEL) <
184         UCollectUtil::SYS_EVENT_JANK_LEVEL_VALUE_TRACE) {
185         // hicollie capture stack in application process, only need to share app event to application by hiview
186         Json::Value eventJson;
187         eventJson[UCollectUtil::APP_EVENT_PARAM_UID] = sysEvent.GetUid();
188         eventJson[UCollectUtil::APP_EVENT_PARAM_PID] = sysEvent.GetPid();
189         eventJson[UCollectUtil::APP_EVENT_PARAM_TIME] = sysEvent.happenTime_;
190         eventJson[UCollectUtil::APP_EVENT_PARAM_BUNDLE_NAME] = sysEvent.GetEventValue(
191             UCollectUtil::SYS_EVENT_PARAM_BUNDLE_NAME);
192         eventJson[UCollectUtil::APP_EVENT_PARAM_BUNDLE_VERSION] = sysEvent.GetEventValue(
193             UCollectUtil::SYS_EVENT_PARAM_BUNDLE_VERSION);
194         eventJson[UCollectUtil::APP_EVENT_PARAM_BEGIN_TIME] = sysEvent.GetEventIntValue(
195             UCollectUtil::SYS_EVENT_PARAM_BEGIN_TIME);
196         eventJson[UCollectUtil::APP_EVENT_PARAM_END_TIME] = sysEvent.GetEventIntValue(
197             UCollectUtil::SYS_EVENT_PARAM_END_TIME);
198         eventJson[UCollectUtil::APP_EVENT_PARAM_APP_START_JIFFIES_TIME] = sysEvent.GetEventIntValue(
199             UCollectUtil::SYS_EVENT_PARAM_APP_START_JIFFIES_TIME);
200         eventJson[UCollectUtil::APP_EVENT_PARAM_HEAVIEST_STACK] = sysEvent.GetEventValue(
201             UCollectUtil::SYS_EVENT_PARAM_HEAVIEST_STACK);
202         Json::Value externalLog;
203         externalLog.append(sysEvent.GetEventValue(UCollectUtil::SYS_EVENT_PARAM_EXTERNAL_LOG));
204         eventJson[UCollectUtil::APP_EVENT_PARAM_EXTERNAL_LOG] = externalLog;
205         std::string param = Json::FastWriter().write(eventJson);
206 
207         HIVIEW_LOGI("send as stack trigger for uid=%{public}d pid=%{public}d", sysEvent.GetUid(), sysEvent.GetPid());
208         EventPublish::GetInstance().PushEvent(sysEvent.GetUid(), UCollectUtil::MAIN_THREAD_JANK,
209             HiSysEvent::EventType::FAULT, param);
210     }
211 }
212 
Reset()213 void AppTraceContext::Reset()
214 {
215     pid_ = 0;
216     traceBegin_ = 0;
217     isOpenTrace_ = false;
218     isTraceOn_ = false;
219     isDumpTrace_ = false;
220 }
221 
Accept(std::shared_ptr<AppTraceState> preState)222 bool StartTraceState::Accept(std::shared_ptr<AppTraceState> preState)
223 {
224     // stop -> start
225     if (preState->GetState() == TRACE_STATE_STOP_APP_TRACE) {
226         return true;
227     }
228 
229     appCallerEvent_->resultCode_ = UCollect::UcError::INVALID_TRACE_STATE;
230     return false;
231 }
232 
GetState()233 int32_t StartTraceState::GetState()
234 {
235     return TRACE_STATE_START_APP_TRACE;
236 }
237 
CaptureTrace()238 int32_t StartTraceState::CaptureTrace()
239 {
240     int32_t retCode = DoCaptureTrace();
241 
242     appCallerEvent_->eventName_ = UCollectUtil::STOP_APP_TRACE;
243     if (retCode == 0) {
244         // start -> stop after DURATION_TRACE seconds
245         plugin_->DelayProcessEvent(appCallerEvent_, DURATION_TRACE);
246     } else {
247         // start -> stop right now as start trace fail
248         // need to change to stop state then can wait for next start
249         appTraceContext_->TransferTo(std::make_shared<StopTraceState>(appTraceContext_, appCallerEvent_));
250     }
251 
252     return retCode;
253 }
254 
DoCaptureTrace()255 int32_t StartTraceState::DoCaptureTrace()
256 {
257     if (AppCallerEvent::isDynamicTraceOpen_) {
258         HIVIEW_LOGE("start trace is already open uid=%{public}d, pid=%{public}d",
259             appCallerEvent_->uid_, appCallerEvent_->pid_);
260         appCallerEvent_->resultCode_ = UCollect::UcError::EXISTS_CAPTURE_TASK;
261         return -1;
262     }
263 
264     // app only has one trace file each day
265     if (InnerHasCallAppTrace(appCallerEvent_)) {
266         return -1;
267     }
268 
269     AppCallerEvent::isDynamicTraceOpen_ = true;
270     HIVIEW_LOGI("start trace serval seconds for uid=%{public}d pid=%{public}d",
271         appCallerEvent_->uid_, appCallerEvent_->pid_);
272 
273     if (!InnerStartAppTrace(appCallerEvent_, appTraceContext_->isOpenTrace_, appTraceContext_->isTraceOn_)) {
274         return -1;
275     }
276 
277     appTraceContext_->traceBegin_ = static_cast<int64_t>(TimeUtil::GetMilliseconds());
278     appCallerEvent_->resultCode_ = UCollect::UcError::SUCCESS;
279     int64_t delay = appCallerEvent_->taskBeginTime_ - static_cast<int64_t>(appCallerEvent_->happenTime_);
280     int64_t cost = appTraceContext_->traceBegin_ - static_cast<int64_t>(appCallerEvent_->happenTime_);
281     HIVIEW_LOGI("trace is start for uid=%{public}d pid=%{public}d delay=%{public}" PRId64 ", cost=%{public}" PRId64 "",
282         appCallerEvent_->uid_, appCallerEvent_->pid_, delay, cost);
283     return 0;
284 }
285 
Accept(std::shared_ptr<AppTraceState> preState)286 bool DumpTraceState::Accept(std::shared_ptr<AppTraceState> preState)
287 {
288     // start -> dump
289     if (preState->GetState() == TRACE_STATE_START_APP_TRACE) {
290         if (preState->appCallerEvent_->pid_ != appCallerEvent_->pid_) {
291             appCallerEvent_->resultCode_ = UCollect::UcError::INCONSISTENT_PROCESS;
292             return false;
293         }
294         return true;
295     }
296 
297     appCallerEvent_->resultCode_ = UCollect::UcError::INVALID_TRACE_STATE;
298     return false;
299 }
300 
GetState()301 int32_t DumpTraceState::GetState()
302 {
303     return TRACE_STATE_DUMP_APP_TRACE;
304 }
305 
CaptureTrace()306 int32_t DumpTraceState::CaptureTrace()
307 {
308     int32_t retCode = DoCaptureTrace();
309 
310     // dump -> stop right now
311     appCallerEvent_->eventName_ = UCollectUtil::STOP_APP_TRACE;
312     appTraceContext_->TransferTo(std::make_shared<StopTraceState>(appTraceContext_, appCallerEvent_));
313     return retCode;
314 }
315 
DoCaptureTrace()316 int32_t DumpTraceState::DoCaptureTrace()
317 {
318     if (!AppCallerEvent::isDynamicTraceOpen_) {
319         HIVIEW_LOGE("dump trace is not open uid=%{public}d, pid=%{public}d",
320             appCallerEvent_->uid_, appCallerEvent_->pid_);
321         appCallerEvent_->resultCode_ = UCollect::UcError::UNEXISTS_CAPTURE_TASK;
322         return -1;
323     }
324 
325     // app only has one trace file each day
326     if (InnerHasCallAppTrace(appCallerEvent_)) {
327         return -1;
328     }
329 
330     int64_t delay = appCallerEvent_->taskBeginTime_ - static_cast<int64_t>(appCallerEvent_->happenTime_);
331     appCallerEvent_->taskBeginTime_ = appTraceContext_->traceBegin_;
332     InnerDumpAppTrace(appCallerEvent_, appTraceContext_->isDumpTrace_, appTraceContext_->isTraceOn_);
333 
334     // hicollie capture stack in application process, only need to share app event to application by hiview
335     InnerShareAppEvent(appCallerEvent_);
336 
337     std::shared_ptr<TraceFlowController> traceController = std::make_shared<TraceFlowController>();
338     traceController->RecordCaller(appCallerEvent_);
339     traceController->CleanOldAppTrace();
340 
341     InnerReportMainThreadJankForTrace(appCallerEvent_);
342 
343     int64_t cost = appCallerEvent_->taskEndTime_ - static_cast<int64_t>(appCallerEvent_->happenTime_);
344     HIVIEW_LOGI("dump trace for uid=%{public}d pid=%{public}d  delay=%{public}" PRId64 ", cost=%{public}" PRId64 "",
345         appCallerEvent_->uid_, appCallerEvent_->pid_, delay, cost);
346     return 0;
347 }
348 
Accept(std::shared_ptr<AppTraceState> preState)349 bool StopTraceState::Accept(std::shared_ptr<AppTraceState> preState)
350 {
351     // start -> stop
352     if (preState->GetState() == TRACE_STATE_START_APP_TRACE) {
353         return true;
354     }
355 
356     // dump -> stop
357     if (preState->GetState() == TRACE_STATE_DUMP_APP_TRACE) {
358         return true;
359     }
360 
361     HIVIEW_LOGI("already stop for uid=%{public}d pid=%{public}d", appCallerEvent_->uid_, appCallerEvent_->pid_);
362     return false;
363 }
364 
GetState()365 int32_t StopTraceState::GetState()
366 {
367     return TRACE_STATE_STOP_APP_TRACE;
368 }
369 
370 
CaptureTrace()371 int32_t StopTraceState::CaptureTrace()
372 {
373     if (appTraceContext_ == nullptr || appCallerEvent_ == nullptr) {
374         HIVIEW_LOGI("does not init state, can not run");
375         return -1;
376     }
377 
378     int32_t retCode = DoCaptureTrace();
379     appTraceContext_->Reset();
380     AppCallerEvent::isDynamicTraceOpen_ = false;
381     return retCode;
382 }
383 
DoCaptureTrace()384 int32_t StopTraceState::DoCaptureTrace()
385 {
386     if (!appTraceContext_->isOpenTrace_) {
387         HIVIEW_LOGI("as start trace failed, does not need stop trace for uid=%{public}d pid=%{public}d",
388             appCallerEvent_->uid_, appCallerEvent_->pid_);
389         return 0;
390     }
391 
392     if (appTraceContext_->isTraceOn_) {
393         std::shared_ptr<UCollectUtil::TraceCollector> traceCollector = UCollectUtil::TraceCollector::Create();
394         CollectResult<std::vector<std::string>> result = traceCollector->TraceOff();
395         if (result.retCode != UCollect::UcError::SUCCESS) {
396             HIVIEW_LOGE("trace off for uid=%{public}d pid=%{public}d error code=%{public}d",
397                 appCallerEvent_->uid_, appCallerEvent_->pid_, result.retCode);
398         }
399     }
400 
401     HIVIEW_LOGI("%{public}s for uid=%{public}d pid=%{public}d",
402         (appTraceContext_->isDumpTrace_ ? "stop trace" : "no dump"), appCallerEvent_->uid_, appCallerEvent_->pid_);
403 
404     TraceManager manager;
405     int32_t retCode = manager.CloseTrace();
406     if (retCode != UCollect::UcError::SUCCESS) {
407         HIVIEW_LOGE("close trace for uid=%{public}d pid=%{public}d error code=%{public}d",
408             appCallerEvent_->uid_, appCallerEvent_->pid_, retCode);
409     }
410     return 0;
411 }
412 }; // HiviewDFX
413 }; // HiviewDFX