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