1. 程式人生 > >Android Broadcast廣播機制分析

Android Broadcast廣播機制分析

基於Android 6.0的原始碼剖析, 分析android廣播的傳送與接收流程。

framework/base/services/core/java/com/android/server/
  - ActivityManagerService.java
  - BroadcastQueue.java
  - BroadcastFilter.java
  - BroadcastRecord.java
  - ReceiverList.java
  - ProcessRecord.java

framework/base/core/java/android/content/
  - BroadcastReceiver.java
  - IntentFilter.java

framework/base/core/java/android/app/
  - ActivityManagerNative.java (內含AMP)
  - ActivityManager.java
  - ApplicationThreadNative.java (內含ATP)
  - ActivityThread.java (內含ApplicationThread)
  - ContextImpl.java
  - LoadedApk

一、概述

廣播(Broadcast)機制用於程序/執行緒間通訊,廣播分為廣播發送和廣播接收兩個過程,其中廣播接收者BroadcastReceiver便是Android四大元件之一。

BroadcastReceiver分為兩類:

  • 靜態廣播接收者:通過AndroidManifest.xml的標籤來申明的BroadcastReceiver。
  • 動態廣播接收者:通過AMS.registerReceiver()方式註冊的BroadcastReceiver,動態註冊更為靈活,可在不需要時通過unregisterReceiver()取消註冊。

從廣播發送方式可分為三類:

  • 普通廣播:通過Context.sendBroadcast()傳送,可並行處理
  • 有序廣播:通過Context.sendOrderedBroadcast()傳送,序列處理
  • Sticky廣播:通過Context.sendStickyBroadcast()傳送

1.1 BroadcastRecord

廣播在系統中以BroadcastRecord物件來記錄, 該物件有幾個時間相關的成員變數.

final class BroadcastRecord extends Binder {
    final ProcessRecord callerApp; //廣播發送者所在程序
    final String callerPackage; //廣播發送者所在包名
    final List receivers;   // 包括動態註冊的BroadcastFilter和靜態註冊的ResolveInfo

    final String callerPackage; //廣播發送者
    final int callingPid;   // 廣播發送者pid
    final List receivers;   // 廣播接收者
    int nextReceiver;  // 下一個被執行的接收者
    IBinder receiver; // 當前正在處理的接收者
    int anrCount;   //廣播ANR次數

    long enqueueClockTime;  //入佇列時間
    long dispatchTime;      //分發時間
    long dispatchClockTime; //分發時間
    long receiverTime;      //接收時間(首次等於dispatchClockTime)
    long finishTime;        //廣播完成時間

}
  • enqueueClockTime 伴隨著 scheduleBroadcastsLocked
  • dispatchClockTime伴隨著 deliverToRegisteredReceiverLocked
  • finishTime 位於 addBroadcastToHistoryLocked方法內

二、註冊廣播

廣播註冊,對於應用開發來說,往往是在Activity/Service中呼叫registerReceiver()方法,而Activity或Service都間接繼承於Context抽象類,真正幹活是交給ContextImpl類。另外呼叫getOuterContext()可獲取最外層的呼叫者Activity或Service。

2.1 registerReceiver

[ContextImpl.java]

public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
    return registerReceiver(receiver, filter, null, null);
}

public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
        String broadcastPermission, Handler scheduler) {
    return registerReceiverInternal(receiver, getUserId(),
            filter, broadcastPermission, scheduler, getOuterContext());
}

其中broadcastPermission擁有廣播的許可權控制,scheduler用於指定接收到廣播時onRecive執行執行緒,當scheduler=null則預設代表在主執行緒中執行,這也是最常見的用法

2.2 registerReceiverInternal

[ContextImpl.java]

private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
        IntentFilter filter, String broadcastPermission,
        Handler scheduler, Context context) {
    IIntentReceiver rd = null;
    if (receiver != null) {
        if (mPackageInfo != null && context != null) {
            if (scheduler == null) {
                //將主執行緒Handler賦予scheuler
                scheduler = mMainThread.getHandler();
            }
            //獲取IIntentReceiver物件【2.3】
            rd = mPackageInfo.getReceiverDispatcher(
                receiver, context, scheduler,
                mMainThread.getInstrumentation(), true);
        } else {
            if (scheduler == null) {
                scheduler = mMainThread.getHandler();
            }
            rd = new LoadedApk.ReceiverDispatcher(
                  receiver, context, scheduler, null, true).getIIntentReceiver();
        }
    }
    try {
        //呼叫AMP.registerReceiver 【2.4】
        return ActivityManagerNative.getDefault().registerReceiver(
                mMainThread.getApplicationThread(), mBasePackageName,
                rd, filter, broadcastPermission, userId);
    } catch (RemoteException e) {
        return null;
    }
}

ActivityManagerNative.getDefault()返回的是ActivityManagerProxy物件,簡稱AMP.
該方法中引數有mMainThread.getApplicationThread()返回的是ApplicationThread,這是Binder的Bn端,用於system_server程序與該程序的通訊。

2.3 LoadedApk.getReceiverDispatcher

[-> LoadedApk.java]

public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
        Context context, Handler handler,
        Instrumentation instrumentation, boolean registered) {
    synchronized (mReceivers) {
        LoadedApk.ReceiverDispatcher rd = null;
        ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
        //此處registered=true,則進入該分支
        if (registered) {
            map = mReceivers.get(context);
            if (map != null) {
                rd = map.get(r);
            }
        }

        if (rd == null) {
            //當廣播分發者為空,則建立ReceiverDispatcher【2.3.1】
            rd = new ReceiverDispatcher(r, context, handler,
                    instrumentation, registered);
            if (registered) {
                if (map == null) {
                    map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
                    mReceivers.put(context, map);
                }
                map.put(r, rd);
            }
        } else {
            //驗證廣播分發者的context、handler是否一致
            rd.validate(context, handler);
        }
        rd.mForgotten = false;
        //獲取IIntentReceiver物件
        return rd.getIIntentReceiver();
    }
}

不妨令 以BroadcastReceiver(廣播接收者)為key,LoadedApk.ReceiverDispatcher(分發者)為value的ArrayMap 記為A。此處mReceivers是一個以Context為key,以A為value的ArrayMap。對於ReceiverDispatcher(廣播分發者),當不存在時則建立一個。

2.3.1 建立ReceiverDispatcher

ReceiverDispatcher(BroadcastReceiver receiver, Context context,
        Handler activityThread, Instrumentation instrumentation,
        boolean registered) {
    //建立InnerReceiver【2.3.2】
    mIIntentReceiver = new InnerReceiver(this, !registered);
    mReceiver = receiver;
    mContext = context;
    mActivityThread = activityThread;
    mInstrumentation = instrumentation;
    mRegistered = registered;
    mLocation = new IntentReceiverLeaked(null);
    mLocation.fillInStackTrace();
}

