广播发送过程

下面说广播发送过程

sendBroadcast()

Context.java

@Override
public void sendBroadcast(Intent intent) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
        intent.prepareToLeaveProcess(this);
        ActivityManagerNative.getDefault().broadcastIntent(
                mMainThread.getApplicationThread(), intent, resolvedType, null,
                Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                getUserId());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}
public final int broadcastIntent(IApplicationThread caller,
        Intent intent, String resolvedType, IIntentReceiver resultTo,
        int resultCode, String resultData, Bundle resultExtras,
        String[] requiredPermissions, int appOp, Bundle bOptions,
        boolean serialized, boolean sticky, int userId) {
    enforceNotIsolatedCaller("broadcastIntent");
    synchronized(this) {
        intent = verifyBroadcastLocked(intent);

        final ProcessRecord callerApp = getRecordForAppLocked(caller);
        final int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        int res = broadcastIntentLocked(callerApp,
                callerApp != null ? callerApp.info.packageName : null,
                intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                requiredPermissions, appOp, bOptions, serialized, sticky,
                callingPid, callingUid, userId);
        Binder.restoreCallingIdentity(origId);
        return res;
    }
}

我们通过传递参数来看,使用到了一下参数:

  • PocessRecord 发送者的进程记录
  • callingPid 发送者的PID
  • callingUid 发送者的UID
  • intent 意图
  • resultExtras Bundle类型的数据
  • sticky boolean是不是粘连广播

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) {

part-1

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的情况下,除非是系统升级广播或者关机广播,否则直接返回。

也就是大量的检查信息

part-1

..............
// Add to the sticky list if requested.
// 处理粘性广播相关的内容
if (sticky) {
    //检查是否有发送权限
    if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
            callingPid, callingUid)
            != PackageManager.PERMISSION_GRANTED) {
        ..................
    }

    //粘性广播不能指定接收权限
    if (requiredPermissions != null && requiredPermissions.length > 0) {
        ..............
        return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
    }

    if (intent.getComponent() != null) {
        //粘性广播不能指定接收方
        ............
    }
    //当粘性广播是针对特定userId时,判断该粘性广播与系统保存的是否冲突
    if (userId != UserHandle.USER_ALL) {

        //取出发送给所有user的粘性广播
        ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(
                UserHandle.USER_ALL);
        if (stickies != null) {
            ArrayList<Intent> list = stickies.get(intent.getAction());
            if (list != null) {
                int N = list.size();
                int i;
                for (i=0; i<N; i++) {
                    //发送给特定user的粘性广播,与发送给所有user的粘性广播,action一致时,发生冲突
                    if (intent.filterEquals(list.get(i))) {
                        //抛出异常
                        .............
                    }
                }
            }
        }

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

        //按照Action保存粘性广播
        //即一个Action,可能对应中多个广播
        ArrayList<Intent> list = stickies.get(intent.getAction());
        if (list == null) {
            //list为null时,直接加入
            list = new ArrayList<>();
            stickies.put(intent.getAction(), list);
        }
        final int stickiesCount = list.size();
        int i;
        for (i = 0; i < stickiesCount; i++) {
            //新的粘性广播与之前的重复,则保留新的
            //即当发送多个相同的粘性广播时,系统仅会保留最新的
            if (intent.filterEquals(list.get(i))) {
                // This sticky already exists, replace it.
                list.set(i, new Intent(intent));
                break;
            }
        }
        if (i >= stickiesCount) {
            //不重复时,直接加入
            list.add(new Intent(intent));
        }
    }
}
...............

系统通过sticky描述intent所描述的广播是不是一个粘连性广播,如果是,它的值就等于true,此时AMS就需要将这个广播进行保存,后面注册的时候要接收这种类型的广播接受者可以获取这个广播。

所以action相同的粘连广播都保存在一个列表中,这些列表最终存在AMS类型的成员变量mStickyBroadcasts所描述的HashMap中,并且以他们的userId为关键字。

AMS会通过intent的Action来描述,因此通过Action得到能够得到粘连广播的list如果不存在则加入粘连广播列表。

part-3

.............
// Figure out who all will receive this broadcast.
//receivers主要用于保存匹配当前广播的静态注册的BroadcastReceiver
//若当前广播是有序广播时,还会插入动态注册的BroadcastReceiver
List receivers = null;

