1. 程式人生 > >Android廣播管理三--廣播發送(sendBroadcast)流程分析

Android廣播管理三--廣播發送(sendBroadcast)流程分析

        前面我們分析了Android應用程式註冊廣播接收器的過程,接下來它還要等待ActivityManagerService將廣播分發過來。ActivityManagerService是如何得到廣播並把它分發出去的呢?

         廣播的傳送者將廣播發送到ActivityManagerService,ActivityManagerService接收到這個廣播以後,就會在自己的註冊中心檢視有哪些廣播接收器訂閱了該廣播,然後把這個廣播逐一發送到這些廣播接收器中,但是ActivityManagerService並不等待廣播接收器處理這些廣播就返回了,因此,廣播的傳送和處理是非同步的。概括來說,廣播的傳送路徑就是從傳送者到ActivityManagerService,再從ActivityManagerService到接收者,這中間的兩個過程都是通過Binder程序間通訊機制來完成的

傳送廣播

ContextWrapper.sendBroadcast

        這個函式定義在frameworks/base/core/java/android/content/ContextWrapper.java檔案中:

public class ContextWrapper extends Context {  
    Context mBase;  
  
    ......  
  
    @Override  
    public void sendBroadcast(Intent intent) {  
        mBase.sendBroadcast(intent);  
    }  
  
    ......  
  
} 
         我們上文介紹了ContextWrapper類是Context類的封裝類,ContextImpl是Context類的實現類。這裡的成員變數mBase是一個ContextImpl例項,這裡只簡單地呼叫ContextImpl.sendBroadcast進一行操作。

ContextImpl.sendBroadcast

         這個函式定義在frameworks/base/core/java/android/app/ContextImpl.java檔案中:

public void sendBroadcast(Intent intent) {
    ............
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
        //StrictMode下,對一些Action需要進行檢查
        intent.prepareToLeaveProcess(this);

        //呼叫AMS中的介面
        ActivityManagerNative.getDefault().broadcastIntent(
                mMainThread.getApplicationThread(), intent, resolvedType, null,
                Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                getUserId());
    } catch(RemoteException e) {
        ..............
    }
}
        這裡的resolvedType表示這個Intent的MIME型別,如果沒有設定這個Intent的MIME型別,resolvedType為null。接下來就呼叫ActivityManagerService的遠端介面ActivityManagerProxy把這個廣播發送給ActivityManagerService了。

ActivityManagerProxy.broadcastIntent

        這個函式定義在frameworks/base/core/java/android/app/ActivityManagerNative.java檔案中:

    class ActivityManagerProxy implements IActivityManager  
    {  
        ......  
      
        public int broadcastIntent(IApplicationThread caller,  
            Intent intent, String resolvedType,  IIntentReceiver resultTo,  
            int resultCode, String resultData, Bundle map,  
            String requiredPermission, boolean serialized,  
            boolean sticky) throws RemoteException  
        {  
            Parcel data = Parcel.obtain();  
            Parcel reply = Parcel.obtain();  
            data.writeInterfaceToken(IActivityManager.descriptor);  
            data.writeStrongBinder(caller != null ? caller.asBinder() : null);  
            intent.writeToParcel(data, 0);  
            data.writeString(resolvedType);  
            ......
            mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0);  
            reply.readException();  
            int res = reply.readInt();  
            reply.recycle();  
            data.recycle();  
            return res;  
        }  
      
        ......  
      
    }  
        這裡主要是把要傳遞的引數封裝好,然後通過Binder驅動程式進入到ActivityManagerService的broadcastIntent()方法中。

ActivityManagerService.broadcastIntent

         這個函式定義在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java檔案中:
    public final class ActivityManagerService extends ActivityManagerNative  
            implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {  
        ......  
      
        public final int broadcastIntent(IApplicationThread caller,  
                Intent intent, String resolvedType, IIntentReceiver resultTo,  
                int resultCode, String resultData, Bundle map,  
                String requiredPermission, boolean serialized, boolean sticky) {  
            synchronized(this) {//verifyBroadcastLocked方法檢查Broadcast中intent攜帶的資訊是否有問題(不能攜帶檔案描述符,避免安全隱患)
                intent = verifyBroadcastLocked(intent);//同時檢查intent的flag
      
                final ProcessRecord callerApp = getRecordForAppLocked(caller);//獲取呼叫方(傳送廣播)的ProcessRecord
                final int callingPid = Binder.getCallingPid();  
                final int callingUid = Binder.getCallingUid();  
                final long origId = Binder.clearCallingIdentity();  
                int res = broadcastIntentLocked(callerApp,  
                    callerApp != null ? callerApp.info.packageName : null,  
                    intent, resolvedType, resultTo,  
                    resultCode, resultData, map, requiredPermission, serialized,  
                    sticky, callingPid, callingUid);  
                Binder.restoreCallingIdentity(origId);  
                return res;  
            }  
        }  
      
        ......  
    }  
        這裡注意幾個引數:

        serialized:表示當前廣播是否是order廣播,true代表order廣播(有序廣播);

        sticky:表示當前廣播是否是sticky廣播,true代表sticky廣播(粘性廣播);

        broadcastIntent中對Broadcast對應的Intent進行一些檢查後,呼叫broadcastIntentLocked進行實際的處理。

ActivityManagerService.broadcastIntentLocked

        這個函式定義在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java檔案中,程式碼量較大,分段分析。

Part I

final int broadcastIntentLocked(.....) {
    intent = new Intent(intent);

    // By default broadcasts do not go to stopped apps.
    // Android系統對所有app的執行狀態進行了跟蹤
    // 當應用第一次安裝但未使用過,或從程式管理器被強行關閉後,將處於停止狀態

    // 在傳送廣播時,不管是什麼廣播型別,系統預設增加了FLAG_EXCLUDE_STOPPED_PACKAGES的flag
    // 使得對於所有BroadcastReceiver而言,如果其所在程序的處於停止狀態,該BroadcastReceiver將無法接收到廣播
    intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

    //大量條件檢查,例如:
    //有些Action只能由系統來發送;
    //有些Action需要傳送方申明瞭對應許可權
    ...................

    //某些Action,例如Package增加或移除、時區或時間改變、清除DNS、代理變化等,需要AMS來處理
    //AMS需要根據Action,進行對應的操作
    ..................
}
1、排除Stopped狀態的應用
        // By default broadcasts do not go to stopped apps.
        intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
        所有的廣播Intent在這裡都會預設加上這個標記,表示所有的廣播都不會發送到Stopped狀態的應用,應該在傳送的時候會檢查應用當前的狀態。
