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