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

Posted ZhangJianIsAStark

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 7.0 ActivityManagerService 广播(Broadcast)相关流程分析相关的知识,希望对你有一定的参考价值。

本篇博客旨在分析android中广播相关的源码流程。

一、基础知识
广播(Broadcast)是一种Android组件间的通信方式。
从本质上来看,广播信息的载体是intent。在这种通信机制下,发送intent的对象就是广播发送方,接收intent的对象就是广播接收者。
在Android中,为广播接收者定义了一个单独的组件:BroadcastReceiver。

1 BroadcastReceiver的注册类型
在监听广播前,要将BroadcastReceiver注册到系统中。
BroadcastReceiver总体上可以分为两种注册类型:静态注册和动态注册。

静态注册
静态注册是指:通过在AndroidManifest.xml中声明receiver标签,来定义BroadcastReceiver。
PKMS初始化时,通过解析Application的AndroidManifest.xml,就能得到所有静态注册的BroadcastReceiver信息。

当广播发往这种方式注册的BroadcastReceiver时,若该BroadcastReceiver对应的进程没有启动,
AMS需要先启动对应的进程,然后利用Java反射机制构造出BroadcastReceiver,然后才能开始后续的处理。

在AndroidManifest.xml中定义BroadcastReceiver时,对应的标签类似于如下形式:

<receiver android:enabled=["true" | "false"]
    android:exported=["true" | "false"]
    android:icon="drawable resource"
    android:label="string resource"
    android:name="string"
    android:permission="string"
    android:process="string" >
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

其中:
android:enabled表示此broadcastReceiver是否可用,默认值为true。

android:exported表示此broadcastReceiver能否接收其它App的发出的广播;
如果标签中定义了intent-filter字段,则此值默认值为true,否则为false。

android:name表示BroadcastReceiver的类名。

android:permission用于指定广播发送方应该具有的权限;
即具有对应权限的发送者,才能通过AMS将广播发送给此broadcastReceiver;

android:process表示broadcastReceiver运行的进程;
BroadcastReceiver默认运行在当前app的进程中,也可以通过此字段指定其运行于其它独立的进程。

intent-filter用于指定该broadcastReceiver接收广播的类型。

动态注册
与静态注册不同,动态注册是指:
应用程序在运行过程中,调用Context的registerReceiver函数注册BroadcastReceiver;
当应用程序不再需要监听广播时,则需要调用unregisterReceiver函数进行反注册。

动态注册BroadcastReceiver时,需要指定对应的IntentFilter。
IntentFilter用于描述该BroadcastReceiver期待接受的广播类型。
同时,动态注册时也可以指定该BroadcastReceiver要求的权限。

2 广播的种类

从广播的发送特点来看,可以将Android中定义的广播分为以下几类:

普通广播
普通广播由发送方调用sendBroadcast及相关重载函数发送。

AMS转发这种类型的广播时,根据BroadcastReceiver的注册方式,进行不同的处理流程。
对于动态注册的广播,理论上可以认为,AMS将在同一时刻,向所有监听此广播的BroadcastReceiver发送消息,因此整体的消息传递的效率比较高。
对于静态注册的广播,AMS将按照有序广播的方式,向BroadcastReceiver发送消息。

有序广播
有序广播由发送方调用sendOrderedBroadcast及相关重载函数发送,是一种串行的广播发送方式。

处理这种类型的广播时,AMS会按照优先级,将广播依次分发给BroadcastReceiver。
AMS收到上一个BroadcastReceiver处理完毕的消息后,才会将广播发送给下一个BroadcastReceiver。
其中,任意一个BroadcastReceiver,都可以中止后续的广播分发流程。
同时,上一个BroadcastReceiver可以将额外的信息添加到广播中。

前文已经指出,当普通广播发送给静态注册的BroadcastReceiver时,AMS实际上是按照有序广播的方式来进行发送,这么做的原因是:

静态注册的BroadcastReceiver仅申明在AndroidManifest.xml中,因此其所在的进程可能并没有启动。

当AMS向这些BroadcastReceiver发送消息时,可能必须先启动对应的进程。
如果同时向静态注册的BroadcastReceiver发送广播,那么可能需要在一段时间内同时创建出大量的进程,
这将对系统造成极大的负担。

若以有序广播的方式来发送,那么系统可以依次创建进程,
同时,每次收到上一个广播处理完毕的消息后,都可以尝试清理掉无用的进程。
这样即可以避免突发创建大量的进程,又可以及时回收一些系统资源。

