欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

ActivityManagerService廣播并行發(fā)送與串行發(fā)送示例解析

 更新時(shí)間:2023年03月02日 10:55:22   作者:大胃粥  
這篇文章主要為大家介紹了ActivityManagerService廣播并行發(fā)送與串行發(fā)送示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

"并行"廣播的發(fā)送

本文以 ActivityManagerService之廣播(1): 注冊(cè)與發(fā)送 為基礎(chǔ),分析“串行”和“并行”廣播的發(fā)送流程,并介紹廣播 ANR 的原理。

// 1. 獲取廣播隊(duì)列
final BroadcastQueue queue = broadcastQueueForIntent(intent);
// 2. 創(chuàng)建廣播記錄
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
        callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
        requiredPermissions, excludedPermissions, appOp, brOptions, registeredReceivers,
        resultTo, resultCode, resultData, resultExtras, ordered, sticky, false, userId,
        allowBackgroundActivityStarts, backgroundActivityStartsToken,
        timeoutExempt);
// 3. 廣播記錄加入到并行隊(duì)列中
queue.enqueueParallelBroadcastLocked(r);
// 4. 調(diào)度發(fā)送廣播
queue.scheduleBroadcastsLocked();

第3步,把廣播記錄保存到并行隊(duì)列中

// BroadcastQueue.java
public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
    // mParallelBroadcasts 類型為 ArrayList<BroadcastRecord>
    mParallelBroadcasts.add(r);
    enqueueBroadcastHelper(r);
}

第4步,調(diào)度發(fā)送廣播,最終會(huì)調(diào)用如下方法

// BroadcastQueue.java
// 此時(shí),參數(shù) fromMsg 為 true,skipOomAdj 為 false
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
    BroadcastRecord r;
    mService.updateCpuStats();
    if (fromMsg) {
        mBroadcastsScheduled = false;
    }
    // 遍歷"并行"廣播隊(duì)列
    while (mParallelBroadcasts.size() > 0) {
        r = mParallelBroadcasts.remove(0);
        r.dispatchTime = SystemClock.uptimeMillis();
        r.dispatchClockTime = System.currentTimeMillis();
        final int N = r.receivers.size();
        for (int i=0; i<N; i++) {
            Object target = r.receivers.get(i);
            // 廣播發(fā)送給動(dòng)態(tài)接收器
            deliverToRegisteredReceiverLocked(r,
                    (BroadcastFilter) target, false, i);
        }
        addBroadcastToHistoryLocked(r);
    }
    // ... 省略"串行"廣播的發(fā)送 ...
}

雖然名為“并行”廣播,但是仍然是從隊(duì)列取出廣播,然后逐個(gè)發(fā)送給動(dòng)態(tài)接收器。很顯然,這里的行為與“并行”的含義并不一致?那么廣播的“并行”發(fā)送究竟是什么意思?

接著看“并行”廣播如何發(fā)送給動(dòng)態(tài)接收器的

private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
        BroadcastFilter filter, boolean ordered, int index) {
    // ... 省略一大堆的權(quán)限或者異常檢測(cè) ...
    // 一個(gè)廣播可能有多個(gè)接收者,因此需要一個(gè)數(shù)組來(lái)保存發(fā)送的狀態(tài)
    r.delivery[index] = BroadcastRecord.DELIVERY_DELIVERED;
    // ordered 目前為 false
    if (ordered) {
        // ...
        }
    } else if (filter.receiverList.app != null) {
        // 馬上要發(fā)送廣播給接收方,因此要暫時(shí)解凍接收方的進(jìn)程
        mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(filter.receiverList.app);
    }
    try {
        if (filter.receiverList.app != null && filter.receiverList.app.isInFullBackup()) {
            // ... 處于備份狀態(tài)中 ...
        } else {
            r.receiverTime = SystemClock.uptimeMillis();
            // 保存允許從后臺(tái)啟動(dòng)activity的token
            maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
            // 添加到省電模式白名單中
            maybeScheduleTempAllowlistLocked(filter.owningUid, r, r.options);
            // 執(zhí)行廣播的發(fā)送
            performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                    new Intent(r.intent), r.resultCode, r.resultData,
                    r.resultExtras, r.ordered, r.initialSticky, r.userId);
            // parallel broadcasts are fire-and-forget, not bookended by a call to
            // finishReceiverLocked(), so we manage their activity-start token here
            if (filter.receiverList.app != null
                    && r.allowBackgroundActivityStarts && !r.ordered) {
                postActivityStartTokenRemoval(filter.receiverList.app, r);
            }
        }
        // ordered 目前為 false
        if (ordered) {
            r.state = BroadcastRecord.CALL_DONE_RECEIVE;
        }
    } catch (RemoteException e) {
        // ...
    }
}

拋開(kāi)一些細(xì)節(jié),直接看 performReceiveLocked()

// BroadcastQueue.java
void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
        Intent intent, int resultCode, String data, Bundle extras,
        boolean ordered, boolean sticky, int sendingUser)
        throws RemoteException {
    // 動(dòng)態(tài)廣播接收器的進(jìn)程,應(yīng)該是存在的
    if (app != null) {
        final IApplicationThread thread = app.getThread();
        if (thread != null) {
            try {
                // 發(fā)送廣播給接收方進(jìn)程
                thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                        data, extras, ordered, sticky, sendingUser,
            } catch (RemoteException ex) {
               // ...
            }
        } else {
            throw new RemoteException("app.thread must not be null");
        }
    } else {
        // ...
    }
}

很簡(jiǎn)單,就是通過(guò)進(jìn)程 attach 的 IApplicationThread 接口,發(fā)送廣播給進(jìn)程。這個(gè)過(guò)程,暫時(shí)先不分析,后面會(huì)分析到。

那么,現(xiàn)在來(lái)回答一下,何為“并行”廣播?其實(shí)這個(gè)答案,我也是對(duì)比了串行廣播的發(fā)送過(guò)程,才得出來(lái)的。所謂的"并行"發(fā)送,實(shí)際上就是把廣播逐個(gè)發(fā)送給動(dòng)態(tài)接收器,但是不需要等待前一個(gè)接收器反饋處理結(jié)果,就可以發(fā)送下一個(gè)。而“串行”廣播的發(fā)送,是需要等待前一個(gè)廣播接收器反饋處理結(jié)果后,才能調(diào)度發(fā)送下一個(gè)廣播。

“串行”廣播的發(fā)送