//registeredReceivers用于保存匹配当前广播的动态注册的BroadcastReceiver 
//BroadcastFilter中有对应的BroadcastReceiver的引用
List<BroadcastFilter> registeredReceivers = null;

// Need to resolve the intent to interested receivers...
// 若设置了FLAG_RECEIVER_REGISTERED_ONLY,那么只有此时完成了注册的BroadcastReceiver才会收到信息
// 简单讲就是,有FLAG_RECEIVER_REGISTERED_ONLY时,不通知静态注册的BroadcastReceiver

// 此处处理未设置该标记的场景
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
    //利用PKMS的queryIntentReceivers接口,查询满足条件的静态BroadcastReceiver
    receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
}

//广播没有指定特定接收者时
if (intent.getComponent() == null) {
    //这里的要求比较特殊,针对所有user,且从shell发送的广播
    //即处理调试用的广播
    if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) {
        // Query one target user at a time, excluding shell-restricted users
        for (int i = 0; i < users.length; i++) {
            //user不允许调试时,跳过
            if (mUserController.hasUserRestriction(
                    UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
                continue;
            }

            //得到当前user对应的满足Intent要求的BroadcastReceiver
            //mReceiverResolver中保存的都是动态注册的BroadcastReceiver对应的BroadcastFilter
            List<BroadcastFilter> registeredReceiversForUser =
                    mReceiverResolver.queryIntent(intent,
                            resolvedType, false, users[i]);

            if (registeredReceivers == null) {
                registeredReceivers = registeredReceiversForUser;
            } else if (registeredReceiversForUser != null) {
                registeredReceivers.addAll(registeredReceiversForUser);
            }
        }
    } else {
        //通常的处理流程
        registeredReceivers = mReceiverResolver.queryIntent(intent,
                resolvedType, false, userId);
    }
}

//检查广播中是否有REPLACE_PENDING标签
//如果设置了这个标签,那么新的广播可以替换掉AMS广播队列中,与之匹配的且还未被处理的旧有广播
//这么做的目的是:尽可能的减少重复广播的发送
final boolean replacePending =
        (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
.....................

//先处理动态注册的BroadcastReceiver对应的广播
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;

//处理无序的广播,即普通广播
if (!ordered && NR > 0) {
    // If we are not serializing this broadcast, then send the
    // registered receivers separately so they don't wait for the
    // components to be launched.
    //根据Intent的Flag决定BroadcastQueue
    final BroadcastQueue queue = broadcastQueueForIntent(intent);

    //构造广播对应的BroadcastRecord
    //BroadcastRecord中包含了该广播的所有接收者
    BroadcastRecord r = new BroadcastRecord(........);
    ................
    //设置了REPLACE_PENDING标签,同时与旧有广播匹配时,才会进行替换
    //若能够替换,replaceParallelBroadcastLocked中就会将新的广播替换到队列中
    final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);

    if (!replaced) {
        //没有替换时,才需要将新的广播加入到队列中
        queue.enqueueParallelBroadcastLocked(r);

        //触发广播发送流程
        queue.scheduleBroadcastsLocked();
    }
    registeredReceivers = null;
    NR = 0;
}
.....................
List receivers = null;//静态广播
List<BroadcastFilter> registeredReceivers = null;//动态广播
  • 处理没有设置FLAG_RECEIVER_REGISTERED_ONLY这个标记的场景
  • 判断发送的组件不等于null
  • 根据intent得到广播注册者
  • 先处理动态注册的广播&处理无序广播
    - 根据Flag决定BroadcastQueue
    - 构造BroadcastRecord中包含了这个广播的所有接收者

这里我们可以看出,无序广播&动态广播先发出

小节:

通过第一部分和第二部分我们知道,先是处理粘连广播,将粘连广播保存起来。
然后处理广播匹配的静态和动态BroadcastReceiver,若当前带发送的广播是无序的,那么为动态注册的BroadcastReceiver木构造该广播对应的BraoadcastRecord加入到发送队列中,并出发广播发送流程。

part-4

