Broadcast 分析 --- 之二

3,发送广播

对应不同的广播,发送方法如下:

public void sendBroadcast(Intent intent, String receiverPermission)
public void sendOrderedBroadcast(Intent intent, String receiverPermission)
public void sendStickyBroadcast(Intent intent)

ContextImpl的sendBroadcast调用流程图如下,


sendBroadcast方法如下,

public void sendBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess();
            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 new RuntimeException("Failure from system", e);
        }
    }

当应用apk发起一个广播时,最后都会通过跨进程调用到AMS的broadcastIntent方法,只是有些标志(是否是顺序广播)不一样而已。

broadcastIntent方法如下,

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 = 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, null, serialized, sticky,
                    callingPid, callingUid, userId);
            Binder.restoreCallingIdentity(origId);
            return res;
        }
}

broadcastIntentLocked方法又臭又长,其他的就不多说了,看主要的,

private final int broadcastIntentLocked(){
    List receivers = null; // 记录静态广播
    List<BroadcastFilter> registeredReceivers = null; // 记录动态广播
          // 根据intent 获取匹配的静态广播
    receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
          // 根据intent 获取匹配的动态广播
     registeredReceivers = mReceiverResolver.queryIntent(intent,
                           resolvedType, false, userId);


if (!ordered && NR > 0) { 
      final BroadcastQueue queue = broadcastQueueForIntent(intent);
      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) {
                queue.enqueueParallelBroadcastLocked(r);
                queue.scheduleBroadcastsLocked(); // 发送动态广播
            }
            registeredReceivers = null;
            NR = 0;
        }


if ((receivers != null && receivers.size() > 0)|| resultTo != null) {
      BroadcastQueue queue = broadcastQueueForIntent(intent);
      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) {
                queue.enqueueOrderedBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();  // 发送静态广播
            }
        }
}

由于广播分为动态广播和静态广播,所以在该函数中,分别定义了2个list来查询并保存匹配的静态和动态广播,最后分别插入广播队列进行处理。

3.1 查询过程分析

3.1.1静态广播的匹配查询

collectReceiverComponents方法如下,

private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,
            int callingUid, int[] users) {
        List<ResolveInfo> receivers = null;
        try {
            HashSet<ComponentName> singleUserReceivers = null;
            boolean scannedFirstReceivers = false;
            for (int user : users) {
                // Skip users that have Shell restrictions
                if (callingUid == Process.SHELL_UID
                        && getUserManagerLocked().hasUserRestriction(
                                UserManager.DISALLOW_DEBUGGING_FEATURES, user)) {
                    continue;
                }
                List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
                        .queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, user);
                if (user != UserHandle.USER_OWNER && newReceivers != null) {
                   •••
                    for (int i=0; i<newReceivers.size(); i++) {
                        ResolveInfo ri = newReceivers.get(i);
                        if ((ri.activityInfo.flags&ActivityInfo.FLAG_SINGLE_USER) != 0) {
                            ComponentName cn = new ComponentName(
                                    ri.activityInfo.packageName, ri.activityInfo.name);
                            if (singleUserReceivers == null) {
                                singleUserReceivers = new HashSet<ComponentName>();
                            }
                            if (!singleUserReceivers.contains(cn)) {
                                singleUserReceivers.add(cn);
                                receivers.add(ri);
                            }
                        } else {
                            receivers.add(ri);
                        }
                    }
                }
            }
        } catch (RemoteException ex) {
            // pm is in same process, this will never happen.
        }
        return receivers;
    }

AppGlobals.getPackageManager()方法最后会得到PMS,直接看queryIntentReceivers方法,

public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int 
flags, int userId) {
        if (!sUserManager.exists(userId)) return Collections.emptyList();
        ComponentName comp = intent.getComponent();
        if (comp == null) {
            if (intent.getSelector() != null) {
                intent = intent.getSelector();
                comp = intent.getComponent();
            }
        }
        if (comp != null) {
            List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
            ActivityInfo ai = getReceiverInfo(comp, flags, userId);
            if (ai != null) {
                ResolveInfo ri = new ResolveInfo();
                ri.activityInfo = ai;
                list.add(ri);
            }
            return list;
        }

        // reader
        synchronized (mPackages) {
            String pkgName = intent.getPackage();
            if (pkgName == null) {
                return mReceivers.queryIntent(intent, resolvedType, flags, userId);
            }
            final PackageParser.Package pkg = mPackages.get(pkgName);
            if (pkg != null) {
                return mReceivers.queryIntentForPackage(intent, resolvedType, flags, 
                          pkg.receivers, userId);
            }
            return null;
        }
    }

一般广播都是动态广播,而有序广播两种状态都有,有序广播保存receivers 序列中。首先查询符合条件的静态广播,

receivers = collectReceiverComponents(intent,
AppGlobals.getPackageManager().queryIntentReceivers(intent

然后将receivers 和registeredReceivers根据数据的大小(优先级)合并到receivers中,最后插入队列并发起实际的广播调度。

queue.enqueueOrderedBroadcastLocked(r);
queue.scheduleBroadcastsLocked();

结构图如下:


3.1.2动态广播的匹配查询

查询到符合条件的动态广播之后,根据BroadcastFilter创建一个BroadcastRecord节点,插入BroadcastQueue内的并行处理队列,最后发起实际的广播调度。

final BroadcastQueue queue = broadcastQueueForIntent(intent);
BroadcastRecord r = new BroadcastRecord(queue, 
queue.enqueueParallelBroadcastLocked(r);
queue.scheduleBroadcastsLocked();

结构图如下:



3.2 一般广播执行流程

3.2.1流程图

一般广播执行过程流程图如下,


3.2.1 关键代码解析

一般广播里面的所有广播同时全部执行,最后调用onReceive函数,通过finishReceiver反馈结果。在processNextBroadcast函数中,可以看到同时调用,

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);
        . . . . . .
        deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
    }
    . . . . . .
}

3.3 有序广播

3.3.1流程图

有序广播执行流程图如下,


3.3.1 关键代码分析

在processNextBroadcast函数中,首先判断该app是否为空,说明该进程还没有起来,那就先调用processCurBroadcastLocked启动app,最后都会调用

processCurBroadcastLocked执行,调用onReceive处理广播。

因为是有序广播,是一个一个安装顺序执行,在反馈的结果BroadcastReceive中,会根据相关信息调用processNextBroadcast函数接着执行下一个广播。

广播完成之后和AMS还有一个交互,其实有序广播就比一般广播多了一个重复的过程,相当于多条广播逐条执行。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值