// 1.獲取廣播隊(duì)列
BroadcastQueue queue = broadcastQueueForIntent(intent);
// 2.創(chuàng)建廣播記錄
BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
        callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
        requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
        receivers, resultTo, resultCode, resultData, resultExtras,
        ordered, sticky, false, userId, allowBackgroundActivityStarts,
        backgroundActivityStartsToken, timeoutExempt);
// 3.廣播記錄加入到串行隊(duì)列中
queue.enqueueOrderedBroadcastLocked(r);
// 4.調(diào)度發(fā)送廣播
queue.scheduleBroadcastsLocked();

第3步,廣播加入到串行隊(duì)列中

// BroadcastQueue.java
public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
    mDispatcher.enqueueOrderedBroadcastLocked(r);
    enqueueBroadcastHelper(r);
}
// BroadcastDispatcher.java
void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
    mOrderedBroadcasts.add(r);
}

并行發(fā)送的廣播保存到 BroadcastQueue#mParallelBroadcasts 中,而串行發(fā)送的廣播保存到 BroadcastDispatcher#mOrderedBroadcasts 中,為何要這樣設(shè)計(jì)呢?有興趣的讀者可以研究下。

第4步,“串行”廣播的調(diào)度發(fā)送,仍然使用的是 processNextBroadcastLocked() 方法,但是代碼量是非常的大,下面將把函數(shù)分段解析。

processNextBroadcastLocked() 函數(shù)有400多行代碼,這個(gè)函數(shù)里有很多東西都可以抽出來(lái)的,但是隨著版本的更新,這塊代碼一直沒(méi)有優(yōu)化過(guò)。

final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
    BroadcastRecord r;
    mService.updateCpuStats();
    if (fromMsg) {
        mBroadcastsScheduled = false;
    }
    // 把并行廣播發(fā)送給動(dòng)態(tài)接收器
    while (mParallelBroadcasts.size() > 0) {
        // ...
    }
    // 1. 處理 receiver 進(jìn)程正在啟動(dòng)的情況
    if (mPendingBroadcast != null) {
        // 檢測(cè) receiver 進(jìn)程是否死亡
        boolean isDead;
        if (mPendingBroadcast.curApp.getPid() > 0) {
            synchronized (mService.mPidsSelfLocked) {
                ProcessRecord proc = mService.mPidsSelfLocked.get(
                        mPendingBroadcast.curApp.getPid());
                isDead = proc == null || proc.mErrorState.isCrashing();
            }
        } else {
            final ProcessRecord proc = mService.mProcessList.getProcessNamesLOSP().get(
                    mPendingBroadcast.curApp.processName, mPendingBroadcast.curApp.uid);
            isDead = proc == null || !proc.isPendingStart();
        }
        if (!isDead) {
            // 進(jìn)程仍然存活,結(jié)束此次廣播的處理流程,繼續(xù)等待
            // 等待什么呢?等待廣播進(jìn)程起來(lái),并與 AMS 完成 attach application
            // 在 attach application 的過(guò)程中,會(huì)完成廣播的發(fā)送
            return;
        } else {
            // 進(jìn)程死亡,繼續(xù)處理下一個(gè)廣播
            mPendingBroadcast.state = BroadcastRecord.IDLE;
            mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
            mPendingBroadcast = null;
        }
    }

當(dāng)發(fā)送一個(gè)廣播給 receiver 時(shí),如果 receiver 進(jìn)程沒(méi)有啟動(dòng),那么會(huì)先 fork 一個(gè) receiver 進(jìn)程,然后用 mPendingBroadcast 保存待發(fā)送的廣播。當(dāng) receiver 進(jìn)程起來(lái)的時(shí)候,會(huì)與 AMS 執(zhí)行 attach application 過(guò)程,在這個(gè)過(guò)程中,會(huì)自動(dòng)把 mPendingBroadcast 保存的廣播發(fā)送給 receiver 進(jìn)程。

因此,這里檢測(cè)到 mPendingBroadcast 不為 null 時(shí),那么 receiver 進(jìn)程肯定在啟動(dòng)中,只要 receiver 進(jìn)程沒(méi)有死亡,就什么也不用做,因?yàn)閺V播會(huì)自動(dòng)發(fā)送給 receiver 進(jìn)程。

接著看下一步的處理

final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
    // ...
    // 把并行廣播發(fā)送給動(dòng)態(tài)接收器
    while (mParallelBroadcasts.size() > 0) {
        // ...
    }
    // 1. 處理 receiver 進(jìn)程正在啟動(dòng)的情況
    if (mPendingBroadcast != null) {
        // ...
    }
    boolean looped = false;
    // 2. 通過(guò) do-while 循環(huán),找到一個(gè)現(xiàn)在可以處理的廣播
    do {
        final long now = SystemClock.uptimeMillis();
        // 獲取一個(gè)待處理的廣播
        r = mDispatcher.getNextBroadcastLocked(now);
        if (r == null) {
            // ... 沒(méi)有廣播需要處理 ...
            return;
        }
        boolean forceReceive = false;
        // 處理嚴(yán)重超時(shí)的廣播,有兩種情況
        // 一種情況是,在系統(tǒng)還沒(méi)有起來(lái)前,發(fā)送的廣播得不到執(zhí)行,發(fā)生嚴(yán)重超時(shí)
        // 另外一種情況是,在系統(tǒng)起來(lái)后,有一些超時(shí)豁免的廣播,發(fā)生了嚴(yán)重超時(shí)
        int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
        if (mService.mProcessesReady && !r.timeoutExempt && r.dispatchTime > 0) {
            if ((numReceivers > 0) &&
                    (now > r.dispatchTime + (2 * mConstants.TIMEOUT * numReceivers))) {
                broadcastTimeoutLocked(false); // forcibly finish this broadcast
                forceReceive = true;
                r.state = BroadcastRecord.IDLE;
            }
        }
        if (r.state != BroadcastRecord.IDLE) {
            return;
        }
        // 當(dāng)前廣播因?yàn)槟撤N原因,終止處理,然后處理下一個(gè)廣播 
        if (r.receivers == null || r.nextReceiver >= numReceivers
                || r.resultAbort || forceReceive) {
            // ...
            // 通知 BroadcastDispatcher ,不處理這個(gè)廣播了
            mDispatcher.retireBroadcastLocked(r);
            r = null;
            looped = true;
            // 下一次循環(huán),獲取下一個(gè)廣播來(lái)處理
            continue;
        }
        // 處理推遲發(fā)送廣播的情況
        if (!r.deferred) {
            final int receiverUid = r.getReceiverUid(r.receivers.get(r.nextReceiver));
            if (mDispatcher.isDeferringLocked(receiverUid)) {
                // ...
                // 保存推遲發(fā)送的廣播
                mDispatcher.addDeferredBroadcast(receiverUid, defer);
                r = null;
                looped = true;
                // 下一次循環(huán)時(shí),獲取下一個(gè)廣播來(lái)處理
                continue;
            }
        }
    } while (r == null);

