• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <chrono>
19 #include <iomanip>
20 #include <sstream>
21 #ifdef HICOLLIE_ENABLE
22 #include "xcollie/xcollie.h"
23 #include "xcollie/xcollie_define.h"
24 #endif
25 
26 #include "avcodec_errors.h"
27 #include "avcodec_dump_utils.h"
28 #include "avcodec_log.h"
29 #include "avcodec_sysevent.h"
30 
31 namespace {
32     constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_FRAMEWORK, "AVCodecXCollie"};
33     constexpr uint32_t DUMP_XCOLLIE_INDEX = 0x01'00'00'00;
34     constexpr uint8_t DUMP_OFFSET_16 = 16;
35     constexpr uint8_t DUMP_OFFSET_8 = 8;
36     constexpr uint64_t COLLIE_INVALID_INDEX = 0;
37 }
38 
39 namespace OHOS {
40 namespace MediaAVCodec {
GetTimeString(std::time_t time)41 static std::string GetTimeString(std::time_t time)
42 {
43     std::stringstream ss;
44     struct tm timeTm;
45     ss << std::put_time(localtime_r(&time, &timeTm), "%F %T");
46     return ss.str();
47 }
48 
GetInstance()49 AVCodecXCollie &AVCodecXCollie::GetInstance()
50 {
51     static AVCodecXCollie instance;
52     return instance;
53 }
54 
SetTimer(const std::string & name,bool recovery,uint32_t timeout,std::function<void (void *)> callback)55 int32_t AVCodecXCollie::SetTimer(const std::string &name, bool recovery, uint32_t timeout,
56                                  std::function<void(void *)> callback)
57 {
58     std::lock_guard<std::shared_mutex> lock(mutex_);
59 
60     unsigned int flag = HiviewDFX::XCOLLIE_FLAG_LOG | HiviewDFX::XCOLLIE_FLAG_NOOP;
61     flag |= (recovery ? HiviewDFX::XCOLLIE_FLAG_RECOVERY : 0);
62 
63     TimerInfo timerInfo = {
64         .name = name.data(),
65         .startTime = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()),
66         .timeout = timeout
67     };
68     int32_t id = HiviewDFX::XCollie::GetInstance().SetTimer(
69         name.data(), timeout, callback, reinterpret_cast<void *>(&timerInfo), flag);
70     if (id != HiviewDFX::INVALID_ID) {
71         dfxDumper_.emplace(id, timerInfo);
72     }
73     return id;
74 }
75 
SetInterfaceTimer(const std::string & name,bool isService,bool recovery,uint32_t timeout)76 int32_t AVCodecXCollie::SetInterfaceTimer(const std::string &name, bool isService, bool recovery, uint32_t timeout)
77 {
78 #ifdef HICOLLIE_ENABLE
79     std::function<void (void *)> func = isService ?
80         [](void *data) { AVCodecXCollie::ServiceInterfaceTimerCallback(data); } :
81         [](void *data) { AVCodecXCollie::ClientInterfaceTimerCallback(data); };
82 
83     return SetTimer(name, recovery, timeout, func);
84 #else
85     return COLLIE_INVALID_INDEX;
86 #endif
87 }
88 
CancelTimer(int32_t timerId)89 void AVCodecXCollie::CancelTimer([[maybe_unused]]int32_t timerId)
90 {
91 #ifdef HICOLLIE_ENABLE
92     if (timerId == COLLIE_INVALID_INDEX) {
93         return;
94     }
95     std::lock_guard<std::shared_mutex> lock(mutex_);
96     HiviewDFX::XCollie::GetInstance().CancelTimer(timerId);
97 
98     auto it = dfxDumper_.find(timerId);
99     if (it == dfxDumper_.end()) {
100         return;
101     }
102     dfxDumper_.erase(it);
103 #endif
104 }
105 
Dump(int32_t fd)106 int32_t AVCodecXCollie::Dump(int32_t fd)
107 {
108     using namespace std::string_literals;
109     std::shared_lock<std::shared_mutex> lock(mutex_);
110     if (dfxDumper_.empty()) {
111         return AVCS_ERR_OK;
112     }
113 
114     std::string dumpString = "[AVCodec_XCollie]\n";
115     AVCodecDumpControler dumpControler;
116     uint32_t dumperIndex = 1;
117     for (const auto &iter : dfxDumper_) {
118         uint32_t timeInfoIndex = 1;
119         auto titleIndex = DUMP_XCOLLIE_INDEX + (dumperIndex << DUMP_OFFSET_16);
120         dumpControler.AddInfo(titleIndex, "Timer_"s + std::to_string(dumperIndex));
121         dumpControler.AddInfo(titleIndex + (timeInfoIndex++ << DUMP_OFFSET_8), "TimerName", iter.second.name);
122         dumpControler.AddInfo(titleIndex + (timeInfoIndex++ << DUMP_OFFSET_8),
123             "StartTime", GetTimeString(iter.second.startTime).c_str());
124         dumpControler.AddInfo(titleIndex + (timeInfoIndex++ << DUMP_OFFSET_8),
125             "TimeLeft",
126             std::to_string(iter.second.timeout + iter.second.startTime -
127                 std::chrono::system_clock::to_time_t(std::chrono::system_clock::now())));
128         dumperIndex++;
129     }
130 
131     dumpControler.GetDumpString(dumpString);
132     if (fd != -1) {
133         write(fd, dumpString.c_str(), dumpString.size());
134         dumpString.clear();
135     }
136     return AVCS_ERR_OK;
137 }
138 
ServiceInterfaceTimerCallback(void * data)139 void AVCodecXCollie::ServiceInterfaceTimerCallback(void *data)
140 {
141     static uint32_t threadDeadlockCount_ = 0;
142     threadDeadlockCount_++;
143     std::string name = data != nullptr ? reinterpret_cast<TimerInfo *>(data)->name.c_str() : "";
144 
145     AVCODEC_LOGE("Service task %{public}s timeout", name.c_str());
146     FaultEventWrite(FaultType::FAULT_TYPE_FREEZE, std::string("Service task ") +
147         name + std::string(" timeout"), "Service");
148 
149     static constexpr uint32_t threshold = 1; // >= 1 Restart service
150     if (threadDeadlockCount_ >= threshold) {
151         FaultEventWrite(FaultType::FAULT_TYPE_FREEZE,
152             "Process timeout, AVCodec service process exit.", "Service");
153         AVCODEC_LOGF("Process timeout, AVCodec service process exit.");
154         _exit(-1);
155     }
156 }
157 
ClientInterfaceTimerCallback(void * data)158 void AVCodecXCollie::ClientInterfaceTimerCallback(void *data)
159 {
160     std::string name = data != nullptr ? reinterpret_cast<TimerInfo *>(data)->name.c_str() : "";
161     AVCODEC_LOGE("Client task %{public}s timeout", name.c_str());
162     FaultEventWrite(FaultType::FAULT_TYPE_FREEZE, std::string("Client task ") +
163         name + std::string(" timeout"), "Client");
164 }
165 } // namespace MediaAVCodec
166 } // namespace OHOS