• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Subscribing to Crash Events (C/C++)
2<!--Kit: Performance Analysis Kit-->
3<!--Subsystem: HiviewDFX-->
4<!--Owner: @chenshi51-->
5<!--Designer: @Maplestory-->
6<!--Tester: @yufeifei-->
7<!--Adviser: @foryourself-->
8
9## Overview
10
11The following describes how to subscribe to application crash events by using the C/C++ APIs provided by HiAppEvent. For details, see [hiappevent.h](../reference/apis-performance-analysis-kit/capi-hiappevent-h.md).
12
13> **NOTE**
14>
15> Use the C/C++ APIs to subscribe to the **JsError** and **NativeCrash** events.
16
17## Available APIs
18
19| API| Description|
20| -------- | -------- |
21| int OH_HiAppEvent_AddWatcher(HiAppEvent_Watcher \*watcher) | Adds a watcher to listen for application events.|
22| int OH_HiAppEvent_RemoveWatcher(HiAppEvent_Watcher \*watcher) | Removes a watcher to unsubscribe from application events.|
23
24## How to Develop
25
26### Adding an Event Watcher
27
28After the application starts, add an event watcher before any service logic runs to ensure subscription to crash events. Otherwise, a crash may cause the application to exit, leaving the subscription uncompleted.
29
30The following example describes how to subscribe to a crash event triggered by button clicking.
31
321. Obtain the dependency **jsoncpp** of the sample project.
33
34   Specifically, obtain the **jsoncpp.cpp**, **json.h**, and **json-forwards.h** files by referring to **Amalgamated source** in [JsonCpp](https://github.com/open-source-parsers/jsoncpp).
35
362. Create a native C++ project and import the preceding files to the project. The directory structure is as follows:
37
38   ```yml
39   entry:
40     src:
41       main:
42         cpp:
43           - json:
44               - json.h
45               - json-forwards.h
46           - types:
47               libentry:
48                 - index.d.ts
49           - CMakeLists.txt
50           - napi_init.cpp
51           - jsoncpp.cpp
52         ets:
53           - entryability:
54               - EntryAbility.ets
55           - pages:
56               - Index.ets
57   ```
58
593. In the **CMakeLists.txt** file, add the source file and dynamic libraries.
60
61   ```cmake
62   # Add the jsoncpp.cpp file, which is used to parse the JSON strings in the subscription events.
63   add_library(entry SHARED napi_init.cpp jsoncpp.cpp)
64   # Add libhiappevent_ndk.z.so and libhilog_ndk.z.so (log output).
65   target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so libhiappevent_ndk.z.so)
66   ```
67
684. In the **napi_init.cpp** file, import the dependency files and define **LOG_TAG**.
69
70   ```c++
71   #include "napi/native_api.h"
72   #include "json/json.h"
73   #include "hilog/log.h"
74   #include "hiappevent/hiappevent.h"
75
76   #undef LOG_TAG
77   #define LOG_TAG "testTag"
78   ```
79
805. Subscribe to system events.
81
82   - Watcher of the onReceive type:
83
84      In the **napi_init.cpp** file, define **onReceive()** as follows:
85
86      ```c++
87      // Define a variable to cache the created watcher pointer.
88      static HiAppEvent_Watcher *systemEventWatcher;
89
90      static void OnReceive(const char *domain, const struct HiAppEvent_AppEventGroup *appEventGroups, uint32_t groupLen) {
91          for (int i = 0; i < groupLen; ++i) {
92              for (int j = 0; j < appEventGroups[i].infoLen; ++j) {
93                  OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.domain=%{public}s", appEventGroups[i].appEventInfos[j].domain);
94                  OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.name=%{public}s", appEventGroups[i].appEventInfos[j].name);
95                  OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.eventType=%{public}d", appEventGroups[i].appEventInfos[j].type);
96                  if (strcmp(appEventGroups[i].appEventInfos[j].domain, DOMAIN_OS) == 0 &&
97                      strcmp(appEventGroups[i].appEventInfos[j].name, EVENT_APP_CRASH) == 0) {
98                      Json::Value params;
99                      Json::Reader reader(Json::Features::strictMode());
100                      Json::FastWriter writer;
101                      if (reader.parse(appEventGroups[i].appEventInfos[j].params, params)) {
102                          auto time = params["time"].asInt64();
103                          auto crashType = params["crash_type"].asString();
104                          auto foreground = params["foreground"].asBool();
105                          auto bundleVersion = params["bundle_version"].asString();
106                          auto bundleName = params["bundle_name"].asString();
107                          auto pid = params["pid"].asInt();
108                          auto uid = params["uid"].asInt();
109                          auto uuid = params["uuid"].asString();
110                          auto exception = writer.write(params["exception"]);
111                          auto hilogSize = params["hilog"].size();
112                          auto externalLog = writer.write(params["external_log"]);
113                          auto logOverLimit = params["log_over_limit"].asBool();
114                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.time=%{public}lld", time);
115                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.crash_type=%{public}s", crashType.c_str());
116                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.foreground=%{public}d", foreground);
117                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.bundle_version=%{public}s", bundleVersion.c_str());
118                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.bundle_name=%{public}s", bundleName.c_str());
119                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.pid=%{public}d", pid);
120                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.uid=%{public}d", uid);
121                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.uuid=%{public}s", uuid.c_str());
122                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.exception=%{public}s", exception.c_str());
123                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.hilog.size=%{public}d", hilogSize);
124                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.external_log=%{public}s", externalLog.c_str());
125                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.log_over_limit=%{public}d", logOverLimit);
126                      }
127                  }
128              }
129          }
130      }
131
132      static napi_value RegisterWatcher(napi_env env, napi_callback_info info) {
133          // Set the watcher name. The system identifies different watchers based on their names.
134          systemEventWatcher = OH_HiAppEvent_CreateWatcher("onReceiverWatcher");
135          // Set the event to watch to EVENT_APP_CRASH.
136          const char *names[] = {EVENT_APP_CRASH};
137          // Subscribe to the system event EVENT_APP_CRASH.
138          OH_HiAppEvent_SetAppEventFilter(systemEventWatcher, DOMAIN_OS, 0, names, 1);
139          // Call the OH_HiAppEvent_SetWatcherOnReceive function to set the implemented callback. After the watcher receives an event, the OnReceive callback is triggered.
140          OH_HiAppEvent_SetWatcherOnReceive(systemEventWatcher, OnReceive);
141          // Start the watcher to listen for events.
142          OH_HiAppEvent_AddWatcher(systemEventWatcher);
143          return {};
144      }
145      ```
146
147   - Watcher of the **onTrigger** type:
148
149      Define **OnTrigger()** in the **napi_init.cpp** file.
150
151      ```c++
152      // Define a variable to cache the created watcher pointer.
153      static HiAppEvent_Watcher *systemEventWatcher;
154
155      // You need to implement the OnTake callback to obtain the listened events. The events pointer is valid only in this function.
156      static void OnTake(const char *const *events, uint32_t eventLen) {
157          Json::Reader reader(Json::Features::strictMode());
158          Json::FastWriter writer;
159          for (int i = 0; i < eventLen; ++i) {
160              Json::Value eventInfo;
161              if (reader.parse(events[i], eventInfo)) {
162                  auto domain =  eventInfo["domain_"].asString();
163                  auto name = eventInfo["name_"].asString();
164                  auto type = eventInfo["type_"].asInt();
165                  OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.domain=%{public}s", domain.c_str());
166                  OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.name=%{public}s", name.c_str());
167                  OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.eventType=%{public}d", type);
168                  if (domain ==  DOMAIN_OS && name == EVENT_APP_CRASH) {
169                      auto time = eventInfo["time"].asInt64();
170                      auto crashType = eventInfo["crash_type"].asString();
171                      auto foreground = eventInfo["foreground"].asBool();
172                      auto bundleVersion = eventInfo["bundle_version"].asString();
173                      auto bundleName = eventInfo["bundle_name"].asString();
174                      auto pid = eventInfo["pid"].asInt();
175                      auto uid = eventInfo["uid"].asInt();
176                      auto uuid = eventInfo["uuid"].asString();
177                      auto exception = writer.write(eventInfo["exception"]);
178                      auto hilogSize = eventInfo["hilog"].size();
179                      auto externalLog = writer.write(eventInfo["external_log"]);
180                      auto logOverLimit = eventInfo["log_over_limit"].asBool();
181                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.time=%{public}lld", time);
182                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.crash_type=%{public}s", crashType.c_str());
183                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.foreground=%{public}d", foreground);
184                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.bundle_version=%{public}s", bundleVersion.c_str());
185                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.bundle_name=%{public}s", bundleName.c_str());
186                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.pid=%{public}d", pid);
187                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.uid=%{public}d", uid);
188                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.uuid=%{public}s", uuid.c_str());
189                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.exception=%{public}s", exception.c_str());
190                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.hilog.size=%{public}d", hilogSize);
191                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.external_log=%{public}s", externalLog.c_str());
192                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.log_over_limit=%{public}d", logOverLimit);
193                  }
194              }
195          }
196      }
197
198      // Implement the subscription callback to customize the processing of the obtained event data.
199      static void OnTrigger(int row, int size) {
200          // After the callback is received, obtain the specified number of events.
201          OH_HiAppEvent_TakeWatcherData(systemEventWatcher, row, OnTake);
202      }
203
204      static napi_value RegisterWatcher(napi_env env, napi_callback_info info) {
205          // Set the watcher name. The system identifies different watchers based on their names.
206          systemEventWatcher = OH_HiAppEvent_CreateWatcher("onTriggerWatcher");
207          // Set the event to watch to EVENT_APP_CRASH.
208          const char *names[] = {EVENT_APP_CRASH};
209          // Add the events to watch, for example, system events.
210          OH_HiAppEvent_SetAppEventFilter(systemEventWatcher, DOMAIN_OS, 0, names, 1);
211          // Set the implemented callback function. The callback function will be triggered when the conditions set by OH_HiAppEvent_SetTriggerCondition are met.
212          OH_HiAppEvent_SetWatcherOnTrigger(systemEventWatcher, OnTrigger);
213          // Set the conditions for triggering the subscription callback. For example, trigger the onTrigger callback when the number of new events is 1.
214          OH_HiAppEvent_SetTriggerCondition(systemEventWatcher, 1, 0, 0);
215          // Start the watcher to listen for subscribed events.
216          OH_HiAppEvent_AddWatcher(systemEventWatcher);
217          return {};
218      }
219      ```
220
2216. Register **RegisterWatcher** as an ArkTS API.
222
223   In the **napi_init.cpp** file, register **RegisterWatcher** as an ArkTS API.
224
225   ```c++
226   static napi_value Init(napi_env env, napi_value exports)
227   {
228       napi_property_descriptor desc[] = {
229           { "registerWatcher", nullptr, RegisterWatcher, nullptr, nullptr, nullptr, napi_default, nullptr }
230       };
231       napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
232       return exports;
233   }
234   ```
235
236   Define the ArkTS API in the **index.d.ts** file.
237
238   ```typescript
239   export const registerWatcher: () => void;
240   ```
241
2427. In the **EntryAbility.ets** file, add the following API to **onCreate()**.
243
244   ```typescript
245   // Import the dependent module.
246   import testNapi from 'libentry.so'
247
248   // Add the API to onCreate().
249   // Register the system event watcher at startup.
250   testNapi.registerWatcher();
251   ```
252
2538. In the **Index.ets** file, add a button to trigger a crash event.
254
255   ```typescript
256   Button("appCrash").onClick(() => {
257     JSON.parse("");
258   })
259   ```
260
2619. Click **Run** to start the application project. Then, click the **appCrash** button to trigger a crash event. The system generates crash logs and triggers the callback.
262
263> **NOTE**
264>
265> **JsError** triggers callback by collecting fault information in the process, which is fast. **NativeCrash** collects fault information outside the process. The average time is about 2 seconds, depending on the number of service threads and inter-process communication. After the crash event is subscribed, the fault information is reported asynchronously after the collection is complete, and the current service is not blocked.
266
267### Verifying the Subscription
268
269The callback time of a crash event varies depending on whether the crash exception is captured by the application proactively. You need to verify whether the crash event is subscribed to in different scenarios.
270
271**Application not proactively captures crash events**
272
273If the application does not proactively capture the crash exception, the application will exit after the system handles the crash. When the application restarts, HiAppEvent reports the crash event to the registered watcher to complete the callback.
274
275**Application proactively captures crash events**
276
277If the application proactively captures the crash exception, HiAppEvent will trigger the callback before the application exits. For example:
278
2791. The application does not exit during exception handling.
280
281   When [errorManager.on](../reference/apis-ability-kit/js-apis-app-ability-errorManager.md#errormanageronerror) is used to capture the **JsError** crash event, a callback is triggered before the application exits. If the application registers the [crash signal](cppcrash-guidelines.md#crash-signals) processing function but does not exit, the NativeCrash event triggers a callback before the application exits.
282
2832. If the exception handling takes a long time, the application exits with a delay.
284
285In the development and debugging phase, after HiAppEvent reports a crash event and completes the callback, you can view the event information in the **HiLog** window of DevEco Studio.
286
287```text
288HiAppEvent eventInfo.domain=OS
289HiAppEvent eventInfo.name=APP_CRASH
290HiAppEvent eventInfo.eventType=1
291HiAppEvent eventInfo.params.time=1502032265088
292HiAppEvent eventInfo.params.crash_type=JsError
293HiAppEvent eventInfo.params.foreground=1
294HiAppEvent eventInfo.params.bundle_version=1.0.0
295HiAppEvent eventInfo.params.bundle_name=com.example.myapplication
296HiAppEvent eventInfo.params.pid=19237
297HiAppEvent eventInfo.params.uid=20010043
298HiAppEvent eventInfo.params.uuid=cc0f062e1b28c1fd2c817fafab5e8ca3207925b4bdd87c43ed23c60029659e01
299HiAppEvent eventInfo.params.exception={"message":"Unexpected Text in JSON","name":"SyntaxError","stack":"at anonymous (entry/src/main/ets/pages/Index.ets:16:11)"}
300HiAppEvent eventInfo.params.hilog.size=110
301HiAppEvent eventInfo.params.external_log=["/data/storage/el2/log/hiappevent/APP_CRASH_1502032265211_19237.log"]
302HiAppEvent eventInfo.params.log_over_limit=0
303```
304
305### Removing and Destroying an Event Watcher
306
3071. Remove the event watcher.
308
309   ```c++
310   static napi_value RemoveWatcher(napi_env env, napi_callback_info info) {
311       // Remove the watcher.
312       OH_HiAppEvent_RemoveWatcher(systemEventWatcher);
313       return {};
314   }
315   ```
316
3172. Destroy the event watcher.
318
319   ```c++
320   static napi_value DestroyWatcher(napi_env env, napi_callback_info info) {
321       // Destroy the created watcher and set systemEventWatcher to nullptr.
322       OH_HiAppEvent_DestroyWatcher(systemEventWatcher);
323       systemEventWatcher = nullptr;
324       return {};
325   }
326   ```
327