廣播相關(guān)學(xué)習(xí)-processNextBroadcast相關(guān)邏輯

BroadcastQueue#addBroadcastToHistoryLocked

1528    private final void addBroadcastToHistoryLocked(BroadcastRecord original) {
1529        if (original.callingUid < 0) {
1530            // This was from a registerReceiver() call; ignore it.
1531            return;
1532        }
            //注意這里為BroadcastRecord的finishTime賦值了
1533        original.finishTime = SystemClock.uptimeMillis();
1534
1535        if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
1536            Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
1537                createBroadcastTraceTitle(original, BroadcastRecord.DELIVERY_DELIVERED),
1538                System.identityHashCode(original));
1539        }
1540
1541        // Note sometimes (only for sticky broadcasts?) we reuse BroadcastRecords,
1542        // So don't change the incoming record directly.
1543        final BroadcastRecord historyRecord = original.maybeStripForHistory();
1544
1545        mBroadcastHistory[mHistoryNext] = historyRecord;
1546        mHistoryNext = ringAdvance(mHistoryNext, 1, MAX_BROADCAST_HISTORY);
1547
1548        mBroadcastSummaryHistory[mSummaryHistoryNext] = historyRecord.intent;
1549        mSummaryHistoryEnqueueTime[mSummaryHistoryNext] = historyRecord.enqueueClockTime;
1550        mSummaryHistoryDispatchTime[mSummaryHistoryNext] = historyRecord.dispatchClockTime;
1551        mSummaryHistoryFinishTime[mSummaryHistoryNext] = System.currentTimeMillis();
1552        mSummaryHistoryNext = ringAdvance(mSummaryHistoryNext, 1, MAX_BROADCAST_SUMMARY_HISTORY);
1553    }

這個(gè)方用的調(diào)用處有兩處
對于并行廣播:

843        // First, deliver any non-serialized broadcasts right away.
844        while (mParallelBroadcasts.size() > 0) {
845            r = mParallelBroadcasts.remove(0);
846            r.dispatchTime = SystemClock.uptimeMillis();
847            r.dispatchClockTime = System.currentTimeMillis();
848
849            if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
850                Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
851                    createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),
852                    System.identityHashCode(r));
853                Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
854                    createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),
855                    System.identityHashCode(r));
856            }
857
858            final int N = r.receivers.size();
859            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
860                    + mQueueName + "] " + r);
861            for (int i=0; i<N; i++) {
862                Object target = r.receivers.get(i);
863                if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
864                        "Delivering non-ordered on [" + mQueueName + "] to registered "
865                        + target + ": " + r);
866                deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
867            }
868            addBroadcastToHistoryLocked(r);
869            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
870                    + mQueueName + "] " + r);
871        }

對于串行廣播:

910        do {
911            if (mOrderedBroadcasts.size() == 0) {
912                // No more broadcasts pending, so all done!
913                mService.scheduleAppGcsLocked();
914                if (looped) {
915                    // If we had finished the last ordered broadcast, then
916                    // make sure all processes have correct oom and sched
917                    // adjustments.
918                    mService.updateOomAdjLocked();
919                }
920                return;
921            }
922            r = mOrderedBroadcasts.get(0);
923            boolean forceReceive = false;
924
925            // Ensure that even if something goes awry with the timeout
926            // detection, we catch "hung" broadcasts here, discard them,
927            // and continue to make progress.
928            //
929            // This is only done if the system is ready so that PRE_BOOT_COMPLETED
930            // receivers don't get executed with timeouts. They're intended for
931            // one time heavy lifting after system upgrades and can take
932            // significant amounts of time.
933            int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
934            if (mService.mProcessesReady && r.dispatchTime > 0) {
935                long now = SystemClock.uptimeMillis();
936                if ((numReceivers > 0) &&
937                        (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
938                    Slog.w(TAG, "Hung broadcast ["
939                            + mQueueName + "] discarded after timeout failure:"
940                            + " now=" + now
941                            + " dispatchTime=" + r.dispatchTime
942                            + " startTime=" + r.receiverTime
943                            + " intent=" + r.intent
944                            + " numReceivers=" + numReceivers
945                            + " nextReceiver=" + r.nextReceiver
946                            + " state=" + r.state);
947                    broadcastTimeoutLocked(false); // forcibly finish this broadcast
948                    forceReceive = true;
949                    r.state = BroadcastRecord.IDLE;
950                }
951            }
952
953            if (r.state != BroadcastRecord.IDLE) {
954                if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST,
955                        "processNextBroadcast("
956                        + mQueueName + ") called when not idle (state="
957                        + r.state + ")");
958                return;
959            }
960
961            if (r.receivers == null || r.nextReceiver >= numReceivers
962                    || r.resultAbort || forceReceive) {
963                // No more receivers for this broadcast!  Send the final
964                // result if requested...
965                if (r.resultTo != null) {
966                    try {
967                        if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
968                                "Finishing broadcast [" + mQueueName + "] "
969                                + r.intent.getAction() + " app=" + r.callerApp);
970                        performReceiveLocked(r.callerApp, r.resultTo,
971                            new Intent(r.intent), r.resultCode,
972                            r.resultData, r.resultExtras, false, false, r.userId);
973                        // Set this to null so that the reference
974                        // (local and remote) isn't kept in the mBroadcastHistory.
975                        r.resultTo = null;
976                    } catch (RemoteException e) {
977                        r.resultTo = null;
978                        Slog.w(TAG, "Failure ["
979                                + mQueueName + "] sending broadcast result of "
980                                + r.intent, e);
981
982                    }
983                }
984
985                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG");
986                cancelBroadcastTimeoutLocked();
987
988                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
989                        "Finished with ordered broadcast " + r);
990
991                // ... and on to the next...
992                addBroadcastToHistoryLocked(r);
993                if (r.intent.getComponent() == null && r.intent.getPackage() == null
994                        && (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
995                    // This was an implicit broadcast... let's record it for posterity.
996                    mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage,
997                            r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime);
998                }
999                mOrderedBroadcasts.remove(0);
1000                r = null;
1001                looped = true;
1002                continue;
1003            }
1004        } while (r == null);

