1/*
2 * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include <gtest/gtest.h>
17#include <csignal>
18#include <map>
19#include <securec.h>
20#include <string>
21#include <thread>
22#include <unistd.h>
23#include <vector>
24#include <sys/prctl.h>
25
26#include "dfx_define.h"
27#include "dfx_signal_handler.h"
28#include "dfx_signalhandler_exception.h"
29#include "dfx_test_util.h"
30
31using namespace testing;
32using namespace testing::ext;
33using namespace std;
34
35namespace OHOS {
36namespace HiviewDFX {
37class SignalHandlerTest : public testing::Test {
38public:
39    static void SetUpTestCase();
40    static void TearDownTestCase();
41    void SetUp();
42    void TearDown();
43};
44
45void SignalHandlerTest::SetUpTestCase()
46{}
47
48void SignalHandlerTest::TearDownTestCase()
49{}
50
51void SignalHandlerTest::SetUp()
52{}
53
54void SignalHandlerTest::TearDown()
55{}
56
57extern "C" void SetThreadInfoCallback(ThreadInfoCallBack func) __attribute__((weak));
58extern "C" void DFX_InstallSignalHandler(void) __attribute__((weak));
59extern "C" void SetAsyncStackCallbackFunc(void* func) __attribute__((weak));
60extern "C" int DFX_SetAppRunningUniqueId(const char* appRunningId, size_t len) __attribute__((weak));
61static bool CheckThreadCrashKeyWords(const string& filePath, pid_t pid, int sig)
62{
63    if (filePath.empty() || pid <= 0) {
64        return false;
65    }
66    map<int, string> sigKey = {
67        { SIGILL, string("SIGILL") },
68        { SIGBUS, string("SIGBUS") },
69        { SIGSEGV, string("SIGSEGV") },
70    };
71    string sigKeyword = "";
72    map<int, string>::iterator iter = sigKey.find(sig);
73    if (iter != sigKey.end()) {
74        sigKeyword = iter->second;
75    }
76    string keywords[] = {
77        "Pid:" + to_string(pid), "Uid:", "name:./test_signalhandler", sigKeyword,
78        "Tid:", "#00", "Registers:", "FaultStack:", "Maps:", "test_signalhandler"
79    };
80    int length = sizeof(keywords) / sizeof(keywords[0]);
81    int minRegIdx = -1;
82    return CheckKeyWords(filePath, keywords, length, minRegIdx) == length;
83}
84static bool CheckCrashKeyWords(const string& filePath, pid_t pid, int sig)
85{
86    if (filePath.empty() || pid <= 0) {
87        return false;
88    }
89    map<int, string> sigKey = {
90        { SIGILL, string("SIGILL") },
91        { SIGBUS, string("SIGBUS") },
92        { SIGSEGV, string("SIGSEGV") },
93        { SIGABRT, string("SIGABRT") },
94        { SIGFPE, string("SIGFPE") },
95        { SIGSTKFLT, string("SIGSTKFLT") },
96        { SIGSYS, string("SIGSYS") },
97        { SIGTRAP, string("SIGTRAP") },
98    };
99    string sigKeyword = "";
100    map<int, string>::iterator iter = sigKey.find(sig);
101    if (iter != sigKey.end()) {
102        sigKeyword = iter->second;
103    }
104    string keywords[] = {
105        "Pid:" + to_string(pid), "Uid:", "name:./test_signalhandler", sigKeyword,
106        "Tid:", "#00", "Registers:", "FaultStack:", "Maps:", "test_signalhandler"
107    };
108    int length = sizeof(keywords) / sizeof(keywords[0]);
109    int minRegIdx = -1;
110    return CheckKeyWords(filePath, keywords, length, minRegIdx) == length;
111}
112
113void ThreadInfo(char* buf, size_t len, void* context __attribute__((unused)))
114{
115    char mes[] = "this is cash information of test thread";
116    if (memcpy_s(buf, len, mes, sizeof(mes)) != 0) {
117        GTEST_LOG_(INFO) << "Failed to set thread info";
118    }
119}
120
121int TestThread(int threadId, int sig)
122{
123    std::string subThreadName = "SubTestThread" + to_string(threadId);
124    prctl(PR_SET_NAME, subThreadName.c_str());
125    if (SetThreadInfoCallback != nullptr) {
126        SetThreadInfoCallback(ThreadInfo);
127    }
128    int cashThreadId = 2;
129    if (threadId == cashThreadId) {
130        GTEST_LOG_(INFO) << subThreadName << " is ready to raise signo(" << sig <<")";
131        raise(sig);
132    }
133    return 0;
134}
135
136/**
137 * @tc.name: SignalHandlerTest001
138 * @tc.desc: test thread cash SignalHandler signo(SIGILL)
139 * @tc.type: FUNC
140 */
141HWTEST_F(SignalHandlerTest, SignalHandlerTest001, TestSize.Level2)
142{
143    GTEST_LOG_(INFO) << "SignalHandlerTest001: start.";
144    pid_t pid = fork();
145    if (pid < 0) {
146        GTEST_LOG_(ERROR) << "Failed to fork new test process.";
147    } else if (pid == 0) {
148        if (SetThreadInfoCallback != nullptr) {
149            SetThreadInfoCallback(ThreadInfo);
150        }
151        sleep(1);
152    } else {
153        usleep(10000); // 10000 : sleep 10ms
154        GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
155        kill(pid, SIGILL);
156        sleep(2); // 2 : wait for cppcrash generating
157        bool ret = CheckThreadCrashKeyWords(GetCppCrashFileName(pid), pid, SIGILL);
158        ASSERT_TRUE(ret);
159    }
160    GTEST_LOG_(INFO) << "SignalHandlerTest001: end.";
161}
162
163/**
164 * @tc.name: SignalHandlerTest002
165 * @tc.desc: test thread cash SignalHandler signo(SIGBUS)
166 * @tc.type: FUNC
167 */
168HWTEST_F(SignalHandlerTest, SignalHandlerTest002, TestSize.Level2)
169{
170    GTEST_LOG_(INFO) << "SignalHandlerTest002: start.";
171    pid_t pid = fork();
172    if (pid < 0) {
173        GTEST_LOG_(ERROR) << "Failed to fork new test process.";
174    } else if (pid == 0) {
175        if (SetThreadInfoCallback != nullptr) {
176            SetThreadInfoCallback(ThreadInfo);
177        }
178        sleep(1);
179    } else {
180        usleep(10000); // 10000 : sleep 10ms
181        GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
182        kill(pid, SIGBUS);
183        sleep(2); // 2 : wait for cppcrash generating
184        bool ret = CheckThreadCrashKeyWords(GetCppCrashFileName(pid), pid, SIGBUS);
185        ASSERT_TRUE(ret);
186    }
187    GTEST_LOG_(INFO) << "SignalHandlerTest002: end.";
188}
189
190/**
191 * @tc.name: SignalHandlerTest003
192 * @tc.desc: test thread cash SignalHandler signo(SIGSEGV)
193 * @tc.type: FUNC
194 */
195HWTEST_F(SignalHandlerTest, SignalHandlerTest003, TestSize.Level2)
196{
197    GTEST_LOG_(INFO) << "SignalHandlerTest003: start.";
198    pid_t pid = fork();
199    if (pid < 0) {
200        GTEST_LOG_(ERROR) << "Failed to fork new test process.";
201    } else if (pid == 0) {
202        if (SetThreadInfoCallback != nullptr) {
203            SetThreadInfoCallback(ThreadInfo);
204        }
205        sleep(1);
206    } else {
207        usleep(10000); // 10000 : sleep 10ms
208        GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill process(" << pid << ")";
209        kill(pid, SIGSEGV);
210        sleep(2); // 2 : wait for cppcrash generating
211        bool ret = CheckThreadCrashKeyWords(GetCppCrashFileName(pid), pid, SIGSEGV);
212        ASSERT_TRUE(ret);
213    }
214    GTEST_LOG_(INFO) << "SignalHandlerTest003: end.";
215}
216
217/**
218 * @tc.name: SignalHandlerTest004
219 * @tc.desc: test thread crash SignalHandler in multi-thread situation signo(SIGILL)
220 * @tc.type: FUNC
221 */
222HWTEST_F(SignalHandlerTest, SignalHandlerTest004, TestSize.Level2)
223{
224    GTEST_LOG_(INFO) << "SignalHandlerTest004: start.";
225    pid_t pid = fork();
226    if (pid < 0) {
227        GTEST_LOG_(ERROR) << "Failed to fork new test process.";
228    } else if (pid == 0) {
229        std::thread (TestThread, 1, SIGILL).join(); // 1 : first thread
230        std::thread (TestThread, 2, SIGILL).join(); // 2 : second thread
231        _exit(0);
232    } else {
233        sleep(2); // 2 : wait for cppcrash generating
234        bool ret = CheckThreadCrashKeyWords(GetCppCrashFileName(pid), pid, SIGILL);
235        ASSERT_TRUE(ret);
236    }
237    GTEST_LOG_(INFO) << "SignalHandlerTest004: end.";
238}
239
240/**
241 * @tc.name: SignalHandlerTest005
242 * @tc.desc: test thread crash SignalHandler in multi-thread situation signo(SIGBUS)
243 * @tc.type: FUNC
244 */
245HWTEST_F(SignalHandlerTest, SignalHandlerTest005, TestSize.Level2)
246{
247    GTEST_LOG_(INFO) << "SignalHandlerTest005: start.";
248    pid_t pid = fork();
249    if (pid < 0) {
250        GTEST_LOG_(ERROR) << "Failed to fork new test process.";
251    } else if (pid == 0) {
252        std::thread (TestThread, 1, SIGBUS).join(); // 1 : first thread
253        std::thread (TestThread, 2, SIGBUS).join(); // 2 : second thread
254        _exit(0);
255    } else {
256        sleep(2); // 2 : wait for cppcrash generating
257        bool ret = CheckThreadCrashKeyWords(GetCppCrashFileName(pid), pid, SIGBUS);
258        ASSERT_TRUE(ret);
259    }
260    GTEST_LOG_(INFO) << "SignalHandlerTest005: end.";
261}
262
263/**
264 * @tc.name: SignalHandlerTest006
265 * @tc.desc: test thread crash SignalHandler in multi-thread situation signo(SIGSEGV)
266 * @tc.type: FUNC
267 */
268HWTEST_F(SignalHandlerTest, SignalHandlerTest006, TestSize.Level2)
269{
270    GTEST_LOG_(INFO) << "SignalHandlerTest006: start.";
271    pid_t pid = fork();
272    if (pid < 0) {
273        GTEST_LOG_(ERROR) << "Failed to fork new test process.";
274    } else if (pid == 0) {
275        std::thread (TestThread, 1, SIGSEGV).join(); // 1 : first thread
276        std::thread (TestThread, 2, SIGSEGV).join(); // 2 : second thread
277        _exit(0);
278    } else {
279        sleep(2); // 2 : wait for cppcrash generating
280        bool ret = CheckThreadCrashKeyWords(GetCppCrashFileName(pid), pid, SIGSEGV);
281        ASSERT_TRUE(ret);
282    }
283    GTEST_LOG_(INFO) << "SignalHandlerTest006: end.";
284}
285
286/**
287 * @tc.name: SignalHandlerTest007
288 * @tc.desc: test DFX_InstallSignalHandler interface
289 * @tc.type: FUNC
290 */
291HWTEST_F(SignalHandlerTest, SignalHandlerTest007, TestSize.Level2)
292{
293    GTEST_LOG_(INFO) << "SignalHandlerTest007: start.";
294    int interestedSignalList[] = {
295        SIGABRT, SIGBUS, SIGFPE,
296        SIGSEGV, SIGSTKFLT, SIGSYS, SIGTRAP
297    };
298    for (int sig : interestedSignalList) {
299        pid_t pid = fork();
300        if (pid < 0) {
301            GTEST_LOG_(ERROR) << "Failed to fork new test process.";
302        } else if (pid == 0) {
303            if (DFX_InstallSignalHandler != nullptr) {
304                DFX_InstallSignalHandler();
305            }
306            sleep(1);
307        } else {
308            usleep(10000); // 10000 : sleep 10ms
309            GTEST_LOG_(INFO) << "process(" << getpid() << ") is ready to kill << process(" << pid << ")";
310            GTEST_LOG_(INFO) << "signal:" << sig;
311            kill(pid, sig);
312            sleep(2); // 2 : wait for cppcrash generating
313            bool ret = CheckCrashKeyWords(GetCppCrashFileName(pid), pid, sig);
314            ASSERT_TRUE(ret);
315        }
316    }
317    GTEST_LOG_(INFO) << "SignalHandlerTest007: end.";
318}
319
320int TestThread2(int threadId, int sig, int total, bool exitEarly)
321{
322    std::string subThreadName = "SubTestThread" + to_string(threadId);
323    prctl(PR_SET_NAME, subThreadName.c_str());
324    if (SetThreadInfoCallback != nullptr) {
325        SetThreadInfoCallback(ThreadInfo);
326    }
327    if (threadId == total - 1) {
328        GTEST_LOG_(INFO) << subThreadName << " is ready to raise signo(" << sig <<")";
329        raise(sig);
330    }
331
332    if (!exitEarly) {
333        sleep(total - threadId);
334    }
335    if (SetThreadInfoCallback != nullptr) {
336        SetThreadInfoCallback(ThreadInfo);
337    }
338    return 0;
339}
340
341/**
342 * @tc.name: SignalHandlerTest008
343 * @tc.desc: test add 36 thread info callback and crash thread has no callback
344 * @tc.type: FUNC
345 */
346HWTEST_F(SignalHandlerTest, SignalHandlerTest008, TestSize.Level2)
347{
348    GTEST_LOG_(INFO) << "SignalHandlerTest008: start.";
349    pid_t pid = fork();
350    if (pid < 0) {
351        GTEST_LOG_(ERROR) << "Failed to fork new test process.";
352    } else if (pid == 0) {
353        std::vector<std::thread> threads;
354        const int testThreadCount = 36;
355        for (int i = 0; i < testThreadCount; i++) {
356            threads.push_back(std::thread(TestThread2, i, SIGSEGV, testThreadCount, false));
357        }
358
359        for (auto& thread : threads) {
360            thread.join();
361        }
362        _exit(0);
363    } else {
364        sleep(2); // 2 : wait for cppcrash generating
365        auto file = GetCppCrashFileName(pid);
366        ASSERT_FALSE(file.empty());
367    }
368    GTEST_LOG_(INFO) << "SignalHandlerTest008: end.";
369}
370
371/**
372 * @tc.name: SignalHandlerTest009
373 * @tc.desc: test add 36 thread info callback and crash thread has the callback
374 * @tc.type: FUNC
375 */
376HWTEST_F(SignalHandlerTest, SignalHandlerTest009, TestSize.Level2)
377{
378    GTEST_LOG_(INFO) << "SignalHandlerTest009: start.";
379    pid_t pid = fork();
380    if (pid < 0) {
381        GTEST_LOG_(ERROR) << "Failed to fork new test process.";
382    } else if (pid == 0) {
383        std::vector<std::thread> threads;
384        const int testThreadCount = 36;
385        for (int i = 0; i < testThreadCount; i++) {
386            bool exitEarly = false;
387            if (i % 2 == 0) {
388                exitEarly =  true;
389            }
390            threads.push_back(std::thread (TestThread2, i, SIGSEGV, testThreadCount, exitEarly));
391        }
392
393        for (auto& thread : threads) {
394            thread.join();
395        }
396        _exit(0);
397    } else {
398        sleep(2); // 2 : wait for cppcrash generating
399        auto file = GetCppCrashFileName(pid);
400        ASSERT_FALSE(file.empty());
401    }
402    GTEST_LOG_(INFO) << "SignalHandlerTest009: end.";
403}
404
405/**
406 * @tc.name: SignalHandlerTest010
407 * @tc.desc: test crash when free a invalid address
408 * @tc.type: FUNC
409 */
410HWTEST_F(SignalHandlerTest, SignalHandlerTest010, TestSize.Level2)
411{
412    GTEST_LOG_(INFO) << "SignalHandlerTest010: start.";
413    pid_t pid = fork();
414    if (pid < 0) {
415        GTEST_LOG_(ERROR) << "Failed to fork new test process.";
416    } else if (pid == 0) {
417        if (SetThreadInfoCallback != nullptr) {
418            SetThreadInfoCallback(ThreadInfo);
419        }
420        int32_t freeAddr = 0x111;
421        // trigger crash
422        free(reinterpret_cast<void*>(freeAddr));
423        // force crash if not crash in free
424        abort();
425    } else {
426        sleep(2); // 2 : wait for cppcrash generating
427        auto file = GetCppCrashFileName(pid);
428        ASSERT_FALSE(file.empty());
429    }
430    GTEST_LOG_(INFO) << "SignalHandlerTest010: end.";
431}
432
433/**
434 * @tc.name: SignalHandlerTest011
435 * @tc.desc: test crash when realloc a invalid address
436 * @tc.type: FUNC
437 */
438HWTEST_F(SignalHandlerTest, SignalHandlerTest011, TestSize.Level2)
439{
440    GTEST_LOG_(INFO) << "SignalHandlerTest011: start.";
441    pid_t pid = fork();
442    if (pid < 0) {
443        GTEST_LOG_(ERROR) << "Failed to fork new test process.";
444    } else if (pid == 0) {
445        int32_t initAllocSz = 10;
446        int32_t reallocSz = 20;
447        if (SetThreadInfoCallback != nullptr) {
448            SetThreadInfoCallback(ThreadInfo);
449        }
450        // alloc a buffer
451        int8_t* addr = reinterpret_cast<int8_t*>(malloc(initAllocSz));
452        // overwrite the control block
453        int8_t* newAddr = addr - initAllocSz;
454        (void)memset_s(newAddr, initAllocSz, 0, initAllocSz);
455        addr = reinterpret_cast<int8_t*>(realloc(reinterpret_cast<void*>(addr), reallocSz));
456        free(addr);
457        // force crash if not crash in realloc
458        abort();
459    } else {
460        sleep(2); // 2 : wait for cppcrash generating
461        auto file = GetCppCrashFileName(pid);
462        ASSERT_FALSE(file.empty());
463    }
464    GTEST_LOG_(INFO) << "SignalHandlerTest011: end.";
465}
466
467/**
468 * @tc.name: SignalHandlerTest012
469 * @tc.desc: test crash when realloc a invalid address without threadInfo callback
470 * @tc.type: FUNC
471 */
472HWTEST_F(SignalHandlerTest, SignalHandlerTest012, TestSize.Level2)
473{
474    GTEST_LOG_(INFO) << "SignalHandlerTest012: start.";
475    pid_t pid = fork();
476    if (pid < 0) {
477        GTEST_LOG_(ERROR) << "Failed to fork new test process.";
478    } else if (pid == 0) {
479        int32_t initAllocSz = 10;
480        int32_t reallocSz = 20;
481        // alloc a buffer
482        int8_t* addr = reinterpret_cast<int8_t*>(malloc(initAllocSz));
483        // overwrite the control block
484        int8_t* newAddr = addr - initAllocSz;
485        (void)memset_s(newAddr, initAllocSz, 0, initAllocSz);
486        addr = reinterpret_cast<int8_t*>(realloc(reinterpret_cast<void*>(addr), reallocSz));
487        free(addr);
488        // force crash if not crash in realloc
489        abort();
490    } else {
491        sleep(2); // 2 : wait for cppcrash generating
492        auto file = GetCppCrashFileName(pid);
493        ASSERT_FALSE(file.empty());
494    }
495    GTEST_LOG_(INFO) << "SignalHandlerTest012: end.";
496}
497
498/**
499 * @tc.name: SignalHandlerTest013
500 * @tc.desc: test add 100 thread info callback and do nothing
501 * @tc.type: FUNC
502 */
503HWTEST_F(SignalHandlerTest, SignalHandlerTest013, TestSize.Level2)
504{
505    GTEST_LOG_(INFO) << "SignalHandlerTest013: start.";
506    std::vector<std::thread> threads;
507    const int testThreadCount = 100;
508    for (int i = 0; i < testThreadCount - 1; i++) {
509        threads.push_back(std::thread (TestThread2, i, SIGSEGV, testThreadCount, true));
510    }
511
512    for (auto& thread : threads) {
513        if (thread.joinable()) {
514            thread.join();
515        }
516    }
517    auto file = GetCppCrashFileName(getpid());
518    ASSERT_TRUE(file.empty());
519    GTEST_LOG_(INFO) << "SignalHandlerTest013: end.";
520}
521
522void TestCallbackFunc()
523{}
524
525/**
526 * @tc.name: SignalHandlerTest015
527 * @tc.desc: test DFX_SetAppRunningUniqueId
528 * @tc.type: FUNC
529 */
530HWTEST_F(SignalHandlerTest, SignalHandlerTest015, TestSize.Level2)
531{
532    bool isSuccess = DFX_SetAppRunningUniqueId != nullptr;
533    if (!isSuccess) {
534        ASSERT_FALSE(isSuccess);
535        return;
536    }
537    /**
538     * @tc.steps: step1.
539     *            case: appRunningId == nullptr, len= 0
540     * @tc.expected: ret == -1
541     * */
542    int ret = DFX_SetAppRunningUniqueId(nullptr, 0);
543    ASSERT_EQ(ret, -1);
544
545    /**
546     * @tc.steps: step2.
547     *            case: appRunningId == nullptr, len= MAX_APP_RUNNING_UNIQUE_ID_LEN
548     * @tc.expected: ret == -1
549     * */
550    ret = DFX_SetAppRunningUniqueId(nullptr, MAX_APP_RUNNING_UNIQUE_ID_LEN);
551    ASSERT_EQ(ret, -1);
552
553    /**
554     * @tc.steps: step3.
555     *            case: appRunningId != nullptr, len= 0
556     * @tc.expected: ret == 0
557     * */
558    constexpr char testId1[] = "App running unique test id";
559    ret = DFX_SetAppRunningUniqueId(testId1, 0);
560    ASSERT_EQ(ret, 0);
561
562    /**
563     * @tc.steps: step4.
564     *            case: appRunningId != nullptr, len= strleng(appRunningId)
565     * @tc.expected: ret == 0
566     * */
567    ret = DFX_SetAppRunningUniqueId(testId1, strlen(testId1));
568    ASSERT_EQ(ret, 0);
569
570    /**
571     * @tc.steps: step5.
572     *            case: appRunningId != nullptr, len= MAX_APP_RUNNING_UNIQUE_ID_LEN + 1
573     * @tc.expected: ret == -1
574     * */
575    constexpr size_t testLen = MAX_APP_RUNNING_UNIQUE_ID_LEN + 1;
576    ret = DFX_SetAppRunningUniqueId(testId1, testLen);
577    ASSERT_EQ(ret, -1);
578
579    /**
580     * @tc.steps: step6.
581     *            case: appRunningId != nullptr, len= MAX_APP_RUNNING_UNIQUE_ID_LEN
582     * @tc.expected: ret == 0
583     * */
584    constexpr char testId2[MAX_APP_RUNNING_UNIQUE_ID_LEN] = "App running unique test id";
585    ret = DFX_SetAppRunningUniqueId(testId2, MAX_APP_RUNNING_UNIQUE_ID_LEN);
586    ASSERT_EQ(ret, -1);
587}
588
589/**
590 * @tc.name: SignalHandlerTest016
591 * @tc.desc: test ReportException
592 * @tc.type: FUNC
593 */
594HWTEST_F(SignalHandlerTest, SignalHandlerTest016, TestSize.Level2)
595{
596    GTEST_LOG_(INFO) << "SignalHandlerTest016: start.";
597    if (SetAsyncStackCallbackFunc != nullptr) {
598        SetAsyncStackCallbackFunc(reinterpret_cast<void*>(TestCallbackFunc));
599    }
600
601    struct CrashDumpException exception;
602    exception.pid = 1;
603    exception.uid = 1;
604    exception.error = CRASH_SIGNAL_EMASKED;
605    int ret = ReportException(exception);
606    ASSERT_NE(ret, -1);
607    GTEST_LOG_(INFO) << "SignalHandlerTest016: end.";
608}
609} // namespace HiviewDFX
610} // namepsace OHOS
611