Android广播处理流程

目录

一.注册广播

二.注销流程:

三.广播的处理流程:

四.总结:


一.注册广播

时序图:

注册过程主要是创建2个存储Receiver的对象:

  1. ReceiverList 记录接收器的所有信息
  2. BroadcastFilter Receiver的选择条件,主要就是权限和Action

并将这2个对象进行存储

主要源码如下:

/framework/base/services/core/java/com/android/server/am/ActivityManagerService.java

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 {
        try {
            receiver.asBinder().linkToDeath(rl, 0);
        } catch (RemoteException e) {
            return sticky;
        }
        rl.linkedToDeath = true;
    }
    mRegisteredReceivers.put(receiver.asBinder(), rl);
} else if (rl.uid != callingUid) {
    throw new IllegalArgumentException(
            "Receiver requested to register for uid " + callingUid
            + " was previously registered for uid " + rl.uid
            + " callerPackage is " + callerPackage);
} else if (rl.pid != callingPid) {
    throw new IllegalArgumentException(
            "Receiver requested to register for pid " + callingPid
            + " was previously registered for pid " + rl.pid
            + " callerPackage is " + callerPackage);
} else if (rl.userId != userId) {
    throw new IllegalArgumentException(
            "Receiver requested to register for user " + userId
            + " was previously registered for user " + rl.userId
            + " callerPackage is " + callerPackage);
}
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
        permission, callingUid, userId, instantApp, visibleToInstantApps);
rl.add(bf);
if (!bf.debugCheck()) {
    Slog.w(TAG, "==> For Dynamic broadcast");
}
mReceiverResolver.addFilter(bf);

二.注销流程:

注销流程就是注册的逆过程,将创建的ReceiverList和BroadcastFilter移除并销毁。

主要源码如下:

/framework/base/services/core/java/com/android/server/am/ActivityManagerService.java

ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
if (rl != null) {
final BroadcastRecord r = rl.curBroadcast;
if (r != null && r == r.queue.getMatchingOrderedReceiver(r)) {
    final boolean doNext = r.queue.finishReceiverLocked(
            r, r.resultCode, r.resultData, r.resultExtras,
            r.resultAbort, false);
    if (doNext) {
        doTrim = true;
        r.queue.processNextBroadcast(false);
    }
}

if (rl.app != null) {
    rl.app.receivers.remove(rl);
}
removeReceiverLocked(rl);
if (rl.linkedToDeath) {
    rl.linkedToDeath = false;
    rl.receiver.asBinder().unlinkToDeath(rl, 0);
}
}

三.广播的处理流程:

在ActivityManagerService主要做了以下工作:

  1. 根据Action获取对应的static Receiver和Dynamic Receiver
  2. 根据Action获取对应处理Static Receiver和Dynamic Receiver的BroadcastQueue
  3. 针对static Receiver和Dynamic Receiver集合分别创建BroadcastRecord并交给对应的BroadcastQueue处理

对应的源码:

/framework/base/services/core/java/com/android/server/am/ActivityManagerService.java
的broadcastIntentLocked方法

//获取Static Receiver集合
receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);

//获取Dynamic Receiver集合
registeredReceivers = mReceiverResolver.queryIntent(intent,
                        resolvedType, false /*defaultOnly*/, userId);

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.
    if (isCallerSystem) {
        checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
                isProtectedBroadcast, registeredReceivers);
    }
    //根据Intent的获取BroadcastQueue用来给Dynamic  Receiver分发
    final BroadcastQueue queue;
    queue = broadcastQueueForIntent(intent);
    BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
            callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
            requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
            resultCode, resultData, resultExtras, ordered, sticky, false, userId);

    final boolean replaced = replacePending
            && (queue.replaceParallelBroadcastLocked(r) != null);
    // Note: We assume resultTo is null for non-ordered broadcasts.
    if (!replaced) {
        queue.enqueueParallelBroadcastLocked(r);
        queue.scheduleBroadcastsLocked();
    }
    registeredReceivers = null;
    NR = 0;
}

Static Receiver的分发机制与Dynamic Receiver基本相同


接下来就到BroadQueue中执行了,在学习BroadQueue执行流程之前需要了解2个集合的作用:

  1. mParallelBroadcasts 并行集合,调用enqueueParallelBroadcastLocked方法将Receiver放到并行队列中执行,通常是Dynamic Receiver在并行队列中执行。
  2. mOrderedBroadcasts 串行集合,调用enqueueOrderedBroadcastLocked方法将Receiver放到串行队列中执行,通常是Static Receiver在串行队列中执行,因此Static Receiver必须等待上一个Receiver执行完毕,下一个Receiver才会开始执行。存在排队现象导致程序执行较慢,因此建议Receiver都使用Dynamic Receiver。

在BroadcastQueue中主要做了一下工作:

  1. 从并行集合中取出所有BroadcastRecord,并取出BroadcastRecord中所有的Receiver,循环遍历更新状态并调用BroadcastReceiver中的onReceiver方法。
  2. 处理完并行集合后在处理串行集合,流程同上。
  3. 处理完成后此次scheduleBroadcastsLocked执行完毕,等待下次调用scheduleBroadcastsLocked方法。

重要的源码如下:

/framewrk/base/services/core/java/com/android/server/am/BroadcastQueue.java

final void processNextBroadcast(boolean fromMsg) {
    BroadcastRecord r;    

    while (mParallelBroadcasts.size() > 0) {
        synchronized (mParallelBroadcasts) {
            r = mParallelBroadcasts.remove(0);
        }

        final int N = r.receivers.size();
        
        for (int i=0; i<N; i++) {
            Object target = r.receivers.get(i);
            deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
        }

        
    }

}

四.总结:

  1. 在广播处理过程中使用了大量的Binder通信,因此需要具有Binder通信的基础之后才能读懂整个流程;

  2. 在日常编码过程中尽量使用动态注册广播,不要在onReceiver中处理耗时操作,否则会发生Broadcast的ANR错误;

  3. 广播的处理工作也是在ActivityManagerService这个服务中;

  4. 本文中贴的源码省略了大量的代码,阅读此文章最好和源代码一起参照学习;

  5. 有关Android广播的学习会持续进行,这篇只是最基层的处理;

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值