• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Subscribing to Resource Leak Events (C/C++)
2
3<!--Kit: Performance Analysis Kit-->
4<!--Subsystem: HiviewDFX-->
5<!--Owner: @xuxinao-->
6<!--Designer: @peterhuangyu-->
7<!--Tester: @gcw_KuLfPSbe-->
8<!--Adviser: @foryourself-->
9
10## Available APIs
11
12This topic describes how to use the C/C++ APIs provided by HiAppEvent to subscribe to resource leak events. For details about how to use the APIs (such as parameter usage restrictions and value ranges), see [hiappevent.h](../reference/apis-performance-analysis-kit/capi-hiappevent-h.md).
13
14**Subscription APIs**
15
16| API| Description|
17| -------- | -------- |
18| int OH_HiAppEvent_AddWatcher(HiAppEvent_Watcher \*watcher) | Adds a watcher to listen for application events.|
19| int OH_HiAppEvent_RemoveWatcher(HiAppEvent_Watcher \*watcher) | Removes a watcher to unsubscribe from the application events.|
20
21## How to Develop
22
23### Step 1: Creating a Project
24
251. Obtain the **jsoncpp** file on which the sample project depends. Specifically, download the source code package from [JsonCpp](https://github.com/open-source-parsers/jsoncpp) and obtain the **jsoncpp.cpp**, **json.h**, and **json-forwards.h** files by following the procedure described in **Amalgamated source**.
26
27   Create a native C++ project in DevEco Studio. The directory structure is as follows:
28
29   ```yml
30   entry:
31     src:
32       main:
33         cpp:
34           - json:
35               - json.h
36               - json-forwards.h
37           - types:
38               libentry:
39                 - index.d.ts
40           - CMakeLists.txt
41           - napi_init.cpp
42           - jsoncpp.cpp
43         ets:
44           - entryability:
45               - EntryAbility.ets
46           - pages:
47               - Index.ets
48   ```
49
502. In the **CMakeLists.txt** file, add the source file and dynamic libraries.
51
52   ```cmake
53   # Add the jsoncpp.cpp file, which is used to parse the JSON strings in the subscription events.
54   add_library(entry SHARED napi_init.cpp jsoncpp.cpp)
55   # Add libhiappevent_ndk.z.so and libhilog_ndk.z.so (log output).
56   target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so libhiappevent_ndk.z.so)
57   ```
58
593. Import the dependencies to the **napi_init.cpp** file, and define **LOG_TAG**.
60
61   ```c++
62   #include "napi/native_api.h"
63   #include "json/json.h"
64   #include "hilog/log.h"
65   #include "hiappevent/hiappevent.h"
66
67   #undef LOG_TAG
68   #define LOG_TAG "testTag"
69   ```
70
71### Step 2: Subscribing to a System Event
72
731. Subscribe to system events.
74
75   - Watcher of the onReceive type:
76
77      In the **napi_init.cpp** file, define the methods related to **onReceive()**.
78
79      ```c++
80      // Define a variable to cache the pointer to the created watcher.
81      static HiAppEvent_Watcher *systemEventWatcher;
82
83      static void OnReceive(const char *domain, const struct HiAppEvent_AppEventGroup *appEventGroups, uint32_t groupLen) {
84          for (int i = 0; i < groupLen; ++i) {
85              for (int j = 0; j < appEventGroups[i].infoLen; ++j) {
86                  OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.domain=%{public}s", appEventGroups[i].appEventInfos[j].domain);
87                  OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.name=%{public}s", appEventGroups[i].appEventInfos[j].name);
88                  OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.eventType=%{public}d", appEventGroups[i].appEventInfos[j].type);
89                  if (strcmp(appEventGroups[i].appEventInfos[j].domain, DOMAIN_OS) == 0 &&
90                      strcmp(appEventGroups[i].appEventInfos[j].name, EVENT_RESOURCE_OVERLIMIT) == 0) {
91                      Json::Value params;
92                      Json::Reader reader(Json::Features::strictMode());
93                      Json::FastWriter writer;
94                      if (reader.parse(appEventGroups[i].appEventInfos[j].params, params)) {
95                          auto time = params["time"].asInt64();
96                          auto pid = params["pid"].asInt();
97                          auto uid = params["uid"].asInt();
98                          auto resourceType = params["resourceType"].asString();
99                          auto bundleName = params["bundle_name"].asString();
100                          auto bundleVersion = params["bundle_version"].asString();
101                          auto memory = writer.write(params["memory"]);
102                          auto externalLog = writer.write(params["external_log"]);
103                          std::string logOverLimit = params["log_over_limit"].asBool() ? "true":"false";
104                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.time=%{public}lld", time);
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.resource_type=%{public}s", resourceType.c_str());
108                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.bundle_name=%{public}s", bundleName.c_str());
109                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.bundle_version=%{public}s", bundleVersion.c_str());
110                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.memory=%{public}s", memory.c_str());
111                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.external_log=%{public}s", externalLog.c_str());
112                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.log_over_limit=%{public}s", logOverLimit.c_str());
113                      }
114                  }
115              }
116          }
117      }
118
119      static napi_value RegisterWatcher(napi_env env, napi_callback_info info) {
120          // Set the watcher name. The system identifies different watchers based on their names.
121          systemEventWatcher = OH_HiAppEvent_CreateWatcher("onReceiverWatcher");
122          // Set the event to watch to EVENT_RESOURCE_OVERLIMIT.
123          const char *names[] = {EVENT_RESOURCE_OVERLIMIT};
124          // Add the events to watch, for example, system events.
125          OH_HiAppEvent_SetAppEventFilter(systemEventWatcher, DOMAIN_OS, 0, names, 1);
126          // Set the implemented callback. After receiving the event, the watcher immediately triggers the OnReceive callback.
127          OH_HiAppEvent_SetWatcherOnReceive(systemEventWatcher, OnReceive);
128          // Add a watcher to listen for the specified event.
129          OH_HiAppEvent_AddWatcher(systemEventWatcher);
130          return {};
131      }
132      ```
133
134   - Watcher of the onTrigger type:
135
136      In the **napi_init.cpp** file, define the methods related to **OnTrigger()**.
137
138      ```c++
139      // Define a variable to cache the pointer to the created watcher.
140      static HiAppEvent_Watcher *systemEventWatcher;
141
142      // Implement the callback function used to return the listened events. The content pointed to by the events pointer is valid only in this function.
143      static void OnTake(const char *const *events, uint32_t eventLen) {
144          Json::Reader reader(Json::Features::strictMode());
145          Json::FastWriter writer;
146          for (int i = 0; i < eventLen; ++i) {
147              Json::Value eventInfo;
148              if (reader.parse(events[i], eventInfo)) {
149                  auto domain =  eventInfo["domain_"].asString();
150                  auto name = eventInfo["name_"].asString();
151                  auto type = eventInfo["type_"].asInt();
152                  OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.domain=%{public}s", domain.c_str());
153                  OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.name=%{public}s", name.c_str());
154                  OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.eventType=%{public}d", type);
155                  if (domain ==  DOMAIN_OS && name == EVENT_RESOURCE_OVERLIMIT) {
156                      auto time = eventInfo["time"].asInt64();
157                      auto pid = eventInfo["pid"].asInt();
158                      auto uid = eventInfo["uid"].asInt();
159                      auto resourceType = eventInfo["resourceType"].asString();
160                      auto bundleName = eventInfo["bundle_name"].asString();
161                      auto bundleVersion = eventInfo["bundle_version"].asString();
162                      auto memory = writer.write(eventInfo["memory"]);
163                      auto externalLog = writer.write(eventInfo["external_log"]);
164                      std::string logOverLimit = eventInfo["log_over_limit"].asBool() ? "true":"false";
165                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.time=%{public}lld", time);
166                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.pid=%{public}d", pid);
167                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.uid=%{public}d", uid);
168                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.resource_type=%{public}s", resourceType.c_str());
169                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.bundle_name=%{public}s", bundleName.c_str());
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.memory=%{public}s", memory.c_str());
172                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.external_log=%{public}s", externalLog.c_str());
173                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.log_over_limit=%{public}s", logOverLimit.c_str());
174                  }
175              }
176          }
177      }
178
179      // Implement the subscription callback function to apply custom processing to the obtained event logging data.
180      static void OnTrigger(int row, int size) {
181          // After the callback is received, obtain the specified number of received events.
182          OH_HiAppEvent_TakeWatcherData(systemEventWatcher, row, OnTake);
183      }
184
185      static napi_value RegisterWatcher(napi_env env, napi_callback_info info) {
186          // Set the watcher name. The system identifies different watchers based on their names.
187          systemEventWatcher = OH_HiAppEvent_CreateWatcher("onTriggerWatcher");
188          // Set the event to watch to EVENT_RESOURCE_OVERLIMIT.
189          const char *names[] = {EVENT_RESOURCE_OVERLIMIT};
190          // Add the events to watch, for example, system events.
191          OH_HiAppEvent_SetAppEventFilter(systemEventWatcher, DOMAIN_OS, 0, names, 1);
192          // Set the implemented callback function. The callback function will be triggered when the conditions set by OH_HiAppEvent_SetTriggerCondition are met.
193          OH_HiAppEvent_SetWatcherOnTrigger(systemEventWatcher, OnTrigger);
194          // Set the conditions for triggering the subscription callback. For example, trigger this onTrigger callback when the number of new event logs is 2.
195          OH_HiAppEvent_SetTriggerCondition(systemEventWatcher, 1, 0, 0);
196          // Add a watcher to listen for the specified event.
197          OH_HiAppEvent_AddWatcher(systemEventWatcher);
198          return {};
199      }
200      ```
201
2022. Register **RegisterWatcher** as an ArkTS API.
203
204   In the **napi_init.cpp** file, register **RegisterWatcher** as an ArkTS API.
205
206   ```c++
207   static napi_value Init(napi_env env, napi_value exports)
208   {
209       napi_property_descriptor desc[] = {
210           { "registerWatcher", nullptr, RegisterWatcher, nullptr, nullptr, nullptr, napi_default, nullptr }
211       };
212       napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
213       return exports;
214   }
215   ```
216
217   In the **index.d.ts** file, define the ArkTS API.
218
219   ```typescript
220   export const registerWatcher: () => void;
221   ```
222
2233. In the **EntryAbility.ets** file, add the following API to **onCreate()**.
224
225   ```typescript
226   import testNapi from 'libentry.so'
227   import hidebug from '@kit.PerformanceAnalysisKit'
228   export default class EntryAbility extends UIAbility {
229     onCreate(want, launchParam) {
230       // Register the system event watcher at startup.
231       testNapi.registerWatcher();
232     }
233   }
234   ```
235
236### Step 3: Triggering a Resource Leak Event
237
2381. In the **entry/src/main/ets/pages/index.ets** file, add the **memoryleak** button and construct a scenario for triggering a resource leak event in **onClick()**.
239
240   In this case, use [hidebug.setAppResourceLimit](../reference/apis-performance-analysis-kit/js-apis-hidebug.md#hidebugsetappresourcelimit12) to set the memory limit to trigger a memory leak event, and enable **System resource leak log** in **Developer options**. (Restart the device to enable or disable this functionality.) The sample code is as follows:
241
242   ```ts
243    import { hidebug } from '@kit.PerformanceAnalysisKit';
244
245    @Entry
246    @Component
247    struct Index {
248      @State leakedArray: string[][] = [];
249
250      build() {
251        Column() {
252          Row() {
253            Column() {
254              Button("pss leak")
255                .onClick(() => {
256                  hidebug.setAppResourceLimit("pss_memory", 1024, true);
257                  for (let i = 0; i < 20 * 1024; i++) {
258                    this.leakedArray.push(new Array(1).fill("leak"));
259                  }
260                })
261            }
262          }
263          .height('100%')
264          .width('100%')
265        }
266      }
267    }
268   ```
269
2702. Click the **Run** button in DevEco Studio to run the project. Click the **pss leak** button and wait for 15 to 30 minutes; the system will then report the memory leak event.
271
272   For the same application, the resource leak event can be reported at most once within 24 hours. If the memory leak needs to be reported again within a shorter time, restart the device.
273
2743. After the memory leak event is reported, you can view the following event information in the **Log** window.
275
276   ```text
277   08-07 03:53:35.314 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.domain=OS
278   08-07 03:53:35.314 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.name=RESOURCE_OVERLIMIT
279   08-07 03:53:35.314 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.eventType=1
280   08-07 03:53:35.349 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.params.time=1502049167732
281   08-07 03:53:35.349 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.params.pid=1587
282   08-07 03:53:35.349 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.params.uid=20010043
283   08-07 03:53:35.349 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.params.resource_type=pss_memory
284   08-07 03:53:35.349 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.params.bundle_name=com.example.myapplication
285   08-07 03:53:35.349 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.params.bundle_version=1.0.0
286   08-07 03:53:35.350 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.params.memory={"pss":2100257,"rss":1352644,"sys_avail_mem":250272,"sys_free_mem":60004,"sys_total_mem":1992340,"vss":2462936}
287   08-07 03:53:35.350 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.params.external_log=["/data/storage/el2/log/resourcelimit/RESOURCE_OVERLIMIT_1725614572401_6808.log","/data/storage/el2/log/resourcelimit/RESOURCE_OVERLIMIT_1725614572412_6808.log"]
288   08-07 03:53:35.350 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.params.log_over_limit=false
289   ```
290
291### Step 4: Removing a Watcher
292
2931. Remove the event watcher.
294
295   ```c++
296   static napi_value RemoveWatcher(napi_env env, napi_callback_info info) {
297       // Remove the watcher to unsubscribe from events.
298       OH_HiAppEvent_RemoveWatcher(systemEventWatcher);
299       return {};
300   }
301   ```
302
3032. Destroy the event watcher.
304
305   ```c++
306   static napi_value DestroyWatcher(napi_env env, napi_callback_info info) {
307       // Destroy the created watcher and set systemEventWatcher to nullptr.
308       OH_HiAppEvent_DestroyWatcher(systemEventWatcher);
309       systemEventWatcher = nullptr;
310       return {};
311   }
312   ```
313