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
28 namespace OHOS {
29 namespace AppExecFwk {
30 namespace {
31 constexpr uint32_t CHECK_MAIN_THREAD_IS_ALIVE = 1;
32 constexpr int RESET_RATIO = 2;
33
34 constexpr int32_t BACKGROUND_REPORT_COUNT_MAX = 5;
35 constexpr int32_t WATCHDOG_REPORT_COUNT_MAX = 5;
36 #ifdef SUPPORT_ASAN
37 constexpr uint32_t CHECK_INTERVAL_TIME = 45000;
38 #else
39 constexpr uint32_t CHECK_INTERVAL_TIME = 3000;
40 #endif
41 }
42 std::shared_ptr<EventHandler> Watchdog::appMainHandler_ = nullptr;
43
Watchdog()44 Watchdog::Watchdog()
45 {}
46
~Watchdog()47 Watchdog::~Watchdog()
48 {
49 if (!stopWatchdog_) {
50 TAG_LOGD(AAFwkTag::APPDFR, "Stop watchdog");
51 OHOS::HiviewDFX::Watchdog::GetInstance().StopWatchdog();
52 }
53 }
54
Init(const std::shared_ptr<EventHandler> mainHandler)55 void 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::HIGH);
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
Stop()69 void 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
SetAppMainThreadState(const bool appMainThreadState)87 void Watchdog::SetAppMainThreadState(const bool appMainThreadState)
88 {
89 std::unique_lock<std::mutex> lock(cvMutex_);
90 appMainThreadIsAlive_.store(appMainThreadState);
91 }
92
SetBundleInfo(const std::string & bundleName,const std::string & bundleVersion)93 void Watchdog::SetBundleInfo(const std::string& bundleName, const std::string& bundleVersion)
94 {
95 OHOS::HiviewDFX::Watchdog::GetInstance().SetBundleInfo(bundleName, bundleVersion);
96 }
97
SetBackgroundStatus(const bool isInBackground)98 void 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
AllowReportEvent()105 void 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
IsReportEvent()114 bool 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
IsStopWatchdog()124 bool Watchdog::IsStopWatchdog()
125 {
126 std::unique_lock<std::mutex> lock(cvMutex_);
127 return stopWatchdog_;
128 }
129
SetBgWorkingThreadStatus(const bool isBgWorkingThread)130 void Watchdog::SetBgWorkingThreadStatus(const bool isBgWorkingThread)
131 {
132 std::unique_lock<std::mutex> lock(cvMutex_);
133 isBgWorkingThread_.store(isBgWorkingThread);
134 }
135
Timer()136 void 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::HIGH);
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
ReportEvent()179 void 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