因此解幽,Broadcast的finishTime屬于當(dāng)一個(gè)BroadcastRecord中所有receiver執(zhí)行完成鸳址,或者超時(shí)強(qiáng)制終止時(shí),作為BroadcastRecord的finishTime

BroadcastQueue#skipReceiverLocked

主動(dòng)跳過一個(gè)receiver矮固,觸發(fā)下一次處理流程

389    private void skipReceiverLocked(BroadcastRecord r) {
390        logBroadcastReceiverDiscardLocked(r);
391        finishReceiverLocked(r, r.resultCode, r.resultData,
392                r.resultExtras, r.resultAbort, false);
393        scheduleBroadcastsLocked(); //用于觸發(fā)進(jìn)行nextReceiver的處理
394    }

BroadcastQueue#logBroadcastReceiverDiscardLocked

將BroadcastRecord當(dāng)前receiver放棄了失息,打印event log

1651    final void logBroadcastReceiverDiscardLocked(BroadcastRecord r) {
1652        final int logIndex = r.nextReceiver - 1;
1653        if (logIndex >= 0 && logIndex < r.receivers.size()) {
1654            Object curReceiver = r.receivers.get(logIndex);
1655            if (curReceiver instanceof BroadcastFilter) {
1656                BroadcastFilter bf = (BroadcastFilter) curReceiver;
1657                EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
1658                        bf.owningUserId, System.identityHashCode(r),
1659                        r.intent.getAction(), logIndex, System.identityHashCode(bf));
1660            } else {
1661                ResolveInfo ri = (ResolveInfo) curReceiver;
1662                EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
1663                        UserHandle.getUserId(ri.activityInfo.applicationInfo.uid),
1664                        System.identityHashCode(r), r.intent.getAction(), logIndex, ri.toString());
1665            }
1666        } else {
1667            if (logIndex < 0) Slog.w(TAG,
1668                    "Discarding broadcast before first receiver is invoked: " + r);
1669            EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
1670                    -1, System.identityHashCode(r),
1671                    r.intent.getAction(),
1672                    r.nextReceiver,
1673                    "NONE");
1674        }
1675    }

BroadcastQueue#finishReceiverLocked

418    public boolean finishReceiverLocked(BroadcastRecord r, int resultCode,
419            String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {
420        final int state = r.state;
421        final ActivityInfo receiver = r.curReceiver;
422        r.state = BroadcastRecord.IDLE;
423        if (state == BroadcastRecord.IDLE) {
424            Slog.w(TAG, "finishReceiver [" + mQueueName + "] called but state is IDLE");
425        }
426        r.receiver = null;
427        r.intent.setComponent(null);
428        if (r.curApp != null && r.curApp.curReceivers.contains(r)) {
429            r.curApp.curReceivers.remove(r);
430        }
431        if (r.curFilter != null) {
432            r.curFilter.receiverList.curBroadcast = null;
433        }
434        r.curFilter = null;
435        r.curReceiver = null;
436        r.curApp = null;
437        mPendingBroadcast = null;
//置空操作
//將當(dāng)前BroadcastRecord中的一些值置空
438
439        r.resultCode = resultCode;
440        r.resultData = resultData;
441        r.resultExtras = resultExtras;
442        if (resultAbort && (r.intent.getFlags()&Intent.FLAG_RECEIVER_NO_ABORT) == 0) {
443            r.resultAbort = resultAbort;
444        } else {
445            r.resultAbort = false;
446        }
447       //waitForServices的特殊情況
448        if (waitForServices && r.curComponent != null && r.queue.mDelayBehindServices
449                && r.queue.mOrderedBroadcasts.size() > 0
450                && r.queue.mOrderedBroadcasts.get(0) == r) {
451            ActivityInfo nextReceiver;
452            if (r.nextReceiver < r.receivers.size()) {
453                Object obj = r.receivers.get(r.nextReceiver);
454                nextReceiver = (obj instanceof ActivityInfo) ? (ActivityInfo)obj : null;
455            } else {
456                nextReceiver = null;
457            }
458            // Don't do this if the next receive is in the same process as the current one.
459            if (receiver == null || nextReceiver == null
460                    || receiver.applicationInfo.uid != nextReceiver.applicationInfo.uid
461                    || !receiver.processName.equals(nextReceiver.processName)) {
462                // In this case, we are ready to process the next receiver for the current broadcast,
463                // but are on a queue that would like to wait for services to finish before moving
464                // on.  If there are background services currently starting, then we will go into a
465                // special state where we hold off on continuing this broadcast until they are done.
466                if (mService.mServices.hasBackgroundServicesLocked(r.userId)) {
467                    Slog.i(TAG, "Delay finish: " + r.curComponent.flattenToShortString());
468                    r.state = BroadcastRecord.WAITING_SERVICES; //Broadcast已經(jīng)執(zhí)行完了,要等當(dāng)前user的后臺服務(wù)執(zhí)行完才繼續(xù)下一個(gè)broadcast档址;或者是當(dāng)我們切換用戶時(shí)或者進(jìn)程時(shí)盹兢,我們需要把當(dāng)前用戶的后臺服務(wù)執(zhí)行完,才執(zhí)行下一個(gè)BroadcastRecord或者BroadcastReceiver
469                    return false; //返回false守伸,代表暫時(shí)不執(zhí)行下一個(gè)broadcast
470                }
471            }
472        }
473
474        r.curComponent = null;
475
476        // We will process the next receiver right now if this is finishing
477        // an app receiver (which is always asynchronous) or after we have
478        // come back from calling a receiver.
479        return state == BroadcastRecord.APP_RECEIVE
480                || state == BroadcastRecord.CALL_DONE_RECEIVE;
         //CALL_DONE_RECEIVE 串行廣播+動(dòng)態(tài)注冊receiver:執(zhí)行完performReceiveLocked后绎秒,將BroadcastRecord的state置為CALL_DONE_RECEIVE
         //APP_RECEIVE 串行廣播+靜態(tài)注冊receiver:執(zhí)行processCurBroadcastLocked之前就將狀態(tài)置為APP_RECEIVE
         //總之是針對串行廣播的,這個(gè)返回值會(huì)在finishReceiver中被用到尼摹,返回true則自動(dòng)調(diào)用processNextBroadcastLocked见芹,進(jìn)行BroadcastRecord的下一個(gè)receiver的處理
481    }

BroadcastQueue#scheduleBroadcastsLocked

通過BROADCAST_INTENT_MSG消息觸發(fā)下一個(gè)receiver的處理

396    public void scheduleBroadcastsLocked() {
397        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
398                + mQueueName + "]: current="
399                + mBroadcastsScheduled);
400
401        if (mBroadcastsScheduled) {
402            return;
403        }
404        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
405        mBroadcastsScheduled = true;
406    }

