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 #ifdef ABILITY_RUNTIME_HITRACE_ENABLE
34 constexpr int32_t CHARACTER_WIDTH = 2;
35 #endif
36
37 constexpr int32_t BACKGROUND_REPORT_COUNT_MAX = 5;
38 constexpr int32_t WATCHDOG_REPORT_COUNT_MAX = 5;
39 #ifdef SUPPORT_ASAN
40 constexpr uint32_t CHECK_INTERVAL_TIME = 45000;
41 #else
42 constexpr uint32_t CHECK_INTERVAL_TIME = 3000;
43 #endif
44
45 #ifdef APP_NO_RESPONSE_DIALOG_WEARABLE
46 constexpr uint32_t WEARABLE_CHECK_INTERVAL_TIME = 5000;
47 #endif
48 }
49 std::shared_ptr<EventHandler> Watchdog::appMainHandler_ = nullptr;
50
51 #ifdef ABILITY_RUNTIME_HITRACE_ENABLE
52 OHOS::HiviewDFX::HiTraceId* Watchdog::hitraceId_ = nullptr;
53 #endif
54
Watchdog()55 Watchdog::Watchdog()
56 {}
57
~Watchdog()58 Watchdog::~Watchdog()
59 {
60 if (!stopWatchdog_) {
61 TAG_LOGD(AAFwkTag::APPDFR, "Stop watchdog");
62 OHOS::HiviewDFX::Watchdog::GetInstance().StopWatchdog();
63 }
64 }
65
Init(const std::shared_ptr<EventHandler> mainHandler)66 void Watchdog::Init(const std::shared_ptr<EventHandler> mainHandler)
67 {
68 std::unique_lock<std::mutex> lock(cvMutex_);
69 Watchdog::appMainHandler_ = mainHandler;
70 if (appMainHandler_ != nullptr) {
71 TAG_LOGD(AAFwkTag::APPDFR, "Watchdog init send event");
72 appMainHandler_->SendEvent(CHECK_MAIN_THREAD_IS_ALIVE, 0, EventQueue::Priority::VIP);
73 }
74 lastWatchTime_ = 0;
75 #ifdef ABILITY_RUNTIME_HITRACE_ENABLE
76 hitraceId_ = OHOS::HiviewDFX::HiTraceChain::GetIdAddress();
77 #endif
78 auto watchdogTask = [this] { this->Timer(); };
79 #ifdef APP_NO_RESPONSE_DIALOG_WEARABLE
80 OHOS::HiviewDFX::Watchdog::GetInstance().RunPeriodicalTask("AppkitWatchdog", watchdogTask,
81 WEARABLE_CHECK_INTERVAL_TIME, INI_TIMER_FIRST_SECOND);
82 #else
83 OHOS::HiviewDFX::Watchdog::GetInstance().RunPeriodicalTask("AppkitWatchdog", watchdogTask,
84 CHECK_INTERVAL_TIME, INI_TIMER_FIRST_SECOND);
85 #endif
86 }
87
Stop()88 void Watchdog::Stop()
89 {
90 TAG_LOGD(AAFwkTag::APPDFR, "called");
91 std::unique_lock<std::mutex> lock(cvMutex_);
92 if (stopWatchdog_) {
93 TAG_LOGD(AAFwkTag::APPDFR, "stoped");
94 return;
95 }
96 stopWatchdog_.store(true);
97 cvWatchdog_.notify_all();
98 OHOS::HiviewDFX::Watchdog::GetInstance().StopWatchdog();
99
100 if (appMainHandler_) {
101 appMainHandler_.reset();
102 appMainHandler_ = nullptr;
103 }
104 }
105
SetAppMainThreadState(const bool appMainThreadState)106 void Watchdog::SetAppMainThreadState(const bool appMainThreadState)
107 {
108 std::unique_lock<std::mutex> lock(cvMutex_);
109 appMainThreadIsAlive_.store(appMainThreadState);
110 }
111
112 #ifdef ABILITY_RUNTIME_HITRACE_ENABLE
SetHiTraceChainId()113 void Watchdog::SetHiTraceChainId()
114 {
115 OHOS::HiviewDFX::HiTraceId hitraceId = *hitraceId_;
116 if (hitraceId.IsValid() == 0) {
117 TAG_LOGW(AAFwkTag::APPDFR, "get hitrace id is invalid.");
118 return;
119 }
120 OHOS::HiviewDFX::HiTraceChain::SetId(hitraceId);
121 std::stringstream ss;
122 ss << std::hex << std::setfill('0') << std::setw(CHARACTER_WIDTH) << hitraceId.GetChainId();
123 TAG_LOGI(AAFwkTag::APPDFR, "Main thread blocked, %{public}s", ss.str().c_str());
124 }
125 #endif
126
127 #ifdef APP_NO_RESPONSE_DIALOG
isDeviceType2in1()128 bool isDeviceType2in1()
129 {
130 const int bufferLen = 128;
131 char paramOutBuf[bufferLen] = {0};
132 const char *devicetype2in1 = "2in1";
133 int ret = GetParameter("const.product.devicetype", "", paramOutBuf, bufferLen);
134 return ret > 0 && strncmp(paramOutBuf, devicetype2in1, strlen(devicetype2in1)) == 0;
135 }
136 #endif
137
138 #ifdef APP_NO_RESPONSE_DIALOG
ChangeTimeOut(const std::string & bundleName)139 void Watchdog::ChangeTimeOut(const std::string& bundleName)
140 {
141 constexpr char SCENEBOARD_SERVICE_ABILITY[] = "com.ohos.sceneboard";
142 constexpr int TIMEOUT = 5000;
143 if (bundleName == SCENEBOARD_SERVICE_ABILITY) {
144 OHOS::HiviewDFX::Watchdog::GetInstance().RemovePeriodicalTask("AppkitWatchdog");
145 auto watchdogTask = [this] { this->Timer(); };
146 OHOS::HiviewDFX::Watchdog::GetInstance().RunPeriodicalTask("AppkitWatchdog", watchdogTask, TIMEOUT,
147 INI_TIMER_FIRST_SECOND);
148 }
149 }
150 #endif
151
SetBundleInfo(const std::string & bundleName,const std::string & bundleVersion)152 void Watchdog::SetBundleInfo(const std::string& bundleName, const std::string& bundleVersion)
153 {
154 OHOS::HiviewDFX::Watchdog::GetInstance().SetBundleInfo(bundleName, bundleVersion);
155 #ifdef APP_NO_RESPONSE_DIALOG
156 if (isDeviceType2in1()) {
157 ChangeTimeOut(bundleName);
158 }
159 #endif
160 }
161
SetBackgroundStatus(const bool isInBackground)162 void Watchdog::SetBackgroundStatus(const bool isInBackground)
163 {
164 std::unique_lock<std::mutex> lock(cvMutex_);
165 isInBackground_.store(isInBackground);
166 OHOS::HiviewDFX::Watchdog::GetInstance().SetForeground(!isInBackground);
167 }
168
AllowReportEvent()169 void Watchdog::AllowReportEvent()
170 {
171 std::unique_lock<std::mutex> lock(cvMutex_);
172 needReport_.store(true);
173 isSixSecondEvent_.store(false);
174 watchdogReportCount_.store(0);
175 }
176
IsReportEvent()177 bool Watchdog::IsReportEvent()
178 {
179 if (appMainThreadIsAlive_) {
180 appMainThreadIsAlive_.store(false);
181 return false;
182 }
183 TAG_LOGD(AAFwkTag::APPDFR, "AppMainThread not alive");
184 return true;
185 }
186
IsStopWatchdog()187 bool Watchdog::IsStopWatchdog()
188 {
189 std::unique_lock<std::mutex> lock(cvMutex_);
190 return stopWatchdog_;
191 }
192
SetBgWorkingThreadStatus(const bool isBgWorkingThread)193 void Watchdog::SetBgWorkingThreadStatus(const bool isBgWorkingThread)
194 {
195 std::unique_lock<std::mutex> lock(cvMutex_);
196 isBgWorkingThread_.store(isBgWorkingThread);
197 }
198
Timer()199 void Watchdog::Timer()
200 {
201 std::unique_lock<std::mutex> lock(cvMutex_);
202 if (stopWatchdog_) {
203 TAG_LOGD(AAFwkTag::APPDFR, "stoped");
204 return;
205 }
206 if (!needReport_) {
207 watchdogReportCount_++;
208 TAG_LOGE(AAFwkTag::APPDFR, "wait count: %{public}d", watchdogReportCount_.load());
209 if (watchdogReportCount_.load() >= WATCHDOG_REPORT_COUNT_MAX) {
210 #ifdef ABILITY_RUNTIME_HITRACE_ENABLE
211 SetHiTraceChainId();
212 #endif
213 #ifndef APP_NO_RESPONSE_DIALOG
214 AppExecFwk::AppfreezeInner::GetInstance()->AppfreezeHandleOverReportCount(true);
215 #endif
216 watchdogReportCount_.store(0);
217 } else if (watchdogReportCount_.load() >= (WATCHDOG_REPORT_COUNT_MAX - 1)) {
218 #ifndef APP_NO_RESPONSE_DIALOG
219 AppExecFwk::AppfreezeInner::GetInstance()->AppfreezeHandleOverReportCount(false);
220 #endif
221 }
222 return;
223 }
224
225 if (IsReportEvent()) {
226 const int bufferLen = 128;
227 char paramOutBuf[bufferLen] = {0};
228 const char *hook_mode = "startup:";
229 int ret = GetParameter("libc.hook_mode", "", paramOutBuf, bufferLen);
230 if (ret <= 0 || strncmp(paramOutBuf, hook_mode, strlen(hook_mode)) != 0) {
231 ReportEvent();
232 }
233 }
234 if (appMainHandler_ != nullptr) {
235 appMainHandler_->SendEvent(CHECK_MAIN_THREAD_IS_ALIVE, 0, EventQueue::Priority::VIP);
236 }
237 int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::
238 system_clock::now().time_since_epoch()).count();
239 #ifdef APP_NO_RESPONSE_DIALOG_WEARABLE
240 if ((now - lastWatchTime_) < 0 || (now - lastWatchTime_) >= (WEARABLE_CHECK_INTERVAL_TIME / RESET_RATIO)) {
241 #else
242 if ((now - lastWatchTime_) < 0 || (now - lastWatchTime_) >= (CHECK_INTERVAL_TIME / RESET_RATIO)) {
243 #endif
244 lastWatchTime_ = now;
245 }
246 }
247
248 void Watchdog::ReportEvent()
249 {
250 if (isBgWorkingThread_) {
251 TAG_LOGD(AAFwkTag::APPDFR, "Thread is working in the background, do not report this time");
252 return;
253 }
254 int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::
255 system_clock::now().time_since_epoch()).count();
256 #ifdef APP_NO_RESPONSE_DIALOG_WEARABLE
257 if ((now - lastWatchTime_) > (RESET_RATIO * WEARABLE_CHECK_INTERVAL_TIME) ||
258 (now - lastWatchTime_) < (WEARABLE_CHECK_INTERVAL_TIME / RESET_RATIO)) {
259 #else
260 if ((now - lastWatchTime_) > (RESET_RATIO * CHECK_INTERVAL_TIME) ||
261 (now - lastWatchTime_) < (CHECK_INTERVAL_TIME / RESET_RATIO)) {
262 #endif
263 TAG_LOGI(AAFwkTag::APPDFR,
264 "Thread may be blocked, not report time. currTime: %{public}llu, lastTime: %{public}llu",
265 static_cast<unsigned long long>(now), static_cast<unsigned long long>(lastWatchTime_));
266 return;
267 }
268
269 if (isInBackground_) {
270 TAG_LOGI(AAFwkTag::APPDFR, "In Background, thread may be blocked in, not report time"
271 "currTime: %{public}" PRIu64 ", lastTime: %{public}" PRIu64 "",
272 static_cast<uint64_t>(now), static_cast<uint64_t>(lastWatchTime_));
273 return;
274 }
275
276 if (!needReport_) {
277 return;
278 }
279
280 #ifndef APP_NO_RESPONSE_DIALOG
281 if (isSixSecondEvent_) {
282 needReport_.store(false);
283 }
284 #endif
285
286 #ifdef ABILITY_RUNTIME_HITRACE_ENABLE
287 if (isSixSecondEvent_) {
288 SetHiTraceChainId();
289 }
290 #endif
291 AppExecFwk::AppfreezeInner::GetInstance()->ThreadBlock(isSixSecondEvent_);
292 }
293 } // namespace AppExecFwk
294 } // namespace OHOS
295