因此从Android的设计方式可以看出,从接收广播的效率来讲:
排在第一的是,接收普通广播的动态注册的BroadcastReceiver,
其次是,接收有序广播的动态注册的BroadcastReceiver;
最后是,静态注册的BroadcastReceiver,此时接收的广播是否有序,已经不重要了。
实际上,源码就是按这种顺序来处理的,我们后面将进行深入分析。

粘性广播
粘性广播由发送方调用sendStickyBroadcast及相关重载函数发送。
需要注意的是,目前这种广播已经被附上Deprecated标签了,不再建议使用。

Android设计这种广播的初衷是:
正常情况下,假设发送方发送了一个普通广播A。
在广播A发送完毕后,系统中新注册了一个BroadcastReceiver,此时这个BroadcastReceiver是无法收到广播A的。

但是,如果发送方发送的是一个粘性广播B,那么系统将负责存储该粘性广播。
于是,即使BroadcastReceiver在广播B发送完后才注册到系统,这个BroadcastReceiver也会立即收到AMS转发的广播B。

粘性广播和有序广播等概念实际上不是冲突的。
粘性仅仅强调系统将会保存这个广播,它的其它处理过程与上文一致。

3 适时地限制广播发送范围
从上文可知,对于定义了intent-filter的BroadcastReceiver而言,其exported属性默认为true。
这种设计是符合预期的,毕竟我们使用广播的目的,就是使得属于不同应用、不同进程的组件能够彼此通信。

但在某些场景下,这种设计也可能带来一些安全隐患:
1.其它App可能会针对性的发出与当前App intent-filter相匹配的广播,导致当前App不断接收到广播并处理;
2.其它App可以注册与当前App一致的intent-filter用于接收广播,获取广播具体信息。

因此,在必要的时候,需要适时地限制广播发送范围,例如:
1.对于同一App内部发送和接收广播,将exported属性设置成false;
2.在广播发送和接收时,都增加上相应的permission;
3.发送广播时,指定BroadcastReceiver对应的包名。

通过以上三种方式,可以缩小广播的发送和接收范围,提高效率和安全性。

实际上,在framework/support/v4/java/android/support/v4/content目录下,Android定义了LocalBroadcastManager类,用于发送和接收仅在同一个App应用内传递的广播。
这个类仅针对动态注册的BroadcastReceiver有效,具体的使用方式与普通的全局广播类似,
只是注册/反注册BroadcastReceiver和发送广播时,将Context变成了LocalBroadcastManager。

举例如下:

//registerReceiver
localBroadcastManager = LocalBroadcastManager.getInstance(this);
localBroadcastManager.registerReceiver(mBroadcastReceiver, intentFilter);
..........     

//unregisterReceiver
localBroadcastManager.unregisterReceiver(mBroadcastReceiver);
..........

//send broadcast 
Intent intent = new Intent();
intent.setAction("Test");
localBroadcastManager.sendBroadcast(intent);
...........

以上是Android中关于广播的基础知识,接下来进入到实际的源码分析。

二、registerReceiver流程分析
现在我们看一下广播相关的源码,先从BroadcastReceiver的动态注册流程开始分析。

1 ContextImpl中的registerReceiver
动态注册BroadcastReceiver,将使用Context中定义的registerReceiver函数,具体的实现定义于ContextImpl中:

//这是最常用的接口
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
    return registerReceiver(receiver, filter, null, null);
}

//broadcastPermission与静态注册中的permission标签对应,用于对广播发送方的权限进行限制
//只有拥有对应权限的发送方,发送的广播才能被此receiver接收

//不指定scheduler时,receiver收到广播后,将在主线程调用onReceive函数
//指定scheduler后,onReceive函数由scheduler对应线程处理
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
        String broadcastPermission, Handler scheduler) {

    //ContextImpl是Context家族中实际工作的对象,getOuterContext得到的是ContextImpl对外的代理
    //一般为Application、Activity、Service等
    return registerReceiverInternal(receiver, getUserId(),
            filter, broadcastPermission, scheduler, getOuterContext());
}

与上述代码类似,不论调用Context中的哪个接口注册BroadcastReceiver,最终流程均会进入到registerReceiverInternal函数。

现在,我们跟进一下registerReceiverInternal函数:

private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
        IntentFilter filter, String broadcastPermission,
        Handler scheduler, Context context) {
    IIntentReceiver rd = null;

    if (receiver != null) {
        //mPackageInfo的类型为LoadedApk
        if (mPackageInfo != null && context != null) {
            if (scheduler == null) {
                //未设置scheduler时,将使用主线程的handler处理
                //这就是默认情况下,Receiver的onReceive函数在主线程被调用的原因
                scheduler = mMainThread.getHandler();
            }

            //getReceiverDispatcher函数的内部,利用BroadcastReceiver构造出ReceiverDispatcher
            //返回ReceiverDispatcher中的IIntentReceiver对象
            //IIntentReceiver是注册到AMS中,供AMS回调的Binder通信接口
            rd = mPackageInfo.getReceiverDispatcher(
                    receiver, context, scheduler,
                    mMainThread.getInstrumentation(), true);
        } else {
            //这段代码写的我瞬间懵逼了。。。scheduler == null对应的判断,明显可以移出if-else结构的
            //不符合大google的逼格
            if (scheduler == null) {
                scheduler = mMainThread.getHandler();
            }
            //主动创建
            rd = new LoadedApk.ReceiverDispatcher(
                    receiver, context, scheduler, null, true).getIIntentReceiver();
        }
    }

    try {
        //将Receiver注册到AMS
        final Intent intent = ActivityManagerNative.getDefault().registerReceiver(
                mMainThread.getApplicationThread(), mBasePackageName,
                rd, filter, broadcastPermission, userId);
        .................
    } catch (RemoteException e) {
        ...........
    }
}

以上代码中主要的工作是:
创建BroadcastReceiver对应的ReceiverDispatcher,得到ReceiverDispatcher内部的IIntentReceiver对象,
然后利用Binder通信将该对象连同BroadcastReceiver的其它信息注册到AMS中。

IIntentReceiver对应的继承关系如下图所示:

结合上图,我们需要知道的是:
1、BroadcastReceiver收到的广播实际上是AMS发送的,因此BroadcastReceiver与AMS之间必须进行Binder通信。
从类图可以看出,BroadcastReceiver及其内部成员并没有直接继承Binder类。

负责与AMS通信的,实际上是定义于LoadedApk中的InnerReceiver类,该类继承IIntentReceiver.Stub,作为Binder通信的服务端。
从上文的代码可以看出,注册BroadcastReceiver时,会将该对象注册到AMS中供其回调。

当InnerReceiver收到AMS的通知后,将会调用ReceiverDispatcher进行处理。
由于ReceiverDispatcher持有了实际的BroadcastReceiver,于是最终将广播递交给BroadcastReceiver的onReceive函数进行处理。

以上的设计思路实际上是:
将业务接口(处理广播的BroadcastReceiver类)与通信接口(InnerReceiver类)分离,由统一的管理类(ReceiverDispatcher)进行衔接。
这基本是Java层使用Binder通信的标配,AIDL本身也是这种思路。

2、BroadcastRecevier中定义了一个PendingResult类,该类用于异步处理广播消息。

从上文的代码我们知道了,如果没有明确指定BroadcastReceiver对应的handler,那么其onReceive函数将在主线程中被调用。
因此当onReceive中需要执行较耗时的操作时,会阻塞主线程,影响用户体验。
为了解决这种问题,可以在onReceive函数中采用异步的方式处理广播消息。

一提到异步的方式处理广播消息,大家可能会想到在BroadcastReceiver的onReceive中单独创建线程来处理广播消息。
然而,这样做存在一些问题。

例如:
对于一个静态注册的BroadcastReceiver 对象,对应的进程初始时可能并没有启动。
当AMS向这个BroadcastReceiver对象发送广播时,才会先启动对应的进程。
一旦BroadcastReceiver对象处理完广播,i并将返回结果通知给AMS后,AMS就有可能清理掉对应进程。
因此,若在onReceive中创建线程处理问题,那么onReceive函数就可能在线程完成工作前返回,导致AMS提前销毁进程。
此时,线程也会消亡,使得工作并没有有效完成。

为了解决这个问题,就可以用到BroadcastReceiver提供的PendingResult。
具体的做法是:
先调用BroadcastReceiver的goAsync函数得到一个PendingResult对象,
然后将该对象放到工作线程中去释放。
这样onReceive函数就可以立即返回而不至于阻塞主线程。
同时,Android系统将保证BroadcastReceiver对应进程的生命周期,
直到工作线程处理完广播消息后,调用PendingResult的finish函数为止。