ActivityManagerService#finishReceiver

如調(diào)用BroadcastReceiver實(shí)例的onReceive函數(shù)過程中,如果receiver所在進(jìn)程死了蠢涝;最終會(huì)調(diào)用到

22570    public void finishReceiver(IBinder who, int resultCode, String resultData,
22571            Bundle resultExtras, boolean resultAbort, int flags) {
22572        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Finish receiver: " + who);
22573
22574        // Refuse possible leaked file descriptors
22575        if (resultExtras != null && resultExtras.hasFileDescriptors()) {
22576            throw new IllegalArgumentException("File descriptors passed in Bundle");
22577        }
22578
22579        final long origId = Binder.clearCallingIdentity();
22580        try {
22581            boolean doNext = false;
22582            BroadcastRecord r;
22583
22584            synchronized(this) {
22585                BroadcastQueue queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0
22586                        ? mFgBroadcastQueue : mBgBroadcastQueue;
22587                r = queue.getMatchingOrderedReceiver(who);
22588                if (r != null) {
22589                    doNext = r.queue.finishReceiverLocked(r, resultCode,
22590                        resultData, resultExtras, resultAbort, true); //處理當(dāng)前BroadcastRecord狀態(tài)玄呛,并返回一個(gè)結(jié)果,用于判斷是否要觸發(fā)下一個(gè)processNextBroadcastLocked
22591                }
22592                if (doNext) {
22593                    r.queue.processNextBroadcastLocked(/*fromMsg=*/ false, /*skipOomAdj=*/ true);
                              //所以processNextBroadcastLocked中的next不是BroadcastRecord這個(gè)粒度的和二,而是BroadcatReceiver這個(gè)粒度的(針對串行廣播)
                              //對于并行廣播而言徘铝,每執(zhí)行一次都會(huì)將并行隊(duì)列中的Broadcast全部處理完畢
22594                }
22595                // updateOomAdjLocked() will be done here
22596                trimApplicationsLocked();
22597            }
22598
22599        } finally {
22600            Binder.restoreCallingIdentity(origId);
22601        }
22602    }

超時(shí)發(fā)生ANR的相關(guān)邏輯

每個(gè)receiver都會(huì)嘗試發(fā)送,但是只有mPendingBroadcastTimeoutMessage為false是才會(huì)真正發(fā)送;每次取出BroadcastRecord中的一個(gè)receiver準(zhǔn)備執(zhí)行時(shí)惯吕,就會(huì)先嘗試發(fā)送一個(gè)broadcast的timeout消息

1074        if (! mPendingBroadcastTimeoutMessage) { //mPendingBroadcastTimeoutMessage = true代表當(dāng)前已經(jīng)有BROADCAST_TIMEOUT_MSG消息了惕它,無需再重復(fù)發(fā)送了
1075            long timeoutTime = r.receiverTime + mTimeoutPeriod;
1076            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
1077                    "Submitting BROADCAST_TIMEOUT_MSG ["
1078                    + mQueueName + "] for " + r + " at " + timeoutTime);
1079            setBroadcastTimeoutLocked(timeoutTime); //針對BroadcastReceiver發(fā)送超時(shí)消息
1080        }

BroadcastQueue#setBroadcastTimeoutLocked

1475    final void setBroadcastTimeoutLocked(long timeoutTime) {
1476        if (! mPendingBroadcastTimeoutMessage) {
1477            Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
1478            mHandler.sendMessageAtTime(msg, timeoutTime);
1479            mPendingBroadcastTimeoutMessage = true; 
1480        }
1481    }

那么比如我有4個(gè)receiver,每個(gè)3s废登,那么會(huì)在第四個(gè)的時(shí)候進(jìn)行broadcastTimeoutLocked的處理(如果相關(guān)線程不繁忙的話)