2、系統升級廣播
        // If we have not finished booting, don't allow this to launch new processes.
        if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
        }
         Intent.FLAG_RECEIVER_BOOT_UPGRADE是系統升級的flag,允許在系統啟動前傳送。只有註冊了的接收者被呼叫,所有的BroadcastReceiver元件不會被載入。
3、處理受保護廣播
        // Verify that protected broadcasts are only being sent by system code,受保護的廣播只能有系統傳送
        // and that system code is only sending protected broadcasts.
        final String action = intent.getAction();
        final boolean isProtectedBroadcast;
        try {
            isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
        } catch (RemoteException e) {
            Slog.w(TAG, "Remote exception", e);
            return ActivityManager.BROADCAST_SUCCESS;
        }
        受保護廣播是通過查詢PMS得到的,如果是受保護廣播,丟擲異常後直接返回ActivityManager.BROADCAST_SUCCESS,不會進行下面的動作。
4、判斷髮送者是否是系統程序
        final boolean isCallerSystem;
        switch (UserHandle.getAppId(callingUid)) {//如果是root、system、phone、bluetooth、nfc等的UID,則廣播不受限制
            case Process.ROOT_UID:
            case Process.SYSTEM_UID:
            case Process.PHONE_UID:
            case Process.BLUETOOTH_UID:
            case Process.NFC_UID:
                isCallerSystem = true;
                break;
            default:
                isCallerSystem = (callerApp != null) && callerApp.persistent;
                break;
        }
        isCallerSystem表示系統級使用者傳送的廣播,這部分廣播不受限制。
5、處理特定系統廣播
        if (action != null) {
            switch (action) {
                case Intent.ACTION_UID_REMOVED:
                case Intent.ACTION_PACKAGE_REMOVED:
                case Intent.ACTION_PACKAGE_CHANGED:
                case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
                case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
                case Intent.ACTION_PACKAGES_SUSPENDED:
                case Intent.ACTION_PACKAGES_UNSUSPENDED:
                    // Handle special intents: if this broadcast is from the package
                    // manager about a package being removed, we need to remove all of
                    // its activities from the history stack.
        對於一些來自PMS的包狀態的變化,AMS需要及時的處理相關的Activity,這裡是因為AMS兼顧了所有的4大元件,當包的狀態發生變化,AMS作為總管需要第一時間內處理完總管要做的事情,然後將對應的廣播再轉發給對應的應用。

        傳送廣播的第一階段主要工作有:

        (1).根據廣播對應的Intent中的資訊,判斷髮送方是否有傳送該廣播的許可權;

        (2).檢查傳送的廣播是否是一些特殊的系統廣播,特別是從PackageManagerService中發出的有個安裝的應用移除的廣播,如果檢測到,需要將這些包中的Activity從AMS的Activity棧中移除。

Part II

..............
// Add to the sticky list if requested.
// 處理粘性廣播相關的內容
if (sticky) {
    //檢查是否有傳送許可權,在AndroidManifest.xml中必須宣告android.permission.BROADCAST_STICKY許可權
    if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
            callingPid, callingUid)
            != PackageManager.PERMISSION_GRANTED) {
        ..................//丟擲SecurityException異常
    }

    //粘性廣播不能指定接收許可權,即傳送時不能有requiredPermission許可權資訊
    if (requiredPermissions != null && requiredPermissions.length > 0) {
        ..............
        return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
    }

    if (intent.getComponent() != null) {
        //傳送的intent裡面不能指定接收者,即粘性廣播不能指定接收方
        ............
    }

    // We use userId directly here, since the "all" target is maintained
    // as a separate set of sticky broadcasts.
    //當粘性廣播是針對特定userId時,判斷該粘性廣播與系統儲存的是否衝突
    if (userId != UserHandle.USER_ALL) {

        //取出傳送給所有user的粘性廣播,關於mStickyBroadcasts的介紹可參考上一篇部落格
        ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(
                UserHandle.USER_ALL);
        if (stickies != null) {
            ArrayList<Intent> list = stickies.get(intent.getAction());
            if (list != null) {
                int N = list.size();
                int i;
                for (i=0; i<N; i++) {
                    //傳送給特定user的粘性廣播,與傳送給所有user的粘性廣播,action一致時,發生衝突
                    if (intent.filterEquals(list.get(i))) {
                        //丟擲異常
                        .............
                    }
                }
            }
        }

        ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
        if (stickies == null) {
            stickies = new ArrayMap<>();
            //按userId儲存粘性廣播
            //即一個user,可能有多個粘性廣播
            mStickyBroadcasts.put(userId, stickies);
        }

        //按照Action儲存粘性廣播
        //即一個Action,可能對應中多個廣播
        ArrayList<Intent> list = stickies.get(intent.getAction());
        if (list == null) {
            //list為null時,直接加入
            list = new ArrayList<>();
            stickies.put(intent.getAction(), list);
        }
        final int stickiesCount = list.size();
        int i;
        for (i = 0; i < stickiesCount; i++) {
            //新的粘性廣播與之前的重複,則保留新的
            //即當傳送多個相同的粘性廣播時,系統僅會保留最新的
            if (intent.filterEquals(list.get(i))) {
                // This sticky already exists, replace it.
                list.set(i, new Intent(intent));
                break;
            }
        }
        if (i >= stickiesCount) {
            //不重複時,直接加入
            list.add(new Intent(intent));
        }
    }
}
...............

        broadcastIntentLocked方法第二部分主要是處理粘性廣播的,判斷髮送粘性廣播的條件是否滿足,然後就粘性廣播儲存起來,將其儲存到AMS的mStickyBroadcasts變數裡面,上一篇部落格中分析了mStickyBroadcasts是以使用者id作為key儲存的,首先取出當前使用者的所有sticky廣播,然後根據當前廣播的action儲存到action對應的List裡面即可。裡面還有一個細節,就是如果當前intent和list中的某個intent用filterEquals()比較相等,就直接替換掉以前的,否則直接新增到list末尾。

Part III

.............
// Figure out who all will receive this broadcast.弄清楚誰會接收這個廣播
//receivers主要用於儲存匹配當前廣播的靜態註冊的BroadcastReceiver
//若當前廣播是有序廣播時,還會插入動態註冊的BroadcastReceiver
List receivers = null;

//registeredReceivers用於儲存匹配當前廣播的動態註冊的BroadcastReceiver 
//BroadcastFilter中有對應的BroadcastReceiver的引用
List<BroadcastFilter> registeredReceivers = null;

// Need to resolve the intent to interested receivers...
// 若設定了FLAG_RECEIVER_REGISTERED_ONLY,那麼只有此時完成了註冊的BroadcastReceiver才會收到資訊
// 簡單講就是,有FLAG_RECEIVER_REGISTERED_ONLY時,不通知靜態註冊的BroadcastReceiver

