ANR 如何产生?

1.概念

ANR application not responding 应用程序无响应
一般页面卡顿时间超过(一般是5秒)一定时间就会出现ANR提示框。
如果发生ANR,会产生trace.txt文件,提示错误。

adb pull data/anr/trances.txt 导入ANR的错误日志

2.原因

一般是输入事件超出时间限制,且无响应,就会发生ANR。
keyDispatchTimeOut 5s
BroadcastTimeOut 前台10s 后台60s
ServiceTimeOut 前台20s 后台200s

3.ANR触发原理

比如我们启动一个service,当service的创建超过了时间限制,就会发生一个ANR的提示出来。
具体原理
1.启动service

ActiveServices.java

private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException {
    
    
    ...
    //发送delay消息(SERVICE_TIMEOUT_MSG)
    bumpServiceExecutingLocked(r, execInFg, "create");
    try {
    
    
        ...
        //最终执行服务的onCreate()方法
        app.thread.scheduleCreateService(r, r.serviceInfo,
                mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                app.repProcState);
    } catch (DeadObjectException e) {
    
    
        mAm.appDiedLocked(app);
        throw e;
    } finally {
    
    
        ...
    }
}

ActiveService.bumpServiceExecutingLocked

private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
    
    
    ... 
    scheduleServiceTimeoutLocked(r.app);
}

void scheduleServiceTimeoutLocked(ProcessRecord proc) {
    
    
    if (proc.executingServices.size() == 0 || proc.thread == null) {
    
    
        return;
    }
    long now = SystemClock.uptimeMillis();
    Message msg = mAm.mHandler.obtainMessage(
            ActivityManagerService.SERVICE_TIMEOUT_MSG);
    msg.obj = proc;
    
    //当超时后仍没有remove该SERVICE_TIMEOUT_MSG消息, 
    mAm.mHandler.sendMessageAtTime(msg,
        proc.execServicesFg ? (now+SERVICE_TIMEOUT) : (now+ SERVICE_BACKGROUND_TIMEOUT));
}

当启动service的时候,发送一个延迟消息,如果这个时间内,service没有创建成功,就无法撤销延迟消息,所以就发生ANR。

4 何时取消了延迟消息

ActivityThread.java

private void handleCreateService(CreateServiceData data) {
    
    
        ...
        java.lang.ClassLoader cl = packageInfo.getClassLoader();
        Service service = (Service) cl.loadClass(data.info.name).newInstance();
        ...

        try {
    
    
            //创建ContextImpl对象
            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);
            //创建Application对象
            Application app = packageInfo.makeApplication(false, mInstrumentation);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManagerNative.getDefault());
            //调用服务onCreate()方法 
            service.onCreate();
            
            //拆除炸弹引线[见小节2.2.2]
            ActivityManagerNative.getDefault().serviceDoneExecuting(
                    data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
        } catch (Exception e) {
    
    
            ...
        }
    }

AS.serviceDoneExecutingLocked

private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying, boolean finishing) {
    
    
    ...
    if (r.executeNesting <= 0) {
    
    
        if (r.app != null) {
    
    
            r.app.execServicesFg = false;
            r.app.executingServices.remove(r);
            if (r.app.executingServices.size() == 0) {
    
    
                //当前服务所在进程中没有正在执行的service
                mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
        ...
    }
    ...
}

Guess you like

Origin blog.csdn.net/chentaishan/article/details/106039256