1# Subscribing to Crash 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> **NOTE**
8>
9> The C/C++ APIs can be used to subscribe to JsError and NativeCrash events.
10
11**Subscription APIs**
12
13| API                                                      | Description                                        |
14| ------------------------------------------------------------ | -------------------------------------------- |
15| int OH_HiAppEvent_AddWatcher(HiAppEvent_Watcher \*watcher)   | Adds a watcher to listen for application events.|
16| int OH_HiAppEvent_RemoveWatcher (HiAppEvent_Watcher \*watcher) | Removes a watcher to unsubscribe from application events.|
17
18## How to Develop
19
20The following describes how to subscribe to the crash event triggered by a button click.
21
221. Create a native C++ project and import the **jsoncpp** file to the project. The directory structure is as follows:
23
24   ```yml
25   entry:
26     src:
27       main:
28         cpp:
29           - json:
30               - json.h
31               - json-forwards.h
32           - types:
33               libentry:
34                 - index.d.ts
35           - CMakeLists.txt
36           - napi_init.cpp
37           - jsoncpp.cpp
38         ets:
39           - entryability:
40               - EntryAbility.ets
41           - pages:
42               - Index.ets
43   ```
44
452. In the **CMakeLists.txt** file, add the source file and dynamic libraries.
46
47   ```cmake
48   # Add the jsoncpp.cpp file, which is used to parse the JSON strings in the subscription events.
49   add_library(entry SHARED napi_init.cpp jsoncpp.cpp)
50   # Add libhiappevent_ndk.z.so and libhilog_ndk.z.so (log output).
51   target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so libhiappevent_ndk.z.so)
52   ```
53
543. Import the dependency files to the **napi_init.cpp** file, and define **LOG_TAG**.
55
56   ```c++
57   #include "napi/native_api.h"
58   #include "json/json.h"
59   #include "hilog/log.h"
60   #include "hiappevent/hiappevent.h"
61
62   #undef LOG_TAG
63   #define LOG_TAG "testTag"
64   ```
65
664. Subscribe to system events.
67
68   - Watcher of the onReceive type:
69
70     In the **napi_init.cpp** file, define the methods related to the watcher of the onReceive type.
71
72     ```c++
73     // Define a variable to cache the pointer to the created watcher.
74     static HiAppEvent_Watcher *systemEventWatcher;
75
76     static void OnReceive(const char *domain, const struct HiAppEvent_AppEventGroup *appEventGroups, uint32_t groupLen) {
77         for (int i = 0; i < groupLen; ++i) {
78             for (int j = 0; j < appEventGroups[i].infoLen; ++j) {
79                 OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.domain=%{public}s", appEventGroups[i].appEventInfos[j].domain);
80                 OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.name=%{public}s", appEventGroups[i].appEventInfos[j].name);
81                 OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.eventType=%{public}d", appEventGroups[i].appEventInfos[j].type);
82                 if (strcmp(appEventGroups[i].appEventInfos[j].domain, DOMAIN_OS) == 0 &&
83                     strcmp(appEventGroups[i].appEventInfos[j].name, EVENT_APP_CRASH) == 0) {
84                     Json::Value params;
85                     Json::Reader reader(Json::Features::strictMode());
86                     Json::FastWriter writer;
87                     if (reader.parse(appEventGroups[i].appEventInfos[j].params, params)) {
88                         auto time = params["time"].asInt64();
89                         auto crashType = params["crash_type"].asString();
90                         auto foreground = params["foreground"].asBool();
91                         auto bundleVersion = params["bundle_version"].asString();
92                         auto bundleName = params["bundle_name"].asString();
93                         auto pid = params["pid"].asInt();
94                         auto uid = params["uid"].asInt();
95                         auto uuid = params["uuid"].asString();
96                         auto exception = writer.write(params["exception"]);
97                         auto hilogSize = params["hilog"].size();
98                         auto externalLog = writer.write(params["external_log"]);
99                         auto logOverLimit = params["log_over_limit"].asBool();
100                         OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.time=%{public}lld", time);
101                         OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.crash_type=%{public}s", crashType.c_str());
102                         OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.foreground=%{public}d", foreground);
103                         OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.bundle_version=%{public}s", bundleVersion.c_str());
104                         OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.bundle_name=%{public}s", bundleName.c_str());
105                         OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.pid=%{public}d", pid);
106                         OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.uid=%{public}d", uid);
107                         OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.uuid=%{public}s", uuid.c_str());
108                         OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.exception=%{public}s", exception.c_str());
109                         OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.hilog.size=%{public}d", hilogSize);
110                         OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.external_log=%{public}s", externalLog.c_str());
111                         OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.log_over_limit=%{public}d", logOverLimit);
112                     }
113                 }
114             }
115         }
116     }
117
118     static napi_value RegisterWatcher(napi_env env, napi_callback_info info) {
119         // Set the watcher name. The system identifies different watchers based on their names.
120         systemEventWatcher = OH_HiAppEvent_CreateWatcher("onReceiverWatcher");
121         // Set the event to watch to EVENT_APP_CRASH.
122         const char *names[] = {EVENT_APP_CRASH};
123         // Add the events to watch, for example, system events.
124         OH_HiAppEvent_SetAppEventFilter(systemEventWatcher, DOMAIN_OS, 0, names, 1);
125         // Set the implemented callback. After receiving the event, the watcher immediately triggers the OnReceive callback.
126         OH_HiAppEvent_SetWatcherOnReceive(systemEventWatcher, OnReceive);
127         // Add a watcher to listen for the specified event.
128         OH_HiAppEvent_AddWatcher(systemEventWatcher);
129         return {};
130     }
131     ```
132
133   - Watcher of the onTrigger type:
134
135     In the **napi_init.cpp** file, define the methods related to the watcher of the OnTrigger type.
136
137     ```c++
138     // Define a variable to cache the pointer to the created watcher.
139     static HiAppEvent_Watcher *systemEventWatcher;
140
141     // Implement the callback function used to return the listened events. The content pointed to by the events pointer is valid only in this function.
142     static void OnTake(const char *const *events, uint32_t eventLen) {
143         Json::Reader reader(Json::Features::strictMode());
144         Json::FastWriter writer;
145         for (int i = 0; i < eventLen; ++i) {
146             Json::Value eventInfo;
147             if (reader.parse(events[i], eventInfo)) {
148                 auto domain =  eventInfo["domain_"].asString();
149                 auto name = eventInfo["name_"].asString();
150                 auto type = eventInfo["type_"].asInt();
151                 OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.domain=%{public}s", domain.c_str());
152                 OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.name=%{public}s", name.c_str());
153                 OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.eventType=%{public}d", type);
154                 if (domain ==  DOMAIN_OS && name == EVENT_APP_CRASH) {
155                     auto time = eventInfo["time"].asInt64();
156                     auto crashType = eventInfo["crash_type"].asString();
157                     auto foreground = eventInfo["foreground"].asBool();
158                     auto bundleVersion = eventInfo["bundle_version"].asString();
159                     auto bundleName = eventInfo["bundle_name"].asString();
160                     auto pid = eventInfo["pid"].asInt();
161                     auto uid = eventInfo["uid"].asInt();
162                     auto uuid = eventInfo["uuid"].asString();
163                     auto exception = writer.write(eventInfo["exception"]);
164                     auto hilogSize = eventInfo["hilog"].size();
165                     auto externalLog = writer.write(eventInfo["external_log"]);
166                     auto logOverLimit = eventInfo["log_over_limit"].asBool();
167                     OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.time=%{public}lld", time);
168                     OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.crash_type=%{public}s", crashType.c_str());
169                     OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.foreground=%{public}d", foreground);
170                     OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.bundle_version=%{public}s", bundleVersion.c_str());
171                     OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.bundle_name=%{public}s", bundleName.c_str());
172                     OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.pid=%{public}d", pid);
173                     OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.uid=%{public}d", uid);
174                     OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.uuid=%{public}s", uuid.c_str());
175                     OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.exception=%{public}s", exception.c_str());
176                     OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.hilog.size=%{public}d", hilogSize);
177                     OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.external_log=%{public}s", externalLog.c_str());
178                     OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.log_over_limit=%{public}d", logOverLimit);
179                 }
180             }
181         }
182     }
183
184     // Implement the subscription callback function to apply custom processing to the obtained event logging data.
185     static void OnTrigger(int row, int size) {
186         // After the callback is received, obtain the specified number of received events.
187         OH_HiAppEvent_TakeWatcherData(systemEventWatcher, row, OnTake);
188     }
189
190     static napi_value RegisterWatcher(napi_env env, napi_callback_info info) {
191         // Set the watcher name. The system identifies different watchers based on their names.
192         systemEventWatcher = OH_HiAppEvent_CreateWatcher("onTriggerWatcher");
193         // Set the event to watch to EVENT_APP_CRASH.
194         const char *names[] = {EVENT_APP_CRASH};
195         // Add the events to watch, for example, system events.
196         OH_HiAppEvent_SetAppEventFilter(systemEventWatcher, DOMAIN_OS, 0, names, 1);
197         // Set the implemented callback function. The callback function will be triggered when the conditions set by OH_HiAppEvent_SetTriggerCondition are met.
198         OH_HiAppEvent_SetWatcherOnTrigger(systemEventWatcher, OnTrigger);
199         // Set the conditions for triggering the subscription callback. For example, trigger this onTrigger callback when the number of new event logs is 1.
200         OH_HiAppEvent_SetTriggerCondition(systemEventWatcher, 1, 0, 0);
201         // Add a watcher to listen for the specified event.
202         OH_HiAppEvent_AddWatcher(systemEventWatcher);
203         return {};
204     }
205     ```
206
2075. Register **RegisterWatcher** as an ArkTS API.
208
209   In the **napi_init.cpp** file, register **RegisterWatcher** as an ArkTS API.
210
211   ```c++
212   static napi_value Init(napi_env env, napi_value exports)
213   {
214       napi_property_descriptor desc[] = {
215           { "registerWatcher", nullptr, RegisterWatcher, nullptr, nullptr, nullptr, napi_default, nullptr }
216       };
217       napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
218       return exports;
219   }
220   ```
221
222   In the **index.d.ts** file, define ArkTS APIs.
223
224   ```typescript
225   export const registerWatcher: () => void;
226   ```
227
2286. In the **EntryAbility.ets** file, add the following API to **onCreate()**.
229
230   ```typescript
231   // Import the dependent module.
232   import testNapi from 'libentry.so'
233
234   // Add the API to onCreate().
235   // Register the system event watcher at startup.
236   testNapi.registerWatcher();
237   ```
238
2397. In the **Index.ets** file, add a button to trigger the crash event.
240
241   ```typescript
242   Button("appCrash").onClick(() => {
243     JSON.parse("");
244   })
245   ```
246
2478. In DevEco Studio, click the **Run** button to run the project. Then, click the **appCrash** button to trigger a crash event. After a crash occurs, the system uses different stack backtracking methods to generate crash logs based on the crash type (JsError or NativeCrash) and then invokes callback. The NativeCrash stack backtracking takes about 2s. In practice, the duration depends on the number of service threads and the duration of inter-process communication. JsError triggers in-process stack backtracking, and NativeCrash triggers out-of-process stack backtracking. Therefore, NativeCrash stack backtracking is more time-consuming than JsError stack backtracking. You can subscribe to crash events so that the stack backtracking result is asynchronously reported without blocking the current service.
248
2499. When the application is started next time, HiAppEvent reports the crash event to the registered watcher. You can view the processing logs of system event data in the **Log** window.
250
251   ```text
252   HiAppEvent eventInfo.domain=OS
253   HiAppEvent eventInfo.name=APP_CRASH
254   HiAppEvent eventInfo.eventType=1
255   HiAppEvent eventInfo.params.time=1502032265088
256   HiAppEvent eventInfo.params.crash_type=JsError
257   HiAppEvent eventInfo.params.foreground=1
258   HiAppEvent eventInfo.params.bundle_version=1.0.0
259   HiAppEvent eventInfo.params.bundle_name=com.example.myapplication
260   HiAppEvent eventInfo.params.pid=19237
261   HiAppEvent eventInfo.params.uid=20010043
262   HiAppEvent eventInfo.params.uuid=cc0f062e1b28c1fd2c817fafab5e8ca3207925b4bdd87c43ed23c60029659e01
263   HiAppEvent eventInfo.params.exception={"message":"Unexpected Text in JSON","name":"SyntaxError","stack":"at anonymous (entry/src/main/ets/pages/Index.ets:16:11)"}
264   HiAppEvent eventInfo.params.hilog.size=110
265   HiAppEvent eventInfo.params.external_log=["/data/storage/el2/log/hiappevent/APP_CRASH_1502032265211_19237.log"]
266   HiAppEvent eventInfo.params.log_over_limit=0
267   ```
268
26910. Remove the event watcher.
270
271    ```c++
272    static napi_value RemoveWatcher(napi_env env, napi_callback_info info) {
273        // Remove the watcher.
274        OH_HiAppEvent_RemoveWatcher(systemEventWatcher);
275        return {};
276    }
277    ```
278
27911. Destroy the event watcher.
280
281    ```c++
282    static napi_value DestroyWatcher(napi_env env, napi_callback_info info) {
283        // Destroy the created watcher and set systemEventWatcher to nullptr.
284        OH_HiAppEvent_DestroyWatcher(systemEventWatcher);
285        systemEventWatcher = nullptr;
286        return {};
287    }
288    ```
289