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