先從整體看,通過(guò)一個(gè) do-while 循環(huán),最終是為了找到下一個(gè)處理的廣播。為何要用一個(gè)循環(huán)來(lái)尋找呢? 因?yàn)閺V播可能沒(méi)有接收器,或者已經(jīng)嚴(yán)重超時(shí),又或者廣播需要推遲發(fā)送。所以要通過(guò)一個(gè)循環(huán),找到一個(gè)能立即發(fā)送的廣播。

由于本文主要是為了分析廣播發(fā)送的整體流程,對(duì)于有些細(xì)節(jié),只做注釋而不做細(xì)致分析。需要深入研究的讀者,可以在本文的基礎(chǔ)上繼續(xù)分析。

繼續(xù)接著看下一步

final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
    BroadcastRecord r;
    mService.updateCpuStats();
    if (fromMsg) {
        mBroadcastsScheduled = false;
    }
    // 把并行廣播發(fā)送給動(dòng)態(tài)接收器
    while (mParallelBroadcasts.size() > 0) {
        // ...
    }
    // 1. 處理 receiver 進(jìn)程正在啟動(dòng)的情況
    if (mPendingBroadcast != null) {
        // ...
    }
    boolean looped = false;
    // 2. 通過(guò) do-while 循環(huán),找到一個(gè)現(xiàn)在可以處理的廣播
    do {
        final long now = SystemClock.uptimeMillis();
        // 獲取一個(gè)待處理的廣播
        r = mDispatcher.getNextBroadcastLocked(now);
        // ...
    } while (r == null);
    // 走到這里,表示已經(jīng)獲取了一個(gè)現(xiàn)在可以處理的廣播
    int recIdx = r.nextReceiver++;
    // 3. 在發(fā)送廣播之前,先發(fā)送一個(gè)超時(shí)消息
    r.receiverTime = SystemClock.uptimeMillis();
    if (recIdx == 0) {
        // 在廣播開(kāi)始發(fā)送給第一個(gè)接收器時(shí),記錄發(fā)送的時(shí)間
        r.dispatchTime = r.receiverTime;
        r.dispatchClockTime = System.currentTimeMillis();
    }
    if (! mPendingBroadcastTimeoutMessage) {
        long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
        setBroadcastTimeoutLocked(timeoutTime);
    }    

在廣播發(fā)送給一個(gè) receiver 之前,會(huì)先發(fā)送一個(gè)超時(shí)消息。從廣播準(zhǔn)備發(fā)送給一個(gè) receiver 算起,到 receiver 處理完廣播,并反饋給 AMS,如果這個(gè)時(shí)間段超過(guò)了一個(gè)時(shí)間閾值,就會(huì)引發(fā) ANR。觸發(fā) ANR 的代碼設(shè)計(jì)非常巧妙,后面會(huì)具體分析這個(gè)過(guò)程。

接著看下一步

final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
    // ...
    // 把并行廣播發(fā)送給動(dòng)態(tài)接收器
    while (mParallelBroadcasts.size() > 0) {
        // ...
    }
    // 1. 處理 receiver 進(jìn)程正在啟動(dòng)的情況
    if (mPendingBroadcast != null) {
        // ...
    }
    boolean looped = false;
    // 2. 通過(guò) do-while 循環(huán),找到一個(gè)現(xiàn)在可以處理的廣播
    do {
        // ...
    } while (r == null);
    int recIdx = r.nextReceiver++;
    // ...
    // 3. 在發(fā)送廣播之前,先發(fā)送一個(gè)超時(shí)消息
    // 當(dāng)廣播處理超時(shí)時(shí),會(huì)觸發(fā) ANR
    if (! mPendingBroadcastTimeoutMessage) {
        long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
        setBroadcastTimeoutLocked(timeoutTime);
    }
    final BroadcastOptions brOptions = r.options;
    // 4. 獲取一個(gè) receiver
    final Object nextReceiver = r.receivers.get(recIdx);
    // 5. 如果這個(gè)接收器是動(dòng)態(tài)接收器,先把廣播發(fā)送給它
    // 注意,這里處理的是有序廣播發(fā)送給動(dòng)態(tài)接收器的情況
    if (nextReceiver instanceof BroadcastFilter) {
        BroadcastFilter filter = (BroadcastFilter)nextReceiver;
        // 發(fā)送廣播給動(dòng)態(tài)接收器
        deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
        if (r.receiver == null || !r.ordered) {
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing ["
                    + mQueueName + "]: ordered="
                    + r.ordered + " receiver=" + r.receiver);
            r.state = BroadcastRecord.IDLE;
            scheduleBroadcastsLocked();
        } else {
            if (filter.receiverList != null) {
                maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
            }
        }
        // 注意,把廣播發(fā)送給 動(dòng)態(tài)receiver 后,直接返回
        return;
    }

現(xiàn)在一切就緒,那么開(kāi)始獲取一個(gè) receiver,當(dāng)這個(gè) receiver 是一個(gè)動(dòng)態(tài)接收器時(shí),直接發(fā)送廣播給它,這個(gè)發(fā)送過(guò)程前面已經(jīng)分析過(guò)。

注意,這里處理的情況是,把有序廣播發(fā)送給動(dòng)態(tài)接收器。并且發(fā)送完成后,直接 return, 也就是結(jié)束了此次廣播的發(fā)送流程。

一個(gè)廣播可能有多個(gè)接收器,為何這里只發(fā)送給一個(gè)動(dòng)態(tài)接收器,就直接返回了? 這就是從“串行”廣播的本質(zhì),需要等待當(dāng)前的廣播接收器處理完廣播,并返回結(jié)果后,才能把廣播發(fā)送給下一個(gè)廣播接收器。

接著看下一步

