• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 订阅崩溃事件(C/C++)
2<!--Kit: Performance Analysis Kit-->
3<!--Subsystem: HiviewDFX-->
4<!--Owner: @chenshi51-->
5<!--Designer: @Maplestory-->
6<!--Tester: @yufeifei-->
7<!--Adviser: @foryourself-->
8
9## 简介
10
11本文介绍如何使用HiAppEvent提供的C/C++接口订阅应用崩溃事件。详细使用说明请参考[HiAppEvent C API文档](../reference/apis-performance-analysis-kit/capi-hiappevent-h.md)。
12
13> **说明:**
14>
15> 使用C/C++接口订阅JsError和NativeCrash崩溃事件。
16
17## 接口说明
18
19| 接口名 | 描述 |
20| -------- | -------- |
21| int OH_HiAppEvent_AddWatcher(HiAppEvent_Watcher \*watcher) | 添加应用事件观察者,以添加对应用事件的订阅。 |
22| int OH_HiAppEvent_RemoveWatcher(HiAppEvent_Watcher \*watcher) | 移除应用事件观察者,以移除对应用事件的订阅。 |
23
24## 开发步骤
25
26### 添加事件观察者
27
28**在应用启动后,在执行业务逻辑前添加事件观察者,以确保订阅到崩溃事件。否则,应用可能因崩溃而退出,无法订阅崩溃事件。**
29
30以用户点击按钮触发崩溃事件为例,开发步骤如下:
31
321. 获取示例工程的依赖项jsoncpp。
33
34   参考[三方开源库jsoncpp代码仓](https://github.com/open-source-parsers/jsoncpp)README中**Amalgamated source**部分,获取jsoncpp.cppjson.hjson-forwards.h三个文件。
35
362. 新建Native C++工程,并将上述文件导入到新建工程,目录结构如下。
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. 在"CMakeLists.txt"文件中,添加源文件和动态库。
60
61   ```cmake
62   # 新增jsoncpp.cpp(解析订阅事件中的json字符串)源文件
63   add_library(entry SHARED napi_init.cpp jsoncpp.cpp)
64   # 新增动态库依赖libhiappevent_ndk.z.solibhilog_ndk.z.so(日志输出)
65   target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so libhiappevent_ndk.z.so)
66   ```
67
684. 在"napi_init.cpp"文件中,导入依赖文件,并定义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. 订阅系统事件。
81
82   - onReceive类型观察者
83
84      在"napi_init.cpp"文件中,定义onReceive类型观察者的方法:
85
86      ```c++
87      //定义一个变量,缓存创建的观察者指针。
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          // 开发者自定义观察者名称,系统根据名称识别不同的观察者。
134          systemEventWatcher = OH_HiAppEvent_CreateWatcher("onReceiverWatcher");
135          // 订阅的事件为EVENT_APP_CRASH。
136          const char *names[] = {EVENT_APP_CRASH};
137          // 此处开发者订阅了系统事件EVENT_APP_CRASH。
138          OH_HiAppEvent_SetAppEventFilter(systemEventWatcher, DOMAIN_OS, 0, names, 1);
139          // 开发者通过调用OH_HiAppEvent_SetWatcherOnReceive函数设置已实现的回调函数,观察者接收到事件后会触发OnReceive回调。
140          OH_HiAppEvent_SetWatcherOnReceive(systemEventWatcher, OnReceive);
141          // 启动观察者以监听事件。
142          OH_HiAppEvent_AddWatcher(systemEventWatcher);
143          return {};
144      }
145      ```
146
147   - onTrigger类型观察者
148
149      在"napi_init.cpp"文件中,定义OnTrigger类型观察者:
150
151      ```c++
152      //定义一个变量,用来缓存创建的观察者指针。
153      static HiAppEvent_Watcher *systemEventWatcher;
154
155      // 开发者需要实现一个回调函数`OnTake`来获取已监听事件,其中`events`指针仅在该函数内有效。
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      // 开发者应实现订阅回调函数,用以对获取的事件打点数据进行自定义处理。
199      static void OnTrigger(int row, int size) {
200          // 接收回调后,获取指定数量的事件。
201          OH_HiAppEvent_TakeWatcherData(systemEventWatcher, row, OnTake);
202      }
203
204      static napi_value RegisterWatcher(napi_env env, napi_callback_info info) {
205          // 开发者自定义观察者名称,系统根据不同的名称来识别不同的观察者。
206          systemEventWatcher = OH_HiAppEvent_CreateWatcher("onTriggerWatcher");
207          // 设置订阅的事件为EVENT_APP_CRASH。
208          const char *names[] = {EVENT_APP_CRASH};
209          // 开发者订阅感兴趣的事件,此处订阅了系统事件。
210          OH_HiAppEvent_SetAppEventFilter(systemEventWatcher, DOMAIN_OS, 0, names, 1);
211          // 开发者设置已实现的回调函数,需OH_HiAppEvent_SetTriggerCondition设置的条件满足方可触发。
212          OH_HiAppEvent_SetWatcherOnTrigger(systemEventWatcher, OnTrigger);
213          // 设置订阅触发回调的条件:当设置新增事件打点数量为1时,触发onTrigger回调。
214          OH_HiAppEvent_SetTriggerCondition(systemEventWatcher, 1, 0, 0);
215          // 启动观察者以监听订阅的事件。
216          OH_HiAppEvent_AddWatcher(systemEventWatcher);
217          return {};
218      }
219      ```
220
2216. 将RegisterWatcher注册为ArkTS接口。
222
223   在"napi_init.cpp"文件中,将RegisterWatcher注册为ArkTS接口:
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   在"index.d.ts"文件中,定义ArkTS接口:
237
238   ```typescript
239   export const registerWatcher: () => void;
240   ```
241
2427. 在"EntryAbility.ets"文件的onCreate()函数中添加接口调用。
243
244   ```typescript
245   // 导入依赖模块
246   import testNapi from 'libentry.so'
247
248   // 在onCreate()函数中新增接口调用
249   // 启动时,注册系统事件观察者
250   testNapi.registerWatcher();
251   ```
252
2538. 在"Index.ets"文件中,新增按钮触发崩溃事件。
254
255   ```typescript
256   Button("appCrash").onClick(() => {
257     JSON.parse("");
258   })
259   ```
260
2619. 点击运行按钮,启动应用工程。在应用界面中点击“appCrash”按钮,触发崩溃事件。系统生成相应的崩溃日志并进行回调。
262
263> **说明:**
264>
265> JsError通过进程内采集故障信息触发回调,速度快。NativeCrash采取进程外采集故障信息,平均耗时约2秒,具体受业务线程数量和进程间通信影响。订阅崩溃事件后,故障信息采集完成会异步上报,不阻塞当前业务。
266
267### 验证观察者是否订阅到崩溃事件
268
269在应用未主动捕获崩溃异常和主动捕获崩溃异常的两种场景中,崩溃事件的回调时机不同。开发者需要在每种情况下验证是否订阅到崩溃事件。
270
271**应用未主动捕获崩溃异常场景**
272
273若应用未主动捕获崩溃异常,则系统处理崩溃后应用将退出。**应用下次启动时**,HiAppEvent将崩溃事件上报给已注册的监听,完成回调。
274
275**应用主动捕获崩溃异常场景**
276
277若应用主动捕获崩溃异常,HiAppEvent事件将在**应用退出前**触发回调,例如:
278
2791. 异常处理中未主动退出的应用崩溃后不会退出。
280
281   采用[errorManger.on](../reference/apis-ability-kit/js-apis-app-ability-errorManager.md#errormanageronerror)方法捕获异常会导致JsError类型的崩溃事件在应用退出前触发回调。若应用注册[崩溃信号](cppcrash-guidelines.md#系统处理的崩溃信号)处理函数但未主动退出,会导致NativeCrash类型的崩溃事件在应用退出前触发回调。
282
2832. 异常处理耗时过长,会导致应用退出延迟。
284
285在开发调试阶段,HiAppEvent上报事件完成回调后,可在DevEco Studio的HiLog窗口查看订阅的崩溃事件内容。
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### 移除并销毁事件观察者
306
3071. 移除事件观察者。
308
309   ```c++
310   static napi_value RemoveWatcher(napi_env env, napi_callback_info info) {
311       // 使观察者停止监听事件
312       OH_HiAppEvent_RemoveWatcher(systemEventWatcher);
313       return {};
314   }
315   ```
316
3172. 销毁事件观察者。
318
319   ```c++
320   static napi_value DestroyWatcher(napi_env env, napi_callback_info info) {
321       // 销毁创建的观察者,并置systemEventWatcher为nullptr。
322       OH_HiAppEvent_DestroyWatcher(systemEventWatcher);
323       systemEventWatcher = nullptr;
324       return {};
325   }
326   ```
327