• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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_task.h"
17 
18 #include <cinttypes>
19 #include <ctime>
20 #include <thread>
21 
22 #include <unistd.h>
23 
24 #include "hisysevent.h"
25 #include "xcollie_utils.h"
26 
27 namespace OHOS {
28 namespace HiviewDFX {
WatchdogTask(std::string name,std::shared_ptr<AppExecFwk::EventHandler> handler,TimeOutCallback timeOutCallback,uint64_t interval)29 WatchdogTask::WatchdogTask(std::string name, std::shared_ptr<AppExecFwk::EventHandler> handler,
30     TimeOutCallback timeOutCallback, uint64_t interval)
31     : name(name), task(nullptr), timeOutCallback(timeOutCallback)
32 {
33     checker = std::make_shared<HandlerChecker>(name, handler);
34     checkInterval = interval;
35     nextTickTime = GetCurrentTickMillseconds();
36     isTaskScheduled = false;
37     isOneshotTask = false;
38 }
39 
WatchdogTask(std::string name,Task && task,uint64_t delay,uint64_t interval,bool isOneshot)40 WatchdogTask::WatchdogTask(std::string name, Task&& task, uint64_t delay, uint64_t interval,  bool isOneshot)
41     : name(name), task(std::move(task)), timeOutCallback(nullptr), checker(nullptr)
42 {
43     checkInterval = interval;
44     nextTickTime = GetCurrentTickMillseconds() + delay;
45     isTaskScheduled = false;
46     isOneshotTask = isOneshot;
47 }
48 
Run(uint64_t now)49 void WatchdogTask::Run(uint64_t now)
50 {
51     constexpr int RESET_RATIO = 2;
52     if ((checkInterval != 0) && (now - nextTickTime > (RESET_RATIO * checkInterval))) {
53         XCOLLIE_LOGI("checker thread may be blocked, reset next tick time."
54             "now:%{public}" PRIu64 " expect:%{public}" PRIu64 " interval:%{public}" PRIu64 "",
55             now, nextTickTime, checkInterval);
56         nextTickTime = now;
57         isTaskScheduled = false;
58         return;
59     }
60 
61     if (task != nullptr) {
62         task();
63     } else {
64         RunHandlerCheckerTask();
65     }
66 }
67 
RunHandlerCheckerTask()68 void WatchdogTask::RunHandlerCheckerTask()
69 {
70     if (checker == nullptr) {
71         return;
72     }
73 
74     if (!isTaskScheduled) {
75         checker->ScheduleCheck();
76         isTaskScheduled = true;
77     } else {
78         if (EvaluateCheckerState() == CheckStatus::COMPLETED) {
79             // allow next check
80             isTaskScheduled = false;
81         }
82     }
83 }
84 
SendEvent(const std::string & msg,const std::string & eventName) const85 void WatchdogTask::SendEvent(const std::string &msg, const std::string &eventName) const
86 {
87     int32_t pid = getpid();
88     int32_t gid = getgid();
89     int32_t uid = getuid();
90     time_t curTime = time(nullptr);
91     std::string sendMsg = std::string((ctime(&curTime) == nullptr) ? "" : ctime(&curTime)) +
92         "\n" + msg + "\n";
93     sendMsg += checker->GetDumpInfo();
94     HiSysEvent::Write("FRAMEWORK", eventName, HiSysEvent::EventType::FAULT,
95         "PID", pid,
96         "TGID", gid,
97         "UID", uid,
98         "MODULE_NAME", name,
99         "PROCESS_NAME", GetSelfProcName(),
100         "MSG", sendMsg);
101     XCOLLIE_LOGI("send event [FRAMEWORK,%{public}s], msg=%{public}s", eventName.c_str(), msg.c_str());
102 }
103 
EvaluateCheckerState()104 int WatchdogTask::EvaluateCheckerState()
105 {
106     int waitState = checker->GetCheckState();
107     if (waitState == CheckStatus::COMPLETED) {
108         return waitState;
109     } else if (waitState == CheckStatus::WAITED_HALF) {
110         XCOLLIE_LOGI("Watchdog half-block happened, send event");
111         std::string description = GetBlockDescription(checkInterval / 1000); // 1s = 1000ms
112         if (timeOutCallback != nullptr) {
113             timeOutCallback(name, waitState);
114         } else {
115             SendEvent(description, "SERVICE_WARNING");
116         }
117     } else {
118         XCOLLIE_LOGI("Watchdog happened, send event twice, and skip exiting process");
119         std::string description = GetBlockDescription(checkInterval / 1000) +
120             ", report twice instead of exiting process."; // 1s = 1000ms
121         if (timeOutCallback != nullptr) {
122             timeOutCallback(name, waitState);
123         } else {
124             SendEvent(description, "SERVICE_BLOCK");
125             std::this_thread::sleep_for(std::chrono::seconds(3)); // after 3s exit
126             _exit(0);
127         }
128     }
129     return waitState;
130 }
131 
GetBlockDescription(uint64_t interval)132 std::string WatchdogTask::GetBlockDescription(uint64_t interval)
133 {
134     std::string desc = "Watchdog: thread(";
135     desc += name;
136     desc += ") blocked " + std::to_string(interval) + "s";
137     return desc;
138 }
139 } // end of namespace HiviewDFX
140 } // end of namespace OHOS
141