// 此處處理未設定該標記的場景
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
    //利用PKMS的queryIntentReceivers介面,查詢滿足條件的靜態BroadcastReceiver
    receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
}

//廣播沒有指定特定接收者時
if (intent.getComponent() == null) {
    //這裡的要求比較特殊,針對所有user,且從shell傳送的廣播
    //即處理除錯用的廣播
    if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) {
        // Query one target user at a time, excluding shell-restricted users
        for (int i = 0; i < users.length; i++) {
            //user不允許除錯時,跳過
            if (mUserController.hasUserRestriction(
                    UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
                continue;
            }

            //得到當前user對應的滿足Intent要求的BroadcastReceiver
            //mReceiverResolver中儲存的都是動態註冊的BroadcastReceiver對應的BroadcastFilter
            List<BroadcastFilter> registeredReceiversForUser =
                    mReceiverResolver.queryIntent(intent,
                            resolvedType, false, users[i]);

            if (registeredReceivers == null) {
                registeredReceivers = registeredReceiversForUser;
            } else if (registeredReceiversForUser != null) {
                registeredReceivers.addAll(registeredReceiversForUser);
            }
        }
    } else {
        //一般沒有指定接收者的廣播,都會走到這裡,這是通常的處理流程
        registeredReceivers = mReceiverResolver.queryIntent(intent,
                resolvedType, false, userId);
    }
}

//檢查廣播中是否有REPLACE_PENDING標籤
//如果設定了這個標籤,那麼新的廣播可以替換掉AMS廣播佇列中,與之匹配的且還未被處理的舊有廣播
//這麼做的目的是:儘可能的減少重複廣播的傳送
final boolean replacePending =
        (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
.....................

//先處理動態註冊的BroadcastReceiver對應的廣播
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;

//處理無序的廣播,即普通廣播
if (!ordered && NR > 0) {
    // If we are not serializing this broadcast, then send the
    // registered receivers separately so they don't wait for the
    // components to be launched.
    //根據Intent的Flag決定BroadcastQueue,獲取前臺或後臺的廣播佇列
    final BroadcastQueue queue = broadcastQueueForIntent(intent);

    //構造廣播對應的BroadcastRecord
    //BroadcastRecord中包含了該廣播的所有接收者
    BroadcastRecord r = new BroadcastRecord(........);
    ................
    //設定了REPLACE_PENDING標籤,同時與舊有廣播匹配時,才會進行替換
    //若能夠替換,replaceParallelBroadcastLocked方法中就會將新的廣播替換到佇列中
    final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);

    if (!replaced) {
        //沒有替換時,才需要將新的廣播加入到BroadcastQueue.mParallelBroadcasts佇列中
        queue.enqueueParallelBroadcastLocked(r);//這裡非常重要,也就是說動態廣播都放在了BroadcastQueue.mParallelBroadcasts中

        //觸發廣播發送流程
        queue.scheduleBroadcastsLocked();
    }
    registeredReceivers = null;
    NR = 0;
}
.....................
        broadcastIntentLocke第三部分的工作主要包括:

        1、查詢與當前廣播匹配的靜態和動態BroadcastReceiver;

        2、若當前待發送的廣播是無序的,那麼為動態註冊的BroadcastReceiver,構造該廣播對應的BroadcastRecord加入到傳送佇列中,並觸發廣播發送流程;最後將動態廣播接收器置為null。

        從這部分程式碼可以看出,對於無序廣播而言,動態註冊的BroadcastReceiver接收廣播的優先順序,高於靜態註冊的BroadcastReceiver。

Part IV

.................
// Merge into one list.將receivers和registerReceiver合併到一個列表(receivers)中。
int ir = 0;
if (receivers != null) {//靜態BroadcastReceiver
    // A special case for PACKAGE_ADDED: do not allow the package
    // being added to see this broadcast.  This prevents them from
    // using this as a back door to get run as soon as they are
    // installed.  Maybe in the future we want to have a special install
    // broadcast or such for apps, but we'd like to deliberately make
    // this decision.
    //處理特殊的Action,例如PACKAGE_ADDED,系統不希望有些應用一安裝就能啟動
    //APP安裝後,PKMS將傳送PACKAGE_ADDED廣播
    //若沒有這個限制,在剛安裝的APP內部靜態註冊監聽該訊息的BroadcastReceiver,新安裝的APP就能直接啟動
    String skipPackages[] = null;
    if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
            || Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
            || Intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
        Uri data = intent.getData();
        if (data != null) {
            String pkgName = data.getSchemeSpecificPart();
            if (pkgName != null) {
                skipPackages = new String[] { pkgName };//將廣播對應的包名新增到skipPackages中
            }
        }
    } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {//移動app之後發出的廣播(APP2SD)
        skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
    }

    if (skipPackages != null && (skipPackages.length > 0)) {
        for (String skipPackage : skipPackages) {
            if (skipPackage != null) {
                int NT = receivers.size();
                for (int it=0; it<NT; it++) {
                    ResolveInfo curt = (ResolveInfo)receivers.get(it);
                    if (curt.activityInfo.packageName.equals(skipPackage)) {
                        //將skipPackages對應的BroadcastReceiver移出receivers;這就是上面說的限制,因此,應用不能接收到自己的PACKAGE_ADDED廣播
                        receivers.remove(it);
                        it--;
                        NT--;
                     }
                }
            }
        }
    }

    int NT = receivers != null ? receivers.size() : 0;
    int it = 0;
    ResolveInfo curt = null;
    BroadcastFilter curr = null;
    //NT對應的是靜態BroadcastReceiver的數量
    //NR對應的是動態BroadcastReceiver的數量
    //若傳送的是無序廣播,此時NR為0
    //若是有序廣播,才會進入下面兩個while迴圈

    //下面兩個while迴圈就是將靜態註冊的BroadcastReceiver和動態註冊的BroadcastReceiver
    //按照優先順序合併到一起(有序廣播才會合併)
    while (it < NT && ir < NR) {
        if (curt == null) {
            curt = (ResolveInfo)receivers.get(it);
        }
        if (curr == null) {
            curr = registeredReceivers.get(ir);
        }

        //動態優先順序大於靜態時,將動態插入到receivers中
        if (curr.getPriority() >= curt.priority) {
            // Insert this broadcast record into the final list.
            receivers.add(it, curr);
            ir++;
            curr = null;
            it++;
            NT++;
        } else {
            // Skip to the next ResolveInfo in the final list.
            it++;
            curt = null;
        }
    }
}

