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