• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "fault_logger_service.h"
17 
18 #include <algorithm>
19 #include <fstream>
20 #include <sys/wait.h>
21 #include <sys/socket.h>
22 #include <sys/syscall.h>
23 #include "dfx_define.h"
24 #include "dfx_log.h"
25 #include "dfx_lperf.h"
26 #include "dfx_trace.h"
27 #include "dfx_util.h"
28 #include "fault_logger_daemon.h"
29 #include "faultloggerd_socket.h"
30 #include "fault_common_util.h"
31 #include "procinfo.h"
32 #include "proc_util.h"
33 
34 #ifndef is_ohos_lite
35 #include "fault_logger_pipe.h"
36 #endif
37 
38 #ifndef HISYSEVENT_DISABLE
39 #include "hisysevent.h"
40 #endif
41 
42 #include "string_printf.h"
43 #include "temp_file_manager.h"
44 
45 namespace OHOS {
46 namespace HiviewDFX {
47 
48 namespace {
49 constexpr const char* const FAULTLOGGERD_SERVICE_TAG = "FAULT_LOGGER_SERVICE";
CheckCallerUID(uint32_t callerUid)50 bool CheckCallerUID(uint32_t callerUid)
51 {
52     const uint32_t whitelist[] = {
53         0, // rootUid
54         1000, // bmsUid
55         1201, // hiviewUid
56         1212, // hidumperServiceUid
57         5523, // foundationUid
58     };
59     if (std::find(std::begin(whitelist), std::end(whitelist), callerUid) == std::end(whitelist)) {
60         DFXLOGW("%{public}s :: CheckCallerUID :: Caller Uid(%{public}d) is unexpectly.",
61                 FAULTLOGGERD_SERVICE_TAG, callerUid);
62         return false;
63     }
64     return true;
65 }
66 
CheckRequestCredential(int32_t connectionFd,int32_t requestPid)67 bool CheckRequestCredential(int32_t connectionFd, int32_t requestPid)
68 {
69     struct ucred creds{};
70     if (!FaultCommonUtil::GetUcredByPeerCred(creds, connectionFd)) {
71         return false;
72     }
73     if (CheckCallerUID(creds.uid)) {
74         return true;
75     }
76     if (creds.pid != requestPid) {
77         DFXLOGW("Failed to check request credential request:%{public}d: cred:%{public}d fd:%{public}d",
78                 requestPid, creds.pid, connectionFd);
79         return false;
80     }
81     return true;
82 }
83 }
84 
85 #ifndef HISYSEVENT_DISABLE
Filter(int32_t connectionFd,const CrashDumpException & requestData)86 bool ExceptionReportService::Filter(int32_t connectionFd, const CrashDumpException& requestData)
87 {
88     if (strlen(requestData.message) == 0) {
89         return false;
90     }
91     struct ucred creds{};
92     if (!FaultCommonUtil::GetUcredByPeerCred(creds, connectionFd) ||
93             creds.uid != static_cast<uint32_t>(requestData.uid)) {
94         DFXLOGW("Failed to check request credential request uid:%{public}d: cred uid:%{public}d fd:%{public}d",
95                 requestData.uid, creds.uid, connectionFd);
96         return false;
97     }
98     return true;
99 }
100 
OnRequest(const std::string & socketName,int32_t connectionFd,const CrashDumpException & requestData)101 int32_t ExceptionReportService::OnRequest(const std::string& socketName, int32_t connectionFd,
102     const CrashDumpException& requestData)
103 {
104     if (!Filter(connectionFd, requestData)) {
105         return ResponseCode::REQUEST_REJECT;
106     }
107     HiSysEventWrite(
108         HiSysEvent::Domain::RELIABILITY,
109         "CPP_CRASH_EXCEPTION",
110         HiSysEvent::EventType::FAULT,
111         "PID", requestData.pid,
112         "UID", requestData.uid,
113         "HAPPEN_TIME", requestData.time,
114         "ERROR_CODE", requestData.error,
115         "ERROR_MSG", requestData.message);
116 #ifdef FAULTLOGGERD_TEST
117     int32_t responseData = ResponseCode::REQUEST_SUCCESS;
118     SendMsgToSocket(connectionFd, &responseData, sizeof(responseData));
119 #endif
120     return ResponseCode::REQUEST_SUCCESS;
121 }
122 
RemoveTimeoutDumpStats()123 void StatsService::RemoveTimeoutDumpStats()
124 {
125     constexpr uint64_t timeout = 10000; // 10s
126     uint64_t now = GetTimeMilliSeconds();
127     stats_.remove_if([&now, &timeout](const auto& stats) {
128         return (now > stats.signalTime && now - stats.signalTime > timeout) ||
129             now <= stats.signalTime;
130     });
131 }
132 
ReportDumpStats(const DumpStats & stat)133 void StatsService::ReportDumpStats(const DumpStats& stat)
134 {
135     HiSysEventWrite(
136         HiSysEvent::Domain::HIVIEWDFX,
137         "DUMP_CATCHER_STATS",
138         HiSysEvent::EventType::STATISTIC,
139         "CALLER_PROCESS_NAME", stat.callerProcessName,
140         "CALLER_FUNC_NAME", stat.callerElfName,
141         "TARGET_PROCESS_NAME", stat.targetProcessName,
142         "RESULT", stat.result,
143         "SUMMARY", stat.summary, // we need to parse summary when interface return false
144         "PID", stat.pid,
145         "REQUEST_TIME", stat.requestTime,
146         "OVERALL_TIME", stat.dumpCatcherFinishTime - stat.requestTime,
147         "SIGNAL_TIME", stat.signalTime - stat.requestTime,
148         "DUMPER_START_TIME", stat.processdumpStartTime - stat.signalTime,
149         "WRITE_DUMP_INFO_TIME", stat.writeDumpInfoCost,
150         "UNWIND_TIME", stat.processdumpFinishTime - stat.processdumpStartTime,
151         "TARGET_PROCESS_THREAD_COUNT", stat.targetProcessThreadCount);
152 }
153 
GetElfName(const FaultLoggerdStatsRequest & request)154 std::string StatsService::GetElfName(const FaultLoggerdStatsRequest& request)
155 {
156     if (strlen(request.callerElf) > NAME_BUF_LEN) {
157         return "";
158     }
159     return StringPrintf("%s(%p)", request.callerElf, reinterpret_cast<void*>(request.offset));
160 }
161 
OnRequest(const std::string & socketName,int32_t connectionFd,const FaultLoggerdStatsRequest & requestData)162 int32_t StatsService::OnRequest(const std::string& socketName, int32_t connectionFd,
163     const FaultLoggerdStatsRequest& requestData)
164 {
165     constexpr int32_t delayTime = 7; // allow 10s for processdump report, 3s for dumpcatch timeout and 7s for delay
166     DFXLOGI("%{public}s :: %{public}s: HandleDumpStats", FAULTLOGGERD_SERVICE_TAG, __func__);
167     auto iter = std::find_if(stats_.begin(), stats_.end(), [&requestData](const DumpStats& dumpStats) {
168         return dumpStats.pid == requestData.pid;
169     });
170     if (requestData.type == PROCESS_DUMP && iter == stats_.end()) {
171         auto& stats = stats_.emplace_back();
172         stats.pid = requestData.pid;
173         stats.signalTime = requestData.signalTime;
174         stats.processdumpStartTime = requestData.processdumpStartTime;
175         stats.processdumpFinishTime = requestData.processdumpFinishTime;
176         stats.targetProcessName = requestData.targetProcess;
177         stats.writeDumpInfoCost = requestData.writeDumpInfoCost;
178     } else if (requestData.type == DUMP_CATCHER) {
179         auto task = [requestData, this] {
180             auto iter = std::find_if(stats_.begin(), stats_.end(), [&requestData](const DumpStats& dumpStats) {
181                 return dumpStats.pid == requestData.pid;
182             });
183             DumpStats stats;
184             if (iter != stats_.end()) {
185                 stats = *iter;
186                 stats_.erase(iter);
187             }
188             stats.pid = requestData.pid;
189             stats.requestTime = requestData.requestTime;
190             stats.dumpCatcherFinishTime = requestData.dumpCatcherFinishTime;
191             stats.callerElfName = GetElfName(requestData);
192             stats.result = requestData.result;
193             stats.callerProcessName = requestData.callerProcess;
194             stats.summary = requestData.summary;
195             stats.targetProcessName = requestData.targetProcess;
196             stats.targetProcessThreadCount = requestData.targetProcessThreadCount;
197             ReportDumpStats(stats);
198             RemoveTimeoutDumpStats();
199         };
200         StartDelayTask(task, delayTime);
201     }
202     RemoveTimeoutDumpStats();
203 #ifdef FAULTLOGGERD_TEST
204     int32_t responseData = ResponseCode::REQUEST_SUCCESS;
205     SendMsgToSocket(connectionFd, &responseData, sizeof(responseData));
206 #endif
207     return ResponseCode::REQUEST_SUCCESS;
208 }
209 
StartDelayTask(std::function<void ()> workFunc,int32_t delayTime)210 void StatsService::StartDelayTask(std::function<void()> workFunc, int32_t delayTime)
211 {
212     auto delayTask = DelayTask::CreateInstance(workFunc, delayTime);
213     FaultLoggerDaemon::GetEpollManager(EpollManagerType::MAIN_SERVER).AddListener(std::move(delayTask));
214 }
215 #endif
216 
OnRequest(const std::string & socketName,int32_t connectionFd,const FaultLoggerdRequest & requestData)217 int32_t FileDesService::OnRequest(const std::string& socketName, int32_t connectionFd,
218     const FaultLoggerdRequest& requestData)
219 {
220     DFX_TRACE_SCOPED("FileDesServiceOnRequest");
221     if (!Filter(socketName, connectionFd, requestData)) {
222         return ResponseCode::REQUEST_REJECT;
223     }
224     SmartFd fileFd(TempFileManager::CreateFileDescriptor(requestData.type, requestData.pid,
225         requestData.tid, requestData.time));
226     if (!fileFd) {
227         return ResponseCode::ABNORMAL_SERVICE;
228     }
229 #ifndef is_ohos_lite
230     TempFileManager::RecordFileCreation(requestData.type, requestData.pid);
231 #endif
232     int32_t responseData = ResponseCode::REQUEST_SUCCESS;
233     SendMsgToSocket(connectionFd, &responseData, sizeof(responseData));
234     int fd = fileFd.GetFd();
235     SendFileDescriptorToSocket(connectionFd, &fd, 1);
236     return responseData;
237 }
238 
Filter(const std::string & socketName,int32_t connectionFd,const FaultLoggerdRequest & requestData)239 bool FileDesService::Filter(const std::string& socketName, int32_t connectionFd,
240     const FaultLoggerdRequest& requestData)
241 {
242     switch (requestData.type) {
243         case FaultLoggerType::CPP_CRASH:
244         case FaultLoggerType::CPP_STACKTRACE:
245         case FaultLoggerType::LEAK_STACKTRACE:
246         case FaultLoggerType::JIT_CODE_LOG:
247             return socketName == SERVER_CRASH_SOCKET_NAME;
248         default:
249             return CheckRequestCredential(connectionFd, requestData.pid);
250     }
251 }
252 
253 #ifndef is_ohos_lite
Filter(const std::string & socketName,const SdkDumpRequestData & requestData,uint32_t uid)254 int32_t SdkDumpService::Filter(const std::string& socketName, const SdkDumpRequestData& requestData, uint32_t uid)
255 {
256     if (requestData.pid <= 0 || socketName != SERVER_SDKDUMP_SOCKET_NAME || !CheckCallerUID(uid)) {
257         DFXLOGE("%{public}s :: HandleSdkDumpRequest :: pid(%{public}d) or socketName(%{public}s) fail.",
258             FAULTLOGGERD_SERVICE_TAG, requestData.pid, socketName.c_str());
259         return ResponseCode::REQUEST_REJECT;
260     }
261     if (TempFileManager::CheckCrashFileRecord(requestData.pid)) {
262         DFXLOGW("%{public}s :: pid(%{public}d) has been crashed, break.",
263                 FAULTLOGGERD_SERVICE_TAG, requestData.pid);
264         return ResponseCode::SDK_PROCESS_CRASHED;
265     }
266     if (FaultLoggerPipePair::CheckSdkDumpRecord(requestData.pid, requestData.time)) {
267         DFXLOGE("%{public}s :: pid(%{public}d) is dumping, break.", FAULTLOGGERD_SERVICE_TAG, requestData.pid);
268         return ResponseCode::SDK_DUMP_REPEAT;
269     }
270     return ResponseCode::REQUEST_SUCCESS;
271 }
272 
OnRequest(const std::string & socketName,int32_t connectionFd,const SdkDumpRequestData & requestData)273 int32_t SdkDumpService::OnRequest(const std::string& socketName, int32_t connectionFd,
274     const SdkDumpRequestData& requestData)
275 {
276     DFX_TRACE_SCOPED("SdkDumpServiceOnRequest");
277     DFXLOGI("Receive dump request for pid:%{public}d tid:%{public}d.", requestData.pid, requestData.tid);
278     struct ucred creds;
279     if (!FaultCommonUtil::GetUcredByPeerCred(creds, connectionFd)) {
280         return ResponseCode::REQUEST_REJECT;
281     }
282     int32_t responseCode = Filter(socketName, requestData, creds.uid);
283     if (responseCode != ResponseCode::REQUEST_SUCCESS) {
284         return responseCode;
285     }
286 
287     /*
288     *           all     threads my user, local pid             my user, remote pid     other user's process
289     * 3rd       Y       Y(in signal_handler local)     Y(in signal_handler loacl)      N
290     * system    Y       Y(in signal_handler local)     Y(in signal_handler loacl)      Y(in signal_handler remote)
291     * root      Y       Y(in signal_handler local)     Y(in signal_handler loacl)      Y(in signal_handler remote)
292     */
293 
294     /*
295     * 1. pid != 0 && tid != 0:    means we want dump a thread, so we send signal to a thread.
296         Main thread stack is tid's stack, we need ignore other thread info.
297     * 2. pid != 0 && tid == 0:    means we want dump a process, so we send signal to process.
298         Main thead stack is pid's stack, we need other tread info.
299     */
300 
301     /*
302      * in signal_handler we need to check caller pid and tid(which is send to signal handler by SYS_rt_sig.).
303      * 1. caller pid == signal pid, means we do back trace in ourself process, means local backtrace.
304      *      |- we do all tid back trace in signal handler's local unwind.
305      * 2. pid != signal pid, means we do remote back trace.
306      */
307 
308     /*
309      * in local back trace, all unwind stack will save to signal_handler global var.(mutex lock in signal handler.)
310      * in remote back trace, all unwind stack will save to file, and read in dump_catcher, then return.
311      */
312 
313 #pragma clang diagnostic push
314 #pragma clang diagnostic ignored "-Winitializer-overrides"
315     // defined in out/hi3516dv300/obj/third_party/musl/intermidiates/linux/musl_src_ported/include/signal.h
316     siginfo_t si{0};
317     si.si_signo = SIGDUMP;
318     si.si_errno = 0;
319     si.si_value.sival_int = requestData.tid;
320     if (requestData.tid == 0 && sizeof(void*) == 8) { // 8 : platform 64
321         si.si_value.sival_ptr = reinterpret_cast<void*>(requestData.endTime | (1ULL << 63)); // 63 : platform 64
322     }
323     si.si_code = requestData.sigCode;
324     si.si_pid = static_cast<int32_t>(creds.pid);
325     si.si_uid = static_cast<uid_t>(requestData.callerTid);
326 #pragma clang diagnostic pop
327     /*
328      * means we need dump all the threads in a process
329      * --------
330      * Accroding to the linux manual, A process-directed signal may be delivered to any one of the
331      * threads that does not currently have the signal blocked.
332      */
333     auto& faultLoggerPipe = FaultLoggerPipePair::CreateSdkDumpPipePair(requestData.pid, requestData.time);
334 
335     if (auto ret = FaultCommonUtil::SendSignalToProcess(requestData.pid, si); ret != ResponseCode::REQUEST_SUCCESS) {
336         FaultLoggerPipePair::DelSdkDumpPipePair(requestData.pid);
337         return ret;
338     }
339 
340     int32_t fds[PIPE_NUM_SZ] = {
341         faultLoggerPipe.GetPipeFd(PipeFdUsage::BUFFER_FD, FaultLoggerPipeType::PIPE_FD_READ),
342         faultLoggerPipe.GetPipeFd(PipeFdUsage::RESULT_FD, FaultLoggerPipeType::PIPE_FD_READ)
343     };
344     if (fds[PIPE_BUF_INDEX] < 0 || fds[PIPE_RES_INDEX] < 0) {
345         return ResponseCode::ABNORMAL_SERVICE;
346     }
347     int32_t res = ResponseCode::REQUEST_SUCCESS;
348     SendMsgToSocket(connectionFd, &res, sizeof(res));
349     SendFileDescriptorToSocket(connectionFd, fds, PIPE_NUM_SZ);
350     return res;
351 }
352 
Filter(const std::string & socketName,int32_t connectionFd,const PipFdRequestData & requestData)353 bool PipeService::Filter(const std::string &socketName, int32_t connectionFd, const PipFdRequestData &requestData)
354 {
355     if (requestData.pipeType > FaultLoggerPipeType::PIPE_FD_DELETE ||
356         requestData.pipeType < FaultLoggerPipeType::PIPE_FD_READ) {
357         return false;
358     }
359     if (socketName == SERVER_CRASH_SOCKET_NAME) {
360         return true;
361     }
362     return CheckRequestCredential(connectionFd, requestData.pid);
363 }
364 
OnRequest(const std::string & socketName,int32_t connectionFd,const PipFdRequestData & requestData)365 int32_t PipeService::OnRequest(const std::string& socketName, int32_t connectionFd, const PipFdRequestData& requestData)
366 {
367     DFX_TRACE_SCOPED("PipeServiceOnRequest");
368     if (!Filter(socketName, connectionFd, requestData)) {
369         return ResponseCode::REQUEST_REJECT;
370     }
371     int32_t responseData = ResponseCode::REQUEST_SUCCESS;
372     if (requestData.pipeType == FaultLoggerPipeType::PIPE_FD_DELETE) {
373         FaultLoggerPipePair::DelSdkDumpPipePair(requestData.pid);
374         SendMsgToSocket(connectionFd, &responseData, sizeof(responseData));
375         return responseData;
376     }
377     FaultLoggerPipePair* faultLoggerPipe = FaultLoggerPipePair::GetSdkDumpPipePair(requestData.pid);
378     if (faultLoggerPipe == nullptr) {
379         DFXLOGE("%{public}s :: cannot find pipe fd for pid(%{public}d).", FAULTLOGGERD_SERVICE_TAG, requestData.pid);
380         return ResponseCode::ABNORMAL_SERVICE;
381     }
382     int32_t fds[PIPE_NUM_SZ] = {
383         faultLoggerPipe->GetPipeFd(PipeFdUsage::BUFFER_FD, FaultLoggerPipeType::PIPE_FD_WRITE),
384         faultLoggerPipe->GetPipeFd(PipeFdUsage::RESULT_FD, FaultLoggerPipeType::PIPE_FD_WRITE)
385     };
386     if (fds[PIPE_BUF_INDEX] < 0 || fds[PIPE_RES_INDEX] < 0) {
387         DFXLOGE("%{public}s :: failed to get fds for pipeType(%{public}d).", FAULTLOGGERD_SERVICE_TAG,
388             requestData.pipeType);
389         return ResponseCode::ABNORMAL_SERVICE;
390     }
391     SendMsgToSocket(connectionFd, &responseData, sizeof(responseData));
392     SendFileDescriptorToSocket(connectionFd, fds, PIPE_NUM_SZ);
393     return responseData;
394 }
395 
Filter(const std::string & socketName,int32_t connectionFd,const LitePerfFdRequestData & requestData)396 bool LitePerfPipeService::Filter(const std::string &socketName, int32_t connectionFd,
397     const LitePerfFdRequestData &requestData)
398 {
399     if (requestData.pipeType > FaultLoggerPipeType::PIPE_FD_DELETE ||
400         requestData.pipeType < FaultLoggerPipeType::PIPE_FD_READ) {
401         return false;
402     }
403 
404     struct ucred creds{};
405     if (!FaultCommonUtil::GetUcredByPeerCred(creds, connectionFd)) {
406         return false;
407     }
408     if (creds.uid != requestData.uid) {
409         DFXLOGW("Failed to check request credential request:%{public}d, cred:%{public}d, fd:%{public}d",
410             requestData.uid, creds.uid, connectionFd);
411         return false;
412     }
413     return true;
414 }
415 
OnRequest(const std::string & socketName,int32_t connectionFd,const LitePerfFdRequestData & requestData)416 int32_t LitePerfPipeService::OnRequest(const std::string& socketName, int32_t connectionFd,
417     const LitePerfFdRequestData& requestData)
418 {
419     DFX_TRACE_SCOPED("LitePerfPipeServiceOnRequest");
420     if (!Filter(socketName, connectionFd, requestData)) {
421         return ResponseCode::REQUEST_REJECT;
422     }
423     int uid = static_cast<int>(requestData.uid);
424     int32_t responseData = ResponseCode::REQUEST_SUCCESS;
425     if (requestData.pipeType == FaultLoggerPipeType::PIPE_FD_DELETE) {
426         LitePerfPipePair::DelPipePair(uid);
427         SendMsgToSocket(connectionFd, &responseData, sizeof(responseData));
428         return responseData;
429     }
430 
431     int32_t fds[PIPE_NUM_SZ] = {0};
432     if (requestData.pipeType == FaultLoggerPipeType::PIPE_FD_READ) {
433         if (LitePerfPipePair::CheckDumpMax() || LitePerfPipePair::CheckDumpRecord(uid)) {
434             DFXLOGE("%{public}s :: uid(%{public}d) is dumping.", FAULTLOGGERD_SERVICE_TAG, uid);
435             return ResponseCode::SDK_DUMP_REPEAT;
436         }
437         auto& pipePair = LitePerfPipePair::CreatePipePair(uid);
438         fds[PIPE_BUF_INDEX] = pipePair.GetPipeFd(PipeFdUsage::BUFFER_FD, FaultLoggerPipeType::PIPE_FD_READ);
439         fds[PIPE_RES_INDEX] = pipePair.GetPipeFd(PipeFdUsage::RESULT_FD, FaultLoggerPipeType::PIPE_FD_READ);
440 
441         constexpr int maxPerfTimeout = (MAX_STOP_SECONDS + DUMP_LITEPERF_TIMEOUT) / 1000;
442         int32_t delayTime = std::min(requestData.timeout, maxPerfTimeout);
443         auto task = [uid, this] {
444             LitePerfPipePair::DelPipePair(uid);
445         };
446         StartDelayTask(task, delayTime);
447     } else if (requestData.pipeType == FaultLoggerPipeType::PIPE_FD_WRITE) {
448         LitePerfPipePair* pipePair = LitePerfPipePair::GetPipePair(uid);
449         if (pipePair == nullptr) {
450             DFXLOGE("%{public}s :: cannot find pipe fd for pid(%{public}d).",
451                 FAULTLOGGERD_SERVICE_TAG, requestData.pid);
452             return ResponseCode::ABNORMAL_SERVICE;
453         }
454         fds[PIPE_BUF_INDEX] = pipePair->GetPipeFd(PipeFdUsage::BUFFER_FD, FaultLoggerPipeType::PIPE_FD_WRITE);
455         fds[PIPE_RES_INDEX] = pipePair->GetPipeFd(PipeFdUsage::RESULT_FD, FaultLoggerPipeType::PIPE_FD_WRITE);
456     }
457     if (fds[PIPE_BUF_INDEX] < 0 || fds[PIPE_RES_INDEX] < 0) {
458         DFXLOGE("%{public}s :: failed to get fds for pipeType(%{public}d).", FAULTLOGGERD_SERVICE_TAG,
459             requestData.pipeType);
460         return ResponseCode::ABNORMAL_SERVICE;
461     }
462     SendMsgToSocket(connectionFd, &responseData, sizeof(responseData));
463     SendFileDescriptorToSocket(connectionFd, fds, PIPE_NUM_SZ);
464     return responseData;
465 }
466 
StartDelayTask(std::function<void ()> workFunc,int32_t delayTime)467 void LitePerfPipeService::StartDelayTask(std::function<void()> workFunc, int32_t delayTime)
468 {
469     auto delayTask = DelayTask::CreateInstance(workFunc, delayTime);
470     FaultLoggerDaemon::GetEpollManager(EpollManagerType::MAIN_SERVER).AddListener(std::move(delayTask));
471 }
472 #endif
473 }
474 }