1 /*
2  * Copyright (c) 2021-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_inner.h"
17 
18 #include <cerrno>
19 #include <climits>
20 #include <mutex>
21 
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <fcntl.h>
25 #include <pthread.h>
26 #include <unistd.h>
27 #include <csignal>
28 #include <string>
29 
30 #include <securec.h>
31 #include <dlfcn.h>
32 
33 #include "backtrace_local.h"
34 #include "hisysevent.h"
35 #include "ipc_skeleton.h"
36 #include "xcollie_utils.h"
37 #include "xcollie_define.h"
38 #include "dfx_define.h"
39 #include "parameter.h"
40 
41 typedef void(*ThreadInfoCallBack)(char* buf, size_t len, void* ucontext);
42 extern "C" void SetThreadInfoCallback(ThreadInfoCallBack func) __attribute__((weak));
43 namespace OHOS {
44 namespace HiviewDFX {
45 constexpr uint64_t DEFAULT_TIMEOUT = 60 * 1000;
46 constexpr uint32_t FFRT_CALLBACK_TIME = 30 * 1000;
47 constexpr uint32_t IPC_CHECKER_TIME = 30 * 1000;
48 constexpr uint32_t TIME_MS_TO_S = 1000;
49 constexpr int INTERVAL_KICK_TIME = 6 * 1000;
50 constexpr uint32_t DATA_MANAGE_SERVICE_UID = 3012;
51 constexpr uint32_t FOUNDATION_UID = 5523;
52 constexpr uint32_t RENDER_SERVICE_UID = 1003;
53 constexpr int SERVICE_WARNING = 1;
54 constexpr const char* const KEY_SCB_STATE = "com.ohos.sceneboard";
55 const char* SYS_KERNEL_HUNGTASK_USERLIST = "/sys/kernel/hungtask/userlist";
56 const char* HMOS_HUNGTASK_USERLIST = "/proc/sys/hguard/user_list";
57 const std::string ON_KICK_TIME = "on,72";
58 const std::string ON_KICK_TIME_HMOS = "on,10,foundation";
59 const std::string KICK_TIME = "kick";
60 const std::string KICK_TIME_HMOS = "kick,foundation";
61 const int32_t NOT_OPEN = -1;
62 constexpr uint64_t MAX_START_TIME = 10 * 1000;
63 const char* LIB_THREAD_SAMPLER_PATH = "libthread_sampler.z.so";
64 constexpr size_t STACK_LENGTH = 32 * 1024;
65 constexpr uint32_t JOIN_IPC_FULL_UIDS[] = {DATA_MANAGE_SERVICE_UID, FOUNDATION_UID, RENDER_SERVICE_UID};
66 
67 std::mutex WatchdogInner::lockFfrt_;
68 static uint64_t g_nextKickTime = GetCurrentTickMillseconds();
69 static int32_t g_fd = NOT_OPEN;
70 static bool g_existFile = true;
71 
72 SigActionType WatchdogInner::threadSamplerSigHandler_ = nullptr;
73 std::mutex WatchdogInner::threadSamplerSignalMutex_;
74 
75 namespace {
ThreadInfo(char * buf,size_t len,void * ucontext)76 void ThreadInfo(char *buf  __attribute__((unused)),
77                 size_t len  __attribute__((unused)),
78                 void* ucontext  __attribute__((unused)))
79 {
80     if (ucontext == nullptr) {
81         return;
82     }
83 
84     auto ret = memcpy_s(buf, len, WatchdogInner::GetInstance().currentScene_.c_str(),
85         WatchdogInner::GetInstance().currentScene_.size());
86     if (ret != 0) {
87         return;
88     }
89 }
90 
SetThreadSignalMask(int signo,bool isAddSignal,bool isBlock)91 void SetThreadSignalMask(int signo, bool isAddSignal, bool isBlock)
92 {
93     sigset_t set;
94     sigemptyset(&set);
95     pthread_sigmask(SIG_SETMASK, nullptr, &set);
96     if (isAddSignal) {
97         sigaddset(&set, signo);
98     } else {
99         sigdelset(&set, signo);
100     }
101     if (isBlock) {
102         pthread_sigmask(SIG_BLOCK, &set, nullptr);
103     } else {
104         pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
105     }
106 }
107 
108 static const int CRASH_SIGNAL_LIST[] = {
109     SIGILL, SIGABRT, SIGBUS, SIGFPE,
110     SIGSEGV, SIGSTKFLT, SIGSYS, SIGTRAP
111 };
112 }
113 
WatchdogInner()114 WatchdogInner::WatchdogInner()
115     : cntCallback_(0), timeCallback_(0), sampleTaskState_(0)
116 {
117     currentScene_ = "thread DfxWatchdog: Current scenario is hicollie.\n";
118 }
119 
~WatchdogInner()120 WatchdogInner::~WatchdogInner()
121 {
122     Stop();
123 }
124 
IsInAppspwan()125 static bool IsInAppspwan()
126 {
127     if (getuid() == 0 && GetSelfProcName().find("appspawn") != std::string::npos) {
128         return true;
129     }
130 
131     if (getuid() == 0 && GetSelfProcName().find("nativespawn") != std::string::npos) {
132         return true;
133     }
134 
135     return false;
136 }
137 
SetBundleInfo(const std::string & bundleName,const std::string & bundleVersion)138 void WatchdogInner::SetBundleInfo(const std::string& bundleName, const std::string& bundleVersion)
139 {
140     bundleName_ = bundleName;
141     bundleVersion_ = bundleVersion;
142 }
143 
SetForeground(const bool & isForeground)144 void WatchdogInner::SetForeground(const bool& isForeground)
145 {
146     isForeground_ = isForeground;
147 }
148 
ReportMainThreadEvent()149 bool WatchdogInner::ReportMainThreadEvent()
150 {
151     std::string stack = "";
152     CollectStack(stack);
153 
154     std::string path = "";
155     std::string eventName = "MAIN_THREAD_JANK";
156     if (!buissnessThreadInfo_.empty()) {
157         eventName = "BUSSINESS_THREAD_JANK";
158     }
159     if (!WriteStackToFd(getprocpid(), path, stack, eventName)) {
160         XCOLLIE_LOGI("MainThread WriteStackToFd Failed");
161         return false;
162     }
163     int result = HiSysEventWrite(HiSysEvent::Domain::FRAMEWORK, "MAIN_THREAD_JANK",
164         HiSysEvent::EventType::FAULT,
165         "BUNDLE_VERSION", bundleVersion_,
166         "BUNDLE_NAME", bundleName_,
167         "BEGIN_TIME", timeContent_.reportBegin / MILLISEC_TO_NANOSEC,
168         "END_TIME", timeContent_.reportEnd / MILLISEC_TO_NANOSEC,
169         "EXTERNAL_LOG", path,
170         "STACK", stack,
171         "JANK_LEVEL", 0,
172         "THREAD_NAME", GetSelfProcName(),
173         "FOREGROUND", isForeground_,
174         "LOG_TIME", GetTimeStamp() / MILLISEC_TO_NANOSEC);
175     XCOLLIE_LOGI("MainThread HiSysEventWrite result=%{public}d", result);
176     return result >= 0;
177 }
178 
CheckEventTimer(const int64_t & currentTime)179 bool WatchdogInner::CheckEventTimer(const int64_t& currentTime)
180 {
181     if (timeContent_.reportBegin == timeContent_.curBegin &&
182         timeContent_.reportEnd == timeContent_.curEnd) {
183         return false;
184     }
185     return (timeContent_.curEnd <= timeContent_.curBegin &&
186         (currentTime - timeContent_.curBegin >= DURATION_TIME * MILLISEC_TO_NANOSEC)) ||
187         (timeContent_.curEnd - timeContent_.curBegin > DURATION_TIME * MILLISEC_TO_NANOSEC);
188 }
189 
ThreadSamplerSigHandler(int sig,siginfo_t * si,void * context)190 void WatchdogInner::ThreadSamplerSigHandler(int sig, siginfo_t* si, void* context)
191 {
192     std::lock_guard<std::mutex> lock(threadSamplerSignalMutex_);
193     if (WatchdogInner::threadSamplerSigHandler_ == nullptr) {
194         return;
195     }
196     WatchdogInner::threadSamplerSigHandler_(sig, si, context);
197 }
198 
InstallThreadSamplerSignal()199 bool WatchdogInner::InstallThreadSamplerSignal()
200 {
201     struct sigaction action {};
202     sigfillset(&action.sa_mask);
203     for (size_t i = 0; i < sizeof(CRASH_SIGNAL_LIST) / sizeof(CRASH_SIGNAL_LIST[0]); i++) {
204         sigdelset(&action.sa_mask, CRASH_SIGNAL_LIST[i]);
205     }
206     action.sa_sigaction = WatchdogInner::ThreadSamplerSigHandler;
207     action.sa_flags = SA_RESTART | SA_SIGINFO;
208     if (sigaction(MUSL_SIGNAL_SAMPLE_STACK, &action, nullptr) != 0) {
209         XCOLLIE_LOGE("Failed to register signal(%{public}d:%{public}d)", MUSL_SIGNAL_SAMPLE_STACK, errno);
210         return false;
211     }
212     return true;
213 }
214 
UninstallThreadSamplerSignal()215 void WatchdogInner::UninstallThreadSamplerSignal()
216 {
217     std::lock_guard<std::mutex> lock(threadSamplerSignalMutex_);
218     threadSamplerSigHandler_ = nullptr;
219 }
220 
ThreadSampleTask()221 void WatchdogInner::ThreadSampleTask()
222 {
223     if (sampleTaskState_ == DumpStackState::DEFAULT) {
224         sampleTaskState_++;
225 
226         if (!InitThreadSamplerFuncs()) {
227             isMainThreadProfileTaskEnabled_ = true;
228             return;
229         }
230 
231         if (!InstallThreadSamplerSignal()) {
232             isMainThreadProfileTaskEnabled_ = true;
233             XCOLLIE_LOGE("ThreadSampler install signal failed.\n");
234             return;
235         }
236 
237         int initThreadSamplerRet = threadSamplerInitFunc_(COLLECT_STACK_COUNT);
238         if (initThreadSamplerRet != 0) {
239             isMainThreadProfileTaskEnabled_ = true;
240             XCOLLIE_LOGE("Thread sampler init failed. ret %{public}d\n", initThreadSamplerRet);
241             return;
242         }
243         XCOLLIE_LOGI("Thread sampler initialized. ret %{public}d\n", initThreadSamplerRet);
244     }
245     if (threadSamplerSampleFunc_ == nullptr) {
246         isMainThreadProfileTaskEnabled_ = true;
247         return;
248     }
249     int64_t currentTime = GetTimeStamp();
250     if (stackContent_.collectCount > DumpStackState::DEFAULT && stackContent_.collectCount < COLLECT_STACK_COUNT) {
251         XCOLLIE_LOGI("ThreadSampler in ThreadSamplerTask, %{public}d.\n", stackContent_.collectCount);
252         threadSamplerSampleFunc_();
253         stackContent_.collectCount++;
254     } else if (stackContent_.collectCount == COLLECT_STACK_COUNT) {
255         XCOLLIE_LOGI("ThreadSampler complete ThreadSamplerTask.\n");
256         ReportMainThreadEvent();
257         isMainThreadProfileTaskEnabled_ = true;
258         return;
259     } else {
260         if (CheckEventTimer(currentTime)) {
261             XCOLLIE_LOGI("ThreadSampler in ThreadSamplerTask, %{public}d.\n", stackContent_.collectCount);
262             threadSamplerSampleFunc_();
263             stackContent_.collectCount++;
264         } else {
265             stackContent_.detectorCount++;
266         }
267     }
268     if (stackContent_.detectorCount == DETECT_STACK_COUNT) {
269         isMainThreadProfileTaskEnabled_ = true;
270     }
271 }
272 
InitThreadSamplerFuncs()273 bool WatchdogInner::InitThreadSamplerFuncs()
274 {
275     threadSamplerFuncHandler_ = dlopen(LIB_THREAD_SAMPLER_PATH, RTLD_LAZY);
276     if (threadSamplerFuncHandler_ == nullptr) {
277         XCOLLIE_LOGE("dlopen failed, funcHandler is nullptr.\n");
278         return false;
279     }
280 
281     threadSamplerInitFunc_ =
282         reinterpret_cast<ThreadSamplerInitFunc>(FunctionOpen(threadSamplerFuncHandler_, "ThreadSamplerInit"));
283     threadSamplerSampleFunc_ =
284         reinterpret_cast<ThreadSamplerSampleFunc>(FunctionOpen(threadSamplerFuncHandler_, "ThreadSamplerSample"));
285     threadSamplerCollectFunc_ =
286         reinterpret_cast<ThreadSamplerCollectFunc>(FunctionOpen(threadSamplerFuncHandler_, "ThreadSamplerCollect"));
287     threadSamplerDeinitFunc_ =
288         reinterpret_cast<ThreadSamplerDeinitFunc>(FunctionOpen(threadSamplerFuncHandler_, "ThreadSamplerDeinit"));
289     threadSamplerSigHandler_ =
290         reinterpret_cast<SigActionType>(FunctionOpen(threadSamplerFuncHandler_, "ThreadSamplerSigHandler"));
291     if (threadSamplerInitFunc_ == nullptr || threadSamplerSampleFunc_ == nullptr ||
292         threadSamplerCollectFunc_ == nullptr || threadSamplerDeinitFunc_ == nullptr ||
293         threadSamplerSigHandler_ == nullptr) {
294         ResetThreadSamplerFuncs();
295         XCOLLIE_LOGE("ThreadSampler dlsym some function failed.\n");
296         return false;
297     }
298     XCOLLIE_LOGE("ThreadSampler has been successfully loaded.\n");
299     return true;
300 }
301 
ResetThreadSamplerFuncs()302 void WatchdogInner::ResetThreadSamplerFuncs()
303 {
304     threadSamplerInitFunc_ = nullptr;
305     threadSamplerSampleFunc_ = nullptr;
306     threadSamplerCollectFunc_ = nullptr;
307     threadSamplerDeinitFunc_ = nullptr;
308     threadSamplerSigHandler_ = nullptr;
309     dlclose(threadSamplerFuncHandler_);
310     threadSamplerFuncHandler_ = nullptr;
311 }
312 
StartProfileMainThread(int32_t interval)313 int32_t WatchdogInner::StartProfileMainThread(int32_t interval)
314 {
315     std::unique_lock<std::mutex> lock(lock_);
316 
317     uint64_t now = GetCurrentTickMillseconds();
318     if (now - watchdogStartTime_ < MAX_START_TIME) {
319         XCOLLIE_LOGI("application is in starting period.\n");
320         stackContent_.stackState = DumpStackState::DEFAULT;
321         return -1;
322     }
323 
324     sampleTaskState_ = 0;
325     stackContent_.detectorCount = 0;
326     stackContent_.collectCount = 0;
327     auto sampleTask = [this]() {
328         ThreadSampleTask();
329     };
330 
331     WatchdogTask task("ThreadSampler", sampleTask, 0, interval, true);
332     InsertWatchdogTaskLocked("ThreadSampler", std::move(task));
333     return 0;
334 }
335 
CollectStack(std::string & stack)336 bool WatchdogInner::CollectStack(std::string& stack)
337 {
338     if (threadSamplerCollectFunc_ == nullptr) {
339         return false;
340     }
341     int treeFormat = 1;
342     char* stk = new char[STACK_LENGTH];
343     int collectRet = threadSamplerCollectFunc_(stk, STACK_LENGTH, treeFormat);
344     stack = stk;
345     delete[] stk;
346     return collectRet == 0;
347 }
348 
Deinit()349 bool WatchdogInner::Deinit()
350 {
351     if (threadSamplerDeinitFunc_ == nullptr) {
352         return false;
353     }
354     UninstallThreadSamplerSignal();
355     int ret = threadSamplerDeinitFunc_();
356     return ret == 0;
357 }
358 
ChangeState(int & state,int targetState)359 void WatchdogInner::ChangeState(int& state, int targetState)
360 {
361     timeContent_.reportBegin = timeContent_.curBegin;
362     timeContent_.reportEnd = timeContent_.curEnd;
363     state = targetState;
364 }
365 
DayChecker(int & state,TimePoint currenTime,TimePoint lastEndTime,int64_t checkTimer)366 void WatchdogInner::DayChecker(int& state, TimePoint currenTime, TimePoint lastEndTime,
367     int64_t checkTimer)
368 {
369     auto diff = currenTime - lastEndTime;
370     int64_t intervalTime = std::chrono::duration_cast<std::chrono::milliseconds>
371         (diff).count();
372     if (intervalTime >= checkTimer) {
373         XCOLLIE_LOGD("MainThread StartProfileMainThread Over checkTimer: "
374             "%{public}" PRId64 " ms", checkTimer);
375         state = DumpStackState::DEFAULT;
376     }
377 }
378 
StartTraceProfile(int32_t interval)379 void WatchdogInner::StartTraceProfile(int32_t interval)
380 {
381     if (traceCollector_ == nullptr) {
382         XCOLLIE_LOGI("MainThread TraceCollector Failed.");
383         return;
384     }
385     traceContent_.dumpCount = 0;
386     traceContent_.traceCount = 0;
387     auto traceTask = [this]() {
388         traceContent_.traceCount++;
389         int64_t currentTime = GetTimeStamp();
390         if (CheckEventTimer(currentTime)) {
391             traceContent_.dumpCount++;
392         }
393         if (traceContent_.traceCount >= COLLECT_TRACE_MAX) {
394             if (traceContent_.dumpCount >= COLLECT_TRACE_MIN) {
395                 CreateWatchdogDir();
396                 appCaller_.actionId = UCollectClient::ACTION_ID_DUMP_TRACE;
397                 appCaller_.isBusinessJank = !buissnessThreadInfo_.empty();
398                 auto result = traceCollector_->CaptureDurationTrace(appCaller_);
399                 XCOLLIE_LOGI("MainThread TraceCollector Dump result: %{public}d", result.retCode);
400             }
401             isMainThreadTraceEnabled_ = true;
402         }
403     };
404     WatchdogTask task("TraceCollector", traceTask, 0, interval, true);
405     std::unique_lock<std::mutex> lock(lock_);
406     InsertWatchdogTaskLocked("TraceCollector", std::move(task));
407 }
408 
CollectTrace()409 void WatchdogInner::CollectTrace()
410 {
411     traceCollector_ = UCollectClient::TraceCollector::Create();
412     int32_t pid = getprocpid();
413     int32_t uid = static_cast<int64_t>(getuid());
414     appCaller_.actionId = UCollectClient::ACTION_ID_START_TRACE;
415     appCaller_.bundleName = bundleName_;
416     appCaller_.bundleVersion = bundleVersion_;
417     appCaller_.uid = uid;
418     appCaller_.pid = pid;
419     appCaller_.threadName = GetSelfProcName();
420     appCaller_.foreground = isForeground_;
421     appCaller_.happenTime = GetTimeStamp() / MILLISEC_TO_NANOSEC;
422     appCaller_.beginTime = timeContent_.reportBegin / MILLISEC_TO_NANOSEC;
423     appCaller_.endTime = timeContent_.reportEnd / MILLISEC_TO_NANOSEC;
424     auto result = traceCollector_->CaptureDurationTrace(appCaller_);
425     XCOLLIE_LOGI("MainThread TraceCollector Start result: %{public}d", result.retCode);
426     if (result.retCode != 0) {
427         return;
428     }
429     StartTraceProfile(DURATION_TIME);
430 }
431 
DistributeStart(const std::string & name)432 static TimePoint DistributeStart(const std::string& name)
433 {
434     WatchdogInner::GetInstance().timeContent_.curBegin = GetTimeStamp();
435     return std::chrono::steady_clock::now();
436 }
437 
DistributeEnd(const std::string & name,const TimePoint & startTime)438 static void DistributeEnd(const std::string& name, const TimePoint& startTime)
439 {
440     TimePoint endTime = std::chrono::steady_clock::now();
441     auto duration = endTime - startTime;
442     int64_t durationTime = std::chrono::duration_cast<std::chrono::milliseconds>
443         (duration).count();
444     if (duration > std::chrono::milliseconds(DISTRIBUTE_TIME)) {
445         XCOLLIE_LOGI("BlockMonitor event name: %{public}s, Duration Time: %{public}" PRId64 " ms",
446             name.c_str(), durationTime);
447     }
448     WatchdogInner::GetInstance().timeContent_.curEnd = GetTimeStamp();
449     if (WatchdogInner::GetInstance().stackContent_.stackState == DumpStackState::COMPLETE) {
450         int64_t checkTimer = ONE_DAY_LIMIT;
451         if (IsDeveloperOpen() || (IsBetaVersion() &&
452             GetProcessNameFromProcCmdline(getpid()) == KEY_SCB_STATE)) {
453             checkTimer = ONE_HOUR_LIMIT;
454         }
455         WatchdogInner::GetInstance().DayChecker(WatchdogInner::GetInstance().stackContent_.stackState,
456             endTime, WatchdogInner::GetInstance().lastStackTime_, checkTimer);
457     }
458     if (WatchdogInner::GetInstance().traceContent_.traceState == DumpStackState::COMPLETE) {
459         WatchdogInner::GetInstance().DayChecker(WatchdogInner::GetInstance().traceContent_.traceState,
460             endTime, WatchdogInner::GetInstance().lastTraceTime_, ONE_DAY_LIMIT);
461     }
462     if (duration > std::chrono::milliseconds(DURATION_TIME) && duration < std::chrono::milliseconds(DUMPTRACE_TIME) &&
463         WatchdogInner::GetInstance().stackContent_.stackState == DumpStackState::DEFAULT) {
464         WatchdogInner::GetInstance().ChangeState(WatchdogInner::GetInstance().stackContent_.stackState,
465             DumpStackState::COMPLETE);
466         WatchdogInner::GetInstance().lastStackTime_ = endTime;
467 
468         int32_t ret = WatchdogInner::GetInstance().StartProfileMainThread(TASK_INTERVAL);
469         XCOLLIE_LOGI("MainThread StartProfileMainThread ret: %{public}d  "
470             "Duration Time: %{public}" PRId64 " ms", ret, durationTime);
471     }
472     if (duration > std::chrono::milliseconds(DUMPTRACE_TIME) &&
473         WatchdogInner::GetInstance().traceContent_.traceState == DumpStackState::DEFAULT) {
474         if (IsBetaVersion()) {
475             return;
476         }
477         XCOLLIE_LOGI("MainThread TraceCollector Duration Time: %{public}" PRId64 " ms", durationTime);
478         WatchdogInner::GetInstance().ChangeState(WatchdogInner::GetInstance().traceContent_.traceState,
479             DumpStackState::COMPLETE);
480         WatchdogInner::GetInstance().lastTraceTime_ = endTime;
481         WatchdogInner::GetInstance().CollectTrace();
482     }
483 }
484 
AddThread(const std::string & name,std::shared_ptr<AppExecFwk::EventHandler> handler,TimeOutCallback timeOutCallback,uint64_t interval)485 int WatchdogInner::AddThread(const std::string &name,
486     std::shared_ptr<AppExecFwk::EventHandler> handler, TimeOutCallback timeOutCallback, uint64_t interval)
487 {
488     if (name.empty() || handler == nullptr) {
489         XCOLLIE_LOGE("Add thread fail, invalid args!");
490         return -1;
491     }
492 
493     if (IsInAppspwan()) {
494         return -1;
495     }
496 
497     std::string limitedName = GetLimitedSizeName(name);
498     XCOLLIE_LOGI("Add thread %{public}s to watchdog.", limitedName.c_str());
499     std::unique_lock<std::mutex> lock(lock_);
500 
501     IpcCheck();
502 
503     if (!InsertWatchdogTaskLocked(limitedName, WatchdogTask(limitedName, handler, timeOutCallback, interval))) {
504         return -1;
505     }
506     return 0;
507 }
508 
RunOneShotTask(const std::string & name,Task && task,uint64_t delay)509 void WatchdogInner::RunOneShotTask(const std::string& name, Task&& task, uint64_t delay)
510 {
511     if (name.empty() || task == nullptr) {
512         XCOLLIE_LOGE("Add task fail, invalid args!");
513         return;
514     }
515 
516     if (IsInAppspwan()) {
517         return;
518     }
519 
520     std::unique_lock<std::mutex> lock(lock_);
521     std::string limitedName = GetLimitedSizeName(name);
522     InsertWatchdogTaskLocked(limitedName, WatchdogTask(limitedName, std::move(task), delay, 0, true));
523 }
524 
RunXCollieTask(const std::string & name,uint64_t timeout,XCollieCallback func,void * arg,unsigned int flag)525 int64_t WatchdogInner::RunXCollieTask(const std::string& name, uint64_t timeout, XCollieCallback func,
526     void *arg, unsigned int flag)
527 {
528     if (name.empty() || timeout == 0) {
529         XCOLLIE_LOGE("Add XCollieTask fail, invalid args!");
530         return INVALID_ID;
531     }
532 
533     if (IsInAppspwan()) {
534         return INVALID_ID;
535     }
536 
537     std::unique_lock<std::mutex> lock(lock_);
538     IpcCheck();
539     std::string limitedName = GetLimitedSizeName(name);
540     return InsertWatchdogTaskLocked(limitedName, WatchdogTask(limitedName, timeout, func, arg, flag));
541 }
542 
RemoveXCollieTask(int64_t id)543 void WatchdogInner::RemoveXCollieTask(int64_t id)
544 {
545     std::priority_queue<WatchdogTask> tmpQueue;
546     std::unique_lock<std::mutex> lock(lock_);
547     size_t size = checkerQueue_.size();
548     if (size == 0) {
549         XCOLLIE_LOGE("Remove XCollieTask %{public}lld fail, empty queue!", static_cast<long long>(id));
550         return;
551     }
552     while (!checkerQueue_.empty()) {
553         const WatchdogTask& task = checkerQueue_.top();
554         if (task.id != id || task.timeout == 0) {
555             tmpQueue.push(task);
556         }
557         checkerQueue_.pop();
558     }
559     if (tmpQueue.size() == size) {
560         XCOLLIE_LOGE("Remove XCollieTask fail, can not find timer %{public}lld, size=%{public}zu!",
561             static_cast<long long>(id), size);
562     }
563     tmpQueue.swap(checkerQueue_);
564 }
565 
RunPeriodicalTask(const std::string & name,Task && task,uint64_t interval,uint64_t delay)566 void WatchdogInner::RunPeriodicalTask(const std::string& name, Task&& task, uint64_t interval, uint64_t delay)
567 {
568     if (name.empty() || task == nullptr) {
569         XCOLLIE_LOGE("Add task fail, invalid args!");
570         return;
571     }
572 
573     if (IsInAppspwan()) {
574         return;
575     }
576 
577     std::string limitedName = GetLimitedSizeName(name);
578     XCOLLIE_LOGD("Add periodical task %{public}s to watchdog.", name.c_str());
579     std::unique_lock<std::mutex> lock(lock_);
580     InsertWatchdogTaskLocked(limitedName, WatchdogTask(limitedName, std::move(task), delay, interval, false));
581 }
582 
SetTimerCountTask(const std::string & name,uint64_t timeLimit,int countLimit)583 int64_t WatchdogInner::SetTimerCountTask(const std::string &name, uint64_t timeLimit, int countLimit)
584 {
585     if (name.empty() || timeLimit == 0 || countLimit <= 0) {
586         XCOLLIE_LOGE("SetTimerCountTask fail, invalid args!");
587         return INVALID_ID;
588     }
589 
590     if (IsInAppspwan()) {
591         return INVALID_ID;
592     }
593     std::string limitedName = GetLimitedSizeName(name);
594     XCOLLIE_LOGD("SetTimerCountTask name : %{public}s", name.c_str());
595     std::unique_lock<std::mutex> lock(lock_);
596     return InsertWatchdogTaskLocked(limitedName, WatchdogTask(limitedName, timeLimit, countLimit));
597 }
598 
TriggerTimerCountTask(const std::string & name,bool bTrigger,const std::string & message)599 void WatchdogInner::TriggerTimerCountTask(const std::string &name, bool bTrigger, const std::string &message)
600 {
601     std::unique_lock<std::mutex> lock(lock_);
602 
603     if (checkerQueue_.empty()) {
604         XCOLLIE_LOGE("TriggerTimerCountTask name : %{public}s fail, empty queue!", name.c_str());
605         return;
606     }
607 
608     bool isTaskExist = false;
609     uint64_t now = GetCurrentTickMillseconds();
610     std::priority_queue<WatchdogTask> tmpQueue;
611     while (!checkerQueue_.empty()) {
612         WatchdogTask task = checkerQueue_.top();
613         if (task.name == name) {
614             isTaskExist = true;
615             if (bTrigger) {
616                 task.triggerTimes.push_back(now);
617                 task.message = message;
618             } else {
619                 task.triggerTimes.clear();
620             }
621         }
622         tmpQueue.push(task);
623         checkerQueue_.pop();
624     }
625     tmpQueue.swap(checkerQueue_);
626 
627     if (!isTaskExist) {
628         XCOLLIE_LOGE("TriggerTimerCount name : %{public}s does not exist!", name.c_str());
629     }
630 }
631 
IsTaskExistLocked(const std::string & name)632 bool WatchdogInner::IsTaskExistLocked(const std::string& name)
633 {
634     return (taskNameSet_.find(name) != taskNameSet_.end());
635 }
636 
IsExceedMaxTaskLocked()637 bool WatchdogInner::IsExceedMaxTaskLocked()
638 {
639     if (checkerQueue_.size() >= MAX_WATCH_NUM) {
640         XCOLLIE_LOGE("Exceed max watchdog task!");
641         return true;
642     }
643 
644     return false;
645 }
646 
InsertWatchdogTaskLocked(const std::string & name,WatchdogTask && task)647 int64_t WatchdogInner::InsertWatchdogTaskLocked(const std::string& name, WatchdogTask&& task)
648 {
649     if (!task.isOneshotTask && IsTaskExistLocked(name)) {
650         XCOLLIE_LOGI("Task with %{public}s already exist, failed to insert.", name.c_str());
651         return 0;
652     }
653 
654     if (IsExceedMaxTaskLocked()) {
655         XCOLLIE_LOGE("Exceed max watchdog task, failed to insert.");
656         return 0;
657     }
658     int64_t id = task.id;
659     checkerQueue_.push(std::move(task));
660     if (!task.isOneshotTask) {
661         taskNameSet_.insert(name);
662     }
663     CreateWatchdogThreadIfNeed();
664     condition_.notify_all();
665 
666     return id;
667 }
668 
StopWatchdog()669 void WatchdogInner::StopWatchdog()
670 {
671     Stop();
672 }
673 
IsCallbackLimit(unsigned int flag)674 bool WatchdogInner::IsCallbackLimit(unsigned int flag)
675 {
676     bool ret = false;
677     time_t startTime = time(nullptr);
678     if (!(flag & XCOLLIE_FLAG_LOG)) {
679         return ret;
680     }
681     if (timeCallback_ + XCOLLIE_CALLBACK_TIMEWIN_MAX < startTime) {
682         timeCallback_ = startTime;
683     } else {
684         if (++cntCallback_ > XCOLLIE_CALLBACK_HISTORY_MAX) {
685             ret = true;
686         }
687     }
688     return ret;
689 }
690 
IPCProxyLimitCallback(uint64_t num)691 void IPCProxyLimitCallback(uint64_t num)
692 {
693     XCOLLIE_LOGE("ipc proxy num %{public}" PRIu64 " exceed limit", num);
694     if (getuid() >= MIN_APP_UID && IsBetaVersion()) {
695         XCOLLIE_LOGI("Process is going to exit, reason: ipc proxy num exceed limit");
696         _exit(0);
697     }
698 }
699 
CreateWatchdogThreadIfNeed()700 void WatchdogInner::CreateWatchdogThreadIfNeed()
701 {
702     std::call_once(flag_, [this] {
703         if (threadLoop_ == nullptr) {
704             if (mainRunner_ == nullptr) {
705                 mainRunner_ = AppExecFwk::EventRunner::GetMainEventRunner();
706             }
707             mainRunner_->SetMainLooperWatcher(DistributeStart, DistributeEnd);
708             const uint64_t limitNum = 20000;
709             IPCDfx::SetIPCProxyLimit(limitNum, IPCProxyLimitCallback);
710             threadLoop_ = std::make_unique<std::thread>(&WatchdogInner::Start, this);
711             if (getpid() == gettid()) {
712                 SetThreadSignalMask(SIGDUMP, true, true);
713             }
714             XCOLLIE_LOGD("Watchdog is running!");
715         }
716     });
717 }
718 
FetchNextTask(uint64_t now,WatchdogTask & task)719 uint64_t WatchdogInner::FetchNextTask(uint64_t now, WatchdogTask& task)
720 {
721     std::unique_lock<std::mutex> lock(lock_);
722     if (isNeedStop_) {
723         while (!checkerQueue_.empty()) {
724             checkerQueue_.pop();
725         }
726         return DEFAULT_TIMEOUT;
727     }
728 
729     if (checkerQueue_.empty()) {
730         return DEFAULT_TIMEOUT;
731     }
732 
733     const WatchdogTask& queuedTaskCheck = checkerQueue_.top();
734     bool popCheck = true;
735     if (queuedTaskCheck.name.empty()) {
736         checkerQueue_.pop();
737         XCOLLIE_LOGW("queuedTask name is empty.");
738     } else if (queuedTaskCheck.name == STACK_CHECKER && isMainThreadProfileTaskEnabled_) {
739         checkerQueue_.pop();
740         taskNameSet_.erase("ThreadSampler");
741         isMainThreadProfileTaskEnabled_ = false;
742         if (Deinit()) {
743             ResetThreadSamplerFuncs();
744         }
745         XCOLLIE_LOGI("STACK_CHECKER Task pop");
746     } else if (queuedTaskCheck.name == TRACE_CHECKER && isMainThreadTraceEnabled_) {
747         checkerQueue_.pop();
748         taskNameSet_.erase("TraceCollector");
749         isMainThreadTraceEnabled_ = false;
750         XCOLLIE_LOGI("TRACE_CHECKER Task pop");
751     } else {
752         popCheck = false;
753     }
754     if (popCheck && checkerQueue_.empty()) {
755         return DEFAULT_TIMEOUT;
756     }
757 
758     const WatchdogTask& queuedTask = checkerQueue_.top();
759     if (g_existFile && queuedTask.name == IPC_FULL && now - g_nextKickTime > INTERVAL_KICK_TIME) {
760         if (KickWatchdog()) {
761             g_nextKickTime = now;
762         }
763     }
764     if (queuedTask.nextTickTime > now) {
765         return queuedTask.nextTickTime - now;
766     }
767 
768     currentScene_ = "thread DfxWatchdog: Current scenario is task name: " + queuedTask.name + "\n";
769     task = queuedTask;
770     checkerQueue_.pop();
771     return 0;
772 }
773 
ReInsertTaskIfNeed(WatchdogTask & task)774 void WatchdogInner::ReInsertTaskIfNeed(WatchdogTask& task)
775 {
776     if (task.checkInterval == 0) {
777         return;
778     }
779 
780     std::unique_lock<std::mutex> lock(lock_);
781     task.nextTickTime = task.nextTickTime + task.checkInterval;
782     checkerQueue_.push(task);
783 }
784 
Start()785 bool WatchdogInner::Start()
786 {
787     if (pthread_setname_np(pthread_self(), "OS_DfxWatchdog") != 0) {
788         XCOLLIE_LOGW("Failed to set threadName for watchdog, errno:%d.", errno);
789     }
790     SetThreadSignalMask(SIGDUMP, false, false);
791     watchdogStartTime_ = GetCurrentTickMillseconds();
792     XCOLLIE_LOGD("Watchdog is running in thread(%{public}d)!", getproctid());
793     if (SetThreadInfoCallback != nullptr) {
794         SetThreadInfoCallback(ThreadInfo);
795         XCOLLIE_LOGD("Watchdog Set Thread Info Callback");
796     }
797     while (!isNeedStop_) {
798         uint64_t now = GetCurrentTickMillseconds();
799         WatchdogTask task;
800         uint64_t leftTimeMill = FetchNextTask(now, task);
801         if (leftTimeMill == 0) {
802             task.Run(now);
803             ReInsertTaskIfNeed(task);
804             currentScene_ = "thread DfxWatchdog: Current scenario is hicollie.\n";
805             continue;
806         } else if (isNeedStop_) {
807             break;
808         } else {
809             std::unique_lock<std::mutex> lock(lock_);
810             condition_.wait_for(lock, std::chrono::milliseconds(leftTimeMill));
811         }
812     }
813     if (SetThreadInfoCallback != nullptr) {
814         SetThreadInfoCallback(nullptr);
815     }
816     return true;
817 }
818 
SendMsgToHungtask(const std::string & msg)819 bool WatchdogInner::SendMsgToHungtask(const std::string& msg)
820 {
821     if (g_fd == NOT_OPEN) {
822         return false;
823     }
824 
825     ssize_t watchdogWrite = write(g_fd, msg.c_str(), msg.size());
826     if (watchdogWrite < 0 || watchdogWrite != static_cast<ssize_t>(msg.size())) {
827         XCOLLIE_LOGE("watchdogWrite msg failed");
828         close(g_fd);
829         g_fd = NOT_OPEN;
830         return false;
831     }
832     XCOLLIE_LOGE("Send %{public}s to hungtask Successful\n", msg.c_str());
833     return true;
834 }
835 
KickWatchdog()836 bool WatchdogInner::KickWatchdog()
837 {
838     if (g_fd == NOT_OPEN) {
839         g_fd = open(SYS_KERNEL_HUNGTASK_USERLIST, O_WRONLY);
840         if (g_fd < 0) {
841             g_fd = open(HMOS_HUNGTASK_USERLIST, O_WRONLY);
842             if (g_fd < 0) {
843                 XCOLLIE_LOGE("can't open hungtask file");
844                 g_existFile = false;
845                 return false;
846             }
847             XCOLLIE_LOGE("change to hmos kernel");
848             isHmos = true;
849         } else {
850             XCOLLIE_LOGE("change to linux kernel");
851         }
852 
853         if (!SendMsgToHungtask(isHmos ? ON_KICK_TIME_HMOS : ON_KICK_TIME)) {
854             XCOLLIE_LOGE("KickWatchdog SendMsgToHungtask false");
855             return false;
856         }
857     }
858     return SendMsgToHungtask(isHmos ? KICK_TIME_HMOS : KICK_TIME);
859 }
860 
IpcCheck()861 void WatchdogInner::IpcCheck()
862 {
863     static bool isIpcCheckInit = false;
864     if (isIpcCheckInit) {
865         return;
866     }
867 
868     uint32_t uid = getuid();
869     bool isJoinIpcFullUid = std::any_of(std::begin(JOIN_IPC_FULL_UIDS), std::end(JOIN_IPC_FULL_UIDS),
870         [uid](const uint32_t joinIpcFullUid) { return uid == joinIpcFullUid; });
871     if (isJoinIpcFullUid || GetSelfProcName() == KEY_SCB_STATE) {
872         if (binderCheckHander_ == nullptr) {
873             auto runner = AppExecFwk::EventRunner::Create(IPC_CHECKER);
874             binderCheckHander_ = std::make_shared<AppExecFwk::EventHandler>(runner);
875             if (!InsertWatchdogTaskLocked(IPC_CHECKER, WatchdogTask(IPC_FULL, binderCheckHander_,
876                 nullptr, IPC_CHECKER_TIME))) {
877                 XCOLLIE_LOGE("Add %{public}s thread fail", IPC_CHECKER);
878             }
879         }
880     }
881     isIpcCheckInit = true;
882 }
883 
WriteStringToFile(int32_t pid,const char * str)884 void WatchdogInner::WriteStringToFile(int32_t pid, const char *str)
885 {
886     char file[PATH_LEN] = {0};
887     if (snprintf_s(file, PATH_LEN, PATH_LEN - 1, "/proc/%d/unexpected_die_catch", pid) == -1) {
888         XCOLLIE_LOGE("failed to build path for %{public}d.", pid);
889         return;
890     }
891     int fd = open(file, O_RDWR);
892     if (fd == -1) {
893         return;
894     }
895     if (write(fd, str, strlen(str)) < 0) {
896         XCOLLIE_LOGI("failed to write 0 for %{public}s", file);
897     }
898     close(fd);
899     return;
900 }
901 
FfrtCallback(uint64_t taskId,const char * taskInfo,uint32_t delayedTaskCount)902 void WatchdogInner::FfrtCallback(uint64_t taskId, const char *taskInfo, uint32_t delayedTaskCount)
903 {
904     std::string description = "FfrtCallback: task(";
905     description += taskInfo;
906     description += ") blocked " + std::to_string(FFRT_CALLBACK_TIME / TIME_MS_TO_S) + "s";
907     std::string info(taskInfo);
908     if (info.find("Queue_Schedule_Timeout") != std::string::npos) {
909         WatchdogInner::SendFfrtEvent(description, "SERVICE_WARNING", taskInfo, false);
910         description += ", report twice instead of exiting process.";
911         WatchdogInner::SendFfrtEvent(description, "SERVICE_BLOCK", taskInfo);
912         WatchdogInner::KillPeerBinderProcess(description);
913         return;
914     }
915     bool isExist = false;
916     {
917         std::unique_lock<std::mutex> lock(lockFfrt_);
918         auto &map = WatchdogInner::GetInstance().taskIdCnt;
919         auto search = map.find(taskId);
920         if (search != map.end()) {
921             isExist = true;
922         } else {
923             map[taskId] = SERVICE_WARNING;
924         }
925     }
926 
927     if (isExist) {
928         description += ", report twice instead of exiting process."; // 1s = 1000ms
929         WatchdogInner::SendFfrtEvent(description, "SERVICE_BLOCK", taskInfo);
930         WatchdogInner::GetInstance().taskIdCnt.erase(taskId);
931         WatchdogInner::KillPeerBinderProcess(description);
932     } else {
933         WatchdogInner::SendFfrtEvent(description, "SERVICE_WARNING", taskInfo);
934     }
935 }
936 
InitFfrtWatchdog()937 void WatchdogInner::InitFfrtWatchdog()
938 {
939     CreateWatchdogThreadIfNeed();
940     ffrt_task_timeout_set_cb(FfrtCallback);
941     ffrt_task_timeout_set_threshold(FFRT_CALLBACK_TIME);
942     std::unique_lock<std::mutex> lock(lock_);
943     IpcCheck();
944 }
945 
SendFfrtEvent(const std::string & msg,const std::string & eventName,const char * taskInfo,const bool isDumpStack)946 void WatchdogInner::SendFfrtEvent(const std::string &msg, const std::string &eventName, const char * taskInfo,
947     const bool isDumpStack)
948 {
949     int32_t pid = getprocpid();
950     if (IsProcessDebug(pid)) {
951         XCOLLIE_LOGI("heap dump or debug for %{public}d, don't report.", pid);
952         return;
953     }
954     uint32_t gid = getgid();
955     uint32_t uid = getuid();
956     time_t curTime = time(nullptr);
957     std::string sendMsg = std::string((ctime(&curTime) == nullptr) ? "" : ctime(&curTime)) +
958         "\n" + msg + "\n";
959     char* buffer = new char[FFRT_BUFFER_SIZE + 1]();
960     buffer[FFRT_BUFFER_SIZE] = 0;
961     ffrt_dump(DUMP_INFO_ALL, buffer, FFRT_BUFFER_SIZE);
962     sendMsg += buffer;
963     delete[] buffer;
964     int32_t tid = pid;
965     GetFfrtTaskTid(tid, sendMsg);
966     int ret = HiSysEventWrite(HiSysEvent::Domain::FRAMEWORK, eventName, HiSysEvent::EventType::FAULT,
967         "PID", pid, "TID", tid, "TGID", gid, "UID", uid, "MODULE_NAME", taskInfo, "PROCESS_NAME", GetSelfProcName(),
968         "MSG", sendMsg, "STACK", isDumpStack ? GetProcessStacktrace() : "");
969     XCOLLIE_LOGI("hisysevent write result=%{public}d, send event [FRAMEWORK,%{public}s], "
970         "msg=%{public}s", ret, eventName.c_str(), msg.c_str());
971 }
972 
GetFfrtTaskTid(int32_t & tid,const std::string & msg)973 void WatchdogInner::GetFfrtTaskTid(int32_t& tid, const std::string& msg)
974 {
975     std::string queueNameFrontStr = "us. queue name [";
976     size_t queueNameFrontPos = msg.find(queueNameFrontStr);
977     if (queueNameFrontPos == std::string::npos) {
978         return;
979     }
980     size_t queueNameRearPos = msg.find("], remaining tasks count=");
981     size_t queueStartPos = queueNameFrontPos + queueNameFrontStr.length();
982     if (queueNameRearPos == std::string::npos || queueNameRearPos <= queueStartPos) {
983         return;
984     }
985     size_t queueNameLength = queueNameRearPos - queueStartPos;
986     std::string workerTidFrontStr = " worker tid ";
987     std::string taskIdFrontStr = " is running, task id ";
988     std::string queueNameStr = " name " + msg.substr(queueStartPos, queueNameLength);
989     std::istringstream issMsg(msg);
990     std::string line;
991     while (std::getline(issMsg, line, '\n')) {
992         size_t workerTidFrontPos = line.find(workerTidFrontStr);
993         size_t taskIdFrontPos = line.find(taskIdFrontStr);
994         size_t queueNamePos = line.find(queueNameStr);
995         size_t workerStartPos = workerTidFrontPos + workerTidFrontStr.length();
996         if (workerTidFrontPos == std::string::npos || taskIdFrontPos == std::string::npos ||
997             queueNamePos == std::string::npos || taskIdFrontPos <= workerStartPos) {
998             continue;
999         }
1000         size_t tidLength = taskIdFrontPos - workerStartPos;
1001         if (tidLength < std::to_string(INT32_MAX).length()) {
1002             std::string tidStr = line.substr(workerStartPos, tidLength);
1003             if (std::all_of(std::begin(tidStr), std::end(tidStr), [] (const char& c) {
1004                 return isdigit(c);
1005             })) {
1006                 tid = std::stoi(tidStr);
1007                 return;
1008             }
1009         }
1010     }
1011 }
1012 
LeftTimeExitProcess(const std::string & description)1013 void WatchdogInner::LeftTimeExitProcess(const std::string &description)
1014 {
1015     int32_t pid = getprocpid();
1016     if (IsProcessDebug(pid)) {
1017         XCOLLIE_LOGI("heap dump or debug for %{public}d, don't exit.", pid);
1018         return;
1019     }
1020     DelayBeforeExit(10); // sleep 10s for hiview dump
1021     XCOLLIE_LOGI("Process is going to exit, reason:%{public}s.", description.c_str());
1022     WatchdogInner::WriteStringToFile(pid, "0");
1023 
1024     _exit(0);
1025 }
1026 
Stop()1027 bool WatchdogInner::Stop()
1028 {
1029     IPCDfx::SetIPCProxyLimit(0, nullptr);
1030     if (mainRunner_ != nullptr) {
1031         mainRunner_->SetMainLooperWatcher(nullptr, nullptr);
1032     }
1033     isNeedStop_.store(true);
1034     condition_.notify_all();
1035     if (threadLoop_ != nullptr && threadLoop_->joinable()) {
1036         threadLoop_->join();
1037         threadLoop_ = nullptr;
1038     }
1039     if (g_fd != NOT_OPEN) {
1040         close(g_fd);
1041         g_fd = NOT_OPEN;
1042     }
1043     return true;
1044 }
1045 
KillPeerBinderProcess(const std::string & description)1046 void WatchdogInner::KillPeerBinderProcess(const std::string &description)
1047 {
1048     bool result = false;
1049     if (getuid() == FOUNDATION_UID) {
1050         result = KillProcessByPid(getprocpid());
1051     }
1052     if (!result) {
1053         WatchdogInner::LeftTimeExitProcess(description);
1054     }
1055 }
1056 
RemoveInnerTask(const std::string & name)1057 void WatchdogInner::RemoveInnerTask(const std::string& name)
1058 {
1059     if (name.empty()) {
1060         XCOLLIE_LOGI("RemoveInnerTask fail, cname is null");
1061         return;
1062     }
1063     std::priority_queue<WatchdogTask> tmpQueue;
1064     std::unique_lock<std::mutex> lock(lock_);
1065     size_t size = checkerQueue_.size();
1066     if (size == 0) {
1067         XCOLLIE_LOGE("RemoveInnerTask %{public}s fail, empty queue!", name.c_str());
1068         return;
1069     }
1070     while (!checkerQueue_.empty()) {
1071         const WatchdogTask& task = checkerQueue_.top();
1072         if (task.name != name) {
1073             tmpQueue.push(task);
1074         } else {
1075             size_t nameSize = taskNameSet_.size();
1076             if (nameSize != 0 && !task.isOneshotTask) {
1077                 taskNameSet_.erase(name);
1078                 XCOLLIE_LOGD("RemoveInnerTask name %{public}s, remove result=%{public}d",
1079                     name.c_str(), nameSize > taskNameSet_.size());
1080             }
1081         }
1082         checkerQueue_.pop();
1083     }
1084     if (tmpQueue.size() == size) {
1085         XCOLLIE_LOGE("RemoveInnerTask fail, can not find name %{public}s, size=%{public}zu!",
1086             name.c_str(), size);
1087     }
1088     tmpQueue.swap(checkerQueue_);
1089 }
1090 
InitBeginFunc(const char * name)1091 void InitBeginFunc(const char* name)
1092 {
1093     std::string nameStr(name);
1094     WatchdogInner::GetInstance().bussinessBeginTime_ = DistributeStart(nameStr);
1095 }
1096 
InitEndFunc(const char * name)1097 void InitEndFunc(const char* name)
1098 {
1099     std::string nameStr(name);
1100     DistributeEnd(nameStr, WatchdogInner::GetInstance().bussinessBeginTime_);
1101 }
1102 
InitMainLooperWatcher(WatchdogInnerBeginFunc * beginFunc,WatchdogInnerEndFunc * endFunc)1103 void WatchdogInner::InitMainLooperWatcher(WatchdogInnerBeginFunc* beginFunc,
1104     WatchdogInnerEndFunc* endFunc)
1105 {
1106     int64_t tid = getproctid();
1107     if (beginFunc && endFunc) {
1108         if (buissnessThreadInfo_.find(tid) != buissnessThreadInfo_.end()) {
1109             XCOLLIE_LOGI("Tid =%{public}" PRId64 "already exits, "
1110                 "no repeated initialization.", tid);
1111             return;
1112         }
1113         if (mainRunner_ != nullptr) {
1114             mainRunner_->SetMainLooperWatcher(nullptr, nullptr);
1115         }
1116         *beginFunc = InitBeginFunc;
1117         *endFunc = InitEndFunc;
1118         buissnessThreadInfo_.insert(tid);
1119     } else {
1120         if (buissnessThreadInfo_.find(tid) != buissnessThreadInfo_.end()) {
1121             XCOLLIE_LOGI("Remove already init tid=%{public}." PRId64, tid);
1122             mainRunner_->SetMainLooperWatcher(DistributeStart, DistributeEnd);
1123             buissnessThreadInfo_.erase(tid);
1124         }
1125     }
1126 }
1127 
SetAppDebug(bool isAppDebug)1128 void WatchdogInner::SetAppDebug(bool isAppDebug)
1129 {
1130     isAppDebug_ = isAppDebug;
1131 }
1132 
GetAppDebug()1133 bool WatchdogInner::GetAppDebug()
1134 {
1135     return isAppDebug_;
1136 }
1137 } // end of namespace HiviewDFX
1138 } // end of namespace OHOS
1139