• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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