1# Subscribing to Main Thread Jank Events (ArkTS) 2 3## Main Thread Jank Event Specifications 4 5For details, see [Main Thread Jank Event Overview](./hiappevent-watcher-mainthreadjank-events.md). 6 7## Available APIs 8 9For details about how to use the APIs, see [Application Event Logging](../reference/apis-performance-analysis-kit/js-apis-hiviewdfx-hiappevent.md). 10 11| API | Description | 12| --------------------------------------------------- | -------------------------------------------- | 13| addWatcher(watcher: Watcher): AppEventPackageHolder | Adds a watcher to listen for application events.| 14| removeWatcher(watcher: Watcher): void | Removes a watcher to unsubscribe from application events.| 15 16## How to Develop 17 18The following describes how to subscribe to the main thread jank event in sampling stack, which is reported when a task running in the main thread times out. 19 201. Create an ArkTS application project. In the **entry/src/main/ets/entryability/EntryAbility.ets** file, import the dependent modules. 21 22 ```ts 23 import { hiAppEvent } from '@kit.PerformanceAnalysisKit'; 24 ``` 25 262. In the **entry/src/main/ets/entryability/EntryAbility.ets** file, add a watcher in **onForeground()** to subscribe to system events. The sample code is as follows: 27 28 ```ts 29 hiAppEvent.addWatcher({ 30 // Set the watcher name. The system identifies different watchers based on their names. 31 name: "watcher", 32 // Add the system events to watch, for example, the main thread jank event. 33 appEventFilters: [ 34 { 35 domain: hiAppEvent.domain.OS, 36 names: [hiAppEvent.event.MAIN_THREAD_JANK] 37 } 38 ], 39 // Implement a callback for the registered system event so that you can apply custom processing to the event data obtained. 40 onReceive: (domain: string, appEventGroups: Array<hiAppEvent.AppEventGroup>) => { 41 hilog.info(0x0000, 'testTag', `HiAppEvent onReceive: domain=${domain}`); 42 for (const eventGroup of appEventGroups) { 43 // The event name uniquely identifies a system event. 44 hilog.info(0x0000, 'testTag', `HiAppEvent eventName=${eventGroup.name}`); 45 for (const eventInfo of eventGroup.appEventInfos) { 46 // Apply custom processing to the event data obtained, for example, print the event data in the log. 47 hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.domain=${eventInfo.domain}`); 48 hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.name=${eventInfo.name}`); 49 hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.eventType=${eventInfo.eventType}`); 50 // Obtain the timestamp when the main thread jank event occurs. 51 hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.time=${eventInfo.params['time']}`); 52 // Obtain the version information of the application. 53 hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.bundle_version=${eventInfo.params['bundle_version']}`); 54 // Obtain the bundle name of the application. 55 hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.bundle_name=${eventInfo.params['bundle_name']}`); 56 // Obtain the PID and UID of the application. 57 hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.pid=${eventInfo.params['pid']}`); 58 hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.uid=${eventInfo.params['uid']}`); 59 // Obtain the begin time and end time on the main thread. 60 hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.begin_time=${eventInfo.params['begin_time']}`); 61 hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.end_time=${eventInfo.params['end_time']}`); 62 // Obtain the error log file generated when the main thread jank event occurs. 63 hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.external_log=${JSON.stringify(eventInfo.params['external_log'])}`); 64 hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.log_over_limit=${eventInfo.params['log_over_limit']}`); 65 // Obtain the start time of the task when the main thread jank event occurs. 66 hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.app_start_jiffies_time=${JSON.stringify(eventInfo.params['app_start_jiffies_time'])}`); 67 // Obtain the call stack that is printed most frequently in the generated log file. 68 hilog.info(0x0000, 'testTag', `HiAppEvent eventInfo.params.heaviest_stack=${eventInfo.params['heaviest_stack']}`); 69 } 70 } 71 } 72 }); 73 ``` 74 753. (Optional) Simulate a main thread jank event. 76 Edit the **entry > src > main > ets > pages> Index.ets** file in the project. 77 78 ```ts 79 @Entry 80 @Component 81 struct Index { 82 build() { 83 RelativeContainer() { 84 Column() { 85 Button("timeOut350", { stateEffect:true, type: ButtonType.Capsule}) 86 .width('75%') 87 .height(50) 88 .margin(15) 89 .fontSize(20) 90 .fontWeight(FontWeight.Bold) 91 .onClick(() => { 92 let t = Date.now(); 93 while (Date.now() - t <= 350) {} 94 }) 95 }.width('100%') 96 } 97 .height('100%') 98 .width('100%') 99 } 100 } 101 ``` 102 1034. (Optional) Simulate the scenario where the custom sampling stack parameters are used and the main thread jank event is triggered. 104 105 Edit the **entry > src > main > ets > pages> Index.ets** file in the project. In this example, a **customSample** button component is configured in **onClick()** to implement the custom sampling stack parameters. The sample code is as follows: 106 107 ```ts 108 import { hiAppEvent, hilog } from '@kit.PerformanceAnalysisKit'; 109 import { BusinessError } from '@kit.BasicServicesKit'; 110 111 // Simulate a main thread jank event. 112 function wait150ms() { 113 let t = Date.now(); 114 while (Date.now() - t <= 150){ 115 } 116 } 117 118 function wait500ms() { 119 let t = Date.now(); 120 while (Date.now() - t <= 500){ 121 } 122 } 123 124 @Entry 125 @Component 126 struct Index { 127 build() { 128 RelativeContainer() { 129 Column() { 130 // Set the button for setting custom sampling stack parameters. 131 Button("customSample", { stateEffect:true, type: ButtonType.Capsule}) 132 .width('75%') 133 .height(50) 134 .margin(15) 135 .fontSize(20) 136 .fontWeight(FontWeight.Bold) 137 .onClick(() => { 138 // Log a button onclick event when the button is clicked. 139 let params: Record<string, hiAppEvent.ParamType> = { 140 // The log type. The value 0 indicates the default value. The value 1 indicates that only the stack is sampled. The value 2 indicates that only the trace is collected. 141 "log_type": "1", 142 // The sampling interval. 143 "sample_interval": "100", 144 // The startup time to be ignored. 145 "ignore_startup_time": "11", 146 // Sampling count. 147 "sample_count": "21", 148 // The number of event reporting times. 149 "report_times_per_app": "3", 150 }; 151 hiAppEvent.setEventConfig(hiAppEvent.event.MAIN_THREAD_JANK, params).then(() => { 152 hilog.info(0x0000, 'testTag', `HiAppEvent success to set event params.`) 153 }).catch((err: BusinessError) => { 154 hilog.error(0x0000, 'testTag', `HiAppEvent err.code: ${err.code}, err.message: ${err.message}`) 155 }); 156 }) 157 // The button for triggering the event that times out for 150 ms. 158 Button("timeOut150", { stateEffect:true, type: ButtonType.Capsule}) 159 .width('75%') 160 .height(50) 161 .margin(15) 162 .fontSize(20) 163 .fontWeight(FontWeight.Bold) 164 .onClick(() => { 165 wait150ms(); 166 }) 167 // The button for triggering the event that times out for 500 ms. 168 Button("timeOut500", { stateEffect:true, type: ButtonType.Capsule}) 169 .width('75%') 170 .height(50) 171 .margin(15) 172 .fontSize(20) 173 .fontWeight(FontWeight.Bold) 174 .onClick(() => { 175 wait500ms(); 176 }) 177 }.width('100%') 178 } 179 .height('100%') 180 .width('100%') 181 } 182 } 183 ``` 184 1855. In DevEco Studio, click the **Run** button to run the application project. Click the button twice consecutively to trigger a main thread jank event. 186 1876. After the main thread jank event is reported, the system calls **onReceive()**. You can view the following event information in the **Log** window. 188 189 Tracing data of the main thread jank event is as follows: 190 191 ```text 192 HiAppEvent eventInfo.domain=OS 193 HiAppEvent eventInfo.name=MAIN_THREAD_JANK 194 HiAppEvent eventInfo.eventType=1 195 HiAppEvent eventInfo.params.time=1717593620518 196 HiAppEvent eventInfo.params.bundle_version=1.0.0 197 HiAppEvent eventInfo.params.bundle_name=com.example.main_thread_jank 198 HiAppEvent eventInfo.params.pid=40986 199 HiAppEvent eventInfo.params.uid=20020150 200 HiAppEvent eventInfo.params.begin_time=1717593620016 201 HiAppEvent eventInfo.params.end_time=1717593620518 202 HiAppEvent eventInfo.params.external_log=["/data/storage/el2/log/watchdog/MAIN_THREAD_JANK_20240613211739_40986.txt"] 203 HiAppEvent eventInfo.params.log_over_limit=false 204 HiAppEvent eventInfo.params.app_start_jiffies_time=XXXX 205 HiAppEvent eventInfo.params.heaviest_stack=XXXX 206 ``` 207 208 The sampling stack of the main thread jank event is similar to the trace result. The differences are as follows: 209 210 ```text 211 Stack: 212 The app_start_jiffies_time and heaviest_stack parameters are added to the sampling stack. 213 external_log=["/data/storage/el2/log/watchdog/MAIN_THREAD_JANK_yyyyMMDDHHmmss_xxxx.txt"]. xxxx indicates the process ID. 214 215 Trace: 216 external_log=[""/data/storage/el2/log/watchdog/MAIN_THREAD_JANK_unix timestamp_xxxx.trace"]. xxxx indicates the process ID. 217 ``` 218