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