1 /*
2 * Copyright (c) 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 #ifndef LOG_TAG
16 #define LOG_TAG "DfxMsgManager"
17 #endif
18
19 #include <map>
20 #include <algorithm>
21
22 #include "dfx_msg_manager.h"
23 #include "hisysevent.h"
24 #include "audio_common_log.h"
25
26 namespace OHOS {
27 namespace AudioStandard {
28
29 static constexpr int32_t DEFAULT_DFX_REPORT_INTERVAL_MIN = 24 * 60;
30 static constexpr int32_t DFX_MSG_QUEUE_CAPACITY = 100;
31 static constexpr int32_t MAX_DFX_MSG_MEMBER_SIZE = 100;
32 static constexpr int32_t MAX_DFX_REPORT_APP_COUNT = 20;
33 static constexpr int64_t DFX_CHECK_REPORT_MSG_TIME_MS = 60 * 1000;
34 static constexpr uint32_t BIT_2_OFFSET = 1;
35 static constexpr uint32_t BIT_3_OFFSET = 2;
36
DfxMsgHandler(IHandler * handler)37 DfxMsgHandler::DfxMsgHandler(IHandler* handler) : handler_(handler) {}
38
OnHandle(uint32_t code,int64_t data)39 void DfxMsgHandler::OnHandle(uint32_t code, int64_t data)
40 {
41 CHECK_AND_RETURN_LOG(handler_ != nullptr, "handler is nullptr");
42 handler_->OnHandle(code, data);
43 }
44
GetInstance()45 DfxMsgManager& DfxMsgManager::GetInstance()
46 {
47 static DfxMsgManager instance;
48 return instance;
49 }
50
DfxMsgManager()51 DfxMsgManager::DfxMsgManager() : msgQueue_(DFX_MSG_QUEUE_CAPACITY)
52 {
53 }
54
OnHandle(uint32_t code,int64_t data)55 void DfxMsgManager::OnHandle(uint32_t code, int64_t data)
56 {
57 switch (code) {
58 case DFX_CHECK_REPORT_MSG:
59 CheckReportDfxMsg();
60 break;
61 default:
62 break;
63 }
64 }
65
SafeSendCallBackEvent(uint32_t eventCode,int64_t data,int64_t delayTime)66 void DfxMsgManager::SafeSendCallBackEvent(uint32_t eventCode, int64_t data, int64_t delayTime)
67 {
68 Trace trace("DfxMsgManager::SafeSendCallBackEvent");
69 CHECK_AND_RETURN_LOG(callbackHandler_ != nullptr, "Runner is Release");
70 std::lock_guard<std::mutex> lock(runnerMutex_);
71 callbackHandler_->SendCallbackEvent(eventCode, data, delayTime);
72 }
73
CheckReportDfxMsg()74 void DfxMsgManager::CheckReportDfxMsg()
75 {
76 Trace trace("DfxMsgManager::CheckReportDfxMsg");
77 AUDIO_INFO_LOG("entering CheckReportDfxMsg");
78 SafeSendCallBackEvent(DFX_CHECK_REPORT_MSG, 0, DFX_CHECK_REPORT_MSG_TIME_MS);
79
80 std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
81 auto interval = std::chrono::system_clock::from_time_t(now - lastReportTime_).time_since_epoch();
82 int intervalMin = std::chrono::duration_cast<std::chrono::minutes>(interval).count();
83
84 std::lock_guard<std::mutex> lock(mutexLock_);
85 if (intervalMin >= DEFAULT_DFX_REPORT_INTERVAL_MIN) {
86 AUDIO_INFO_LOG("time is up, report msg size=%{public}d", static_cast<int32_t>(reportQueue_.size()));
87 for (auto &item : reportQueue_) {
88 HandleToHiSysEvent(item.second);
89 }
90 reportQueue_.clear();
91 isFull_ = false;
92 reportedCnt_ = 0;
93 lastReportTime_ = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
94 cvReachLimit_.notify_all();
95 appInfo_.clear();
96 }
97
98 for (auto it = reportQueue_.begin(); it != reportQueue_.end();) {
99 if (reportedCnt_ >= MAX_DFX_REPORT_APP_COUNT) {
100 reportQueue_.clear();
101 break;
102 }
103 if (IsMsgReady(it->second)) {
104 HandleToHiSysEvent(it->second);
105 reportedCnt_++;
106 it = reportQueue_.erase(it);
107 } else {
108 ++it;
109 }
110 }
111 if (reportedCnt_ >= MAX_DFX_REPORT_APP_COUNT) {
112 AUDIO_WARNING_LOG("dfx report reach maximum size");
113 isFull_ = true;
114 }
115 }
116
IsMsgReady(const DfxMessage & msg)117 bool DfxMsgManager::IsMsgReady(const DfxMessage &msg)
118 {
119 return (msg.interruptInfo.size() == MAX_DFX_MSG_MEMBER_SIZE &&
120 (msg.captureInfo.size() == MAX_DFX_MSG_MEMBER_SIZE ||
121 msg.renderInfo.size() == MAX_DFX_MSG_MEMBER_SIZE));
122 }
123
Init()124 void DfxMsgManager::Init()
125 {
126 lastReportTime_ = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
127 timeThread_ = std::make_unique<std::thread>(&DfxMsgManager::TimeFunc, this);
128 pthread_setname_np(timeThread_->native_handle(), "AudioServerDFXTiming");
129
130 std::unique_lock<std::mutex> lock(runnerMutex_);
131 if (callbackHandler_ == nullptr) {
132 handler_ = std::make_shared<DfxMsgHandler>(this);
133 callbackHandler_ = CallbackHandler::GetInstance(handler_, "OS_DfxMsgCB");
134 AUDIO_INFO_LOG("init handler success");
135 }
136 lock.unlock();
137
138 SafeSendCallBackEvent(DFX_CHECK_REPORT_MSG, 0, DFX_CHECK_REPORT_MSG_TIME_MS);
139 }
140
~DfxMsgManager()141 DfxMsgManager::~DfxMsgManager()
142 {
143 AUDIO_INFO_LOG("DfxMsgManager deconstructor");
144 HandleThreadExit();
145 std::lock_guard<std::mutex> lock(runnerMutex_);
146 if (callbackHandler_ != nullptr) {
147 AUDIO_INFO_LOG("runner move");
148 callbackHandler_->ReleaseEventRunner();
149 callbackHandler_ = nullptr;
150 }
151 }
152
HandleThreadExit()153 void DfxMsgManager::HandleThreadExit()
154 {
155 startThread_.store(false, std::memory_order_release);
156 if (timeThread_ && timeThread_->joinable()) {
157 timeThread_->detach();
158 }
159
160 msgQueue_.PushNoWait({});
161 isFull_ = false;
162 cvReachLimit_.notify_all();
163 }
164
TimeFunc()165 void DfxMsgManager::TimeFunc()
166 {
167 while (startThread_.load(std::memory_order_acquire)) {
168 DfxMessage msg;
169 while (!isFull_ && startThread_) {
170 msg = msgQueue_.Pop();
171 if (!ProcessCheck(msg)) {
172 continue;
173 } else {
174 Process(msg);
175 }
176 }
177
178 std::unique_lock<std::mutex> lock(mutexLock_);
179 while (isFull_) {
180 AUDIO_INFO_LOG("today report reach max count, wait...");
181 cvReachLimit_.wait(lock, [&] { return !isFull_; });
182 }
183 }
184 AUDIO_INFO_LOG("TimeFunc exit");
185 }
186
ProcessCheck(const DfxMessage & msg)187 bool DfxMsgManager::ProcessCheck(const DfxMessage &msg)
188 {
189 if (msg.appUid == DFX_INVALID_APP_UID ||
190 msg.renderInfo.size() >= MAX_DFX_MSG_MEMBER_SIZE ||
191 msg.interruptInfo.size() >= MAX_DFX_MSG_MEMBER_SIZE ||
192 msg.captureInfo.size() >= MAX_DFX_MSG_MEMBER_SIZE) {
193 AUDIO_INFO_LOG("invalid msg, renderInfo=%{public}d" \
194 ", interruptInfo=%{public}d, captureInfo=%{public}d",
195 static_cast<int32_t>(msg.renderInfo.size()), static_cast<int32_t>(msg.interruptInfo.size()),
196 static_cast<int32_t>(msg.captureInfo.size()));
197 return false;
198 }
199
200 if (isFull_) {
201 AUDIO_INFO_LOG("dfx report reach maximum size, discard msg.appUid=%{public}d", msg.appUid);
202 return false;
203 }
204 return true;
205 }
206
Process(DfxMessage & msg)207 bool DfxMsgManager::Process(DfxMessage &msg)
208 {
209 std::lock_guard<std::mutex> lock(mutexLock_);
210 if (reportQueue_.count(msg.appUid) == 0) {
211 InsertReportQueue(msg);
212 return true;
213 }
214
215 bool processed = false;
216 auto range = reportQueue_.equal_range(msg.appUid);
217 for (auto it = range.first; it != range.second; ++it) {
218 auto nextIt = it;
219 ++nextIt;
220 bool isLast = (nextIt == range.second);
221 if (IsMsgReady(it->second) && !isLast) {
222 continue;
223 }
224 if (processed) {
225 break;
226 }
227 if (ProcessInner(msg.appUid, msg.renderInfo, it->second.renderInfo) ||
228 ProcessInner(msg.appUid, msg.interruptInfo, it->second.interruptInfo) ||
229 ProcessInner(msg.appUid, msg.captureInfo, it->second.captureInfo)) {
230 processed = true;
231 }
232 }
233 return processed;
234 }
235
InsertReportQueue(const DfxMessage & msg)236 void DfxMsgManager::InsertReportQueue(const DfxMessage &msg)
237 {
238 if (reportQueue_.size() == MAX_DFX_REPORT_APP_COUNT) {
239 Trace trace("reportQueue_ reach maximum size, can not insert");
240 return;
241 }
242 reportQueue_.insert(std::make_pair(msg.appUid, msg));
243 }
244
ProcessInner(int32_t index,std::list<RenderDfxInfo> & dfxInfo,std::list<RenderDfxInfo> & curDfxInfo)245 bool DfxMsgManager::ProcessInner(int32_t index,
246 std::list<RenderDfxInfo> &dfxInfo, std::list<RenderDfxInfo> &curDfxInfo)
247 {
248 bool processed = false;
249 int32_t size = dfxInfo.size();
250 if (size != 0) {
251 processed = true;
252 int32_t vacancy = MAX_DFX_MSG_MEMBER_SIZE - curDfxInfo.size();
253 vacancy = std::max(vacancy, 0);
254 if (vacancy == 0) {
255 InsertReportQueue({.appUid = index, .renderInfo = dfxInfo});
256 return processed;
257 }
258 if (vacancy < size) {
259 auto start = std::next(dfxInfo.begin(), vacancy);
260 std::list<RenderDfxInfo> split1{dfxInfo.begin(), start};
261 std::list<RenderDfxInfo> split2{start, dfxInfo.end()};
262 std::copy(split1.begin(), split1.end(), std::back_inserter(curDfxInfo));
263 InsertReportQueue({.appUid = index, .renderInfo = split2});
264 } else {
265 std::copy(dfxInfo.begin(), dfxInfo.end(), std::back_inserter(curDfxInfo));
266 }
267 }
268 return processed;
269 }
270
ProcessInner(int32_t index,std::list<InterruptDfxInfo> & dfxInfo,std::list<InterruptDfxInfo> & curDfxInfo)271 bool DfxMsgManager::ProcessInner(int32_t index,
272 std::list<InterruptDfxInfo> &dfxInfo, std::list<InterruptDfxInfo> &curDfxInfo)
273 {
274 bool processed = false;
275 int32_t size = dfxInfo.size();
276 if (size != 0) {
277 processed = true;
278 int32_t vacancy = MAX_DFX_MSG_MEMBER_SIZE - curDfxInfo.size();
279 vacancy = std::max(vacancy, 0);
280 if (vacancy == 0) {
281 InsertReportQueue({.appUid = index, .interruptInfo = dfxInfo});
282 return processed;
283 }
284 if (vacancy < size) {
285 auto start = std::next(dfxInfo.begin(), vacancy);
286 std::list<InterruptDfxInfo> split1{dfxInfo.begin(), start};
287 std::list<InterruptDfxInfo> split2{start, dfxInfo.end()};
288 std::copy(split1.begin(), split1.end(), std::back_inserter(curDfxInfo));
289 InsertReportQueue({.appUid = index, .interruptInfo = split2});
290 } else {
291 std::copy(dfxInfo.begin(), dfxInfo.end(), std::back_inserter(curDfxInfo));
292 }
293 }
294 return processed;
295 }
296
ProcessInner(int32_t index,std::list<CapturerDfxInfo> & dfxInfo,std::list<CapturerDfxInfo> & curDfxInfo)297 bool DfxMsgManager::ProcessInner(int32_t index,
298 std::list<CapturerDfxInfo> &dfxInfo, std::list<CapturerDfxInfo> &curDfxInfo)
299 {
300 bool processed = false;
301 int32_t size = dfxInfo.size();
302 if (size != 0) {
303 processed = true;
304 int32_t vacancy = MAX_DFX_MSG_MEMBER_SIZE - curDfxInfo.size();
305 vacancy = std::max(vacancy, 0);
306 if (vacancy == 0) {
307 InsertReportQueue({.appUid = index, .captureInfo = dfxInfo});
308 return processed;
309 }
310 if (vacancy < size) {
311 auto start = std::next(dfxInfo.begin(), vacancy);
312 std::list<CapturerDfxInfo> split1{dfxInfo.begin(), start};
313 std::list<CapturerDfxInfo> split2{start, dfxInfo.end()};
314 std::copy(split1.begin(), split1.end(), std::back_inserter(curDfxInfo));
315 InsertReportQueue({.appUid = index, .captureInfo = split2});
316 } else {
317 std::copy(dfxInfo.begin(), dfxInfo.end(), std::back_inserter(curDfxInfo));
318 }
319 }
320 return processed;
321 }
322
Enqueue(const DfxMessage & msg)323 bool DfxMsgManager::Enqueue(const DfxMessage &msg)
324 {
325 if (isFull_) {
326 AUDIO_WARNING_LOG("queue is full,");
327 Trace trace("queue is full, discard msg, appUid=" + std::to_string(msg.appUid));
328 return false;
329 }
330
331 if (CheckoutSystemAppUtil::CheckoutSystemApp(msg.appUid)) {
332 Trace trace("skip system app dfx msg.., appuid=" + std::to_string(msg.appUid));
333 AUDIO_WARNING_LOG("skip system app dfx msg.., appuid=%{public}d", msg.appUid);
334 return false;
335 }
336
337 return msgQueue_.PushNoWait(msg);
338 }
339
HandleToHiSysEvent(DfxMessage & msg)340 void DfxMsgManager::HandleToHiSysEvent(DfxMessage &msg)
341 {
342 auto dfxResult = std::make_unique<DfxReportResult>();
343 Trace trace("renderInfoSize=" + std::to_string(msg.renderInfo.size()) +
344 ", interruptInfoSize=" + std::to_string(msg.interruptInfo.size()) +
345 ", captureInfosize=" + std::to_string(msg.captureInfo.size()));
346 WriteRenderMsg(msg, dfxResult);
347 WriteInterruptMsg(msg, dfxResult);
348 WriteCapturerMsg(msg, dfxResult);
349 WriteRunningAppMsg(msg, dfxResult);
350
351 LogDfxResult(dfxResult);
352 WritePlayAudioStatsEvent(dfxResult);
353 }
354
LogDfxResult(const std::unique_ptr<DfxReportResult> & result)355 void DfxMsgManager::LogDfxResult(const std::unique_ptr<DfxReportResult> &result)
356 {
357 CHECK_AND_RETURN_LOG(result != nullptr, "result is null");
358 AUDIO_INFO_LOG("[HandleToHiSysEvent] appName=%{public}s", result->appName.c_str());
359 AUDIO_INFO_LOG("[HandleToHiSysEvent] appVersion=%{public}s", result->appVersion.c_str());
360 AUDIO_INFO_LOG("[HandleToHiSysEvent] summary=%{public}d", static_cast<int32_t>(result->summary));
361 AUDIO_INFO_LOG("[HandleToHiSysEvent] rendererActions=%{public}s",
362 DfxUtils::SerializeToJSONString(result->rendererActions).c_str());
363 AUDIO_INFO_LOG("[HandleToHiSysEvent] renderInfo=%{public}s",
364 DfxUtils::SerializeToJSONString(result->renderInfo).c_str());
365 AUDIO_INFO_LOG("[HandleToHiSysEvent] renderTimestamp=%{public}s",
366 DfxUtils::SerializeToJSONString(result->renderTimestamp).c_str());
367 AUDIO_INFO_LOG("[HandleToHiSysEvent] rendererStats=%{public}s",
368 DfxUtils::SerializeToJSONString(result->rendererStats).c_str());
369 AUDIO_INFO_LOG("[HandleToHiSysEvent] interruptActions=%{public}s",
370 DfxUtils::SerializeToJSONString(result->interruptActions).c_str());
371 AUDIO_INFO_LOG("[HandleToHiSysEvent] interruptTimestamp=%{public}s",
372 DfxUtils::SerializeToJSONString(result->interruptTimestamp).c_str());
373 AUDIO_INFO_LOG("[HandleToHiSysEvent] interruptEffect=%{public}s",
374 DfxUtils::SerializeToJSONString(result->interruptEffect).c_str());
375 AUDIO_INFO_LOG("[HandleToHiSysEvent] interruptInfo=%{public}s",
376 DfxUtils::SerializeToJSONString(result->interruptInfo).c_str());
377 AUDIO_INFO_LOG("[HandleToHiSysEvent] capturerActions=%{public}s",
378 DfxUtils::SerializeToJSONString(result->capturerActions).c_str());
379 AUDIO_INFO_LOG("[HandleToHiSysEvent] capturerInfo=%{public}s",
380 DfxUtils::SerializeToJSONString(result->capturerInfo).c_str());
381 AUDIO_INFO_LOG("[HandleToHiSysEvent] capturerTimestamp=%{public}s",
382 DfxUtils::SerializeToJSONString(result->capturerTimestamp).c_str());
383 AUDIO_INFO_LOG("[HandleToHiSysEvent] capturerStat=%{public}s",
384 DfxUtils::SerializeToJSONString(result->capturerStat).c_str());
385 AUDIO_INFO_LOG("[HandleToHiSysEvent] appState=%{public}s",
386 DfxUtils::SerializeToJSONString(result->appState).c_str());
387 AUDIO_INFO_LOG("[HandleToHiSysEvent] appStateTimestamp=%{public}s",
388 DfxUtils::SerializeToJSONString(result->appStateTimestamp).c_str());
389 }
390
WriteRenderMsg(DfxMessage & msg,const std::unique_ptr<DfxReportResult> & result)391 void DfxMsgManager::WriteRenderMsg(DfxMessage &msg, const std::unique_ptr<DfxReportResult> &result)
392 {
393 CHECK_AND_RETURN_LOG(result != nullptr, "result is null");
394 std::vector<uint32_t> rendererActions{};
395 std::vector<uint32_t> rendererInfos{};
396 std::vector<uint64_t> timestamps{};
397 std::vector<std::string> rendererStatVec{};
398
399 msg.renderInfo.sort([](const auto &item1, const auto &item2) {
400 return item1.rendererAction.timestamp < item2.rendererAction.timestamp;
401 });
402
403 for (auto &item : msg.renderInfo) {
404 auto rendererAction = DfxUtils::SerializeToUint32(item.rendererAction);
405
406 rendererActions.push_back(static_cast<uint32_t>(rendererAction));
407 timestamps.push_back(item.rendererAction.timestamp);
408
409 if (static_cast<RendererStage>(item.rendererAction.fourthByte) == RendererStage::RENDERER_STAGE_STOP_OK) {
410 auto rendererStat = DfxUtils::SerializeToJSONString(item.rendererStat);
411 rendererStatVec.push_back(rendererStat);
412 }
413
414 if (static_cast<RendererStage>(item.rendererAction.fourthByte) == RendererStage::RENDERER_STAGE_START_OK ||
415 static_cast<RendererStage>(item.rendererAction.fourthByte) == RendererStage::RENDERER_STAGE_START_FAIL) {
416 auto rendererInfo = DfxUtils::SerializeToUint32(item.rendererInfo);
417 rendererInfos.push_back(rendererInfo);
418 }
419 }
420
421 result->rendererActions = std::move(rendererActions);
422 result->renderTimestamp = std::move(timestamps);
423 result->renderInfo = std::move(rendererInfos);
424 result->rendererStats = std::move(rendererStatVec);
425 }
426
WriteInterruptMsg(DfxMessage & msg,const std::unique_ptr<DfxReportResult> & result)427 void DfxMsgManager::WriteInterruptMsg(DfxMessage &msg, const std::unique_ptr<DfxReportResult> &result)
428 {
429 CHECK_AND_RETURN_LOG(result != nullptr, "result is null");
430 std::vector<uint32_t> interruptActions{};
431 std::vector<uint64_t> timestamps{};
432 std::vector<std::string> interruptEffectVec{};
433 std::vector<uint32_t> interruptInfoVec{};
434
435 uint8_t interruptOthersFlag = 0;
436 uint8_t interruptedFlag = 0;
437 msg.interruptInfo.sort([](const auto &item1, const auto &item2) {
438 return item1.interruptAction.timestamp < item2.interruptAction.timestamp;
439 });
440
441 for (auto &item : msg.interruptInfo) {
442 auto interruptAction = DfxUtils::SerializeToUint32(item.interruptAction);
443 interruptActions.push_back(interruptAction);
444 timestamps.push_back(item.interruptAction.timestamp);
445 auto stage = static_cast<InterruptStage>(item.interruptAction.fourthByte);
446 if (!item.interruptEffectVec.empty()) {
447 auto interruptEffect = DfxUtils::SerializeToJSONString(item.interruptEffectVec);
448 interruptEffectVec.push_back(interruptEffect);
449 interruptOthersFlag = 1;
450 }
451 interruptedFlag = stage == InterruptStage::INTERRUPT_STAGE_STOPPED ? 1 : interruptedFlag;
452
453 if (stage == InterruptStage::INTERRUPT_STAGE_START ||
454 stage == InterruptStage::INTERRUPT_STAGE_RESTART) {
455 auto interruptInfo = DfxUtils::SerializeToUint32(item.interruptInfo);
456 interruptInfoVec.push_back(interruptInfo);
457 }
458 }
459
460 uint8_t interruptBackgroundFlag = 0;
461 if (appInfo_.count(msg.appUid) != 0) {
462 auto &item = appInfo_[msg.appUid];
463 auto iter = std::find_if(item.appStateVec.begin(), item.appStateVec.end(), [](const auto &item) {
464 return static_cast<DfxAppState>(item) == DFX_APP_STATE_BACKGROUND;
465 });
466 if (iter != item.appStateVec.end()) {
467 interruptBackgroundFlag = 1;
468 }
469 }
470
471 result->interruptActions = std::move(interruptActions);
472 result->interruptTimestamp = std::move(timestamps);
473 result->interruptInfo = std::move(interruptInfoVec);
474 result->interruptEffect = std::move(interruptEffectVec);
475 uint8_t summaryInt = (interruptOthersFlag << BIT_3_OFFSET) | (interruptedFlag << BIT_2_OFFSET) |
476 interruptBackgroundFlag;
477 result->summary = DfxUtils::SerializeToUint32({0, 0, 0, summaryInt});
478 }
479
WriteCapturerMsg(DfxMessage & msg,const std::unique_ptr<DfxReportResult> & result)480 void DfxMsgManager::WriteCapturerMsg(DfxMessage &msg, const std::unique_ptr<DfxReportResult> &result)
481 {
482 CHECK_AND_RETURN_LOG(result != nullptr, "result is null");
483 std::vector<uint32_t> capturerActions{};
484 std::vector<uint32_t> capturerInfos{};
485 std::vector<uint64_t> timestamps{};
486 std::vector<std::string> capturerStatVec{};
487
488 msg.captureInfo.sort([](const auto &item1, const auto &item2) {
489 return item1.capturerAction.timestamp < item2.capturerAction.timestamp;
490 });
491
492 for (auto &item : msg.captureInfo) {
493 auto capturerAction = DfxUtils::SerializeToUint32(item.capturerAction);
494
495 capturerActions.push_back(static_cast<uint32_t>(capturerAction));
496 timestamps.push_back(item.capturerAction.timestamp);
497 if (static_cast<CapturerStage>(item.capturerAction.fourthByte) == CapturerStage::CAPTURER_STAGE_STOP_OK) {
498 auto capturerStat = DfxUtils::SerializeToJSONString(item.capturerStat);
499 capturerStatVec.push_back(capturerStat);
500 }
501
502 if (static_cast<CapturerStage>(item.capturerAction.fourthByte) == CapturerStage::CAPTURER_STAGE_START_OK ||
503 static_cast<CapturerStage>(item.capturerAction.fourthByte) == CapturerStage::CAPTURER_STAGE_START_FAIL) {
504 auto capturerInfo = DfxUtils::SerializeToUint32(item.capturerInfo);
505 capturerInfos.push_back(capturerInfo);
506 }
507 }
508
509 result->capturerActions = std::move(capturerActions);
510 result->capturerTimestamp = std::move(timestamps);
511 result->capturerInfo = std::move(capturerInfos);
512 result->capturerStat = std::move(capturerStatVec);
513 }
514
WriteRunningAppMsg(DfxMessage & msg,const std::unique_ptr<DfxReportResult> & result)515 void DfxMsgManager::WriteRunningAppMsg(DfxMessage &msg, const std::unique_ptr<DfxReportResult> &result)
516 {
517 CHECK_AND_RETURN_LOG(result != nullptr, "result is null");
518 if (appInfo_.count(msg.appUid) == 0) {
519 AUDIO_ERR_LOG("unknown appUid=%{public}d", msg.appUid);
520 return;
521 }
522
523 auto &item = appInfo_[msg.appUid];
524 result->appName = item.appName;
525 result->appVersion = item.versionName;
526 for (auto item : item.appStateVec) {
527 result->appState.push_back(item);
528 }
529
530 for (auto item : item.appStateTimeStampVec) {
531 result->appStateTimestamp.push_back(item);
532 }
533
534 item.appStateVec.clear();
535 item.appStateTimeStampVec.clear();
536 }
537
WritePlayAudioStatsEvent(const std::unique_ptr<DfxReportResult> & result)538 void DfxMsgManager::WritePlayAudioStatsEvent(const std::unique_ptr<DfxReportResult> &result)
539 {
540 CHECK_AND_RETURN_LOG(result != nullptr, "result is null");
541 auto ret = HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::AUDIO, "PLAY_AUDIO_STATS",
542 HiviewDFX::HiSysEvent::EventType::STATISTIC,
543 "APP_NAME", result->appName,
544 "APP_VERSION", result->appVersion,
545 "INTERRUPT_ACTION", result->interruptActions,
546 "INTERRUPT_TIMESTAMP", result->interruptTimestamp,
547 "INTERRUPT_INFO", result->interruptInfo,
548 "INTERRUPT_EFFECT", result->interruptEffect,
549 "RENDERER_ACTION", result->rendererActions,
550 "RENDERER_TIMESTAMP", result->renderTimestamp,
551 "RENDERER_INFO", result->renderInfo,
552 "RENDERER_STATS", result->rendererStats,
553 "RECORDER_ACTION", result->capturerActions,
554 "RECORDER_TIMESTAMP", result->capturerTimestamp,
555 "RECORDER_INFO", result->capturerInfo,
556 "RECORDER_STATS", result->capturerStat,
557 "APP_STATE", result->appState,
558 "APP_STATE_TIMESTAMP", result->appStateTimestamp,
559 "SUMMARY", result->summary);
560 if (ret) {
561 AUDIO_ERR_LOG("write event fail: PLAY_AUDIO_STATS, ret = %{public}d", ret);
562 }
563 }
564
CheckCanAddAppInfo(int32_t appUid)565 bool DfxMsgManager::CheckCanAddAppInfo(int32_t appUid)
566 {
567 bool ret = false;
568 if (CheckoutSystemAppUtil::CheckoutSystemApp(appUid)) {
569 Trace trace("skip system app dfx msg.., appuid=" + std::to_string(appUid));
570 AUDIO_WARNING_LOG("skip system app dfx msg.., appuid=%{public}d", appUid);
571 return ret;
572 }
573
574 ret = appInfo_.count(appUid) == 0;
575 return ret;
576 }
577
SaveAppInfo(const DfxRunningAppInfo info)578 void DfxMsgManager::SaveAppInfo(const DfxRunningAppInfo info)
579 {
580 if (appInfo_.count(info.appUid) == 0) {
581 appInfo_.insert(std::make_pair(info.appUid, info));
582 }
583 }
584
UpdateAppState(int32_t appUid,DfxAppState appState,bool forceUpdate)585 void DfxMsgManager::UpdateAppState(int32_t appUid, DfxAppState appState, bool forceUpdate)
586 {
587 if (appInfo_.count(appUid) != 0) {
588 auto &item = appInfo_[appUid];
589 DfxAppState recentAppState = !item.appStateVec.empty() ?
590 static_cast<DfxAppState>(item.appStateVec.back()) : DFX_APP_STATE_UNKNOWN;
591 if (!forceUpdate && recentAppState == DFX_APP_STATE_START) {
592 AUDIO_WARNING_LOG("discard unstarted audio stream app state");
593 return;
594 }
595 if (recentAppState == appState) {
596 AUDIO_WARNING_LOG("discard repeated app state");
597 return;
598 }
599 DfxStatAction dfxAppState = {appState, 0, 0, 0};
600 item.appStateVec.push_back(static_cast<uint8_t>(appState));
601 item.appStateTimeStampVec.push_back(dfxAppState.timestamp);
602 }
603 }
604
605 } // namespace AudioStandard
606 } // namespace OHOS
607