.................
// Merge into one list.
int ir = 0;
if (receivers != null) {
    //处理特殊的Action,例如PACKAGE_ADDED,系统不希望有些应用一安装就能启动
    //APP安装后,PKMS将发送PACKAGE_ADDED广播
    //若没有这个限制,在刚安装的APP内部静态注册监听该消息的BroadcastReceiver,新安装的APP就能直接启动
    String skipPackages[] = null;
    if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
            || Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
            || Intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
        Uri data = intent.getData();
        if (data != null) {
            String pkgName = data.getSchemeSpecificPart();
            if (pkgName != null) {
                skipPackages = new String[] { pkgName };
            }
        }
    } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
        skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
    }

    if (skipPackages != null && (skipPackages.length > 0)) {
        for (String skipPackage : skipPackages) {
            if (skipPackage != null) {
                int NT = receivers.size();
                for (int it=0; it<NT; it++) {
                    ResolveInfo curt = (ResolveInfo)receivers.get(it);
                    if (curt.activityInfo.packageName.equals(skipPackage)) {
                        //将skipPackages对应的BroadcastReceiver移出receivers
                        receivers.remove(it);
                        it--;
                        NT--;
                     }
                }
            }
        }
    }

    int NT = receivers != null ? receivers.size() : 0;
    int it = 0;
    ResolveInfo curt = null;
    BroadcastFilter curr = null;
    //NT对应的是静态BroadcastReceiver的数量
    //NR对应的是动态BroadcastReceiver的数量
    //若发送的是无序广播,此时NR为0
    //若是有序广播,才会进入下面两个while循环

    //下面两个while循环就是将静态注册的BroadcastReceiver和动态注册的BroadcastReceiver
    //按照优先级合并到一起(有序广播才会合并)
    while (it < NT && ir < NR) {
        if (curt == null) {
            curt = (ResolveInfo)receivers.get(it);
        }
        if (curr == null) {
            curr = registeredReceivers.get(ir);
        }

        //动态优先级大于静态时,将动态插入到receivers中
        if (curr.getPriority() >= curt.priority) {
            // Insert this broadcast record into the final list.
            receivers.add(it, curr);
            ir++;
            curr = null;
            it++;
            NT++;
        } else {
            // Skip to the next ResolveInfo in the final list.
            it++;
            curt = null;
        }
    }
}

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