while (ir < NR) {
    if (receivers == null) {
        receivers = new ArrayList();
    }
    //插入剩下的動態BroadcastReceiver
    receivers.add(registeredReceivers.get(ir));
    ir++;
}

if ((receivers != null && receivers.size() > 0)
        || resultTo != null) {
    BroadcastQueue queue = broadcastQueueForIntent(intent);//根據intent的FLAG獲取前臺或後臺廣播佇列
    //構造對應的BroadcastRecord
    BroadcastRecord r = new BroadcastRecord(........);
    ............
    //同樣判斷是否需要替換,這裡是Ordered Queue
    boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
    if (!replaced) {
        //沒替換時,就加入Ordered Queue
        queue.enqueueOrderedBroadcastLocked(r);

        //觸發傳送流程
        queue.scheduleBroadcastsLocked();
    }
} else {
    // There was nobody interested in the broadcast, but we still want to record
    // that it happened.
    if (intent.getComponent() == null && intent.getPackage() == null
            && (intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
        // This was an implicit broadcast... let's record it for posterity.
        //沒有處理的靜態或有序廣播,儲存起來
        //感覺儲存起來也沒什麼用啊
        addBroadcastStatLocked(intent.getAction(), callerPackage, 0, 0, 0);
    }
}
...............

        走到這裡的話,registerReceivers不為null說明當前傳送的是一個order廣播。如果是order廣播,動態BroadcastReceiver和靜態BroadcastReceiver合併到一個佇列中進行處理,也就是說order廣播下,所有的BroadcastReceiver(靜態和動態)處理方式都是一樣的(序列化處理)。另外,對於靜態BroadcastReceiver而言,始終是和order廣播的處理方式是一樣的,也就是說靜態的BroadcastReceiver只有order模式。

        簡單來說,broadcastIntentLocked()的第四部分工作就是有序廣播,把靜態BroadcastReceiver和動態BroadcastReceiver按照優先順序合併到receivers中,構造對於的BroadcastRecord,然後將BroadcastRecord加入到Ordered Queue中,並觸發廣播發送流程。

        至此,整個broadcastIntentLocked函式分析完畢,除去一些條件判斷的細節外,整個工作流程如下圖所示:


        1、處理粘性廣播。

        由於粘性廣播的特性(BroadcastReceiver註冊即可接收),系統必須首先儲存粘性廣播。

        2、處理普通動態廣播。

        普通廣播是併發的,系統優先為動態註冊的BroadcastReceiver傳送廣播。動態廣播對應的BroadcastRecord加入到Parallel Queue中。

        3、處理靜態廣播和有序廣播。

        這一步主要是為靜態註冊BroadcastReceiver傳送廣播,對應的BroadcastRecord加入到Ordered Queue中。

        此外,需要注意的是:如果廣播是有序的,那麼第2步不會為動態註冊的BroadcastReceiver傳送廣播,而是在第三步統一發送。傳送有序廣播時,AMS將按照BroadcastReceiver的優先順序,依次構造BroadcastRecord加入到Ordered Queue中。

BroadcastQueue.scheduleBroadcastsLocked

        從上面的程式碼,我們知道廣播發送方呼叫sendBroadcast後,AMS會構造對應的BroadcastRecord加入到BroadcastQueue中,返回呼叫BroadcastQueue的scheduleBroadcastsLocked()方法。現在我們看下這個方法。

    public void scheduleBroadcastsLocked() {
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
                + mQueueName + "]: current="
                + mBroadcastsScheduled);

        if (mBroadcastsScheduled) {//避免短時間內重複傳送BROADCAST_INTENT_MSG
            return;
        }
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }
    /**
     * Set when we current have a BROADCAST_INTENT_MSG in flight.
     */
    boolean mBroadcastsScheduled = false;
        上面的程式碼將傳送BROADCAST_INTENT_MSG,觸發BroadcastQueue呼叫processNextBroadcast()方法進行處理。

BroadcastQueue.processNextBroadcast

        processNextBroadcast方法較長,分段進行分析。

Part I

final void processNextBroadcast(boolean fromMsg) {
    synchronized(mService) {
        BroadcastRecord r;
        ..............
        //更新CPU的使用情況
        //處理靜態廣播時,可能需要拉起對應程序,因此在這裡先記錄一下CPU情況
        mService.updateCpuStats();

        if (fromMsg) {
            //處理BROADCAST_INTENT_MSG後,將mBroadcastsScheduled置為false
            //scheduleBroadcastsLocked就可以再次被呼叫了
            mBroadcastsScheduled = false;
        }

        // First, deliver any non-serialized broadcasts right away.
        //先處理“併發”傳送的普通廣播(無序廣播),mParallelBroadcasts中儲存動態註冊的廣播接收器
        while (mParallelBroadcasts.size() > 0) {
            //依次取出BroadcastRecord
            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++) {
                //mParallelBroadcasts中的每個成員均為BroadcastFilter型別
                Object target = r.receivers.get(i);
                ............
                //為該BroadcastRecord對應的每個Receiver傳送廣播 
                deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
            }

            //將這裡處理過的資訊加入到歷史記錄中
            addBroadcastToHistoryLocked(r);
        }
        ........................
    }
}
        從上面的程式碼可以看出,processNextBroadcast方法第一部分主要是為動態註冊的BroadcastReceiver傳送普通廣播。傳送普通廣播的方法為deliverToRegisteredReceiverLocked方法。