final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
    // ...
    // 把并行廣播發(fā)送給動(dòng)態(tài)接收器
    while (mParallelBroadcasts.size() > 0) {
        // ...
    }
    // 1. 處理 receiver 進(jìn)程正在啟動(dòng)的情況
    if (mPendingBroadcast != null) {
        // ...
    }
    boolean looped = false;
    // 2. 通過(guò) do-while 循環(huán),找到一個(gè)現(xiàn)在可以處理的廣播
    do {
        final long now = SystemClock.uptimeMillis();
        // 獲取一個(gè)待處理的廣播
        r = mDispatcher.getNextBroadcastLocked(now);
        // ...
    } while (r == null);
    // 走到這里,表示已經(jīng)獲取了一個(gè)現(xiàn)在可以處理的廣播
    int recIdx = r.nextReceiver++;
    // 3. 在發(fā)送廣播之前,先發(fā)送一個(gè)超時(shí)消息
    r.receiverTime = SystemClock.uptimeMillis();
    // ...
    if (! mPendingBroadcastTimeoutMessage) {
        long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
        setBroadcastTimeoutLocked(timeoutTime);
    }
    final BroadcastOptions brOptions = r.options;
    // 4. 獲取一個(gè) receiver
    final Object nextReceiver = r.receivers.get(recIdx);
    // 5. 如果這個(gè)接收器是動(dòng)態(tài)接收器,先把廣播發(fā)送給它
    // 注意,這里處理的是有序廣播發(fā)送給動(dòng)態(tài)接收器的情況
    if (nextReceiver instanceof BroadcastFilter) {
        // ...
        return;
    }
    // 走到這里,表示當(dāng)前的廣播接收器,是靜態(tài)接收器
    // 獲取靜態(tài)接收器的信息
    ResolveInfo info =
        (ResolveInfo)nextReceiver;
    ComponentName component = new ComponentName(
            info.activityInfo.applicationInfo.packageName,
            info.activityInfo.name);
    boolean skip = false;
    // 6. 檢測(cè)是否不需要把廣播發(fā)送給靜態(tài)接收器
    // ... 省略一大堆的檢測(cè)代碼 ...
    String targetProcess = info.activityInfo.processName;
    ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
            info.activityInfo.applicationInfo.uid);
    if (!skip) {
        // 檢測(cè)是否允許把廣播發(fā)送給靜態(tài)接收器
        final int allowed = mService.getAppStartModeLOSP(
                info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
                info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false, false);
        // 例如,大于等于 O+ 版本的 app ,不允許廣播發(fā)送給靜態(tài)接收器
        if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
            // ephemeral app 會(huì)返回這個(gè)模式
            if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
                skip = true;
            } else if (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)
                    || (r.intent.getComponent() == null
                        && r.intent.getPackage() == null
                        && ((r.intent.getFlags()
                                & Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0)
                        && !isSignaturePerm(r.requiredPermissions))) {
                // 打破以上任意一個(gè)條件,即可把廣播發(fā)送給靜態(tài)接收器
                mService.addBackgroundCheckViolationLocked(r.intent.getAction(),
                        component.getPackageName());
                skip = true;
            }
        }
    }
    // 跳過(guò)當(dāng)前廣播的發(fā)送
    if (skip) {
        // ...
        return;
    }

如果這個(gè) reciever 是靜態(tài)接收器,那么在把廣播發(fā)送給它之前,首先得進(jìn)行一大堆的檢測(cè)。最常見(jiàn)的就是權(quán)限,但是這里展示了一段 Android O+ 限制廣播發(fā)送給靜態(tài)接收器的限制,有興趣的讀者可以詳細(xì)分析。

接著看下一步

final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
    // ...
    // 把并行廣播發(fā)送給動(dòng)態(tài)接收器
    while (mParallelBroadcasts.size() > 0) {
        // ...
    }
    // 1. 處理 receiver 進(jìn)程正在啟動(dòng)的情況
    if (mPendingBroadcast != null) {
        // ...
    }
    boolean looped = false;
    // 2. 通過(guò) do-while 循環(huán),找到一個(gè)現(xiàn)在可以處理的廣播
    do {
        final long now = SystemClock.uptimeMillis();
        // 獲取一個(gè)待處理的廣播
        r = mDispatcher.getNextBroadcastLocked(now);
        // ...
    } while (r == null);
    // 走到這里,表示已經(jīng)獲取了一個(gè)現(xiàn)在可以處理的廣播
    int recIdx = r.nextReceiver++;
    // 3. 在發(fā)送廣播之前,先發(fā)送一個(gè)超時(shí)消息
    r.receiverTime = SystemClock.uptimeMillis();
    // ...
    if (! mPendingBroadcastTimeoutMessage) {
        long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
        setBroadcastTimeoutLocked(timeoutTime);
    }
    final BroadcastOptions brOptions = r.options;
    // 4. 獲取一個(gè) receiver
    final Object nextReceiver = r.receivers.get(recIdx);
    // 5. 如果這個(gè)接收器是動(dòng)態(tài)接收器,先把廣播發(fā)送給它
    // 注意,這里處理的是有序廣播發(fā)送給動(dòng)態(tài)接收器的情況
    if (nextReceiver instanceof BroadcastFilter) {
        // ...
        return;
    }
    // 走到這里,表示當(dāng)前的廣播接收器,是靜態(tài)接收器
    ResolveInfo info =
        (ResolveInfo)nextReceiver;
    ComponentName component = new ComponentName(
            info.activityInfo.applicationInfo.packageName,
            info.activityInfo.name);
    boolean skip = false;
    // 6. 檢測(cè)是否不需要把廣播發(fā)送給靜態(tài)接收器
    // ... 省略一大堆的檢測(cè)代碼 ...
    String targetProcess = info.activityInfo.processName;
    ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
            info.activityInfo.applicationInfo.uid);
    // ...
    // 跳過(guò)當(dāng)前廣播的發(fā)送
    if (skip) {
        // ...
        return;
    }
    // 現(xiàn)在可以把廣播發(fā)送給靜態(tài)接收器了
    // ...
    // 7. 靜態(tài)接收器的進(jìn)程正在運(yùn)行,那么就把廣播發(fā)送給它
    if (app != null && app.getThread() != null && !app.isKilled()) {
        try {
            app.addPackage(info.activityInfo.packageName,
                    info.activityInfo.applicationInfo.longVersionCode, mService.mProcessStats);
            maybeAddAllowBackgroundActivityStartsToken(app, r);
            // 發(fā)送廣播給廣播進(jìn)程
            processCurBroadcastLocked(r, app);
            // 注意,廣播發(fā)送給這個(gè)靜態(tài)接收器后,直接結(jié)束此次廣播的處理
            return;
        } catch (RemoteException e) {
            // ...
        }
    }
}

