1 /*
2 * Copyright (c) 2024-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
16 #define HST_LOG_TAG "DfxAgent"
17
18 #include "dfx_agent.h"
19 #include "common/log.h"
20 #include "common/media_source.h"
21 #include "hisysevent.h"
22
23 namespace OHOS {
24 namespace Media {
25 namespace {
26 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_PLAYER, "DfxAgent" };
27 constexpr int64_t LAG_EVENT_THRESHOLD_MS = 500; // Lag threshold is 500 ms
28 constexpr int64_t LAG_EVENT_UPPER_MS = 5000; // Lag upper threshold is 5000 ms
29 ConcurrentUidSet g_appUidSet{};
30 const std::string SOURCE = "SRC";
31 const std::string DEMUXER = "DEMUX";
32 const std::string VIDEO_SINK = "VSINK";
33 const std::string AUDIO_SINK = "ASINK";
34 const std::string VIDEO_RENDERER = "VRNDR";
35 }
36
37 const std::map<DfxEventType, DfxEventHandleFunc> DfxAgent::DFX_EVENT_HANDLERS_ = {
38 { DfxEventType::DFX_INFO_PLAYER_VIDEO_LAG, DfxAgent::ProcessVideoLagEvent },
39 { DfxEventType::DFX_INFO_PLAYER_AUDIO_LAG, DfxAgent::ProcessAudioLagEvent },
40 { DfxEventType::DFX_INFO_PLAYER_STREAM_LAG, DfxAgent::ProcessStreamLagEvent },
41 { DfxEventType::DFX_INFO_PLAYER_EOS_SEEK, DfxAgent::ProcessEosSeekEvent },
42 { DfxEventType::DFX_INFO_PERF_REPORT, DfxAgent::ProcessPerfInfoEvent },
43 };
44
45 const std::unordered_map<std::string, bool> PERF_ITEM_NECESSITY = {
46 { SOURCE, false },
47 { DEMUXER, false },
48 { VIDEO_SINK, true },
49 { AUDIO_SINK, false },
50 { VIDEO_RENDERER, true },
51 };
52
53
DfxAgent(const std::string & groupId,const std::string & appName)54 DfxAgent::DfxAgent(const std::string& groupId, const std::string& appName) : groupId_(groupId), appName_(appName)
55 {
56 dfxTask_ = std::make_unique<Task>("OS_Ply_Dfx", groupId_, TaskType::GLOBAL, TaskPriority::NORMAL, false);
57 MEDIA_LOG_I("DfxAgent create for app " PUBLIC_LOG_S, appName_.c_str());
58 }
59
~DfxAgent()60 DfxAgent::~DfxAgent()
61 {
62 dfxTask_.reset();
63 }
64
SetSourceType(PlayerDfxSourceType type)65 void DfxAgent::SetSourceType(PlayerDfxSourceType type)
66 {
67 FALSE_RETURN(dfxTask_ != nullptr);
68 std::weak_ptr<DfxAgent> agent = shared_from_this();
69 dfxTask_->SubmitJobOnce([agent, type] {
70 auto ptr = agent.lock();
71 FALSE_RETURN_MSG(ptr != nullptr, "DfxAgent is released");
72 ptr->sourceType_ = type;
73 });
74 }
75
SetInstanceId(const std::string & instanceId)76 void DfxAgent::SetInstanceId(const std::string& instanceId)
77 {
78 FALSE_RETURN(dfxTask_ != nullptr);
79 std::weak_ptr<DfxAgent> agent = shared_from_this();
80 dfxTask_->SubmitJobOnce([agent, instanceId] {
81 auto ptr = agent.lock();
82 FALSE_RETURN_MSG(ptr != nullptr, "DfxAgent is released");
83 ptr->instanceId_ = instanceId;
84 });
85 }
86
OnDfxEvent(const DfxEvent & event)87 void DfxAgent::OnDfxEvent(const DfxEvent &event)
88 {
89 auto ret = DfxAgent::DFX_EVENT_HANDLERS_.find(event.type);
90 FALSE_RETURN(ret != DfxAgent::DFX_EVENT_HANDLERS_.end());
91 FALSE_RETURN(dfxTask_ != nullptr);
92 std::weak_ptr<DfxAgent> agent = shared_from_this();
93 dfxTask_->SubmitJobOnce([agent, event, handler = ret->second] {
94 auto ptr = agent.lock();
95 FALSE_RETURN_MSG(ptr != nullptr, "DfxAgent is released");
96 handler(ptr, event);
97 });
98 }
99
ReportLagEvent(int64_t lagDuration,const std::string & eventMsg)100 void DfxAgent::ReportLagEvent(int64_t lagDuration, const std::string& eventMsg)
101 {
102 FALSE_RETURN(dfxTask_ != nullptr);
103 std::weak_ptr<DfxAgent> agent = shared_from_this();
104 dfxTask_->SubmitJobOnce([agent, lagDuration, eventMsg] {
105 auto ptr = agent.lock();
106 FALSE_RETURN_MSG(ptr != nullptr, "DfxAgent is released");
107 FALSE_RETURN(!(ptr->hasReported_));
108 std::string msg = eventMsg;
109 MEDIA_LOG_W("PLAYER_LAG event reported, lagDuration=" PUBLIC_LOG_D64 ", msg=" PUBLIC_LOG_S,
110 lagDuration, eventMsg.c_str());
111 HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::MULTI_MEDIA,
112 "PLAYER_LAG",
113 OHOS::HiviewDFX::HiSysEvent::EventType::FAULT,
114 "APP_NAME", ptr->appName_,
115 "INSTANCE_ID", ptr->instanceId_,
116 "SOURCE_TYPE", static_cast<uint8_t>(ptr->sourceType_),
117 "LAG_DURATION", static_cast<int32_t>(lagDuration),
118 "MSG", msg);
119 ptr->hasReported_ = true;
120 });
121 }
122
ReportEosSeek0Event(int32_t appUid)123 void DfxAgent::ReportEosSeek0Event(int32_t appUid)
124 {
125 FALSE_RETURN(dfxTask_ != nullptr);
126 dfxTask_->SubmitJobOnce([appUid, appName = appName_] {
127 FALSE_RETURN(g_appUidSet.IsAppFirstEvent(appUid));
128 HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::MULTI_MEDIA,
129 "EOS_SEEK_0",
130 OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC,
131 "APP_NAME", appName,
132 "APP_UID", appUid);
133 });
134 }
135
ResetAgent()136 void DfxAgent::ResetAgent()
137 {
138 FALSE_RETURN(dfxTask_ != nullptr);
139 std::weak_ptr<DfxAgent> agent = shared_from_this();
140 dfxTask_->SubmitJobOnce([agent] {
141 auto ptr = agent.lock();
142 FALSE_RETURN_MSG(ptr != nullptr, "DfxAgent is released");
143 ptr->hasReported_ = false;
144 });
145 }
146
ProcessVideoLagEvent(std::weak_ptr<DfxAgent> ptr,const DfxEvent & event)147 void DfxAgent::ProcessVideoLagEvent(std::weak_ptr<DfxAgent> ptr, const DfxEvent &event)
148 {
149 auto agent = ptr.lock();
150 FALSE_RETURN(agent != nullptr);
151 auto perfStr = agent->GetPerfStr(false);
152 MEDIA_LOG_W("%{public}s", perfStr.c_str());
153 agent->needPrintPerfLog_ = true;
154 int64_t lagDuration = AnyCast<int64_t>(event.param);
155 FALSE_RETURN(lagDuration >= LAG_EVENT_THRESHOLD_MS && lagDuration <= LAG_EVENT_UPPER_MS);
156 std::string msg = "lagEvent=Video ";
157 agent->ReportLagEvent(lagDuration, msg + perfStr);
158 }
159
ProcessAudioLagEvent(std::weak_ptr<DfxAgent> ptr,const DfxEvent & event)160 void DfxAgent::ProcessAudioLagEvent(std::weak_ptr<DfxAgent> ptr, const DfxEvent &event)
161 {
162 auto agent = ptr.lock();
163 FALSE_RETURN(agent != nullptr);
164 int64_t lagDuration = AnyCast<int64_t>(event.param);
165 FALSE_RETURN(lagDuration >= LAG_EVENT_THRESHOLD_MS);
166 std::string msg = "lagEvent=Audio";
167 agent->ReportLagEvent(lagDuration, msg);
168 }
169
ProcessStreamLagEvent(std::weak_ptr<DfxAgent> ptr,const DfxEvent & event)170 void DfxAgent::ProcessStreamLagEvent(std::weak_ptr<DfxAgent> ptr, const DfxEvent &event)
171 {
172 auto agent = ptr.lock();
173 FALSE_RETURN(agent != nullptr);
174 int64_t lagDuration = AnyCast<int64_t>(event.param);
175 FALSE_RETURN(lagDuration >= LAG_EVENT_THRESHOLD_MS);
176 std::string msg = "lagEvent=Stream";
177 agent->ReportLagEvent(lagDuration, msg);
178 }
179
ProcessEosSeekEvent(std::weak_ptr<DfxAgent> ptr,const DfxEvent & event)180 void DfxAgent::ProcessEosSeekEvent(std::weak_ptr<DfxAgent> ptr, const DfxEvent &event)
181 {
182 auto agent = ptr.lock();
183 FALSE_RETURN(agent != nullptr);
184 int64_t appUid = AnyCast<int32_t>(event.param);
185 agent->ReportEosSeek0Event(appUid);
186 }
187
ProcessPerfInfoEvent(std::weak_ptr<DfxAgent> ptr,const DfxEvent & event)188 void DfxAgent::ProcessPerfInfoEvent(std::weak_ptr<DfxAgent> ptr, const DfxEvent &event)
189 {
190 auto agent = ptr.lock();
191 FALSE_RETURN(agent != nullptr);
192 agent->UpdateDfxInfo(event);
193 }
194
UpdateDfxInfo(const DfxEvent & event)195 void DfxAgent::UpdateDfxInfo(const DfxEvent &event)
196 {
197 auto data = AnyCast<MainPerfData>(event.param);
198 perfDataMap_.insert_or_assign(event.callerName, data);
199 FALSE_RETURN_NOLOG(needPrintPerfLog_);
200 MEDIA_LOG_D("%{public}s", GetPerfStr(true).c_str());
201 }
202
GetPerfStr(const bool needWaitAllData)203 std::string DfxAgent::GetPerfStr(const bool needWaitAllData)
204 {
205 bool isAllDataReady = true;
206 std::string waitFor = "not all ready, wait for";
207 std::string perfStr = needPrintPerfLog_ ? "AfterLag\n" : "Lag\n";
208 for (auto it = PERF_ITEM_NECESSITY.begin(); it != PERF_ITEM_NECESSITY.end(); ++it) {
209 auto dataMapIt = perfDataMap_.find(it->first);
210 if (dataMapIt != perfDataMap_.end()) {
211 perfStr += "[" + it->first + " speed] max " + std::to_string(dataMapIt->second.max) + " min " +
212 std::to_string(dataMapIt->second.min) + " avg " + std::to_string(dataMapIt->second.avg) + "\n";
213 } else if (!it->second) {
214 perfStr += "not enough data, but " + it->first + " is not bottleneck\n";
215 } else {
216 waitFor += " " + it->first;
217 isAllDataReady = false;
218 }
219 }
220 if (isAllDataReady) {
221 perfDataMap_.clear();
222 }
223 needPrintPerfLog_ = !isAllDataReady;
224 return (!isAllDataReady && needWaitAllData) ? waitFor : perfStr;
225 }
226 } // namespace Media
227 } // namespace OHOS