166    final class BroadcastHandler extends Handler {
167        public BroadcastHandler(Looper looper) {
168            super(looper, null, true);
169        }
170
171        @Override
172        public void handleMessage(Message msg) {
173            switch (msg.what) {
174                case BROADCAST_INTENT_MSG: {
175                    if (DEBUG_BROADCAST) Slog.v(
176                            TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
177                    processNextBroadcast(true);
178                } break;
179                case BROADCAST_TIMEOUT_MSG: {
180                    synchronized (mService) {
181                        broadcastTimeoutLocked(true);
182                    }
183                } break;
184            }
185        }
186    }

BroadcastQueue#broadcastTimeoutLocked

發(fā)生超時(shí)時(shí)淹魄,當(dāng)前BroadcastReceiver所在進(jìn)程ANR

1490    final void broadcastTimeoutLocked(boolean fromMsg) {
1491        if (fromMsg) {
1492            mPendingBroadcastTimeoutMessage = false; //調(diào)到這以后mPendingBroadcastTimeoutMessage 置為false,就可以重新發(fā)送超時(shí)消息了
1493        }
1494
1495        if (mOrderedBroadcasts.size() == 0) {
1496            return;
1497        }
1498
1499        long now = SystemClock.uptimeMillis();
1500        BroadcastRecord r = mOrderedBroadcasts.get(0); 
1501        if (fromMsg) {
1502            if (!mService.mProcessesReady) {
1503                // Only process broadcast timeouts if the system is ready. That way
1504                // PRE_BOOT_COMPLETED broadcasts can't timeout as they are intended
1505                // to do heavy lifting for system up.
1506                return;
1507            }
1508
1509            long timeoutTime = r.receiverTime + mTimeoutPeriod;  
1510            if (timeoutTime > now) {
1511                // We can observe premature timeouts because we do not cancel and reset the
1512                // broadcast timeout message after each receiver finishes.  Instead, we set up
1513                // an initial timeout then kick it down the road a little further as needed
1514                // when it expires.
1515                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
1516                        "Premature timeout ["
1517                        + mQueueName + "] @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
1518                        + timeoutTime);
1519                setBroadcastTimeoutLocked(timeoutTime); //重新發(fā)送BROADCAST_TIMEOUT_MSG消息并直接返回
1520                return;
1521            }
1522        }
1523
1524        BroadcastRecord br = mOrderedBroadcasts.get(0);
1525        if (br.state == BroadcastRecord.WAITING_SERVICES) {
1526            // In this case the broadcast had already finished, but we had decided to wait
1527            // for started services to finish as well before going on.  So if we have actually
1528            // waited long enough time timeout the broadcast, let's give up on the whole thing
1529            // and just move on to the next.
1530            Slog.i(TAG, "Waited long enough for: " + (br.curComponent != null
1531                    ? br.curComponent.flattenToShortString() : "(null)"));
1532            br.curComponent = null;
1533            br.state = BroadcastRecord.IDLE;
1534            processNextBroadcast(false);
1535            return;
1536        }
1537
                //確定超時(shí)了堡距,將r.receiverTime改為當(dāng)前時(shí)間(這樣就不會(huì)因?yàn)檫@個(gè)broadcast超時(shí)影響下一個(gè)receiver所在進(jìn)程也ANR了)甲锡,然后finish當(dāng)前Receiver兆蕉,重新觸發(fā)下一輪流程
1538        // If the receiver app is being debugged we quietly ignore unresponsiveness, just
1539        // tidying up and moving on to the next broadcast without crashing or ANRing this
1540        // app just because it's stopped at a breakpoint.
1541        final boolean debugging = (r.curApp != null && r.curApp.debugging);
1542
1543        Slog.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver
1544                + ", started " + (now - r.receiverTime) + "ms ago");
1545        r.receiverTime = now;
1546        if (!debugging) {
1547            r.anrCount++;
1548        }
1549
1550        ProcessRecord app = null;
1551        String anrMessage = null;
1552
1553        Object curReceiver;
1554        if (r.nextReceiver > 0) {
1555            curReceiver = r.receivers.get(r.nextReceiver-1);
1556            r.delivery[r.nextReceiver-1] = BroadcastRecord.DELIVERY_TIMEOUT;
1557        } else {
1558            curReceiver = r.curReceiver;
1559        }
1560        Slog.w(TAG, "Receiver during timeout of " + r + " : " + curReceiver);
1561        logBroadcastReceiverDiscardLocked(r);
1562        if (curReceiver != null && curReceiver instanceof BroadcastFilter) {
1563            BroadcastFilter bf = (BroadcastFilter)curReceiver;
1564            if (bf.receiverList.pid != 0
1565                    && bf.receiverList.pid != ActivityManagerService.MY_PID) {
1566                synchronized (mService.mPidsSelfLocked) {
1567                    app = mService.mPidsSelfLocked.get(
1568                            bf.receiverList.pid);
1569                }
1570            }
1571        } else {
1572            app = r.curApp;
1573        }
1574
1575        if (app != null) {
1576            anrMessage = "Broadcast of " + r.intent.toString();
1577        }
1578
1579        if (mPendingBroadcast == r) {
1580            mPendingBroadcast = null;
1581        }
1582
1583        // Move on to the next receiver.
1584        finishReceiverLocked(r, r.resultCode, r.resultData,
1585                r.resultExtras, r.resultAbort, false);
1586        scheduleBroadcastsLocked();
1587
1588        if (!debugging && anrMessage != null) {
1589            // Post the ANR to the handler since we do not want to process ANRs while
1590            // potentially holding our lock.
1591            mHandler.post(new AppNotResponding(app, anrMessage));
1592        }
1593    }

BroadcastQueue#cancelBroadcastTimeoutLocked

只有當(dāng)串行廣播所有的BroadcastReceiver時(shí),或者當(dāng)廣播強(qiáng)制被結(jié)束時(shí)搔体,才會(huì)調(diào)用cancelBroadcastTimeoutLocked恨樟,取消隊(duì)列中BROADCAST_TIMEOUT_MSG消息

1409    final void cancelBroadcastTimeoutLocked() {
1410        if (mPendingBroadcastTimeoutMessage) {
1411            mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this); //BROADCAST_TIMEOUT_MSG消息從隊(duì)列中移除
1412            mPendingBroadcastTimeoutMessage = false;
1413        }
1414    }

下面舉例說明下,已前臺廣播為例:
1.一個(gè)broadcast有4個(gè)receiver疚俱,分別是3,3,3,3

時(shí)間軸
0 3 6 9 10(耗時(shí)操作消息被取出執(zhí)行執(zhí)行了劝术,此時(shí)dispatch time = 9,9+10 = 19)12 此時(shí)整個(gè)Broadcast執(zhí)行完了,會(huì)cancel超時(shí)小心呆奕;因此整個(gè)并沒有耗時(shí)