如果沒(méi)有限制,那么現(xiàn)在就可以把廣播發(fā)送給靜態(tài)接收器。

如果靜態(tài)接收器所在的進(jìn)程已經(jīng)運(yùn)行了,那么把廣播發(fā)送給這個(gè)進(jìn)程,這個(gè)過(guò)程與前面發(fā)送廣播給動(dòng)態(tài)接收器的過(guò)程非常類似,這里就不分析了。

注意,這里把廣播發(fā)送給一個(gè)靜態(tài)接收器,也是直接 return,懂了吧?

接著往下看

final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
    // ...
    // 把并行廣播發(fā)送給動(dòng)態(tài)接收器
    while (mParallelBroadcasts.size() > 0) {
        // ...
    }
    // 1. 處理 receiver 進(jìn)程正在啟動(dòng)的情況
    if (mPendingBroadcast != null) {
        // ...
    }
    boolean looped = false;
    // 2. 通過(guò) do-while 循環(huán),找到一個(gè)現(xiàn)在可以處理的廣播
    do {
        final long now = SystemClock.uptimeMillis();
        // 獲取一個(gè)待處理的廣播
        r = mDispatcher.getNextBroadcastLocked(now);
        // ...
    } while (r == null);
    // 走到這里,表示已經(jīng)獲取了一個(gè)現(xiàn)在可以處理的廣播
    int recIdx = r.nextReceiver++;
    // 3. 在發(fā)送廣播之前,先發(fā)送一個(gè)超時(shí)消息
    r.receiverTime = SystemClock.uptimeMillis();
    // ...
    if (! mPendingBroadcastTimeoutMessage) {
        long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
        setBroadcastTimeoutLocked(timeoutTime);
    }
    final BroadcastOptions brOptions = r.options;
    // 4. 獲取一個(gè) receiver
    final Object nextReceiver = r.receivers.get(recIdx);
    // 5. 如果這個(gè)接收器是動(dòng)態(tài)接收器,先把廣播發(fā)送給它
    // 注意,這里處理的是有序廣播發(fā)送給動(dòng)態(tài)接收器的情況
    if (nextReceiver instanceof BroadcastFilter) {
        // ...
        return;
    }
    // 走到這里,表示當(dāng)前的廣播接收器,是靜態(tài)接收器
    ResolveInfo info =
        (ResolveInfo)nextReceiver;
    ComponentName component = new ComponentName(
            info.activityInfo.applicationInfo.packageName,
            info.activityInfo.name);
    boolean skip = false;
    // 6. 檢測(cè)是否不需要把廣播發(fā)送給靜態(tài)接收器
    // ...
    // 跳過(guò)當(dāng)前廣播的發(fā)送
    if (skip) {
        r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED;
        r.receiver = null;
        r.curFilter = null;
        r.state = BroadcastRecord.IDLE;
        r.manifestSkipCount++;
        // 發(fā)送下一個(gè)廣播
        scheduleBroadcastsLocked();
        return;
    }
    // 現(xiàn)在可以把廣播發(fā)送給靜態(tài)接收器了
    // ...
    // 7. 靜態(tài)接收器的進(jìn)程正在運(yùn)行,那么就把廣播發(fā)送給它
    if (app != null && app.getThread() != null && !app.isKilled()) {
        // ...
    }
    // 8. 靜態(tài)接收器的進(jìn)程沒(méi)有運(yùn)行,fork it!
    r.curApp = mService.startProcessLocked(targetProcess,
            info.activityInfo.applicationInfo, true,
            r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
            new HostingRecord("broadcast", r.curComponent), isActivityCapable
            ? ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE : ZYGOTE_POLICY_FLAG_EMPTY,
            (r.intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false);
    // 處理 fork 進(jìn)程失敗的情況
    if (r.curApp == null) {
        // ...
        return;
    }
    maybeAddAllowBackgroundActivityStartsToken(r.curApp, r);
    // fork 進(jìn)程成功,保存廣播數(shù)據(jù),等待進(jìn)程起來(lái)后,再處理這個(gè)廣播
    mPendingBroadcast = r;
    mPendingBroadcastRecvIndex = recIdx;
}

剛才已經(jīng)處理了靜態(tài)接收器的進(jìn)程存在的情況,那么現(xiàn)在處理進(jìn)程不存在的情況,因此首先得 fork 進(jìn)程。當(dāng)成功 fork 進(jìn)程后,保存待發(fā)送的廣播的數(shù)據(jù),例如,用 mPendingBroadcast 保存廣播,然后當(dāng)進(jìn)程啟動(dòng)時(shí),與 AMS 進(jìn)行 attach application 時(shí),會(huì)自動(dòng)把廣播發(fā)送給該進(jìn)程。這個(gè)過(guò)程后面會(huì)分析。

注意,此時(shí)函數(shù)已經(jīng)結(jié)束,而廣播正在發(fā)送給一個(gè)正在啟動(dòng)的進(jìn)程。很顯然,需要等待這個(gè)廣播的處理結(jié)果,才能繼續(xù)下一個(gè)廣播的發(fā)送,這也符合“串行”廣播的定義。

廣播發(fā)送給正在啟動(dòng)的進(jìn)程

剛才,我們分析到一個(gè)過(guò)程,當(dāng)靜態(tài)接收器所在的進(jìn)程沒(méi)有啟動(dòng)的時(shí)候,首先 fork 進(jìn)程,那么廣播之后是如何發(fā)送給進(jìn)程的呢?

首先,我們知道當(dāng)進(jìn)程啟動(dòng)后,會(huì)執(zhí)行 attach application 過(guò)程,最終會(huì)調(diào)用 AMS 如下方法