if ((receivers != null && receivers.size() > 0)
        || resultTo != null) {
    BroadcastQueue queue = broadcastQueueForIntent(intent);
    //构造对应的BroadcastRecord
    BroadcastRecord r = new BroadcastRecord(........);
    ............
    //同样判断是否需要替换,这里是Ordered Queue
    boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r);
    if (!replaced) {
        //没替换时,就加入Ordered Queue
        queue.enqueueOrderedBroadcastLocked(r);

        //触发发送流程
        queue.scheduleBroadcastsLocked();
    }
} else {
    // There was nobody interested in the broadcast, but we still want to record
    // that it happened.
    if (intent.getComponent() == null && intent.getPackage() == null
            && (intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
        // This was an implicit broadcast... let's record it for posterity.
        //没有处理的静态或有序广播,保存起来
        //感觉保存起来也没什么用啊
        addBroadcastStatLocked(intent.getAction(), callerPackage, 0, 0, 0);
    }
}
...............

上面意思是由于NR,NR是动态广播,动态广播无序的已经发送完成NR=0,如果是有序广播NR!=0,如果有静态广播&有有序动态广播,则将这两种广播进行合并,合并的结果都存入receivers列表中。

然后对receivers列表中所有广播都构造一个BroadcastRecord,然后触发发送流程。

从上面这些发送过程看,我们先是保存粘连广播,接着处理无序动态广播,接着处理有序动态广播和静态广播。

小节

1、处理粘性广播。
由于粘性广播的特性(BroadcastReceiver注册即可接收),系统必须首先保存粘性广播。

2、处理普通动态广播。
普通广播是并发的,系统优先为动态注册的BroadcastReceiver发送广播。
动态广播对应的BroadcastRecord加入到Parallel Queue中。

3、处理静态广播和有序广播。
这一步主要是为静态注册的BroadcastReceiver发送广播,对应的BroadcastRecord加入到Ordered Queue中。

此外,需要注意的是:
如果广播是有序的,那么第2步不会为动态注册的BroadcastReceiver发送广播,而是在第3步统一发送。
发送有序广播时,AMS将按照BroadcastReceiver的优先级,依次构造BroadcastRecord加入到Ordered Queue中。

BroadcastQueue.scheduleBroadcastsLocked()

public void scheduleBroadcastsLocked() {
    if (mBroadcastsScheduled) {
        return;
    }
    mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
    mBroadcastsScheduled = true;
}

其中注意mHandler是MainHandler即主线程哈

public void scheduleBroadcastsLocked() {
    ...........
    //避免短时间内重复发送BROADCAST_INTENT_MSG
    if (mBroadcastsScheduled) {
        return;
    }
    mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
    mBroadcastsScheduled = true;
}

这里通过一个变量进行表达,如果这个变量是true,则不进行发送这个广播了,那么什么时候是false呢,就在下面有展示。

最后调用到了processNextBroadcast()这个方法

BroadcastQueue.processNextBroadcast()

这个方法还是很长,我们就分部分解析

part-1

final void processNextBroadcast(boolean fromMsg) {
    synchronized(mService) {
        BroadcastRecord r;
        ..............
        //更新CPU的使用情况
        //处理静态广播时,可能需要拉起对应进程,因此在这里先记录一下CPU情况
        mService.updateCpuStats();

        if (fromMsg) {
            //处理BROADCAST_INTENT_MSG后,将mBroadcastsScheduled置为false
            //scheduleBroadcastsLocked就可以再次被调用了
            mBroadcastsScheduled = false;
        }

        // First, deliver any non-serialized broadcasts right away.
        //先处理“并发”发送的普通广播
        while (mParallelBroadcasts.size() > 0) {
            //依次取出BroadcastRecord
            r = mParallelBroadcasts.remove(0);

            //记录发送的时间
            r.dispatchTime = SystemClock.uptimeMillis();
            r.dispatchClockTime = System.currentTimeMillis();

            final int N = r.receivers.size();
            ................
            for (int i=0; i<N; i++) {
                //mParallelBroadcasts中的每个成员均为BroadcastFilter类型
                Object target = r.receivers.get(i);
                ............
                //为该BroadcastRecord对应的每个Receiver发送广播 
                deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
            }

            //将这里处理过的信息加入到历史记录中
            addBroadcastToHistoryLocked(r);
        }
        ........................
    }
}

在这里注意之前出现的两个变量,一个变量是mParallelBroadcasts(处理无序广播,并行),一个变量是mOrderedBroadcasts(处理有序广播)

  • 我们看见如果处理的是处理BROADCAST_INTENT_MSG后,将mBroadcastsScheduled置为false,目的是为了短时间内重复发送这个广播。
  • 然后通过一个循环进行发送广播
    • 从无序广播队列中获取发送的广播记录
    • 记录发送时间
    • 然后为这个BroadcastRecord对应的每一个Receiver发送广播
    • 将处理过后的广播记录加到历史列表中

我们稍后分析这个发送的方法是怎么一回事

part-2

if (mPendingBroadcast != null) {
    boolean isDead;
    synchronized (mService.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;
    }
}

mPendingBroadcast表示处理静态&要启动进程的广播

当这个进程没有启动,则返回等待,这里提到等到是因为此函数外边也是一个循环。直到进程启动这个广播才能发送出去。

part-3

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); // forcibly finish this broadcast
            forceReceive = true;
            r.state = BroadcastRecord.IDLE;//超时时候设置状态为IDLE
        }
    }

处理超时,超时时间注意里面乘以广播接收者的数量

    //如果当前广播没有完成,返回继续等待
    if (r.state != BroadcastRecord.IDLE) {
        return;
    }
    //如果当前广播没有接收者||是最后一个接收者
    if (r.receivers == null || r.nextReceiver >= numReceivers
            || r.resultAbort || forceReceive) {
        //发送最后带有结果的广播
        if (r.resultTo != null) {
            try {
                performReceiveLocked(r.callerApp, r.resultTo,
                    new Intent(r.intent), r.resultCode,
                    r.resultData, r.resultExtras, false, false, r.userId);
                r.resultTo = null;
            } catch (RemoteException e) {
                r.resultTo = null;
            }
        }

        cancelBroadcastTimeoutLocked();

        addBroadcastToHistoryLocked(r);
        if (r.intent.getComponent() == null && r.intent.getPackage() == null
                && (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
            mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage,
                    r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime);
        }
        mOrderedBroadcasts.remove(0);
        r = null;
        looped = true;
        continue;
    }

处理最后一个广播接收者

} while (r == null);

这些处理如果都没发生,则正常的得到第一个有序广播的记录

part-4