其中原理是:
正常情况下,BroadcastReceiver在onReceive函数结束后,
判断PendingResult不为null,才会将处理完毕的信息通知给AMS。

一旦调用BroadcastReceiver的goAsync函数,就会将BroadcastReceiver中的PendingResult置为null,
因此即使onReceive函数返回,也不会将信息通知给AMS。
AMS也就不会处理BroadcastReceiver对应的进程。

待工作线程调用PendingResult的finish函数时,才会将处理完毕的信息通知给AMS。

代码示例如下:

private class MyBroadcastReceiver extends BroadcastReceiver {
    ..................
    public void onReceive(final Context context, final Intent intent) {
        //得到PendingResult
        final PendingResult result = goAsync();  

        //放到异步线程中执行
        AsyncHandler.post(new Runnable() {  
            @Override  
            public void run() {  
                handleIntent(context, intent);//可进行一些耗时操作  
                result.finish();  
            }  
        });  
    } 
}

final class AsyncHandler {  
    private static final HandlerThread sHandlerThread = new HandlerThread("AsyncHandler");  
    private static final Handler sHandler;  

    static {  
        sHandlerThread.start();  
        sHandler = new Handler(sHandlerThread.getLooper());  
    }  

    public static void post(Runnable r) {  
        sHandler.post(r);  
    }  

    private AsyncHandler() {}  
}  

需要注意的是:
在onReceive函数中执行异步操作,主要目的是避免一些操作阻塞了主线程,
但整个操作仍然需要保证在10s内返回结果,尤其是处理有序广播和静态广播时。
毕竟AMS必须要收到返回结果后,才能向下一个BroadcastReceiver发送广播。

2 AMS中的registerReceiver
AMS的registerReceiver函数被调用时,将会保存BroadcastReceiver对应的Binder通信端,我们一起来看看这部分的代码:

public Intent registerReceiver(IApplicationThread caller, String callerPackage,
        IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
    ...............
    //保存系统内已有的sticky广播
    ArrayList<Intent> stickyIntents = null;
    ...............
    synchronized(this) {
        if (caller != null) {
            //根据IApplicationThread得到对应的进程信息
            callerApp = getRecordForAppLocked(caller);

            if (callerApp == null) {
                //抛出异常,即不允许未登记的进程注册BroadcastReceiver
                ...............
            }

            if (callerApp.info.uid != Process.SYSTEM_UID &&
                    !callerApp.pkgList.containsKey(callerPackage) &&
                    !"android".equals(callerPackage)) {
                //抛出异常,即注册进程必须携带Package名称
                ..................
            }
        } else {
            .............
        }
        ......................
        //为了得到IntentFilter中定义的Action信息,先取出其Iterator
        Iterator<String> actions = filter.actionsIterator();
        if (actions == null) {
            ArrayList<String> noAction = new ArrayList<String>(1);
            noAction.add(null);
            actions = noAction.iterator();
        }

        // Collect stickies of users
        int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
        while (actions.hasNext()) {
            //依次比较BroadcastReceiver关注的Action与Stick广播是否一致
            String action = actions.next();
            for (int id : userIds) {
                ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
                if (stickies != null) {

                    //Sticky广播中,有BroadcastReceiver关注的
                    //可能有多个Intent,对应的Action相似,在此先做一个初步筛选
                    ArrayList<Intent> intents = stickies.get(action);
                    if (intents != null) {
                        if (stickyIntents == null) {
                            stickyIntents = new ArrayList<Intent>();
                        }

                        //将这些广播保存到stickyIntents中
                        stickyIntents.addAll(intents);
                    }
                }
            }
        }
    }

    ArrayList<Intent> allSticky = null;

    //stickyIntents中保存的是action匹配的
    if (stickyIntents != null) {
        //用于解析intent的type
        final ContentResolver resolver = mContext.getContentResolver();

        // Look for any matching sticky broadcasts...
        for (int i = 0, N = stickyIntents.size(); i < N; i++) {
            Intent intent = stickyIntents.get(i);

            //此时进一步判断Intent与BroadcastReceiver的IntentFilter是否匹配
            if (filter.match(resolver, intent, true, TAG) >= 0) {
                if (allSticky == null) {
                    allSticky = new ArrayList<Intent>();
                }
                allSticky.add(intent);
            }
        }
    }

    // The first sticky in the list is returned directly back to the client.
    Intent sticky = allSticky != null ? allSticky.get(0) : null;
    ................
    synchronized (this) {
        ..............
        //一个Receiver可能监听多个广播,多个广播对应的BroadcastFilter组成ReceiverList
        ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
        if (rl == null) {
            //首次注册,rl为null,进入此分支
            //新建BroadcastReceiver对应的ReceiverList
            rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                    userId, receiver);
            if (rl.app != null) {
                rl.app.receivers.add(rl);
            } else {
                try {
                    //rl监听receiver所在进程的死亡消息
                    receiver.asBinder().linkToDeath(rl, 0);
                } catch (RemoteException e) {
                    return sticky;
                }
                rl.linkedToDeath = true;
            }
            //保存到AMS上
            mRegisteredReceivers.put(receiver.asBinder(), rl);
        } ..........
        ............

        //创建当前IntentFilter对应的BroadcastFilter
        //AMS收到广播后,将根据BroadcastFilter决定是否将广播递交给对应的BroadcastReceiver
        //一个BroadcastReceiver可以对应多个IntentFilter
        //这些IntentFilter对应的BroadcastFilter共用一个ReceiverList
        BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                permission, callingUid, userId);
        rl.add(bf);
        ................
        mReceiverResolver.addFilter(bf);

        // Enqueue broadcasts for all existing stickies that match
        // this filter.
        //allSticky不为空,说明有粘性广播需要发送给刚注册的BroadcastReceiver
        if (allSticky != null) {
            ArrayList receivers = new ArrayList();
            //receivers记录bf
            receivers.add(bf);

            final int stickyCount = allSticky.size();
            for (int i = 0; i < stickyCount; i++) {
                Intent intent = allSticky.get(i);
                //根据intent的flag (FLAG_RECEIVER_FOREGROUND)决定是使用gBroadcastQueue还是BgBroadcastQueue
                BroadcastQueue queue = broadcastQueueForIntent(intent);

                //创建广播对应的BroadcastRecord
                //BroadcastRecord中包含了Intent,即知道要发送什么广播;
                //同时其中含有receivers,内部包含bf,即知道需要将广播发送给哪个BroadcastReceiver
                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);

                //加入到BroadcastQueue中,存入的是并发广播对应的队列
                queue.enqueueParallelBroadcastLocked(r);

                //将发送BROADCAST_INTENT_MSG,触发AMS发送广播
                queue.scheduleBroadcastsLocked();
            }
        }
    }
}

