Android Broadcast廣播機制分析

基於Android 6.0的源碼剖析, 分析android廣播的發送與接收流程。java

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

1、概述

廣播(Broadcast)機制用於進程/線程間通訊,廣播分爲廣播發送和廣播接收兩個過程,其中廣播接收者BroadcastReceiver即是Android四大組件之一。android

BroadcastReceiver分爲兩類:git

  • 靜態廣播接收者:經過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方法內

2、註冊廣播

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

2.1 registerReceiver

[ContextImpl.java]app

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]oop

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進程與該進程的通訊。post

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

廣播註冊完, 另外一個操做即是在廣播發送過程.

3、 發送廣播

發送廣播是在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) {
    //根據intent的flag來判斷前臺隊列或者後臺隊列[見小節2.5.3]
    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) {
    //根據intent的flag來判斷前臺隊列或者後臺隊列[見小節2.5.3]
    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;

可見無論哪一種廣播方式,都是經過broadcastQueueForIntent()來根據intent的flag來判斷前臺隊列或者後臺隊列,而後再調用對應廣播隊列的scheduleBroadcastsLocked方法來處理廣播;

4、 處理廣播

在發送廣播過程當中會執行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]
                doNext = r.queue.finishReceiverLocked(r, resultCode,
                    resultData, resultExtras, resultAbort, true);
            }
        }

        if (doNext) {
            //處理下一條廣播
            r.queue.processNextBroadcast(false);
        }
        trimApplications();
    } finally {
        Binder.restoreCallingIdentity(origId);
    }
}

4.10.3 BQ.finishReceiverLocked

[-> BroadcastQueue.java]

public boolean finishReceiverLocked(BroadcastRecord r, int resultCode, String resultData, Bundle resultExtras, boolean resultAbort, boolean waitForServices) {
    final int state = r.state;
    final ActivityInfo receiver = r.curReceiver;
    r.state = BroadcastRecord.IDLE;

    r.receiver = null;
    r.intent.setComponent(null);
    if (r.curApp != null && r.curApp.curReceiver == r) {
        r.curApp.curReceiver = null;
    }
    if (r.curFilter != null) {
        r.curFilter.receiverList.curBroadcast = null;
    }
    r.curFilter = null;
    r.curReceiver = null;
    r.curApp = null;
    mPendingBroadcast = null;

    r.resultCode = resultCode;
    r.resultData = resultData;
    r.resultExtras = resultExtras;
    if (resultAbort && (r.intent.getFlags()&Intent.FLAG_RECEIVER_NO_ABORT) == 0) {
        r.resultAbort = resultAbort;
    } else {
        r.resultAbort = false;
    }

    if (waitForServices && r.curComponent != null && r.queue.mDelayBehindServices
            && r.queue.mOrderedBroadcasts.size() > 0
            && r.queue.mOrderedBroadcasts.get(0) == r) {
        ActivityInfo nextReceiver;
        if (r.nextReceiver < r.receivers.size()) {
            Object obj = r.receivers.get(r.nextReceiver);
            nextReceiver = (obj instanceof ActivityInfo) ? (ActivityInfo)obj : null;
        } else {
            nextReceiver = null;
        }

        if (receiver == null || nextReceiver == null
                || receiver.applicationInfo.uid != nextReceiver.applicationInfo.uid
                || !receiver.processName.equals(nextReceiver.processName)) {
            if (mService.mServices.hasBackgroundServices(r.userId)) {
                r.state = BroadcastRecord.WAITING_SERVICES;
                return false;
            }
        }
    }
    r.curComponent = null;

    return state == BroadcastRecord.APP_RECEIVE
            || state == BroadcastRecord.CALL_DONE_RECEIVE;
}

5、總結

5.1 基礎知識

1.BroadcastReceiver分爲兩類:

  • 靜態廣播接收者:經過AndroidManifest.xml的標籤來申明的BroadcastReceiver;
  • 動態廣播接收者:經過AMS.registerReceiver()方式註冊的BroadcastReceiver, 不須要時記得調用unregisterReceiver();

2.廣播發送方式可分爲三類:

類型 方法 ordered sticky
普通廣播 sendBroadcast false false
有序廣播 sendOrderedBroadcast true false
Sticky廣播 sendStickyBroadcast false true