2.一個(gè)broadcast有2個(gè)receiver养晋,分別是1,13
0 1 10(耗時(shí)操作消息被取出執(zhí)行執(zhí)行了梁钾,此時(shí)dispatch time = 1,1+10 = 11) 11(此時(shí)超時(shí)了绳泉,receiver所在進(jìn)程發(fā)生ANR),然后進(jìn)入下一輪流程姆泻,進(jìn)入下一個(gè)broadcast

3.一個(gè)broadcast有3個(gè)receiver零酪,分別是1,13拇勃,2
0 1 10(耗時(shí)操作消息被取出執(zhí)行執(zhí)行了四苇,此時(shí)dispatch time = 1,1+10 = 11) 11(此時(shí)超時(shí)了,receiver所在進(jìn)程發(fā)生ANR)方咆,然后進(jìn)入下一輪流程月腋,進(jìn)入下一個(gè)receiver,發(fā)送超時(shí)消息(時(shí)間為11+10 = 21)瓣赂,13(該Broadcast執(zhí)行完成榆骚,取消超時(shí)消息);進(jìn)入下一個(gè)Broadcast

4.一個(gè)broadcast有3個(gè)receiver煌集,分別是5妓肢,等待7s才進(jìn)入下一輪,5苫纤,2

0 5 10 (下一輪timeout = 15) 12(取出開始執(zhí)行) 15(ANR,當(dāng)前receiver執(zhí)行超時(shí)),(下一輪timeout = 25),17(此時(shí)結(jié)束职恳,取消超時(shí)消息,觸發(fā)一個(gè)BroadcastRecord)

總結(jié)

用這種方式能查出兩個(gè)receiver處理之間的耗時(shí)超過timeout就會(huì)ANR(本次receiver處理的相關(guān)Message方面,BROADCAST_INTENT_MSG等待取出時(shí)間+執(zhí)行時(shí)間 >= timeout),且不會(huì)連帶影響下一個(gè)receiver(看起來system_server中的ActivityMananger線程耗時(shí)以及receiver所在進(jìn)程的主線程耗時(shí)色徘,來回binder call耗時(shí)恭金,都可能會(huì)造成相關(guān)receiver廣播超時(shí))

deliverToRegisteredReceiverLocked

處理動(dòng)態(tài)注冊的receiver
首先檢查相關(guān)權(quán)限,然后調(diào)用performReceiveLocked進(jìn)行相關(guān)處理

