1 /*
2  * Copyright (c) 2022 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 #include <media_dfx.h>
17 #include <unistd.h>
18 #include "securec.h"
19 #include "hitrace_meter.h"
20 #include "hitrace/tracechain.h"
21 #include "ipc_skeleton.h"
22 #include "media_utils.h"
23 #include "hitrace/tracechain.h"
24 #include "common/log.h"
25 #include "common/media_core.h"
26 #include "meta/any.h"
27 #include <cstdint>
28 
29 namespace {
30     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_SYSTEM_PLAYER, "MediaDFX" };
31 
32     constexpr uint32_t MAX_STRING_SIZE = 256;
33     constexpr int64_t HOURS_BETWEEN_REPORTS = 4;
34     constexpr int64_t MAX_MAP_SIZE = 100;
35 
36     std::mutex collectMut_;
37     std::mutex reportMut_;
38     std::map<OHOS::Media::CallType,
39         std::map<int32_t, std::list<std::pair<uint64_t, std::shared_ptr<OHOS::Media::Meta>>>>> mediaInfoMap_;
40     std::map<OHOS::Media::CallType,
41         std::map<int32_t, std::list<std::pair<uint64_t, std::shared_ptr<OHOS::Media::Meta>>>>> reportMediaInfoMap_;
42     std::map<uint64_t, std::pair<OHOS::Media::CallType, int32_t>> idMap_;
43     std::chrono::system_clock::time_point currentTime_ = std::chrono::system_clock::now();
44     bool g_reachMaxMapSize {false};
45 
CollectReportMediaInfo(uint64_t instanceId)46     bool CollectReportMediaInfo(uint64_t instanceId)
47     {
48         OHOS::Media::CallType ct;
49         int32_t uid;
50         std::pair<uint64_t, std::shared_ptr<OHOS::Media::Meta>> metaAppIdPair;
51         {
52             std::lock_guard<std::mutex> lock(collectMut_);
53             MEDIA_LOG_I("CollectReportMediaInfo, instanceId is : %{public}" PRIu64, instanceId);
54             auto idMapIt = idMap_.find(instanceId);
55             if (idMapIt == idMap_.end()) {
56                 MEDIA_LOG_W("Not found instanceId in idMap, instanceId is : %{public}" PRIu64, instanceId);
57                 return false;
58             }
59             ct = idMapIt->second.first;
60             uid = idMapIt->second.second;
61             idMap_.erase(idMapIt);
62             auto ctUidToMediaInfo = mediaInfoMap_.find(ct);
63             if (ctUidToMediaInfo == mediaInfoMap_.end()) {
64                 MEDIA_LOG_W("Not found calltype, calltype is : %{public}d", static_cast<OHOS::Media::CallType>(ct));
65                 return false;
66             }
67             auto uidToMediaInfo = ctUidToMediaInfo->second.find(uid);
68             if (uidToMediaInfo == ctUidToMediaInfo->second.end()) {
69                 MEDIA_LOG_W("Not found uid in mediaInfoMap_, uid is : %{public}" PRId32, uid);
70                 return false;
71             }
72             auto& instanceList = uidToMediaInfo->second;
73             for (const auto& instancePair : instanceList) {
74                 if (instancePair.first == instanceId) {
75                     metaAppIdPair = instancePair;
76                     instanceList.remove(instancePair);
77                     break;
78                 }
79             }
80         }
81         std::lock_guard<std::mutex> lock(reportMut_);
82         auto reportCtUidToMediaInfo  = reportMediaInfoMap_.find(ct);
83         if (reportCtUidToMediaInfo != reportMediaInfoMap_.end()) {
84             auto it = reportCtUidToMediaInfo->second.find(uid);
85             if (it != reportCtUidToMediaInfo->second.end()) {
86                 it->second.push_back(metaAppIdPair);
87             } else {
88                 reportCtUidToMediaInfo->second[uid].push_back(metaAppIdPair);
89             }
90         } else {
91             reportMediaInfoMap_[ct][uid].push_back(metaAppIdPair);
92         }
93         g_reachMaxMapSize = (reportMediaInfoMap_[ct].size() >= MAX_MAP_SIZE);
94         return true;
95     }
96 
StatisticsEventReport()97     int32_t StatisticsEventReport()
98     {
99         MEDIA_LOG_I("StatisticsEventReport.");
100         if (reportMediaInfoMap_.empty()) {
101             MEDIA_LOG_I("reportMediaInfoMap_ is empty, can't report");
102             return OHOS::Media::MSERR_INVALID_OPERATION;
103         }
104         OHOS::Media::MediaEvent event;
105         for (const auto &it : reportMediaInfoMap_) {
106             event.CommonStatisicsEventWrite(it.first, OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC, it.second);
107         }
108         auto currentTime = std::chrono::system_clock::now();
109         currentTime_ = currentTime;
110         reportMediaInfoMap_.clear();
111         return OHOS::Media::MSERR_OK;
112     }
113 }
114 
115 namespace OHOS {
116 namespace Media {
117 using namespace OHOS::HiviewDFX;
CreateMsg(const char *format, ...)118 bool MediaEvent::CreateMsg(const char *format, ...)
119 {
120     va_list args;
121     va_start(args, format);
122     char msg[MAX_STRING_SIZE] = {0};
123     auto ret = vsnprintf_s(msg, sizeof(msg), sizeof(msg) - 1, format, args);
124     va_end(args);
125     msg_ = msg;
126     return ret < 0 ? false : true;
127 }
128 
EventWrite(std::string eventName, OHOS::HiviewDFX::HiSysEvent::EventType type, std::string module)129 void MediaEvent::EventWrite(std::string eventName, OHOS::HiviewDFX::HiSysEvent::EventType type,
130     std::string module)
131 {
132     int32_t pid = getpid();
133     uint32_t uid = getuid();
134     HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::MULTI_MEDIA, eventName, type,
135         "PID", pid,
136         "UID", uid,
137         "MODULE", module,
138         "MSG", msg_);
139 }
140 
EventWriteWithAppInfo(std::string eventName, OHOS::HiviewDFX::HiSysEvent::EventType type, std::string module, std::string status, int32_t appUid, int32_t appPid)141 void MediaEvent::EventWriteWithAppInfo(std::string eventName, OHOS::HiviewDFX::HiSysEvent::EventType type,
142     std::string module, std::string status, int32_t appUid, int32_t appPid)
143 {
144     int32_t pid = getpid();
145     uint32_t uid = getuid();
146     HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::MULTI_MEDIA, eventName, type,
147         "PID", pid,
148         "UID", uid,
149         "MODULE", module,
150         "MSG", msg_,
151         "APP_PID", appPid,
152         "APP_UID", appUid,
153         "STATUS", status);
154 }
155 
EventWriteBundleName(std::string eventName, OHOS::HiviewDFX::HiSysEvent::EventType type, std::string module, std::string status, int32_t appUid, int32_t appPid, std::string bundleName)156 void MediaEvent::EventWriteBundleName(std::string eventName, OHOS::HiviewDFX::HiSysEvent::EventType type,
157     std::string module, std::string status, int32_t appUid, int32_t appPid, std::string bundleName)
158 {
159     int32_t pid = getpid();
160     uint32_t uid = getuid();
161     HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::MULTI_MEDIA, eventName, type,
162                     "PID", pid,
163                     "UID", uid,
164                     "MODULE", module,
165                     "MSG", msg_,
166                     "APP_PID", appPid,
167                     "APP_UID", appUid,
168                     "STATUS", status,
169                     "BUNDLE", bundleName);
170 }
171 
SourceEventWrite(const std::string& eventName, OHOS::HiviewDFX::HiSysEvent::EventType type, const std::string& appName, uint64_t instanceId, const std::string& callerType, int8_t sourceType, const std::string& sourceUrl, const std::string& errMsg)172 void MediaEvent::SourceEventWrite(const std::string& eventName, OHOS::HiviewDFX::HiSysEvent::EventType type,
173     const std::string& appName, uint64_t instanceId, const std::string& callerType, int8_t sourceType,
174     const std::string& sourceUrl, const std::string& errMsg)
175 {
176     std::string instanceIdStr = std::to_string(instanceId);
177     HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::MULTI_MEDIA, eventName, type,
178                     "APP_NAME", appName,
179                     "INSTANCE_ID", instanceIdStr,
180                     "CALLER_TYPE", callerType,
181                     "SOURCE_TYPE", sourceType,
182                     "SOURCE_URI", sourceUrl,
183                     "ERROR_MESG", errMsg);
184 }
185 
ScreenCaptureEventWrite(const std::string& eventName, OHOS::HiviewDFX::HiSysEvent::EventType type, const std::string& appName, uint64_t instanceId, int8_t captureMode, int8_t dataMode, int32_t errorCode, const std::string& errorMessage)186 void MediaEvent::ScreenCaptureEventWrite(const std::string& eventName, OHOS::HiviewDFX::HiSysEvent::EventType type,
187     const std::string& appName, uint64_t instanceId, int8_t captureMode, int8_t dataMode, int32_t errorCode,
188     const std::string& errorMessage)
189 {
190     std::string instanceIdStr = std::to_string(instanceId);
191     HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::MULTI_MEDIA, eventName, type,
192                     "APP_NAME", appName,
193                     "INSTANCE_ID", instanceIdStr,
194                     "CAPTURE_MODE", captureMode,
195                     "DATA_MODE", dataMode,
196                     "ERROR_CODE", errorCode,
197                     "ERROR_MESG", errorMessage);
198 }
199 
CommonStatisicsEventWrite(CallType callType, OHOS::HiviewDFX::HiSysEvent::EventType type, const std::map<int32_t, std::list<std::pair<uint64_t, std::shared_ptr<Meta>>>>& infoMap)200 void MediaEvent::CommonStatisicsEventWrite(CallType callType, OHOS::HiviewDFX::HiSysEvent::EventType type,
201     const std::map<int32_t, std::list<std::pair<uint64_t, std::shared_ptr<Meta>>>>& infoMap)
202 {
203     MEDIA_LOG_I("MediaEvent::CommonStatisicsEventWrite");
204     if (infoMap.empty()) {
205         MEDIA_LOG_I("Player infoMap is empty.");
206         return;
207     }
208     std::vector<std::string> infoArr;
209 #ifdef SUPPORT_JSON
210     for (const auto& kv : infoMap) {
211         json jsonArray;
212         json eventInfoJson;
213         json mediaEvents;
214         for (const auto& listPair : kv.second) {
215             json metaInfoJson;
216             ParseOneEvent(listPair, metaInfoJson);
217             mediaEvents.push_back(metaInfoJson);
218         }
219         eventInfoJson["appName"] = GetClientBundleName(kv.first);
220         eventInfoJson["mediaEvents"] = mediaEvents;
221         jsonArray.push_back(eventInfoJson);
222         infoArr.push_back(jsonArray.dump());
223     }
224 #endif
225     StatisicsHiSysEventWrite(callType, type, infoArr);
226 }
227 
228 
229 #ifdef SUPPORT_JSON
ParseOneEvent(const std::pair<uint64_t, std::shared_ptr<OHOS::Media::Meta>> &listPair, json& metaInfoJson)230 void MediaEvent::ParseOneEvent(const std::pair<uint64_t, std::shared_ptr<OHOS::Media::Meta>> &listPair,
231     json& metaInfoJson)
232 {
233     for (auto it = listPair.second->begin(); it != listPair.second->end(); ++it) {
234         Any valueType = OHOS::Media::GetDefaultAnyValue(it->first);
235         if (Any::IsSameTypeWith<int32_t>(valueType)) {
236             int32_t intVal;
237             if (listPair.second->GetData(it->first, intVal)) {
238                 metaInfoJson[it->first] = std::to_string(intVal);
239             }
240         } else if (Any::IsSameTypeWith<uint32_t>(valueType)) {
241             uint32_t uintVal;
242             if (listPair.second->GetData(it->first, uintVal)) {
243                 metaInfoJson[it->first] = std::to_string(uintVal);
244             }
245         } else if (Any::IsSameTypeWith<uint64_t>(valueType)) {
246             uint64_t uintVal;
247             if (listPair.second->GetData(it->first, uintVal)) {
248                 metaInfoJson[it->first] = std::to_string(uintVal);
249             }
250         } else if (Any::IsSameTypeWith<std::string>(valueType)) {
251             metaInfoJson[it->first] = AnyCast<std::string>(it->second);
252         } else if (Any::IsSameTypeWith<int8_t>(valueType)) {
253             int8_t intVal;
254             if (listPair.second->GetData(it->first, intVal)) {
255                 metaInfoJson[it->first] = std::to_string(intVal);
256             }
257         } else if (Any::IsSameTypeWith<bool>(valueType)) {
258             bool isTrue;
259             if (listPair.second->GetData(it->first, isTrue)) {
260                 metaInfoJson[it->first] = isTrue ? "true" : "false";
261             }
262         } else {
263             MEDIA_LOG_I("not found type matched with it->first: %{public}s", it->first.c_str());
264         }
265     }
266 }
267 #endif
268 
StatisicsHiSysEventWrite(CallType callType, OHOS::HiviewDFX::HiSysEvent::EventType type, const std::vector<std::string>& infoArr)269 void MediaEvent::StatisicsHiSysEventWrite(CallType callType, OHOS::HiviewDFX::HiSysEvent::EventType type,
270     const std::vector<std::string>& infoArr)
271 {
272     MEDIA_LOG_I("MediaEvent::StatisicsHiSysEventWrite");
273     std::string eventName;
274     switch (callType) {
275         case CallType::AVPLAYER:
276             eventName = "PLAYER_COMMON_STATISTICS";
277             break;
278         case CallType::AVRECORDER:
279             eventName = "RECORDER_STATISTICS";
280             break;
281         case CallType::SCREEN_CAPTRUER:
282             eventName = "SCREEN_CAPTURE_STATISTICS";
283             break;
284         case CallType::AVTRANSCODER:
285             eventName = "TRANSCODER_STATISTICS";
286             break;
287         default:
288             return;
289     }
290     HiSysEventWrite(OHOS::HiviewDFX::HiSysEvent::Domain::MULTI_MEDIA, eventName, type,
291                     "EVENTS", infoArr);
292 }
293 
BehaviorEventWrite(std::string status, std::string module)294 void BehaviorEventWrite(std::string status, std::string module)
295 {
296     MediaEvent event;
297     if (event.CreateMsg("%s, current state is: %s", "state change", status.c_str())) {
298         event.EventWrite("PLAYER_STATE", OHOS::HiviewDFX::HiSysEvent::EventType::BEHAVIOR, module);
299     }
300 }
301 
BehaviorEventWriteForScreenCapture(std::string status, std::string module, int32_t appUid, int32_t appPid)302 void BehaviorEventWriteForScreenCapture(std::string status, std::string module, int32_t appUid, int32_t appPid)
303 {
304     MediaEvent event;
305     if (event.CreateMsg("%s, current state is: %s", "state change", status.c_str())) {
306         event.EventWriteWithAppInfo("PLAYER_STATE", OHOS::HiviewDFX::HiSysEvent::EventType::BEHAVIOR,
307             module, status, appUid, appPid);
308     }
309 }
310 
StatisticEventWriteBundleName(std::string status, std::string module)311 void StatisticEventWriteBundleName(std::string status, std::string module)
312 {
313     MediaEvent event;
314     int32_t appUid = IPCSkeleton::GetCallingUid();
315     int32_t appPid = IPCSkeleton::GetCallingPid();
316     std::string bundleName = GetClientBundleName(appUid);
317     if (event.CreateMsg("%s is invoke %s", bundleName.c_str(), module.c_str())) {
318         event.EventWriteBundleName("PLAYER_STATISTICS", OHOS::HiviewDFX::HiSysEvent::EventType::STATISTIC,
319             module, status, appUid, appPid, bundleName);
320     }
321 }
322 
FaultEventWrite(std::string msg, std::string module)323 void FaultEventWrite(std::string msg, std::string module)
324 {
325     MediaEvent event;
326     if (event.CreateMsg("%s", msg.c_str())) {
327         event.EventWrite("PLAYER_ERR", OHOS::HiviewDFX::HiSysEvent::EventType::FAULT, module);
328     }
329 }
330 
FaultSourceEventWrite(const std::string& appName, uint64_t instanceId, const std::string& callerType, int8_t sourceType, const std::string& sourceUrl, const std::string& errorMessage)331 void FaultSourceEventWrite(const std::string& appName, uint64_t instanceId, const std::string& callerType,
332     int8_t sourceType, const std::string& sourceUrl, const std::string& errorMessage)
333 {
334     MediaEvent event;
335     event.SourceEventWrite("SOURCE_FAILURE", OHOS::HiviewDFX::HiSysEvent::EventType::FAULT, appName, instanceId,
336         callerType, sourceType, sourceUrl, errorMessage);
337 }
338 
FaultScreenCaptureEventWrite(const std::string& appName, uint64_t instanceId, int8_t captureMode, int8_t dataMode, int32_t errorCode, const std::string& errorMessage)339 void FaultScreenCaptureEventWrite(const std::string& appName, uint64_t instanceId, int8_t captureMode, int8_t dataMode,
340     int32_t errorCode, const std::string& errorMessage)
341 {
342     MediaEvent event;
343     event.ScreenCaptureEventWrite("SCREEN_CAPTURE_FAILURE", OHOS::HiviewDFX::HiSysEvent::EventType::FAULT, appName,
344         instanceId, captureMode, dataMode, errorCode, errorMessage);
345 }
346 
CreateMediaInfo(CallType callType, int32_t uid, uint64_t instanceId)347 int32_t CreateMediaInfo(CallType callType, int32_t uid, uint64_t instanceId)
348 {
349     MEDIA_LOG_I("CreateMediaInfo uid is: %{public}" PRId32 " instanceId is: %{public}" PRIu64, uid, instanceId);
350     std::lock_guard<std::mutex> lock(collectMut_);
351     auto instanceIdMap = idMap_.find(instanceId);
352     if (instanceIdMap != idMap_.end()) {
353         MEDIA_LOG_I("instanceId already exists id idMap_");
354         return MSERR_INVALID_VAL;
355     } else {
356         MEDIA_LOG_I("CreateMediaInfo not found instanceId in idMap_, add the instanceId to idMap_");
357         std::pair<CallType, int32_t> insertToMapPair(callType, uid);
358         idMap_[instanceId] = insertToMapPair;
359     }
360     std::shared_ptr<Meta> meta = std::make_shared<Meta>();
361     std::pair<uint64_t, std::shared_ptr<Meta>> metaAppIdPair(instanceId, meta);
362     auto ctUidToMediaInfo = mediaInfoMap_.find(callType);
363     if (ctUidToMediaInfo != mediaInfoMap_.end()) {
364         auto it = ctUidToMediaInfo->second.find(uid);
365         if (it != ctUidToMediaInfo->second.end()) {
366             it->second.push_back(metaAppIdPair);
367             MEDIA_LOG_I("CreateMediaInfo: Successfully inserted metaAppIdPair for uid ");
368         } else {
369             ctUidToMediaInfo->second[uid].push_back(metaAppIdPair);
370             MEDIA_LOG_I("CreateMediaInfo: Successfully created new list for uid and inserted metaAppIdPair.");
371         }
372     } else {
373         mediaInfoMap_[callType][uid].push_back(metaAppIdPair);
374         MEDIA_LOG_I("CreateMediaInfo: Successfully created new list for callType and uid ");
375     }
376     return MSERR_OK;
377 }
378 
AppendMediaInfo(const std::shared_ptr<Meta>& meta, uint64_t instanceId)379 int32_t AppendMediaInfo(const std::shared_ptr<Meta>& meta, uint64_t instanceId)
380 {
381     MEDIA_LOG_I("AppendMediaInfo.");
382     if (meta == nullptr || meta->Empty()) {
383         MEDIA_LOG_I("Insert meta is empty.");
384         return MSERR_INVALID_OPERATION;
385     }
386     std::lock_guard<std::mutex> lock(collectMut_);
387     auto idMapIt = idMap_.find(instanceId);
388     if (idMapIt == idMap_.end()) {
389         MEDIA_LOG_I("Not found instanceId when append meta, instanceId is : %{public}" PRIu64, instanceId);
390         return MSERR_INVALID_VAL;
391     }
392     CallType ct = idMapIt->second.first;
393     int32_t uid = idMapIt->second.second;
394     auto ctUidToMediaInfo = mediaInfoMap_.find(ct);
395     if (ctUidToMediaInfo == mediaInfoMap_.end()) {
396         MEDIA_LOG_I("Not found calltype when append meta, calltype is : %{public}d", static_cast<CallType>(ct));
397         return MSERR_INVALID_OPERATION;
398     }
399     auto it = ctUidToMediaInfo->second.find(uid);
400     if (it == ctUidToMediaInfo->second.end()) {
401         MEDIA_LOG_I("Not found uid when append meta, uid is : %{public}" PRId32, uid);
402         return MSERR_INVALID_OPERATION;
403     }
404     auto& instanceList = it->second;
405     for (const auto& instancePair : instanceList) {
406         if (instancePair.first == instanceId) {
407             auto arg = meta->begin();
408             while (arg != meta->end()) {
409                 instancePair.second->SetData(arg->first, arg->second);
410                 ++arg;
411             }
412             break;
413         }
414     }
415     return MSERR_OK;
416 }
417 
ReportMediaInfo(uint64_t instanceId)418 int32_t ReportMediaInfo(uint64_t instanceId)
419 {
420     MEDIA_LOG_I("Report.");
421     MEDIA_LOG_I("Delete media info instanceId is: %{public}" PRIu64, instanceId);
422     if (!CollectReportMediaInfo(instanceId)) {
423         MEDIA_LOG_I("Collect media info fail.");
424         return MSERR_INVALID_OPERATION;
425     }
426     std::lock_guard<std::mutex> lock(reportMut_);
427     if (g_reachMaxMapSize) {
428         MEDIA_LOG_I("Event data size exceeds 100, report the event");
429         g_reachMaxMapSize = false;
430         return StatisticsEventReport();
431     }
432     auto currentTime = std::chrono::system_clock::now();
433     auto diff = currentTime - currentTime_;
434     auto hour = std::chrono::duration_cast<std::chrono::hours>(diff).count();
435     if (hour >= HOURS_BETWEEN_REPORTS) {
436         MEDIA_LOG_I("Over 4 hours, report the event");
437         return StatisticsEventReport();
438     }
439     return MSERR_OK;
440 }
441 
MediaTrace(const std::string &funcName)442 MediaTrace::MediaTrace(const std::string &funcName)
443 {
444     StartTrace(HITRACE_TAG_ZMEDIA, funcName);
445     isSync_ = true;
446 }
447 
TraceBegin(const std::string &funcName, int32_t taskId)448 void MediaTrace::TraceBegin(const std::string &funcName, int32_t taskId)
449 {
450     StartAsyncTrace(HITRACE_TAG_ZMEDIA, funcName, taskId);
451 }
452 
TraceEnd(const std::string &funcName, int32_t taskId)453 void MediaTrace::TraceEnd(const std::string &funcName, int32_t taskId)
454 {
455     FinishAsyncTrace(HITRACE_TAG_ZMEDIA, funcName, taskId);
456 }
457 
CounterTrace(const std::string &varName, int32_t val)458 void MediaTrace::CounterTrace(const std::string &varName, int32_t val)
459 {
460     CountTrace(HITRACE_TAG_ZMEDIA, varName, val);
461 }
462 
~MediaTrace()463 MediaTrace::~MediaTrace()
464 {
465     if (isSync_) {
466         FinishTrace(HITRACE_TAG_ZMEDIA);
467     }
468 }
469 } // namespace Media
470 } // namespace OHOS
471