此處mActivityThread便是前面傳遞過來的當前主執行緒的Handler.

2.3.2 建立InnerReceiver

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;
    }
    ...
}

ReceiverDispatcher(廣播分發者)有一個內部類InnerReceiver,該類繼承於IIntentReceiver.Stub。顯然,這是一個Binder服務端,廣播分發者通過rd.getIIntentReceiver()可獲取該Binder服務端物件InnerReceiver,用於Binder IPC通訊。

2.4 AMP.registerReceiver

[-> ActivityManagerNative.java]

public Intent registerReceiver(IApplicationThread caller, String packageName,
        IIntentReceiver receiver,
        IntentFilter filter, String perm, int userId) throws RemoteException
{
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IActivityManager.descriptor);
    data.writeStrongBinder(caller != null ? caller.asBinder() : null);
    data.writeString(packageName);
    data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);
    filter.writeToParcel(data, 0);
    data.writeString(perm);
    data.writeInt(userId);

    //Command為REGISTER_RECEIVER_TRANSACTION
    mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);
    reply.readException();
    Intent intent = null;
    int haveIntent = reply.readInt();
    if (haveIntent != 0) {
        intent = Intent.CREATOR.createFromParcel(reply);
    }
    reply.recycle();
    data.recycle();
    return intent;
}

這裡有兩個Binder服務端物件callerreceiver,都代表執行註冊廣播動作所在的程序. AMP通過Binder驅動將這些資訊傳送給system_server程序中的AMS物件,接下來進入AMS.registerReceiver。

2.5 AMS.registerReceiver

[-> ActivityManagerService.java]

public Intent registerReceiver(IApplicationThread caller, String callerPackage,
        IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
    ArrayList<Intent> stickyIntents = null;
    ProcessRecord callerApp = null;
    ...
    synchronized(this) {
        if (caller != null) {
            //從mLruProcesses查詢呼叫者的程序資訊【見2.5.1】
            callerApp = getRecordForAppLocked(caller);
            ...
            callingUid = callerApp.info.uid;
            callingPid = callerApp.pid;
        } else {
            callerPackage = null;
            callingUid = Binder.getCallingUid();
            callingPid = Binder.getCallingPid();
        }

        userId = handleIncomingUser(callingPid, callingUid, userId,
                true, ALLOW_FULL_ONLY, "registerReceiver", callerPackage);

        //獲取IntentFilter中的actions. 這就是平時所加需要監聽的廣播action
        Iterator<String> actions = filter.actionsIterator();
        if (actions == null) {
            ArrayList<String> noAction = new ArrayList<String>(1);
            noAction.add(null);
            actions = noAction.iterator();
        }

        int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
        while (actions.hasNext()) {
            String action = actions.next();
            for (int id : userIds) {
                //從mStickyBroadcasts中檢視使用者的sticky Intent
                ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
                if (stickies != null) {
                    ArrayList<Intent> intents = stickies.get(action);
                    if (intents != null) {
                        if (stickyIntents == null) {
                            stickyIntents = new ArrayList<Intent>();
                        }
                        //將sticky Intent加入到佇列
                        stickyIntents.addAll(intents);
                    }
                }
            }
        }
    }

    ArrayList<Intent> allSticky = null;
    if (stickyIntents != null) {
        final ContentResolver resolver = mContext.getContentResolver();
        for (int i = 0, N = stickyIntents.size(); i < N; i++) {
            Intent intent = stickyIntents.get(i);
            //查詢匹配的sticky廣播 【見2.5.2】
            if (filter.match(resolver, intent, true, TAG) >= 0) {
                if (allSticky == null) {
                    allSticky = new ArrayList<Intent>();
                }
                //匹配成功,則將給intent新增到allSticky佇列
                allSticky.add(intent);
            }
        }
    }

    //當IIntentReceiver為空,則直接返回第一個sticky Intent,
    Intent sticky = allSticky != null ? allSticky.get(0) : null;
    if (receiver == null) {
        return sticky;
    }

    synchronized (this) {
        if (callerApp != null && (callerApp.thread == null
                || callerApp.thread.asBinder() != caller.asBinder())) {
            return null; //呼叫者已經死亡
        }
        ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
        if (rl == null) {
            //對於沒有註冊的廣播,則建立接收者佇列
            rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                    userId, receiver);
            if (rl.app != null) {
                rl.app.receivers.add(rl);
            } else {
                receiver.asBinder().linkToDeath(rl, 0); //註冊死亡通知
                ...
                rl.linkedToDeath = true;
            }
            //新建立的接收者佇列,新增到已註冊廣播佇列。
            mRegisteredReceivers.put(receiver.asBinder(), rl);
        }
        ...
        //建立BroadcastFilter物件,並新增到接收者佇列
        BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                permission, callingUid, userId);
        rl.add(bf);
        //新建立的廣播過濾者,新增到ReceiverResolver佇列
        mReceiverResolver.addFilter(bf);

        //所有匹配該filter的sticky廣播執行入隊操作
        //如果沒有使用sendStickyBroadcast,則allSticky=null。
        if (allSticky != null) {
            ArrayList receivers = new ArrayList();
            receivers.add(bf);

            final int stickyCount = allSticky.size();
            for (int i = 0; i < stickyCount; i++) {
                Intent intent = allSticky.get(i);
                //根據intent返回前臺或後臺廣播佇列【見2.5.3】
                BroadcastQueue queue = broadcastQueueForIntent(intent);
                //建立BroadcastRecord
                BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                        null, -1, -1, null, null, AppOpsManager.OP_NONE, null, receivers,
                        null, 0, null, null, false, true, true, -1);
                //該廣播加入到並行廣播佇列
                queue.enqueueParallelBroadcastLocked(r);
                //排程廣播,傳送BROADCAST_INTENT_MSG訊息,觸發處理下一個廣播。
                queue.scheduleBroadcastsLocked();
            }
        }
        return sticky;
    }
}

其中mRegisteredReceivers記錄著所有已註冊的廣播,以receiver IBinder為key, ReceiverList為value為HashMap。

在BroadcastQueue中有兩個廣播佇列mParallelBroadcasts,mOrderedBroadcasts,資料型別都為ArrayList:

  • mParallelBroadcasts:並行廣播佇列,可以立刻執行,而無需等待另一個廣播執行完成,該佇列只允許動態已註冊的廣播,從而避免發生同時拉起大量程序來執行廣播,前臺的和後臺的廣播分別位於獨立的佇列。
  • mOrderedBroadcasts:有序廣播佇列,同一時間只允許執行一個廣播,該佇列頂部的廣播便是活動廣播,其他廣播必須等待該廣播結束才能執行,也是獨立區別前臺的和後臺的廣播。

