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