• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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