订阅应用冻屏事件（ArkTS）
===============

#### 简介

本文介绍如何使用HiAppEvent提供的ArkTS接口订阅应用冻屏事件。接口的详细使用说明（参数限制、取值范围等）请参考[@ohos.hiviewdfx.hiAppEvent](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-hiviewdfx-hiappevent)。

#### 接口说明

| 接口名 | 描述 |
| :-- | :-- |
| addWatcher(watcher: Watcher): AppEventPackageHolder | 添加应用事件观察者，以添加对应用事件的订阅。 |
| removeWatcher(watcher: Watcher): void | 移除应用事件观察者，以移除对应用事件的订阅。 |

#### 开发步骤

#### \[h2\]添加事件观察者

以订阅应用冻屏事件为例，说明开发步骤。

1.  新建一个ArkTS应用工程，编辑工程中的“entry > src > main > ets > entryability > EntryAbility.ets”文件，导入依赖模块，示例代码如下：
    
    import { BusinessError, deviceInfo } from '@kit.BasicServicesKit';
    import { hiAppEvent, hilog } from '@kit.PerformanceAnalysisKit';
    
2.  编辑工程中的“entry > src > main > ets > entryability > EntryAbility.ets”文件，在onCreate函数中设置事件的自定义参数，示例代码如下：
    
     // 开发者完成参数键值对赋值
     let params: Record<string, hiAppEvent.ParamType> = {
       "test\_data": 100,
     };
     // 开发者可以设置应用冻屏事件的自定义参数
     hiAppEvent.setEventParam(params, hiAppEvent.domain.OS, hiAppEvent.event.APP\_FREEZE).then(() => {
       hilog.info(0x0000, 'testTag', \`HiAppEvent success to set event param\`);
     }).catch((err: BusinessError) => {
       hilog.error(0x0000, 'testTag', \`HiAppEvent code: ${err.code}, message: ${err.message}\`);
     });
    
     if (deviceInfo.sdkApiVersion >= 24) {  // API Version 24及以后版本，支持设置页面切换日志
       // 配置页面切换日志
       let switchLogPolicy : hiAppEvent.EventPolicy = {
         "appFreezePolicy": {
           "pageSwitchLogEnable": true
         }
       };
       // 开发者可以设置应用冻屏日志配置参数
       hiAppEvent.configEventPolicy(switchLogPolicy).then(() => {
         hilog.info(0x0000, 'testTag', \`HiAppEvent success to config event policy.\`);
       }).catch((err: BusinessError) => {
         hilog.error(0x0000, 'testTag', \`HiAppEvent code: ${err.code}, message: ${err.message}\`);
       });
     }
    
3.  编辑工程中的“entry > src > main > ets > entryability > EntryAbility.ets”文件，在onCreate函数中添加系统事件的订阅，示例代码如下：
    
      hiAppEvent.addWatcher({
       // 开发者可以自定义观察者名称，系统会使用名称来标识不同的观察者
       name: "watcher",
       // 开发者可以订阅感兴趣的系统事件，此处是订阅了应用冻屏事件
       appEventFilters: \[
         {
           domain: hiAppEvent.domain.OS,
           names: \[hiAppEvent.event.APP\_FREEZE\]
         }
       \],
       // 开发者可以自行实现订阅实时回调函数，以便对订阅获取到的事件数据进行自定义处理
       onReceive: (domain: string, appEventGroups: Array<hiAppEvent.AppEventGroup>) => {
         hilog.info(0x0000, 'testTag', \`HiAppEvent onReceive: domain=${domain}\`);
         for (const eventGroup of appEventGroups) {
           // 开发者可以根据事件集合中的事件名称区分不同的系统事件
           hilog.info(0x0000, 'testTag', \`HiAppEvent eventName=${eventGroup.name}\`);
           for (const eventInfo of eventGroup.appEventInfos) {
             // 开发者可以对事件集合中的事件数据进行自定义处理，此处是将事件数据打印在日志中
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.domain=${eventInfo.domain}\`);
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.name=${eventInfo.name}\`);
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.eventType=${eventInfo.eventType}\`);
             // 开发者可以获取到应用冻屏事件发生的时间戳
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.time=${eventInfo.params\['time'\]}\`);
             // 开发者可以获取到应用冻屏事件发生时应用的前后台状态
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.foreground=${eventInfo.params\['foreground'\]}\`);
             // 开发者可以获取到应用冻屏事件发生时应用的唯一关联id
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.app\_running\_unique\_id=${eventInfo.params\['app\_running\_unique\_id'\]}\`);
             // 开发者可以获取到应用冻屏事件发生时应用的版本信息
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.bundle\_version=${eventInfo.params\['bundle\_version'\]}\`);
             // 开发者可以获取到应用冻屏事件发生时应用的包名
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.bundle\_name=${eventInfo.params\['bundle\_name'\]}\`);
             // 开发者可以获取到应用冻屏事件发生时应用的进程名称
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.process\_name=${eventInfo.params\['process\_name'\]}\`);
             // 开发者可以获取到应用冻屏事件发生时应用的进程id
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.pid=${eventInfo.params\['pid'\]}\`);
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.uid=${eventInfo.params\['uid'\]}\`);
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.uuid=${eventInfo.params\['uuid'\]}\`);
             // 开发者可以获取到应用冻屏事件发生的异常类型、异常原因
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.exception=${JSON.stringify(eventInfo.params\['exception'\])}\`);
             // 开发者可以获取到应用冻屏事件发生时日志信息
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.hilog.size=${eventInfo.params\['hilog'\].length}\`);
             // 开发者可以获取到应用冻屏事件发生时主线程未处理消息
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.event\_handler.size=${eventInfo.params\['event\_handler'\].length}\`);
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.event\_handler\_size\_3s=${eventInfo.params\['event\_handler\_size\_3s'\]}\`);
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.event\_handler\_size\_6s=${eventInfo.params\['event\_handler\_size\_6s'\]}\`);
             // 开发者可以获取到应用冻屏事件发生时同步binder调用信息
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.peer\_binder.size=${eventInfo.params\['peer\_binder'\].length}\`);
             // 开发者可以获取到应用冻屏事件发生时全量线程调用栈
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.threads.size=${eventInfo.params\['threads'\].length}\`);
             // 开发者可以获取到应用冻屏事件发生时内存信息
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.memory=${JSON.stringify(eventInfo.params\['memory'\])}\`);
             // 开发者可以获取到应用冻屏事件发生时的故障日志文件
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.external\_log=${JSON.stringify(eventInfo.params\['external\_log'\])}\`);
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.log\_over\_limit=${eventInfo.params\['log\_over\_limit'\]}\`);
             // 开发者可以获取到应用冻屏事件的自定义数据test\_data
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.test\_data=${eventInfo.params\['test\_data'\]}\`);
             // 开发者可以获取到应用冻屏事件的故障进程存活时间
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.process\_life\_time=${eventInfo.params\['process\_life\_time'\]}\`);
             // 开发者可以获取到应用冻屏事件的回调日志信息
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.external\_callback\_log=${eventInfo.params\['external\_callback\_log'\]}\`);
             // 开发者可以获取到应用冻屏事件的页面切换日志
             hilog.info(0x0000, 'testTag', \`HiAppEvent eventInfo.params.page\_switch\_log=${JSON.stringify(eventInfo.params\['page\_switch\_log'\])}\`);
           }
         }
       }
     });
    
4.  编辑工程中的“entry > src > main > ets > pages > Index.ets”文件，添加按钮并在其onClick函数构造应用无响应场景，以触发应用冻屏事件，示例代码如下：
    
     Button("appFreeze").onClick(()=>{
       // 在按钮点击函数中构造一个freeze场景，触发应用冻屏事件
       setTimeout(() => {
         let t = Date.now();
         while (Date.now() - t <= 15000) {}
       }, 5000);
     })
    
5.  点击DevEco Studio界面中的运行按钮，运行应用工程，然后在应用界面中点击按钮“appFreeze”，触发一次应用冻屏事件。
    

#### \[h2\]验证观察者是否订阅到应用冻屏事件

1.  应用无响应退出后，重新进入应用可以在Log窗口看到对系统事件数据的处理日志：
    
    HiAppEvent onReceive: domain=OS
    HiAppEvent eventName=APP\_FREEZE
    HiAppEvent eventInfo.domain=OS
    HiAppEvent eventInfo.name=APP\_FREEZE
    HiAppEvent eventInfo.eventType=1
    HiAppEvent eventInfo.params.time=1711440881768
    HiAppEvent eventInfo.params.foreground=true
    HiAppEvent eventInfo.params.app\_running\_unique\_id=215456512336951247
    HiAppEvent eventInfo.params.bundle\_version=1.0.0
    HiAppEvent eventInfo.params.bundle\_name=com.example.myapplication
    HiAppEvent eventInfo.params.process\_name=com.example.myapplication
    HiAppEvent eventInfo.params.pid=3197
    HiAppEvent eventInfo.params.uid=20010043
    HiAppEvent eventInfo.params.uuid=27fac7098da46efe1cae9904946ec06c5acc91689c365efeefb7a23a0c37df77
    HiAppEvent eventInfo.params.exception={"message":"App main thread is not response!","name":"THREAD\_BLOCK\_6S"}
    HiAppEvent eventInfo.params.hilog.size=77
    HiAppEvent eventInfo.params.event\_handler.size=6
    HiAppEvent eventInfo.params.event\_handler\_size\_3s=5
    HiAppEvent eventInfo.params.event\_handler\_size\_6s=6
    HiAppEvent eventInfo.params.peer\_binder.size=0
    HiAppEvent eventInfo.params.threads.size=28
    HiAppEvent eventInfo.params.memory={"pss":0,"rss":0,"sys\_avail\_mem":1361464,"sys\_free\_mem":796232,"sys\_total\_mem":1992340,"vm\_heap\_total\_size":"9961472","vm\_heap\_used\_size":"7596424","vss":0}
    HiAppEvent eventInfo.params.external\_log=\["/data/storage/el2/log/hiappevent/APP\_FREEZE\_1711440899240\_3197.log"\]
    HiAppEvent eventInfo.params.log\_over\_limit=false
    HiAppEvent eventInfo.params.test\_data=100
    HiAppEvent eventInfo.params.process\_life\_time=18
    HiAppEvent eventInfo.params.external\_callback\_log=THREAD\_BLOCK\_3S:log3s THREAD\_BLOCK\_6S:log6s
    
2.  若应用无法启动或长时间未启动，开发者可以参考[使用FaultLogExtensionAbility订阅事件](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/fault-log-extension-app-events-arkts)回调重写的函数，进行延迟上报。
    

#### 从Faultlogger接口迁移应用冻屏事件

[@ohos.faultLogger (故障日志获取)](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-faultlogger)接口从API version 18开始废弃使用, 不再维护。后续版本推荐使用[@ohos.hiviewdfx.hiAppEvent](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-hiviewdfx-hiappevent)订阅应用冻屏事件。该章节指导开发者从Faultlogger接口迁移至hiAppEvent接口，来订阅应用冻屏事件。

在Faultlogger的[FaultType](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-faultlogger#faulttype)里定义的APP\_FREEZE即为应用冻屏故障类型。

在hiAppEvent的hiAppEvent.addWatcher接口中设置事件名称为hiAppEvent.event.APP\_FREEZE、事件领域为hiAppEvent.domain.OS，可以订阅应用冻屏事件。

通过[hiAppEvent.AppEventInfo.params](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/hiappevent-watcher-freeze-events#params字段说明)中exception字段的name子字段可以区分具体是哪种应用冻屏事件。

[FaultLogInfo](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-faultlogger#faultloginfo)与[hiAppEvent.AppEventInfo.params](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/hiappevent-watcher-freeze-events#params字段说明)的字段对应关系如下：

| Faultlogger.FaultLogInfo | hiAppEvent.AppEventInfo.params | 说明 |
| :-- | :-- | :-- |
| pid | pid | 无。 |
| uid | uid | 无。 |
| type | exception字段中的name子字段 | 类型不同，Faultlogger中是故障类型枚举，hiAppEvent中是字符串类型。 |
| timestamp | time | 无。 |
| module | bundle\_name | 无。 |
| fullLog | external\_log | fullLog为故障日志全文。external\_log为故障日志文件在应用沙箱中的具体路径(/data/storage/el2/log/)，访问该路径的文件，可以得到故障日志全文。 |
| reason | external\_log文件内容中的Reason字段 | 无。 |
| summary | external\_log文件内容中特定段落 | APP\_FREEZE的summary对应external\_log文件中从appfreeze:进程名所在行到DisplayPowerInfo:所在行的这一段内容。 |

[FaultLogger.query(使用callback回调)](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-faultlogger#faultloggerquery9)和[FaultLogger.query(使用Promise回调)](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-faultlogger#faultloggerquery9-1)都可以使用[hiAppEvent.addWatcher](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-hiviewdfx-hiappevent#hiappeventaddwatcher)实现相同功能。

查阅[开发步骤](#开发步骤)和[验证观察者是否订阅到应用冻屏事件](#验证观察者是否订阅到应用冻屏事件)，了解使用hiAppEvent订阅应用冻屏事件（ArkTS）的具体步骤。

#### 示例代码

*   [应用异常处理](https://gitcode.com/HarmonyOS_Samples/exception-handling)