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