1# Using HiCollie (C/C++)
2
3HiCollie provides APIs for detecting service thread stuck and jank events and reporting service thread stuck events.
4
5## Available APIs
6| API                         | Description                             |
7| ------------------------------- | --------------------------------- |
8| OH_HiCollie_Init_StuckDetection | Registers a callback to periodically detect service thread stuck events.           |
9| 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.                  |
10| 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.   |
11
12
13For 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).
14
15## How to Develop
16The following describes how to add a button in the application and click the button to call the HiCollie APIs.
17
181. Create a native C++ project and import the **jsoncpp** file to the project. The directory structure is as follows:
19
20   ```yml
21   entry:
22     src:
23       main:
24         cpp:
25           - types:
26               libentry:
27                 - index.d.ts
28           - CMakeLists.txt
29           - napi_init.cpp
30         ets:
31           - entryability:
32               - EntryAbility.ts
33           - pages:
34               - Index.ets
35   ```
36
372. In the **CMakeLists.txt** file, add the source file and dynamic libraries.
38
39   ```cmake
40   # Add libhilog_ndk.z.so (log output).
41   target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so libohhicollie.so)
42   ```
43
443. Import the dependencies to the **napi_init.cpp** file, and define **LOG_TAG** and the test method.
45
46   ```c++
47    # include "napi/native_api.h"
48    # include "hilog/log.h"
49    # include "hicollie/hicollie.h"
50    # include <thread>
51    # include <string>
52    # include <unistd.h>
53    # include <atomic>
54    
55    # undef LOG_TAG
56    # define LOG_TAG "testTag"
57
58    static OH_HiCollie_BeginFunc beginFunc_; // Define the callback object used before the processing event.
59    static OH_HiCollie_EndFunc endFunc_; // Define the callback object used after the processing event.
60    HiCollie_DetectionParam param {.sampleStackTriggerTime = 150, .reserved = 0}; // Define the struct.
61    int64_t lastWatchTime = 0; // Record the last detection time.
62    const int64_t CHECK_INTERNAL_TIME = 3000; // Set the detection interval.
63    std::shared_ptr<std::atomic<bool>> isReport = std::make_shared<std::atomic<bool>>(false); // Set the flag for reporting stuck events.
64    int count = 0; // Record the first initialization.
65    bool needReport = false; // Set whether to report the stuck events.
66
67    // Define the callback.
68    void InitBeginFunc(const char* eventName)
69    {
70        std::string str(eventName);
71        OH_LOG_INFO(LogType::LOG_APP, "InitBeginFunc eventName: %{public}s", str.c_str());
72    }
73    void InitEndFunc(const char* eventName)
74    {
75        std::string str(eventName);
76        OH_LOG_INFO(LogType::LOG_APP, "OH_HiCollie_EndFunc eventName: %{public}s", str.c_str());
77    }
78    // Define the callback of the subthread.
79    void TestJankDetection()
80    {
81        beginFunc_ = InitBeginFunc; // Initialize the callback.
82        endFunc_ = InitEndFunc;
83        int initResult = OH_HiCollie_Init_JankDetection(&beginFunc_, &endFunc_, param); // Initialize the function for detecting thread jank events.
84        OH_LOG_INFO(LogType::LOG_APP, "OH_HiCollie_Init_JankDetection: %{public}d", initResult); // Display the success result 0.
85        int count = 0;
86        while (count < 2) {
87            beginFunc_("TestBegin"); // Set the callback used to record the start time of the processing event.
88            usleep(350 * 1000); // Simulate a thread stuck event by putting the thread to sleep for 350 ms.
89            endFunc_("TestEnd"); // Set the callback used to record the end time of the processing event.
90            count++;
91        }
92    }
93
94    static napi_value TestHiCollieJankNdk(napi_env env, napi_callback_info info)
95    {
96        std::thread threadObj(TestJankDetection); // Create a subthread.
97        threadObj.join(); // Execute the callback.
98        return 0;
99    }
100
101    int64_t GetCurrentTime()
102    {
103      return std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::
104          system_clock::now().time_since_epoch()).count();
105    }
106
107    bool ReportEvent()
108    {
109      if ((GetCurrentTime() - lastWatchTime) > CHECK_INTERNAL_TIME) {
110          return true;
111      }
112      return false;
113    }
114
115    void TestTask()
116    {
117        if (needReport && ReportEvent()) {
118          bool temp = isReport->load();
119          int reportResult = OH_HiCollie_Report(&temp);
120          OH_LOG_INFO(LogType::LOG_APP, "OH_HiCollie_Report: %{public}d", reportResult); // Return 0 if the function is initialized successfully.
121          OH_LOG_INFO(LogType::LOG_APP, "OH_HiCollie_Report isReport: %{public}d", temp);
122          needReport = false;
123        }
124        int64_t now = GetCurrentTime();
125        if ((now - lastWatchTime) >= (CHECK_INTERNAL_TIME / 2)) {
126            lastWatchTime = now;
127        }
128    }
129
130    // Define the callback of the subthread.
131    void TestStuckDetection()
132    {
133        int initResult = -1;
134        if(count == 0) {
135          initResult = OH_HiCollie_Init_StuckDetection(TestTask); // Initialize the function for detecting thread stuck events.
136          OH_LOG_INFO(LogType::LOG_APP, "OH_HiCollie_Init_StuckDetection: %{public}d", initResult); // Display the success result 0.
137          count++;
138        }
139    }
140    static napi_value TestHiCollieStuckNdk(napi_env env, napi_callback_info info)
141    {
142      std::thread threadObj(TestStuckDetection); // Create a subthread.
143      threadObj.join(); // Execute the callback.
144      return 0;
145    }
146   ```
147
1484. Register **TestHiCollieNdk** as an ArkTS API.
149
150   In the **napi_init.cpp** file, register **TestHiCollieNdk** as an ArkTS API.
151
152   ```c++
153    static napi_value Init(napi_env env, napi_value exports)
154    {
155        napi_property_descriptor desc[] = {
156            { "testHiCollieJankNdk", nullptr, TestHiCollieJankNdk, nullptr, nullptr, nullptr, napi_default, nullptr },
157            { "testHiCollieStuckNdk", nullptr, TestHiCollieStuckNdk, nullptr, nullptr, nullptr, napi_default, nullptr }};
158        };
159        napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
160        return exports;
161    }
162   ```
163
164   In the **index.d.ts** file, define the ArkTS API.
165
166   ```typescript
167   export const testHiCollieJankNdk: () => void;
168   export const testHiCollieStuckNdk: () => void;
169   ```
170
1715. Edit the **Index.ets** file.
172
173   ```ts
174   import testNapi from 'libentry.so'
175   
176   @Entry
177   @Component
178   struct Index {
179     @State message: string = 'Hello World'
180   
181     build() {
182       Row() {
183         Column() {
184           Button("testHiCollieJankNdk")
185             .fontSize(50)
186             .fontWeight(FontWeight.Bold)
187             .onClick(testNapi.testHiCollieJankNdk);// Add a click event to trigger testHiCollieJankNdk().
188           Button("testHiCollieStuckNdk")
189             .fontSize(50)
190             .fontWeight(FontWeight.Bold)
191             .onClick(testNapi.testHiCollieStuckNdk);// Add a click event to trigger testHiCollieStuckNdk().
192         }
193         .width('100%')
194       }
195       .height('100%')
196     }
197   }
198   ```
199
2006. Click the **Run** button in DevEco Studio to run the project.
201
2027. At the bottom of DevEco Studio, switch to the **Log** tab and set the filter criteria to **testTag**.
203
204    (1) Click the **testHiCollieJankNdk** button after the thread processed the event for 10s.
205    The thread timeout information of the sampling stack obtained through **OH_HiCollie_Init_JankDetection()** is displayed.
206    The path of the sampling stack: **/data/app/el2/100/log/application bundle name/watchdog/BUSSINESS_THREAD_JANK_XXX.txt.**
207
208    (2) Click the **testHiCollieStuckNdk** button.
209    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.
210
211<!--no_check-->