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