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>
16namespace ch =
std::chrono;
24constexpr int resetRatio = 2;
26constexpr auto bigDataEnterFreezeStateEventName =
"enterFreezeState";
27constexpr auto bigDataRecoveredFromFreezeStateEventName =
"recoveredFromFreezeState";
29constexpr auto bigDataEventDescriptionPropertyName =
"eventDescription";
30constexpr auto bigDataFreezeStateDurationPropertyName =
"freezeStateDurationMs";
33constexpr auto checkIntervalTime = ch::seconds(45);
35constexpr auto checkIntervalTime = ch::seconds(3);
38void logEnterFreezeStateBigDataEvent(ch::time_point<ch::system_clock> eventTime)
40 qCDebug(QtForOhos,
"%s", Q_FUNC_INFO);
42 auto eventBuilder = QtOhos::makeBigEventLoggingEventBuilder(
43 bigDataEnterFreezeStateEventName, ::EventType::STATISTIC, eventTime);
44 eventBuilder->addParam(bigDataEventDescriptionPropertyName,
"The application triggered a 6 second freeze");
45 eventBuilder->buildEvent()->trySend();
48void logRecoveredFromFreezeStateBigDataEvent(
49 ch::time_point<ch::system_clock> eventTime, ch::system_clock::duration freezeStateDuration)
51 qCDebug(QtForOhos,
"%s", Q_FUNC_INFO);
53 auto eventBuilder = QtOhos::makeBigEventLoggingEventBuilder(
54 bigDataRecoveredFromFreezeStateEventName, ::EventType::STATISTIC, eventTime);
55 eventBuilder->addParam(bigDataEventDescriptionPropertyName,
"Recovered from the frozen state");
56 eventBuilder->addParam(
57 bigDataFreezeStateDurationPropertyName,
58 static_cast<
std::int64_t>(ch::duration_cast<ch::milliseconds>(freezeStateDuration).count()));
59 eventBuilder->buildEvent()->trySend();
62class QtWatchdog :
public QObject
67 void runHiCollieStuckDetectionTask();
69 bool event(QEvent *ev)
override;
72 void handleAppMainThreadAliveNotification();
73 void reportStuckEvent();
75 ch::steady_clock::time_point m_lastWatchTime;
76 bool m_appMainThreadIsAlive =
false;
77 bool m_isSixSecondEvent =
false;
78 QOhosOptional<ch::system_clock::time_point> m_sixSecondEventDetectionTime;
81QEvent::Type getCheckMainThreadIsAliveQEventType()
83 static auto eventType =
static_cast<QEvent::Type>(QEvent::registerEventType());
87QtWatchdog::QtWatchdog()
90 QCoreApplication::postEvent(
this,
new QEvent(getCheckMainThreadIsAliveQEventType()), Qt::HighEventPriority);
93void QtWatchdog::handleAppMainThreadAliveNotification()
95 qCDebug(QtForOhos,
"QtWatchdog::handleAppMainThreadAliveNotification");
96 m_appMainThreadIsAlive =
true;
97 m_isSixSecondEvent =
false;
98 if (m_sixSecondEventDetectionTime.hasValue()) {
99 const auto now = ch::system_clock::now();
100 const auto elapsedTime = now - m_sixSecondEventDetectionTime.value();
101 logRecoveredFromFreezeStateBigDataEvent(now, elapsedTime);
102 m_sixSecondEventDetectionTime.reset();
106void QtWatchdog::runHiCollieStuckDetectionTask()
108 qCDebug(QtForOhos,
"QtWatchdog::runHiCollieStuckDetectionTask start");
110 if (m_appMainThreadIsAlive) {
111 qCDebug(QtForOhos,
"QtWatchdog: m_appMainThreadIsAlive store false");
112 m_appMainThreadIsAlive =
false;
114 qCWarning(QtForOhos,
"QtWatchdog: AppMainThread is not alive");
118 QCoreApplication::postEvent(
this,
new QEvent(getCheckMainThreadIsAliveQEventType()), Qt::HighEventPriority);
120 auto now = ch::steady_clock::now();
121 if ((now - m_lastWatchTime) >= (checkIntervalTime / resetRatio))
122 m_lastWatchTime = now;
124 qCDebug(QtForOhos,
"QtWatchdog::runHiCollieStuckDetectionTask end");
127bool QtWatchdog::event(QEvent *ev)
129 if (ev->type() == getCheckMainThreadIsAliveQEventType()) {
130 qCDebug(QtForOhos,
"QtWatchdog: CheckMainThreadIsAlive event start (%d)",
static_cast<
int>(getCheckMainThreadIsAliveQEventType()));
131 handleAppMainThreadAliveNotification();
132 qCDebug(QtForOhos,
"QCoreApplication: CheckMainThreadIsAlive event end");
135 return QObject::event(ev);
139void QtWatchdog::reportStuckEvent()
141 auto now = ch::steady_clock::now();
142 auto timeDelta = now - m_lastWatchTime;
143 if (timeDelta > resetRatio * checkIntervalTime || timeDelta < checkIntervalTime / resetRatio) {
146 "QtWatchdog: Thread may be blocked, do not report this time. currTime: %.3f, lastTime: %.3f",
147 ch::duration<
double>(now.time_since_epoch()).count(),
148 ch::duration<
double>(m_lastWatchTime.time_since_epoch()).count());
152 qCDebug(QtForOhos,
"QtWatchdog: calling OH_HiCollie_Report(), m_isSixSecondEvent = %d", m_isSixSecondEvent);
153 HiCollie_ErrorCode reportRes = OH_HiCollie_Report(&m_isSixSecondEvent);
154 if (reportRes == HICOLLIE_SUCCESS) {
155 qCDebug(QtForOhos,
"QtWatchdog: after OH_HiCollie_Report(), m_isSixSecondEvent = %d", m_isSixSecondEvent);
156 if (m_isSixSecondEvent && !m_sixSecondEventDetectionTime.hasValue()) {
157 m_sixSecondEventDetectionTime = ch::system_clock::now();
158 logEnterFreezeStateBigDataEvent(m_sixSecondEventDetectionTime.value());
161 qCWarning(QtForOhos,
"QtWatchdog: OH_HiCollie_Report() failed with code %d",
static_cast<
int>(reportRes));
165void runWithQtWatchdogSharedPtr(
const std::function<
void(
std::shared_ptr<QtWatchdog> &)> &runFunc)
167 static std::mutex runMutex;
168 static std::shared_ptr<QtWatchdog> qtWatchdogPtr;
171 std::lock_guard<
std::mutex> runLock(runMutex);
172 runFunc(qtWatchdogPtr);
180 runWithQtWatchdogSharedPtr(
181 [](
auto &watchdogSharedPtr) {
182 watchdogSharedPtr =
std::make_shared<QtWatchdog>();
185 auto watchdogHandle = QtOhos::makeDestroyNotifier(
187 runWithQtWatchdogSharedPtr(
188 [](
auto &watchdogSharedPtr) {
189 watchdogSharedPtr.reset();
193 HiCollie_ErrorCode stuckDetectionInitRes = OH_HiCollie_Init_StuckDetection(
195 runWithQtWatchdogSharedPtr(
196 [](
auto &watchdogSharedPtr) {
197 if (watchdogSharedPtr)
198 watchdogSharedPtr->runHiCollieStuckDetectionTask();
202 std::shared_ptr<
void> result;
203 if (stuckDetectionInitRes == HICOLLIE_SUCCESS) {
204 result = watchdogHandle;
208 "OH_HiCollie_Init_StuckDetection() failed with code %d, disabling QtWatchdog",
209 static_cast<
int>(stuckDetectionInitRes));
std::enable_if_t< qohosplugincore_h_detail::isQOhosOptional< QOhosInvokeResult< Func, T > >, QOhosInvokeResult< Func, T > > andThen(Func &&func) const
std::shared_ptr< void > makeWatchdog()