// ActivityManagerService.java
    private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
            int pid, int callingUid, long startSeq) {
        // ...
        try {
            // ...
            if (app.getIsolatedEntryPoint() != null) {
                // ...
            } else if (instr2 != null) {
                // ...
            } else {
                // 初始化進(jìn)程環(huán)境
                thread.bindApplication(processName, appInfo, providerList, null, profilerInfo,
                        null, null, null, testMode,
                        mBinderTransactionTrackingEnabled, enableTrackAllocation,
                        isRestrictedBackupMode || !normalMode, app.isPersistent(),
                        new Configuration(app.getWindowProcessController().getConfiguration()),
                        app.getCompat(), getCommonServicesLocked(app.isolated),
                        mCoreSettingsObserver.getCoreSettingsLocked(),
                        buildSerial, autofillOptions, contentCaptureOptions,
                        app.getDisabledCompatChanges(), serializedSystemFontMap);
            }
            // ...
        } catch (Exception e) {
            // ...
        }
        // ....
        // 處理正在等待宿主進(jìn)程起來(lái)的廣播
        if (!badApp && isPendingBroadcastProcessLocked(pid)) {
            try {
                // 發(fā)送隊(duì)列中正在等待進(jìn)程起來(lái)的廣播
                didSomething |= sendPendingBroadcastsLocked(app);
                checkTime(startTime, "attachApplicationLocked: after sendPendingBroadcastsLocked");
            } catch (Exception e) {
                // ...
            }
        }
        // ...
        return true;
    }
    boolean sendPendingBroadcastsLocked(ProcessRecord app) {
        boolean didSomething = false;
        for (BroadcastQueue queue : mBroadcastQueues) {
            didSomething |= queue.sendPendingBroadcastsLocked(app);
        }
        return didSomething;
    }

看到了,AMS 首先對(duì)進(jìn)程進(jìn)行了初始化,然后就會(huì)把等待進(jìn)程啟動(dòng)的廣播,發(fā)送給它。

// BroadcastQueue.java
public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
    boolean didSomething = false;
    // mPendingBroadcast 保存的就是等待進(jìn)程啟動(dòng)啟動(dòng)后,需要發(fā)送的廣播。
    final BroadcastRecord br = mPendingBroadcast;
    if (br != null && br.curApp.getPid() > 0 && br.curApp.getPid() == app.getPid()) {
        if (br.curApp != app) {
            Slog.e(TAG, "App mismatch when sending pending broadcast to "
                    + app.processName + ", intended target is " + br.curApp.processName);
            return false;
        }
        try {
            mPendingBroadcast = null;
            // 發(fā)送廣播給進(jìn)程
            processCurBroadcastLocked(br, app);
            didSomething = true;
        } catch (Exception e) {
            // ...
        }
    }
    return didSomething;
}

mPendingBroadcast 保存的就是等待進(jìn)程啟動(dòng)啟動(dòng)后,需要發(fā)送的廣播?,F(xiàn)在進(jìn)程已經(jīng)啟動(dòng),立即發(fā)送廣播

// BroadcastQueue.java
private final void processCurBroadcastLocked(BroadcastRecord r,
        ProcessRecord app) throws RemoteException {
    final IApplicationThread thread = app.getThread();
    if (thread == null) {
        throw new RemoteException();
    }
    if (app.isInFullBackup()) {
        skipReceiverLocked(r);
        return;
    }
    // 更新正在處理廣播的 receiver 數(shù)據(jù)
    r.receiver = thread.asBinder();
    r.curApp = app;
    // 保存當(dāng)前正在運(yùn)行的 receiver
    final ProcessReceiverRecord prr = app.mReceivers;
    prr.addCurReceiver(r);
    app.mState.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
    mService.updateLruProcessLocked(app, false, null);
    mService.enqueueOomAdjTargetLocked(app);
    mService.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
    r.intent.setComponent(r.curComponent);
    boolean started = false;
    try {
        mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
                                  PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER);
        // 通知進(jìn)程啟動(dòng) receiver 來(lái)處理廣播
        thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
                mService.compatibilityInfoForPackage(r.curReceiver.applicationInfo),
                r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
                app.mState.getReportedProcState());
        started = true;
    } finally {
        if (!started) {
            // ...
        }
    }
}

現(xiàn)在 AMS 通知 receiver 所在的進(jìn)程來(lái)處理廣播

// ActivityThread.java
private class ApplicationThread extends IApplicationThread.Stub {
    private static final String DB_INFO_FORMAT = "  %8s %8s %14s %14s  %s";
    public final void scheduleReceiver(Intent intent, ActivityInfo info,
            CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
            boolean sync, int sendingUser, int processState) {
        updateProcessState(processState, false);
        // 廣播數(shù)據(jù)包裝成 ReceiverData
        ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
                sync, false, mAppThread.asBinder(), sendingUser);
        r.info = info;
        r.compatInfo = compatInfo;
        sendMessage(H.RECEIVER, r);
    }

最終調(diào)用 handleReceiver() 處理廣播數(shù)據(jù)

private void handleReceiver(ReceiverData data) {
    unscheduleGcIdler();
    String component = data.intent.getComponent().getClassName();
    LoadedApk packageInfo = getPackageInfoNoCheck(
            data.info.applicationInfo, data.compatInfo);
    IActivityManager mgr = ActivityManager.getService();
    Application app;
    BroadcastReceiver receiver;
    ContextImpl context;
    try {
        // 1. 創(chuàng)建 Application 對(duì)象,并調(diào)用 Application#onCreate()
        app = packageInfo.makeApplication(false, mInstrumentation);
        // ...
        // 2. 創(chuàng)建 BroadcastReceiver 對(duì)象
        receiver = packageInfo.getAppFactory()
                .instantiateReceiver(cl, data.info.name, data.intent);
    } catch (Exception e) {
        // ...
    }
    try {
        sCurrentBroadcastIntent.set(data.intent);
        receiver.setPendingResult(data);
        // 3. 執(zhí)行 BroadcastReceiver#onReceive()
        receiver.onReceive(context.getReceiverRestrictedContext(),
                data.intent);
    } catch (Exception e) {
        // ...
    } finally {
        sCurrentBroadcastIntent.set(null);
    }
    // 4. 返回廣播的處理結(jié)果給 AMS
    if (receiver.getPendingResult() != null) {
        data.finish();
    }
}

這里的過(guò)程很清晰明了吧,直接看最后一步,把廣播的處理結(jié)果反饋給 AMS

