1 /*
2  * Copyright (C) 2023 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 "avcodec_xcollie.h"
17 #include <unistd.h>
18 #include "avcodec_errors.h"
19 #include "param_wrapper.h"
20 #include "avcodec_dump_utils.h"
21 #include "avcodec_log.h"
22 #include "avcodec_sysevent.h"
23 #ifdef HICOLLIE_ENABLE
24 #include "xcollie/xcollie.h"
25 #include "xcollie/xcollie_define.h"
26 #endif
27 
28 namespace {
29     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_FRAMEWORK, "AVCodecXCollie"};
30     constexpr uint32_t DUMP_XCOLLIE_INDEX = 0x01000000;
31     constexpr uint8_t DUMP_OFFSET_16 = 16;
32     constexpr uint64_t COLLIE_INVALID_INDEX = 0;
33 }
34 
35 namespace OHOS {
36 namespace MediaAVCodec {
GetInstance()37 AVCodecXCollie &AVCodecXCollie::GetInstance()
38 {
39     static AVCodecXCollie instance;
40     return instance;
41 }
42 
ServiceTimerCallback(void * data)43 void AVCodecXCollie::ServiceTimerCallback(void *data)
44 {
45     std::lock_guard<std::mutex> lock(mutex_);
46     threadDeadlockCount_++;
47     std::string name = data != nullptr ? (char *)data : "";
48 
49     AVCODEC_LOGE("Service task %{public}s timeout", name.c_str());
50     FaultEventWrite(FaultType::FAULT_TYPE_FREEZE, std::string("Service task ") +
51         name + std::string(" timeout"), "Service");
52 
53     static constexpr uint32_t threshold = 1; // >= 1 Restart service
54     if (threadDeadlockCount_ >= threshold) {
55         FaultEventWrite(FaultType::FAULT_TYPE_FREEZE,
56             "Process timeout, AVCodec service process exit.", "Service");
57         AVCODEC_LOGF("Process timeout, AVCodec service process exit.");
58         _exit(-1);
59     }
60 }
61 
ClientTimerCallback(void * data)62 void AVCodecXCollie::ClientTimerCallback(void *data)
63 {
64     std::lock_guard<std::mutex> lock(mutex_);
65     std::string name = data != nullptr ? (char *)data : "";
66     AVCODEC_LOGE("Client task %{public}s timeout", name.c_str());
67     FaultEventWrite(FaultType::FAULT_TYPE_FREEZE, std::string("Client task ") +
68         name + std::string(" timeout"), "Client");
69 }
70 
Dump(int32_t fd)71 int32_t AVCodecXCollie::Dump(int32_t fd)
72 {
73     if (dfxDumper_.empty()) {
74         return AVCS_ERR_OK;
75     }
76 
77     std::lock_guard<std::mutex> lock(mutex_);
78     std::string dumpString = "[AVCodec_XCollie]\n";
79     AVCodecDumpControler dumpControler;
80     uint32_t dumperIndex = 1;
81     for (const auto &iter : dfxDumper_) {
82         dumpControler.AddInfo(DUMP_XCOLLIE_INDEX + (dumperIndex << DUMP_OFFSET_16), "Timer_Name", iter.second.second);
83         dumperIndex++;
84     }
85     dumpControler.GetDumpString(dumpString);
86     if (fd != -1) {
87         write(fd, dumpString.c_str(), dumpString.size());
88         dumpString.clear();
89     }
90     return AVCS_ERR_OK;
91 }
92 
93 
SetTimer(const std::string & name,bool isService,bool recovery,uint32_t timeout)94 uint64_t AVCodecXCollie::SetTimer(const std::string &name, bool isService, bool recovery, uint32_t timeout)
95 {
96 #ifdef HICOLLIE_ENABLE
97     std::lock_guard<std::mutex> lock(mutex_);
98 
99     std::function<void (void *)> func;
100     if (isService) {
101         func = [this](void *data) { this->ServiceTimerCallback(data); };
102     } else {
103         func = [this](void *data) { this->ClientTimerCallback(data); };
104     }
105 
106     unsigned int flag = HiviewDFX::XCOLLIE_FLAG_LOG | HiviewDFX::XCOLLIE_FLAG_NOOP;
107     if (recovery) {
108         flag |= HiviewDFX::XCOLLIE_FLAG_RECOVERY;
109     }
110     uint64_t tempIndex = dumperIndex_++;
111     dfxDumper_.emplace(tempIndex, std::pair<int32_t, std::string>(HiviewDFX::INVALID_ID, name));
112     int32_t id = HiviewDFX::XCollie::GetInstance().SetTimer(name,
113         timeout, func, (void *)dfxDumper_[tempIndex].second.c_str(), flag);
114     if (id == HiviewDFX::INVALID_ID) {
115         auto it = dfxDumper_.find(tempIndex);
116         if (it != dfxDumper_.end()) {
117             dfxDumper_.erase(it);
118             return COLLIE_INVALID_INDEX;
119         }
120     }
121     dfxDumper_[tempIndex].first = id;
122     return tempIndex;
123 #else
124     (void)dumperIndex_;
125     return COLLIE_INVALID_INDEX;
126 #endif
127 }
128 
CancelTimer(uint64_t index)129 void AVCodecXCollie::CancelTimer(uint64_t index)
130 {
131 #ifdef HICOLLIE_ENABLE
132     if (index == COLLIE_INVALID_INDEX) {
133         return;
134     }
135     std::lock_guard<std::mutex> lock(mutex_);
136     auto it = dfxDumper_.find(index);
137     if (it == dfxDumper_.end()) {
138         return;
139     }
140     int32_t id = it->second.first;
141     dfxDumper_.erase(it);
142     return HiviewDFX::XCollie::GetInstance().CancelTimer(id);
143 #else
144     (void)index;
145     return;
146 #endif
147 }
148 } // namespace MediaAVCodec
149 } // namespace OHOS