3.廣播註冊registerReceiver():默認將當前進程的主線程設置爲scheuler. 再向AMS註冊該廣播相應信息, 根據類型選擇加入mParallelBroadcasts或mOrderedBroadcasts隊列.

4.廣播發送processNextBroadcast():根據不一樣狀況調用不一樣的處理過程:

  • 若是是動態廣播接收者,則調用deliverToRegisteredReceiverLocked處理;
  • 若是是靜態廣播接收者,且對應進程已經建立,則調用processCurBroadcastLocked處理;
  • 若是是靜態廣播接收者,且對應進程還沒有建立,則調用startProcessLocked建立進程。

5.2 流程圖

最後,經過一幅圖來總結整個廣播處理過程. 點擊查看大圖

send_broadcast

5.2.1 並行廣播

整個過程涉及過程進程間通訊, 先來講說並行廣播處理過程:

  1. 廣播發送端所在進程: 步驟1~2;
  2. system_server的binder線程: 步驟3~5;
  3. system_server的ActivityManager線程: 步驟6~11;
  4. 廣播接收端所在進程的binder線程: 步驟12~13;
  5. 廣播接收端所在進程的主線程: 步驟14~15,以及23;
  6. system_server的binder線程: 步驟24~25.

5.2.2 串行廣播

能夠看出整個流程中,步驟8~15是並行廣播, 而步驟16~22則是串行廣播.那麼再來講說串行廣播的處理過程.

  1. 廣播發送端所在進程: 步驟1~2;
  2. system_server的binder線程: 步驟3~5;
  3. system_server的ActivityManager線程:步驟6以及16~18;
  4. 廣播接收端所在進程的binder線程: 步驟19;
  5. 廣播接收端所在進程的主線程: 步驟20~22;
  6. system_server的binder線程: 步驟24~25.

再來講說幾個關鍵的時間點:

  • enqueueClockTime: 位於步驟4 scheduleBroadcastsLocked(), 這是在system_server的binder線程.
  • dispatchClockTime: 位於步驟8 deliverToRegisteredReceiverLocked(),這是在system_server的ActivityManager線程.
  • finishTime : 位於步驟11 addBroadcastToHistoryLocked()以後, 這是在並行廣播向全部receivers發送完成後的時間點,而串行廣播則是一個一個發送完成纔會繼續.

5.2.3 粘性廣播

對於粘性廣播,registerReceiver()會有一個返回值,數據類型爲Intent。 只有粘性廣播在註冊過程過程會直接返回Intent,裏面帶有相關參數。 好比常見的使用場景好比Battery廣播的註冊。

5.3 廣播處理機制

  1. 當發送串行廣播(ordered=true)的狀況下:
    • 靜態註冊的廣播接收者(receivers),採用串行處理;
    • 動態註冊的廣播接收者(registeredReceivers),採用串行處理;
  2. 當發送並行廣播(ordered=false)的狀況下:
    • 靜態註冊的廣播接收者(receivers),依然採用串行處理;
    • 動態註冊的廣播接收者(registeredReceivers),採用並行處理;

簡單來講,靜態註冊的receivers始終採用串行方式來處理(processNextBroadcast); 動態註冊的registeredReceivers處理方式是串行仍是並行方式, 取決於廣播的發送方式(processNextBroadcast)。

靜態註冊的廣播每每其所在進程尚未建立,而進程建立相對比較耗費系統資源的操做,因此 讓靜態註冊的廣播串行化,能防止出現瞬間啓動大量進程的噴井效應。

ANR時機:只有串行廣播才須要考慮超時,由於接收者是串行處理的,前一個receiver處理慢,會影響後一個receiver;並行廣播 經過一個循環一次性向全部的receiver分發廣播事件,因此不存在彼此影響的問題,則沒有廣播超時;

  • 串行廣播超時狀況1:某個廣播總處理時間 > 2* receiver總個數 * mTimeoutPeriod, 其中mTimeoutPeriod,前臺隊列默認爲10s,後臺隊列默認爲60s;
  • 串行廣播超時狀況2:某個receiver的執行時間超過mTimeoutPeriod;
相關文章
相關標籤/搜索