当应用的代码存在规范问题或错误时,会在运行中产生异常和错误,如应用未捕获异常等。在错误产生后,应用会异常退出。错误日志通常会保存在用户本地存储设备中,不方便开发者定位问题。所以,应用开发者可以使用错误管理的接口,在应用退出前,及时将相关错误及日志上报到开发者的服务平台来定位问题。
使用errorManager接口监听异常和错误后,应用不会退出,建议在回调函数执行完后,增加同步退出操作,如果只是为了获取错误日志,建议使用HiAppEvent订阅事件。
应用错误管理接口由@ohos.app.ability.errorManager (错误管理模块)提供,使用接口能力前需注册错误观测器,开发者可以通过import引入,详见开发示例。
错误管理接口功能介绍:
| 接口名称 | 说明 |
|---|---|
| on(type: "error", observer: ErrorObserver): number | 注册错误监听接口,当系统监测到应用异常时会回调该监听。该接口为同步接口,返回值为注册的监听对象对应的序号。 |
| off(type: "error", observerId: number, callback: AsyncCallback<void>): void | 以callback的形式解除注册监听,传入的number为之前注册监听时返回的序号。 |
| off(type: "error", observerId: number): Promise<void> | 以Promise的形式解除注册监听,传入的number为之前注册监听时返回的序号。 |
| on(type: 'globalErrorOccurred', observer: GlobalObserver): void | 注册进程错误监听接口,当系统监测到应用异常时会回调该监听,该接口为同步接口,即一次注册,全局监听。 说明:从API version 18开始,支持该接口。 |
| off(type: 'globalErrorOccurred', observer?: GlobalObserver): void | 以callback的形式解除注册监听。 说明: - 从API version 18开始,支持该接口。 - 注销监听器时可以监听进程中所有线程的异常,建议在进程回收时调用off接口,否则可能造成应用崩溃。 |
| on(type: 'globalUnhandledRejectionDetected', observer: GlobalObserver): void | 注册进程错误监听接口,当系统监测到应用promise异常时会回调该监听,该接口为同步接口,即一次注册,全局监听。 说明:从API version 18开始,支持该接口。 |
| off(type: 'globalUnhandledRejectionDetected', observer?: GlobalObserver): void | 以callback的形式解除注册监听。 说明: - 从API version 18开始,支持该接口。 - 注销监听器时可以监听进程中所有线程的异常,建议在进程回收时调用off接口,否则可能造成应用崩溃。 |
| on(type: 'loopObserver', timeout: number, observer: LoopObserver): void | 注册主线程消息处理耗时监听器,当系统监测到应用主线程事件处理超时时会回调该监听。 只能在主线程调用,多次注册后,后一次的注册会覆盖前一次的。 |
| off(type: 'loopObserver', observer?: LoopObserver): void | 以LoopObserver的形式解除应用主线程消息处理耗时监听。 |
| on(type: 'freeze', observer: FreezeObserver): void | 注册应用主线程freeze监听。只能在主线程调用,重复注册后,后一次的注册会覆盖前一次的。 |
| off(type: 'freeze', observer?: FreezeObserver): void | 以FreezeObserver的形式解除应用主线程消息处理耗时监听。 说明:从API version 18开始,支持该接口。 |
| setDefaultErrorHandler(defaultHandler?: ErrorHandler): ErrorHandler | 仅允许在主线程调用,发生JS_CRASH异常时,支持链式回调,返回值为上一次注册的处理器。 说明:从API version 21开始,支持该接口。 |
| setDefaultResourceUsageObserver(defaultObserver?: ResourceUsageObserver): ResourceUsageObserver; | 仅允许在主线程调用,发生应用资源超基线时,支持链式回调,返回值为上一次注册的资源占用观察者。 说明:从API version 24开始,支持该接口。 |
| setDefaultFreezeObserver(defaultObserver?: FreezeObserver) : FreezeObserver | 仅允许在主线程调用,发生APP_FREEZE异常时,支持链式回调,返回值为上一次注册的处理器。 说明:从API版本26.0.0开始,支持该接口。 模型约束: 此接口仅可在Stage模型下使用。 |
当采用callback作为异步回调时,可以在callback中进行下一步处理。
当采用Promise对象返回时,可以在Promise对象中类似地处理接口返回值,具体结果码说明见解除注册结果码。
错误监听(ErrorObserver)接口功能介绍:
| 接口名称 | 说明 |
|---|---|
| onUnhandledException(errMsg: string): void | 系统回调接口,应用注册后,当应用产生未捕获的异常时的回调。 |
| onException?(errObject: Error): void | 系统回调接口,应用注册后,当应用产生异常上报JS层时的回调。 |
应用主线程监听(LoopObserver)接口功能介绍:
| 接口名称 | 说明 |
|---|---|
| onLoopTimeOut?(timeout: number): void | 系统回调接口,应用注册后,当应用主线程处理事件超时的回调。 |
引入头文件。
import { errorManager } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit'; 自定义hilog打印的domain值。
const DOMAIN = 0x0000;
新增监听回调函数。
let observer: errorManager.ErrorObserver = {
onUnhandledException(errorMsg) {
hilog.error(DOMAIN, 'testErrorManage', 'onUnhandledException, errorMsg: %{public}s', errorMsg);
},
onException(errorObj) {
hilog.error(DOMAIN, 'testErrorManage', 'onException, name: %{public}s', errorObj.name);
hilog.error(DOMAIN, 'testErrorManage', 'onException, message: %{public}s', errorObj.message);
if (typeof(errorObj.stack) === 'string') {
hilog.error(DOMAIN, 'testErrorManage', 'onException, stack: %{public}s', errorObj.stack);
}
}
}; 新增触发按钮。
Button('单线程监听场景').onClick(()=>{
let observerId = -1;
try {
observerId = errorManager.on('error', observer);
} catch (paramError) {
let code = (paramError as BusinessError).code;
let message = (paramError as BusinessError).message;
hilog.error(DOMAIN, 'testErrorManage', 'error: %{public}s, %{public}s', `${code}`, `${message}`);
}
// 构造场景故障
throw new Error('test errorObserver msg');
}).position({x:50, y:50}); 引入头文件。
import { errorManager } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit'; 自定义hilog打印的domain值。
const DOMAIN = 0x0000;
新增监听回调函数。
function errorFunc(observer: errorManager.GlobalError) {
hilog.error(DOMAIN, 'testErrorManage', 'result name :%{public}s', observer.name);
hilog.error(DOMAIN, 'testErrorManage', 'result message :%{public}s', observer.message);
hilog.error(DOMAIN, 'testErrorManage', 'result stack :%{public}s', observer.stack);
hilog.error(DOMAIN, 'testErrorManage', 'result instanceName :%{public}s', observer.instanceName);
hilog.error(DOMAIN, 'testErrorManage', 'result instanceType :%{public}s', observer.instanceType);
}; 新增触发按钮。
Button('进程监听异常场景').onClick(()=>{
try {
errorManager.on('globalErrorOccurred', errorFunc);
} catch (paramError) {
let code = (paramError as BusinessError).code;
let message = (paramError as BusinessError).message;
hilog.error(DOMAIN, 'testErrorManage', 'error: %{public}s, %{public}s', `${code}`, `${message}`);
}
// 构造场景故障
throw new Error('test errorFunc msg');
}).position({x:50, y:100}); 引入头文件。
import { errorManager } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit'; 自定义hilog打印的domain值。
const DOMAIN = 0x0000;
新增监听回调函数。
function promiseFunc(observer: errorManager.GlobalError) {
hilog.error(DOMAIN, 'testErrorManage', 'result name :%{public}s', observer.name);
hilog.error(DOMAIN, 'testErrorManage', 'result message :%{public}s', observer.message);
hilog.error(DOMAIN, 'testErrorManage', 'result stack :%{public}s', observer.stack);
hilog.error(DOMAIN, 'testErrorManage', 'result instanceName :%{public}s', observer.instanceName);
hilog.error(DOMAIN, 'testErrorManage', 'result instanceType :%{public}s', observer.instanceType);
};
async function promiseFuncOne() {
throw new Error('process promise exception');
}; 新增触发按钮。
Button('进程监听promise异常场景').onClick(()=>{
try {
errorManager.on('globalUnhandledRejectionDetected', promiseFunc);
} catch (paramError) {
let code = (paramError as BusinessError).code;
let message = (paramError as BusinessError).message;
hilog.error(DOMAIN, 'testErrorManage', 'error: %{public}s, %{public}s', `${code}`, `${message}`);
}
// 构造场景故障
new Promise<string>(() => {
promiseFuncOne();
}).then(() => {
throw new Error('test promiseFuncOne msg');
});
}).position({x:50, y:200}); 引入头文件。
import { errorManager } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit'; 自定义hilog打印的domain值。
const DOMAIN = 0x0000;
新增监听回调函数。
function freezeCallback() {
hilog.error(DOMAIN, 'testErrorManage', '%{public}s', 'freezecallback');
}; 新增触发按钮。
Button('主线程监听freeze').onClick(()=>{
try {
errorManager.on('freeze', freezeCallback);
} catch (paramError) {
let code = (paramError as BusinessError).code;
let message = (paramError as BusinessError).message;
hilog.error(DOMAIN, 'testErrorManage', 'error: %{public}s, %{public}s', `${code}`, `${message}`);
}
// 构造场景故障
let date = Date.now();
while (Date.now() - date < 15000) {
};
}).position({x:50, y:300}); 引入头文件。
import { errorManager } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit'; 自定义hilog打印的domain值。
const DOMAIN = 0x0000;
新增监听回调函数。
let loopObserver: errorManager.LoopObserver = {
onLoopTimeOut(timeout: number) {
hilog.error(DOMAIN, 'testErrorManage', 'Duration timeout: %{public}s', `${timeout}`);
}
}; 新增触发按钮。
Button('主线程监听消息处理耗时').onClick(()=>{
try {
errorManager.on('loopObserver', 1, loopObserver);
} catch (paramError) {
let code = (paramError as BusinessError).code;
let message = (paramError as BusinessError).message;
hilog.error(DOMAIN, 'testErrorManage', 'error: %{public}s, %{public}s', `${code}`, `${message}`);
}
// 构造场景故障
let date = Date.now();
while (Date.now() - date < 4000) {
};
}).position({x:50, y:150}); 引入头文件。
import { errorManager } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit'; 自定义hilog打印的domain值。
const DOMAIN = 0x0000;
新增监听回调函数。
let promise1 = new Promise<void>(() => {}).then(() => {
throw new Error('uncaught error');
});
let unhandledrejectionObserver: errorManager.UnhandledRejectionObserver = (reason: Error, promise: Promise<void>) => {
if (promise === promise1) {
hilog.error(DOMAIN, 'testErrorManage', '%{public}s', 'promise1 is rejected');
}
hilog.error(DOMAIN, 'testErrorManage', 'reason.name: %{public}s', reason.name);
hilog.error(DOMAIN, 'testErrorManage', 'reason.message: %{public}s', reason.message);
if (reason.stack) {
hilog.error(DOMAIN, 'testErrorManage', 'reason.stack: %{public}s', reason.stack);
}
};
async function promiseFuncTwo() {
throw new Error('process promise unhandled rejection exception');
}; 新增触发按钮。
Button('进程promise监听注册被拒绝').onClick(()=>{
try {
errorManager.on('unhandledRejection', unhandledrejectionObserver);
} catch (paramError) {
let code = (paramError as BusinessError).code;
let message = (paramError as BusinessError).message;
hilog.error(DOMAIN, 'testErrorManage', 'error: %{public}s, %{public}s', `${code}`, `${message}`);
}
// 构造场景故障
new Promise<string>(() => {
promiseFuncTwo();
}).then(() => {
throw new Error('test promiseFuncTwo msg');
});
}).position({x:50, y:250}); 定义第一个错误处理器及注册方法,无前置处理器时退出进程。
import { errorManager } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { process } from '@kit.ArkTS';
import { BusinessError } from '@kit.BasicServicesKit';
const DOMAIN = 0x0000;
let firstHandler: errorManager.ErrorHandler;
const firstErrorHandler: errorManager.ErrorHandler = (reason: Error) => {
// 自定义的第一个errorHandler实现逻辑
hilog.info(DOMAIN, 'testErrorManage', '%{public}s', '[FirstHandler] First uncaught exception handler invoked.');
if (firstHandler) {
firstHandler(reason);
} else {
// 建议增加判空操作,如果为空采用同步退出方式
const processManager = new process.ProcessManager();
processManager.exit(0);
}
};
export function setFirstErrorHandler() {
try {
firstHandler = errorManager.setDefaultErrorHandler(firstErrorHandler);
} catch (paramError) {
let code = (paramError as BusinessError).code;
let message = (paramError as BusinessError).message;
hilog.error(DOMAIN, 'testErrorManage', 'error: %{public}s, %{public}s', `${code}`, `${message}`);
}
hilog.info(DOMAIN, 'testErrorManage', '%{public}s', 'Registered First Error Handler');
} 定义第二个错误处理器及注册方法,形成链式调用。
import { errorManager } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { process } from '@kit.ArkTS';
import { BusinessError } from '@kit.BasicServicesKit';
const DOMAIN = 0x0000;
let secondHandler: errorManager.ErrorHandler;
const secondErrorHandler: errorManager.ErrorHandler = (reason: Error) => {
// 自定义的第二个errorHandler实现逻辑
hilog.info(DOMAIN, 'testErrorManage', '%{public}s', '[SecondHandler] Second uncaught exception handler invoked.');
if (secondHandler) {
secondHandler(reason);
} else {
const processManager = new process.ProcessManager();
processManager.exit(0);
}
};
export function setSecondErrorHandler() {
try {
secondHandler = errorManager.setDefaultErrorHandler(secondErrorHandler);
} catch (paramError) {
let code = (paramError as BusinessError).code;
let message = (paramError as BusinessError).message;
hilog.error(DOMAIN, 'testErrorManage', 'error: %{public}s, %{public}s', `${code}`, `${message}`);
}
hilog.info(DOMAIN, 'testErrorManage', '%{public}s', 'Registered Second Error Handler');
} 引入头文件。
import { setFirstErrorHandler } from './FirstErrorHandler';
import { setSecondErrorHandler } from './SecondErrorHandler'; 新增错误处理器责任链模式构造函数。
function testErrorHandlers() {
setFirstErrorHandler();
setSecondErrorHandler();
throw new Error('Test uncaught exception!');
} 主组件通过按钮触发测试,注册两个处理器并抛错验证处理链。
Button('错误处理器责任链模式场景').onClick(()=>{
testErrorHandlers();
}).position({x:50, y:350}); 定义第一个freeze处理器及注册方法,无前置处理器时退出进程。
import { errorManager } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';
const DOMAIN = 0x0000;
let firstHandler: errorManager.FreezeObserver = () => {};
const firstFreezeHandler: errorManager.FreezeObserver = () => {
// 自定义的第一个FreezeHandler实现逻辑
hilog.info(DOMAIN, 'testErrorManage', '%{public}s', '[FirstHandler] First freeze handler invoked.');
if (firstHandler) {
firstHandler();
} else {
hilog.info(DOMAIN, 'testErrorManage', '%{public}s', '[FirstHandler] First freeze handler end.');
}
};
export function setFirstFreezeHandler() {
try {
firstHandler = errorManager.setDefaultFreezeObserver(firstFreezeHandler);
} catch (paramError) {
let code = (paramError as BusinessError).code;
let message = (paramError as BusinessError).message;
hilog.error(DOMAIN, 'testErrorManage', 'error: %{public}s, %{public}s', `${code}`, `${message}`);
}
hilog.info(DOMAIN, 'testErrorManage', '%{public}s', 'Registered First freeze Handler.');
} 定义第二个freeze处理器及注册方法,形成链式调用。
import { errorManager } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { BusinessError } from '@kit.BasicServicesKit';
const DOMAIN = 0x0000;
let secondHandler: errorManager.FreezeObserver = () => {};
const secondFreezeHandler: errorManager.FreezeObserver = () => {
// 自定义的第二个SecondHandler实现逻辑
hilog.info(DOMAIN, 'testErrorManage', '%{public}s', '[SecondHandler] Second freeze handler invoked.');
if (secondHandler) {
secondHandler();
} else {
hilog.info(DOMAIN, 'testErrorManage', '%{public}s', '[SecondHandler] Second freeze handler end.');
}
};
export function setSecondFreezeHandler() {
try {
secondHandler = errorManager.setDefaultFreezeObserver(secondFreezeHandler);
} catch (paramError) {
let code = (paramError as BusinessError).code;
let message = (paramError as BusinessError).message;
hilog.error(DOMAIN, 'testErrorManage', 'error: %{public}s, %{public}s', `${code}`, `${message}`);
}
hilog.info(DOMAIN, 'testErrorManage', '%{public}s', 'Registered Second freeze Handler.');
} 引入头文件。
import { setFirstFreezeHandler } from './FirstFreezeHandler';
import { setSecondFreezeHandler } from './SecondFreezeHandler'; 新增构造场景故障函数。
function waitTime() {
// 构造场景故障
let date = Date.now();
while (Date.now() - date < 15000) {
};
} 新增freeze处理器责任链模式构造函数。
function testFreezeHandlers() {
setFirstFreezeHandler();
setSecondFreezeHandler();
waitTime();
} 主组件通过按钮触发测试,注册两个处理器并调用构造场景故障函数验证处理链。
Button('freeze处理器责任链模式场景').onClick(()=>{
testFreezeHandlers();
}).position({x:50, y:400});