1# Subscribing to Main Thread Jank Events (C/C++)
2
3## Available APIs
4
5For details about how to use the APIs (such as parameter usage restrictions and value ranges), see [HiAppEvent](../reference/apis-performance-analysis-kit/_hi_app_event.md#hiappevent).
6
7**Subscription APIs**
8
9| API                                                      | Description                                        |
10| ------------------------------------------------------------ | -------------------------------------------- |
11| int OH_HiAppEvent_AddWatcher(HiAppEvent_Watcher *watcher)   | Adds a watcher to listen for application events.|
12| int OH_HiAppEvent_RemoveWatcher(HiAppEvent_Watcher *watcher)| Removes a watcher to unsubscribe from application events.|
13
14## How to Develop
15
161. Create a native C++ project and import the **jsoncpp** file to the project. The directory structure is as follows:
17
18   ```yml
19   entry:
20     src:
21       main:
22         cpp:
23           - json:
24               - json.h
25               - json-forwards.h
26           - types:
27               libentry:
28                 - index.d.ts
29           - CMakeLists.txt
30           - napi_init.cpp
31           - jsoncpp.cpp
32         ets:
33           - entryability:
34               - EntryAbility.ets
35           - pages:
36               - Index.ets
37   ```
38
392. In the **CMakeLists.txt** file, add the source file and dynamic libraries.
40
41   ```cmake
42   # Add the jsoncpp.cpp file, which is used to parse the JSON strings in the subscription events.
43   add_library(entry SHARED napi_init.cpp jsoncpp.cpp)
44   # Add libhiappevent_ndk.z.so and libhilog_ndk.z.so (log output). 
45   target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so libhiappevent_ndk.z.so)
46   ```
47
483. Import the dependencies to the **napi_init.cpp** file, and define **LOG_TAG**.
49
50   ```c++
51   # include "json/json.h"
52   # include "hilog/log.h"
53   # include "hiappevent/hiappevent.h"
54   # include "hiappevent/hiappevent_event.h"
55   # undef LOG_TAG
56   # define LOG_TAG "testTag"
57   ```
58
594. Subscribe to application events.
60
61    - Watcher of the onReceive type.
62
63      In the **napi_init.cpp** file, define the methods related to the watcher of the onReceive type.
64
65      ```c++
66      // Define a variable to cache the pointer to the created watcher.
67      static HiAppEvent_Watcher *systemEventWatcher; 
68
69      static void OnReceive(const char *domain, const struct HiAppEvent_AppEventGroup *appEventGroups, uint32_t groupLen) {
70          for (int i = 0; i < groupLen; ++i) {
71              for (int j = 0; j < appEventGroups[i].infoLen; ++j) {
72                  OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.domain=%{public}s",
73                              appEventGroups[i].appEventInfos[j].domain);
74                  OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.name=%{public}s",
75                              appEventGroups[i].appEventInfos[j].name);
76                  OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.eventType=%{public}d",
77                              appEventGroups[i].appEventInfos[j].type);
78                  if (strcmp(appEventGroups[i].appEventInfos[j].domain, DOMAIN_OS) == 0 &&
79                      strcmp(appEventGroups[i].appEventInfos[j].name, EVENT_MAIN_THREAD_JANK) == 0) {
80                      Json::Value params;
81                      Json::Reader reader(Json::Features::strictMode());
82                      Json::FastWriter writer;
83                      if (reader.parse(appEventGroups[i].appEventInfos[j].params, params)) {
84                          auto time = params["time"].asInt64();
85                          auto pid = params["pid"].asInt();
86                          auto uid = params["uid"].asInt();
87                          auto bundleName = params["bundle_name"].asString();
88                          auto bundleVersion = params["bundle_version"].asString();
89                          auto beginTime = params["begin_time"].asInt64();
90                          auto endTime = params["end_time"].asInt64();
91                          auto externalLogSize = params["external_log"].size();
92                          auto logOverLimit = params["logOverLimit"].asBool();
93                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.time=%{public}lld", time);
94                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.pid=%{public}d", pid);
95                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.uid=%{public}d", uid);
96                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.bundle_name=%{public}s",
97                                      bundleName.c_str());
98                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.bundle_version=%{public}s",
99                                      bundleVersion.c_str());
100                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.begin_time=%{public}lld", beginTime);
101                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.end_time=%{public}lld", endTime);
102                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.external_log=%{public}d",
103                                      externalLogSize);
104                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.log_over_limit=%{public}d",
105                                      logOverLimit);
106                      }
107                  }
108              }
109          }
110      }
111
112      static napi_value RegisterWatcher(napi_env env, napi_callback_info info) {
113          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent RegisterWatcher");
114          // Set the watcher name. The system identifies different watchers based on their names.
115          systemEventWatcher = OH_HiAppEvent_CreateWatcher("onReceiverWatcher");
116          // Set the event type to EVENT_MAIN_THREAD_JANK.
117          const char *names[] = {EVENT_MAIN_THREAD_JANK};
118          // Add the events to watch, for example, system events.
119          OH_HiAppEvent_SetAppEventFilter(systemEventWatcher, DOMAIN_OS, 0, names, 1);
120          // Set the implemented callback. After receiving the event, the watcher immediately triggers the OnReceive callback.
121          OH_HiAppEvent_SetWatcherOnReceive(systemEventWatcher, OnReceive);
122          // Add a watcher to listen for the specified event.
123          OH_HiAppEvent_AddWatcher(systemEventWatcher);
124          return {};
125      }	  
126      ```
127    
1285. Register **RegisterWatcher** as an ArkTS API.
129
130   In the **napi_init.cpp** file, register **RegisterWatcher** as an ArkTS API.
131
132   ```c++
133   static napi_value Init(napi_env env, napi_value exports)
134   {
135       napi_property_descriptor desc[] = {
136           { "registerWatcher", nullptr, RegisterWatcher, nullptr, nullptr, nullptr, napi_default, nullptr }
137       };
138       napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
139       return exports;
140   }
141   ```
142
143   In the **index.d.ts** file, define the ArkTS API.
144
145   ```typescript
146   export const registerWatcher: () => void;
147   ```
148
1496. In the **entry/src/main/ets/entryability/EntryAbility.ets** file, add the following interface invocation to **onCreate()**.
150
151   ```typescript
152   // Import the dependent module.
153   import testNapi from 'libentry.so'
154
155   // Add the interface invocation to onCreate().
156   // Register the system event watcher at startup.
157   testNapi.registerWatcher();
158   ```
159
1607. In the **entry/src/main/ets/pages/Index.ets** file, add the **timeOut500** button with **onClick()** to trigger a main thread jank event when the button is clicked. The sample code is as follows:
161   ```typescript
162      Button("timeOut350")
163      .fontSize(50)
164      .fontWeight(FontWeight.Bold)
165      .onClick(() => {
166          let t = Date.now();
167          while (Date.now() - t <= 350){
168          
169          }
170      })
171   ```
172
1738. If the nolog version is used and the developer mode is disabled, the main thread checker will collect tracing data when a task times out.
174
1759. In DevEco Studio, click the **Run** button to run the application project. Click the **timeOut350** button twice consecutively to trigger a main thread jank event.
176
17710. After the main thread jank event is reported, you can view the following event information in the **Log** window.
178
179    ```text
180      HiAppEvent eventInfo.domain=OS
181      HiAppEvent eventInfo.name=MAIN_THREAD_JANK
182      HiAppEvent eventInfo.eventType=1
183      HiAppEvent eventInfo.params.time=1717597063727
184      HiAppEvent eventInfo.params.pid=45572
185      HiAppEvent eventInfo.params.uid=20020151
186      HiAppEvent eventInfo.params.bundle_name=com.example.nativemainthread
187      HiAppEvent eventInfo.params.bundle_version=1.0.0
188      HiAppEvent eventInfo.params.begin_time=1717597063225
189      HiAppEvent eventInfo.params.end_time=1717597063727
190      HiAppEvent eventInfo.params.external_log=1
191      HiAppEvent eventInfo.params.log_over_limit=0
192    ```
193
194    > **NOTE**
195    > For details, see [Main Thread Jank Event Time Specifications](./hiappevent-watcher-mainthreadjank-events-arkts.md#main-thread-jank-event-time-specifications) and [Main Thread Jank Event Specifications](./hiappevent-watcher-mainthreadjank-events-arkts.md#main-thread-jank-event-specifications).
196
19711. Remove the application event watcher.
198
199    ```c++
200    static napi_value RemoveWatcher(napi_env env, napi_callback_info info) {
201        // Remove the watcher.
202        OH_HiAppEvent_RemoveWatcher(systemEventWatcher);
203        return {};
204    }
205    ```
206
20712. Destroy the application event watcher.
208
209    ```c++
210    static napi_value DestroyWatcher(napi_env env, napi_callback_info info) {
211        // Destroy the created watcher and set systemEventWatcher to nullptr.
212        OH_HiAppEvent_DestroyWatcher(systemEventWatcher);
213        systemEventWatcher = nullptr;
214        return {};
215    }
216    ```
217
218<!--no_check-->