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