2.5.1 AMS.getRecordForAppLocked

final ProcessRecord getRecordForAppLocked(
        IApplicationThread thread) {
    if (thread == null) {
        return null;
    }
    //從mLruProcesses佇列中檢視
    int appIndex = getLRURecordIndexForAppLocked(thread);
    return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
}

mLruProcesses資料型別為ArrayList<ProcessRecord>,而ProcessRecord物件有一個IApplicationThread欄位,根據該欄位查找出滿足條件的ProcessRecord物件。

2.5.2 IntentFilter.match

public final int match(ContentResolver resolver, Intent intent,
        boolean resolve, String logTag) {
    String type = resolve ? intent.resolveType(resolver) : intent.getType();
    return match(intent.getAction(), type, intent.getScheme(),
                 intent.getData(), intent.getCategories(), logTag);
}

public final int match(String action, String type, String scheme,
        Uri data, Set<String> categories, String logTag) {
    //不存在匹配的action
    if (action != null && !matchAction(action)) {
        return NO_MATCH_ACTION;
    }

    //不存在匹配的type或data
    int dataMatch = matchData(type, scheme, data);
    if (dataMatch < 0) {
        return dataMatch;
    }

    //不存在匹配的category
    String categoryMismatch = matchCategories(categories);
    if (categoryMismatch != null) {
        return NO_MATCH_CATEGORY;
    }
    return dataMatch;
}

該方法用於匹配發起的Intent資料是否匹配成功,匹配項共有4項action, type, data, category,任何一項匹配不成功都會失敗。

2.5.3 AMS.broadcastQueueForIntent

BroadcastQueue broadcastQueueForIntent(Intent intent) {
    final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
    return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue;
}

broadcastQueueForIntent(Intent intent)通過判斷intent.getFlags()是否包含FLAG_RECEIVER_FOREGROUND 來決定是前臺或後臺廣播,進而返回相應的廣播佇列mFgBroadcastQueue或者mBgBroadcastQueue。

  • 當Intent的flags包含FLAG_RECEIVER_FOREGROUND,則返回mFgBroadcastQueue;
  • 當Intent的flags不包含FLAG_RECEIVER_FOREGROUND,則返回mBgBroadcastQueue;

2.6 廣播註冊小結

註冊廣播:

  1. 傳遞的引數為廣播接收者BroadcastReceiver和Intent過濾條件IntentFilter;
  2. 建立物件LoadedApk.ReceiverDispatcher.InnerReceiver,該物件繼承於IIntentReceiver.Stub;
  3. 通過AMS把當前程序的ApplicationThread和InnerReceiver物件的代理類,註冊登記到system_server程序;
  4. 當廣播receiver沒有註冊過,則建立廣播接收者佇列ReceiverList,該物件繼承於ArrayList, 並新增到AMS.mRegisteredReceivers(已註冊廣播佇列);
  5. 建立BroadcastFilter,並新增到AMS.mReceiverResolver;
  6. 將BroadcastFilter新增到該廣播接收者的ReceiverList

另外,當註冊的是Sticky廣播:

  • 建立BroadcastRecord,並新增到BroadcastQueue的mParallelBroadcasts(並行廣播佇列),註冊後呼叫AMS來儘快處理該廣播。
  • 根據註冊廣播的Intent是否包含FLAG_RECEIVER_FOREGROUND,則mFgBroadcastQueue

廣播註冊完, 另一個操作便是在廣播發送過程.

三、 傳送廣播

傳送廣播是在Activity或Service中呼叫sendBroadcast()方法,而Activity或Service都間接繼承於Context抽象類,真正幹活是交給ContextImpl類。

3.1 sendBroadcast

[ContextImpl.java]

public void sendBroadcast(Intent intent) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
        intent.prepareToLeaveProcess();
        // 呼叫AMP.broadcastIntent  【見3.2】
        ActivityManagerNative.getDefault().broadcastIntent(
                mMainThread.getApplicationThread(), intent, resolvedType, null,
                Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                getUserId());
    } catch (RemoteException e) {
        ...
    }
}

3.2 AMP.broadcastIntent

[-> ActivityManagerNative.java]

public int broadcastIntent(IApplicationThread caller,
        Intent intent, String resolvedType, IIntentReceiver resultTo,
        int resultCode, String resultData, Bundle map,
        String[] requiredPermissions, int appOp, Bundle options, boolean serialized,
        boolean sticky, int userId) 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);
    data.writeStrongBinder(resultTo != null ? resultTo.asBinder() : null);
    data.writeInt(resultCode);
    data.writeString(resultData);
    data.writeBundle(map);
    data.writeStringArray(requiredPermissions);
    data.writeInt(appOp);
    data.writeBundle(options);
    data.writeInt(serialized ? 1 : 0);
    data.writeInt(sticky ? 1 : 0);
    data.writeInt(userId);

    //Command為BROADCAST_INTENT_TRANSACTION
    mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0);
    reply.readException();
    int res = reply.readInt();
    reply.recycle();
    data.recycle();
    return res;
}

3.3 AMS.broadcastIntent

[-> ActivityManagerService.java]

public final int broadcastIntent(IApplicationThread caller,
        Intent intent, String resolvedType, IIntentReceiver resultTo,
        int resultCode, String resultData, Bundle resultExtras,
        String[] requiredPermissions, int appOp, Bundle options,
        boolean serialized, boolean sticky, int userId) {
    enforceNotIsolatedCaller("broadcastIntent");
    synchronized(this) {
        //驗證廣播intent是否有效
        intent = verifyBroadcastLocked(intent);
        //獲取呼叫者程序記錄物件
        final ProcessRecord callerApp = getRecordForAppLocked(caller);
        final int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        //【見小節3.4】
        int res = broadcastIntentLocked(callerApp,
                callerApp != null ? callerApp.info.packageName : null,
                intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                requiredPermissions, appOp, null, serialized, sticky,
                callingPid, callingUid, userId);
        Binder.restoreCallingIdentity(origId);
        return res;
    }
}

broadcastIntent()方法有兩個布林引數serialized和sticky來共同決定是普通廣播,有序廣播,還是Sticky廣播,引數如下:

型別 serialized sticky
sendBroadcast false false
sendOrderedBroadcast true false
sendStickyBroadcast false true

3.4 AMS.broadcastIntentLocked

