• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# 错误管理开发指导
2
3<!--Kit: Performance Analysis Kit-->
4<!--Subsystem: HiviewDFX-->
5<!--Owner: @rr_cn-->
6<!--Designer: @peterhuangyu-->
7<!--Tester: @gcw_KuLfPSbe-->
8<!--Adviser: @foryourself-->
9
10## 场景介绍
11
12当应用的代码存在规范问题或错误时,会在运行中产生异常和错误,如应用未捕获异常等。在错误产生后,应用会异常退出。错误日志通常会保存在用户本地存储设备中,不方便开发者定位问题。所以,应用开发者可以使用错误管理的接口,在应用退出前,及时将相关错误及日志上报到开发者的服务平台来定位问题。
13
14使用errorManager接口监听异常和错误后,应用不会退出,建议在回调函数执行完后,增加同步退出操作,如果只是为了获取错误日志,建议使用[HiAppEvent订阅事件](hiappevent-intro.md)。
15
16## 接口说明
17
18应用错误管理接口由[@ohos.app.ability.errorManager (错误管理模块)](../reference/apis-ability-kit/js-apis-app-ability-errorManager.md)提供,使用接口能力前需注册错误观测器,开发者可以通过import引入,详见[开发示例](#开发示例)。
19
20**错误管理接口功能介绍**:
21
22| 接口名称 | 说明 |
23| -------- | -------- |
24| on(type: "error", observer: ErrorObserver): number | 注册错误监听接口,当系统监测到应用异常时会回调该监听。该接口为同步接口,返回值为注册的监听对象对应的序号。 |
25| off(type: "error", observerId: number, callback: AsyncCallback&lt;void>): void | 以callback的形式解除注册监听,传入的number为之前注册监听时返回的序号。 |
26| off(type: "error", observerId: number): Promise&lt;void> | 以Promise的形式解除注册监听,传入的number为之前注册监听时返回的序号。 |
27| on(type: 'globalErrorOccurred', observer: GlobalObserver): void | 注册进程错误监听接口,当系统监测到应用异常时会回调该监听,该接口为同步接口,即一次注册,全局监听。(**推荐使用**)<br/>说明:从API version 18开始,支持该接口。 |
28| off(type: 'globalErrorOccurred', observer?: GlobalObserver): void | 以callback的形式解除注册监听。(**推荐使用**)<br/>说明:从API version 18开始,支持该接口。 |
29| on(type: 'globalUnhandledRejectionDetected', observer: GlobalObserver): void | 注册进程错误监听接口,当系统监测到应用promise异常时会回调该监听,该接口为同步接口,即一次注册,全局监听。(**推荐使用**)<br/>说明:从API version 18开始,支持该接口。 |
30| off(type: 'globalUnhandledRejectionDetected', observer?: GlobalObserver): void | 以callback的形式解除注册监听。(**推荐使用**)<br/>说明:从API version 18开始,支持该接口。 |
31| on(type: 'loopObserver', timeout: number, observer: LoopObserver): void | 注册主线程消息处理耗时监听器,当系统监测到应用主线程事件处理超时时会回调该监听。<br/>只能在主线程调用,多次注册后,后一次的注册会覆盖前一次的。 |
32| off(type: 'loopObserver', observer?: LoopObserver): void | 以LoopObserver的形式解除应用主线程消息处理耗时监听。 |
33| on(type: 'freeze', observer: FreezeObserver): void | 注册应用主线程freeze监听。只能在主线程调用,重复注册后,后一次的注册会覆盖前一次的。 |
34| off(type: 'freeze', observer?: FreezeObserver): void | 以FreezeObserver的形式解除应用主线程消息处理耗时监听。<br/>说明:从API version 18开始,支持该接口。 |
35
36当采用callback作为异步回调时,可以在callback中进行下一步处理。
37当采用Promise对象返回时,可以在Promise对象中类似地处理接口返回值,具体结果码说明见[解除注册结果码](#解除注册结果码)。
38
39**错误监听(ErrorObserver)接口功能介绍**:
40
41| 接口名称 | 说明 |
42| -------- | -------- |
43| onUnhandledException(errMsg: string): void | 系统回调接口,应用注册后,当应用产生未捕获的异常时的回调。 |
44| onException?(errObject: Error): void | 系统回调接口,应用注册后,当应用产生异常上报js层时的回调。 |
45
46**应用主线程监听(LoopObserver)接口功能介绍**:
47
48| 接口名称 | 说明 |
49| -------- | -------- |
50| onLoopTimeOut?(timeout: number): void | 系统回调接口,应用注册后,当应用主线程处理事件超时的回调。 |
51
52### 解除注册结果码
53
54| 结果码 | 原因 |
55| -------- | -------- |
56| 0 | 正常返回 |
57| -1 | 传入的number参数不存在 |
58| -2 | 参数错误 |
59
60## 开发示例
61
62> **注意:**
63>
64> 建议在异常回调函数处理的最后,增加同步退出操作,以避免多次异常回调。
65
66### 单线程监听场景
67
68```ts
69import { AbilityConstant, errorManager, UIAbility, Want } from '@kit.AbilityKit';
70import { window } from '@kit.ArkUI';
71import { process } from '@kit.ArkTS';
72
73let registerId = -1;
74let callback: errorManager.ErrorObserver = {
75    onUnhandledException: (errMsg) => {
76        console.info(errMsg);
77    },
78    onException: (errorObj) => {
79        console.info('onException, name: ', errorObj.name);
80        console.info('onException, message: ', errorObj.message);
81        if (typeof(errorObj.stack) == 'string') {
82            console.info('onException, stack: ', errorObj.stack);
83        }
84        //回调函数执行完,采用同步退出方式,避免多次触发异常
85        let pro = new process.ProcessManager();
86        pro.exit(0);
87    }
88}
89
90let abilityWant: Want;
91
92export default class EntryAbility extends UIAbility {
93    onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
94        console.info("[Demo] EntryAbility onCreate");
95        registerId = errorManager.on("error", callback);
96        abilityWant = want;
97    }
98
99    onDestroy() {
100        console.info("[Demo] EntryAbility onDestroy");
101        errorManager.off("error", registerId, (result) => {
102            console.info("[Demo] result " + result.code + ";" + result.message);
103        });
104    }
105
106    onWindowStageCreate(windowStage: window.WindowStage) {
107        // 为已创建的主窗口设置主页面
108        console.info("[Demo] EntryAbility onWindowStageCreate");
109
110        windowStage.loadContent("pages/index", (err) => {
111            if (err.code) {
112                console.error('Failed to load the content. Cause:' + JSON.stringify(err));
113                return;
114            }
115        });
116    }
117
118    onWindowStageDestroy() {
119        // 销毁主窗口,释放相关UI资源
120        console.info("[Demo] EntryAbility onWindowStageDestroy");
121    }
122
123    onForeground() {
124        // 切换前台
125        console.info("[Demo] EntryAbility onForeground");
126    }
127
128    onBackground() {
129        // 切换后台
130        console.info("[Demo] EntryAbility onBackground");
131    }
132};
133```
134
135### 进程监听异常场景
136
137```ts
138import { AbilityConstant, errorManager, UIAbility, Want } from '@kit.AbilityKit';
139import { window } from '@kit.ArkUI';
140import { process } from '@kit.ArkTS';
141
142function errorFunc(observer: errorManager.GlobalError) {
143    console.info("[Demo] result name :" + observer.name);
144    console.info("[Demo] result message :" + observer.message);
145    console.info("[Demo] result stack :" + observer.stack);
146    console.info("[Demo] result instanceName :" + observer.instanceName);
147    console.info("[Demo] result instanceType :" + observer.instanceType);
148    //回调函数执行完,采用同步退出方式,避免多次触发异常
149    let pro = new process.ProcessManager();
150    pro.exit(0);
151}
152
153let abilityWant: Want;
154
155export default class EntryAbility extends UIAbility {
156    onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
157        console.info("[Demo] EntryAbility onCreate");
158        errorManager.on("globalErrorOccurred", errorFunc);
159        abilityWant = want;
160    }
161
162    onDestroy() {
163        console.info("[Demo] EntryAbility onDestroy");
164        errorManager.off("globalErrorOccurred", errorFunc);
165    }
166
167    onWindowStageCreate(windowStage: window.WindowStage) {
168        // 为已创建的主窗口设置主页面
169        console.info("[Demo] EntryAbility onWindowStageCreate");
170
171        windowStage.loadContent("pages/index", (err) => {
172            if (err.code) {
173                console.error('Failed to load the content. Cause:' + JSON.stringify(err));
174                return;
175            }
176        });
177    }
178
179    onWindowStageDestroy() {
180        // 销毁主窗口,释放相关UI资源
181        console.info("[Demo] EntryAbility onWindowStageDestroy");
182    }
183
184    onForeground() {
185        // 切换前台
186        console.info("[Demo] EntryAbility onForeground");
187    }
188
189    onBackground() {
190        // 切换后台
191        console.info("[Demo] EntryAbility onBackground");
192    }
193};
194```
195
196### 进程监听promise异常场景
197
198```ts
199import { AbilityConstant, errorManager, UIAbility, Want } from '@kit.AbilityKit';
200import { window } from '@kit.ArkUI';
201import { process } from '@kit.ArkTS';
202
203function promiseFunc(observer: errorManager.GlobalError) {
204    console.info("[Demo] result name :" + observer.name);
205    console.info("[Demo] result message :" + observer.message);
206    console.info("[Demo] result stack :" + observer.stack);
207    console.info("[Demo] result instanceName :" + observer.instanceName);
208    console.info("[Demo] result instanceType :" + observer.instanceType);
209    //回调函数执行完,采用同步退出方式,避免多次触发异常
210    let pro = new process.ProcessManager();
211    pro.exit(0);
212}
213
214
215let abilityWant: Want;
216
217export default class EntryAbility extends UIAbility {
218    onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
219        console.info("[Demo] EntryAbility onCreate");
220        errorManager.on("globalUnhandledRejectionDetected", promiseFunc);
221        abilityWant = want;
222    }
223
224    onDestroy() {
225        console.info("[Demo] EntryAbility onDestroy");
226        errorManager.off("globalUnhandledRejectionDetected", promiseFunc);
227    }
228
229    onWindowStageCreate(windowStage: window.WindowStage) {
230        // 为已创建的主窗口设置主页面
231        console.info("[Demo] EntryAbility onWindowStageCreate");
232
233        windowStage.loadContent("pages/index", (err) => {
234            if (err.code) {
235                console.error('Failed to load the content. Cause:' + JSON.stringify(err));
236                return;
237            }
238        });
239    }
240
241    onWindowStageDestroy() {
242        // 销毁主窗口,释放相关UI资源
243        console.info("[Demo] EntryAbility onWindowStageDestroy");
244    }
245
246    onForeground() {
247        // 切换前台
248        console.info("[Demo] EntryAbility onForeground");
249    }
250
251    onBackground() {
252        // 切换后台
253        console.info("[Demo] EntryAbility onBackground");
254    }
255};
256```
257
258### 主线程监听freeze
259
260```ts
261import { AbilityConstant, errorManager, UIAbility, Want } from '@kit.AbilityKit';
262import { window } from '@kit.ArkUI';
263import { process } from '@kit.ArkTS';
264
265// Define freezeCallback
266function freezeCallback() {
267    console.info("freezecallback");
268}
269
270
271let abilityWant: Want;
272
273export default class EntryAbility extends UIAbility {
274    onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) {
275        console.info("[Demo] EntryAbility onCreate");
276        errorManager.on("freeze", freezeCallback);
277        abilityWant = want;
278    }
279
280    onDestroy() {
281        console.info("[Demo] EntryAbility onDestroy");
282        errorManager.off("freeze", freezeCallback);
283    }
284
285    onWindowStageCreate(windowStage: window.WindowStage) {
286        // 为已创建的主窗口设置主页面
287        console.info("[Demo] EntryAbility onWindowStageCreate");
288
289        windowStage.loadContent("pages/index", (err) => {
290            if (err.code) {
291                console.error('Failed to load the content. Cause:' + JSON.stringify(err));
292                return;
293            }
294        });
295    }
296
297    onWindowStageDestroy() {
298        // 销毁主窗口,释放相关UI资源
299        console.info("[Demo] EntryAbility onWindowStageDestroy");
300    }
301
302    onForeground() {
303        // 切换前台
304        console.info("[Demo] EntryAbility onForeground");
305    }
306
307    onBackground() {
308        // 切换后台
309        console.info("[Demo] EntryAbility onBackground");
310    }
311};
312```
313