1# 订阅资源泄漏事件(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## 接口说明 11 12本文介绍如何使用HiAppEvent提供的C/C++接口订阅资源泄漏事件。API接口的具体使用说明(参数使用限制、具体取值范围等)请参考[HiAppEvent C API文档](../reference/apis-performance-analysis-kit/capi-hiappevent-h.md)。 13 14**订阅接口功能介绍**: 15 16| 接口名 | 描述 | 17| -------- | -------- | 18| int OH_HiAppEvent_AddWatcher(HiAppEvent_Watcher \*watcher) | 添加应用事件观察者,以添加对应用事件的订阅。 | 19| int OH_HiAppEvent_RemoveWatcher(HiAppEvent_Watcher \*watcher) | 移除应用事件观察者,以移除对应用事件的订阅。 | 20 21## 开发步骤 22 23### 步骤一:新建工程 24 251. 获取该示例工程依赖的jsoncpp文件,从[三方开源库jsoncpp代码仓](https://github.com/open-source-parsers/jsoncpp)下载源码的压缩包,并按照README的**Amalgamated source**中介绍的操作步骤得到jsoncpp.cpp、json.h和json-forwards.h三个文件。 26 27 在DevEco Studio中新建工程,选择“Native C++”工程。目录结构如下: 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. 编辑“CMakeLists.txt”文件,添加源文件及动态库: 51 52 ```cmake 53 # 新增jsoncpp.cpp(解析订阅事件中的json字符串)源文件 54 add_library(entry SHARED napi_init.cpp jsoncpp.cpp) 55 # 新增动态库依赖libhiappevent_ndk.z.so和libhilog_ndk.z.so(日志输出) 56 target_link_libraries(entry PUBLIC libace_napi.z.so libhilog_ndk.z.so libhiappevent_ndk.z.so) 57 ``` 58 593. 编辑“napi_init.cpp”文件,导入依赖文件,并定义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### 步骤二:订阅系统事件 72 731. 订阅系统事件: 74 75 - onReceive类型观察者: 76 77 编辑“napi_init.cpp”文件,定义onReceive类型观察者相关方法: 78 79 ```c++ 80 //定义一变量,用来缓存创建的观察者的指针。 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 // 开发者自定义观察者名称,系统根据不同的名称来识别不同的观察者。 121 systemEventWatcher = OH_HiAppEvent_CreateWatcher("onReceiverWatcher"); 122 // 设置订阅的事件为EVENT_RESOURCE_OVERLIMIT。 123 const char *names[] = {EVENT_RESOURCE_OVERLIMIT}; 124 // 开发者订阅感兴趣的事件,此处订阅了系统事件。 125 OH_HiAppEvent_SetAppEventFilter(systemEventWatcher, DOMAIN_OS, 0, names, 1); 126 // 开发者设置已实现的回调函数,观察者接收到事件后回立即触发OnReceive回调。 127 OH_HiAppEvent_SetWatcherOnReceive(systemEventWatcher, OnReceive); 128 // 使观察者开始监听订阅的事件。 129 OH_HiAppEvent_AddWatcher(systemEventWatcher); 130 return {}; 131 } 132 ``` 133 134 - onTrigger类型观察者: 135 136 编辑“napi_init.cpp”文件,定义OnTrigger类型观察者相关方法: 137 138 ```c++ 139 //定义一变量,用来缓存创建的观察者的指针。 140 static HiAppEvent_Watcher *systemEventWatcher; 141 142 // 开发者可以自行实现获取已监听到事件的回调函数,其中events指针指向内容仅在该函数内有效。 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 // 开发者可以自行实现订阅回调函数,以便对获取到的事件打点数据进行自定义处理。 180 static void OnTrigger(int row, int size) { 181 // 接收回调后,获取指定数量的已接收事件。 182 OH_HiAppEvent_TakeWatcherData(systemEventWatcher, row, OnTake); 183 } 184 185 static napi_value RegisterWatcher(napi_env env, napi_callback_info info) { 186 // 开发者自定义观察者名称,系统根据不同的名称来识别不同的观察者。 187 systemEventWatcher = OH_HiAppEvent_CreateWatcher("onTriggerWatcher"); 188 // 设置订阅的事件为EVENT_RESOURCE_OVERLIMIT。 189 const char *names[] = {EVENT_RESOURCE_OVERLIMIT}; 190 // 开发者订阅感兴趣的事件,此处订阅了系统事件。 191 OH_HiAppEvent_SetAppEventFilter(systemEventWatcher, DOMAIN_OS, 0, names, 1); 192 // 开发者设置已实现的回调函数,需OH_HiAppEvent_SetTriggerCondition设置的条件满足方可触发。 193 OH_HiAppEvent_SetWatcherOnTrigger(systemEventWatcher, OnTrigger); 194 // 开发者可以设置订阅触发回调的条件,此处是设置新增事件打点数量为2个时,触发onTrigger回调。 195 OH_HiAppEvent_SetTriggerCondition(systemEventWatcher, 1, 0, 0); 196 // 使观察者开始监听订阅的事件。 197 OH_HiAppEvent_AddWatcher(systemEventWatcher); 198 return {}; 199 } 200 ``` 201 2022. 将RegisterWatcher注册为ArkTS接口: 203 204 编辑“napi_init.cpp”文件,将RegisterWatcher注册为ArkTS接口: 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 编辑“index.d.ts”文件,定义ArkTS接口: 218 219 ```typescript 220 export const registerWatcher: () => void; 221 ``` 222 2233. 编辑“EntryAbility.ets”文件,在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 // 启动时,注册系统事件观察者 231 testNapi.registerWatcher(); 232 } 233 } 234 ``` 235 236### 步骤三:测试资源泄漏事件 237 2381. 编辑工程中的“entry > src > main > ets > pages > Index.ets”文件,添加按钮并在其 `onClick` 函数中构造资源泄漏场景,以触发资源泄漏事件。 239 240 此处需要使用[hidebug.setAppResourceLimit](../reference/apis-performance-analysis-kit/js-apis-hidebug.md#hidebugsetappresourcelimit12)设置内存限制,造成内存泄漏,同步在“开发者选项”中打开“系统资源泄漏日志”(开关状态变更后需重启设备)。接口示例代码如下: 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. 单击DevEco Studio界面中的运行按钮,运行应用工程,单击 `pss leak` 按钮后,等待15到30分钟,系统将上报应用内存泄漏事件。 271 272 同一个应用,24小时内至多上报一次资源泄漏事件,如果短时间内要二次上报,需要重启设备。 273 2743. 内存泄漏事件上报后,可以在Log窗口看到对系统事件数据的处理日志: 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### 步骤四:移除观察者 292 2931. 移除事件观察者: 294 295 ```c++ 296 static napi_value RemoveWatcher(napi_env env, napi_callback_info info) { 297 // 移除观察者以停止监听事件 298 OH_HiAppEvent_RemoveWatcher(systemEventWatcher); 299 return {}; 300 } 301 ``` 302 3032. 销毁事件观察者: 304 305 ```c++ 306 static napi_value DestroyWatcher(napi_env env, napi_callback_info info) { 307 // 销毁创建的观察者,并置systemEventWatcher为nullptr。 308 OH_HiAppEvent_DestroyWatcher(systemEventWatcher); 309 systemEventWatcher = nullptr; 310 return {}; 311 } 312 ``` 313