530    private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
531            BroadcastFilter filter, boolean ordered, int index) {
532        boolean skip = false;
//檢查廣播發(fā)送方是否有BroadcastReceiver指定的權(quán)限
533        if (filter.requiredPermission != null) {
534            int perm = mService.checkComponentPermission(filter.requiredPermission,
535                    r.callingPid, r.callingUid, -1, true);
536            if (perm != PackageManager.PERMISSION_GRANTED) {
537                Slog.w(TAG, "Permission Denial: broadcasting "
538                        + r.intent.toString()
539                        + " from " + r.callerPackage + " (pid="
540                        + r.callingPid + ", uid=" + r.callingUid + ")"
541                        + " requires " + filter.requiredPermission
542                        + " due to registered receiver " + filter);
543                skip = true;
544            } else {
545                final int opCode = AppOpsManager.permissionToOpCode(filter.requiredPermission);
546                if (opCode != AppOpsManager.OP_NONE
547                        && mService.mAppOpsService.noteOperation(opCode, r.callingUid,
548                                r.callerPackage) != AppOpsManager.MODE_ALLOWED) {
549                    Slog.w(TAG, "Appop Denial: broadcasting "
550                            + r.intent.toString()
551                            + " from " + r.callerPackage + " (pid="
552                            + r.callingPid + ", uid=" + r.callingUid + ")"
553                            + " requires appop " + AppOpsManager.permissionToOp(
554                                    filter.requiredPermission)
555                            + " due to registered receiver " + filter);
556                    skip = true;
557                }
558            }
559        }
560        if (!skip && r.requiredPermissions != null && r.requiredPermissions.length > 0) {
561            for (int i = 0; i < r.requiredPermissions.length; i++) {
562                String requiredPermission = r.requiredPermissions[i];
563                int perm = mService.checkComponentPermission(requiredPermission,
564                        filter.receiverList.pid, filter.receiverList.uid, -1, true);
565                if (perm != PackageManager.PERMISSION_GRANTED) {
566                    Slog.w(TAG, "Permission Denial: receiving "
567                            + r.intent.toString()
568                            + " to " + filter.receiverList.app
569                            + " (pid=" + filter.receiverList.pid
570                            + ", uid=" + filter.receiverList.uid + ")"
571                            + " requires " + requiredPermission
572                            + " due to sender " + r.callerPackage
573                            + " (uid " + r.callingUid + ")");
574                    skip = true;
575                    break;
576                }
577                int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
578                if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
//檢查BroadcastReceiver是否有Broadcast要求的權(quán)限
581                        && mService.mAppOpsService.checkOperation(appOp,
582                        filter.receiverList.uid, filter.packageName)
583                        != AppOpsManager.MODE_ALLOWED) {
584                    Slog.w(TAG, "Appop Denial: receiving "
585                            + r.intent.toString()
586                            + " to " + filter.receiverList.app
587                            + " (pid=" + filter.receiverList.pid
588                            + ", uid=" + filter.receiverList.uid + ")"
589                            + " requires appop " + AppOpsManager.permissionToOp(
590                            requiredPermission)
591                            + " due to sender " + r.callerPackage
592                            + " (uid " + r.callingUid + ")");
593                    skip = true;
594                    break;
595                }
596            }
597        }
598        if (!skip && (r.requiredPermissions == null || r.requiredPermissions.length == 0)) {
599            int perm = mService.checkComponentPermission(null,
600                    filter.receiverList.pid, filter.receiverList.uid, -1, true);
601            if (perm != PackageManager.PERMISSION_GRANTED) {
602                Slog.w(TAG, "Permission Denial: security check failed when receiving "
603                        + r.intent.toString()
604                        + " to " + filter.receiverList.app
605                        + " (pid=" + filter.receiverList.pid
606                        + ", uid=" + filter.receiverList.uid + ")"
607                        + " due to sender " + r.callerPackage
608                        + " (uid " + r.callingUid + ")");
609                skip = true;
610            }
611        }
612        if (!skip && r.appOp != AppOpsManager.OP_NONE
613               
614                 && mService.mAppOpsService.noteOperation(r.appOp,
615                filter.receiverList.uid, filter.packageName)
619                != AppOpsManager.MODE_ALLOWED) {
620            Slog.w(TAG, "Appop Denial: receiving "
621                    + r.intent.toString()
622                    + " to " + filter.receiverList.app
623                    + " (pid=" + filter.receiverList.pid
624                    + ", uid=" + filter.receiverList.uid + ")"
625                    + " requires appop " + AppOpsManager.opToName(r.appOp)
626                    + " due to sender " + r.callerPackage
627                    + " (uid " + r.callingUid + ")");
628            skip = true;
629        }
630
636
637        if (!mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
638                r.callingPid, r.resolvedType, filter.receiverList.uid)) {
639            skip = true;
640        }
641
642        if (!skip && (filter.receiverList.app == null || filter.receiverList.app.killed
643                || filter.receiverList.app.crashing)) {
644            Slog.w(TAG, "Skipping deliver [" + mQueueName + "] " + r
645                    + " to " + filter.receiverList + ": process gone or crashing");
646            skip = true;
647        }
648
649        // Ensure that broadcasts are only sent to other Instant Apps if they are marked as
650        // visible to Instant Apps.
651        final boolean visibleToInstantApps =
652                (r.intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;
653
654        if (!skip && !visibleToInstantApps && filter.instantApp
655                && filter.receiverList.uid != r.callingUid) {
656            Slog.w(TAG, "Instant App Denial: receiving "
657                    + r.intent.toString()
658                    + " to " + filter.receiverList.app
659                    + " (pid=" + filter.receiverList.pid
660                    + ", uid=" + filter.receiverList.uid + ")"
661                    + " due to sender " + r.callerPackage
662                    + " (uid " + r.callingUid + ")"
663                    + " not specifying FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS");
664            skip = true;
665        }
666
667        if (!skip && !filter.visibleToInstantApp && r.callerInstantApp
668                && filter.receiverList.uid != r.callingUid) {
669            Slog.w(TAG, "Instant App Denial: receiving "
670                    + r.intent.toString()
671                    + " to " + filter.receiverList.app
672                    + " (pid=" + filter.receiverList.pid
673                    + ", uid=" + filter.receiverList.uid + ")"
674                    + " requires receiver be visible to instant apps"
675                    + " due to sender " + r.callerPackage
676                    + " (uid " + r.callingUid + ")");
677            skip = true;
678        }
679
680        if (skip) {
//不滿足發(fā)送條件的話褂策,標(biāo)記一下横腿,結(jié)束發(fā)送
681            r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
682            return;
683        }
684
685        // If permissions need a review before any of the app components can run, we drop
686        // the broadcast and if the calling app is in the foreground and the broadcast is
687        // explicit we launch the review UI passing it a pending intent to send the skipped
688        // broadcast.
//特殊情況颓屑,還需要再次檢查權(quán)限,中斷廣播發(fā)送
    //再次滿足發(fā)送條件后耿焊,會(huì)重新進(jìn)入到后續(xù)的發(fā)送流程
689        if (mService.mPermissionReviewRequired) {
690            if (!requestStartTargetPermissionsReviewIfNeededLocked(r, filter.packageName,
691                    filter.owningUserId)) {
692                r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
693                return;
694            }
695        }
696
697        r.delivery[index] = BroadcastRecord.DELIVERY_DELIVERED;//可以發(fā)送了揪惦,標(biāo)記一下
698
699        // If this is not being sent as an ordered broadcast, then we
700        // don't want to touch the fields that keep track of the current
701        // state of ordered broadcasts.
702        if (ordered) { //針對串行廣播,保存BroadRecord,BroadcastFilter中的結(jié)構(gòu)罗侯,代表串行廣播走到哪了
703            r.receiver = filter.receiverList.receiver.asBinder();
704            r.curFilter = filter;
705            filter.receiverList.curBroadcast = r;
706            r.state = BroadcastRecord.CALL_IN_RECEIVE; //當(dāng)前Broadcast的狀態(tài)
707            if (filter.receiverList.app != null) {
708                // Bump hosting application to no longer be in background
709                // scheduling class.  Note that we can't do that if there
710                // isn't an app...  but we can only be in that case for
711                // things that directly call the IActivityManager API, which
712                // are already core system stuff so don't matter for this.
713                r.curApp = filter.receiverList.app;
714                filter.receiverList.app.curReceivers.add(r);
715                mService.updateOomAdjLocked(r.curApp, true);
716            }
717        }
723        try {
724            if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
725                    "Delivering to " + filter + " : " + r);
726            if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
                      //若BroadcastReceiver對應(yīng)的進(jìn)程處于fullBackup狀態(tài)(備份和恢復(fù))器腋,則不發(fā)送廣播
727                // Skip delivery if full backup in progress
728                // If it's an ordered broadcast, we need to continue to the next receiver.
729                if (ordered) {
                          //有序廣播必須處理完一個(gè),才能處理下一個(gè)钩杰,因此這里主動(dòng)觸發(fā)一下
730                    skipReceiverLocked(r);
731                }
732            } else {
                                //執(zhí)行發(fā)送工作
733                performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
734                        new Intent(r.intent), r.resultCode, r.resultData,
735                        r.resultExtras, r.ordered, r.initialSticky, r.userId);
736            }
737            if (ordered) {
738                r.state = BroadcastRecord.CALL_DONE_RECEIVE; //將BroadcastRecord的state設(shè)為CALL_DONE_RECEIVE
                                     //從字面上理解纫塌,似乎取已經(jīng)通過performReceiveLocked來調(diào)用BroadcastRecord實(shí)例中的onReceive了
739            }
740        } catch (RemoteException e) {
741            Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
742            if (ordered) {
743                r.receiver = null;
744                r.curFilter = null;
745                filter.receiverList.curBroadcast = null;
746                if (filter.receiverList.app != null) {
747                    filter.receiverList.app.curReceivers.remove(r);
748                }
749            }
750        }
751    }

