• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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