ANR详解

作者: CDF_cc7d | 来源:发表于2020-08-16 09:49 被阅读0次

    说到ANR,首先提出以下三个问题

    • ANR是什么
    • ANR什么时候出现
    • ANR发生的原理

    带着这三个问题我们进入本次的话题


    ANR是什么

    ANR全称Application Not Response,应用无响应。指的是一定时间内处理某一事件超过一定时间就会弹出应用无响应的弹框,用于用户可以强制结束进程。

    ANR什么时候出现

    • InputDispatch响应时间超过5秒
    • BroadCastReceiver 前台响应时间超过10秒,后台响应时间超过60秒
    • Service 前台响应时间超过20秒,后台响应时间超过200秒
    • ContentProvider响应时间超过10秒

    ANR发生的原理

    针对上面4种情况接下来一一分析:

    1. InputDispatch ANR

    Android底层接收处理触摸事件主要依赖
    InputReader.cpp和InputDispatcher.cpp两大类。这里先简单介绍下这两个类
    首先来看InputReader.cpp

    /frameworks/native/services/inputflinger/InputReader.cpp

    bool InputReaderThread::threadLoop() {
        mReader->loopOnce();
        return true;
    }
    
    void InputReader::loopOnce() {
        int32_t oldGeneration;
        int32_t timeoutMillis;
        bool inputDevicesChanged = false;
        Vector<InputDeviceInfo> inputDevices;
        { // acquire lock
           ...代码省略...
    
        size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
    
        ...代码省略...
    
        // Flush queued events out to the listener.
        // This must happen outside of the lock because the listener could potentially call
        // back into the InputReader's methods, such as getScanCodeState, or become blocked
        // on another thread similarly waiting to acquire the InputReader lock thereby
        // resulting in a deadlock.  This situation is actually quite plausible because the
        // listener is actually the input dispatcher, which calls into the window manager,
        // which occasionally calls into the input reader.
        mQueuedListener->flush();
    }
    

    本身做loop循环,然后通过EventHub#getEvents方法获取指定事件,然后生成事件,加入到队列,通知唤醒InputDispatcher(此处详情不再展开)

    然后介绍InputDispatcher.cpp

    /frameworks/native/services/inputflinger/InputDispatcher.cpp

    bool InputDispatcherThread::threadLoop() {
        mDispatcher->dispatchOnce(); //【见小节1.2】
        return true;
    }
    
    void InputDispatcher::dispatchOnce() {
        nsecs_t nextWakeupTime = LONG_LONG_MAX;
        { // acquire lock
            AutoMutex _l(mLock);
            mDispatcherIsAliveCondition.broadcast();
    
            // Run a dispatch loop if there are no pending commands.
            // The dispatch loop might enqueue commands to run afterwards.
            if (!haveCommandsLocked()) {
                dispatchOnceInnerLocked(&nextWakeupTime);
            }
    
            // Run all pending commands if there are any.
            // If any commands were run then force the next poll to wake up immediately.
            if (runCommandsLockedInterruptible()) {
                nextWakeupTime = LONG_LONG_MIN;
            }
        } // release lock
    
        // Wait for callback or timeout or wake.  (make sure we round up, not down)
        nsecs_t currentTime = now();
        int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
        mLooper->pollOnce(timeoutMillis);
    }
    

    与InputReader类似,自身开启一个Loop循环,然后当队列不为空时,开始执行dispatchOnceInnerLocked-> dispatchKeyLocked-> findFocusedWindowTargetsLocked-> handleTargetsNotReadyLocked.
    接下来我们重点关注下handleTargetsNotReadyLocked方法

    int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime,
            const EventEntry* entry,
            const sp<InputApplicationHandle>& applicationHandle,
            const sp<InputWindowHandle>& windowHandle,
            nsecs_t* nextWakeupTime, const char* reason) {
       ...代码省略...
                nsecs_t timeout;
                if (windowHandle != NULL) {
                    timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
                } else if (applicationHandle != NULL) {
                    timeout = applicationHandle->getDispatchingTimeout(
                            DEFAULT_INPUT_DISPATCHING_TIMEOUT);
                } else {
                    timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT;
                }
    
         ...代码省略...
        if (currentTime >= mInputTargetWaitTimeoutTime) {
            onANRLocked(currentTime, applicationHandle, windowHandle,
                    entry->eventTime, mInputTargetWaitStartTime, reason);
    
            // Force poll loop to wake up immediately on next iteration once we get the
            // ANR response back from the policy.
            *nextWakeupTime = LONG_LONG_MIN;
            return INPUT_EVENT_INJECTION_PENDING;
        } else {
            // Force poll loop to wake up when timeout is due.
            if (mInputTargetWaitTimeoutTime < *nextWakeupTime) {
                *nextWakeupTime = mInputTargetWaitTimeoutTime;
            }
            return INPUT_EVENT_INJECTION_PENDING;
        }
    }
    

    从中我们可以看到两点:

    1. DEFAULT_INPUT_DISPATCHING_TIMEOUT这个值为5秒
    2. currentTime >= mInputTargetWaitTimeoutTime 代表超过5秒的时候就要处理相应的事件了
      即onANRLocked方法(看名字就是ANR的处理了)
      然后会执行doNotifyANRLockedInterruptible方法
    void InputDispatcher::doNotifyANRLockedInterruptible(
            CommandEntry* commandEntry) {
        mLock.unlock();
    
        nsecs_t newTimeout = mPolicy->notifyANR(
                commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle,
                commandEntry->reason);
    
        mLock.lock();
    
        resumeAfterTargetsNotReadyTimeoutLocked(newTimeout,
                commandEntry->inputWindowHandle != NULL
                        ? commandEntry->inputWindowHandle->getInputChannel() : NULL);
    }
    

    接下来会执行mPolicy的notifyANR方法。
    此处的mPolicy便是com_android_server_input_InputManagerService

    frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
    看这名字感觉已经快到Java层了,我们慢慢往下看:

    nsecs_t NativeInputManager::notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
            const sp<InputWindowHandle>& inputWindowHandle, const std::string& reason) {
    #if DEBUG_INPUT_DISPATCHER_POLICY
        ALOGD("notifyANR");
    #endif
        ATRACE_CALL();
    
        JNIEnv* env = jniEnv();
    
        jobject inputApplicationHandleObj =
                getInputApplicationHandleObjLocalRef(env, inputApplicationHandle);
        jobject inputWindowHandleObj =
                getInputWindowHandleObjLocalRef(env, inputWindowHandle);
        jstring reasonObj = env->NewStringUTF(reason.c_str());
    
        jlong newTimeout = env->CallLongMethod(mServiceObj,
                    gServiceClassInfo.notifyANR, inputApplicationHandleObj, inputWindowHandleObj,
                    reasonObj);
        if (checkAndClearExceptionFromCallback(env, "notifyANR")) {
            newTimeout = 0; // abort dispatch
        } else {
            assert(newTimeout >= 0);
        }
    
        env->DeleteLocalRef(reasonObj);
        env->DeleteLocalRef(inputWindowHandleObj);
        env->DeleteLocalRef(inputApplicationHandleObj);
        return newTimeout;
    }
    

    关键代码为 env->CallLongMethod 。 此处正是C++ 层调用Java代码也就是执行了gServiceClassInfo的notifyANR方法,此处的gServiceClassInfo便是InputManagerService。那么我们继续往Java层看:

        private long notifyANR(InputApplicationHandle inputApplicationHandle,
                InputWindowHandle inputWindowHandle, String reason) {
            return mWindowManagerCallbacks.notifyANR(
                    inputApplicationHandle, inputWindowHandle, reason);
        }
    

    这里的处理逻辑很简单,执行了mWindowManagerCallbacks的notifyANR方法,InputMonitor实现了WindowManagerCallbacks,所以这里便进入了InputMonitor类:

        @Override
        public long notifyANR(InputApplicationHandle inputApplicationHandle,
                InputWindowHandle inputWindowHandle, String reason) {
            ...代码省略...
    
            if (appWindowToken != null && appWindowToken.appToken != null) {
                // Notify the activity manager about the timeout and let it decide whether
                // to abort dispatching or keep waiting.
                ...代码省略...
            } else if (windowState != null) {
                try {
                    // Notify the activity manager about the timeout and let it decide whether
                    // to abort dispatching or keep waiting.
                    long timeout = ActivityManager.getService().inputDispatchingTimedOut(
                            windowState.mSession.mPid, aboveSystem, reason);
                    if (timeout >= 0) {
                        // The activity manager declined to abort dispatching.
                        // Wait a bit longer and timeout again later.
                        return timeout * 1000000L; // nanoseconds
                    }
                } catch (RemoteException ex) {
                }
            }
            return 0; // abort dispatching
        }
    

    当WindowState不为空的时候执行ActivityManager.getService().inputDispatchingTimedOut方法即ActivityManagerService#inputDispatchingTimedOut。(这里的WindowState即代表一个真正的 窗口。,此处不做展开)。

    
        @Override
        public long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
            if (checkCallingPermission(android.Manifest.permission.FILTER_EVENTS)
                    != PackageManager.PERMISSION_GRANTED) {
                throw new SecurityException("Requires permission "
                        + android.Manifest.permission.FILTER_EVENTS);
            }
            ProcessRecord proc;
            long timeout;
            synchronized (this) {
                synchronized (mPidsSelfLocked) {
                    proc = mPidsSelfLocked.get(pid);
                }
                timeout = getInputDispatchingTimeoutLocked(proc);
            }
    
            if (inputDispatchingTimedOut(proc, null, null, aboveSystem, reason)) {
                return -1;
            }
    
            return timeout;
        }
    

    然后继续执行inputDispatchingTimedOut方法

        public boolean inputDispatchingTimedOut(final ProcessRecord proc,
                final ActivityRecord activity, final ActivityRecord parent,
                final boolean aboveSystem, String reason) {
            ...代码省略...
    
            if (proc != null) {
                synchronized (this) {
                    if (proc.debugging) {    
                        //当程序Debug的情况下,不弹出ANR窗口
                        return false;
                    }
    
                    if (proc.instr != null) {
                        //当前进程为子进程的时候,直接kill掉子进程,不弹出ANR窗口
                        Bundle info = new Bundle();
                        info.putString("shortMsg", "keyDispatchingTimedOut");
                        info.putString("longMsg", annotation);
                        finishInstrumentationLocked(proc, Activity.RESULT_CANCELED, info);
                        return true;
                    }
                }
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mAppErrors.appNotResponding(proc, activity, parent, aboveSystem, annotation);
                    }
                });
            }
    
            return true;
        }
    

    执行mAppErrors.appNotResponding方法:

        final void appNotResponding(ProcessRecord app, ActivityRecord activity,
                ActivityRecord parent, boolean aboveSystem, final String annotation) {
            ...代码省略...
    
            synchronized (mService) {
                mService.mBatteryStatsService.noteProcessAnr(app.processName, app.uid);
    
                if (isSilentANR) {
                    app.kill("bg anr", true);
                    return;
                }
    
                // Set the app's notResponding state, and look up the errorReportReceiver
                makeAppNotRespondingLocked(app,
                        activity != null ? activity.shortComponentName : null,
                        annotation != null ? "ANR " + annotation : "ANR",
                        info.toString());
    
                // Bring up the infamous App Not Responding dialog
                Message msg = Message.obtain();
                msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
                msg.obj = new AppNotRespondingDialog.Data(app, activity, aboveSystem);
    
                mService.mUiHandler.sendMessage(msg);
            }
        }
    

    这段代码非常长,直接省略部分代码,看最后,通过UIHandler发送了一个SHOW_NOT_RESPONDING_UI_MSG通知。我们找到初始化这个UIHandler的地方看看他的dispatchMessage 吧

        final class UiHandler extends Handler {
            public UiHandler() {
                super(com.android.server.UiThread.get().getLooper(), null, true);
            }
    
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                case SHOW_ERROR_UI_MSG: {
                    mAppErrors.handleShowAppErrorUi(msg);
                    ensureBootCompleted();
                } break;
                case SHOW_NOT_RESPONDING_UI_MSG: {
                    mAppErrors.handleShowAnrUi(msg);
                    ensureBootCompleted();
                } break;
                ...代码省略...
            }
    }
    

    看SHOW_NOT_RESPONDING_UI_MSG是执行了mAppErrors.handleShowAnrUi方法:

       void handleShowAnrUi(Message msg) {
            Dialog dialogToShow = null;
            synchronized (mService) {
                ... 代码省略...
                if (mService.canShowErrorDialogs() || showBackground) {
                    dialogToShow = new AppNotRespondingDialog(mService, mContext, data);
                    proc.anrDialog = dialogToShow;
                } else {
                    MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_APP_ANR,
                            AppNotRespondingDialog.CANT_SHOW);
                    // Just kill the app if there is no dialog to be shown.
                    mService.killAppAtUsersRequest(proc, null);
                }
            }
            // If we've created a crash dialog, show it without the lock held
            if (dialogToShow != null) {
                dialogToShow.show();
            }
        }
    

    终于到了最后一步了,这里的dialogToShow正是我们非常熟悉的ANR提示窗口了,最终就会弹出ANR窗口。下面给出对应的时序图:


    input dispatch ANR.jpg

    2. BroadCastReceiver ANR

    同样的我们从BroadcastReceiver启动源头开始sendBroadcast说起,调用这个方法的时候会调用到ContextWrapper的sendBroadcast方法:

        @Override
        public void sendBroadcast(Intent intent) {
            mBase.sendBroadcast(intent);
        }
    

    然后会执行mBase的sendBroadcast方法,那么这个mBase是什么呢,这就要从Activity启动流程开始说起,本文篇幅有限直接进入ActivityThread#performLaunchActivity()方法:

        private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
            ...代码省略...
            try {
                Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    
                ...代码省略...
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);
    
            } catch (SuperNotCalledException e) {
                throw e;
    
            } catch (Exception e) {
                if (!mInstrumentation.onException(activity, e)) {
                    throw new RuntimeException(
                        "Unable to start activity " + component
                        + ": " + e.toString(), e);
                }
            }
    
            return activity;
        }
    

    这里Activity会执行attach方法将appContext传入然后执行attachBaseContent将appContent赋值给mBase。而此处的appContext就是ContextImpl。那么就进入ContextImp看下:

        @Override
        public void sendBroadcast(Intent intent) {
            warnIfCallingFromSystemProcess();
            String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
            try {
                intent.prepareToLeaveProcess(this);
                ActivityManager.getService().broadcastIntent(
                        mMainThread.getApplicationThread(), intent, resolvedType, null,
                        Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                        getUserId());
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    

    处理也是非常简单,直接调起了ActivityManagerService的broadcastIntent方法:

    public final int broadcastIntent(IApplicationThread caller,
                Intent intent, String resolvedType, IIntentReceiver resultTo,
                int resultCode, String resultData, Bundle resultExtras,
                String[] requiredPermissions, int appOp, Bundle bOptions,
                boolean serialized, boolean sticky, int userId) {
            enforceNotIsolatedCaller("broadcastIntent");
            synchronized(this) {
                intent = verifyBroadcastLocked(intent);
    
                final ProcessRecord callerApp = getRecordForAppLocked(caller);
                final int callingPid = Binder.getCallingPid();
                final int callingUid = Binder.getCallingUid();
                final long origId = Binder.clearCallingIdentity();
                int res = broadcastIntentLocked(callerApp,
                        callerApp != null ? callerApp.info.packageName : null,
                        intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                        requiredPermissions, appOp, bOptions, serialized, sticky,
                        callingPid, callingUid, userId);
                Binder.restoreCallingIdentity(origId);
                return res;
            }
        }
    

    然后调用broadcastIntentLocked,这里的代码过长就不再展示,然后是调用了BroadcastQueue#scheduleBroadcastsLocked方法:

        public void scheduleBroadcastsLocked() {
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
                    + mQueueName + "]: current="
                    + mBroadcastsScheduled);
    
            if (mBroadcastsScheduled) {
                return;
            }
            mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
            mBroadcastsScheduled = true;
        }
    

    我们可以看到它是通过Handler发送了一条消息:

        private final class BroadcastHandler extends Handler {
            public BroadcastHandler(Looper looper) {
                super(looper, null, true);
            }
    
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    case BROADCAST_INTENT_MSG: {
                        if (DEBUG_BROADCAST) Slog.v(
                                TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
                        processNextBroadcast(true);
                    } break;
                    case BROADCAST_TIMEOUT_MSG: {
                        synchronized (mService) {
                            broadcastTimeoutLocked(true);
                        }
                    } break;
                }
            }
        }
    
        final void processNextBroadcast(boolean fromMsg) {
            synchronized (mService) {
                processNextBroadcastLocked(fromMsg, false);
            }
        }
    

    跟到消息处理里面,然后执行processNextBroadcast->processNextBroadcastLocked方法:

    final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
             // Keep track of when this receiver started, and make sure there
            // is a timeout message pending to kill it if need be.
            r.receiverTime = SystemClock.uptimeMillis();
            if (! mPendingBroadcastTimeoutMessage) {
                  //mPendingBroadcastTimeoutMessage这个参数只有在已经发送了延时消息的时候才会设置成true目的是为了防止重新发送延时消息。这个延时时间点正式超时时间
                long timeoutTime = r.receiverTime + mTimeoutPeriod;
                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
                        "Submitting BROADCAST_TIMEOUT_MSG ["
                        + mQueueName + "] for " + r + " at " + timeoutTime);
                setBroadcastTimeoutLocked(timeoutTime);
            }
    }
    

    这里面我们可以看下mTimeoutPeriod,因为延时消息发送的时候是将当前时间+mTimeoutPeriod这个时间的。搜了一下发现是在初始化对象的时候将值传入的:

        BroadcastQueue(ActivityManagerService service, Handler handler,
                String name, long timeoutPeriod, boolean allowDelayBehindServices) {
            mService = service;
            mHandler = new BroadcastHandler(handler.getLooper());
            mQueueName = name;
            mTimeoutPeriod = timeoutPeriod;
            mDelayBehindServices = allowDelayBehindServices;
        }
    

    再去看下什么时候初始化:

            mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
                    "foreground", BROADCAST_FG_TIMEOUT, false);
            mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
                    "background", BROADCAST_BG_TIMEOUT, true);
    

    发现有两种类型的广播队列初始化,一种是前台的,一种是后台的

        // How long we allow a receiver to run before giving up on it.
        static final int BROADCAST_FG_TIMEOUT = 10*1000;
        static final int BROADCAST_BG_TIMEOUT = 60*1000;
    

    前台广播对应的超时时间是10s,后台广播对应的超时时间是60s,然后一旦延时消息执行的时候会调用下面的方法:

        final void broadcastTimeoutLocked(boolean fromMsg) {
            if (fromMsg) {
                //从延时消息过来的时候,将这个值设置为false,解锁操作
                mPendingBroadcastTimeoutMessage = false;
            }
    
            if (mOrderedBroadcasts.size() == 0) {
                //当前广播已经处理完了,那么就不需要弹出ANR了
                return;
            }
    
           ...代码省略...
    
            if (app != null) {
                anrMessage = "Broadcast of " + r.intent.toString();
            }
    
            if (mPendingBroadcast == r) {
                mPendingBroadcast = null;
            }
    
            // Move on to the next receiver.
            finishReceiverLocked(r, r.resultCode, r.resultData,
                    r.resultExtras, r.resultAbort, false);
            scheduleBroadcastsLocked();
    
            if (!debugging && anrMessage != null) {
                // Post the ANR to the handler since we do not want to process ANRs while
                // potentially holding our lock.
                mHandler.post(new AppNotResponding(app, anrMessage));
            }
        }
    

    当当前不属于debug状态,并且ANR信息不为空的时候调用 mHandler.post(new AppNotResponding(app, anrMessage));,这个方法是不是很熟悉,就跟前面手势事件超时最后调用的地方一致会执行mAppErrors.appNotResponding操作,最终弹出ANR窗口,这里给出对应的流程图:


    BroadcastReceiver ANR.png

    3. Service ANR

    ServiceANR原理与BroadcastReceiver类似,那么也从源头开始说起吧:

        @Override
        public ComponentName startService(Intent service) {
            return mBase.startService(service);
        }
    

    类似的启动方式,然后跳到ContextImpl中:

        @Override
        public ComponentName startService(Intent service) {
            warnIfCallingFromSystemProcess();
            return startServiceCommon(service, false, mUser);
        }
    
        private ComponentName startServiceCommon(Intent service, boolean requireForeground,
                UserHandle user) {
            try {
                validateServiceIntent(service);
                service.prepareToLeaveProcess(this);
                ComponentName cn = ActivityManager.getService().startService(
                    mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                                getContentResolver()), requireForeground,
                                getOpPackageName(), user.getIdentifier());
                if (cn != null) {
                    if (cn.getPackageName().equals("!")) {
                        throw new SecurityException(
                                "Not allowed to start service " + service
                                + " without permission " + cn.getClassName());
                    } else if (cn.getPackageName().equals("!!")) {
                        throw new SecurityException(
                                "Unable to start service " + service
                                + ": " + cn.getClassName());
                    } else if (cn.getPackageName().equals("?")) {
                        throw new IllegalStateException(
                                "Not allowed to start service " + service + ": " + cn.getClassName());
                    }
                }
                return cn;
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    

    也是一样最终会进入ActivityManagerService中startService

        @Override
        public ComponentName startService(IApplicationThread caller, Intent service,
                String resolvedType, boolean requireForeground, String callingPackage, int userId)
                throws TransactionTooLargeException {
            enforceNotIsolatedCaller("startService");
            // Refuse possible leaked file descriptors
            if (service != null && service.hasFileDescriptors() == true) {
                throw new IllegalArgumentException("File descriptors passed in Intent");
            }
    
            if (callingPackage == null) {
                throw new IllegalArgumentException("callingPackage cannot be null");
            }
    
            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                    "*** startService: " + service + " type=" + resolvedType + " fg=" + requireForeground);
            synchronized(this) {
                final int callingPid = Binder.getCallingPid();
                final int callingUid = Binder.getCallingUid();
                final long origId = Binder.clearCallingIdentity();
                ComponentName res;
                try {
                    res = mServices.startServiceLocked(caller, service,
                            resolvedType, callingPid, callingUid,
                            requireForeground, callingPackage, userId);
                } finally {
                    Binder.restoreCallingIdentity(origId);
                }
                return res;
            }
        }
    

    ActivityManagerService最终会调用ActiveServices的startServiceLocked->startServiceInnerLocked:

    ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
                boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
            ServiceState stracker = r.getTracker();
            if (stracker != null) {
                stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
            }
            r.callStart = false;
            synchronized (r.stats.getBatteryStats()) {
                r.stats.startRunningLocked();
            }
            String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
            ..代码省略...
    
            return r.name;
        }
    

    然后就是执行bringUpServiceLocked方法,此方法里面会真正开始启动service,也就是会执行realStartServiceLocked方法:

    private final void realStartServiceLocked(ServiceRecord r,
                ProcessRecord app, boolean execInFg) throws RemoteException {
            ...代码省略...
            //此处处理方式与BroadcastReceiver相似,都是先获取当前时间,然后加上超时所需要的时间就是最后的超时时间
            r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
            //这个地方会先发送一个超时消息
            bumpServiceExecutingLocked(r, execInFg, "create");
            ...代码省略...
            try {
                ...代码省略...
                mAm.notifyPackageUse(r.serviceInfo.packageName,
                                     PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
                app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
                //app.thread就是ApplicationThread,就是ActivityThread的子类
                //然后scheduleCreateService就会执行Service的onCreate方法
                app.thread.scheduleCreateService(r, r.serviceInfo,
                        mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                        app.repProcState);
                r.postNotification();
                created = true;
            } catch (DeadObjectException e) {
                Slog.w(TAG, "Application dead when creating service " + r);
                mAm.appDiedLocked(app);
                throw e;
            } finally {
                ...代码省略...
            }
    
            ...代码省略...
        }
    

    在调用Service的onCreate方法前会先调用bumpServiceExecutingLocked发送超时消息

        private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
            ...代码省略...
            if (r.executeNesting == 0) {
                ...代码省略...
            } else if (r.app != null && fg && !r.app.execServicesFg) {
                r.app.execServicesFg = true;
                if (timeoutNeeded) {
                    scheduleServiceTimeoutLocked(r.app);
                }
            }
             ...代码省略...
        }
    
    
          void scheduleServiceTimeoutLocked(ProcessRecord proc) {
            if (proc.executingServices.size() == 0 || proc.thread == null) {
                return;
            }
            Message msg = mAm.mHandler.obtainMessage(
                    ActivityManagerService.SERVICE_TIMEOUT_MSG);
            msg.obj = proc;
            mAm.mHandler.sendMessageDelayed(msg,
                    proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
        }
    
        // How long we wait for a service to finish executing.
        static final int SERVICE_TIMEOUT = 20*1000;
    
        // How long we wait for a service to finish executing.
        static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;
    

    在scheduleServiceTimeoutLocked方法中会先判断Service是到底是属于前台Service还是后台Service,前台Service超时时间是20s,后台Service超时时间是200s.
    发送超时消息以后,会在ActivityManagerService里面接收到此消息,会执行ActiveServices的serviceTimeout方法:

      void serviceTimeout(ProcessRecord proc) {
            ...代码省略...
    
            if (anrMessage != null) {
                mAm.mAppErrors.appNotResponding(proc, null, null, false, anrMessage);
            }
        }
    

    最后无一例外都会调用AppErrors的appNotResponding方法,后续就不在跟进了。此处给出时序图:


    Service ANR.png

    4. ContentProvider ANR

    ContentProvider启动的流程就有点不太一致了,它的入口是ActivityThread的main方法(这也是整个APP启动的入口):

        public static void main(String[] args) {
            ...代码省略...
            ActivityThread thread = new ActivityThread();
            thread.attach(false, startSeq);
    
            ...代码省略...
        }
    

    ContentProvider就从thread.attach方法开始的:

    private void attach(boolean system, long startSeq) {
                ...代码省略
                final IActivityManager mgr = ActivityManager.getService();
                try {
                    mgr.attachApplication(mAppThread, startSeq);
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
                ...代码省略...
    }
    

    这里也是交给了ActivityManagerService来处理,调用了attachApplication方法:

        @Override
        public final void attachApplication(IApplicationThread thread, long startSeq) {
            synchronized (this) {
                int callingPid = Binder.getCallingPid();
                final int callingUid = Binder.getCallingUid();
                final long origId = Binder.clearCallingIdentity();
                attachApplicationLocked(thread, callingPid, callingUid, startSeq);
                Binder.restoreCallingIdentity(origId);
            }
        }
    

    接着就会执行attachApplicationLocked方法:

        @GuardedBy("this")
        private final boolean attachApplicationLocked(IApplicationThread thread,
                int pid, int callingUid, long startSeq) {
    
            ...代码省略...
    
            if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
                Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
                msg.obj = app;
                mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT);
            }
    
            ...代码省略...
    
            return true;
        }
    
        // How long we wait for an attached process to publish its content providers
        // before we decide it must be hung.
        static final int CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10*1000;
    

    这里会发送CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG的延时消息,延时时间为CONTENT_PROVIDER_PUBLISH_TIMEOUT即10秒。然后延时消息里面会执行processContentProviderPublishTimedOutLocked方法:

         @GuardedBy("this")
        boolean removeProcessLocked(ProcessRecord app,
                boolean callerWillRestart, boolean allowRestart, String reason) {
           ...代码省略...
            boolean needRestart = false;
            if ((app.pid > 0 && app.pid != MY_PID) || (app.pid == 0 && app.pendingStart)) {
                ...代码省略...
                app.kill(reason, true);
                handleAppDiedLocked(app, willRestart, allowRestart);
                if (willRestart) {
                    removeLruProcessLocked(app);
                    addAppLocked(app.info, null, false, null /* ABI override */);
                }
            } else {
                mRemovedProcesses.add(app);
            }
    
            return needRestart;
        }
    

    与其他三种情况不一样的是,ContentProvider在超时的时候并不会弹出ANR的Dialog,而是直接干掉了进程,下面给出ContentProvider超时的时序图:


    ContentProvider ANR.png

    从上面四种ANR流程可以看出一个共同点,那就是不管以何种方式出现超时处理,都需要经过AMS,由此也可以看出AMS作为一个核心类的重要性

    相关文章

      网友评论

        本文标题:ANR详解

        本文链接:https://www.haomeiwen.com/subject/rvxodktx.html