BroadcastQueue#performReceiveLocked

495    void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
496            Intent intent, int resultCode, String data, Bundle extras,
497            boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
498        // Send the intent to the receiver asynchronously using one-way binder calls.
499        if (app != null) { //app:receiver所在進(jìn)程
500            if (app.thread != null) {
501                // If we have an app thread, do the call through that so it is
502                // correctly ordered with other one-way calls.
503                try {
504                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
505                            data, extras, ordered, sticky, sendingUser, app.repProcState);
                     //app進(jìn)程中的一個(gè)binder線程響應(yīng)(binder call都是binder線程響應(yīng)的),在其中會(huì)調(diào)用mActivityThread.post來發(fā)送消息讲弄,最終調(diào)用onReceive函數(shù)措左;mActivityThread默認(rèn)為null
506                // TODO: Uncomment this when (b/28322359) is fixed and we aren't getting
507                // DeadObjectException when the process isn't actually dead.
508                //} catch (DeadObjectException ex) {
509                // Failed to call into the process.  It's dying so just let it die and move on.
510                //    throw ex;
511                } catch (RemoteException ex) {
512                    // Failed to call into the process. It's either dying or wedged. Kill it gently.
513                    synchronized (mService) {
514                        Slog.w(TAG, "Can't deliver broadcast to " + app.processName
515                                + " (pid " + app.pid + "). Crashing it.");
516                        app.scheduleCrash("can't deliver broadcast");
517                    }
518                    throw ex;
519                }
520            } else {
521                // Application has died. Receiver doesn't exist.
522                throw new RemoteException("app.thread must not be null");
523            }
524        } else {
                  //如果動(dòng)態(tài)接收者的所在進(jìn)程已死亡,則IIntentReceiver中弱引用的LoadedApk.ReceiverDispatcher為null
                 //則調(diào)用AMS的finishReceiver
525            receiver.performReceive(intent, resultCode, data, extras, ordered,
526                    sticky, sendingUser);
527        }
528    }

BroadcastQueue#processCurBroadcastLocked

處理靜態(tài)廣播(此時(shí)所在進(jìn)程已喚起)

273    private final void processCurBroadcastLocked(BroadcastRecord r,
274            ProcessRecord app, boolean skipOomAdj) throws RemoteException {
275        if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
276                "Process cur broadcast " + r + " for app " + app);
277        if (app.thread == null) {
278            throw new RemoteException();
279        }
280        if (app.inFullBackup) {
281            skipReceiverLocked(r);
282            return;
283        }
284
285        r.receiver = app.thread.asBinder();
286        r.curApp = app;
287        app.curReceivers.add(r);
288        app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
289        mService.updateLruProcessLocked(app, false, null);
                // 要派發(fā)之前避除,調(diào)整這個(gè)進(jìn)程的優(yōu)先級
                // 所以app在receiver執(zhí)行的過程中優(yōu)先級是很高的
290        if (!skipOomAdj) {
291            mService.updateOomAdjLocked();
292        }
293
294        // Tell the application to launch this receiver.
295        r.intent.setComponent(r.curComponent);
296
297        boolean started = false;
298        try {
299            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
300                    "Delivering to component " + r.curComponent
301                    + ": " + r);
302            mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
303                                      PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER);
                  // binder call到app進(jìn)程 調(diào)用onReceive
304            app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
305                    mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
306                    r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
307                    app.repProcState);
308            if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
309                    "Process cur broadcast " + r + " DELIVERED for app " + app);
310            started = true;
311        } finally {
312            if (!started) {
313                if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
314                        "Process cur broadcast " + r + ": NOT STARTED!");
315                r.receiver = null;
316                r.curApp = null;
317                app.curReceivers.remove(r);
318            }
319        }
320    }

ActivityThread#scheduleReceiver

776        public final void scheduleReceiver(Intent intent, ActivityInfo info,
777                CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
778                boolean sync, int sendingUser, int processState) {
779            updateProcessState(processState, false);
780            ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
781                    sync, false, mAppThread.asBinder(), sendingUser);
782            r.info = info;
783            r.compatInfo = compatInfo;
784            sendMessage(H.RECEIVER, r);
785        }
1660                case RECEIVER:
1661                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp");
1662                    handleReceiver((ReceiverData)msg.obj);
1663                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1664                    break;

