• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Subscribing to Resource Leak 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**Subscription APIs**
8
9| API                                                        | Description                                        |
10|-------------------------------------------------------------| -------------------------------------------- |
11| int OH_HiAppEvent_AddWatcher(HiAppEvent_Watcher *watcher)   | Adds a watcher to listen for application events.|
12| int OH_HiAppEvent_RemoveWatcher(HiAppEvent_Watcher *watcher) | Removes a watcher to unsubscribe from the application events.|
13
14## How to Develop
15
161. Create a native C++ project and import the **jsoncpp** file to the project. The directory structure is as follows:
17
18   ```yml
19   entry:
20     src:
21       main:
22         cpp:
23           - json:
24               - json.h
25               - json-forwards.h
26           - types:
27               libentry:
28                 - index.d.ts
29           - CMakeLists.txt
30           - napi_init.cpp
31           - jsoncpp.cpp
32         ets:
33           - entryability:
34               - EntryAbility.ets
35           - pages:
36               - Index.ets
37   ```
38
392. In the **CMakeLists.txt** file, add the source file and dynamic libraries.
40
41   ```cmake
42   # Add the jsoncpp.cpp file, which is used to parse the JSON strings in the subscription events.
43   add_library(entry SHARED napi_init.cpp jsoncpp.cpp)
44   # Add libhiappevent_ndk.z.so and libhilog_ndk.z.so (log output).
45   target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so libhiappevent_ndk.z.so)
46   ```
47
483. Import the dependency files to the **napi_init.cpp** file, and define **LOG_TAG**.
49
50   ```c++
51   #include "napi/native_api.h"
52   #include "json/json.h"
53   #include "hilog/log.h"
54   #include "hiappevent/hiappevent.h"
55
56   #undef LOG_TAG
57   #define LOG_TAG "testTag"
58   ```
59
604. Subscribe to system events.
61
62    - Watcher of the onReceive type:
63
64      In the **napi_init.cpp** file, define the methods related to the watcher of the onReceive type.
65
66      ```c++
67      // Define a variable to cache the pointer to the created watcher.
68      static HiAppEvent_Watcher *systemEventWatcher;
69
70      static void OnReceive(const char *domain, const struct HiAppEvent_AppEventGroup *appEventGroups, uint32_t groupLen) {
71          for (int i = 0; i < groupLen; ++i) {
72              for (int j = 0; j < appEventGroups[i].infoLen; ++j) {
73                  OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.domain=%{public}s", appEventGroups[i].appEventInfos[j].domain);
74                  OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.name=%{public}s", appEventGroups[i].appEventInfos[j].name);
75                  OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.eventType=%{public}d", appEventGroups[i].appEventInfos[j].type);
76                  if (strcmp(appEventGroups[i].appEventInfos[j].domain, DOMAIN_OS) == 0 &&
77                      strcmp(appEventGroups[i].appEventInfos[j].name, EVENT_RESOURCE_OVERLIMIT) == 0) {
78                      Json::Value params;
79                      Json::Reader reader(Json::Features::strictMode());
80                      Json::FastWriter writer;
81                      if (reader.parse(appEventGroups[i].appEventInfos[j].params, params)) {
82                          auto time = params["time"].asInt64();
83                          auto pid = params["pid"].asInt();
84                          auto uid = params["uid"].asInt();
85                          auto resourceType = params["resourceType"].asString();
86                          auto bundleName = params["bundle_name"].asString();
87                          auto bundleVersion = params["bundle_version"].asString();
88                          auto memory = writer.write(params["memory"]);
89                          auto externalLog = writer.write(eventInfo["external_log"]);
90                          std::string logOverLimit = eventInfo["log_over_limit"].asBool() ? "true":"false";
91                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.time=%{public}lld", time);
92                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.pid=%{public}d", pid);
93                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.uid=%{public}d", uid);
94                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.resource_type=%{public}s", resourceType.c_str());
95                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.bundle_name=%{public}s", bundleName.c_str());
96                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.bundle_version=%{public}s", bundleVersion.c_str());
97                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.memory=%{public}s", memory.c_str());
98                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.external_log=%{public}s", externalLog.c_str());
99                          OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.log_over_limit=%{public}d", logOverLimit.c_str());
100                      }
101                  }
102              }
103          }
104      }
105
106      static napi_value RegisterWatcher(napi_env env, napi_callback_info info) {
107          // Set the watcher name. The system identifies different watchers based on their names.
108          systemEventWatcher = OH_HiAppEvent_CreateWatcher("onReceiverWatcher");
109          // Set the event to watch to EVENT_RESOURCE_OVERLIMIT.
110          const char *names[] = {EVENT_RESOURCE_OVERLIMIT};
111          // Add the events to watch, for example, system events.
112          OH_HiAppEvent_SetAppEventFilter(systemEventWatcher, DOMAIN_OS, 0, names, 1);
113          // Set the implemented callback. After receiving the event, the watcher immediately triggers the OnReceive callback.
114          OH_HiAppEvent_SetWatcherOnReceive(systemEventWatcher, OnReceive);
115          // Add a watcher to listen for the specified event.
116          OH_HiAppEvent_AddWatcher(systemEventWatcher);
117          return {};
118      }
119      ```
120
121    - Watcher of the onTrigger type:
122
123      In the **napi_init.cpp** file, define the methods related to the watcher of the OnTrigger type.
124
125      ```c++
126      // Define a variable to cache the pointer to the created watcher.
127      static HiAppEvent_Watcher *systemEventWatcher;
128
129      // Implement the callback function used to return the listened events. The content pointed to by the events pointer is valid only in this function.
130      static void OnTake(const char *const *events, uint32_t eventLen) {
131          Json::Reader reader(Json::Features::strictMode());
132          Json::FastWriter writer;
133          for (int i = 0; i < eventLen; ++i) {
134              Json::Value eventInfo;
135              if (reader.parse(events[i], eventInfo)) {
136                  auto domain =  eventInfo["domain_"].asString();
137                  auto name = eventInfo["name_"].asString();
138                  auto type = eventInfo["type_"].asInt();
139                  OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.domain=%{public}s", domain.c_str());
140                  OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.name=%{public}s", name.c_str());
141                  OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.eventType=%{public}d", type);
142                  if (domain ==  DOMAIN_OS && name == EVENT_RESOURCE_OVERLIMIT) {
143                      auto time = eventInfo["time"].asInt64();
144                      auto pid = eventInfo["pid"].asInt();
145                      auto uid = eventInfo["uid"].asInt();
146                      auto resourceType = eventInfo["resourceType"].asString();
147                      auto bundleName = eventInfo["bundle_name"].asString();
148                      auto bundleVersion = eventInfo["bundle_version"].asString();
149                      auto memory = writer.write(eventInfo["memory"]);
150                      auto externalLog = writer.write(eventInfo["external_log"]);
151                      std::string logOverLimit = eventInfo["log_over_limit"].asBool() ? "true":"false";
152                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.time=%{public}lld", time);
153                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.pid=%{public}d", pid);
154                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.uid=%{public}d", uid);
155                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.resource_type=%{public}s", resourceType.c_str());
156                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.bundle_name=%{public}s", bundleName.c_str());
157                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.bundle_version=%{public}s", bundleVersion.c_str());
158                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.memory=%{public}s", memory.c_str());
159                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.external_log=%{public}s", externalLog.c_str());
160                      OH_LOG_INFO(LogType::LOG_APP, "HiAppEvent eventInfo.params.log_over_limit=%{public}d", logOverLimit.c_str());
161                  }
162              }
163          }
164      }
165
166      // Implement the subscription callback function to apply custom processing to the obtained event logging data.
167      static void OnTrigger(int row, int size) {
168          // After the callback is received, obtain the specified number of received events.
169          OH_HiAppEvent_TakeWatcherData(systemEventWatcher, row, OnTake);
170      }
171
172      static napi_value RegisterWatcher(napi_env env, napi_callback_info info) {
173          // Set the watcher name. The system identifies different watchers based on their names.
174          systemEventWatcher = OH_HiAppEvent_CreateWatcher("onTriggerWatcher");
175          // Set the event to watch to EVENT_RESOURCE_OVERLIMIT.
176          const char *names[] = {EVENT_RESOURCE_OVERLIMIT};
177          // Add the events to watch, for example, system events.
178          OH_HiAppEvent_SetAppEventFilter(systemEventWatcher, DOMAIN_OS, 0, names, 1);
179          // Set the implemented callback function. The callback function will be triggered when the conditions set by OH_HiAppEvent_SetTriggerCondition are met.
180          OH_HiAppEvent_SetWatcherOnTrigger(systemEventWatcher, OnTrigger);
181          // Set the conditions for triggering the subscription callback. For example, trigger this onTrigger callback when the number of new event logs is 2.
182          OH_HiAppEvent_SetTriggerCondition(systemEventWatcher, 1, 0, 0);
183          // Add a watcher to listen for the specified event.
184          OH_HiAppEvent_AddWatcher(systemEventWatcher);
185          return {};
186      }
187      ```
188
1895. Register **RegisterWatcher** as an ArkTS API.
190
191   In the **napi_init.cpp** file, register **RegisterWatcher** as an ArkTS API.
192
193   ```c++
194   static napi_value Init(napi_env env, napi_value exports)
195   {
196       napi_property_descriptor desc[] = {
197           { "registerWatcher", nullptr, RegisterWatcher, nullptr, nullptr, nullptr, napi_default, nullptr }
198       };
199       napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
200       return exports;
201   }
202   ```
203
204   In the **index.d.ts** file, define the ArkTS API.
205
206   ```typescript
207   export const registerWatcher: () => void;
208   ```
209
2106. In the **EntryAbility.ets** file, add the following interface invocation to **onCreate()**.
211
212   ```typescript
213   import testNapi from 'libentry.so'
214   import hidebug from '@kit.PerformanceAnalysisKit'
215   export default class EntryAbility extends UIAbility {
216     onCreate(want, launchParam) {
217       // Register the system event watcher at startup.
218       testNapi.registerWatcher();
219     }
220   }
221   ```
222
2237. 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()**.
224   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 function.) The sample code is as follows:
225
226   ```ts
227    import hidebug from "@ohos.hidebug";
228
229    @Entry
230    @Component
231    struct Index {
232      @State leakedArray: string[][] = [];
233
234      build() {
235        Column() {
236          Row() {
237            Column() {
238              Button("pss leak")
239                .onClick(() => {
240                  hidebug.setAppResourceLimit("pss_memory", 1024, true);
241                  for (let i = 0; i < 20 * 1024; i++) {
242                    this.leakedArray.push(new Array(1).fill("leak"));
243                  }
244                })
245            }
246          }
247          .height('100%')
248          .width('100%')
249        }
250      }
251    }
252   ```
253
2548. Click the **Run** button in DevEco Studio to run the project, and then a memory leak event will be reported after 15 to 30 minutes.
255   For the same application, the memory 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.
256
2579. After the memory leak event is reported, you can view the following event information in the **Log** window.
258
259   ```text
260   08-07 03:53:35.314 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.domain=OS
261   08-07 03:53:35.314 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.name=RESOURCE_OVERLIMIT
262   08-07 03:53:35.314 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.eventType=1
263   08-07 03:53:35.349 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.params.time=1502049167732
264   08-07 03:53:35.349 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.params.pid=1587
265   08-07 03:53:35.349 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.params.uid=20010043
266   08-07 03:53:35.349 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.params.resource_type=pss_memory
267   08-07 03:53:35.349 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.params.bundle_name=com.example.myapplication
268   08-07 03:53:35.349 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.params.bundle_version=1.0.0
269   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}
270   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"]
271   08-07 03:53:35.350 1719-1738/? I A00000/testTag: HiAppEvent eventInfo.params.log_over_limit=false
272   ```
273
27410. Remove the event watcher.
275
276    ```c++
277    static napi_value RemoveWatcher(napi_env env, napi_callback_info info) {
278        // Remove the watcher.
279        OH_HiAppEvent_RemoveWatcher(systemEventWatcher);
280        return {};
281    }
282    ```
283
28411. Destroy the event watcher.
285
286    ```c++
287    static napi_value DestroyWatcher(napi_env env, napi_callback_info info) {
288        // Destroy the created watcher and set systemEventWatcher to nullptr.
289        OH_HiAppEvent_DestroyWatcher(systemEventWatcher);
290        systemEventWatcher = nullptr;
291        return {};
292    }
293    ```
294