// BroadcastReceiver.java
public final void finish() {
    if (mType == TYPE_COMPONENT) {
        final IActivityManager mgr = ActivityManager.getService();
        if (QueuedWork.hasPendingWork()) {
            // ...
        } else {
            sendFinished(mgr);
        }
    } else if (mOrderedHint &amp;&amp; mType != TYPE_UNREGISTERED) {
        // ...
    }
}
public void sendFinished(IActivityManager am) {
    synchronized (this) {
        if (mFinished) {
            throw new IllegalStateException("Broadcast already finished");
        }
        mFinished = true;
        try {
            if (mResultExtras != null) {
                mResultExtras.setAllowFds(false);
            }
            if (mOrderedHint) {
                // 有序廣播的反饋
                am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
                        mAbortBroadcast, mFlags);
            } else {
                // 非有序廣播的費(fèi)奎
                am.finishReceiver(mToken, 0, null, null, false, mFlags);
            }
        } catch (RemoteException ex) {
        }
    }
}

現(xiàn)在看下 AMS 如何處理這個(gè)反饋的結(jié)果

// ActivityManagerService.java
public void finishReceiver(IBinder who, int resultCode, String resultData,
        Bundle resultExtras, boolean resultAbort, int flags) {
    // ...
    final long origId = Binder.clearCallingIdentity();
    try {
        boolean doNext = false;
        BroadcastRecord r;
        BroadcastQueue queue;
        synchronized(this) {
            if (isOnOffloadQueue(flags)) {
                queue = mOffloadBroadcastQueue;
            } else {
                queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0
                        ? mFgBroadcastQueue : mBgBroadcastQueue;
            }
            // 1. 匹配進(jìn)程正在處理的廣播
            r = queue.getMatchingOrderedReceiver(who);
            // 2. 完成當(dāng)前 receiver 廣播的處理流程
            if (r != null) {
                doNext = r.queue.finishReceiverLocked(r, resultCode,
                    resultData, resultExtras, resultAbort, true);
            }
            // 3. 發(fā)送廣播給下一個(gè) receiver,或者發(fā)送下一個(gè)廣播
            if (doNext) {
                r.queue.processNextBroadcastLocked(/*fromMsg=*/ false, /*skipOomAdj=*/ true);
            }
            // updateOomAdjLocked() will be done here
            trimApplicationsLocked(false, OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
        }
    } finally {
        Binder.restoreCallingIdentity(origId);
    }
}

看到了,只有當(dāng)前 receiver 處理完廣播,才會(huì)發(fā)送廣播給下一個(gè) receiver,這就是“串行”廣播的本質(zhì)。

廣播 ANR

最后,來(lái)探討一個(gè)廣播 ANR 的原理,本來(lái)我以為很簡(jiǎn)單的,就是發(fā)送一個(gè)超時(shí)消息嘛。但是當(dāng)我細(xì)看的時(shí)候,我發(fā)現(xiàn)這個(gè) ANR 設(shè)計(jì)的很巧妙,我覺(jué)得我們可以學(xué)習(xí)下,因此這里單獨(dú)拿出來(lái)分析。

這里,我得提醒大家一點(diǎn),只有“串行”廣播才會(huì)發(fā)生 ANR,因?yàn)樗却?receiver 的處理結(jié)果。

根據(jù)前面分析,“串行”廣播發(fā)送給 receiver 前,會(huì)發(fā)送一個(gè)超時(shí)消息,如下

// BroadcastQueue.java
if (! mPendingBroadcastTimeoutMessage) {
    long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
    setBroadcastTimeoutLocked(timeoutTime);
}

當(dāng)這個(gè)消息被執(zhí)行的時(shí)候,會(huì)調(diào)用如下代碼

// BroadcastQueue.java
final void broadcastTimeoutLocked(boolean fromMsg) {
    if (fromMsg) {
        mPendingBroadcastTimeoutMessage = false;
    }
    if (mDispatcher.isEmpty() || mDispatcher.getActiveBroadcastLocked() == null) {
        return;
    }
    long now = SystemClock.uptimeMillis();
    // 獲取當(dāng)前正在處理的廣播
    BroadcastRecord r = mDispatcher.getActiveBroadcastLocked();
    if (fromMsg) {
        // 系統(tǒng)還沒(méi)有就緒
        if (!mService.mProcessesReady) {
            return;
        }
        // 廣播超時(shí)被豁免
        if (r.timeoutExempt) {
            if (DEBUG_BROADCAST) {
                Slog.i(TAG_BROADCAST, "Broadcast timeout but it's exempt: "
                        + r.intent.getAction());
            }
            return;
        }
        // 1. 廣播沒(méi)有超時(shí)
        long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
        if (timeoutTime > now) {
            // 發(fā)送下一個(gè)超時(shí)消息
            setBroadcastTimeoutLocked(timeoutTime);
            return;
        }
    }
    if (r.state == BroadcastRecord.WAITING_SERVICES) {
        // ...
        return;
    }
    // 2. 走到這里,表示廣播超時(shí),觸發(fā) ANR
    final boolean debugging = (r.curApp != null && r.curApp.isDebugging());
    r.receiverTime = now;
    if (!debugging) {
        r.anrCount++;
    }
    ProcessRecord app = null;
    String anrMessage = null;
    Object curReceiver;
    if (r.nextReceiver > 0) {
        curReceiver = r.receivers.get(r.nextReceiver-1);
        r.delivery[r.nextReceiver-1] = BroadcastRecord.DELIVERY_TIMEOUT;
    } else {
        curReceiver = r.curReceiver;
    }
    logBroadcastReceiverDiscardLocked(r);
    // 獲取 receiver 進(jìn)程
    if (curReceiver != null && 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;
    }
    // 強(qiáng)制結(jié)束當(dāng)前廣播的發(fā)送流程
    finishReceiverLocked(r, r.resultCode, r.resultData,
            r.resultExtras, r.resultAbort, false);
    // 調(diào)度下一次的廣播發(fā)送
    scheduleBroadcastsLocked();
    // app 不處于 debug 模式,引發(fā) ANR
    if (!debugging && anrMessage != null) {
        mService.mAnrHelper.appNotResponding(app, anrMessage);
    }
}

第2步,引發(fā) ANR ,很簡(jiǎn)單,就是因?yàn)檎麄€(gè)發(fā)送與反饋過(guò)程超時(shí)了。

而第1步,就是處理不超時(shí)的情況。這里大家是不是很疑惑,移除超時(shí)消息不是在接收到廣播反饋后進(jìn)行的嗎? 我可以負(fù)責(zé)地告訴你,并不是!那這里第1步怎么理解呢?

首先這個(gè)超時(shí)消息一定觸發(fā),但是觸發(fā)這個(gè)超時(shí)消息,并不代表一定會(huì)引發(fā) ANR。

