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