1# Subscribing to Main Thread Jank Events (ArkTS) 2 3## Overview 4 5This topic describes how to use the ArkTS APIs provided by HiAppEvent to subscribe to main thread jank events. For details about how to use the APIs (such as parameter restrictions and value ranges), see [@ohos.hiviewdfx.hiAppEvent (Application Event Logging)](../reference/apis-performance-analysis-kit/js-apis-hiviewdfx-hiappevent.md). 6 7## Available APIs 8 9| API| Description| 10| -------- | -------- | 11| addWatcher(watcher: Watcher): AppEventPackageHolder | Adds a watcher to listen for application events.| 12| removeWatcher(watcher: Watcher): void | Removes a watcher to unsubscribe from application events.| 13 14## How to Develop 15 16### Adding an Event Watcher 17 18The following describes how to subscribe to the main thread jank event, 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 of the project, import the dependent modules. The sample code is as follows: 21 22 ```ts 23 import { hiAppEvent, hilog } 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. Simulate a main thread jank event. 76 77 Edit the **entry/src/main/ets/pages/Index.ets** file. The sample code is as follows: 78 79 ```ts 80 @Entry 81 @Component 82 struct Index { 83 build() { 84 RelativeContainer() { 85 Column() { 86 Button("timeOut350", { stateEffect:true, type: ButtonType.Capsule}) 87 .width('75%') 88 .height(50) 89 .margin(15) 90 .fontSize(20) 91 .fontWeight(FontWeight.Bold) 92 .onClick(() => { 93 let t = Date.now(); 94 while (Date.now() - t <= 350) {} 95 }) 96 }.width('100%') 97 } 98 .height('100%') 99 .width('100%') 100 } 101 } 102 ``` 103 1044. (Optional) Simulate the customization of the main thread timeout parameter and trigger the main thread jank event. 105 106 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: 107 108 ```ts 109 import { hiAppEvent, hilog } from '@kit.PerformanceAnalysisKit'; 110 import { BusinessError } from '@kit.BasicServicesKit'; 111 112 // Simulate a main thread jank event. 113 function wait150ms() { 114 let t = Date.now(); 115 while (Date.now() - t <= 150){ 116 } 117 } 118 119 function wait500ms() { 120 let t = Date.now(); 121 while (Date.now() - t <= 500){ 122 } 123 } 124 125 @Entry 126 @Component 127 struct Index { 128 build() { 129 RelativeContainer() { 130 Column() { 131 // Set the button for setting custom sampling stack parameters. 132 Button("customSample", { stateEffect:true, type: ButtonType.Capsule}) 133 .width('75%') 134 .height(50) 135 .margin(15) 136 .fontSize(20) 137 .fontWeight(FontWeight.Bold) 138 .onClick(() => { 139 // Log a button onclick event when the button is clicked. 140 let params: Record<string, hiAppEvent.ParamType> = { 141 // 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. 142 "log_type": "1", 143 // The sampling interval. 144 "sample_interval": "100", 145 // The startup time to be ignored. 146 "ignore_startup_time": "11", 147 // Sampling count. 148 "sample_count": "21", 149 // The number of event reporting times. 150 "report_times_per_app": "3" 151 }; 152 hiAppEvent.setEventConfig(hiAppEvent.event.MAIN_THREAD_JANK, params).then(() => { 153 hilog.info(0x0000, 'testTag', `HiAppEvent success to set event params.`) 154 }).catch((err: BusinessError) => { 155 hilog.error(0x0000, 'testTag', `HiAppEvent err.code: ${err.code}, err.message: ${err.message}`) 156 }); 157 }) 158 // The button for triggering the event that times out for 150 ms. 159 Button("timeOut150", { stateEffect:true, type: ButtonType.Capsule}) 160 .width('75%') 161 .height(50) 162 .margin(15) 163 .fontSize(20) 164 .fontWeight(FontWeight.Bold) 165 .onClick(() => { 166 wait150ms(); 167 }) 168 // The button for triggering the event that times out for 500 ms. 169 Button("timeOut500", { stateEffect:true, type: ButtonType.Capsule}) 170 .width('75%') 171 .height(50) 172 .margin(15) 173 .fontSize(20) 174 .fontWeight(FontWeight.Bold) 175 .onClick(() => { 176 wait500ms(); 177 }) 178 }.width('100%') 179 } 180 .height('100%') 181 .width('100%') 182 } 183 } 184 ``` 185 1865. In DevEco Studio, click the **Run** button to run the application project. Click the button twice consecutively to trigger a main thread jank event. 187 188### Verifying the Subscription 189 1901. After the main thread jank event is reported, the system calls **onReceive()**. You can view the following event information in the **Log** window. 191 192 Trace data of the main thread jank event is as follows: 193 194 ```text 195 HiAppEvent eventInfo.domain=OS 196 HiAppEvent eventInfo.name=MAIN_THREAD_JANK 197 HiAppEvent eventInfo.eventType=1 198 HiAppEvent eventInfo.params.time=1717593620518 199 HiAppEvent eventInfo.params.bundle_version=1.0.0 200 HiAppEvent eventInfo.params.bundle_name=com.example.main_thread_jank 201 HiAppEvent eventInfo.params.pid=40986 202 HiAppEvent eventInfo.params.uid=20020150 203 HiAppEvent eventInfo.params.begin_time=1717593620016 204 HiAppEvent eventInfo.params.end_time=1717593620518 205 HiAppEvent eventInfo.params.external_log=["/data/storage/el2/log/watchdog/MAIN_THREAD_JANK_20240613211739_40986.txt"] 206 HiAppEvent eventInfo.params.log_over_limit=false 207 HiAppEvent eventInfo.params.app_start_jiffies_time=XXXX 208 HiAppEvent eventInfo.params.heaviest_stack=XXXX 209 ``` 210 211 The sampling stack of the main thread jank event is similar to the trace result. The differences are as follows: 212 213 ```text 214 Stack: 215 The app_start_jiffies_time and heaviest_stack parameters are added to the sampling stack. 216 external_log=["/data/storage/el2/log/watchdog/MAIN_THREAD_JANK_yyyyMMDDHHmmss_xxxx.txt"]. xxxx indicates the process ID. 217 218 Trace: 219 external_log=[""/data/storage/el2/log/watchdog/MAIN_THREAD_JANK_unix timestamp_xxxx.trace"]. xxxx indicates the process ID. 220 ``` 221