Android 静态广播和动态广播接收顺序

Android广播有两个很重要的要素:

1 广播 - 用于发送广播

有序广播  -  被广播接收器接收后,可被终止,无法往下继续传达。         典型代表:短信广播

普通广播  -  发送至每一个已经注册(订阅)的广播接收器,无法被终止。 典型代表:开机启动广播

2 广播接收器 - 用于订阅广播后接收广播

静态注册广播 - 在AndroidManifest.xml中设置,程序不用启动亦可接收。 典型代表:很多开机启动的APP,都是接收开机启动广播带起服务的。

动态注册广播 - 代码中注册广播,程序未启动时,无法接收广播。             典型代表:Go短信,将Go短信强行停止,Go短信无法接收短信。

广播注册过程和接收广播顺序过程

静态广播接收器 由PackageManagerService负责,当手机启动时(或者新安装了应用),PackageManagerService负责扫描手机中所有已安装的APP应用(题外话,确定不再使用的APP需要卸载了),将AndroidManifest.xml中 有关注册广播的信息 解析出来,存储至一个全局静态变量当中mReceivers。

需要注意的是:

1 PackageManagerService扫描目录的顺序如下:

  system/framework

  system/app

  vendor/app

  data/app

  drm/app-private

2 当处于同一目录下时:按照file.list()的返回顺序。(题外话:因为在data/app下的应用都是用户安装的,并且都是以com.xxx.xxx-1.apk 的形式出现,所以如果打算做手机管家之类的应用,需要好好的研究下包名,争取在file.list()的独木桥下抢的头筹---优先接收开机启动完成的广播。)

3 在此处并未对 接收顺序做完整的排序。(注意修饰词完整的,毕竟先扫描的当然会有一定优先级)

动态广播接收器 由ActivityManagerService负责,当APP的服务或者进程起来之后,执行了注册广播接收的代码逻辑,即进行加载,最后会存储在一个全局静态变量

mReceiverResolver中。

需要注意的是:

1 这个并非是一成不变的,当程序被杀死之后,  已注册的动态广播接收器也会被移出mReceiverResolver,直到下次程序启动,再进行动态广播的注册,当然这里面的顺序也已经变更了一次。

2  这里也并没完整的进行广播的排序,只记录的注册的先后顺序,并未有结合优先级的处理。

当有广播发出时,接收顺序如下:

在ActivityManagerService处理广播,当广播为有序广播时,将动态广播接收器和动态广播接收器合并起来,形成最终的有序广播接收顺序。

上述的规则1排序为:

1 优先级高的先接收

2 同优先级的动静态广播接收器,动态优先于静态

3 同优先级的动态广播接收器  或者同优先级的静态广播接收器,按照图1 的流程注册顺序。

即静态:先扫描的大于后扫描的,动态:先注册的大于后注册的。

当广播为普通广播时,规则2排序为:

1 无视优先级,动态广播接收器优先于静态广播接收器

2 同规则1排序的第3点

1.为什么普通的动态广播一定在静态广播之前接收到?

广播注册registerReceiverContextImpl.java会调用到AMS.registerReceiver

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查询调用者的进程信息
            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返回前台或后台广播队列
                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调用enqueueParallelBroadcastLocked添加到mParallelBroadcasts队列里面

BroadcastQueue中有两个广播队列mParallelBroadcasts,mOrderedBroadcasts,数据类型都为ArrayList:

  • mParallelBroadcasts:并行广播队列,可以立刻执行,而无需等待另一个广播运行完成,该队列只允许动态已注册的广播,从而避免发生同时拉起大量进程来执行广播,前台的和后台的广播分别位于独立的队列。
  • mOrderedBroadcasts:有序广播队列,同一时间只允许执行一个广播,该队列顶部的广播便是活动广播,其他广播必须等待该广播结束才能运行,也是独立区别前台的和后台的广播。

http://androidxref.com/6.0.1_r10/xref/frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java

public final class BroadcastQueue {
    //...

    /**
     * Lists of all active broadcasts that are to be executed immediately
     * (without waiting for another broadcast to finish).  Currently this only
     * contains broadcasts to registered receivers, to avoid spinning up
     * a bunch of processes to execute IntentReceiver components.  Background-
     * and foreground-priority broadcasts are queued separately.
     */
    final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>();

    /**
     * List of all active broadcasts that are to be executed one at a time.
     * The object at the top of the list is the currently activity broadcasts;
     * those after it are waiting for the top to finish.  As with parallel
     * broadcasts, separate background- and foreground-priority queues are
     * maintained.
     */
    final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<>();

