• 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 
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::VIP);
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 
93 #ifdef APP_NO_RESPONSE_DIALOG
isDeviceType2in1()94 bool isDeviceType2in1()
95 {
96     const int bufferLen = 128;
97     char paramOutBuf[bufferLen] = {0};
98     const char *devicetype2in1 = "2in1";
99     int ret = GetParameter("const.product.devicetype", "", paramOutBuf, bufferLen);
100     return ret > 0 && strncmp(paramOutBuf, devicetype2in1, strlen(devicetype2in1)) == 0;
101 }
102 #endif
103 
104 #ifdef APP_NO_RESPONSE_DIALOG
ChangeTimeOut(const std::string & bundleName)105 void Watchdog::ChangeTimeOut(const std::string& bundleName)
106 {
107     constexpr char SCENEBOARD_SERVICE_ABILITY[] = "com.ohos.sceneboard";
108     constexpr int TIMEOUT = 5000;
109     if (bundleName == SCENEBOARD_SERVICE_ABILITY) {
110         OHOS::HiviewDFX::Watchdog::GetInstance().RemovePeriodicalTask("AppkitWatchdog");
111         auto watchdogTask = [this] { this->Timer(); };
112         OHOS::HiviewDFX::Watchdog::GetInstance().RunPeriodicalTask("AppkitWatchdog", watchdogTask, TIMEOUT,
113             INI_TIMER_FIRST_SECOND);
114     }
115 }
116 #endif
117 
SetBundleInfo(const std::string & bundleName,const std::string & bundleVersion)118 void Watchdog::SetBundleInfo(const std::string& bundleName, const std::string& bundleVersion)
119 {
120     OHOS::HiviewDFX::Watchdog::GetInstance().SetBundleInfo(bundleName, bundleVersion);
121 #ifdef APP_NO_RESPONSE_DIALOG
122     if (isDeviceType2in1()) {
123         ChangeTimeOut(bundleName);
124     }
125 #endif
126 }
127 
SetBackgroundStatus(const bool isInBackground)128 void Watchdog::SetBackgroundStatus(const bool isInBackground)
129 {
130     std::unique_lock<std::mutex> lock(cvMutex_);
131     isInBackground_.store(isInBackground);
132     OHOS::HiviewDFX::Watchdog::GetInstance().SetForeground(!isInBackground);
133 }
134 
AllowReportEvent()135 void Watchdog::AllowReportEvent()
136 {
137     std::unique_lock<std::mutex> lock(cvMutex_);
138     needReport_.store(true);
139     isSixSecondEvent_.store(false);
140     backgroundReportCount_.store(0);
141     watchdogReportCount_.store(0);
142 }
143 
IsReportEvent()144 bool Watchdog::IsReportEvent()
145 {
146     if (appMainThreadIsAlive_) {
147         appMainThreadIsAlive_.store(false);
148         return false;
149     }
150     TAG_LOGD(AAFwkTag::APPDFR, "AppMainThread not alive");
151     return true;
152 }
153 
IsStopWatchdog()154 bool Watchdog::IsStopWatchdog()
155 {
156     std::unique_lock<std::mutex> lock(cvMutex_);
157     return stopWatchdog_;
158 }
159 
SetBgWorkingThreadStatus(const bool isBgWorkingThread)160 void Watchdog::SetBgWorkingThreadStatus(const bool isBgWorkingThread)
161 {
162     std::unique_lock<std::mutex> lock(cvMutex_);
163     isBgWorkingThread_.store(isBgWorkingThread);
164 }
165 
Timer()166 void Watchdog::Timer()
167 {
168     std::unique_lock<std::mutex> lock(cvMutex_);
169     if (stopWatchdog_) {
170         TAG_LOGD(AAFwkTag::APPDFR, "stoped");
171         return;
172     }
173     if (!needReport_) {
174         watchdogReportCount_++;
175         TAG_LOGE(AAFwkTag::APPDFR, "wait count: %{public}d", watchdogReportCount_.load());
176         if (watchdogReportCount_.load() >= WATCHDOG_REPORT_COUNT_MAX) {
177 #ifndef APP_NO_RESPONSE_DIALOG
178             AppExecFwk::AppfreezeInner::GetInstance()->AppfreezeHandleOverReportCount(true);
179 #endif
180             watchdogReportCount_.store(0);
181         } else if (watchdogReportCount_.load() >= (WATCHDOG_REPORT_COUNT_MAX - 1)) {
182 #ifndef APP_NO_RESPONSE_DIALOG
183             AppExecFwk::AppfreezeInner::GetInstance()->AppfreezeHandleOverReportCount(false);
184 #endif
185         }
186         return;
187     }
188 
189     if (IsReportEvent()) {
190         const int bufferLen = 128;
191         char paramOutBuf[bufferLen] = {0};
192         const char *hook_mode = "startup:";
193         int ret = GetParameter("libc.hook_mode", "", paramOutBuf, bufferLen);
194         if (ret <= 0 || strncmp(paramOutBuf, hook_mode, strlen(hook_mode)) != 0) {
195             ReportEvent();
196         }
197     }
198     if (appMainHandler_ != nullptr) {
199         appMainHandler_->SendEvent(CHECK_MAIN_THREAD_IS_ALIVE, 0, EventQueue::Priority::VIP);
200     }
201     int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::
202         system_clock::now().time_since_epoch()).count();
203     if ((now - lastWatchTime_) < 0 || (now - lastWatchTime_) >= (CHECK_INTERVAL_TIME / RESET_RATIO)) {
204         lastWatchTime_ = now;
205     }
206 }
207 
ReportEvent()208 void Watchdog::ReportEvent()
209 {
210     if (isBgWorkingThread_) {
211         TAG_LOGD(AAFwkTag::APPDFR, "Thread is working in the background, do not report this time");
212         return;
213     }
214     int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::
215         system_clock::now().time_since_epoch()).count();
216     if ((now - lastWatchTime_) > (RESET_RATIO * CHECK_INTERVAL_TIME) ||
217         (now - lastWatchTime_) < (CHECK_INTERVAL_TIME / RESET_RATIO)) {
218         TAG_LOGI(AAFwkTag::APPDFR,
219             "Thread may be blocked, not report time. currTime: %{public}llu, lastTime: %{public}llu",
220             static_cast<unsigned long long>(now), static_cast<unsigned long long>(lastWatchTime_));
221         return;
222     }
223 
224     if (isInBackground_ && backgroundReportCount_.load() < BACKGROUND_REPORT_COUNT_MAX) {
225         TAG_LOGI(AAFwkTag::APPDFR, "In Background, thread may be blocked in, not report time"
226             "currTime: %{public}" PRIu64 ", lastTime: %{public}" PRIu64 "",
227             static_cast<uint64_t>(now), static_cast<uint64_t>(lastWatchTime_));
228         backgroundReportCount_++;
229         return;
230     }
231     backgroundReportCount_++;
232 
233     if (!needReport_) {
234         return;
235     }
236 
237 #ifndef APP_NO_RESPONSE_DIALOG
238     if (isSixSecondEvent_) {
239         needReport_.store(false);
240     }
241 #endif
242     AppExecFwk::AppfreezeInner::GetInstance()->ThreadBlock(isSixSecondEvent_);
243 }
244 }  // namespace AppExecFwk
245 }  // namespace OHOS
246