1.deliverToRegisteredReceiverLocked
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
        BroadcastFilter filter, boolean ordered, int index) {
    boolean skip = false;
    //檢查廣播發送方是否有BroadcastReceiver指定的許可權
    if (filter.requiredPermission != null) {
        int perm = mService.checkComponentPermission(filter.requiredPermission,
                r.callingPid, r.callingUid, -1, true);
        if (perm != PackageManager.PERMISSION_GRANTED) {
            ............
            skip = true;
        } else {
            //進一步檢查許可權的合理性
            final int opCode = AppOpsManager.permissionToOpCode(filter.requiredPermission);
            if (opCode != AppOpsManager.OP_NONE
                    && mService.mAppOpsService.noteOperation(opCode, r.callingUid,
                            r.callerPackage) != AppOpsManager.MODE_ALLOWED) {
                ............
                skip = true;
            }
        }
    }

    //檢查BroadcastReceiver是否有Broadcast要求的許可權
    if (!skip && r.requiredPermissions != null && r.requiredPermissions.length > 0) {
        for (int i = 0; i < r.requiredPermissions.length; i++) {
            String requiredPermission = r.requiredPermissions[i];
            int perm = mService.checkComponentPermission(requiredPermission,
                    filter.receiverList.pid, filter.receiverList.uid, -1, true);
            if (perm != PackageManager.PERMISSION_GRANTED) {
                .................
                //只要一條許可權不滿足,就結束
                skip = true;
                break;
            }

            //進一步檢查許可權的合理性
            int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
            if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
                    && mService.mAppOpsService.noteOperation(appOp,
                            filter.receiverList.uid, filter.packageName)
                    != AppOpsManager.MODE_ALLOWED) {
                ...........
                skip = true;
                break;
            }
        }
    }

    //這段程式碼我看的有些懵逼,傳送方沒要求許可權,還檢查啥?
    if (!skip && (r.requiredPermissions == null || r.requiredPermissions.length == 0)) {
        int perm = mService.checkComponentPermission(null,
                filter.receiverList.pid, filter.receiverList.uid, -1, true);
        if (perm != PackageManager.PERMISSION_GRANTED) {
            ............
            skip = true;
        }
    }

    //還有一些其它的檢查,不再分析程式碼了。。。。。
    //包括是否允許以background的方式傳送、IntentFirewall是否允許廣播中的Intent傳送
    ...............................

    if (skip) {
        //不滿足傳送條件的話,標記一下,結束髮送
        r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
        return;
    }

    // If permissions need a review before any of the app components can run, we drop
    // the broadcast and if the calling app is in the foreground and the broadcast is
    // explicit we launch the review UI passing it a pending intent to send the skipped
    // broadcast.
    //特殊情況,還需要再次檢查許可權,中斷廣播發送
    //再次滿足傳送條件後,會重新進入到後續的傳送流程
    if (Build.PERMISSIONS_REVIEW_REQUIRED) {
        if (!requestStartTargetPermissionsReviewIfNeededLocked(r, filter.packageName,
                filter.owningUserId)) {
            r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
            return;
        }
    }

    //可以傳送了,標記一下
    r.delivery[index] = BroadcastRecord.DELIVERY_DELIVERED;

    // If this is not being sent as an ordered broadcast, then we
    // don't want to touch the fields that keep track of the current
    // state of ordered broadcasts.
    if (ordered) {
        //如果傳送的是有序廣播,則記錄一些狀態資訊等,不涉及廣播發送的過程
        .............
    }

    try {
        ..............
        //若BroadcastReceiver對應的程序處於fullBackup狀態(備份和恢復),則不傳送廣播
        if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
            if (ordered) {
                //有序廣播必須處理完一個,才能處理下一個,因此這裡主動觸發一下
                skipReceiverLocked(r);
            }
        } else {
            //執行傳送工作
            performReceiveLocked(.............);
        }
        if (ordered) {
            r.state = BroadcastRecord.CALL_DONE_RECEIVE;
        }
    } catch (RemoteException e) {
        .............
    }
}
        deliverToRegisteredReceiverLocked方法看起來很長,但大部分內容都是進行許可權檢查等操作,實際的傳送工作交給了performReceiveLocked方法。廣播是一種可以攜帶資料的跨程序、跨APP通訊機制,為了避免安全洩露的問題,Android才在此處使用了大量的篇幅進行許可權檢查的工作。
2.BroadcastQueue.performReceiveLocked
void performReceiveLocked(.........) {
    // Send the intent to the receiver asynchronously using one-way binder calls.
    if (app != null) {
        if (app.thread != null) {
            // If we have an app thread, do the call through that so it is
            // correctly ordered with other one-way calls.
            try {
                //通過Binder通訊,將廣播資訊發往BroadcastReceiver處在的程序
                app.thread.scheduleRegisteredReceiver(.......);
            } catch (RemoteException ex) {
                // Failed to call into the process. It's either dying or wedged. Kill it gently.
                .......
                app.scheduleCrash("can't deliver broadcast");
            }
            throw ex;
        } else {
            // Application has died. Receiver doesn't exist.
            throw new RemoteException("app.thread must not be null");
        }
    } else {
        //直接通過Binder通訊,將訊息發往BroadcastReceiver的IIntentReceiver介面
        receiver.performReceive(intent, resultCode, data, extras, ordered,
                sticky, sendingUser);
    }
}
        對於動態註冊的BroadcastReceiver而言,傳送廣播的流程應該進入到上述程式碼的If分支。程序的ApplicationThread呼叫scheduleRegisteredReceiver函式的流程,我們放在後面單獨分析。這一部分整體的流程如下圖所示:

Part II

        至此,processNextBroadcast函式已經發送完所有的動態普通廣播,我們看看該函式後續的流程:

..........
// Now take care of the next serialized one...

// If we are waiting for a process to come up to handle the next
// broadcast, then do nothing at this point.  Just in case, we
// check that the process we're waiting for still exists.
// 對於有序或靜態廣播而言,需要依次向每個BroadcastReceiver傳送廣播,前一個處理完畢後才能傳送下一個廣播
// 如果BroadcastReceiver對應的程序還未啟動,則需要等待
// mPendingBroadcast就是用於儲存,因為對應程序還未啟動,而處於等待狀態的BroadcastRecord
if (mPendingBroadcast != null) {
    ................
    boolean isDead;
    synchronized (mService.mPidsSelfLocked) {
        //通過AMS得到對應程序的資訊
        //BroadRecord對應多個BroadcastReceiver,即對應多個程序
        //此處curApp儲存當前正在等待的程序
        ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);
        isDead = proc == null || proc.crashing;
    }
    if (!isDead) {
        // It's still alive, so keep waiting
        // 注意到有序和靜態廣播必須依次處理
        // 因此,若前一個BroadcastRecord對應的某個程序啟動較慢,不僅會影響該BroadcastRecord中後續程序接收廣播
        // 還會影響到後續所有BroadcastRecord對應程序接收廣播
        return;
    } else {
        ............
        mPendingBroadcast.state = BroadcastRecord.IDLE;
        mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
        mPendingBroadcast = null;
    }
}

boolean looped = false;