    public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
        mParallelBroadcasts.add(r);
        r.enqueueClockTime = System.currentTimeMillis();
    }

}

发送广播的时候在ActivityManagerService的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是否有效
        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;
    }
}

AMS.broadcastIntentLocked

step1: 设置flag
step2: 广播权限验证
step3: 处理系统相关广播
step4: 增加sticky广播
step5: 查询receivers和registeredReceivers
step6: 处理并行广播
step7: 合并registeredReceivers到receivers
step8: 处理串行广播

private final int broadcastIntentLocked(ProcessRecord callerApp,
        String callerPackage, Intent intent, String resolvedType,
        IIntentReceiver resultTo, int resultCode, String resultData,
        Bundle map, String requiredPermission,
        boolean ordered, boolean sticky, int callingPid, int callingUid) {     

    …………
    …………  

    // 静态广播接收器list
    List receivers = null;   

    // 动态广播接收器List
    List<BroadcastFilter> registeredReceivers = null;     

    // 获取静态广播接收器mReceivers
    try {
        if (intent.getComponent() != null) {
            // Broadcast is going to one specific receiver class...
            ActivityInfo ai = AppGlobals.getPackageManager().
                getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
            if (ai != null) {
                receivers = new ArrayList();
                ResolveInfo ri = new ResolveInfo();
                ri.activityInfo = ai;
                receivers.add(ri);
            }
        } else {
            // Need to resolve the intent to interested receivers...
            if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
                     == 0) {
                receivers =
                    AppGlobals.getPackageManager().queryIntentReceivers(
                            intent, resolvedType, STOCK_PM_FLAGS);
            }
            // 获取动态广播接收器mReceiverResolver
            registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
        }
    } catch (RemoteException ex) {
        // pm is in same process, this will never happen.
    }     

    final boolean replacePending =
            (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;     

    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.
        BroadcastRecord r = new BroadcastRecord(intent, callerApp,
                callerPackage, callingPid, callingUid, requiredPermission,
                registeredReceivers, resultTo, resultCode, resultData, map,
                ordered, sticky, false);     

    // 很明显接收到普通广播之后,在这只处理了动态广播 registeredReceivers,对于普通广播而言,动态广播接收器要优先于静态广播接收器 无关设置的优先级
        boolean replaced = false;
        if (replacePending) {
            for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
                if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
                    if (DEBUG_BROADCAST) Slog.v(TAG,
                            "***** DROPPING PARALLEL: " + intent);
                    mParallelBroadcasts.set(i, r);
                    replaced = true;
                    break;
                }
            }
        }
        if (!replaced) {
            mParallelBroadcasts.add(r);
            scheduleBroadcastsLocked();
        }
        //将registeredReceivers置为null,后面只处理静态广播接收器,所以不会有冲突。
        registeredReceivers = null;
        NR = 0;
    }     

    //如果是有序广播,将静态广播接收器和动态广播接收器组合成一个最终的顺序
    int ir = 0;
    if (receivers != null) {
        ...
        //合并的过程,注意顺序
        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) {
                // 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;
            }
        }
    }  

2.为什么为什么有序广播和普通广播顺序不一样

有序广播,将静态广播接收器和动态广播接收器组合成一个最终的按照优先级顺序

 //如果是有序广播,将静态广播接收器和动态广播接收器组合成一个最终的顺序
    int ir = 0;
    if (receivers != null) {
        ...
        //合并的过程,注意顺序
        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) {
                // 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;
            }
        }     

最后举个例子:

(以下的静A 表示静态广播接收器,同理动B。)

1 静A (优先级1)

2 动B(优先级1)

3 静C (优先级2,后扫描)

4 静D (优先级2,先扫描)

5 动E   (优先级2,先注册)

6 动F  (优先级2,后注册)

当来了一个 有序广播,接收顺序如下:动E >  动F  > 静D > 静C > 动B > 静A

当来了一个 普通广播,接收顺序如下:动E >  动F  > 动B > 静D > 静C > 静A

原文地址:https://www.cnblogs.com/mingfeng002/p/10986357.html

时间: 2024-10-11 16:54:28

Android 静态广播和动态广播接收顺序的相关文章

静态广播与动态广播