private final int broadcastIntentLocked(ProcessRecord callerApp,
        String callerPackage, Intent intent, String resolvedType,
        IIntentReceiver resultTo, int resultCode, String resultData,
        Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle options,
        boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {

    //step1: 設定flag
    //step2: 廣播許可權驗證
    //step3: 處理系統相關廣播
    //step4: 增加sticky廣播
    //step5: 查詢receivers和registeredReceivers
    //step6: 處理並行廣播
    //step7: 合併registeredReceivers到receivers
    //step8: 處理序列廣播

    return ActivityManager.BROADCAST_SUCCESS;
}

broadcastIntentLocked方法比較長,這裡劃分為8個部分來分別說明。

3.4.1 設定廣播flag

intent = new Intent(intent);
//增加該flag,則廣播不會發送給已停止的package
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

//當沒有啟動完成時,不允許啟動新程序
if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
}
userId = handleIncomingUser(callingPid, callingUid, userId,
        true, ALLOW_NON_FULL, "broadcast", callerPackage);

//檢查傳送廣播時使用者狀態
if (userId != UserHandle.USER_ALL && !isUserRunningLocked(userId, false)) {
    if ((callingUid != Process.SYSTEM_UID
            || (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)
            && !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
        return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
    }
}

這個過程最重要的工作是:

  • 新增flag=FLAG_EXCLUDE_STOPPED_PACKAGES,保證已停止app不會收到該廣播;
  • 當系統還沒有啟動完成,則不允許啟動新程序,,即只有動態註冊receiver才能接受廣播
  • 當非USER_ALL廣播且當前使用者並沒有處於Running的情況下,除非是系統升級廣播或者關機廣播,否則直接返回。

BroadcastReceiver還有其他flag,位於Intent.java常量:

FLAG_RECEIVER_REGISTERED_ONLY //只允許已註冊receiver接收廣播
FLAG_RECEIVER_REPLACE_PENDING //新廣播會替代相同廣播
FLAG_RECEIVER_FOREGROUND //只允許前臺receiver接收廣播
FLAG_RECEIVER_NO_ABORT //對於有序廣播,先接收到的receiver無權拋棄廣播
FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT //Boot完成之前,只允許已註冊receiver接收廣播
FLAG_RECEIVER_BOOT_UPGRADE //升級模式下,允許系統準備就緒前可以傳送廣播

3.4.2 廣播許可權驗證

int callingAppId = UserHandle.getAppId(callingUid);
if (callingAppId == Process.SYSTEM_UID || callingAppId == Process.PHONE_UID
    || callingAppId == Process.SHELL_UID || callingAppId == Process.BLUETOOTH_UID
    || callingAppId == Process.NFC_UID || callingUid == 0) {
    //直接通過
} else if (callerApp == null || !callerApp.persistent) {
    try {
        if (AppGlobals.getPackageManager().isProtectedBroadcast(
                intent.getAction())) {
            //不允許傳送給受保護的廣播
            throw new SecurityException(msg);
        } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(intent.getAction())) {
            ...
        }
    } catch (RemoteException e) {
        return ActivityManager.BROADCAST_SUCCESS;
    }
}

主要功能:

  • 對於callingAppId為SYSTEM_UID,PHONE_UID,SHELL_UID,BLUETOOTH_UID,NFC_UID之一或者callingUid == 0時都暢通無阻;
  • 否則當呼叫者程序為空 或者非persistent程序的情況下:
    • 當傳送的是受保護廣播mProtectedBroadcasts(只允許系統使用),則丟擲異常;
    • 當action為ACTION_APPWIDGET_CONFIGURE時,雖然不希望該應用傳送這種廣播,處於相容性考慮,限制該廣播只允許傳送給自己,否則丟擲異常。

3.4.3 處理系統相關廣播

final String action = intent.getAction();
if (action != null) {
    switch (action) {
        case Intent.ACTION_UID_REMOVED: //uid移除
        case Intent.ACTION_PACKAGE_REMOVED: //package移除
        case Intent.ACTION_PACKAGE_ADDED: //增加package
        case Intent.ACTION_PACKAGE_CHANGED: //package改變

        case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE: //外部裝置不可用
        case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE: //外部裝置可用

        case Intent.ACTION_TIMEZONE_CHANGED: //時區改變,通知所有執行中的程序
        case Intent.ACTION_TIME_CHANGED: //時間改變,通知所有執行中的程序

        case Intent.ACTION_CLEAR_DNS_CACHE: //DNS快取清空
        case Proxy.PROXY_CHANGE_ACTION: //網路代理改變
    }
}

這個過主要處於系統相關的10類廣播,這裡不就展開講解了.

3.4.4 增加sticky廣播

if (sticky) {
    if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
            callingPid, callingUid)
            != PackageManager.PERMISSION_GRANTED) {
        throw new SecurityException("");
    }
    if (requiredPermissions != null && requiredPermissions.length > 0) {
        return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
    }

    if (intent.getComponent() != null) {
       //當sticky廣播發送給指定元件,則throw Exception
    }
    if (userId != UserHandle.USER_ALL) {
       //當非USER_ALL廣播跟USER_ALL廣播出現衝突,則throw Exception
    }

    ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
    if (stickies == null) {
        stickies = new ArrayMap<>();
        mStickyBroadcasts.put(userId, stickies);
    }
    ArrayList<Intent> list = stickies.get(intent.getAction());
    if (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))) {
            //替換已存在的sticky intent
            list.set(i, new Intent(intent));
            break;
        }
    }
    //新的intent追加到list
    if (i >= stickiesCount) {
        list.add(new Intent(intent));
    }
}

這個過程主要是將sticky廣播增加到list,並放入mStickyBroadcasts裡面。

3.4.5 查詢receivers和registeredReceivers

List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
//當允許靜態接收者處理該廣播,則通過PKMS根據Intent查詢相應的靜態receivers
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
    receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
}
if (intent.getComponent() == null) {
    if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) {
        ...
    } else {
        // 查詢相應的動態註冊的廣播
        registeredReceivers = mReceiverResolver.queryIntent(intent,
                resolvedType, false, userId);
    }
}
  • receivers:記錄著匹配當前intent的所有靜態註冊廣播接收者;
  • registeredReceivers:記錄著匹配當前的所有動態註冊的廣播接收者。

其他說明:

  • 根據userId來決定廣播是傳送給全部的接收者,還是指定的userId;
  • mReceiverResolver是AMS的成員變數,記錄著已註冊的廣播接收者的resolver.

AMS.collectReceiverComponents