int recIdx = r.nextReceiver++;//开始处理当前BroadcastRecord的下一个BroadcastReceiver下标
r.receiverTime = SystemClock.uptimeMillis();//记录单个广播的起始时间
if (recIdx == 0) {
    r.dispatchTime = r.receiverTime;//记录整个BroadcastRecord的起始时间
    r.dispatchClockTime = System.currentTimeMillis();
}
if (! mPendingBroadcastTimeoutMessage) {
    long timeoutTime = r.receiverTime + mTimeoutPeriod;
    setBroadcastTimeoutLocked(timeoutTime);//设置广播处理的超时时间为10s
}
final BroadcastOptions brOptions = r.options;
final Object nextReceiver = r.receivers.get(recIdx);

得到下一个广播Receiver

if (nextReceiver instanceof BroadcastFilter) {
    //动态注册的BroadcastReceiver,即处理的是有序广播
    BroadcastFilter filter = (BroadcastFilter)nextReceiver;
    deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
    //当发送出现问题的时候为null
    if (r.receiver == null || !r.ordered) {
        //处理下一次广播,当前广播算是挂掉了
        r.state = BroadcastRecord.IDLE;
        scheduleBroadcastsLocked();
    } else {
        if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
            scheduleTempWhitelistLocked(filter.owningUid,
                    brOptions.getTemporaryAppWhitelistDuration(), r);
        }
    }
    return;
}

处理的是动态BroadcastFilter,调用deliverToRegisteredReceiverLocked发送给对应receiver

由于已经处理了动态广播所以返回处理下一个广播

part-5

...................
// 开始处理静态广播
ResolveInfo info = (ResolveInfo)nextReceiver;
//得到静态广播对应的组件名
ComponentName component = new ComponentName(
        info.activityInfo.applicationInfo.packageName,
        info.activityInfo.name);

boolean skip = false;

//以下与deliverToRegisteredReceiverLocked中类似,进行发送广播前的检查工作

//判断发送方和接收方要求的权限,是否互相满足
//判断Intent是否满足AMS的IntentFirewall要求
//判断BroadcastReceiver是否是单例的
...................

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

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

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