//處理之前傳送BroadcastRecord的狀態
do {
    if (mOrderedBroadcasts.size() == 0) {
        // No more broadcasts pending, so all done!
        mService.scheduleAppGcsLocked();

        //當至少一個BroadcastRecord被處理完畢後,looped才會被置變為true
        if (looped) {
            // If we had finished the last ordered broadcast, then
            // make sure all processes have correct oom and sched
            // adjustments.
            // 因為靜態廣播和有序廣播,可能拉起程序
            // 因此這些廣播處理完畢後,AMS需要釋放掉一些不需要的程序
            mService.updateOomAdjLocked();
        }
        return;
    }

    //每次均處理當前的第一個
    r = mOrderedBroadcasts.get(0);
    boolean forceReceive = false;

    // 這裡用於判斷此廣播是否處理超時
    // 僅在系統啟動完畢後,才進行該判斷,因為PRE_BOOT_COMPLETED廣播可能由於系統升級需要等待較長時間
    int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
    if (mService.mProcessesReady && r.dispatchTime > 0) {
        long now = SystemClock.uptimeMillis();
        if ((numReceivers > 0) &&
                //單個廣播處理的超時時間,定義為2 * 每個接收者處理的最長時間(10s)* 接收者的數量
                (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
            ...............
            //如果超時,則強制結束這條廣播的處理
            broadcastTimeoutLocked(false); // forcibly finish this broadcast
            forceReceive = true;
            r.state = BroadcastRecord.IDLE;
        }
    }

    if (r.state != BroadcastRecord.IDLE) {
        //BroadcastRecord還未處理或處理完畢後,狀態為IDLE態
        ............
        return;
    }

    //如果廣播處理完畢,或中途被取消
    if (r.receivers == null || r.nextReceiver >= numReceivers
            || r.resultAbort || forceReceive) {
        // No more receivers for this broadcast!  Send the final
        // result if requested...
        if (r.resultTo != null) {
            try {
                ..........
                //廣播處理完畢,將該廣播的處理結果傳送給resultTo對應BroadcastReceiver
                performReceiveLocked(r.callerApp, r.resultTo,
                        new Intent(r.intent), r.resultCode,
                        r.resultData, r.resultExtras, false, false, r.userId);
            } catch (RemoteException e) {
                .............
            }
        }
        .................
        cancelBroadcastTimeoutLocked();
        addBroadcastToHistoryLocked(r);

        //作一下記錄
        if (r.intent.getComponent() == null && r.intent.getPackage() == null
                 && (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
            // This was an implicit broadcast... let's record it for posterity.
            mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage,
                    r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime);
        }
        mOrderedBroadcasts.remove(0);
        //一個BroadcastRecord處理完畢後,將r置為null
        r = null;

        //如果一個廣播處理完畢,說明可能拉起過程序,於是looped置為true
        looped = true;
        continue;
    }
//r == null時,可以處理下一個BroadcastRecord
//r != null, 繼續處理當前BroadcastRecord的下一個BroadReceiver
} while (r == null);
....................
        這部分程式碼看起來有點亂,其實主要做了兩個工作:

        1、判斷是否有PendingBroadcast。

        當存在PendingBroadcast,且當前正在等待啟動的程序並沒有死亡,那麼不能處理下一個BroadcastRecord,必須等待PendingBroadcast處理完畢。

         2、處理mOrderedBroadcasts中的BroadcastRecord。

        由於有序廣播和靜態廣播,必須一個接一個的處理。因此每傳送完一個廣播後,均會重新呼叫processNextBroadcast方法。

        在傳送新的BroadcastRecord時,需要先處理舊有BroadcastRecord的狀態。於是,這段程式碼後續部分,主要進行了以下操作:

        若所有BroadcastRecord均處理完畢,利用AMS釋放掉無用程序;

        更新超時BroadcastRecord的狀態,同時越過此BroadcastRecord;

        當一個BroadcastRecord處理完畢後,將結果傳送給指定BroadcastReceiver(指定了接收者,才進行此操作),同時將該BroadcastRecord從mOrderedBroadcasts中移除。

        這一系列動作的最終目的,就是選出下一個處理的BroadcastRecord,然後就可以開始向該BroadcastRecord中下一個BroadcastReceiver傳送廣播了。

        這一部分整體的判斷邏輯大致上如下圖所示:


Part III

..............
// Get the next receiver...
// 開始處理當前BroadcastRecord的下一個BroadcastReceiver
int recIdx = r.nextReceiver++;

// Keep track of when this receiver started, and make sure there
// is a timeout message pending to kill it if need be.
// 記錄單個廣播的起始時間
r.receiverTime = SystemClock.uptimeMillis();
if (recIdx == 0) {
    //記錄整個BroadcastRecord的起始時間
    r.dispatchTime = r.receiverTime;
    r.dispatchClockTime = System.currentTimeMillis();
    ................
}

if (! mPendingBroadcastTimeoutMessage) {
    long timeoutTime = r.receiverTime + mTimeoutPeriod;
    ....................
    //設定廣播處理的超時時間為10s
    setBroadcastTimeoutLocked(timeoutTime);
}

final BroadcastOptions brOptions = r.options;
//取出下一個廣播接收者
final Object nextReceiver = r.receivers.get(recIdx);

if (nextReceiver instanceof BroadcastFilter) {
    // Simple case: this is a registered receiver who gets
    // a direct call.
    //動態註冊的BroadcastReceiver,即處理的是有序廣播
    BroadcastFilter filter = (BroadcastFilter)nextReceiver;
    ............
    //與處理普通廣播一樣,呼叫deliverToRegisteredReceiverLocked
    //將廣播發送給BroadcastReceiver對應程序的ApplicationThread
    deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);

    //從程式碼流程來看,deliverToRegisteredReceiverLocked傳送廣播出現問題時,r.receiver才可能是null
    //程式碼執行到這個位置,加入到Ordered Queue的Broadcast一定是order的
    if (r.receiver == null || !r.ordered) {
        // The receiver has already finished, so schedule to
        // process the next one.
        ...............
        //因此這裡應該是有序廣播發送錯誤,因此重新發送BROADCAST_INTENT_MSG,觸發下一次傳送廣播的流程
        r.state = BroadcastRecord.IDLE;
        scheduleBroadcastsLocked();
    } else {
        //處理特殊的選項
        //向DeviceIdleController傳送訊息,賦予白名單內的應用,
        //在Doze模式的啟用視窗中,額外的可以訪問網路和持鎖的時間
        if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
            scheduleTempWhitelistLocked(filter.owningUid,
                    brOptions.getTemporaryAppWhitelistDuration(), r);
        }
    }

    //對於有序廣播而言,已經通知了一個BroadcastReceiver,需要等待處理結果,因此返回
    return;
}
.......................
        processNextBroadcast的第3部分,主要是處理有序廣播發往動態BroadcastReceiver的場景。

        從程式碼可以看出,有序廣播具體的方法流程與普通廣播一致,均是呼叫deliverToRegisteredReceiverLocked函式。唯一不同的是,有序廣播發往一個BroadcastReceiver後,必須等待處理結果,才能進行下一次傳送過程。

Part IV

...................
// Hard case: need to instantiate the receiver, possibly
// starting its application process to host it.
// 開始處理靜態廣播

ResolveInfo info = (ResolveInfo)nextReceiver;

