1eace7efcSopenharmony_ci/*
2eace7efcSopenharmony_ci * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3eace7efcSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4eace7efcSopenharmony_ci * you may not use this file except in compliance with the License.
5eace7efcSopenharmony_ci * You may obtain a copy of the License at
6eace7efcSopenharmony_ci *
7eace7efcSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8eace7efcSopenharmony_ci *
9eace7efcSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10eace7efcSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11eace7efcSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12eace7efcSopenharmony_ci * See the License for the specific language governing permissions and
13eace7efcSopenharmony_ci * limitations under the License.
14eace7efcSopenharmony_ci */
15eace7efcSopenharmony_ci
16eace7efcSopenharmony_ci#include "watchdog.h"
17eace7efcSopenharmony_ci
18eace7efcSopenharmony_ci#include <parameter.h>
19eace7efcSopenharmony_ci#include <unistd.h>
20eace7efcSopenharmony_ci
21eace7efcSopenharmony_ci#include "app_mgr_client.h"
22eace7efcSopenharmony_ci#include "app_recovery.h"
23eace7efcSopenharmony_ci#include "appfreeze_inner.h"
24eace7efcSopenharmony_ci#include "hisysevent.h"
25eace7efcSopenharmony_ci#include "hilog_tag_wrapper.h"
26eace7efcSopenharmony_ci#include "xcollie/watchdog.h"
27eace7efcSopenharmony_ci
28eace7efcSopenharmony_cinamespace OHOS {
29eace7efcSopenharmony_cinamespace AppExecFwk {
30eace7efcSopenharmony_cinamespace {
31eace7efcSopenharmony_ciconstexpr uint32_t CHECK_MAIN_THREAD_IS_ALIVE = 1;
32eace7efcSopenharmony_ciconstexpr int RESET_RATIO = 2;
33eace7efcSopenharmony_ci
34eace7efcSopenharmony_ciconstexpr int32_t BACKGROUND_REPORT_COUNT_MAX = 5;
35eace7efcSopenharmony_ciconstexpr int32_t WATCHDOG_REPORT_COUNT_MAX = 5;
36eace7efcSopenharmony_ci#ifdef SUPPORT_ASAN
37eace7efcSopenharmony_ciconstexpr uint32_t CHECK_INTERVAL_TIME = 45000;
38eace7efcSopenharmony_ci#else
39eace7efcSopenharmony_ciconstexpr uint32_t CHECK_INTERVAL_TIME = 3000;
40eace7efcSopenharmony_ci#endif
41eace7efcSopenharmony_ci}
42eace7efcSopenharmony_cistd::shared_ptr<EventHandler> Watchdog::appMainHandler_ = nullptr;
43eace7efcSopenharmony_ci
44eace7efcSopenharmony_ciWatchdog::Watchdog()
45eace7efcSopenharmony_ci{}
46eace7efcSopenharmony_ci
47eace7efcSopenharmony_ciWatchdog::~Watchdog()
48eace7efcSopenharmony_ci{
49eace7efcSopenharmony_ci    if (!stopWatchdog_) {
50eace7efcSopenharmony_ci        TAG_LOGD(AAFwkTag::APPDFR, "Stop watchdog");
51eace7efcSopenharmony_ci        OHOS::HiviewDFX::Watchdog::GetInstance().StopWatchdog();
52eace7efcSopenharmony_ci    }
53eace7efcSopenharmony_ci}
54eace7efcSopenharmony_ci
55eace7efcSopenharmony_civoid Watchdog::Init(const std::shared_ptr<EventHandler> mainHandler)
56eace7efcSopenharmony_ci{
57eace7efcSopenharmony_ci    std::unique_lock<std::mutex> lock(cvMutex_);
58eace7efcSopenharmony_ci    Watchdog::appMainHandler_ = mainHandler;
59eace7efcSopenharmony_ci    if (appMainHandler_ != nullptr) {
60eace7efcSopenharmony_ci        TAG_LOGD(AAFwkTag::APPDFR, "Watchdog init send event");
61eace7efcSopenharmony_ci        appMainHandler_->SendEvent(CHECK_MAIN_THREAD_IS_ALIVE, 0, EventQueue::Priority::IMMEDIATE);
62eace7efcSopenharmony_ci    }
63eace7efcSopenharmony_ci    lastWatchTime_ = 0;
64eace7efcSopenharmony_ci    auto watchdogTask = [this] { this->Timer(); };
65eace7efcSopenharmony_ci    OHOS::HiviewDFX::Watchdog::GetInstance().RunPeriodicalTask("AppkitWatchdog", watchdogTask,
66eace7efcSopenharmony_ci        CHECK_INTERVAL_TIME, INI_TIMER_FIRST_SECOND);
67eace7efcSopenharmony_ci}
68eace7efcSopenharmony_ci
69eace7efcSopenharmony_civoid Watchdog::Stop()
70eace7efcSopenharmony_ci{
71eace7efcSopenharmony_ci    TAG_LOGD(AAFwkTag::APPDFR, "called");
72eace7efcSopenharmony_ci    std::unique_lock<std::mutex> lock(cvMutex_);
73eace7efcSopenharmony_ci    if (stopWatchdog_) {
74eace7efcSopenharmony_ci        TAG_LOGD(AAFwkTag::APPDFR, "stoped");
75eace7efcSopenharmony_ci        return;
76eace7efcSopenharmony_ci    }
77eace7efcSopenharmony_ci    stopWatchdog_.store(true);
78eace7efcSopenharmony_ci    cvWatchdog_.notify_all();
79eace7efcSopenharmony_ci    OHOS::HiviewDFX::Watchdog::GetInstance().StopWatchdog();
80eace7efcSopenharmony_ci
81eace7efcSopenharmony_ci    if (appMainHandler_) {
82eace7efcSopenharmony_ci        appMainHandler_.reset();
83eace7efcSopenharmony_ci        appMainHandler_ = nullptr;
84eace7efcSopenharmony_ci    }
85eace7efcSopenharmony_ci}
86eace7efcSopenharmony_ci
87eace7efcSopenharmony_civoid Watchdog::SetAppMainThreadState(const bool appMainThreadState)
88eace7efcSopenharmony_ci{
89eace7efcSopenharmony_ci    std::unique_lock<std::mutex> lock(cvMutex_);
90eace7efcSopenharmony_ci    appMainThreadIsAlive_.store(appMainThreadState);
91eace7efcSopenharmony_ci}
92eace7efcSopenharmony_ci
93eace7efcSopenharmony_civoid Watchdog::SetBundleInfo(const std::string& bundleName, const std::string& bundleVersion)
94eace7efcSopenharmony_ci{
95eace7efcSopenharmony_ci    OHOS::HiviewDFX::Watchdog::GetInstance().SetBundleInfo(bundleName, bundleVersion);
96eace7efcSopenharmony_ci}
97eace7efcSopenharmony_ci
98eace7efcSopenharmony_civoid Watchdog::SetBackgroundStatus(const bool isInBackground)
99eace7efcSopenharmony_ci{
100eace7efcSopenharmony_ci    std::unique_lock<std::mutex> lock(cvMutex_);
101eace7efcSopenharmony_ci    isInBackground_.store(isInBackground);
102eace7efcSopenharmony_ci    OHOS::HiviewDFX::Watchdog::GetInstance().SetForeground(!isInBackground);
103eace7efcSopenharmony_ci}
104eace7efcSopenharmony_ci
105eace7efcSopenharmony_civoid Watchdog::AllowReportEvent()
106eace7efcSopenharmony_ci{
107eace7efcSopenharmony_ci    std::unique_lock<std::mutex> lock(cvMutex_);
108eace7efcSopenharmony_ci    needReport_.store(true);
109eace7efcSopenharmony_ci    isSixSecondEvent_.store(false);
110eace7efcSopenharmony_ci    backgroundReportCount_.store(0);
111eace7efcSopenharmony_ci    watchdogReportCount_.store(0);
112eace7efcSopenharmony_ci}
113eace7efcSopenharmony_ci
114eace7efcSopenharmony_cibool Watchdog::IsReportEvent()
115eace7efcSopenharmony_ci{
116eace7efcSopenharmony_ci    if (appMainThreadIsAlive_) {
117eace7efcSopenharmony_ci        appMainThreadIsAlive_.store(false);
118eace7efcSopenharmony_ci        return false;
119eace7efcSopenharmony_ci    }
120eace7efcSopenharmony_ci    TAG_LOGD(AAFwkTag::APPDFR, "AppMainThread not alive");
121eace7efcSopenharmony_ci    return true;
122eace7efcSopenharmony_ci}
123eace7efcSopenharmony_ci
124eace7efcSopenharmony_cibool Watchdog::IsStopWatchdog()
125eace7efcSopenharmony_ci{
126eace7efcSopenharmony_ci    std::unique_lock<std::mutex> lock(cvMutex_);
127eace7efcSopenharmony_ci    return stopWatchdog_;
128eace7efcSopenharmony_ci}
129eace7efcSopenharmony_ci
130eace7efcSopenharmony_civoid Watchdog::SetBgWorkingThreadStatus(const bool isBgWorkingThread)
131eace7efcSopenharmony_ci{
132eace7efcSopenharmony_ci    std::unique_lock<std::mutex> lock(cvMutex_);
133eace7efcSopenharmony_ci    isBgWorkingThread_.store(isBgWorkingThread);
134eace7efcSopenharmony_ci}
135eace7efcSopenharmony_ci
136eace7efcSopenharmony_civoid Watchdog::Timer()
137eace7efcSopenharmony_ci{
138eace7efcSopenharmony_ci    std::unique_lock<std::mutex> lock(cvMutex_);
139eace7efcSopenharmony_ci    if (stopWatchdog_) {
140eace7efcSopenharmony_ci        TAG_LOGD(AAFwkTag::APPDFR, "stoped");
141eace7efcSopenharmony_ci        return;
142eace7efcSopenharmony_ci    }
143eace7efcSopenharmony_ci    if (!needReport_) {
144eace7efcSopenharmony_ci        watchdogReportCount_++;
145eace7efcSopenharmony_ci        TAG_LOGE(AAFwkTag::APPDFR, "timeout, wait to recover, wait count: %{public}d",
146eace7efcSopenharmony_ci            watchdogReportCount_.load());
147eace7efcSopenharmony_ci        if (watchdogReportCount_.load() >= WATCHDOG_REPORT_COUNT_MAX) {
148eace7efcSopenharmony_ci#ifndef APP_NO_RESPONSE_DIALOG
149eace7efcSopenharmony_ci            AppExecFwk::AppfreezeInner::GetInstance()->AppfreezeHandleOverReportCount(true);
150eace7efcSopenharmony_ci#endif
151eace7efcSopenharmony_ci            watchdogReportCount_.store(0);
152eace7efcSopenharmony_ci        } else if (watchdogReportCount_.load() >= (WATCHDOG_REPORT_COUNT_MAX - 1)) {
153eace7efcSopenharmony_ci#ifndef APP_NO_RESPONSE_DIALOG
154eace7efcSopenharmony_ci            AppExecFwk::AppfreezeInner::GetInstance()->AppfreezeHandleOverReportCount(false);
155eace7efcSopenharmony_ci#endif
156eace7efcSopenharmony_ci        }
157eace7efcSopenharmony_ci        return;
158eace7efcSopenharmony_ci    }
159eace7efcSopenharmony_ci
160eace7efcSopenharmony_ci    if (IsReportEvent()) {
161eace7efcSopenharmony_ci        const int bufferLen = 128;
162eace7efcSopenharmony_ci        char paramOutBuf[bufferLen] = {0};
163eace7efcSopenharmony_ci        const char *hook_mode = "startup:";
164eace7efcSopenharmony_ci        int ret = GetParameter("libc.hook_mode", "", paramOutBuf, bufferLen);
165eace7efcSopenharmony_ci        if (ret <= 0 || strncmp(paramOutBuf, hook_mode, strlen(hook_mode)) != 0) {
166eace7efcSopenharmony_ci            ReportEvent();
167eace7efcSopenharmony_ci        }
168eace7efcSopenharmony_ci    }
169eace7efcSopenharmony_ci    if (appMainHandler_ != nullptr) {
170eace7efcSopenharmony_ci        appMainHandler_->SendEvent(CHECK_MAIN_THREAD_IS_ALIVE, 0, EventQueue::Priority::IMMEDIATE);
171eace7efcSopenharmony_ci    }
172eace7efcSopenharmony_ci    int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::
173eace7efcSopenharmony_ci        system_clock::now().time_since_epoch()).count();
174eace7efcSopenharmony_ci    if ((now - lastWatchTime_) >= (CHECK_INTERVAL_TIME / RESET_RATIO)) {
175eace7efcSopenharmony_ci        lastWatchTime_ = now;
176eace7efcSopenharmony_ci    }
177eace7efcSopenharmony_ci}
178eace7efcSopenharmony_ci
179eace7efcSopenharmony_civoid Watchdog::ReportEvent()
180eace7efcSopenharmony_ci{
181eace7efcSopenharmony_ci    if (isBgWorkingThread_) {
182eace7efcSopenharmony_ci        TAG_LOGD(AAFwkTag::APPDFR, "Thread is working in the background, do not report this time");
183eace7efcSopenharmony_ci        return;
184eace7efcSopenharmony_ci    }
185eace7efcSopenharmony_ci    int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::
186eace7efcSopenharmony_ci        system_clock::now().time_since_epoch()).count();
187eace7efcSopenharmony_ci    if ((now - lastWatchTime_) > (RESET_RATIO * CHECK_INTERVAL_TIME) ||
188eace7efcSopenharmony_ci        (now - lastWatchTime_) < (CHECK_INTERVAL_TIME / RESET_RATIO)) {
189eace7efcSopenharmony_ci        TAG_LOGI(AAFwkTag::APPDFR,
190eace7efcSopenharmony_ci            "Thread may be blocked, not report time. currTime: %{public}llu, lastTime: %{public}llu",
191eace7efcSopenharmony_ci            static_cast<unsigned long long>(now), static_cast<unsigned long long>(lastWatchTime_));
192eace7efcSopenharmony_ci        return;
193eace7efcSopenharmony_ci    }
194eace7efcSopenharmony_ci
195eace7efcSopenharmony_ci    if (isInBackground_ && backgroundReportCount_.load() < BACKGROUND_REPORT_COUNT_MAX) {
196eace7efcSopenharmony_ci        TAG_LOGI(AAFwkTag::APPDFR, "In Background, thread may be blocked in, not report time"
197eace7efcSopenharmony_ci            "currTime: %{public}" PRIu64 ", lastTime: %{public}" PRIu64 "",
198eace7efcSopenharmony_ci            static_cast<uint64_t>(now), static_cast<uint64_t>(lastWatchTime_));
199eace7efcSopenharmony_ci        backgroundReportCount_++;
200eace7efcSopenharmony_ci        return;
201eace7efcSopenharmony_ci    }
202eace7efcSopenharmony_ci    backgroundReportCount_++;
203eace7efcSopenharmony_ci
204eace7efcSopenharmony_ci    if (!needReport_) {
205eace7efcSopenharmony_ci        return;
206eace7efcSopenharmony_ci    }
207eace7efcSopenharmony_ci
208eace7efcSopenharmony_ci#ifndef APP_NO_RESPONSE_DIALOG
209eace7efcSopenharmony_ci    if (isSixSecondEvent_) {
210eace7efcSopenharmony_ci        needReport_.store(false);
211eace7efcSopenharmony_ci    }
212eace7efcSopenharmony_ci#endif
213eace7efcSopenharmony_ci    AppExecFwk::AppfreezeInner::GetInstance()->ThreadBlock(isSixSecondEvent_);
214eace7efcSopenharmony_ci}
215eace7efcSopenharmony_ci}  // namespace AppExecFwk
216eace7efcSopenharmony_ci}  // namespace OHOS
217