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