//得到靜態廣播對應的元件名
ComponentName component = new ComponentName(
        info.activityInfo.applicationInfo.packageName,
        info.activityInfo.name);

boolean skip = false;

//以下與deliverToRegisteredReceiverLocked中類似,進行傳送廣播前的檢查工作

//判斷髮送方和接收方要求的許可權,是否互相滿足
//判斷Intent是否滿足AMS的IntentFirewall要求
...................

boolean isSingleton = false;
try {
    //判斷BroadcastReceiver是否是單例的
    isSingleton = mService.isSingleton(info.activityInfo.processName,
            info.activityInfo.applicationInfo,
            info.activityInfo.name, info.activityInfo.flags);
} catch (SecurityException e) {
    .................
}

//BroadcastReceiver要求SINGLE_USER
//那麼必須申明INTERACT_ACROSS_USERS許可權
if ((info.activityInfo.flags&ActivityInfo.FLAG_SINGLE_USER) != 0) {
    if (ActivityManager.checkUidPermission(
            android.Manifest.permission.INTERACT_ACROSS_USERS,
            info.activityInfo.applicationInfo.uid)
                    != PackageManager.PERMISSION_GRANTED) {
        ..............
        skip = true;
    }
}

if (!skip) {
    r.manifestCount++;
} else {
    r.manifestSkipCount++;
}

if (r.curApp != null && r.curApp.crashing) {
    .........
    skip = true;
}

if (!skip) {
    boolean isAvailable = false;
    try {
        isAvailable = AppGlobals.getPackageManager().isPackageAvailable(
                info.activityInfo.packageName,
                UserHandle.getUserId(info.activityInfo.applicationInfo.uid));
    } catch (Exception e) {
        ..........
    }
    if (!isAvailable) {
        .........
        skip = true;
    }
}

//判斷BroadcastReceiver對應程序是否允許後臺啟動
//不允許也會skip
..............

if (skip) {
    ..................
    r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED;
    r.receiver = null;
    r.curFilter = null;
    r.state = BroadcastRecord.IDLE;
    //跳過該廣播,傳送下一個廣播
    scheduleBroadcastsLocked();
    return;
}

r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;
r.state = BroadcastRecord.APP_RECEIVE;
r.curComponent = component;
r.curReceiver = info.activityInfo;
................
if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
    //與處理有序普通廣播一樣,在此處理特殊的選項
    scheduleTempWhitelistLocked(receiverUid,
            brOptions.getTemporaryAppWhitelistDuration(), r);
}

// Broadcast is being executed, its package can't be stopped.
try {
    //傳送靜態廣播前,修改BroadcastReceiver對應的Package狀態
    AppGlobals.getPackageManager().setPackageStoppedState(
            r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid));
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
    ...............
}

