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