ActivityThread#handleReceiver

    private void handleReceiver(ReceiverData data) {
3334        // If we are getting ready to gc after going to the background, well
3335        // we are back active so skip it.
3336        unscheduleGcIdler();
3337
3338        String component = data.intent.getComponent().getClassName();
3339
3340        LoadedApk packageInfo = getPackageInfoNoCheck(
3341                data.info.applicationInfo, data.compatInfo);
3342
3343        IActivityManager mgr = ActivityManager.getService();
3344
3345        Application app;
3346        BroadcastReceiver receiver;
3347        ContextImpl context;
3348        try {
3349            app = packageInfo.makeApplication(false, mInstrumentation);
3350            context = (ContextImpl) app.getBaseContext();
3351            if (data.info.splitName != null) {
3352                context = (ContextImpl) context.createContextForSplit(data.info.splitName);
3353            }
3354            java.lang.ClassLoader cl = context.getClassLoader();
3355            data.intent.setExtrasClassLoader(cl);
3356            data.intent.prepareToEnterProcess();
3357            data.setExtrasClassLoader(cl);
3358            receiver = packageInfo.getAppFactory()
3359                    .instantiateReceiver(cl, data.info.name, data.intent);
        //對于靜態(tài)廣播而言怎披,啟動(dòng)進(jìn)程后就調(diào)用scheduleReceiver函數(shù)處理廣播
        //BroadcastReceiver的實(shí)例還沒有創(chuàng)建,因此需要在此進(jìn)行反射初始化
3360        } catch (Exception e) {
3361            if (DEBUG_BROADCAST) Slog.i(TAG,
3362                    "Finishing failed broadcast to " + data.intent.getComponent());
               //靜態(tài)廣播創(chuàng)建出問題瓶摆,需要通知AMS凉逛,調(diào)用AMS的finishReceiver
3363            data.sendFinished(mgr);
3364            throw new RuntimeException(
3365                "Unable to instantiate receiver " + component
3366                + ": " + e.toString(), e);
3367        }
3368
3369        try {
3370            if (localLOGV) Slog.v(
3371                TAG, "Performing receive of " + data.intent
3372                + ": app=" + app
3373                + ", appName=" + app.getPackageName()
3374                + ", pkg=" + packageInfo.getPackageName()
3375                + ", comp=" + data.intent.getComponent().toShortString()
3376                + ", dir=" + packageInfo.getAppDir());
3377
3378            sCurrentBroadcastIntent.set(data.intent);
3379            receiver.setPendingResult(data);
3380            receiver.onReceive(context.getReceiverRestrictedContext(),
3381                    data.intent);
3382        } catch (Exception e) {
3383            if (DEBUG_BROADCAST) Slog.i(TAG,
3384                    "Finishing failed broadcast to " + data.intent.getComponent());
             //靜態(tài)廣播調(diào)用onReceive時(shí)出問題,如所在進(jìn)程已被銷毀赏壹,需要通知AMS鱼炒,調(diào)用AMS的finishReceiver
3385            data.sendFinished(mgr);
3386            if (!mInstrumentation.onException(receiver, e)) {
3387                throw new RuntimeException(
3388                    "Unable to start receiver " + component
3389                    + ": " + e.toString(), e);
3390            }
3391        } finally {
3392            sCurrentBroadcastIntent.set(null);
3393        }
3394
3395        if (receiver.getPendingResult() != null) {
3396            data.finish();
3397        }
3398    }
send Broadcast.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蝌借,隨后出現(xiàn)的幾起案子昔瞧,更是在濱河造成了極大的恐慌,老刑警劉巖菩佑,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件自晰,死亡現(xiàn)場離奇詭異,居然都是意外死亡稍坯,警方通過查閱死者的電腦和手機(jī)酬荞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瞧哟,“玉大人混巧,你說我怎么就攤上這事∏诳” “怎么了咧党?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長陨亡。 經(jīng)常有香客問我傍衡,道長深员,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任蛙埂,我火速辦了婚禮倦畅,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绣的。我一直安慰自己叠赐,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布被辑。 她就那樣靜靜地躺著燎悍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪盼理。 梳的紋絲不亂的頭發(fā)上谈山,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天,我揣著相機(jī)與錄音宏怔,去河邊找鬼奏路。 笑死,一個(gè)胖子當(dāng)著我的面吹牛臊诊,可吹牛的內(nèi)容都是我干的鸽粉。 我是一名探鬼主播,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼抓艳,長吁一口氣:“原來是場噩夢啊……” “哼触机!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起玷或,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤儡首,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后偏友,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蔬胯,經(jīng)...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年位他,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了氛濒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,683評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鹅髓,死狀恐怖舞竿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情窿冯,我是刑警寧澤骗奖,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響重归,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜厦凤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一鼻吮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧较鼓,春花似錦椎木、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至禽篱,卻和暖如春畜伐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背躺率。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工玛界, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人悼吱。 一個(gè)月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓慎框,卻偏偏與公主長得像,于是被迫代替她去往敵國和親后添。 傳聞我的和親對象是個(gè)殘疾皇子笨枯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評論 2 349

推薦閱讀更多精彩內(nèi)容

  • 面試必背 會(huì)舍棄、總結(jié)概括——根據(jù)我這些年面試和看面試題搜集過來的知識點(diǎn)匯總而來 建議根據(jù)我的寫的面試應(yīng)對思路中的...
    luoyangzk閱讀 6,747評論 6 173
  • Android系統(tǒng)的廣播機(jī)制是一種基于消息發(fā)布和訂閱的事件驅(qū)動(dòng)模型遇西,即廣播發(fā)送者負(fù)責(zé)發(fā)布消息馅精,而接收者需要先訂閱消...
    泡面先生_Jack閱讀 1,152評論 0 2
  • 現(xiàn)實(shí)中的廣播:電臺為了傳達(dá)一些消息而發(fā)送廣播,通過廣播攜帶要傳達(dá)的消息努溃,群眾只要買一個(gè)收音機(jī)硫嘶,就可以收到廣播了。 ...
    stevewang閱讀 4,234評論 0 8
  • 1梧税、動(dòng)態(tài)注冊過程源碼分析: 在Activity中動(dòng)態(tài)注冊廣播室沦疾,在注冊方法之前其實(shí)省略了Context,也就是實(shí)際...
    騎著豬的蝸牛閱讀 717評論 0 1
  • 昨夜心頭 連簾幽夢 已然往事 今朝夢碎 滴滴淚痕 沉淀 前行 還看往昔 字字珠璣 落得黃花飄瘦 何不歸
    鹿飯飯閱讀 202評論 0 1