6#include <hicollie/hicollie.h>
7#include <qarkui/qarkuiutils.h>
8#include <qohosbigdataeventlogging.h>
9#include <QtCore/private/qohoslogger_p.h>
10#include <QtCore/qcoreapplication.h>
11#include <QtCore/qcoreevent.h>
12#include <QtCore/qobject.h>
17namespace ch =
std::chrono;
25constexpr int resetRatio = 2;
27constexpr auto bigDataEnterFreezeStateEventName =
"enterFreezeState";
28constexpr auto bigDataRecoveredFromFreezeStateEventName =
"recoveredFromFreezeState";
30constexpr auto bigDataEventDescriptionPropertyName =
"eventDescription";
31constexpr auto bigDataFreezeStateDurationPropertyName =
"freezeStateDurationMs";
34constexpr auto checkIntervalTime = ch::seconds(45);
36constexpr auto checkIntervalTime = ch::seconds(3);
39void logEnterFreezeStateBigDataEvent(ch::time_point<ch::system_clock> eventTime)
41 qCDebug(QtForOhos,
"%s", Q_FUNC_INFO);
43 auto eventBuilder = QtOhos::makeBigEventLoggingEventBuilder(
44 bigDataEnterFreezeStateEventName, ::EventType::STATISTIC, eventTime);
45 eventBuilder->addParam(bigDataEventDescriptionPropertyName,
"The application triggered a 6 second freeze");
46 eventBuilder->buildEvent()->trySend();
49void logRecoveredFromFreezeStateBigDataEvent(
50 ch::time_point<ch::system_clock> eventTime, ch::system_clock::duration freezeStateDuration)
52 qCDebug(QtForOhos,
"%s", Q_FUNC_INFO);
54 auto eventBuilder = QtOhos::makeBigEventLoggingEventBuilder(
55 bigDataRecoveredFromFreezeStateEventName, ::EventType::STATISTIC, eventTime);
56 eventBuilder->addParam(bigDataEventDescriptionPropertyName,
"Recovered from the frozen state");
57 eventBuilder->addParam(
58 bigDataFreezeStateDurationPropertyName,
59 static_cast<
std::int64_t>(ch::duration_cast<ch::milliseconds>(freezeStateDuration).count()));
60 eventBuilder->buildEvent()->trySend();
63class QtWatchdog :
public QObject
68 void runHiCollieStuckDetectionTask();
70 bool event(QEvent *ev)
override;
73 void handleAppMainThreadAliveNotification();
74 void reportStuckEvent();
76 ch::steady_clock::time_point m_lastWatchTime;
77 bool m_appMainThreadIsAlive =
false;
78 bool m_isSixSecondEvent =
false;
79 std::optional<ch::system_clock::time_point> m_sixSecondEventDetectionTime;
82QEvent::Type getCheckMainThreadIsAliveQEventType()
84 static auto eventType =
static_cast<QEvent::Type>(QEvent::registerEventType());
88QtWatchdog::QtWatchdog()
91 QCoreApplication::postEvent(
this,
new QEvent(getCheckMainThreadIsAliveQEventType()), Qt::HighEventPriority);
94void QtWatchdog::handleAppMainThreadAliveNotification()
96 qCDebug(QtForOhos,
"QtWatchdog::handleAppMainThreadAliveNotification");
97 m_appMainThreadIsAlive =
true;
98 m_isSixSecondEvent =
false;
99 if (m_sixSecondEventDetectionTime.has_value()) {
100 const auto now = ch::system_clock::now();
101 const auto elapsedTime = now - m_sixSecondEventDetectionTime.value();
102 logRecoveredFromFreezeStateBigDataEvent(now, elapsedTime);
103 m_sixSecondEventDetectionTime.reset();
107void QtWatchdog::runHiCollieStuckDetectionTask()
109 qCDebug(QtForOhos,
"QtWatchdog::runHiCollieStuckDetectionTask start");
111 if (m_appMainThreadIsAlive) {
112 qCDebug(QtForOhos,
"QtWatchdog: m_appMainThreadIsAlive store false");
113 m_appMainThreadIsAlive =
false;
115 qCWarning(QtForOhos,
"QtWatchdog: AppMainThread is not alive");
119 QCoreApplication::postEvent(
this,
new QEvent(getCheckMainThreadIsAliveQEventType()), Qt::HighEventPriority);
121 auto now = ch::steady_clock::now();
122 if ((now - m_lastWatchTime) >= (checkIntervalTime / resetRatio))
123 m_lastWatchTime = now;
125 qCDebug(QtForOhos,
"QtWatchdog::runHiCollieStuckDetectionTask end");
128bool QtWatchdog::event(QEvent *ev)
130 if (ev->type() == getCheckMainThreadIsAliveQEventType()) {
131 qCDebug(QtForOhos,
"QtWatchdog: CheckMainThreadIsAlive event start (%d)",
static_cast<
int>(getCheckMainThreadIsAliveQEventType()));
132 handleAppMainThreadAliveNotification();
133 qCDebug(QtForOhos,
"QCoreApplication: CheckMainThreadIsAlive event end");
136 return QObject::event(ev);
140void QtWatchdog::reportStuckEvent()
142 auto now = ch::steady_clock::now();
143 auto timeDelta = now - m_lastWatchTime;
144 if (timeDelta > resetRatio * checkIntervalTime || timeDelta < checkIntervalTime / resetRatio) {
147 "QtWatchdog: Thread may be blocked, do not report this time. currTime: %.3f, lastTime: %.3f",
148 ch::duration<
double>(now.time_since_epoch()).count(),
149 ch::duration<
double>(m_lastWatchTime.time_since_epoch()).count());
153 qCDebug(QtForOhos,
"QtWatchdog: calling OH_HiCollie_Report(), m_isSixSecondEvent = %d", m_isSixSecondEvent);
154 HiCollie_ErrorCode reportRes = OH_HiCollie_Report(&m_isSixSecondEvent);
155 if (reportRes == HICOLLIE_SUCCESS) {
156 qCDebug(QtForOhos,
"QtWatchdog: after OH_HiCollie_Report(), m_isSixSecondEvent = %d", m_isSixSecondEvent);
157 if (m_isSixSecondEvent && !m_sixSecondEventDetectionTime.has_value()) {
158 m_sixSecondEventDetectionTime = ch::system_clock::now();
159 logEnterFreezeStateBigDataEvent(m_sixSecondEventDetectionTime.value());
162 qCWarning(QtForOhos,
"QtWatchdog: OH_HiCollie_Report() failed with code %d",
static_cast<
int>(reportRes));
166void runWithQtWatchdogSharedPtr(
const std::function<
void(
std::shared_ptr<QtWatchdog> &)> &runFunc)
168 static std::mutex runMutex;
169 static std::shared_ptr<QtWatchdog> qtWatchdogPtr;
172 std::lock_guard<
std::mutex> runLock(runMutex);
173 runFunc(qtWatchdogPtr);
181 runWithQtWatchdogSharedPtr(
182 [](
auto &watchdogSharedPtr) {
183 watchdogSharedPtr =
std::make_shared<QtWatchdog>();
186 auto watchdogHandle = QtOhos::makeDestroyNotifier(
188 runWithQtWatchdogSharedPtr(
189 [](
auto &watchdogSharedPtr) {
190 watchdogSharedPtr.reset();
194 HiCollie_ErrorCode stuckDetectionInitRes = OH_HiCollie_Init_StuckDetection(
196 runWithQtWatchdogSharedPtr(
197 [](
auto &watchdogSharedPtr) {
198 if (watchdogSharedPtr)
199 watchdogSharedPtr->runHiCollieStuckDetectionTask();
203 std::shared_ptr<
void> result;
204 if (stuckDetectionInitRes == HICOLLIE_SUCCESS) {
205 result = watchdogHandle;
209 "OH_HiCollie_Init_StuckDetection() failed with code %d, disabling QtWatchdog",
210 static_cast<
int>(stuckDetectionInitRes));
std::shared_ptr< void > makeWatchdog()