Broadcast(五)ANR

作者: 风风风筝 | 来源:发表于2016-09-14 14:03 被阅读567次

    本文关注11、19、21、24、34

    11 设置超时

    // setBroadcastTimeoutLocked()把mPendingBroadcastTimeoutMessage设置为true
    // 所以只会进入一次
    if (! mPendingBroadcastTimeoutMessage) {
        long timeoutTime = r.receiverTime + mTimeoutPeriod;
        setBroadcastTimeoutLocked(timeoutTime);
    }
    
    final void setBroadcastTimeoutLocked(long timeoutTime) {
        if (! mPendingBroadcastTimeoutMessage) {
            Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
            // 延迟timeoutTime给BroadcastHandler发送一条BROADCAST_TIMEOUT_MSG消息
            mHandler.sendMessageAtTime(msg, timeoutTime);
            mPendingBroadcastTimeoutMessage = true;
        }
    }
    

    34 取消超时

    final void cancelBroadcastTimeoutLocked() {
        if (mPendingBroadcastTimeoutMessage) {
            mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
            // 还原mPendingBroadcastTimeoutMessage
            mPendingBroadcastTimeoutMessage = false;
        }
    }
    

    19

    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: {
                    processNextBroadcast(true);
                } break;
                case BROADCAST_TIMEOUT_MSG: {
                    synchronized (mService) {
                        broadcastTimeoutLocked(true);
                    }
                } break;
                ...
            }
        }
    };
    

    上面说只有第一个receiver会设置超时,最后一个receiver执行完才会取消超时。那么假如有ABC3个静态注册的receiver,它们耗时都是6s,然后发送一个前台广播,那么要执行完B就需要12s,我们知道前台广播是10s超时,所以就会进入broadcastTimeoutLocked(),那么会弹出ANR么?接着看

    21或24

    final void broadcastTimeoutLocked(boolean fromMsg) {
        if (fromMsg) {
            // 不管怎样,先还原mPendingBroadcastTimeoutMessage
            mPendingBroadcastTimeoutMessage = false;
        }
    
        if (mOrderedBroadcasts.size() == 0) {
            return;
        }
    
        long now = SystemClock.uptimeMillis();
        BroadcastRecord r = mOrderedBroadcasts.get(0);
        if (fromMsg) {
            if (mService.mDidDexOpt) {
                // Delay timeouts until dexopt finishes.
                mService.mDidDexOpt = false;
                long timeoutTime = SystemClock.uptimeMillis() + mTimeoutPeriod;
                setBroadcastTimeoutLocked(timeoutTime);
                return;
            }
            if (!mService.mProcessesReady) {
                // Only process broadcast timeouts if the system is ready. That way
                // PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended
                // to do heavy lifting for system up.
                return;
            }
    
            long timeoutTime = r.receiverTime + mTimeoutPeriod;
    
            // 所以重点是这个判断,虽然会进入这个broadcastTimeoutLocked()
            // 但是每个receiver的receiverTime是在processNextBroadcast分配的
            // r.receiverTime = SystemClock.uptimeMillis()
            // 我还是不明白为什么不在通知receiver前先去掉超时,然后重新设置超时
            if (timeoutTime > now) {
                // We can observe premature timeouts because we do not cancel and reset the
                // broadcast timeout message after each receiver finishes.  Instead, we set up
                // an initial timeout then kick it down the road a little further as needed
                // when it expires.
                // 设置超时
                setBroadcastTimeoutLocked(timeoutTime);
                return;
            }
        }
    
        BroadcastRecord br = mOrderedBroadcasts.get(0);
        if (br.state == BroadcastRecord.WAITING_SERVICES) {
            // In this case the broadcast had already finished, but we had decided to wait
            // for started services to finish as well before going on.  So if we have actually
            // waited long enough time timeout the broadcast, let's give up on the whole thing
            // and just move on to the next.
            br.curComponent = null;
            br.state = BroadcastRecord.IDLE;
            processNextBroadcast(false);
            return;
        }
        r.receiverTime = now;
        r.anrCount++;
    
        // Current receiver has passed its expiration date.
        if (r.nextReceiver <= 0) {
            return;
        }
    
        ProcessRecord app = null;
        String anrMessage = null;
    
        Object curReceiver = r.receivers.get(r.nextReceiver-1);
        logBroadcastReceiverDiscardLocked(r);
        if (curReceiver instanceof BroadcastFilter) {
            BroadcastFilter bf = (BroadcastFilter)curReceiver;
            if (bf.receiverList.pid != 0
                    && bf.receiverList.pid != ActivityManagerService.MY_PID) {
                synchronized (mService.mPidsSelfLocked) {
                    app = mService.mPidsSelfLocked.get(
                            bf.receiverList.pid);
                }
            }
        } else {
            app = r.curApp;
        }
    
        if (app != null) {
            anrMessage = "Broadcast of " + r.intent.toString();
        }
    
        if (mPendingBroadcast == r) {
            mPendingBroadcast = null;
        }
    
        // 超时了,不继续等待app通知,直接继续下一个receiver
        // Move on to the next receiver.
        finishReceiverLocked(r, r.resultCode, r.resultData,
                r.resultExtras, r.resultAbort, false);
        scheduleBroadcastsLocked();
        
        // ANR
        if (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));
        }
    }
    

    ANR

    final ActivityManagerService mService;
    
    private final class AppNotResponding implements Runnable {
        private final ProcessRecord mApp;
        private final String mAnnotation;
    
        public AppNotResponding(ProcessRecord app, String annotation) {
            mApp = app;
            mAnnotation = annotation;
        }
    
        @Override
        public void run() {
            mService.appNotResponding(mApp, null, null, false, mAnnotation);
        }
    }
    

    进入AMS.appNotResponding(),参考[Service(二)ANR]

    相关文章

      网友评论

        本文标题:Broadcast(五)ANR

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