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