Broadcast(五)ANR

本文關(guān)注11、19、21、24、34

11 設(shè)置超時

// setBroadcastTimeoutLocked()把mPendingBroadcastTimeoutMessage設(shè)置為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發(fā)送一條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會設(shè)置超時,最后一個receiver執(zhí)行完才會取消超時。那么假如有ABC3個靜態(tài)注冊的receiver,它們耗時都是6s,然后發(fā)送一個前臺廣播,那么要執(zhí)行完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前先去掉超時,然后重新設(shè)置超時
        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.
            // 設(shè)置超時
            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;
    }

    // 超時了,不繼續(xù)等待app通知,直接繼續(xù)下一個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]

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 什么是ANR ANR(Application Not Responding)就是應(yīng)用在規(guī)定的時間內(nèi)沒有響應(yīng)用戶輸入...
    lbtrace閱讀 3,540評論 3 9
  • 曾經(jīng)有一份美好的愛情放在我的面前我沒有珍惜。等到失去后才后悔莫及。如果可以再對小李說。毛欣想說。這輩子無緣再牽手。...
    毛欣與小李閱讀 3,326評論 0 13
  • 在實際情況中,當(dāng)Android項目的用戶量特別大時候,一些細小的問題也會被放大,ANR問題就是一個典型的例子。一些...
    Uprising閱讀 54,338評論 4 116
  • 本文將從介紹什么是ANR,給出anr產(chǎn)生的幾種觸發(fā)點,分析這幾種情況下是怎么產(chǎn)生anr的,然后給出優(yōu)化的方法這幾個...
    田間小鹿閱讀 946評論 0 0
  • 一、ANR說明和原因 1.1 簡介 ANR全稱:Application Not Responding,也就是應(yīng)用程...
    Marker_Sky閱讀 102,905評論 6 117

友情鏈接更多精彩內(nèi)容