静态广播与动态广播区别: 两者及其接收广播的区别: 1.动态注册的广播 永远要快于 静态注册的广播,不管静态注册的优先级设置的多高,不管动态注册的优先级有多低>\ 2.动态注册广播不是 常驻型广播 ,也就是说广播跟随activity的生命周期.注意: 在activity结束前,移除广播接收器. 静态注册是常驻型 ,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行. 3.在同一个优先级下,谁先启动的快,谁将先接收到广播. 动态注册代码: UpdateBroadcast  br

Android广播之注册广播(包括静态广播和动态广播的注册)源码分析

Android广播按发送方式分类有三种:无序广播.有序广播(OrderedBroadcast)和粘性广播(StickyBroadcast). 静态广播的注册流程: 在系统服务启动时会添加PackageManagerService,在该类的构造方法中就会对各个应用安装目录的apk文件进行扫描解析.先看下时序图: 先看PackageManagerService类的构造方法: // Keys are String (package name), values are Package. This als

静态广播与动态广播的区别

1.动态注册的广播永远要快于静态注册的广播,不管静态注册的优先级设置的多高,不管动态注册的优先级有多低 2.生存期,静态广播的生存期可以比动态广播的长很多,因为静态广播很多都是用来对系统时间进行监听,比如我们可以监听手机开机.而动态广播会随着context的终止而终止 3.动态广播无需在AndroidManifest.xml中声明即可直接使用,也即动态:而静态广播则需要,有时候还要在AndroidManifest.xml中加上一些权限的声明

Android--静态广播和动态广播的区别

一.标准广播and有序广播 标准广播发出后所有广播接受器几乎同一时刻收到广播,并且没有顺序,所以广播不可被截断. 有序广播发出后同一时刻只能有有一个广播接收器收到广播消息,因此优先级高的广播的先收到消息,并且前面的接受器还可以截断消息. 二.动态注册广播接收器 注册广播的方式有两种:静态注册和动态注册 静态注册是在AndroidManifest.xml注册文件里注册,动态注册时在代码中注册 (1)创建广播接收器 创建一个类继承BroadcastReceiver 并重写onReceive()方法

Android 7.0 ActivityManagerService(5) 广播(Broadcast)相关流程分析

本篇博客旨在分析Android中广播相关的源码流程. 一.基础知识 广播(Broadcast)是一种Android组件间的通信方式. 从本质上来看,广播信息的载体是intent.在这种通信机制下,发送intent的对象就是广播发送方,接收intent的对象就是广播接收者. 在Android中,为广播接收者定义了一个单独的组件:BroadcastReceiver. 1 BroadcastReceiver的注册类型 在监听广播前,要将BroadcastReceiver注册到系统中. Broadcas

Android笔记(二十七) Android中的动态广播和静态广播

广播接收器注册一共有两种形式 : 静态注册和动态注册. 两者及其接收广播的区别: 1.动态注册的广播 永远要快于 静态注册的广播,不管静态注册的优先级设置的多高,不管动态注册的优先级有多低>\ 2.动态注册广播不是 常驻型广播 ,也就是说广播跟随activity的生命周期.注意: 在activity结束前,移除广播接收器. 静态注册是常驻型 ,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行. 3.在同一个优先级下,谁先启动的快,谁将先接收到广播. 动态注册代码: Upda

Android-broadcast静态动态广播

广播的静态和动态类型 静态广播: 1.继承之broadcastreceiver public class MyStaticBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { //RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layou

动态广播和静态广播的区别

广播接收器注册一共有两种形式 : 静态注册和动态注册. 两者及其接收广播的区别: 1.动态注册的广播永远要快于静态注册的广播,不管静态注册的优先级设置的多高,不管动态注册的优先级有多低 2.动态注册广播不是常驻型广播,也就是说广播跟随activity的生命周期.注意:在activity结束前,移除广播接收器. 静态注册是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行. 3.在同一个优先级下,谁先启动的快,谁将先接收到广播. 动态注册代码: UpdateBroadc

动态广播与静态广播的区别

生存期:静态广播的生存期可以比动态广播的长很多,因为静态广播很多都是用来对系统时间进行监听,比如我们可以监听手机开机.而动态广播会随着context的终止而终止 优先级:动态广播的优先级比静态广播高 注册:动态广播无需在AndroidManifest.xml中声明即可直接使用(用receiver注册),也即动态:而静态广播则需要,有时候还要在AndroidManifest.xml中加上一些权限的声明.静态注册是当程序关闭后,如果有广播发过来,还能启动程序.动态注册的生命周期跟程序的生命周期是一样