# Using HiCollie (C/C++) HiCollie provides APIs for detecting service thread stuck and jank events and reporting service thread stuck events. ## Available APIs | API | Description | | ------------------------------- | --------------------------------- | | OH_HiCollie_Init_StuckDetection | Registers a callback to periodically detect service thread stuck events. | | OH_HiCollie_Init_JankDetection | Registers a callback to detect service thread jank events. To monitor service thread jank events, you can implement two callbacks as instrumentation functions, placing them before and after the service thread processes the event. | | OH_HiCollie_Report | Reports service thread stuck events and generates timeout logs to help locate application timeout events. This API is used together with **OH_HiCollie_Init_StuckDetection()**, which initializes the stuck event detection at first, and then **OH_HiCollie_Report()** reports the stuck event when it occurs. | For details about how to use the APIs (such as parameter usage restrictions and value ranges), see [HiCollie](../reference/apis-performance-analysis-kit/_hi_hicollie.md). ## How to Develop The following describes how to add a button in the application and click the button to call the HiCollie APIs. 1. Create a native C++ project and import the **jsoncpp** file to the project. The directory structure is as follows: ```yml entry: src: main: cpp: - types: libentry: - index.d.ts - CMakeLists.txt - napi_init.cpp ets: - entryability: - EntryAbility.ts - pages: - Index.ets ``` 2. In the **CMakeLists.txt** file, add the source file and dynamic libraries. ```cmake # Add libhilog_ndk.z.so (log output). target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so libohhicollie.so) ``` 3. Import the dependencies to the **napi_init.cpp** file, and define **LOG_TAG** and the test method. ```c++ # include "napi/native_api.h" # include "hilog/log.h" # include "hicollie/hicollie.h" # include # include # include # include # undef LOG_TAG # define LOG_TAG "testTag" static OH_HiCollie_BeginFunc beginFunc_; // Define the callback object used before the processing event. static OH_HiCollie_EndFunc endFunc_; // Define the callback object used after the processing event. HiCollie_DetectionParam param {.sampleStackTriggerTime = 150, .reserved = 0}; // Define the struct. int64_t lastWatchTime = 0; // Record the last detection time. const int64_t CHECK_INTERNAL_TIME = 3000; // Set the detection interval. std::shared_ptr> isReport = std::make_shared>(false); // Set the flag for reporting stuck events. int count = 0; // Record the first initialization. bool needReport = false; // Set whether to report the stuck events. // Define the callback. void InitBeginFunc(const char* eventName) { std::string str(eventName); OH_LOG_INFO(LogType::LOG_APP, "InitBeginFunc eventName: %{public}s", str.c_str()); } void InitEndFunc(const char* eventName) { std::string str(eventName); OH_LOG_INFO(LogType::LOG_APP, "OH_HiCollie_EndFunc eventName: %{public}s", str.c_str()); } // Define the callback of the subthread. void TestJankDetection() { beginFunc_ = InitBeginFunc; // Initialize the callback. endFunc_ = InitEndFunc; int initResult = OH_HiCollie_Init_JankDetection(&beginFunc_, &endFunc_, param); // Initialize the function for detecting thread jank events. OH_LOG_INFO(LogType::LOG_APP, "OH_HiCollie_Init_JankDetection: %{public}d", initResult); // Display the success result 0. int count = 0; while (count < 2) { beginFunc_("TestBegin"); // Set the callback used to record the start time of the processing event. usleep(350 * 1000); // Simulate a thread stuck event by putting the thread to sleep for 350 ms. endFunc_("TestEnd"); // Set the callback used to record the end time of the processing event. count++; } } static napi_value TestHiCollieJankNdk(napi_env env, napi_callback_info info) { std::thread threadObj(TestJankDetection); // Create a subthread. threadObj.join(); // Execute the callback. return 0; } int64_t GetCurrentTime() { return std::chrono::duration_cast(std::chrono:: system_clock::now().time_since_epoch()).count(); } bool ReportEvent() { if ((GetCurrentTime() - lastWatchTime) > CHECK_INTERNAL_TIME) { return true; } return false; } void TestTask() { if (needReport && ReportEvent()) { bool temp = isReport->load(); int reportResult = OH_HiCollie_Report(&temp); OH_LOG_INFO(LogType::LOG_APP, "OH_HiCollie_Report: %{public}d", reportResult); // Return 0 if the function is initialized successfully. OH_LOG_INFO(LogType::LOG_APP, "OH_HiCollie_Report isReport: %{public}d", temp); needReport = false; } int64_t now = GetCurrentTime(); if ((now - lastWatchTime) >= (CHECK_INTERNAL_TIME / 2)) { lastWatchTime = now; } } // Define the callback of the subthread. void TestStuckDetection() { int initResult = -1; if(count == 0) { initResult = OH_HiCollie_Init_StuckDetection(TestTask); // Initialize the function for detecting thread stuck events. OH_LOG_INFO(LogType::LOG_APP, "OH_HiCollie_Init_StuckDetection: %{public}d", initResult); // Display the success result 0. count++; } } static napi_value TestHiCollieStuckNdk(napi_env env, napi_callback_info info) { std::thread threadObj(TestStuckDetection); // Create a subthread. threadObj.join(); // Execute the callback. return 0; } ``` 4. Register **TestHiCollieNdk** as an ArkTS API. In the **napi_init.cpp** file, register **TestHiCollieNdk** as an ArkTS API. ```c++ static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor desc[] = { { "testHiCollieJankNdk", nullptr, TestHiCollieJankNdk, nullptr, nullptr, nullptr, napi_default, nullptr }, { "testHiCollieStuckNdk", nullptr, TestHiCollieStuckNdk, nullptr, nullptr, nullptr, napi_default, nullptr }}; }; napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); return exports; } ``` In the **index.d.ts** file, define the ArkTS API. ```typescript export const testHiCollieJankNdk: () => void; export const testHiCollieStuckNdk: () => void; ``` 5. Edit the **Index.ets** file. ```ts import testNapi from 'libentry.so' @Entry @Component struct Index { @State message: string = 'Hello World' build() { Row() { Column() { Button("testHiCollieJankNdk") .fontSize(50) .fontWeight(FontWeight.Bold) .onClick(testNapi.testHiCollieJankNdk);// Add a click event to trigger testHiCollieJankNdk(). Button("testHiCollieStuckNdk") .fontSize(50) .fontWeight(FontWeight.Bold) .onClick(testNapi.testHiCollieStuckNdk);// Add a click event to trigger testHiCollieStuckNdk(). } .width('100%') } .height('100%') } } ``` 6. Click the **Run** button in DevEco Studio to run the project. 7. At the bottom of DevEco Studio, switch to the **Log** tab and set the filter criteria to **testTag**. (1) Click the **testHiCollieJankNdk** button after the thread processed the event for 10s. The thread timeout information of the sampling stack obtained through **OH_HiCollie_Init_JankDetection()** is displayed. The path of the sampling stack: **/data/app/el2/100/log/application bundle name/watchdog/BUSSINESS_THREAD_JANK_XXX.txt.** (2) Click the **testHiCollieStuckNdk** button. The callback used for detecting stuck event is initialized through **OH_HiCollie_Init_StuckDetection()**. You can define the detection function for stuck events as required.