private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,
        int callingUid, int[] users) {
    List<ResolveInfo> receivers = null;
    for (int user : users) {
        //呼叫PKMS.queryIntentReceivers,可獲取AndroidManifest.xml宣告的接收者資訊
        List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
                .queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, user);
        if (receivers == null) {
            receivers = newReceivers;
        } else if (newReceivers != null) {
            ...
            //將所使用者的receiver整合到receivers
        }
     }
    return receivers;
}

3.4.6 處理並行廣播

//用於標識是否需要用新intent替換舊的intent。
final boolean replacePending = (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
//處理並行廣播
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
if (!ordered && NR > 0) {
    final BroadcastQueue queue = broadcastQueueForIntent(intent);
    //建立BroadcastRecord物件
    BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
            callerPackage, callingPid, callingUid, resolvedType, requiredPermissions,
            appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData,
            resultExtras, ordered, sticky, false, userId);

    final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
    if (!replaced) {
        //將BroadcastRecord加入到並行廣播佇列[見下文]
        queue.enqueueParallelBroadcastLocked(r);
        //處理廣播【見小節4.1】
        queue.scheduleBroadcastsLocked();
    }
    //動態註冊的廣播接收者處理完成,則會置空該變數;
    registeredReceivers = null;
    NR = 0;
}

廣播佇列中有一個成員變數mParallelBroadcasts,型別為ArrayList,記錄著所有的並行廣播。

// 並行廣播,加入mParallelBroadcasts佇列
public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
    mParallelBroadcasts.add(r);
    r.enqueueClockTime = System.currentTimeMillis();
}

3.4.7 合併registeredReceivers到receivers

int ir = 0;
if (receivers != null) {
    //防止應用監聽該廣播,在安裝時直接執行。
    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 };
            }
        }
    } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
        skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
    }

    //將skipPackages相關的廣播接收者從receivers列表中移除
    if (skipPackages != null && (skipPackages.length > 0)) {
        ...
    }

    //[3.4.6]有一個處理動態廣播的過程,處理完後再執行將動態註冊的registeredReceivers合併到receivers
    int NT = receivers != null ? receivers.size() : 0;
    int it = 0;
    ResolveInfo curt = null;
    BroadcastFilter curr = null;
    while (it < NT && ir < NR) {
        if (curt == null) {
            curt = (ResolveInfo)receivers.get(it);
        }
        if (curr == null) {
            curr = registeredReceivers.get(ir);
        }
        if (curr.getPriority() >= curt.priority) {
            receivers.add(it, curr);
            ir++;
            curr = null;
            it++;
            NT++;
        } else {
            it++;
            curt = null;
        }
    }
}
while (ir < NR) {
    if (receivers == null) {
        receivers = new ArrayList();
    }
    receivers.add(registeredReceivers.get(ir));
    ir++;
}

動態註冊的registeredReceivers,全部合併都receivers,再統一按序列方式處理。

3.4.8 處理序列廣播

if ((receivers != null && receivers.size() > 0)
        || resultTo != null) {
    BroadcastQueue queue = broadcastQueueForIntent(intent);
    //建立BroadcastRecord
    BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
            callerPackage, callingPid, callingUid, resolvedType,
            requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
            resultData, resultExtras, ordered, sticky, false, userId);

    boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
    if (!replaced) {
        //將BroadcastRecord加入到有序廣播佇列
        queue.enqueueOrderedBroadcastLocked(r);
        //處理廣播【見小節4.1】
        queue.scheduleBroadcastsLocked();
    }
}

廣播佇列中有一個成員變數mOrderedBroadcasts,型別為ArrayList,記錄著所有的有序廣播。

// 序列廣播 加入mOrderedBroadcasts佇列
public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
    mOrderedBroadcasts.add(r);
    r.enqueueClockTime = System.currentTimeMillis();
}

3.5 小結

傳送廣播過程:

  1. 預設不傳送給已停止(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES)的應用包;
  2. 處理各種PACKAGE,TIMEZONE等相關的系統廣播;
  3. 當為粘性廣播,則將sticky廣播增加到list,並放入mStickyBroadcasts裡面;
  4. 當廣播的Intent沒有設定FLAG_RECEIVER_REGISTERED_ONLY,則允許靜態廣播接收者來處理該廣播; 建立BroadcastRecord物件,並將該物件加入到相應的廣播佇列, 然後呼叫BroadcastQueue的scheduleBroadcastsLocked()方法來完成的不同廣播處理:

處理方式:

  1. Sticky廣播: 廣播註冊過程處理AMS.registerReceiver,開始處理粘性廣播,見小節[2.5];
    • 建立BroadcastRecord物件;
    • 並新增到mParallelBroadcasts佇列;
    • 然後執行queue.scheduleBroadcastsLocked;
  2. 並行廣播: 廣播發送過程處理,見小節[3.4.6]
    • 只有動態註冊的mRegisteredReceivers才會並行處理;
    • 會建立BroadcastRecord物件;
    • 並新增到mParallelBroadcasts佇列;
    • 然後執行queue.scheduleBroadcastsLocked;
  3. 序列廣播: 廣播發送廣播處理,見小節[3.4.8]
    • 所有靜態註冊的receivers以及動態註冊mRegisteredReceivers合併到一張表處理;
    • 建立BroadcastRecord物件;
    • 並新增到mOrderedBroadcasts佇列;
    • 然後執行queue.scheduleBroadcastsLocked;

可見不管哪種廣播方式,接下來都會執行scheduleBroadcastsLocked方法來處理廣播;

四、 處理廣播

在傳送廣播過程中會執行scheduleBroadcastsLocked方法來處理相關的廣播

4.1 scheduleBroadcastsLocked

[-> BroadcastQueue.java]

public void scheduleBroadcastsLocked() {
    // 正在處理BROADCAST_INTENT_MSG訊息
    if (mBroadcastsScheduled) {
        return;
    }
    //傳送BROADCAST_INTENT_MSG訊息
    mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
    mBroadcastsScheduled = true;
}

在BroadcastQueue物件建立時,mHandler=new BroadcastHandler(handler.getLooper());那麼此處交由mHandler的handleMessage來處理:

4.1.1 BroadcastHandler

public ActivityManagerService(Context systemContext) {
    //名為"ActivityManager"的執行緒
    mHandlerThread = new ServiceThread(TAG,
            android.os.Process.THREAD_PRIORITY_FOREGROUND, false);
    mHandlerThread.start();
    mHandler = new MainHandler(mHandlerThread.getLooper());
    ...
    //建立BroadcastQueue物件
    mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
            "foreground", BROADCAST_FG_TIMEOUT, false);
    mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
            "background", BROADCAST_BG_TIMEOUT, true);
    ...
}