至此,AMS中registerReceiver的流程结束。
这个函数看起来很长,但主要工作还是比较清晰的,一共可以分为两个部分:
1、将BroadcastReceiver对应的信息保存到AMS中,同时为当前使用的IntentFilter生成对应的BroadcastFilter。
当AMS发送广播时,将根据广播和BroadcastFilter的匹配情况,决定是否为BroadcastReceiver发送消息。

2、单独对粘性广播进行处理。
由于粘性广播有立即发送的特点,因此当有新的BroadcastReceiver注册到AMS后,
AMS需要判断系统中保存的粘性广播中,是否有与该BroadcastReceiver匹配的。
若有与新注册BroadcastReceiver匹配的粘性广播,那么AMS为这些广播构造BroadcastRecord,
并将其加入到发送队列中,同时发送消息触发AMS的广播发送流程。

上述代码的整个过程,还是比较好理解的,唯一麻烦一点的就是涉及到了一些数据结构,需要稍微整理一下:

在AMS中,BroadcastReceiver的过滤条件由BroadcastFilter表示,如上图所示,该类继承自IntentFilter。
由于一个BroadcastReceiver可以设置多个过滤条件,故AMS使用ReceiverList来记录一个BroadcastReceiver对应的所有BroadcastFilter。
同时,BroadcastFilter中持有对ReceiverList的引用,用于记录自己属于哪个ReceiverList;
ReceiverList中也保存着对IIntentReceiver的引用,用于记录自己对应于哪个BroadcastReceiver。

AMS中利用mRegisterdReceivers这个HashMap,来保存广播对应的ReceiverList,其中的键值就是BroadcastReceiver对应的IIntentReceiver。
同时,AMS中的mReceiverResolver用于保存所有动态注册BroadcastReceiver对应的BroadcastFilter。注意此处的IntentResolver是一个模板类,并不是一个Map类型的数据结构。

这部分流程比较简单,大致如下图所示:

三、sendBroadcast流程分析
分析完广播接收方注册BroadcastReceiver的流程,现在我们来看看广播发送方sendBroadcast的流程。

与registerReceiver一样,Context.java中定义了多个sendBroadcast的接口,但是殊途同归,这些接口最终的流程基本一致。
因此,我们以比较常见的接口入手,看看整个代码的逻辑。

public void sendBroadcast(Intent intent) {
    ............
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
        //StrictMode下,对一些Action需要进行检查
        intent.prepareToLeaveProcess(this);

        //调用AMS中的接口
        ActivityManagerNative.getDefault().broadcastIntent(
                mMainThread.getApplicationThread(), intent, resolvedType, null,
                Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                getUserId());
    } catch(RemoteException e) {
        ..............
    }
}

ContextImpl中的sendBroadcast函数比较简单,进行一些必要的检查后,直接调用AMS中接口。
我们跟进流程,看看AMS中的broadcastIntent函数:

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) {
    ..............
    synchronized(this) {
        //检查Broadcast中Intent携带的信息是否有问题
        //例如:Intent中不能携带文件描述符(避免安全隐患)
        //同时检查Intent的Flag
        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;
    }
}

broadcastIntent中对Broadcast对应的Intent进行一些检查后,调用broadcastIntentLocked进行实际的处理。
broadcastIntentLocked函数非常长,大概600行左右吧…….我们只能分段看看它的主要思路。

1 broadcastIntentLocked函数Part I

final int broadcastIntentLocked(.....) {
    intent = new Intent(intent);

    // By default broadcasts do not go to stopped apps.
    // Android系统对所有app的运行状态进行了跟踪
    // 当应用第一次安装但未使用过,或从程序管理器被强行关闭后,将处于停止状态

    // 在发送广播时,不管是什么广播类型,系统默认增加了FLAG_EXCLUDE_STOPPED_PACKAGES的flag
    // 使得对于所有BroadcastReceiver而言,如果其所在进程的处于停止状态,该BroadcastReceiver将无法接收到广播
    intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

    //大量条件检查,例如:
    //有些Action只能由系统来发送;
    //有些Action需要发送方申明了对应权限
    ...................

    //某些Action,例如Package增加或移除、时区或时间改变、清除DNS、代理变化等,需要AMS来处理
    //AMS需要根据Action,进行对应的操作
    ..................
}

这部分的代码较多,主要是针对具体Action的操作,在分析整体流程时,没有必要深究。
当需要研究对应广播引发的操作时,可以再有针对性的研究。

简单地讲,代码主要工作其实只有两个:
1、根据广播对应Intent中的信息,判断发送方是否有发送该广播的权限;
2、针对一些特殊的广播,AMS需要进行一些操作。

2 broadcastIntentLocked函数Part II

..............
// 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) {
        //粘性广播不能指定接收方
        ............
    }

    // We use userId directly here, since the "all" target is maintained
    // as a separate set of sticky broadcasts.
    //当粘性广播是针对特定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));
        }
    }
}
...............

broadcastIntentLocke第二部分主要是处理粘性广播的,整个功能比较清晰,
即判断发送粘性广播的条件是否满足,然后将粘性广播保存起来。

3 broadcastIntentLocked函数Part III

.............
// 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;
}
.....................

broadcastIntentLocke第三部分的工作主要包括:
1、查询与当前广播匹配的静态和动态BroadcastReceiver;
2、若当前待发送的广播是无序的,那么为动态注册的BroadcastReceiver,构造该广播对应的BroadcastRecord加入到发送队列中,
并触发广播发送流程。

从这部分代码可以看出,对于无序广播而言,动态注册的BroadcastReceiver接收广播的优先级,高于静态注册的BroadcastReceiver。

4 broadcastIntentLocked函数Part IV

.................
// Merge into one list.
int ir = 0;
if (receivers != null) {
    // A special case for PACKAGE_ADDED: do not allow the package
    // being added to see this broadcast.  This prevents them from
    // using this as a back door to get run as soon as they are
    // installed.  Maybe in the future we want to have a special install
    // broadcast or such for apps, but we'd like to deliberately make
    // this decision.
    //处理特殊的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 != Android 7.0下仿7.0之前的时间框及去掉日选择框方法

Android 7.0下仿7.0之前的时间框及去掉日选择框方法

关于 Android 7.0 适配中 FileProvider 部分的总结

Android 7.0 抓包配置

Android编程入门--android 7.0 的so文件

Android 7.0动态权限大总结