• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 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_wrapper.h"
26 #include "mix_stack_dumper.h"
27 #include "xcollie/watchdog.h"
28 
29 namespace OHOS {
30 namespace AppExecFwk {
31 namespace {
32 constexpr uint32_t CHECK_MAIN_THREAD_IS_ALIVE = 1;
33 constexpr int RESET_RATIO = 2;
34 
35 constexpr int32_t BACKGROUND_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         HILOG_DEBUG("Stop watchdog when deconstruct.");
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     Watchdog::appMainHandler_ = mainHandler;
58     if (appMainHandler_ != nullptr) {
59         HILOG_DEBUG("Watchdog init send event");
60         appMainHandler_->SendEvent(CHECK_MAIN_THREAD_IS_ALIVE, 0, EventQueue::Priority::HIGH);
61     }
62     lastWatchTime_ = 0;
63     auto watchdogTask = std::bind(&Watchdog::Timer, this);
64     OHOS::HiviewDFX::Watchdog::GetInstance().RunPeriodicalTask("AppkitWatchdog", watchdogTask,
65         CHECK_INTERVAL_TIME, INI_TIMER_FIRST_SECOND);
66 }
67 
Stop()68 void Watchdog::Stop()
69 {
70     HILOG_DEBUG("Watchdog is stop!");
71     std::unique_lock<std::mutex> lock(cvMutex_);
72     if (stopWatchdog_) {
73         HILOG_DEBUG("Watchdog has stoped.");
74         return;
75     }
76     stopWatchdog_.store(true);
77     cvWatchdog_.notify_all();
78     OHOS::HiviewDFX::Watchdog::GetInstance().StopWatchdog();
79 
80     if (appMainHandler_) {
81         appMainHandler_.reset();
82         appMainHandler_ = nullptr;
83     }
84 }
85 
SetAppMainThreadState(const bool appMainThreadState)86 void Watchdog::SetAppMainThreadState(const bool appMainThreadState)
87 {
88     appMainThreadIsAlive_.store(appMainThreadState);
89 }
90 
SetBackgroundStatus(const bool isInBackground)91 void Watchdog::SetBackgroundStatus(const bool isInBackground)
92 {
93     isInBackground_.store(isInBackground);
94 }
95 
AllowReportEvent()96 void Watchdog::AllowReportEvent()
97 {
98     needReport_.store(true);
99     isSixSecondEvent_.store(false);
100     backgroundReportCount_.store(0);
101 }
102 
IsReportEvent()103 bool Watchdog::IsReportEvent()
104 {
105     if (appMainThreadIsAlive_) {
106         appMainThreadIsAlive_.store(false);
107         return false;
108     }
109     HILOG_DEBUG("AppMainThread is not alive");
110     return true;
111 }
112 
IsStopWatchdog()113 bool Watchdog::IsStopWatchdog()
114 {
115     return stopWatchdog_;
116 }
117 
Timer()118 void Watchdog::Timer()
119 {
120     std::unique_lock<std::mutex> lock(cvMutex_);
121     if (stopWatchdog_) {
122         HILOG_DEBUG("Watchdog has stoped.");
123         return;
124     }
125     if (!needReport_) {
126         HILOG_ERROR("Watchdog timeout, wait for the handler to recover, and do not send event.");
127         return;
128     }
129 
130     if (IsReportEvent()) {
131         const int bufferLen = 128;
132         char paramOutBuf[bufferLen] = {0};
133         const char *hook_mode = "startup:";
134         int ret = GetParameter("libc.hook_mode", "", paramOutBuf, bufferLen);
135         if (ret <= 0 || strncmp(paramOutBuf, hook_mode, strlen(hook_mode)) != 0) {
136             ReportEvent();
137         }
138     }
139     if (appMainHandler_ != nullptr) {
140         appMainHandler_->SendEvent(CHECK_MAIN_THREAD_IS_ALIVE, 0, EventQueue::Priority::HIGH);
141     }
142     int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::
143         system_clock::now().time_since_epoch()).count();
144     if ((now - lastWatchTime_) >= (CHECK_INTERVAL_TIME / RESET_RATIO)) {
145         lastWatchTime_ = now;
146     }
147 }
148 
ReportEvent()149 void Watchdog::ReportEvent()
150 {
151     int64_t now = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::
152         system_clock::now().time_since_epoch()).count();
153     if ((now - lastWatchTime_) > (RESET_RATIO * CHECK_INTERVAL_TIME) ||
154         (now - lastWatchTime_) < (CHECK_INTERVAL_TIME / RESET_RATIO)) {
155         HILOG_INFO("Thread may be blocked, do not report this time. currTime: %{public}llu, lastTime: %{public}llu",
156             static_cast<unsigned long long>(now), static_cast<unsigned long long>(lastWatchTime_));
157         return;
158     }
159 
160     if (isInBackground_ && backgroundReportCount_.load() < BACKGROUND_REPORT_COUNT_MAX) {
161         HILOG_INFO("In Background, thread may be blocked in, do not report this time. "
162             "currTime: %{public}" PRIu64 ", lastTime: %{public}" PRIu64 "",
163             static_cast<uint64_t>(now), static_cast<uint64_t>(lastWatchTime_));
164         backgroundReportCount_++;
165         return;
166     }
167     backgroundReportCount_++;
168 
169     if (!needReport_) {
170         return;
171     }
172 
173     if (isSixSecondEvent_) {
174         needReport_.store(false);
175     }
176     AppExecFwk::AppfreezeInner::GetInstance()->ThreadBlock(isSixSecondEvent_);
177 }
178 }  // namespace AppExecFwk
179 }  // namespace OHOS
180