假如當(dāng)前 receiver 的廣播處理流程,在超時(shí)時(shí)間之前就完成了,那么 AMS 會(huì)調(diào)度廣播發(fā)送給下一個(gè) receiver。

于是,針對(duì)下一個(gè) receiver ,會(huì)更新 r.receiverTime,那么第一步此時(shí)計(jì)算出來(lái)的 timeoutTime 是下一個(gè) receiver 的廣播超時(shí)時(shí)間,很顯然是大于 now 的,于是就不會(huì)走第2步的 ANR 流程。

最后利用這個(gè) timeoutTime,為下一個(gè) receiver 再發(fā)送一個(gè)超時(shí)消息,簡(jiǎn)直是完美!

至于為何不在廣播反饋的時(shí)候,移除這個(gè)超時(shí)消息,我心中有一點(diǎn)小小的想法,但是也不能確定是不是這個(gè)原因,才這樣設(shè)計(jì)的。不過(guò),對(duì)我來(lái)說(shuō),這一招,我算是學(xué)會(huì)了。

最后,提醒讀者,廣播接收器是在主線程中運(yùn)行的,不要執(zhí)行耗時(shí)任務(wù),或者潛在耗時(shí)的任務(wù),我在工作中看到了無(wú)數(shù)血與淚的案例。

結(jié)束

本文從整體上分析了“串行”和“并行”廣播的發(fā)送流程,并以此為基礎(chǔ),解析了“串行”廣播的 ANR 原理。

但是,還有一些廣播的細(xì)節(jié),我并沒(méi)有分析,例如 Android O+ 如何限制廣播發(fā)送給靜態(tài)接收器,又例如,什么情況下,會(huì)把廣播延遲發(fā)送給 app。只要你站在我的肩膀上,就可以自行分析這些細(xì)節(jié)。

另外,我在分析的時(shí)候,有個(gè)優(yōu)化廣播發(fā)送的想法,如果廣播有多個(gè)app的靜態(tài)接收器,我可以建立一個(gè)機(jī)制,優(yōu)先把廣播發(fā)送給某些 app,并且對(duì)于這些 app,我不需要等待它反饋廣播處理結(jié)果,就可以發(fā)送廣播給下一個(gè)接收器。如果以后工作有需要,我會(huì)嘗試做一做,更多關(guān)于ActivityManagerService廣播的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Android自定義圓形進(jìn)度條效果

    Android自定義圓形進(jìn)度條效果

    這篇文章主要為大家詳細(xì)介紹了Android自定義圓形進(jìn)度條效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • Android?實(shí)現(xiàn)卡片堆疊錢(qián)包管理動(dòng)畫(huà)效果

    Android?實(shí)現(xiàn)卡片堆疊錢(qián)包管理動(dòng)畫(huà)效果

    這篇文章主要介紹了Android?實(shí)現(xiàn)卡片堆疊錢(qián)包管理動(dòng)畫(huà)效果,實(shí)現(xiàn)思路是在動(dòng)畫(huà)回調(diào)中requestLayout?實(shí)現(xiàn)動(dòng)畫(huà)效果,用Bounds?對(duì)象記錄每一個(gè)CardView?對(duì)象的初始位置,當(dāng)前位置,運(yùn)動(dòng)目標(biāo)位置,需要的朋友可以參考下
    2022-07-07
  • Android SDK Manager更新、下載速度慢問(wèn)題解決辦法

    Android SDK Manager更新、下載速度慢問(wèn)題解決辦法

    這篇文章主要介紹了Android SDK Manager更新、下載速度慢問(wèn)題解決辦法的相關(guān)資料,需要的朋友可以參考下
    2017-05-05
  • Android提高之BroadcastReceiver實(shí)例詳解

    Android提高之BroadcastReceiver實(shí)例詳解

    這篇文章主要介紹了Android的BroadcastReceiver用法,在Android的項(xiàng)目開(kāi)發(fā)中是比較實(shí)用的功能,需要的朋友可以參考下
    2014-08-08
  • Android圖片選擇器 豐富的配置選項(xiàng)

    Android圖片選擇器 豐富的配置選項(xiàng)

    這篇文章主要介紹了Android圖片選擇器,豐富的配置選項(xiàng),極大程度的簡(jiǎn)化使用,感興趣的小伙伴們可以參考一下
    2016-08-08
  • Android仿蘋(píng)果關(guān)機(jī)界面實(shí)現(xiàn)代碼

    Android仿蘋(píng)果關(guān)機(jī)界面實(shí)現(xiàn)代碼

    這篇文章主要為大家詳細(xì)介紹了Android仿蘋(píng)果關(guān)機(jī)界面的實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • Android相機(jī)Camera基礎(chǔ)知識(shí)

    Android相機(jī)Camera基礎(chǔ)知識(shí)

    這篇文章主要為大家詳細(xì)介紹了Android相機(jī)Camera基礎(chǔ)知識(shí),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • Kotlin文件讀寫(xiě)與SharedPreferences存儲(chǔ)功能實(shí)現(xiàn)方法

    Kotlin文件讀寫(xiě)與SharedPreferences存儲(chǔ)功能實(shí)現(xiàn)方法

    SharedPreferences是安卓平臺(tái)上一個(gè)輕量級(jí)的存儲(chǔ)類,用來(lái)保存應(yīng)用的一些常用配置,比如Activity狀態(tài),Activity暫停時(shí),將此activity的狀態(tài)保存到SharedPereferences中;當(dāng)Activity重載,系統(tǒng)回調(diào)方法onSaveInstanceState時(shí),再?gòu)腟haredPreferences中將值取出
    2022-12-12
  • Android崩潰異常捕獲方法

    Android崩潰異常捕獲方法

    這篇文章主要介紹了Android崩潰異常捕獲方法的相關(guān)資料,需要的朋友可以參考下
    2016-03-03
  • Android修改Dialog樣式的方法

    Android修改Dialog樣式的方法

    Android 對(duì)話框支持自定義標(biāo)題,內(nèi)容,按鈕和點(diǎn)擊事件,基本上可以滿足我們?nèi)粘5氖褂谩?但有時(shí)候我們想要修改對(duì)話框的文字,按鈕顏色等,系統(tǒng)并沒(méi)有提供對(duì)應(yīng)的方法,正常情況下只能自定義布局。 接下來(lái)通過(guò)源碼解析介紹幾種修改 Dialog樣式的方法。
    2021-05-05

最新評(píng)論