BroadcastQueue(ActivityManagerService service, Handler handler,
        String name, long timeoutPeriod, boolean allowDelayBehindServices) {
    mService = service;
    //建立BroadcastHandler
    mHandler = new BroadcastHandler(handler.getLooper());
    mQueueName = name;
    mTimeoutPeriod = timeoutPeriod;
    mDelayBehindServices = allowDelayBehindServices;
}

由此可見BroadcastHandler採用的是”ActivityManager”執行緒的Looper

private final class BroadcastHandler extends Handler {

    public void handleMessage(Message msg) {
        switch (msg.what) {
            case BROADCAST_INTENT_MSG: {
                processNextBroadcast(true); //【見小節4.2】
            } break;
            ...
    }
}

4.2 processNextBroadcast

[-> BroadcastQueue.java]

final void processNextBroadcast(boolean fromMsg) {
    synchronized(mService) {
        //part1: 處理並行廣播
        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);
                //分發廣播給已註冊的receiver 【見小節4.3】
                deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
            }
            addBroadcastToHistoryLocked(r);//將廣播新增歷史統計
        }

        //part2: 處理當前有序廣播
        do {
            if (mOrderedBroadcasts.size() == 0) {
                mService.scheduleAppGcsLocked(); //沒有更多的廣播等待處理
                if (looped) {
                    mService.updateOomAdjLocked();
                }
                return;
            }
            r = mOrderedBroadcasts.get(0); //獲取序列廣播的第一個廣播
            boolean forceReceive = false;
            int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
            if (mService.mProcessesReady && r.dispatchTime > 0) {
                long now = SystemClock.uptimeMillis();
                if ((numReceivers > 0) && (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
                    broadcastTimeoutLocked(false); //當廣播處理時間超時,則強制結束這條廣播
                }
            }
            ...
            if (r.receivers == null || r.nextReceiver >= numReceivers
                    || r.resultAbort || forceReceive) {
                if (r.resultTo != null) {
                    //處理廣播訊息訊息,呼叫到onReceive()
                    performReceiveLocked(r.callerApp, r.resultTo,
                        new Intent(r.intent), r.resultCode,
                        r.resultData, r.resultExtras, false, false, r.userId);
                }

                cancelBroadcastTimeoutLocked(); //取消BROADCAST_TIMEOUT_MSG訊息
                addBroadcastToHistoryLocked(r);
                mOrderedBroadcasts.remove(0);
                continue;
            }
        } while (r == null);

        //part3: 獲取下一個receiver
        r.receiverTime = SystemClock.uptimeMillis();
        if (recIdx == 0) {
            r.dispatchTime = r.receiverTime;
            r.dispatchClockTime = System.currentTimeMillis();
        }
        if (!mPendingBroadcastTimeoutMessage) {
            long timeoutTime = r.receiverTime + mTimeoutPeriod;
            setBroadcastTimeoutLocked(timeoutTime); //設定廣播超時延時訊息
        }

        //part4: 處理下條有序廣播
        ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
                info.activityInfo.applicationInfo.uid, false);
        if (app != null && app.thread != null) {
            app.addPackage(info.activityInfo.packageName,
                    info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
            processCurBroadcastLocked(r, app); //[處理序列廣播]
            return;
            ...
        }

        //該receiver所對應的程序尚未啟動,則建立該程序
        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) {
            ...
            return;
        }
    }
}

此處mService為AMS,整個流程還是比較長的,全程持有AMS鎖,所以廣播效率低的情況下,直接會嚴重影響這個手機的效能與流暢度,這裡應該考慮細化同步鎖的粒度。

  • 設定廣播超時延時訊息: setBroadcastTimeoutLocked:
  • 當廣播接收者等待時間過長,則呼叫broadcastTimeoutLocked(false);
  • 當執行完廣播,則呼叫cancelBroadcastTimeoutLocked;

4.2.1 處理並行廣播

BroadcastRecord r;
mService.updateCpuStats(); //更新CPU統計資訊
if (fromMsg)  mBroadcastsScheduled = false;

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);
        //分發廣播給已註冊的receiver 【見小節4.3】
        deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
    }
    addBroadcastToHistoryLocked(r);//將廣播新增歷史統計
}

通過while迴圈, 一次性分發完所有的併發廣播後,則分發完成後則新增到歷史廣播佇列. fromMsg是指processNextBroadcast()是否由BroadcastHandler所呼叫的.

private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
    if (r.callingUid < 0) {
        return;
    }
    r.finishTime = SystemClock.uptimeMillis(); //記錄分發完成時間

    mBroadcastHistory[mHistoryNext] = r;
    mHistoryNext = ringAdvance(mHistoryNext, 1, MAX_BROADCAST_HISTORY);

    mBroadcastSummaryHistory[mSummaryHistoryNext] = r.intent;
    mSummaryHistoryEnqueueTime[mSummaryHistoryNext] = r.enqueueClockTime;
    mSummaryHistoryDispatchTime[mSummaryHistoryNext] = r.dispatchClockTime;
    mSummaryHistoryFinishTime[mSummaryHistoryNext] = System.currentTimeMillis();
    mSummaryHistoryNext = ringAdvance(mSummaryHistoryNext, 1, MAX_BROADCAST_SUMMARY_HISTORY);
}

4.2.2 處理序列廣播

if (mPendingBroadcast != null) {
    boolean isDead;
    synchronized (mService.mPidsSelfLocked) {
        //從mPidsSelfLocked獲取正在處理該廣播程序,判斷該程序是否死亡
        ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);
        isDead = proc == null || proc.crashing;
    }
    if (!isDead) {
        return; //正在處理廣播的程序保持活躍狀態,則繼續等待其執行完成
    } else {
        mPendingBroadcast.state = BroadcastRecord.IDLE;
        mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
        mPendingBroadcast = null;
    }
}