if (!skip) {
    boolean isAvailable = false;
    try {
        isAvailable = AppGlobals.getPackageManager().isPackageAvailable(
                info.activityInfo.packageName,
                UserHandle.getUserId(info.activityInfo.applicationInfo.uid));
    } catch (Exception e) {
        ..........
    }
    if (!isAvailable) {
        .........
        skip = true;
    }
}
if (skip) {
    ..................
    r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED;
    r.receiver = null;
    r.curFilter = null;
    r.state = BroadcastRecord.IDLE;
    //跳过该广播,发送下一个广播
    scheduleBroadcastsLocked();
    return;
}
```java
判断BroadcastReceiver对应进程是否允许后台启动
不允许也会skip
..............
r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;
r.state = BroadcastRecord.APP_RECEIVE;
r.curComponent = component;
r.curReceiver = info.activityInfo;
................
if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
    //与处理有序普通广播一样,在此处理特殊的选项
    scheduleTempWhitelistLocked(receiverUid,
            brOptions.getTemporaryAppWhitelistDuration(), r);
}

// Broadcast is being executed, its package can't be stopped.
try {
    //发送静态广播前,修改BroadcastReceiver对应的Package状态
    AppGlobals.getPackageManager().setPackageStoppedState(
            r.curComponent.getPackageName(), false, UserHandle.getUserId(r.callingUid));
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
    ...............
}

如果静态广播对应的receiver的进存在执行下面逻辑

if (app != null && app.thread != null) {
    try {
        app.addPackage(info.activityInfo.packageName,
                info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
        //BroadcastReceiver对应进程启动时,调用ApplicationThread的scheduleReceiver
        processCurBroadcastLocked(r, app);

        //等待结果,故return
        return;
    } catch (RemoteException e) {
        //这可能是对应进程死亡,可以重新拉起进程发送
        ..........
    } catch (RuntimeException e) {
        .........
        //发送失败,结束本次发送
        finishReceiverLocked(r, r.resultCode, r.resultData,
        r.resultExtras, r.resultAbort, false);

        //继续发送后续的广播
        scheduleBroadcastsLocked();
        // We need to reset the state if we failed to start the receiver.
        r.state = BroadcastRecord.IDLE;
        return;
    }
}

进程不存在则处理下面逻辑

.............
//启动进程处理广播
if ((r.curApp=mService.startProcessLocked(targetProcess,
        info.activityInfo.applicationInfo, true,
        r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
        "broadcast", r.curComponent,
        (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
                == null) {
    //创建进程失败
    ...............
    //发送失败,结束本次发送
    finishReceiverLocked(r, r.resultCode, r.resultData,
    r.resultExtras, r.resultAbort, false);

    //继续发送后续的广播
    scheduleBroadcastsLocked();
    r.state = BroadcastRecord.IDLE;
    return;
}

//进程启动成功时,mPendingBroadcast保存当前的BroadcastRecord,及待发送广播的下标
//当进程启动后,将根据这两个值处理广播
mPendingBroadcast = r;
mPendingBroadcastRecvIndex = recIdx;
.............

除了检查是否满足发送条件外,主要进行了以下工作:

  1. 若BroadcastReceiver对应的进程已经启动,那么将直接调用进程对应ApplicationThread的scheduleReceiver发送广播;
  2. 若BroadcastReceiver对应的进程没有启动,那么AMS将启动对应的进程。

小节:

  1. 处理全部无序广播,遍历动态注册的接收者并通知
  2. 获取第一条有序广播
  3. 获取第一个接收者,设置超时
  4. 如果是动态注册的接收者,通知并return
  5. 如果是静态注册的接收者,校验权限
  6. 通知接收者

ApplicationThread.scheduleRegisteredReceiver()

我们上面提到使用scheduleBroadcastsLocked发送广播,下面看看这个方法的实现

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);
    receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
            sticky, sendingUser);
}

调用recriver的performReceive()

InnerReceiver.java

@Override
public void performReceive(Intent intent, int resultCode, String data,
        Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
    final LoadedApk.ReceiverDispatcher rd;
    if (intent == null) {
        rd = null;
    } else {
        rd = mDispatcher.get();
    }
    if (rd != null) {
        //调用ReceiverDispatcher的performReceive函数
        rd.performReceive(intent, resultCode, data, extras,
                ordered, sticky, sendingUser);
    } else {
        IActivityManager mgr = ActivityManagerNative.getDefault();
        try {
            if (extras != null) {
                extras.setAllowFds(false);
            }
            mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
}
public void performReceive(Intent intent, int resultCode, String data,
        Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
    //构造一个Args对象(runnable对象)
    final Args args = new Args(intent, resultCode, data, extras, ordered,sticky, sendingUser);
    if (intent == null || !mActivityThread.post(args)) {
        if (mRegistered && ordered) {
            IActivityManager mgr = ActivityManagerNative.getDefault();
            args.sendFinished(mgr);
        }
    }
}

其中Args继承于BroadcastReceiver.PendingResult,实现了接口Runnable; 其中mActivityThread是当前进程的主线程这里mActivityThread.post(args) 消息机制.
把消息放入MessageQueue,再调用Args的run()方法。

对应代码:

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();
            }
        }
      }
    }

PendingResult.finish()

public final void finish() {
    //对于动态广播而言,type为TYPE_REGISTERED或TYPE_UNREGISTERED
    if (mType == TYPE_COMPONENT) {
        ................
    //有序广播才返回结果
    } else if (mOrderedHint && mType != TYPE_UNREGISTERED){
        ................
        final IActivityManager mgr = ActivityManagerNative.getDefault();
        //Binder通信,调用AMS的finishReceiver函数
        sendFinished(mgr);
    }
}

此图是引用gityuan的

send_broadcast.jpg
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,864评论 6 494
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,175评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,401评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,170评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,276评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,364评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,401评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,179评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,604评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,902评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,070评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,751评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,380评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,077评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,312评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,924评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,957评论 2 351

推荐阅读更多精彩内容

  • 简介 广播作为Android系统四大组件之一,起得作用是相当大,安卓系统进程之间通信是相当频繁,而且解耦工作是重中...
    我叫王菜鸟阅读 6,227评论 0 2
  • 主目录见:Android高级进阶知识(这是总目录索引)  上一篇文章注册广播接收者的源码分析我们已经讲了注册的过程...
    ZJ_Rocky阅读 811评论 0 2
  • 前言 本来想写一下广播的,发现查阅后有整理的不错的,只好转载图个简便,日后好复习转载:http://www.cnb...
    提升即效率阅读 1,386评论 0 10
  • 诸多无奈,最近在改一个项目的bug的时候,脑子老是一片空白,可能是最近脑子不够用,总之,好多东西忘了,阅读一些别人...
    狗子王1948阅读 7,709评论 6 53
  • 广播接收器 是Android的四大组件之一,可见广播在Android中的重要性; 1. 什么是广播? 广播(Bro...
    Lost_Robot阅读 1,941评论 2 10