// Is this receiver's application already running?
if (app != null && app.thread != null) {
    try {
        app.addPackage(info.activityInfo.packageName,
                info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
        //BroadcastReceiver對應程序啟動時,呼叫ApplicationThread的scheduleReceiver
        processCurBroadcastLocked(r, app);

        //等待結果,故return
        return;
    } catch (RemoteException e) {
        //這可能是對應程序死亡,可以重新拉起程序傳送
        ..........
    } catch (RuntimeException e) {
        .........
        //傳送失敗,結束本次傳送
        finishReceiverLocked(r, r.resultCode, r.resultData,
        r.resultExtras, r.resultAbort, false);

        //繼續傳送後續的廣播
        scheduleBroadcastsLocked();
        // We need to reset the state if we failed to start the receiver.
        r.state = BroadcastRecord.IDLE;
        return;
    }
}
.............
//啟動程序處理廣播
if ((r.curApp=mService.startProcessLocked(targetProcess,
        info.activityInfo.applicationInfo, true,
        r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
        "broadcast", r.curComponent,
        (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
                == null) {
    //建立程序失敗
    ...............
    //傳送失敗,結束本次傳送
    finishReceiverLocked(r, r.resultCode, r.resultData,
    r.resultExtras, r.resultAbort, false);

    //繼續傳送後續的廣播
    scheduleBroadcastsLocked();
    r.state = BroadcastRecord.IDLE;
    return;
}

//程序啟動成功時,mPendingBroadcast儲存當前的BroadcastRecord,及待發送廣播的下標
//當程序啟動後,將根據這兩個值處理廣播
mPendingBroadcast = r;
mPendingBroadcastRecvIndex = recIdx;
.............
        processNextBroadcast第四部分主要是處理靜態廣播,除了檢查是否滿足傳送條件外,主要進行了以下工作:

        1、若BroadcastReceiver對應的程序已經啟動,那麼將直接呼叫程序對應ApplicationThread的scheduleReceiver傳送廣播;

        2、若BroadcastReceiver對應的程序沒有啟動,那麼AMS將啟動對應的程序。

        當對應的程序啟動,同時完成Android環境的建立後,AMS在attachApplicationLocked函式中重新處理等待發送的廣播,對應程式碼如下:

...............
// Check if a next-broadcast receiver is in this process...
if (!badApp && isPendingBroadcastProcessLocked(pid)) {
    try {
        //傳送因目標程序還未啟動,而處於等待狀態的廣播
        //sendPendingBroadcastsLocked將呼叫BroadcastQueue中的sendPendingBroadcastsLocked函式
        //sendPendingBroadcastsLocked最後仍會呼叫程序對應ApplicationThread的scheduleReceiver函式
        didSomething |= sendPendingBroadcastsLocked(app);
    } catch (Exception e) {
        // If the app died trying to launch the receiver we declare it 'bad'
        Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
        badApp = true;
    }
}
.............

         這一部分整體的流程大致如下圖所示:


應用程序處理廣播

        最後,我們看看應用程序收到廣播處理請求後的流程。

1.動態廣播的處理流程

         在上面的performReceiveLocked方法中,呼叫了app.thread.scheduleRegisteredReceiver方法,最後通過Binder通訊呼叫的是程序對應ApplicationThread的scheduleRegisteredReceiver介面。

ActivityThread.ApplicationThread.scheduleRegisteredReceiver

public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
        int resultCode, String dataStr, Bundle extras, boolean ordered,
        boolean sticky, int sendingUser, int processState) throws RemoteException {
    ..............
    //呼叫的是LoadedApk中ReceiverDispatcher的內部類InnerReceiver的介面
    receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
            sticky, sendingUser);
}

       這裡的receiver的具體型別是LoadedApk.ReceiverDispatcher.InnerReceiver,即定義在LoadedApk類的內部類ReceiverDispatcher裡面的一個內部類InnerReceiver,這裡呼叫它的performReceive方法。

InnerReceiver.performReceive()

    static final class ReceiverDispatcher {

        final static class InnerReceiver extends IIntentReceiver.Stub {
            final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
            final LoadedApk.ReceiverDispatcher mStrongRef;

            InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
                mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
                mStrongRef = strong ? rd : null;
            }

            @Override
            public void performReceive(Intent intent, int resultCode, String data,
                    Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                final LoadedApk.ReceiverDispatcher rd;
                if (intent == null) {
                    ........
                    rd = null;
                } else {
                    rd = mDispatcher.get();
                }
                .......
                if (rd != null) {
                    rd.performReceive(intent, resultCode, data, extras,
                            ordered, sticky, sendingUser);//呼叫ReceiverDispatcher的performReceive方法
                } else {
                    // The activity manager dispatched a broadcast to a registered
                    // receiver in this process, but before it could be delivered the
                    // receiver was unregistered.  Acknowledge the broadcast on its
                    // behalf so that the system's broadcast sequence can continue.
                    //處理特殊情況,在收到廣播前,BroadcastReceiver已經unregister了。
                    IActivityManager mgr = ActivityManagerNative.getDefault();
                    try {
                        if (extras != null) {
                            extras.setAllowFds(false);
                        }
                        mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());//通知AMS結束
                    } catch (RemoteException e) {
                        throw e.rethrowFromSystemServer();
                    }
                }
            }
        }
    這裡只是簡單地呼叫ReceiverDispatcher的performReceive方法來進一步處理,這裡的ReceiverDispatcher是LoadedApk類裡面的一個內部類。

ReceiverDispatcher.performReceive()

        public void performReceive(Intent intent, int resultCode, String data,
                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
            final Args args = new Args(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);//建立Args物件
            ..........
            //mActivityThread是一個Handler物件,若建立BroadcastReceiver時沒有指定Handler物件,則預設時ActivityThread主執行緒對應的Handler
            if (intent == null || !mActivityThread.post(args)) {
                if (mRegistered && ordered) {
                    IActivityManager mgr = ActivityManagerNative.getDefault();
                    ...........
                    args.sendFinished(mgr);
                }
            }
        }
        這裡mActivityThread成員變數的型別是Handler,它是Activity在註冊廣播接收器時,從ActivityThread取得的。這裡ReceiverDispatcher藉助這個Handler,把這個廣播以訊息的形式放到Activity所在的ActivityThread的訊息佇列中去,因此,ReceiverDispatcher不等這個廣播被Activity處理就返回了,這裡也體現了廣播的傳送和處理是非同步進行的

        注意這裡處理訊息的方式是通過Handler.post方法進行的,post方法的引數是Runnable型別的,這個訊息最終會呼叫這個引數的run方法來處理。這裡的Args類是LoadedApk類的內部類ReceiverDispatcher的一個內部類,Args類實現了Runnable介面,因此,可以作為mActivityThread.post方法的引數,代表這個廣播的intent也儲存在這個Args例項中。

Args.run()

        final class Args extends BroadcastReceiver.PendingResult implements Runnable {
            private Intent mCurIntent;
            private final boolean mOrdered;
            private boolean mDispatched;

            public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
                    boolean ordered, boolean sticky, int sendingUser) {
                super(resultCode, resultData, resultExtras,
                        mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
                        sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
                mCurIntent = intent;
                mOrdered = ordered;
            }
            
            public void run() {
                final BroadcastReceiver receiver = mReceiver;
                final boolean ordered = mOrdered;
                
                ...........
                
                final IActivityManager mgr = ActivityManagerNative.getDefault();
                final Intent intent = mCurIntent;
                ..........

                mCurIntent = null;
                mDispatched = true;
                if (receiver == null || intent == null || mForgotten) {
                    if (mRegistered && ordered) {
                        ...........
                        sendFinished(mgr);
                    }
                    return;
                }

                ..........
                try {//這裡處理的是動態廣播的註冊,預設認為BroadcastReceiver已經存在
                    ClassLoader cl =  mReceiver.getClass().getClassLoader();
                    intent.setExtrasClassLoader(cl);
                    intent.prepareToEnterProcess();
                    setExtrasClassLoader(cl);
                    receiver.setPendingResult(this);//設定BroadcastReceiver的PendingResult
                    receiver.onReceive(mContext, intent);//呼叫BroadcastReceiver的onReceive方法
                } catch (Exception e) {
                    ......
                }
                //當呼叫BroadcastReceiver的goAsync方法時,會把mPendingResult設為null;於是不會結束髮送流程,直到呼叫PendingResult的finish方法
                if (receiver.getPendingResult() != null) {
                    finish();//Args繼承PendingResult,此處也是呼叫PendingResult的finish方法。
                }
                ..........
            }
        }

    這裡的mReceiver是ReceiverDispatcher類的成員變數,型別是BroadcastReceiver,就是Activity註冊廣播接收器時建立的BroadcastReceiver例項了,有了這個ReceiverDispatcher例項之後,就可以呼叫它的onReceive方法把這個廣播發給它處理了。我們寫的廣播接收器繼承了BroadcastReceiver,並且重寫onReceive方法,因此這裡就呼叫到我們自己寫的onReceive方法中了。之後呼叫了BroadcastReceiver.PendingResult.finish()方法,來結束處理流程。

BroadcastReceiver.PendingResult.finish()

        /**
         * Finish the broadcast.  The current result will be sent and the
         * next broadcast will proceed.傳送當前結果,下一個廣播將會被處理。
         */
        public final void finish() {
            if (mType == TYPE_COMPONENT) {//對於動態廣播而言,mType為TYPE_REGISTERED或TYPE_UNREGISTERED
                final IActivityManager mgr = ActivityManagerNative.getDefault();
                if (QueuedWork.hasPendingWork()) {
                    QueuedWork.singleThreadExecutor().execute( new Runnable() {
                        @Override public void run() {
                            if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                    "Finishing broadcast after work to component " + mToken);
                            sendFinished(mgr);
                        }
                    });
                } else {
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing broadcast to component " + mToken);
                    sendFinished(mgr);
                }
            } else if (mOrderedHint && mType != TYPE_UNREGISTERED) {//有序廣播才返回結果
                ...........
                final IActivityManager mgr = ActivityManagerNative.getDefault();
                sendFinished(mgr);//Binder通訊,呼叫AMS的finishReceiver方法。
            }
        }
        這裡的mType是在建立Args物件的時候傳進來的,在Args的建構函式中,對於動態註冊的廣播接收器,引數mRegistered為true,mType就是TYPE_REGISTERED,對於非order廣播而言,ordered變數是false,這樣BroadcastReceiver.PendingResult中的mOrderedHint為false,mType是TYPE_REGISTERED;根據finish方