boolean looped = false;
do {
    if (mOrderedBroadcasts.size() == 0) {
        //所有序列廣播處理完成,則排程執行gc
        mService.scheduleAppGcsLocked();
        if (looped) {
            mService.updateOomAdjLocked();
        }
        return;
    }
    r = mOrderedBroadcasts.get(0);
    boolean forceReceive = false;

    //獲取所有該廣播所有的接收者
    int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
    if (mService.mProcessesReady && r.dispatchTime > 0) {
        long now = SystemClock.uptimeMillis();
        if ((numReceivers > 0) &&
                (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
            //當廣播處理時間超時,則強制結束這條廣播
            broadcastTimeoutLocked(false);
            forceReceive = true;
            r.state = BroadcastRecord.IDLE;
        }
    }

    if (r.state != BroadcastRecord.IDLE) {
        return;
    }

    if (r.receivers == null || r.nextReceiver >= numReceivers
            || r.resultAbort || forceReceive) {
        if (r.resultTo != null) {
            //處理廣播訊息訊息,呼叫到onReceive()
            performReceiveLocked(r.callerApp, r.resultTo,
                new Intent(r.intent), r.resultCode,
                r.resultData, r.resultExtras, false, false, r.userId);
            r.resultTo = null;
        }
        //取消BROADCAST_TIMEOUT_MSG訊息
        cancelBroadcastTimeoutLocked();

        addBroadcastToHistoryLocked(r);
        mOrderedBroadcasts.remove(0);
        r = null;
        looped = true;
        continue;
    }
} while (r == null);

mTimeoutPeriod,對於前臺廣播則為10s,對於後臺廣播則為60s。廣播超時為2*mTimeoutPeriod*numReceivers,接收者個數numReceivers越多則廣播超時總時長越大。

4.2.3 獲取下條有序廣播

//獲取下一個receiver的index
int recIdx = r.nextReceiver++;

r.receiverTime = SystemClock.uptimeMillis();
if (recIdx == 0) {
    r.dispatchTime = r.receiverTime;
    r.dispatchClockTime = System.currentTimeMillis();
}
if (!mPendingBroadcastTimeoutMessage) {
    long timeoutTime = r.receiverTime + mTimeoutPeriod;
    //設定廣播超時時間,傳送BROADCAST_TIMEOUT_MSG
    setBroadcastTimeoutLocked(timeoutTime);
}

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

if (nextReceiver instanceof BroadcastFilter) {
    //對於動態註冊的廣播接收者,deliverToRegisteredReceiverLocked處理廣播
    BroadcastFilter filter = (BroadcastFilter)nextReceiver;
    deliverToRegisteredReceiverLocked(r, filter, r.ordered);
    if (r.receiver == null || !r.ordered) {
        r.state = BroadcastRecord.IDLE;
        scheduleBroadcastsLocked();
    } else {
        ...
    }
    return;
}

//對於靜態註冊的廣播接收者
ResolveInfo info = (ResolveInfo)nextReceiver;
ComponentName component = new ComponentName(
        info.activityInfo.applicationInfo.packageName,
        info.activityInfo.name);
...
//執行各種許可權檢測,此處省略,當權限不滿足時skip=true

if (skip) {
    r.receiver = null;
    r.curFilter = null;
    r.state = BroadcastRecord.IDLE;
    scheduleBroadcastsLocked();
    return;
}

r.state = BroadcastRecord.APP_RECEIVE;
String targetProcess = info.activityInfo.processName;
r.curComponent = component;
final int receiverUid = info.activityInfo.applicationInfo.uid;
if (r.callingUid != Process.SYSTEM_UID && isSingleton
        && mService.isValidSingletonCall(r.callingUid, receiverUid)) {
    info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0);
}
r.curReceiver = info.activityInfo;
...

//Broadcast正在執行中,stopped狀態設定成false
AppGlobals.getPackageManager().setPackageStoppedState(
        r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid));

4.2.4 處理下條有序廣播

//該receiver所對應的程序已經執行,則直接處理
ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
        info.activityInfo.applicationInfo.uid, false);
if (app != null && app.thread != null) {
    try {
        app.addPackage(info.activityInfo.packageName,
                info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
        processCurBroadcastLocked(r, app);
        return;
    } catch (RemoteException e) {
    } catch (RuntimeException e) {
        finishReceiverLocked(r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, false);
        scheduleBroadcastsLocked();
        r.state = BroadcastRecord.IDLE; //啟動receiver失敗則重置狀態
        return;
    }
}

//該receiver所對應的程序尚未啟動,則建立該程序
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) {
    //建立失敗,則結束該receiver
    finishReceiverLocked(r, r.resultCode, r.resultData,
            r.resultExtras, r.resultAbort, false);
    scheduleBroadcastsLocked();
    r.state = BroadcastRecord.IDLE;
    return;
}
mPendingBroadcast = r;
mPendingBroadcastRecvIndex = recIdx;
  • 如果是動態廣播接收者,則呼叫deliverToRegisteredReceiverLocked處理;
  • 如果是靜態廣播接收者,且對應程序已經建立,則呼叫processCurBroadcastLocked處理;
  • 如果是靜態廣播接收者,且對應程序尚未建立,則呼叫startProcessLocked建立程序。

接下來,介紹deliverToRegisteredReceiverLocked的處理流程:

4.3 deliverToRegisteredReceiverLocked

[-> BroadcastQueue.java]

private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
        BroadcastFilter filter, boolean ordered) {
    ...
    //檢查傳送者是否有BroadcastFilter所需許可權
    //以及接收者是否有傳送者所需的許可權等等
    //當權限不滿足要求,則skip=true。

    if (!skip) {
        //並行廣播ordered = false,只有序列廣播才進入該分支
        if (ordered) {
            r.receiver = filter.receiverList.receiver.asBinder();
            r.curFilter = filter;
            filter.receiverList.curBroadcast = r;
            r.state = BroadcastRecord.CALL_IN_RECEIVE;
            if (filter.receiverList.app != null) {
                r.curApp = filter.receiverList.app;
                filter.receiverList.app.curReceiver = r;
                mService.updateOomAdjLocked(r.curApp);
            }
        }
        // 處理廣播【見小節4.4】
        performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                new Intent(r.intent), r.resultCode, r.resultData,
                r.resultExtras, r.ordered, r.initialSticky, r.userId);
        if (ordered) {
            r.state = BroadcastRecord.CALL_DONE_RECEIVE;
        }
        ...
    }
}

4.4 performReceiveLocked

[-> BroadcastQueue.java]

private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
        Intent intent, int resultCode, String data, Bundle extras,
        boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
    //通過binder非同步機制,向receiver傳送intent
    if (app != null) {
        if (app.thread != null) {
            //呼叫ApplicationThreadProxy類對應的方法 【4.5】
            app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                    data, extras, ordered, sticky, sendingUser, app.repProcState);
        } else {
            //應用程序死亡,則Recevier並不存在
            throw new RemoteException("app.thread must not be null");
        }
    } else {
        //呼叫者程序為空,則執行該分支
        receiver.performReceive(intent, resultCode, data, extras, ordered,
                sticky, sendingUser);
    }
}

4.5 ATP.scheduleRegisteredReceiver

[-> ApplicationThreadNative.java ::ApplicationThreadProxy]

public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
        int resultCode, String dataStr, Bundle extras, boolean ordered,
        boolean sticky, int sendingUser, int processState) throws RemoteException {
    Parcel data = Parcel.obtain();
    data.writeInterfaceToken(IApplicationThread.descriptor);
    data.writeStrongBinder(receiver.asBinder());
    intent.writeToParcel(data, 0);
    data.writeInt(resultCode);
    data.writeString(dataStr);
    data.writeBundle(extras);
    data.writeInt(ordered ? 1 : 0);
    data.writeInt(sticky ? 1 : 0);
    data.writeInt(sendingUser);
    data.writeInt(processState);

    //command=SCHEDULE_REGISTERED_RECEIVER_TRANSACTION
    mRemote.transact(SCHEDULE_REGISTERED_RECEIVER_TRANSACTION, data, null,
            IBinder.FLAG_ONEWAY);
    data.recycle();
}

ATP位於system_server程序,是Binder Bp端通過Binder驅動向Binder Bn端傳送訊息(oneway呼叫方式), ATP所對應的Bn端位於傳送廣播呼叫端所在程序的ApplicationThread,即進入AT.scheduleRegisteredReceiver, 接下來說明該方法。

4.6 AT.scheduleRegisteredReceiver

[-> ActivityThread.java ::ApplicationThread]

public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
        int resultCode, String dataStr, Bundle extras, boolean ordered,
        boolean sticky, int sendingUser, int processState) throws RemoteException {
    //更新虛擬機器程序狀態
    updateProcessState(processState, false);
    //【見小節4.7】
    receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
            sticky, sendingUser);
}

此處receiver是註冊廣播時建立的,見小節[2.3],可知該receiver=LoadedApk.ReceiverDispatcher.InnerReceiver

4.7 InnerReceiver.performReceive

[-> LoadedApk.java]

public void performReceive(Intent intent, int resultCode, String data,
        Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
    LoadedApk.ReceiverDispatcher rd = mDispatcher.get();
    if (rd != null) {
        //【見小節4.8】
        rd.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser);
    } else {
       ...
    }
}

此處方法LoadedApk()屬於LoadedApk.ReceiverDispatcher.InnerReceiver, 也就是LoadedApk內部類的內部類InnerReceiver.

4.8 ReceiverDispatcher.performReceive

[-> LoadedApk.java]

public void performReceive(Intent intent, int resultCode, String data,
        Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
    Args args = new Args(intent, resultCode, data, extras, ordered,
            sticky, sendingUser);
    //通過handler訊息機制傳送args.
    if (!mActivityThread.post(args)) {
        //訊息成功post到主執行緒,則不會走此處。
        if (mRegistered && ordered) {
            IActivityManager mgr = ActivityManagerNative.getDefault();
            args.sendFinished(mgr);
        }
    }
}

其中Args繼承於BroadcastReceiver.PendingResult,實現了介面Runnable; 其中mActivityThread是當前程序的主執行緒, 是由[小節2.3.1]完成賦值過程.

這裡mActivityThread.post(args) 訊息機制,關於Handler訊息機制,見Android訊息機制1-Handler(Java層),把訊息放入MessageQueue,再呼叫Args的run()方法。

4.9 ReceiverDispatcher.Args.run

[-> LoadedApk.java]

public final class LoadedApk {
  static final class ReceiverDispatcher {
    final class Args extends BroadcastReceiver.PendingResult implements Runnable {
        public void run() {
            final BroadcastReceiver receiver = mReceiver;
            final boolean ordered = mOrdered;

            final IActivityManager mgr = ActivityManagerNative.getDefault();
            final Intent intent = mCurIntent;
            mCurIntent = null;

            if (receiver == null || mForgotten) {
                if (mRegistered && ordered) {
                    sendFinished(mgr);
                }
                return;
            }

            try {
                //獲取mReceiver的類載入器
                ClassLoader cl =  mReceiver.getClass().getClassLoader();
                intent.setExtrasClassLoader(cl);
                setExtrasClassLoader(cl);
                receiver.setPendingResult(this);
                //回撥廣播onReceive方法
                receiver.onReceive(mContext, intent);
            } catch (Exception e) {
                ...
            }

            if (receiver.getPendingResult() != null) {
                finish(); //【見小節4.10】
            }
        }
      }
    }

接下來,便進入主執行緒,最終呼叫BroadcastReceiver具體實現類的onReceive()方法。

4.10 PendingResult.finish

[-> BroadcastReceiver.java ::PendingResult]

public final void finish() {
  if (mType == TYPE_COMPONENT) { //代表是靜態註冊的廣播
      final IActivityManager mgr = ActivityManagerNative.getDefault();
      if (QueuedWork.hasPendingWork()) {
          QueuedWork.singleThreadExecutor().execute( new Runnable() {
              void run() {
                  sendFinished(mgr); //[見小節4.10.1]
              }
          });
      } else {
          sendFinished(mgr); //[見小節4.10.1]
      }
  } else if (mOrderedHint && mType != TYPE_UNREGISTERED) { //動態註冊的序列廣播
      final IActivityManager mgr = ActivityManagerNative.getDefault();
      sendFinished(mgr); //[見小節4.10.1]
  }
}

主要功能:

  • 靜態註冊的廣播接收者:
    • 當QueuedWork工作未完成, 即SharedPreferences寫入磁碟的操作沒有完成, 則等待完成再執行sendFinished方法;
    • 當QueuedWork工作已完成, 則直接呼叫sendFinished方法;
  • 動態註冊的廣播接收者:
    • 當傳送的是序列廣播, 則直接呼叫sendFinished方法.

另外常量引數說明:

  • TYPE_COMPONENT: 靜態註冊
  • TYPE_REGISTERED: 動態註冊
  • TYPE_UNREGISTERED: 取消註冊

4.10.1 sendFinished

[-> BroadcastReceiver.java ::PendingResult]

public void sendFinished(IActivityManager am) {
    synchronized (this) {
        mFinished = true;
        ...
        // mOrderedHint代表傳送是否為序列廣播 [見小節4.10.2]
        if (mOrderedHint) {
            am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
                    mAbortBroadcast, mFlags);
        } else {
            //並行廣播, 但屬於靜態註冊的廣播, 仍然需要告知AMS. [見小節4.10.2]
            am.finishReceiver(mToken, 0, null, null, false, mFlags);
        }
        ...
    }
}

此處AMP.finishReceiver,經過binder呼叫,進入AMS.finishReceiver方法

4.10.2 AMS.finishReceiver

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;

        synchronized(this) {
            BroadcastQueue queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0
                    ? mFgBroadcastQueue : mBgBroadcastQueue;
            r = queue.getMatchingOrderedReceiver(who);
            if (r != null) {
                //[見小節4.10.3]