跳转至

Broadcast概述

简介

Broadcast(广播)是Android四大组件之一,在四大组件的另外两个组件Activity和Service拥有发送和接收广播的能力。Android是在Binder进程间通信机制的基础上实现的,内部基于消息发布和订阅的事件驱动模型,广播发送者负责发送消息,广播接收者需要先订阅消息,然后才能收到消息。Binder进程间通信与Broadcast的区别在于:

  • Binder

客户端需要先知道服务端的存在,并获取到它的一个代理对象;

  • Broadcast

广播发送者实现不需要知道广播接收者的存在,这样可以降低发送者和接收者的耦合度。提高系统的可扩展性和可维护性。

Broadcast分类

注册方式

  • 静态注册

android manifest文件注册,常驻广播。

  • 动态注册

在代码中手动调用Context.registerReceiver讲BroadcastReceiver注册到AMS中,所以要求程序必须在运行时才能进行,有一定的局限性。

发送方式

静态注册的广播,一律按照串行广播处理,因为可能会设计到拉起多个进程等,串行广播才有超时处理。

  • 有序广播

发送的广播被接收者有序的接收,根据接收对象的优先级(Priority属性的值决定,值越大,优先级越高;Priority属性相同时,动态注册的广播优先于静态注册的广播)来决定接受顺序。有序广播可以对广播进行拦截,这样之后的接收者就接受不到广播了,也可以对广播内容进行修改。

  • 无序广播

默认无序;并行分发;不可以被拦截、终止、修改;无优先级问题;传递数据用intent.putExtra。

处理类型

AMS中前台广播和后台广播分别有一个广播队列,互不干扰。

  • 前台广播

发送时添加Intent.FLAG_RECEIVER_FOREGROUND,超时时间10s

  • 后台广播

默认后台,超时时间60s

接收者

  • 显示广播

指定接收方的class类型

  • 隐式广播

只指定action,uri等, android 8.0开始限制了隐式广播的接收

主要源码

frameworks/base/services/core/java/com/android/server/am/
├── ActivityManagerService.java
├── BroadcastConstants.java
├── BroadcastDispatcher.java
├── BroadcastFilter.java
├── BroadcastQueue.java
├── BroadcastRecord.java
├── BroadcastStats.java
├── ProcessRecord.java
└── ReceiverList.java


frameworks/base/core/java/android/content/
├── BroadcastReceiver.java
└── IntentFilter.java


frameworks/base/services/core/java/com/android/server/pm
├── PackageManagerService.java
├── parsing
   └── PackageParser2.java
└── pkg
    └── parsing
        ├── ParsingPackageImpl.java
        └── ParsingPackageUtils.java

数据结构

BroadcastRecord

final class BroadcastRecord extends Binder {
    final Intent intent;    // the original intent that generated us
    final ComponentName targetComp; // original component name set on the intent
    //广播发送者的进程
    final ProcessRecord callerApp; // process that sent this
    //广播发送者的包名
    final String callerPackage; // who sent this
    final @Nullable String callerFeatureId; // which feature in the package sent this
    //广播发送者的pid
    final int callingPid;   // the pid of who sent this
    //广播发送者的uid
    final int callingUid;   // the uid of who sent this
    //广播发送者是否是Instant App
    final boolean callerInstantApp; // caller is an Instant App?
    //是否有序广播
    final boolean ordered;  // serialize the send to receivers?
    //是否粘性广播
    final boolean sticky;   // originated from existing sticky data?
    final boolean initialSticky; // initial broadcast from register to sticky?
    final int userId;       // user id this broadcast was for
    final String resolvedType; // the resolved data type
    //广播发送者的要求的权限
    final String[] requiredPermissions; // permissions the caller has required
    final String[] excludedPermissions; // permissions to exclude
    final String[] excludedPackages; // packages to exclude
    final int appOp;        // an app op that is associated with this broadcast
    final BroadcastOptions options; // BroadcastOptions supplied by caller
    //广播接收器,包括动态注册(BroadcastFilter)和静态注册(ResolveInfo);
    final List receivers;   // contains BroadcastFilter and ResolveInfo
    final int[] delivery;   // delivery state of each receiver
    final long[] duration;   // duration a receiver took to process broadcast
    IIntentReceiver resultTo; // who receives final result if non-null
    boolean deferred;
    int splitCount;         // refcount for result callback, when split
    int splitToken;         // identifier for cross-BroadcastRecord refcount
    long enqueueTime;       // uptimeMillis when the broadcast was enqueued
    long enqueueRealTime;   // elapsedRealtime when the broadcast was enqueued
    //广播入队列时间点
    long enqueueClockTime;  // the clock time the broadcast was enqueued
    //广播分发时间点
    long dispatchTime;      // when dispatch started on this set of receivers
    long dispatchRealTime;  // elapsedRealtime when the broadcast was dispatched
    long dispatchClockTime; // the clock time the dispatch started
    //当前receiver开始处理时间点
    long receiverTime;      // when current receiver started for timeouts.
    //广播处理完成时间点
    long finishTime;        // when we finished the current receiver.
    boolean timeoutExempt;  // true if this broadcast is not subject to receiver timeouts
    int resultCode;         // current result code value.
    String resultData;      // current result data value.
    Bundle resultExtras;    // current result extra data values.
    boolean resultAbort;    // current result abortBroadcast value.
    int nextReceiver;       // next receiver to be executed.
    //数据类型为IBinder,保存的广播所在进程的ApplicationThread对象的代理端
    IBinder receiver;       // who is currently running, null if none.
    int state;
    int anrCount;           // has this broadcast record hit any ANRs?
    int manifestCount;      // number of manifest receivers dispatched.
    int manifestSkipCount;  // number of manifest receivers skipped.
    BroadcastQueue queue;   // the outbound queue handling this broadcast
}

广播列表

public final class BroadcastQueue {

    //保存了将要发送的 无序广播
    final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>();

    //有序 Dispatcher
    final BroadcastDispatcher mDispatcher;
}

public class BroadcastDispatcher {

    //保存了将要发送的 有序广播
    private final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<>();
}

静态广播

public class PackageManagerService implements PackageSender, TestUtilityService {

    //PackageManagerService成员变量mComponentResolver就是通过ParsingPackageImpl.receivers拿到所有安装应用的receiver
    final ComponentResolver mComponentResolver;

}

动态广播

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback, ActivityManagerGlobalLock {

    //保存了系统中所有的动态注册的广播,以应用进程中的IIntentReceiver的binder代理端为key, 保存了该Receiver对应的所有IntentFilter,是一个一对多的关系,一个BroadcastReceiver对应多个intentFilter。
    final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();

}

广播队列

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback, ActivityManagerGlobalLock {

    final BroadcastQueue mFgBroadcastQueue;
    final BroadcastQueue mBgBroadcastQueue;
    final BroadcastQueue mBgOffloadBroadcastQueue;
    final BroadcastQueue mFgOffloadBroadcastQueue;

}

使用

注册

静态

<receiver
    android:name=".TestBroadcastReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>
public class BootCompletedReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
       if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
            //接收到开机广播
        }
    }
}
  • android:permission
    如果设置,具有相应权限的广播发送方发送的广播才能被此broadcastReceiver所接收
  • android:priority="999"

Priority属性的值决定,值越大,优先级越高;Priority属性相同时,动态注册的广播优先于静态注册的广播

动态

IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
ScreenBroadcastReceiver receiver = new ScreenBroadcastReceiver();
mContext.registerReceiver(receiver, filter);

private class ScreenBroadcastReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (Intent.ACTION_SCREEN_ON.equals(action)) {
            //TODO
        } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
            //TODO
        }
    }
}

发送

Intent intent = new Intent();
intent.setAction("action...");
mContext.sendBroadcast(intent);

FAQ

  • "W BroadcastQueue: Background execution not allowed: receiving"

不能启动后台进程

  • "W BroadcastQueue: Permission Denial: broadcasting"

注册者 申请权限

发送者 未设置权限

  • "W BroadcastQueue: Permission Denial: receiving"

注册者 未申请权限

发送者 设置权限

静态广播注册流程

AndroidManifest静态注册的安装过程是在PMS处理的,这里我们省略PMS启动过程、处理安装请求过程等,直接从解析包的信息开始分析。

ParsingPackageUtils.java

 public ParseResult<ParsingPackage> parsePackage(ParseInput input, File packageFile, int flags,
        List<File> frameworkSplits) {
    if (((flags & PARSE_FRAMEWORK_RES_SPLITS) != 0)
            && frameworkSplits.size() > 0
            && packageFile.getAbsolutePath().endsWith("/framework-res.apk")) {
        return parseClusterPackage(input, packageFile, frameworkSplits, flags);
    } else if (packageFile.isDirectory()) {
        return parseClusterPackage(input, packageFile, /* frameworkSplits= */null, flags);
    } else {
        return parseMonolithicPackage(input, packageFile, flags);
    }
}

当前流程是走到parseClusterPackage

ParsingPackageUtils.java

private ParseResult<ParsingPackage> parseClusterPackage(ParseInput input, File packageDir,
        List<File> frameworkSplits, int flags) {

    ...

    final ParseResult<PackageLite> liteResult =
            ApkLiteParseUtils.parseClusterPackageLite(input, packageDir, frameworkSplits,
                    liteParseFlags);

    ...


    try {
        final File baseApk = new File(lite.getBaseApkPath());
        final ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk,
                lite.getPath(), assetLoader, flags);
        ...
    }

    ...
}

调用ApkLiteParseUtils.parseClusterPackageLite得到包的一些基本信息。

PackageLite.java

public class PackageLite {
    //apk包名
    private final @NonNull String mPackageName;
    //apk目录
    private final @NonNull String mPath;
    //apk路径
    private final @NonNull String mBaseApkPath;

    ...

    /** Major and minor version number of this package */
    private final int mVersionCodeMajor;
    private final int mVersionCode;
    private final int mTargetSdk;

}

调用parseBaseApk解析BaseApk。

ParsingPackageUtils.java

private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, File apkFile,
        String codePath, SplitAssetLoader assetLoader, int flags) {
    ...

    //创建解析器parser,来解析ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml"
    try (XmlResourceParser parser = assets.openXmlResourceParser(cookie,
            ANDROID_MANIFEST_FILENAME)) {
        final Resources res = new Resources(assets, mDisplayMetrics, null);

        //传入解析器parser,解析BaseApk
        ParseResult<ParsingPackage> result = parseBaseApk(input, apkPath, codePath, res,
                parser, flags);
        ...
    }
    ...
}

创建AndroidManifest.xml解析器XmlResourceParser,并调用parseBaseApk传入解析器parser,解析BaseApk。

ParsingPackageUtils.java

/**
 * Parse the manifest of a <em>base APK</em>. When adding new features you need to consider
 * whether they should be supported by split APKs and child packages.
 *
 * @param apkPath The package apk file path
 * @param res     The resources from which to resolve values
 * @param parser  The manifest parser
 * @param flags   Flags how to parse
 * @return Parsed package or null on error.
 */
private ParseResult<ParsingPackage> parseBaseApk(ParseInput input, String apkPath,
        String codePath, Resources res, XmlResourceParser parser, int flags)
        throws XmlPullParserException, IOException {
    ...

    final TypedArray manifestArray = res.obtainAttributes(parser, R.styleable.AndroidManifest);
    try {
        ...
        final ParseResult<ParsingPackage> result =
                parseBaseApkTags(input, pkg, manifestArray, res, parser, flags);
        ...
    }
    ...
}

调用parseBaseApkTags解析manifest中的各类TAG。

private ParseResult<ParsingPackage> parseBaseApkTags(ParseInput input, ParsingPackage pkg,
        TypedArray sa, Resources res, XmlResourceParser parser, int flags)
        throws XmlPullParserException, IOException {
    ...
    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
            && (type != XmlPullParser.END_TAG
            || parser.getDepth() > depth)) {
        ...

        // <application> has special logic, so it's handled outside the general method
        if (TAG_APPLICATION.equals(tagName)) {
            if (foundApp) {
                ...
            } else {
                foundApp = true;
                result = parseBaseApplication(input, pkg, res, parser, flags);
            }
        }
        ...
    }

    ...

    return input.success(pkg);
}

TAG_APPLICATION = "application"时,则调用parseBaseApplication进行application的内容解析。

private ParseResult<ParsingPackage> parseBaseApplication(ParseInput input,
        ParsingPackage pkg, Resources res, XmlResourceParser parser, int flags)
        throws XmlPullParserException, IOException {
    ...
    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
            && (type != XmlPullParser.END_TAG
            || parser.getDepth() > depth)) {

        ...

        boolean isActivity = false;
        switch (tagName) {
            case "activity":
                isActivity = true;
                // fall-through
            case "receiver":
                ParseResult<ParsedActivity> activityResult =
                        ParsedActivityUtils.parseActivityOrReceiver(mSeparateProcesses, pkg,
                                res, parser, flags, sUseRoundIcon, null /*defaultSplitName*/,
                                input);

                if (activityResult.isSuccess()) {
                    ParsedActivity activity = activityResult.getResult();
                    if (isActivity) {
                        hasActivityOrder |= (activity.getOrder() != 0);
                        pkg.addActivity(activity);
                    } else {
                        hasReceiverOrder |= (activity.getOrder() != 0);
                        pkg.addReceiver(activity);
                    }
                }

                result = activityResult;
                break;
            case "service":
                ...
            case "provider":
                ...
            case "activity-alias":
                ...
            case "apex-system-service":
                ...
        }

        ...
    }

    ...

    if (hasReceiverOrder) {
        pkg.sortReceivers();
    }

    ...

}
  • 这里发现进入activity这个case没有break,这意味着activity和receiver的解析是一样的,它们比较类似;从调用函数名字parseActivityOrReceiver也可以看出。
  • ParsedActivityUtils.parseActivityOrReceiver->ParsedActivityUtils.parseActivityOrAlias中每一个"intent-filter"会对应一个ParsedIntentInfo。
  • pkg.addReceiver(activity) 将该ParsedActivity activity(receiver)放入ParsingPackageImpl的receivers。
  • hasReceiverOrder 按照android:order进行排序,order越大的receiver放在receivers列表的前面。
ParsingPackageImpl.java

public ParsingPackageImpl addReceiver(ParsedActivity parsedReceiver) {
    this.receivers = CollectionUtils.add(this.receivers, parsedReceiver);
    addMimeGroupsFromComponent(parsedReceiver);
    return this;
}

在后续的PMS流程里(InstallPackageHelper.installPackagesLI() -> InstallPackageHelper.commitPackagesLocked() -> InstallPackageHelper.commitReconciledScanResultLocked() -> InstallPackageHelper.commitPackageSettings() -> ComponentResolver.addAllComponents() -> ComponentResolver.addReceiversLocked() )

PackageManagerService成员变量mComponentResolver就是通过ParsingPackageImpl.receivers拿到所有安装应用的receiver。

总结

  • AndroidManifest.xml中的receiver解析成ParsedActivity, 存放在PackageImpl的receivers(PackageImpl父类是ParsingPackageImpl而且实现了AndroidPackage接口)。
  • receivers最终会存放在mComponentResolver(PMS)的mReceivers中,mReceivers包含了所有安装应用的receiver。

动态广播注册流程

在前面使用介绍到了动态注册调用Context.registerReceiver进行注册。

ContextImpl

平时我们在activity中经常调用Context.startActivity()、Context.startService()、、Context.bindService()、Context.registerReceiver()、Context.sendBroadcast()等等,但我们使用Android Studio点进去之后发现Context是一个抽象类。有Android经验的同学都知道其实是调到了ContextImpl。那ContextImpl怎么跟Context关联起来的呢?

启动应用时发出的LaunchActivityItem会执行activity生命周期的内容,在ActivityThread.java的performLaunchActivity函数里。

ActivityThread.java

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...

    ContextImpl appContext = createBaseContextForActivity(r);
    ...

    try {
        ...

        appContext.setOuterContext(activity);
        activity.attach(appContext, this, getInstrumentation(), r.token,
                r.ident, app, r.intent, r.activityInfo, title, r.parent,
                r.embeddedID, r.lastNonConfigurationInstances, config,
                r.referrer, r.voiceInteractor, window, r.activityConfigCallback,
                r.assistToken, r.shareableActivityToken);

        ...

    } 

    ...

    return activity;
}

private ContextImpl createBaseContextForActivity(ActivityClientRecord r) {
    final int displayId = ActivityClient.getInstance().getDisplayId(r.token);
    ContextImpl appContext = ContextImpl.createActivityContext(
            this, r.packageInfo, r.activityInfo, r.token, displayId, r.overrideConfig);

    ...

    return appContext;
}
  • 调用createBaseContextForActivity创建ContextImpl。
ContextImpl.java

static ContextImpl createActivityContext(ActivityThread mainThread,
        LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId,
        Configuration overrideConfiguration) {
    ...
    ContextImpl context = new ContextImpl(null, mainThread, packageInfo, ContextParams.EMPTY,
            attributionTag, null, activityInfo.splitName, activityToken, null, 0, classLoader,
            null);
    ...
    return context;
}

ContextImpl.registerReceiver

ContextImpl.java

@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
    return registerReceiver(receiver, filter, null, null);
}

@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
        int flags) {
    return registerReceiver(receiver, filter, null, null, flags);
}

@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
        String broadcastPermission, Handler scheduler) {
    return registerReceiverInternal(receiver, getUserId(),
            filter, broadcastPermission, scheduler, getOuterContext(), 0);
}

@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
        String broadcastPermission, Handler scheduler, int flags) {
    return registerReceiverInternal(receiver, getUserId(),
            filter, broadcastPermission, scheduler, getOuterContext(), flags);
}

@Override
public Intent registerReceiverForAllUsers(BroadcastReceiver receiver,
        IntentFilter filter, String broadcastPermission, Handler scheduler) {
    return registerReceiverAsUser(receiver, UserHandle.ALL,
            filter, broadcastPermission, scheduler);
}

@Override
public Intent registerReceiverForAllUsers(BroadcastReceiver receiver,
        IntentFilter filter, String broadcastPermission, Handler scheduler, int flags) {
    return registerReceiverAsUser(receiver, UserHandle.ALL,
            filter, broadcastPermission, scheduler, flags);
}

@Override
public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
        IntentFilter filter, String broadcastPermission, Handler scheduler) {
    return registerReceiverInternal(receiver, user.getIdentifier(),
            filter, broadcastPermission, scheduler, getOuterContext(), 0);
}

@Override
public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
        IntentFilter filter, String broadcastPermission, Handler scheduler, int flags) {
    return registerReceiverInternal(receiver, user.getIdentifier(),
            filter, broadcastPermission, scheduler, getOuterContext(), flags);
}

平时我们注册广播调用最多的就是registerReceiver(BroadcastReceiver receiver, IntentFilter filter)

  • 将广播权限broadcastPermission设置成null
  • scheduler调度动态广播的线程设置成null

从上面的代码可以看到注册广播有很多方法,可以指定权限、用户ID、Handler、flags等,无论你调的是哪个接口,最终都是调到了registerReceiverInternal方法。

ContextImpl.registerReceiverInternal

ContextImpl.java

private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
        IntentFilter filter, String broadcastPermission,
        Handler scheduler, Context context, int flags) {
    IIntentReceiver rd = null;
    if (receiver != null) {
        if (mPackageInfo != null && context != null) {
            if (scheduler == null) {
                scheduler = mMainThread.getHandler();
            }
            rd = mPackageInfo.getReceiverDispatcher(
                receiver, context, scheduler,
                mMainThread.getInstrumentation(), true);
        } else {
            if (scheduler == null) {
                scheduler = mMainThread.getHandler();
            }
            rd = new LoadedApk.ReceiverDispatcher(
                    receiver, context, scheduler, null, true).getIIntentReceiver();
        }
    }
    try {
        ActivityThread thread = ActivityThread.currentActivityThread();
        Instrumentation instrumentation = thread.getInstrumentation();
        if (instrumentation.isInstrumenting()
                && ((flags & Context.RECEIVER_NOT_EXPORTED) == 0)) {
            flags = flags | Context.RECEIVER_EXPORTED;
        }
        final Intent intent = ActivityManager.getService().registerReceiverWithFeature(
                mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(),
                AppOpsManager.toReceiverId(receiver), rd, filter, broadcastPermission, userId,
                flags);
        if (intent != null) {
            intent.setExtrasClassLoader(getClassLoader());
            // TODO: determine at registration time if caller is
            // protecting themselves with signature permission
            intent.prepareToEnterProcess(ActivityThread.isProtectedBroadcast(intent),
                    getAttributionSource());
        }
        return intent;
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

看到这里就迷惑了,为什么receiver为空的时候不直接抛异常?难道还可以为空?带着这个问题,不知道后面在何处能找到答案。

  • 传入的广播调度器scheduler是null,那就直接使用主线程ActivityThread的handler(mH)作为调度器;
  • 从mPackageInfo中取得IIntentReceiver,并将该receiver放入LoadedApk mPackageInfo的mReceivers中
  • 调用的是AMS的registerReceiverWithFeature

LoadedApk.getReceiverDispatcher()

LoadedApk.java

public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
        Context context, Handler handler,
        Instrumentation instrumentation, boolean registered) {
    synchronized (mReceivers) {
        LoadedApk.ReceiverDispatcher rd = null;
        ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
        if (registered) {
            map = mReceivers.get(context);
            if (map != null) {
                rd = map.get(r);
            }
        }
        if (rd == null) {
            rd = new ReceiverDispatcher(r, context, handler,
                    instrumentation, registered);
            if (registered) {
                if (map == null) {
                    map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
                    mReceivers.put(context, map);
                }
                map.put(r, rd);
            }
        } else {
            rd.validate(context, handler);
        }
        rd.mForgotten = false;
        return rd.getIIntentReceiver();
    }
}

ReceiverDispatcher(BroadcastReceiver receiver, Context context,
        Handler activityThread, Instrumentation instrumentation,
        boolean registered) {
    if (activityThread == null) {
        throw new NullPointerException("Handler must not be null");
    }

    mIIntentReceiver = new InnerReceiver(this, !registered);
    mReceiver = receiver;
    mContext = context;
    mActivityThread = activityThread;
    mInstrumentation = instrumentation;
    mRegistered = registered;
    mLocation = new IntentReceiverLeaked(null);
    mLocation.fillInStackTrace();
}

IIntentReceiver getIIntentReceiver() {
    return mIIntentReceiver;
}
  • 从mReceivers取出对于该context的ReceiverDispatcher(map)
  • 从map取出对于该BroadcastReceiver的ReceiverDispatcher
  • 如果没有BroadcastReceiver对应的ReceiverDispatcher,根据BroadcastReceiver r新建一个ReceiverDispatcher,并存到mReceivers中。

一个BroadcastReceiver对应一个ReceiverDispatcher

退出进程的时候会用到mReceivers

AMS.registerReceiverWithFeature

public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
        String callerFeatureId, String receiverId, IIntentReceiver receiver,
        IntentFilter filter, String permission, int userId, int flags) {
    // Allow Sandbox process to register only unexported receivers.
    if ((flags & Context.RECEIVER_NOT_EXPORTED) != 0) {
        enforceNotIsolatedCaller("registerReceiver");
    } else if (mSdkSandboxSettings.isBroadcastReceiverRestrictionsEnforced()) {
        enforceNotIsolatedOrSdkSandboxCaller("registerReceiver");
    }
    ArrayList<Intent> stickyIntents = null;
    ProcessRecord callerApp = null;
    final boolean visibleToInstantApps
            = (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;

    int callingUid;
    int callingPid;
    boolean instantApp;
    synchronized(this) {
        if (caller != null) {
            callerApp = getRecordForAppLOSP(caller);
            if (callerApp == null) {
                throw new SecurityException(
                        "Unable to find app for caller " + caller
                        + " (pid=" + Binder.getCallingPid()
                        + ") when registering receiver " + receiver);
            }
            if (callerApp.info.uid != SYSTEM_UID
                    && !callerApp.getPkgList().containsKey(callerPackage)
                    && !"android".equals(callerPackage)) {
                throw new SecurityException("Given caller package " + callerPackage
                        + " is not running in process " + callerApp);
            }
            callingUid = callerApp.info.uid;
            callingPid = callerApp.getPid();
        } else {
            callerPackage = null;
            callingUid = Binder.getCallingUid();
            callingPid = Binder.getCallingPid();
        }

        instantApp = isInstantApp(callerApp, callerPackage, callingUid);
        userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
                ALLOW_FULL_ONLY, "registerReceiver", callerPackage);

        Iterator<String> actions = filter.actionsIterator();
        if (actions == null) {
            ArrayList<String> noAction = new ArrayList<String>(1);
            noAction.add(null);
            actions = noAction.iterator();
        }
        boolean onlyProtectedBroadcasts = true;

        // Collect stickies of users and check if broadcast is only registered for protected
        // broadcasts
        int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
        while (actions.hasNext()) {
            String action = actions.next();
            for (int id : userIds) {
                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>();
                        }
                        stickyIntents.addAll(intents);
                    }
                }
            }
            if (onlyProtectedBroadcasts) {
                try {
                    onlyProtectedBroadcasts &=
                            AppGlobals.getPackageManager().isProtectedBroadcast(action);
                } catch (RemoteException e) {
                    onlyProtectedBroadcasts = false;
                    Slog.w(TAG, "Remote exception", e);
                }
            }
        }

        // If the change is enabled, but neither exported or not exported is set, we need to log
        // an error so the consumer can know to explicitly set the value for their flag.
        // If the caller is registering for a sticky broadcast with a null receiver, we won't
        // require a flag
        final boolean explicitExportStateDefined =
                (flags & (Context.RECEIVER_EXPORTED | Context.RECEIVER_NOT_EXPORTED)) != 0;
        if (((flags & Context.RECEIVER_EXPORTED) != 0) && (
                (flags & Context.RECEIVER_NOT_EXPORTED) != 0)) {
            throw new IllegalArgumentException(
                    "Receiver can't specify both RECEIVER_EXPORTED and RECEIVER_NOT_EXPORTED"
                            + "flag");
        }

        // Don't enforce the flag check if we're EITHER registering for only protected
        // broadcasts, or the receiver is null (a sticky broadcast). Sticky broadcasts should
        // not be used generally, so we will be marking them as exported by default
        final boolean requireExplicitFlagForDynamicReceivers = CompatChanges.isChangeEnabled(
                DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED, callingUid);
        if (!onlyProtectedBroadcasts) {
            if (receiver == null && !explicitExportStateDefined) {
                // sticky broadcast, no flag specified (flag isn't required)
                flags |= Context.RECEIVER_EXPORTED;
            } else if (requireExplicitFlagForDynamicReceivers && !explicitExportStateDefined) {
                throw new SecurityException(
                        callerPackage + ": One of RECEIVER_EXPORTED or "
                                + "RECEIVER_NOT_EXPORTED should be specified when a receiver "
                                + "isn't being registered exclusively for system broadcasts");
                // Assume default behavior-- flag check is not enforced
            } else if (!requireExplicitFlagForDynamicReceivers && (
                    (flags & Context.RECEIVER_NOT_EXPORTED) == 0)) {
                // Change is not enabled, assume exported unless otherwise specified.
                flags |= Context.RECEIVER_EXPORTED;
            }
        } else if ((flags & Context.RECEIVER_NOT_EXPORTED) == 0) {
            flags |= Context.RECEIVER_EXPORTED;
        }
    }

    // Dynamic receivers are exported by default for versions prior to T
    final boolean exported = (flags & Context.RECEIVER_EXPORTED) != 0;

    ArrayList<Intent> allSticky = null;
    if (stickyIntents != null) {
        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);
            // Don't provided intents that aren't available to instant apps.
            if (instantApp &&
                    (intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
                continue;
            }
            // If intent has scheme "content", it will need to access
            // provider that needs to lock mProviderMap in ActivityThread
            // and also it may need to wait application response, so we
            // cannot lock ActivityManagerService here.
            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;
    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Register receiver " + filter + ": " + sticky);
    if (receiver == null) {
        return sticky;
    }

    // SafetyNet logging for b/177931370. If any process other than system_server tries to
    // listen to this broadcast action, then log it.
    if (callingPid != Process.myPid()) {
        if (filter.hasAction("com.android.server.net.action.SNOOZE_WARNING")
                || filter.hasAction("com.android.server.net.action.SNOOZE_RAPID")) {
            EventLog.writeEvent(0x534e4554, "177931370", callingUid, "");
        }
    }

    synchronized (this) {
        IApplicationThread thread;
        if (callerApp != null && ((thread = callerApp.getThread()) == null
                || thread.asBinder() != caller.asBinder())) {
            // Original caller already died
            return null;
        }
        ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
        if (rl == null) {
            rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                    userId, receiver);
            if (rl.app != null) {
                final int totalReceiversForApp = rl.app.mReceivers.numberOfReceivers();
                if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) {
                    throw new IllegalStateException("Too many receivers, total of "
                            + totalReceiversForApp + ", registered for pid: "
                            + rl.pid + ", callerPackage: " + callerPackage);
                }
                rl.app.mReceivers.addReceiver(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, callerFeatureId,
                receiverId, permission, callingUid, userId, instantApp, visibleToInstantApps,
                exported);
        if (rl.containsFilter(filter)) {
            Slog.w(TAG, "Receiver with filter " + filter
                    + " already registered for pid " + rl.pid
                    + ", callerPackage is " + callerPackage);
        } else {
            rl.add(bf);
            if (!bf.debugCheck()) {
                Slog.w(TAG, "==> For Dynamic broadcast");
            }
            mReceiverResolver.addFilter(getPackageManagerInternal().snapshot(), bf);
        }

        // Enqueue broadcasts for all existing stickies that match
        // this filter.
        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);
                BroadcastQueue queue = broadcastQueueForIntent(intent);
                BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                        null, null, -1, -1, false, null, null, null, null, OP_NONE, null,
                        receivers, null, 0, null, null, false, true, true, -1, false, null,
                        false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);
                queue.enqueueParallelBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();
            }
        }

        return sticky;
    }
}

上面为这个函数的完整代码,下面我们从几个方面来分析:

入参

public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
        String callerFeatureId, String receiverId, IIntentReceiver receiver,
        IntentFilter filter, String permission, int userId, int flags)
  • IApplicationThread caller = mMainThread.getApplicationThread(); //应用的ApplicationThread
  • String callerPackage = mBasePackageName; //是调用者的包名
  • IIntentReceiver receiver = rd; //就是LoadedApk.ReceiverDispatcher用户接受广播的地方
  • IntentFilter filter = filter; //是意图过滤器
  • String permission = broadcastPermission; //是发送这个广播需要的权限,一般不设置,
  • int userId = userId; //用户ID

判断权限

// Allow Sandbox process to register only unexported receivers.
if ((flags & Context.RECEIVER_NOT_EXPORTED) != 0) {
    enforceNotIsolatedCaller("registerReceiver");
} else if (mSdkSandboxSettings.isBroadcastReceiverRestrictionsEnforced()) {
    enforceNotIsolatedOrSdkSandboxCaller("registerReceiver");
}

Isolated、Sandbox 进程不允许注册。

初始化

int callingUid;
int callingPid;
boolean instantApp;
synchronized(this) {
    if (caller != null) {
        callerApp = getRecordForAppLOSP(caller);
        if (callerApp == null) {
            throw new SecurityException(
                    "Unable to find app for caller " + caller
                    + " (pid=" + Binder.getCallingPid()
                    + ") when registering receiver " + receiver);
        }
        if (callerApp.info.uid != SYSTEM_UID
                && !callerApp.getPkgList().containsKey(callerPackage)
                && !"android".equals(callerPackage)) {
            throw new SecurityException("Given caller package " + callerPackage
                    + " is not running in process " + callerApp);
        }
        callingUid = callerApp.info.uid;
        callingPid = callerApp.getPid();
    } else {
        callerPackage = null;
        callingUid = Binder.getCallingUid();
        callingPid = Binder.getCallingPid();
    }

    instantApp = isInstantApp(callerApp, callerPackage, callingUid);
    userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
            ALLOW_FULL_ONLY, "registerReceiver", callerPackage);
    ...
}
  • 通过getRecordForAppLOSP获取callerApp,就可以根据callerApp获取到调用者的uid、pid信息
  • 判断是不是instant app
  • 如果是callingUid、userId同一个用户组,则直接返回userId。

Android Instant App 这是一种用户无需安装即可运行 Android 应用的全新方式:基本思路是有一个空壳APK+一个干活的APK,空壳APK classloader干活的APK。

所以干活的APK不需要事先安装应用,开发者就需要将空壳APK做好下载业务,下载完成后重新加载dex即可。

获取action

//遍历IntentFilter中包含的所有action
Iterator<String> actions = filter.actionsIterator();
if (actions == null) {
    //如果没有action,则放入一个null的noAction到actions中,确保actions不为null
    ArrayList<String> noAction = new ArrayList<String>(1);
    noAction.add(null);
    actions = noAction.iterator();
}
boolean onlyProtectedBroadcasts = true;

// Collect stickies of users and check if broadcast is only registered for protected
// broadcasts
int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
//遍历所有的action
while (actions.hasNext()) {
    String action = actions.next();
    for (int id : userIds) {
        //遍历mStickyBroadcasts已经发送了的粘性广播列表stickies
        ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
        if (stickies != null) {
            //获取这个动态注册接受者action的粘性广播
            ArrayList<Intent> intents = stickies.get(action);
            //如果系统发送过这个action的粘性广播
            if (intents != null) {
                if (stickyIntents == null) {
                    stickyIntents = new ArrayList<Intent>();
                }
                //则将粘性广播intents全部放入stickyIntents
                stickyIntents.addAll(intents);
            }
        }
    }
    if (onlyProtectedBroadcasts) {
        try {
            onlyProtectedBroadcasts &=
                    AppGlobals.getPackageManager().isProtectedBroadcast(action);
        } catch (RemoteException e) {
            onlyProtectedBroadcasts = false;
            Slog.w(TAG, "Remote exception", e);
        }
    }
}

ArrayList<Intent> allSticky = null;
//如果之前已经发送过这个action的粘性广播,则stickyIntents不为null,否则为null
if (stickyIntents != null) {
    final ContentResolver resolver = mContext.getContentResolver();
    // Look for any matching sticky broadcasts...
    //遍历粘性广播的Intent:stickyIntents
    for (int i = 0, N = stickyIntents.size(); i < N; i++) {
        Intent intent = stickyIntents.get(i);
        // Don't provided intents that aren't available to instant apps.
        //如果是instantApp,而且没有单独设置接受粘性广播FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS
        //则默认是处理粘性广播的
        if (instantApp &&
                (intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
            continue;
        }
        // If intent has scheme "content", it will need to access
        // provider that needs to lock mProviderMap in ActivityThread
        // and also it may need to wait application response, so we
        // cannot lock ActivityManagerService here.
        //匹配一下注册广播的filter,是否和intent一致,如果大于0则表示匹配成功
        if (filter.match(resolver, intent, true, TAG) >= 0) {
            if (allSticky == null) {
                allSticky = new ArrayList<Intent>();
            }
            //如果匹配成功则将该粘性广播intent保存在allSticky
            allSticky.add(intent);
        }
    }
}
  • 遍历IntentFilter中包含的所有action
  • 遍历所有的action,将粘性广播intents全部放入stickyIntents
  • 遍历粘性广播的stickyIntents,匹配一下注册广播的filter,是否和intent一致

receiver为空

// The first sticky in the list is returned directly back to the client.
//取得匹配成功后的第一个粘性广播sticky
Intent sticky = allSticky != null ? allSticky.get(0) : null;
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Register receiver " + filter + ": " + sticky);
// 判断receiver是否为空,如果为空则直接返回找到的对应Sticky Intent。
if (receiver == null) {
    return sticky;
}

// SafetyNet logging for b/177931370. If any process other than system_server tries to
// listen to this broadcast action, then log it.
if (callingPid != Process.myPid()) {
    if (filter.hasAction("com.android.server.net.action.SNOOZE_WARNING")
            || filter.hasAction("com.android.server.net.action.SNOOZE_RAPID")) {
        EventLog.writeEvent(0x534e4554, "177931370", callingUid, "");
    }
}

如果receiver为空则直接返回找到的对应Sticky Intent。想起来前面ContextImpl.registerReceiverInternal提到receiver为空的问题了吧。

正常情况下receiver是不为空的,但是有时候为了获取粘性广播的一些信息(比如电池信息),可以将receiver设为空,只为了从返回的Sticky Intent中获取这些信息。

这时的注册广播可以写成这种形式,但是注意,这种形式只能在注册的时候获得一次信息,而不会有后续的继续监听。

mBatteryBroadcast = mContext.registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));

保存receiver

synchronized (this) {
    //取得callerApp的IApplicationThread应用线程
    IApplicationThread thread;
    if (callerApp != null && ((thread = callerApp.getThread()) == null
            || thread.asBinder() != caller.asBinder())) {
        // Original caller already died
        //如果callerApp没有IApplicationThread(或者caller和callerApp的IApplicationThread不一致),
        // 则代表进程之前已经死掉了
        return null;
    }
    ///获取这个接受者receiver,是否已经保存在AMS的mRegisteredReceivers动态注册者列表里面
    ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
    if (rl == null) {//如果之前没有注册过(没有在mRegisteredReceivers中)
        //构建一个ReceiverList:传入参数是: AMS, callerApp, callingPid, callingUid, userId, receiver(接受者)
        rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                userId, receiver);
        if (rl.app != null) {//如果callerApp不为null,获取一下当前mReceivers
            final int totalReceiversForApp = rl.app.mReceivers.numberOfReceivers();
            if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) {//一个进程最多1000个接受者(动态)
                throw new IllegalStateException("Too many receivers, total of "
                        + totalReceiversForApp + ", registered for pid: "
                        + rl.pid + ", callerPackage: " + callerPackage);
            }
            //将ReceiverList rl添加到mReceivers(ProcessReceiverRecord.java)中(有点循环的感觉)
            rl.app.mReceivers.addReceiver(rl);
        } else {
            try {
                receiver.asBinder().linkToDeath(rl, 0);
            } catch (RemoteException e) {
                return sticky;
            }
            rl.linkedToDeath = true;
        }
        //mRegisteredReceivers保存了所有的动态注册的receiver
        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);
    }
    // ReceiverList rl接收列表 (ReceiverList extends ArrayList<BroadcastFilter>),它的元素是BroadcastFilter bf
    // BroadcastFilter bf广播过滤器
    // 上面只是把广播接收着receiver的一些信息保存在ReceiverList rl中,但是还没有把它和filter关联起来,
    // 这里就创建一个BroadcastFilter(bf)来把广播接收器列表rl和filter关联起来
    BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
            receiverId, permission, callingUid, userId, instantApp, visibleToInstantApps,
            exported);
    if (rl.containsFilter(filter)) {//如果ReceiverList rl已经包含这个filter,则不再加入
        Slog.w(TAG, "Receiver with filter " + filter
                + " already registered for pid " + rl.pid
                + ", callerPackage is " + callerPackage);
    } else {//如果ReceiverList rl之前没添加过BroadcastFilter(bf),则加入接收列表中
        rl.add(bf);
        if (!bf.debugCheck()) {
            Slog.w(TAG, "==> For Dynamic broadcast");
        }
        //同时添加bf到mReceiverResolver中去
        //该变量用于在broadcastIntentLocked分发广播的时候, 查询符合条件的动态注册的广播
        mReceiverResolver.addFilter(getPackageManagerInternal().snapshot(), bf);
    }
    ...
}
  • 判断应用是否死掉
  • mRegisteredReceivers.put(receiver.asBinder(), rl);保存所有的动态注册的receiver
  • mReceiverResolver.addFilter(getPackageManagerInternal().snapshot(), bf);

粘性广播

// Enqueue broadcasts for all existing stickies that match
// this filter.
if (allSticky != null) {//广播接受者注册的广播的是粘性广播
    //BroadcastFilter bf才是实际的接受者,接受者receivers只有一个BroadcastFilter bf,
    //也就是单发给BroadcastFilter bf
    ArrayList receivers = new ArrayList();
    receivers.add(bf);

    final int stickyCount = allSticky.size();
    //遍历匹配成功的粘性广播列表allSticky
    for (int i = 0; i < stickyCount; i++) {
        Intent intent = allSticky.get(i);
        //取出intent对应的广播队列
        BroadcastQueue queue = broadcastQueueForIntent(intent);
        BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                null, null, -1, -1, false, null, null, null, null, OP_NONE, null,
                receivers, null, 0, null, null, false, true, true, -1, false, null,
                false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);
        //粘性广播接受者注册后, 就放入mParallelBroadcasts中
        queue.enqueueParallelBroadcastLocked(r);
        //这里会马上处理刚才的平行广播队列,也就是达到注册了之后马上执行的效果
        queue.scheduleBroadcastsLocked();
    }
}

return sticky;

总结

  • 广播分发通过LoadedApk.ReceiverDispatcher.getIIntentReceiver获得的IIntentReceiver对象来实现的
  • 动态广播注册其实最终构建的是BroadcastFilter bf,并放入mReceiverResolver中去
  • 粘性广播注册的时候就会收到之前已经发送的粘性广播
  • 粘性广播注册可以不传入IIntentReceiver receiver,而获取一次信息
  • 广播处理如果没有特殊设定广播处理的Handler,默认在ActivityThread的主线程(mH)中执行,主线程卡住会导致广播处理的延迟(超时发生广播anr)。

思考

动态注册的广播没有在进程推出时解注册,经常会看到如下log:

*** has leaked IntentReceiver *** that was originally registered here. Are you missing a call to unregisterReceiver()

Android是怎么判断关闭的进程没有解注册的?我们从在activity退出流程分析:

ActivityManagerService.handleDestroyActivity

ActivityManagerService.java
public void handleDestroyActivity(ActivityClientRecord r, boolean finishing, int configChanges,
            boolean getNonConfigInstance, String reason) {
    ...
    Context c = r.activity.getBaseContext();
    if (c instanceof ContextImpl) {
        ((ContextImpl) c).scheduleFinalCleanup(r.activity.getClass().getName(), "Activity");
    }
    ...
}

ContextImpl.scheduleFinalCleanup

ContextImpl.java
@UnsupportedAppUsage
final void scheduleFinalCleanup(String who, String what) {
    mMainThread.scheduleContextCleanup(this, who, what);
}

这里的mMainThread就是ActivityThread

ActivityThread.scheduleContextCleanup

ActivityThread.java
final void scheduleContextCleanup(ContextImpl context, String who,
        String what) {
    ContextCleanupInfo cci = new ContextCleanupInfo();
    cci.context = context;
    cci.who = who;
    cci.what = what;
    sendMessage(H.CLEAN_UP_CONTEXT, cci);
}

class H extends Handler {
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case CLEAN_UP_CONTEXT:
                ContextCleanupInfo cci = (ContextCleanupInfo)msg.obj;
                cci.context.performFinalCleanup(cci.who, cci.what);
                break;
        }
    }
}

ContextImpl.performFinalCleanup

ContextImpl.java
final void performFinalCleanup(String who, String what) {
    //Log.i(TAG, "Cleanup up context: " + this);
    mPackageInfo.removeContextRegistrations(getOuterContext(), who, what);
    if (mContextType == CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI
            && mToken instanceof WindowTokenClient) {
        mMainThread.onSystemUiContextCleanup(this);
    }
}

mPackageInfo就是LoadedApk。

LoadedApk.removeContextRegistrations

LoadedApk.java

public void removeContextRegistrations(Context context,
        String who, String what) {
    final boolean reportRegistrationLeaks = StrictMode.vmRegistrationLeaksEnabled();
    synchronized (mReceivers) {
        //从mReceivers移除掉并返回ArrayMap<BroadcastReceiver, ReceiverDispatcher>
        ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> rmap =
                mReceivers.remove(context);
        if (rmap != null) {//rmap不为空,则表示进程退出时没有解注册
            for (int i = 0; i < rmap.size(); i++) {
                LoadedApk.ReceiverDispatcher rd = rmap.valueAt(i);
                IntentReceiverLeaked leak = new IntentReceiverLeaked(
                        what + " " + who + " has leaked IntentReceiver "
                        + rd.getIntentReceiver() + " that was " +
                        "originally registered here. Are you missing a " +
                        "call to unregisterReceiver()?");
                leak.setStackTrace(rd.getLocation().getStackTrace());
                Slog.e(ActivityThread.TAG, leak.getMessage(), leak);
                if (reportRegistrationLeaks) {
                    StrictMode.onIntentReceiverLeaked(leak);
                }
                try {
                    //调用AMS解注册
                    ActivityManager.getService().unregisterReceiver(
                            rd.getIIntentReceiver());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
        }
        mUnregisteredReceivers.remove(context);
    }

    ...
}
  • mReceivers在前面动态注册流程LoadedApk.getReceiverDispatcher()中
  • 判断是否解注册,如果没有则从mReceivers移除并调用AMS解注册

ActivityManagerService.unregisterReceiver

public void unregisterReceiver(IIntentReceiver receiver) {
    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Unregister receiver: " + receiver);

    final long origId = Binder.clearCallingIdentity();
    try {
        boolean doTrim = false;

        synchronized(this) {
            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.processNextBroadcastLocked(/* frommsg */ false,
                                /* skipOomAdj */ true);
                    }
                }

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

            // If we actually concluded any broadcasts, we might now be able
            // to trim the recipients' apps from our working set
            if (doTrim) {
                trimApplicationsLocked(false, OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
                return;
            }
        }

    } finally {
        Binder.restoreCallingIdentity(origId);
    }
}

void removeReceiverLocked(ReceiverList rl) {
    mRegisteredReceivers.remove(rl.receiver.asBinder());
    for (int i = rl.size() - 1; i >= 0; i--) {
        mReceiverResolver.removeFilter(rl.get(i));
    }
}

前面提到过AMS把所有动态注册的receiver保存到mRegisteredReceivers,所以解注册的时候移除掉就可以了。

发送广播流程

发送广播是在Activity或Service中调用sendBroadcast()方法,而Activity或Service都间接继承于Context抽象类,真正干活是交给ContextImpl类。

ContextImpl.sendBroadcast

ContextImpl.java

@Override
public void sendBroadcast(Intent intent) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
        intent.prepareToLeaveProcess(this);
        ActivityManager.getService().broadcastIntentWithFeature(
                mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
                null, Activity.RESULT_OK, null, null, null, null /*excludedPermissions=*/,
                null, AppOpsManager.OP_NONE, null, false, false, getUserId());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

@Override
public void sendBroadcast(Intent intent, String receiverPermission) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    String[] receiverPermissions = receiverPermission == null ? null
            : new String[] {receiverPermission};
    try {
        intent.prepareToLeaveProcess(this);
        ActivityManager.getService().broadcastIntentWithFeature(
                mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
                null, Activity.RESULT_OK, null, null, receiverPermissions,
                null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, false, false,
                getUserId());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

@Override
public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
        intent.prepareToLeaveProcess(this);
        ActivityManager.getService().broadcastIntentWithFeature(
                mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
                null, Activity.RESULT_OK, null, null, receiverPermissions,
                null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, false, false,
                getUserId());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

@Override
public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions,
        Bundle options) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
        intent.prepareToLeaveProcess(this);
        ActivityManager.getService().broadcastIntentWithFeature(
                mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
                null, Activity.RESULT_OK, null, null, receiverPermissions,
                null /*excludedPermissions=*/, null /*excludedPackages*/,
                AppOpsManager.OP_NONE, options, false, false, getUserId());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

@Override
public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
        String[] receiverPermissions) {
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
        intent.prepareToLeaveProcess(this);
        ActivityManager.getService().broadcastIntentWithFeature(
                mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
                null, Activity.RESULT_OK, null, null, receiverPermissions,
                null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, false, false,
                user.getIdentifier());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

@Override
public void sendBroadcastMultiplePermissions(Intent intent, String[] receiverPermissions,
        String[] excludedPermissions, String[] excludedPackages) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    try {
        intent.prepareToLeaveProcess(this);
        ActivityManager.getService().broadcastIntentWithFeature(
                mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
                null, Activity.RESULT_OK, null, null, receiverPermissions, excludedPermissions,
                excludedPackages, AppOpsManager.OP_NONE, null, false, false, getUserId());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

@Override
public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    String[] receiverPermissions = receiverPermission == null ? null
            : new String[] {receiverPermission};
    String[] excludedPermissions = null;
    if (options != null) {
        String[] receiverPermissionsBundle = options.getStringArray(
                BroadcastOptions.KEY_REQUIRE_ALL_OF_PERMISSIONS);
        if (receiverPermissionsBundle != null) {
            receiverPermissions = receiverPermissionsBundle;
        }
        excludedPermissions = options.getStringArray(
                BroadcastOptions.KEY_REQUIRE_NONE_OF_PERMISSIONS);
    }
    try {
        intent.prepareToLeaveProcess(this);
        ActivityManager.getService().broadcastIntentWithFeature(
                mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
                null, Activity.RESULT_OK, null, null, receiverPermissions,
                excludedPermissions, null, AppOpsManager.OP_NONE, options, false, false,
                getUserId());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

@Override
public void sendBroadcast(Intent intent, String receiverPermission, int appOp) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    String[] receiverPermissions = receiverPermission == null ? null
            : new String[] {receiverPermission};
    try {
        intent.prepareToLeaveProcess(this);
        ActivityManager.getService().broadcastIntentWithFeature(
                mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
                null, Activity.RESULT_OK, null, null, receiverPermissions,
                null /*excludedPermissions=*/, null, appOp, null, false, false, getUserId());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

@Override
public void sendOrderedBroadcast(Intent intent, String receiverPermission) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    String[] receiverPermissions = receiverPermission == null ? null
            : new String[] {receiverPermission};
    try {
        intent.prepareToLeaveProcess(this);
        ActivityManager.getService().broadcastIntentWithFeature(
                mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
                null, Activity.RESULT_OK, null, null, receiverPermissions,
                null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, true, false,
                getUserId());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

@Override
public void sendOrderedBroadcast(Intent intent,
        String receiverPermission, BroadcastReceiver resultReceiver,
        Handler scheduler, int initialCode, String initialData,
        Bundle initialExtras) {
    sendOrderedBroadcast(intent, receiverPermission, AppOpsManager.OP_NONE,
            resultReceiver, scheduler, initialCode, initialData, initialExtras, null);
}

@Override
public void sendOrderedBroadcast(Intent intent,
        String receiverPermission, Bundle options, BroadcastReceiver resultReceiver,
        Handler scheduler, int initialCode, String initialData,
        Bundle initialExtras) {
    sendOrderedBroadcast(intent, receiverPermission, AppOpsManager.OP_NONE,
            resultReceiver, scheduler, initialCode, initialData, initialExtras, options);
}

@Override
public void sendOrderedBroadcast(Intent intent,
        String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
        Handler scheduler, int initialCode, String initialData,
        Bundle initialExtras) {
    sendOrderedBroadcast(intent, receiverPermission, appOp,
            resultReceiver, scheduler, initialCode, initialData, initialExtras, null);
}

void sendOrderedBroadcast(Intent intent,
        String receiverPermission, int appOp, BroadcastReceiver resultReceiver,
        Handler scheduler, int initialCode, String initialData,
        Bundle initialExtras, Bundle options) {
    warnIfCallingFromSystemProcess();
    IIntentReceiver rd = null;
    if (resultReceiver != null) {
        if (mPackageInfo != null) {
            if (scheduler == null) {
                scheduler = mMainThread.getHandler();
            }
            rd = mPackageInfo.getReceiverDispatcher(
                resultReceiver, getOuterContext(), scheduler,
                mMainThread.getInstrumentation(), false);
        } else {
            if (scheduler == null) {
                scheduler = mMainThread.getHandler();
            }
            rd = new LoadedApk.ReceiverDispatcher(
                    resultReceiver, getOuterContext(), scheduler, null, false).getIIntentReceiver();
        }
    }
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    String[] receiverPermissions = receiverPermission == null ? null
            : new String[] {receiverPermission};
    try {
        intent.prepareToLeaveProcess(this);
        ActivityManager.getService().broadcastIntentWithFeature(
                mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
                rd, initialCode, initialData, initialExtras, receiverPermissions,
                null /*excludedPermissions=*/, null, appOp, options, true, false, getUserId());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

从ContextImpl.java代码可以看出出来,发送广播的函数很多:

  • 普通的广播

sendBroadcast()或者sendBroadcastAsUser(),默认是当前userId,带有“AsUser”的是发送给特定的user。

  • 带权限的广播

endBroadcastMultiplePermissions()或者sendBroadcastAsUserMultiplePermissions()。

  • 有序的广播

sendOrderedBroadcast()或者sendOrderedBroadcastAsUser(),发送有序广播是一个接收完成下一个才能接收,接收者一个个按顺序接收。

  • 粘性广播

sendStickyBroadcast()或者sendStickyBroadcastAsUser()或者,粘性广播是注册者注册了就马上能收到该类型(之前已经发送的粘性广播)的广播,接收者的注册不需要在发送者的前面。

  • 粘性有序广播

sendStickyOrderedBroadcast()或者sendStickyOrderedBroadcastAsUser()。

这些接口最终都是调用到了AMS的broadcastIntentWithFeature()函数。

AMS.broadcastIntentWithFeature

@Override
public final int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId,
        Intent intent, String resolvedType, IIntentReceiver resultTo,
        int resultCode, String resultData, Bundle resultExtras,
        String[] requiredPermissions, String[] excludedPermissions,
        String[] excludedPackages, int appOp, Bundle bOptions,
        boolean serialized, boolean sticky, int userId) {
    enforceNotIsolatedCaller("broadcastIntent");
    synchronized(this) {
        intent = verifyBroadcastLocked(intent);

        final ProcessRecord callerApp = getRecordForAppLOSP(caller);
        final int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();

        final long origId = Binder.clearCallingIdentity();
        try {
            return broadcastIntentLocked(callerApp,
                    callerApp != null ? callerApp.info.packageName : null, callingFeatureId,
                    intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                    requiredPermissions, excludedPermissions, excludedPackages, appOp, bOptions,
                    serialized, sticky, callingPid, callingUid, callingUid, callingPid, userId);
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }
}

通过getRecordForAppLOSP获取callerApp,就可以根据callerApp获取到调用者的packageName、uid、pid等信息,接着调用broadcastIntentLocked()。

AMS.broadcastIntentLocked

 final int broadcastIntentLocked(ProcessRecord callerApp,
        String callerPackage, String callerFeatureId, Intent intent, String resolvedType,
        IIntentReceiver resultTo, int resultCode, String resultData,
        Bundle resultExtras, String[] requiredPermissions, String[] excludedPermissions,
        String[] excludedPackages, int appOp, Bundle bOptions, boolean ordered,
        boolean sticky, int callingPid,
        int callingUid, int realCallingUid, int realCallingPid, int userId) {
    return broadcastIntentLocked(callerApp, callerPackage, callerFeatureId, intent,
            resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions,
            excludedPermissions, excludedPackages, appOp, bOptions, ordered, sticky, callingPid,
            callingUid, realCallingUid, realCallingPid, userId,
            false /* allowBackgroundActivityStarts */,
            null /* tokenNeededForBackgroundActivityStarts */, null /* broadcastAllowList */);
}

@GuardedBy("this")
final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage,
        @Nullable String callerFeatureId, Intent intent, String resolvedType,
        IIntentReceiver resultTo, int resultCode, String resultData,
        Bundle resultExtras, String[] requiredPermissions,
        String[] excludedPermissions, String[] excludedPackages, int appOp, Bundle bOptions,
        boolean ordered, boolean sticky, int callingPid, int callingUid,
        int realCallingUid, int realCallingPid, int userId,
        boolean allowBackgroundActivityStarts,
        @Nullable IBinder backgroundActivityStartsToken,
        @Nullable int[] broadcastAllowList) {
    intent = new Intent(intent);

    final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
    // Instant Apps cannot use FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS
    if (callerInstantApp) {
        intent.setFlags(intent.getFlags() & ~Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
    }

    if (userId == UserHandle.USER_ALL && broadcastAllowList != null) {
            Slog.e(TAG, "broadcastAllowList only applies when sending to individual users. "
                    + "Assuming restrictive whitelist.");
            broadcastAllowList = new int[]{};
    }

    // By default broadcasts do not go to stopped apps.
    intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

    // If we have not finished booting, don't allow this to launch new processes.
    if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
    }

    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
            (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
            + " ordered=" + ordered + " userid=" + userId);
    if ((resultTo != null) && !ordered) {
        Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
    }

    userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
            ALLOW_NON_FULL, "broadcast", callerPackage);

    // Make sure that the user who is receiving this broadcast or its parent is running.
    // If not, we will just skip it. Make an exception for shutdown broadcasts, upgrade steps.
    if (userId != UserHandle.USER_ALL && !mUserController.isUserOrItsParentRunning(userId)) {
        if ((callingUid != SYSTEM_UID
                || (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)
                && !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
            Slog.w(TAG, "Skipping broadcast of " + intent
                    + ": user " + userId + " and its parent (if any) are stopped");
            return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
        }
    }

    final String action = intent.getAction();
    BroadcastOptions brOptions = null;
    if (bOptions != null) {
        brOptions = new BroadcastOptions(bOptions);
        if (brOptions.getTemporaryAppAllowlistDuration() > 0) {
            // See if the caller is allowed to do this.  Note we are checking against
            // the actual real caller (not whoever provided the operation as say a
            // PendingIntent), because that who is actually supplied the arguments.
            if (checkComponentPermission(CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
                    realCallingPid, realCallingUid, -1, true)
                    != PackageManager.PERMISSION_GRANTED
                    && checkComponentPermission(START_ACTIVITIES_FROM_BACKGROUND,
                    realCallingPid, realCallingUid, -1, true)
                    != PackageManager.PERMISSION_GRANTED
                    && checkComponentPermission(START_FOREGROUND_SERVICES_FROM_BACKGROUND,
                    realCallingPid, realCallingUid, -1, true)
                    != PackageManager.PERMISSION_GRANTED) {
                String msg = "Permission Denial: " + intent.getAction()
                        + " broadcast from " + callerPackage + " (pid=" + callingPid
                        + ", uid=" + callingUid + ")"
                        + " requires "
                        + CHANGE_DEVICE_IDLE_TEMP_WHITELIST + " or "
                        + START_ACTIVITIES_FROM_BACKGROUND + " or "
                        + START_FOREGROUND_SERVICES_FROM_BACKGROUND;
                Slog.w(TAG, msg);
                throw new SecurityException(msg);
            }
        }
        if (brOptions.isDontSendToRestrictedApps()
                && !isUidActiveLOSP(callingUid)
                && isBackgroundRestrictedNoCheck(callingUid, callerPackage)) {
            Slog.i(TAG, "Not sending broadcast " + action + " - app " + callerPackage
                    + " has background restrictions");
            return ActivityManager.START_CANCELED;
        }
        if (brOptions.allowsBackgroundActivityStarts()) {
            // See if the caller is allowed to do this.  Note we are checking against
            // the actual real caller (not whoever provided the operation as say a
            // PendingIntent), because that who is actually supplied the arguments.
            if (checkComponentPermission(
                    android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
                    realCallingPid, realCallingUid, -1, true)
                    != PackageManager.PERMISSION_GRANTED) {
                String msg = "Permission Denial: " + intent.getAction()
                        + " broadcast from " + callerPackage + " (pid=" + callingPid
                        + ", uid=" + callingUid + ")"
                        + " requires "
                        + android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
                Slog.w(TAG, msg);
                throw new SecurityException(msg);
            } else {
                allowBackgroundActivityStarts = true;
                // We set the token to null since if it wasn't for it we'd allow anyway here
                backgroundActivityStartsToken = null;
            }
        }

        if (brOptions.getIdForResponseEvent() > 0) {
            enforcePermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS,
                    callingPid, callingUid, "recordResponseEventWhileInBackground");
        }
    }

    // Verify that protected broadcasts are only being sent by system code,
    // and that system code is only sending protected broadcasts.
    final boolean isProtectedBroadcast;
    try {
        isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
    } catch (RemoteException e) {
        Slog.w(TAG, "Remote exception", e);
        return ActivityManager.BROADCAST_SUCCESS;
    }

    final boolean isCallerSystem;
    switch (UserHandle.getAppId(callingUid)) {
        case ROOT_UID:
        case SYSTEM_UID:
        case PHONE_UID:
        case BLUETOOTH_UID:
        case NFC_UID:
        case SE_UID:
        case NETWORK_STACK_UID:
            isCallerSystem = true;
            break;
        default:
            isCallerSystem = (callerApp != null) && callerApp.isPersistent();
            break;
    }

    // First line security check before anything else: stop non-system apps from
    // sending protected broadcasts.
    if (!isCallerSystem) {
        if (isProtectedBroadcast) {
            String msg = "Permission Denial: not allowed to send broadcast "
                    + action + " from pid="
                    + callingPid + ", uid=" + callingUid;
            Slog.w(TAG, msg);
            throw new SecurityException(msg);

        } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
                || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
            // Special case for compatibility: we don't want apps to send this,
            // but historically it has not been protected and apps may be using it
            // to poke their own app widget.  So, instead of making it protected,
            // just limit it to the caller.
            if (callerPackage == null) {
                String msg = "Permission Denial: not allowed to send broadcast "
                        + action + " from unknown caller.";
                Slog.w(TAG, msg);
                throw new SecurityException(msg);
            } else if (intent.getComponent() != null) {
                // They are good enough to send to an explicit component...  verify
                // it is being sent to the calling app.
                if (!intent.getComponent().getPackageName().equals(
                        callerPackage)) {
                    String msg = "Permission Denial: not allowed to send broadcast "
                            + action + " to "
                            + intent.getComponent().getPackageName() + " from "
                            + callerPackage;
                    Slog.w(TAG, msg);
                    throw new SecurityException(msg);
                }
            } else {
                // Limit broadcast to their own package.
                intent.setPackage(callerPackage);
            }
        }
    }

    boolean timeoutExempt = false;

    if (action != null) {
        if (getBackgroundLaunchBroadcasts().contains(action)) {
            if (DEBUG_BACKGROUND_CHECK) {
                Slog.i(TAG, "Broadcast action " + action + " forcing include-background");
            }
            intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
        }

        if (Process.isSdkSandboxUid(realCallingUid)) {
            SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager(
                    SdkSandboxManagerLocal.class);
            if (sdkSandboxManagerLocal == null) {
                throw new IllegalStateException("SdkSandboxManagerLocal not found when sending"
                        + " a broadcast from an SDK sandbox uid.");
            }
            sdkSandboxManagerLocal.enforceAllowedToSendBroadcast(intent);
        }

        switch (action) {
            case Intent.ACTION_MEDIA_SCANNER_SCAN_FILE:
                UserManagerInternal umInternal = LocalServices.getService(
                        UserManagerInternal.class);
                UserInfo userInfo = umInternal.getUserInfo(userId);
                if (userInfo != null && userInfo.isCloneProfile()) {
                    userId = umInternal.getProfileParentId(userId);
                }
                break;
            case Intent.ACTION_UID_REMOVED:
            case Intent.ACTION_PACKAGE_REMOVED:
            case Intent.ACTION_PACKAGE_CHANGED:
            case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
            case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
            case Intent.ACTION_PACKAGES_SUSPENDED:
            case Intent.ACTION_PACKAGES_UNSUSPENDED:
                // Handle special intents: if this broadcast is from the package
                // manager about a package being removed, we need to remove all of
                // its activities from the history stack.
                if (checkComponentPermission(
                        android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
                        callingPid, callingUid, -1, true)
                        != PackageManager.PERMISSION_GRANTED) {
                    String msg = "Permission Denial: " + intent.getAction()
                            + " broadcast from " + callerPackage + " (pid=" + callingPid
                            + ", uid=" + callingUid + ")"
                            + " requires "
                            + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
                    Slog.w(TAG, msg);
                    throw new SecurityException(msg);
                }
                switch (action) {
                    case Intent.ACTION_UID_REMOVED:
                        final int uid = getUidFromIntent(intent);
                        if (uid >= 0) {
                            mBatteryStatsService.removeUid(uid);
                            if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
                                mAppOpsService.resetAllModes(UserHandle.getUserId(uid),
                                        intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME));
                            } else {
                                mAppOpsService.uidRemoved(uid);
                            }
                        }
                        break;
                    case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
                        // If resources are unavailable just force stop all those packages
                        // and flush the attribute cache as well.
                        String list[] =
                                intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
                        if (list != null && list.length > 0) {
                            for (int i = 0; i < list.length; i++) {
                                forceStopPackageLocked(list[i], -1, false, true, true,
                                        false, false, userId, "storage unmount");
                            }
                            mAtmInternal.cleanupRecentTasksForUser(UserHandle.USER_ALL);
                            sendPackageBroadcastLocked(
                                    ApplicationThreadConstants.EXTERNAL_STORAGE_UNAVAILABLE,
                                    list, userId);
                        }
                        break;
                    case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
                        mAtmInternal.cleanupRecentTasksForUser(UserHandle.USER_ALL);
                        break;
                    case Intent.ACTION_PACKAGE_REMOVED:
                    case Intent.ACTION_PACKAGE_CHANGED:
                        Uri data = intent.getData();
                        String ssp;
                        if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
                            boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(action);
                            final boolean replacing =
                                    intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
                            final boolean killProcess =
                                    !intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false);
                            final boolean fullUninstall = removed && !replacing;
                            if (removed) {
                                if (killProcess) {
                                    forceStopPackageLocked(ssp, UserHandle.getAppId(
                                            intent.getIntExtra(Intent.EXTRA_UID, -1)),
                                            false, true, true, false, fullUninstall, userId,
                                            removed ? "pkg removed" : "pkg changed");
                                    getPackageManagerInternal()
                                            .onPackageProcessKilledForUninstall(ssp);
                                } else {
                                    // Kill any app zygotes always, since they can't fork new
                                    // processes with references to the old code
                                    forceStopAppZygoteLocked(ssp, UserHandle.getAppId(
                                            intent.getIntExtra(Intent.EXTRA_UID, -1)),
                                            userId);
                                }
                                final int cmd = killProcess
                                        ? ApplicationThreadConstants.PACKAGE_REMOVED
                                        : ApplicationThreadConstants.PACKAGE_REMOVED_DONT_KILL;
                                sendPackageBroadcastLocked(cmd,
                                        new String[] {ssp}, userId);
                                if (fullUninstall) {
                                    mAppOpsService.packageRemoved(
                                            intent.getIntExtra(Intent.EXTRA_UID, -1), ssp);

                                    // Remove all permissions granted from/to this package
                                    mUgmInternal.removeUriPermissionsForPackage(ssp, userId,
                                            true, false);

                                    mAtmInternal.removeRecentTasksByPackageName(ssp, userId);

                                    mServices.forceStopPackageLocked(ssp, userId);
                                    mAtmInternal.onPackageUninstalled(ssp, userId);
                                    mBatteryStatsService.notePackageUninstalled(ssp);
                                }
                            } else {
                                if (killProcess) {
                                    final int extraUid = intent.getIntExtra(Intent.EXTRA_UID,
                                            -1);
                                    synchronized (mProcLock) {
                                        mProcessList.killPackageProcessesLSP(ssp,
                                                UserHandle.getAppId(extraUid),
                                                userId, ProcessList.INVALID_ADJ,
                                                ApplicationExitInfo.REASON_USER_REQUESTED,
                                                ApplicationExitInfo.SUBREASON_PACKAGE_UPDATE,
                                                "change " + ssp);
                                    }
                                }
                                cleanupDisabledPackageComponentsLocked(ssp, userId,
                                        intent.getStringArrayExtra(
                                                Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST));
                                mServices.schedulePendingServiceStartLocked(ssp, userId);
                            }
                        }
                        break;
                    case Intent.ACTION_PACKAGES_SUSPENDED:
                    case Intent.ACTION_PACKAGES_UNSUSPENDED:
                        final boolean suspended = Intent.ACTION_PACKAGES_SUSPENDED.equals(
                                intent.getAction());
                        final String[] packageNames = intent.getStringArrayExtra(
                                Intent.EXTRA_CHANGED_PACKAGE_LIST);
                        final int userIdExtra = intent.getIntExtra(
                                Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);

                        mAtmInternal.onPackagesSuspendedChanged(packageNames, suspended,
                                userIdExtra);
                        break;
                }
                break;
            case Intent.ACTION_PACKAGE_REPLACED:
            {
                final Uri data = intent.getData();
                final String ssp;
                if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
                    ApplicationInfo aInfo = null;
                    try {
                        aInfo = AppGlobals.getPackageManager()
                                .getApplicationInfo(ssp, STOCK_PM_FLAGS, userId);
                    } catch (RemoteException ignore) {}
                    if (aInfo == null) {
                        Slog.w(TAG, "Dropping ACTION_PACKAGE_REPLACED for non-existent pkg:"
                                + " ssp=" + ssp + " data=" + data);
                        return ActivityManager.BROADCAST_SUCCESS;
                    }
                    updateAssociationForApp(aInfo);
                    mAtmInternal.onPackageReplaced(aInfo);
                    mServices.updateServiceApplicationInfoLocked(aInfo);
                    sendPackageBroadcastLocked(ApplicationThreadConstants.PACKAGE_REPLACED,
                            new String[] {ssp}, userId);
                }
                break;
            }
            case Intent.ACTION_PACKAGE_ADDED:
            {
                // Special case for adding a package: by default turn on compatibility mode.
                Uri data = intent.getData();
                String ssp;
                if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
                    final boolean replacing =
                            intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
                    mAtmInternal.onPackageAdded(ssp, replacing);

                    try {
                        ApplicationInfo ai = AppGlobals.getPackageManager().
                                getApplicationInfo(ssp, STOCK_PM_FLAGS, 0);
                        mBatteryStatsService.notePackageInstalled(ssp,
                                ai != null ? ai.longVersionCode : 0);
                    } catch (RemoteException e) {
                    }
                }
                break;
            }
            case Intent.ACTION_PACKAGE_DATA_CLEARED:
            {
                Uri data = intent.getData();
                String ssp;
                if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
                    mAtmInternal.onPackageDataCleared(ssp, userId);
                }
                break;
            }
            case Intent.ACTION_TIMEZONE_CHANGED:
                // If this is the time zone changed action, queue up a message that will reset
                // the timezone of all currently running processes. This message will get
                // queued up before the broadcast happens.
                mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
                break;
            case Intent.ACTION_TIME_CHANGED:
                // EXTRA_TIME_PREF_24_HOUR_FORMAT is optional so we must distinguish between
                // the tri-state value it may contain and "unknown".
                // For convenience we re-use the Intent extra values.
                final int NO_EXTRA_VALUE_FOUND = -1;
                final int timeFormatPreferenceMsgValue = intent.getIntExtra(
                        Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT,
                        NO_EXTRA_VALUE_FOUND /* defaultValue */);
                // Only send a message if the time preference is available.
                if (timeFormatPreferenceMsgValue != NO_EXTRA_VALUE_FOUND) {
                    Message updateTimePreferenceMsg =
                            mHandler.obtainMessage(UPDATE_TIME_PREFERENCE_MSG,
                                    timeFormatPreferenceMsgValue, 0);
                    mHandler.sendMessage(updateTimePreferenceMsg);
                }
                mBatteryStatsService.noteCurrentTimeChanged();
                break;
            case ConnectivityManager.ACTION_CLEAR_DNS_CACHE:
                mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG);
                break;
            case Proxy.PROXY_CHANGE_ACTION:
                mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG));
                break;
            case android.hardware.Camera.ACTION_NEW_PICTURE:
            case android.hardware.Camera.ACTION_NEW_VIDEO:
                // In N we just turned these off; in O we are turing them back on partly,
                // only for registered receivers.  This will still address the main problem
                // (a spam of apps waking up when a picture is taken putting significant
                // memory pressure on the system at a bad point), while still allowing apps
                // that are already actively running to know about this happening.
                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
                break;
            case android.security.KeyChain.ACTION_TRUST_STORE_CHANGED:
                mHandler.sendEmptyMessage(HANDLE_TRUST_STORAGE_UPDATE_MSG);
                break;
            case "com.android.launcher.action.INSTALL_SHORTCUT":
                // As of O, we no longer support this broadcasts, even for pre-O apps.
                // Apps should now be using ShortcutManager.pinRequestShortcut().
                Log.w(TAG, "Broadcast " + action
                        + " no longer supported. It will not be delivered.");
                return ActivityManager.BROADCAST_SUCCESS;
            case Intent.ACTION_PRE_BOOT_COMPLETED:
                timeoutExempt = true;
                break;
            case Intent.ACTION_CLOSE_SYSTEM_DIALOGS:
                if (!mAtmInternal.checkCanCloseSystemDialogs(callingPid, callingUid,
                        callerPackage)) {
                    // Returning success seems to be the pattern here
                    return ActivityManager.BROADCAST_SUCCESS;
                }
                break;
        }

        if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||
                Intent.ACTION_PACKAGE_REMOVED.equals(action) ||
                Intent.ACTION_PACKAGE_REPLACED.equals(action)) {
            final int uid = getUidFromIntent(intent);
            if (uid != -1) {
                final UidRecord uidRec = mProcessList.getUidRecordLOSP(uid);
                if (uidRec != null) {
                    uidRec.updateHasInternetPermission();
                }
            }
        }
    }

    // Add to the sticky list if requested.
    if (sticky) {
        if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
                callingPid, callingUid)
                != PackageManager.PERMISSION_GRANTED) {
            String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
                    + callingPid + ", uid=" + callingUid
                    + " requires " + android.Manifest.permission.BROADCAST_STICKY;
            Slog.w(TAG, msg);
            throw new SecurityException(msg);
        }
        if (requiredPermissions != null && requiredPermissions.length > 0) {
            Slog.w(TAG, "Can't broadcast sticky intent " + intent
                    + " and enforce permissions " + Arrays.toString(requiredPermissions));
            return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
        }
        if (intent.getComponent() != null) {
            throw new SecurityException(
                    "Sticky broadcasts can't target a specific component");
        }
        // We use userId directly here, since the "all" target is maintained
        // as a separate set of sticky broadcasts.
        if (userId != UserHandle.USER_ALL) {
            // But first, if this is not a broadcast to all users, then
            // make sure it doesn't conflict with an existing broadcast to
            // all users.
            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++) {
                        if (intent.filterEquals(list.get(i))) {
                            throw new IllegalArgumentException(
                                    "Sticky broadcast " + intent + " for user "
                                    + userId + " conflicts with existing global broadcast");
                        }
                    }
                }
            }
        }
        ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
        if (stickies == null) {
            stickies = new ArrayMap<>();
            mStickyBroadcasts.put(userId, stickies);
        }
        ArrayList<Intent> list = stickies.get(intent.getAction());
        if (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));
        }
    }

    int[] users;
    if (userId == UserHandle.USER_ALL) {
        // Caller wants broadcast to go to all started users.
        users = mUserController.getStartedUserArray();
    } else {
        // Caller wants broadcast to go to one specific user.
        users = new int[] {userId};
    }

    // Figure out who all will receive this broadcast.
    List receivers = null;
    List<BroadcastFilter> registeredReceivers = null;
    // Need to resolve the intent to interested receivers...
    if ((intent.getFlags() & Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
        receivers = collectReceiverComponents(
                intent, resolvedType, callingUid, users, broadcastAllowList);
    }
    if (intent.getComponent() == null) {
        final PackageDataSnapshot snapshot = getPackageManagerInternal().snapshot();
        if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
            // Query one target user at a time, excluding shell-restricted users
            for (int i = 0; i < users.length; i++) {
                if (mUserController.hasUserRestriction(
                        UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
                    continue;
                }
                List<BroadcastFilter> registeredReceiversForUser =
                        mReceiverResolver.queryIntent(snapshot, intent,
                                resolvedType, false /*defaultOnly*/, users[i]);
                if (registeredReceivers == null) {
                    registeredReceivers = registeredReceiversForUser;
                } else if (registeredReceiversForUser != null) {
                    registeredReceivers.addAll(registeredReceiversForUser);
                }
            }
        } else {
            registeredReceivers = mReceiverResolver.queryIntent(snapshot, intent,
                    resolvedType, false /*defaultOnly*/, userId);
        }
    }

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

    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing broadcast: " + intent.getAction()
            + " replacePending=" + replacePending);
    if (registeredReceivers != null && broadcastAllowList != null) {
        // if a uid whitelist was provided, remove anything in the application space that wasn't
        // in it.
        for (int i = registeredReceivers.size() - 1; i >= 0; i--) {
            final int owningAppId = UserHandle.getAppId(registeredReceivers.get(i).owningUid);
            if (owningAppId >= Process.FIRST_APPLICATION_UID
                    && Arrays.binarySearch(broadcastAllowList, owningAppId) < 0) {
                registeredReceivers.remove(i);
            }
        }
    }

    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);
        }
        final BroadcastQueue queue = broadcastQueueForIntent(intent);
        BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
                callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
                requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
                registeredReceivers, resultTo, resultCode, resultData, resultExtras, ordered,
                sticky, false, userId, allowBackgroundActivityStarts,
                backgroundActivityStartsToken, timeoutExempt);
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
        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;
    }

    // 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.
        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)) {
                            receivers.remove(it);
                            it--;
                            NT--;
                        }
                    }
                }
            }
        }

        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;
            }
        }
    }
    while (ir < NR) {
        if (receivers == null) {
            receivers = new ArrayList();
        }
        receivers.add(registeredReceivers.get(ir));
        ir++;
    }

    if (isCallerSystem) {
        checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
                isProtectedBroadcast, receivers);
    }

    if ((receivers != null && receivers.size() > 0)
            || resultTo != null) {
        BroadcastQueue queue = broadcastQueueForIntent(intent);
        BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
                callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
                requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
                receivers, resultTo, resultCode, resultData, resultExtras,
                ordered, sticky, false, userId, allowBackgroundActivityStarts,
                backgroundActivityStartsToken, timeoutExempt);

        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);

        final BroadcastRecord oldRecord =
                replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
        if (oldRecord != null) {
            // Replaced, fire the result-to receiver.
            if (oldRecord.resultTo != null) {
                final BroadcastQueue oldQueue = broadcastQueueForIntent(oldRecord.intent);
                try {
                    oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo,
                            oldRecord.intent,
                            Activity.RESULT_CANCELED, null, null,
                            false, false, oldRecord.userId, oldRecord.callingUid, callingUid);
                } catch (RemoteException e) {
                    Slog.w(TAG, "Failure ["
                            + queue.mQueueName + "] sending broadcast result of "
                            + intent, e);

                }
            }
        } else {
            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);
        }
    }

    return ActivityManager.BROADCAST_SUCCESS;
}

这个函数代码非常多,下面我们从几个方面来分析:

instant app

final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
// Instant Apps cannot use FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS
if (callerInstantApp) {
    // 如果caller是instant app,则不能使用FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS
    // 即instant app不能发送给instant app可见的广播
    intent.setFlags(intent.getFlags() & ~Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
}

instant app不能发送给instant app可见的广播。

不发送给stop应用

// By default broadcasts do not go to stopped apps.
//默认广播是不发送给stop的应用的,类似于安装后进程从未启动过,或者给强行停止的应用,
//是无法通过接收静态注册的广播来启动的(具体在IntentResolver.java的buildResolveList会使用)
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

开机未完成

// If we have not finished booting, don't allow this to launch new processes.
//mProcessesReady在systemReady的时候会设置为true
//在系统没有启动完成的时候,而且广播发送没有带FLAG_RECEIVER_BOOT_UPGRADE的flag
if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
    //则默认只能发送到动态注册的接收者中,静态注册的全部无法接收
    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
}

如果开机还没有完成,且没有带升级状态可接受的flag(FLAG_RECEIVER_BOOT_UPGRADE),则默认只能发送到动态注册的接收者中,静态注册的全部无法接收。

user校验

// 获取当前发送广播应用所在用户的userId
userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
        ALLOW_NON_FULL, "broadcast", callerPackage);

// Make sure that the user who is receiving this broadcast or its parent is running.
// If not, we will just skip it. Make an exception for shutdown broadcasts, upgrade steps.
//如果userId不是发送到所有用户USER_ALL(-1),而且当前userId和它的父亲userId都没有在运行
if (userId != UserHandle.USER_ALL && !mUserController.isUserOrItsParentRunning(userId)) {
    //如果调用者不是系统或者没有设置FLAG_RECEIVER_BOOT_UPGRADE,而且不是关机广播,
    //则跳过本次广播发送,不允许stop的userId发送广播,原因是user已经stop了
    if ((callingUid != SYSTEM_UID
            || (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)
            && !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
        Slog.w(TAG, "Skipping broadcast of " + intent
                + ": user " + userId + " and its parent (if any) are stopped");
        return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
    }
}

检查权限

//获取action
final String action = intent.getAction();
BroadcastOptions brOptions = null;
//是否有传入BroadcastOptions的Bundle,开机广播有传入bOptions,亮屏幕广播没有bOptions
if (bOptions != null) {
    //将Bundle转换成BroadcastOptions brOptions
    brOptions = new BroadcastOptions(bOptions);
    if (brOptions.getTemporaryAppAllowlistDuration() > 0) {
        // See if the caller is allowed to do this.  Note we are checking against
        // the actual real caller (not whoever provided the operation as say a
        // PendingIntent), because that who is actually supplied the arguments.

        // 检查一下realCallingPid/realCallingUid是否拥有CHANGE_DEVICE_IDLE_TEMP_WHITELIST(修改临时白名单)、
        // START_ACTIVITIES_FROM_BACKGROUND(后台启动activity)、
        // START_FOREGROUND_SERVICES_FROM_BACKGROUND(后台启动前台服务)的权限,
        // 如果一个都没有,则不允许发送该广播,并抛出安全异常
        // (在部分情况下callingPid/callingUid调用该发送广播的调用者,于realCallingPid/realCallingUid真实调用者不是一样的)
        if (checkComponentPermission(CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
                realCallingPid, realCallingUid, -1, true)
                != PackageManager.PERMISSION_GRANTED
                && checkComponentPermission(START_ACTIVITIES_FROM_BACKGROUND,
                realCallingPid, realCallingUid, -1, true)
                != PackageManager.PERMISSION_GRANTED
                && checkComponentPermission(START_FOREGROUND_SERVICES_FROM_BACKGROUND,
                realCallingPid, realCallingUid, -1, true)
                != PackageManager.PERMISSION_GRANTED) {
            String msg = "Permission Denial: " + intent.getAction()
                    + " broadcast from " + callerPackage + " (pid=" + callingPid
                    + ", uid=" + callingUid + ")"
                    + " requires "
                    + CHANGE_DEVICE_IDLE_TEMP_WHITELIST + " or "
                    + START_ACTIVITIES_FROM_BACKGROUND + " or "
                    + START_FOREGROUND_SERVICES_FROM_BACKGROUND;
            Slog.w(TAG, msg);
            throw new SecurityException(msg);
        }
    }
    //如果带有mDontSendToRestrictedApps不发送给受限制的app
    // callingUid不在mActiveUids中,而且callingUid/callerPackage后台限制操作
    // 则由于“background restrictions”不允许发送广播
    if (brOptions.isDontSendToRestrictedApps()
            && !isUidActiveLOSP(callingUid)
            && isBackgroundRestrictedNoCheck(callingUid, callerPackage)) {
        Slog.i(TAG, "Not sending broadcast " + action + " - app " + callerPackage
                + " has background restrictions");
        return ActivityManager.START_CANCELED;
    }
    //是否允许mAllowBackgroundActivityStarts后台启动activity
    if (brOptions.allowsBackgroundActivityStarts()) {
        // See if the caller is allowed to do this.  Note we are checking against
        // the actual real caller (not whoever provided the operation as say a
        // PendingIntent), because that who is actually supplied the arguments.
        //如果没有START_ACTIVITIES_FROM_BACKGROUND则抛出权限异常
        if (checkComponentPermission(
                android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND,
                realCallingPid, realCallingUid, -1, true)
                != PackageManager.PERMISSION_GRANTED) {
            String msg = "Permission Denial: " + intent.getAction()
                    + " broadcast from " + callerPackage + " (pid=" + callingPid
                    + ", uid=" + callingUid + ")"
                    + " requires "
                    + android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
            Slog.w(TAG, msg);
            throw new SecurityException(msg);
        } else {//将allowBackgroundActivityStarts设置成true,允许后台启动activity
            allowBackgroundActivityStarts = true;
            // We set the token to null since if it wasn't for it we'd allow anyway here
            backgroundActivityStartsToken = null;
        }
    }

    if (brOptions.getIdForResponseEvent() > 0) {
        enforcePermission(android.Manifest.permission.ACCESS_BROADCAST_RESPONSE_STATS,
                callingPid, callingUid, "recordResponseEventWhileInBackground");
    }
}

bOptions是Bundle,brOptions是通过bOptions转换的,大部分情况下发广播都不带Bundle的。

  • 检查caller是否有改变deviceidle名单的权限,如果没有后台启动activity、后台启动前台服务,则不允许发送该广播,并抛出安全异常。
  • 检查是否可以发送给受限制的app
  • 通过BroadcastOptions的mAllowBackgroundActivityStarts成员编译检查是否允许后台启动activity

保护广播

// Verify that protected broadcasts are only being sent by system code,
// and that system code is only sending protected broadcasts.
final boolean isProtectedBroadcast;
try {
    //http://aospxref.com/android-13.0.0_r3/xref/frameworks/base/core/res/AndroidManifest.xml
    //带有“protected-broadcast”的广播
    isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
} catch (RemoteException e) {
    Slog.w(TAG, "Remote exception", e);
    return ActivityManager.BROADCAST_SUCCESS;
}

final boolean isCallerSystem;
switch (UserHandle.getAppId(callingUid)) {
    case ROOT_UID:
    case SYSTEM_UID:
    case PHONE_UID:
    case BLUETOOTH_UID:
    case NFC_UID:
    case SE_UID:
    case NETWORK_STACK_UID:
        isCallerSystem = true;
        break;
    default:
        isCallerSystem = (callerApp != null) && callerApp.isPersistent();
        break;
}

// First line security check before anything else: stop non-system apps from
// sending protected broadcasts.
if (!isCallerSystem) {
    if (isProtectedBroadcast) {//不是系统不能发送保护广播
        String msg = "Permission Denial: not allowed to send broadcast "
                + action + " from pid="
                + callingPid + ", uid=" + callingUid;
        Slog.w(TAG, msg);
        throw new SecurityException(msg);

    } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
            || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
        //如果是widget配置(ACTION_APPWIDGET_CONFIGURE)和更新(ACTION_APPWIDGET_UPDATE)
        //则调用callerPackage不能是空
        // Special case for compatibility: we don't want apps to send this,
        // but historically it has not been protected and apps may be using it
        // to poke their own app widget.  So, instead of making it protected,
        // just limit it to the caller.
        if (callerPackage == null) {
            String msg = "Permission Denial: not allowed to send broadcast "
                    + action + " from unknown caller.";
            Slog.w(TAG, msg);
            throw new SecurityException(msg);
        } else if (intent.getComponent() != null) {
            // They are good enough to send to an explicit component...  verify
            // it is being sent to the calling app.
            if (!intent.getComponent().getPackageName().equals(
                    callerPackage)) {//这种情况只能自己发送给自己,不然抛出权限异常
                String msg = "Permission Denial: not allowed to send broadcast "
                        + action + " to "
                        + intent.getComponent().getPackageName() + " from "
                        + callerPackage;
                Slog.w(TAG, msg);
                throw new SecurityException(msg);
            }
        } else {
            // Limit broadcast to their own package.
            //这类广播只能发给它自己,用于自身widget的更新
            intent.setPackage(callerPackage);
        }
    }
}
  • 检查是否是保护广播,拿当前需要发的 action 去查 frameworks/base/core/res/AndroidManifest.xml带有“protected-broadcast”的action是否一样。
  • root用户、系统、phone、蓝牙、nfc、安全、网络等相关调用则被认为是系统,还有就是否常驻进程。
  • protectBroadcast只能由系统发送。
  • 如果是widget配置(ACTION_APPWIDGET_CONFIGURE)和更新(ACTION_APPWIDGET_UPDATE),只能发给它自己,用于自身widget的更新。

广播能否发给background进程

boolean timeoutExempt = false;

if (action != null) {
    //查看是否background的进程也可以接收该广播,具体列表在SystemConfig.java的mAllowImplicitBroadcasts
    //这个列表是扫描**/etc/sysconfig/*.xml(如system/etc/sysconfig/framework-sysconfig.xml)
    //带有“<allow-implicit-broadcast”的广播
    if (getBackgroundLaunchBroadcasts().contains(action)) {
        if (DEBUG_BACKGROUND_CHECK) {
            Slog.i(TAG, "Broadcast action " + action + " forcing include-background");
        }
        intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
    }

    if (Process.isSdkSandboxUid(realCallingUid)) {
        SdkSandboxManagerLocal sdkSandboxManagerLocal = LocalManagerRegistry.getManager(
                SdkSandboxManagerLocal.class);
        if (sdkSandboxManagerLocal == null) {
            throw new IllegalStateException("SdkSandboxManagerLocal not found when sending"
                    + " a broadcast from an SDK sandbox uid.");
        }
        sdkSandboxManagerLocal.enforceAllowedToSendBroadcast(intent);
    }


    switch (action) {
        ...
        //主要是针对package相关的广播做了特殊处理,这里不再罗列,有兴趣可以自己翻看源码
    }

    ...
}
  • 判断后台应用是否被允许接收改广播,也就是SystemConfig.java的mAllowImplicitBroadcasts,具体是扫描 **/etc/sysconfig/*.xml(如system/etc/sysconfig/framework-sysconfig.xml)带有“<allow-implicit-broadcast”的广播。
  • 对某些的action进行特殊处理。

处理粘性广播

// Add to the sticky list if requested.
if (sticky) {
    //Sticky广播需要在manifest中声明BROADCAST_STICKY权限
    if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
            callingPid, callingUid)
            != PackageManager.PERMISSION_GRANTED) {
        String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
                + callingPid + ", uid=" + callingUid
                + " requires " + android.Manifest.permission.BROADCAST_STICKY;
        Slog.w(TAG, msg);
        throw new SecurityException(msg);
    }
    //Sticky广播不能有权限要求
    if (requiredPermissions != null && requiredPermissions.length > 0) {
        Slog.w(TAG, "Can't broadcast sticky intent " + intent
                + " and enforce permissions " + Arrays.toString(requiredPermissions));
        return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
    }
    //粘性广播不能指定发送到相关组件,否则发出安全异常
    if (intent.getComponent() != null) {
        throw new SecurityException(
                "Sticky broadcasts can't target a specific component");
    }
    // We use userId directly here, since the "all" target is maintained
    // as a separate set of sticky broadcasts.
    if (userId != UserHandle.USER_ALL) {
        // But first, if this is not a broadcast to all users, then
        // make sure it doesn't conflict with an existing broadcast to
        // all users.
        // 校验对于当前的这个对单个user的广播 和现有的针对所有user的广播不冲突
        // 也就是说一个sticky广播不能同时针对单个user又针对user_all
        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++) {
                    if (intent.filterEquals(list.get(i))) {
                        throw new IllegalArgumentException(
                                "Sticky broadcast " + intent + " for user "
                                + userId + " conflicts with existing global broadcast");
                    }
                }
            }
        }
    }
    // 将Sticky广播放入mStickyBroadcasts
    ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
    if (stickies == null) {
        stickies = new ArrayMap<>();
        mStickyBroadcasts.put(userId, stickies);
    }
    ArrayList<Intent> list = stickies.get(intent.getAction());
    if (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.
            // 如果能找到对应的sticky广播,则进行替换
            // 因为sticky广播是在注册者一注册就把最近的u一个发出去了
            // 所以对于同一个sticky广播需要记录下,如果有重复,则替换
            list.set(i, new Intent(intent));
            break;
        }
    }
    //如果上面中途替换过list的intent,则i < stickiesCount
    //而i >= stickiesCount则代表没有替换过
    if (i >= stickiesCount) {
        list.add(new Intent(intent));
    }
}
  • Sticky广播需要在manifest中声明BROADCAST_STICKY权限
  • Sticky广播不能有权限要求
  • Sticky广播不能指定发送到相关组件,否则发出安全异常
  • Sticky广播不能同时针对单个user又针对user_all
  • 将Sticky广播放入mStickyBroadcasts

将粘性广播添加到AMS的mStickyBroadcasts(key是用户组,value是粘性广播列表stickies)中,单个用户组的粘性广播列表stickies(key是action,value是intent),后面动态注册的接收者就可以在注册的时候就接收这类粘性广播, 因为系统有保存这类广播。

筛选出静态广播接受者

int[] users;
if (userId == UserHandle.USER_ALL) {// 发送广播给全部用户
    // Caller wants broadcast to go to all started users.
    // 获取所有已启动用户的列表
    users = mUserController.getStartedUserArray();
} else {// 发送广播给指定用户
    // Caller wants broadcast to go to one specific user.
    users = new int[] {userId};
}

// Figure out who all will receive this broadcast.
// 静态广播接受者或者order的动态广播接受者的列表
List receivers = null;
// 动态广播接受者列表
List<BroadcastFilter> registeredReceivers = null;
// Need to resolve the intent to interested receivers...
if ((intent.getFlags() & Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
    //这里就是查询静态广播的地方,通过PMS的mComponentResolver查询得到该intent静态注册的广播接受者
    //同时传入broadcastAllowList过滤是否允许接受者接收
    receivers = collectReceiverComponents(
            intent, resolvedType, callingUid, users, broadcastAllowList);
}
  • 变量receivers为静态广播接受者
  • collectReceiverComponents(),PMS的mComponentResolver查询得到该intent静态注册的广播接受者
collectReceiverComponents()
private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,
        int callingUid, int[] users, int[] broadcastAllowList) {
    // TODO: come back and remove this assumption to triage all broadcasts
    int pmFlags = STOCK_PM_FLAGS | MATCH_DEBUG_TRIAGED_MISSING;

    List<ResolveInfo> receivers = null;
    HashSet<ComponentName> singleUserReceivers = null;
    boolean scannedFirstReceivers = false;
    for (int user : users) {
        // Skip users that have Shell restrictions
        //如果调用者是shell,而且该user不允许shell调试,则跳过
        if (callingUid == SHELL_UID
                && mUserController.hasUserRestriction(
                UserManager.DISALLOW_DEBUGGING_FEATURES, user)) {
            continue;
        }
        //静态广播通过PMS去查询接收者
        List<ResolveInfo> newReceivers = mPackageManagerInt.queryIntentReceivers(
                intent, resolvedType, pmFlags, callingUid, user, true /* forSend */);
        if (user != UserHandle.USER_SYSTEM && newReceivers != null) {
            // If this is not the system user, we need to check for
            // any receivers that should be filtered out.
            for (int i = 0; i < newReceivers.size(); i++) {
                ResolveInfo ri = newReceivers.get(i);
                //如果取出来的ResolveInfo包含了只允许系统接收的flag(FLAG_SYSTEM_USER_ONLY),
                //则从筛选出来的列表中移除这个接收者
                if ((ri.activityInfo.flags & ActivityInfo.FLAG_SYSTEM_USER_ONLY) != 0) {
                    newReceivers.remove(i);
                    i--;
                }
            }
        }
        // Replace the alias receivers with their targets.
        if (newReceivers != null) {
            for (int i = newReceivers.size() - 1; i >= 0; i--) {
                final ResolveInfo ri = newReceivers.get(i);
                final Resolution<ResolveInfo> resolution =
                        mComponentAliasResolver.resolveReceiver(intent, ri, resolvedType,
                                pmFlags, user, callingUid, true /* forSend */);
                if (resolution == null) {
                    // It was an alias, but the target was not found.
                    newReceivers.remove(i);
                    continue;
                }
                if (resolution.isAlias()) {
                    newReceivers.set(i, resolution.getTarget());
                }
            }
        }

        //如果到目前为止newReceivers(ResolveInfo列表)为null或者空的
        if (newReceivers != null && newReceivers.size() == 0) {
            newReceivers = null;
        }

        if (receivers == null) {
            //如果receivers(最后返回的结果)为null,则先将newReceivers赋值给receivers
            receivers = newReceivers;
        } else if (newReceivers != null) {
            // We need to concatenate the additional receivers
            // found with what we have do far.  This would be easy,
            // but we also need to de-dup any receivers that are
            // singleUser.
            //scannedFirstReceivers默认是fasle,也就是第一次跑到这段代码会进来,只进来一次
            //receivers此时已经赋值过一次,这里是users第二次和以上循环才可能会进来
            if (!scannedFirstReceivers) {
                // Collect any single user receivers we had already retrieved.
                scannedFirstReceivers = true;
                // 遍历之前的receivers(这里receivers没有判空逻辑,只看这段逻辑不太严谨,
                // 没有出错是由于newReceivers有判空)
                for (int i = 0; i < receivers.size(); i++) {
                    ResolveInfo ri = receivers.get(i);
                     //如果接收者包含FLAG_SINGLE_USER的flag
                    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>();
                        }
                        //则把这类组件add到singleUserReceivers中
                        singleUserReceivers.add(cn);
                    }
                }
            }
            // Add the new results to the existing results, tracking
            // and de-dupping single user receivers.
            // 遍历新的users中获取的newReceivers
            for (int i = 0; i < newReceivers.size(); i++) {
                ResolveInfo ri = newReceivers.get(i);
                //如果也是带有FLAG_SINGLE_USER的flag,只发送给单个user
                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>();
                    }
                    //如果之前还没有添加过,才进行receivers添加
                    if (!singleUserReceivers.contains(cn)) {
                        //而且将单个用户接受者ComponentName cn添加到ComponentName中
                        singleUserReceivers.add(cn);
                        receivers.add(ri);
                    }
                } else {
                    //其它情况则直接加入该接收者到receivers
                    receivers.add(ri);
                }
            }
        }
    }
    //如果带有broadcastAllowList,允许接收该广播uid的列表
    if (receivers != null && broadcastAllowList != null) {
        for (int i = receivers.size() - 1; i >= 0; i--) {
            final int receiverAppId = UserHandle.getAppId(
                    receivers.get(i).activityInfo.applicationInfo.uid);
            //接受者的uid如果是app进程,而且不在允许接收该广播uid的列表,则移除查询到的接收者
            if (receiverAppId >= Process.FIRST_APPLICATION_UID
                    && Arrays.binarySearch(broadcastAllowList, receiverAppId) < 0) {
                receivers.remove(i);
            }
        }
    }
    return receivers;
}   
PackageManagerService.queryIntentReceivers
PackageManagerService.java

public @NonNull ParceledListSlice<ResolveInfo> queryIntentReceivers(@NonNull Computer snapshot,
        Intent intent, String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,
        @UserIdInt int userId) {
    return new ParceledListSlice<>(mResolveIntentHelper.queryIntentReceiversInternal(
            snapshot, intent, resolvedType, flags, userId, Binder.getCallingUid()));
}

进入PMS的逻辑就不在详细阐述,最终获取之前在静态广播注册时存在PMS的成员变量mComponentResolver,从而拿到静态注册广播的receivers。

筛选出动态广播接收者

if (intent.getComponent() == null) {
    final PackageDataSnapshot snapshot = getPackageManagerInternal().snapshot();
    if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
        // Query one target user at a time, excluding shell-restricted users
        //对于shell发送的user_all的广播
        for (int i = 0; i < users.length; i++) {
            if (mUserController.hasUserRestriction(
                    UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
                continue;
            }
            List<BroadcastFilter> registeredReceiversForUser =
                    mReceiverResolver.queryIntent(snapshot, intent,
                            resolvedType, false /*defaultOnly*/, users[i]);
            if (registeredReceivers == null) {
                registeredReceivers = registeredReceiversForUser;
            } else if (registeredReceiversForUser != null) {
                registeredReceivers.addAll(registeredReceiversForUser);
            }
        }
    } else {
        //一般情况我们走的这里,直接从mReceiverResolver查询动态接受者赋值给registeredReceivers
        registeredReceivers = mReceiverResolver.queryIntent(snapshot, intent,
                resolvedType, false /*defaultOnly*/, userId);
    }
}

mReceiverResolver查询动态接受者赋值给registeredReceivers。

无序广播

如果没有设置ordered按顺序,则针对动态注册类型的广播会一次性全部发送出去。

// 如果带有FLAG_RECEIVER_REPLACE_PENDING
// 表示如果这个广播还没有派发,则替换掉之前的广播
final boolean replacePending =
        (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;

if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing broadcast: " + intent.getAction()
        + " replacePending=" + replacePending);
// 动态注册查询的时候没有传入broadcastAllowList(允许接收的uid列表)
// 此处会根据broadcastAllowList(不为null才会过滤)来进行动态注册接收者的过滤
if (registeredReceivers != null && broadcastAllowList != null) {
    // if a uid whitelist was provided, remove anything in the application space that wasn't
    // in it.
    for (int i = registeredReceivers.size() - 1; i >= 0; i--) {
        final int owningAppId = UserHandle.getAppId(registeredReceivers.get(i).owningUid);
        if (owningAppId >= Process.FIRST_APPLICATION_UID
                && Arrays.binarySearch(broadcastAllowList, owningAppId) < 0) {
            registeredReceivers.remove(i);
        }
    }
}
// 动态注册的广播接收者个数
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
// 先处理动态注册接收者的逻辑,如果该广播是非ordered(也就是无序广播),则进入里面
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查找对应的广播队列
    final BroadcastQueue queue = broadcastQueueForIntent(intent);
    //创建BroadcastRecord对象并将当前所有通过动态注册的广播接收者传进去
    BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
            callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
            requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
            registeredReceivers, resultTo, resultCode, resultData, resultExtras, ordered,
            sticky, false, userId, allowBackgroundActivityStarts,
            backgroundActivityStartsToken, timeoutExempt);
    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
    // 在BroadcastQueue中等待发送广播中搜索是否有相同的BroadcastRecord并且是否替换
    final boolean replaced = replacePending
            && (queue.replaceParallelBroadcastLocked(r) != null);
    // Note: We assume resultTo is null for non-ordered broadcasts.
    if (!replaced) {
        // 如果不需要替换则插入到BroadcastQueue中
        // 也就是说动态广播接收者都放在了BroadcastQueue的mParallelBroadcasts中
        queue.enqueueParallelBroadcastLocked(r);
        //并推动一次广播发送
        queue.scheduleBroadcastsLocked();
    }
    //清空动态接收者,已经处理过了
    registeredReceivers = null;
    NR = 0;
}
  • 根据intent查找对应的广播队列
  • 创建BroadcastRecord对象并将当前所有通过动态注册的广播接收者传进去
  • 调用enqueueParallelBroadcastLocked(),将动态广播接收者放在了BroadcastQueue的mParallelBroadcasts中
  • 调用scheduleBroadcastsLocked()发送广播

有序广播

如果说【动态注册且接受无序广播的广播接收者】是并行操作,那么【动态注册接受有序广播的广播接收者】和【静态注册的广播接收者】接受广播的最大特点就是串行

如果是有序广播,动态接收者和静态的接收者合并到一个队列里面进行处理,也就是说order广播下,所有的接收者(静态和动态)处理方式都是一样的(后面会分析到,都是串行化处理的)。

还有就是对于静态注册的接收者而言,始终是和order广播的处理方式是一样的,也就是说静态的接收者只有order模式(串行化接收)。在合并过程中,如果一个动态注册的广播接收者和一个静态注册的目标广播接收者的优先级相同,那么动态注册的目标接收者会排在静态注册的目标广播接收者前面,即动态注册的目标广播接收者会优先于静态注册的广播接收者接受有序广播。

  • 无序 ---> registeredReceivers

动态注册 + 无序 ---> registeredReceivers

  • 有序 ---> receivers

  • 动态注册 + 有序

  • 静态注册( 有序 + 无序 )
// 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.
    String skipPackages[] = null;
    //针对ACTION_PACKAGE_ADDED/ACTION_PACKAGE_RESTARTED/ACTION_PACKAGE_DATA_CLEARED
    //这类广播不允许被安装的package接收(自己接收自己安装的广播不允许),防止自启
    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);
    }
    //将跳过的packageName从receivers中移除
    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)) {
                        receivers.remove(it);
                        it--;
                        NT--;
                    }
                }
            }
        }
    }

    //NT是静态接收者的个数,NR是动态接收者的个数
    int NT = receivers != null ? receivers.size() : 0;
    int it = 0;
    ResolveInfo curt = null;//静态注册的广播接收者
    BroadcastFilter curr = null;//动态注册的广播接收者
    while (it < NT && ir < NR) {//开始把动态注册的广播接收者列表registeredReceivers和静态注册的广播接收者列表receivers合并成一个列表
        if (curt == null) {
            //获取静态广播接收者列表第it个
            curt = (ResolveInfo)receivers.get(it);
        }
        if (curr == null) {
            //获取动态广播接收者列表第ir个
            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;
        }
    }
}
while (ir < NR) {//将两个列表合并到一个列表中,这样静态注册广播接收者receivers列表就包含了所有的广播接收者(无序广播和有序广播)
    if (receivers == null) {
        receivers = new ArrayList();
    }
    receivers.add(registeredReceivers.get(ir));
    ir++;
}

if (isCallerSystem) {//isCallerSystem是否系统调用发送广播
    //查看一下发送的是否保护的广播
    checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
            isProtectedBroadcast, receivers);
}

if ((receivers != null && receivers.size() > 0)
        || resultTo != null) {
    // 根据intent查找对应的广播队列
    BroadcastQueue queue = broadcastQueueForIntent(intent);
    // 创建BroadcastRecord对象并将合并过的广播接收者列表receivers传进去
    BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
            callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
            requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
            receivers, resultTo, resultCode, resultData, resultExtras,
            ordered, sticky, false, userId, allowBackgroundActivityStarts,
            backgroundActivityStartsToken, timeoutExempt);

    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);

    final BroadcastRecord oldRecord =
            replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
    if (oldRecord != null) {
        // Replaced, fire the result-to receiver.
        if (oldRecord.resultTo != null) {
            final BroadcastQueue oldQueue = broadcastQueueForIntent(oldRecord.intent);
            try {
                oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo,
                        oldRecord.intent,
                        Activity.RESULT_CANCELED, null, null,
                        false, false, oldRecord.userId, oldRecord.callingUid, callingUid);
            } catch (RemoteException e) {
                Slog.w(TAG, "Failure ["
                        + queue.mQueueName + "] sending broadcast result of "
                        + intent, e);

            }
        }
    } else {
        //无序广播+有序广播合并之后放在了BroadcastQueue的mOrderedBroadcasts中
        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);
    }
}

return ActivityManager.BROADCAST_SUCCESS;
  • 对特殊的广播,需要跳过

如ACTION_PACKAGE_ADDED(安装)/ACTION_PACKAGE_RESTARTED(重新)/ACTION_PACKAGE_DATA_CLEARED(清除),不允许被安装的package接收,防止自启。

  • 动态注册的广播接收者列表registeredReceivers和静态注册的广播接收者列表receivers合并成一个列表
  • 根据intent查找对应的广播队列
  • 创建BroadcastRecord对象并将合并过的广播接收者列表receivers传进去
  • 调用enqueueOrderedBroadcastLocked,将无序广播+有序广播合并之后放在了BroadcastQueue的mOrderedBroadcasts中
  • 调用scheduleBroadcastsLocked()发送广播

总结

这段代码看起来很长,但是仔细捋一遍其中的大致流程其实也是很容易理解的。

  • 做一些检查和判断

如userid校验、是否允许后台启动activity、改变deviceidle名单,进行权限校验、protectBroadcast的caller校验等等

  • 特殊action广播特殊处理
  • sticky广播处理
  • 动态注册的并行广播处理入队
  • 静态注册广播以及动态注册有序广播根据优先级排序后入队
  • 开始调度

AMS创建广播队列

前面讲的是过滤接收者,然后将信息放入广播队列中,那么广播队列是如何处理这类信息的呢?广播队列又是在哪里创建的呢?

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback, ActivityManagerGlobalLock {

    final BroadcastQueue mFgBroadcastQueue;
    final BroadcastQueue mBgBroadcastQueue;
    final BroadcastQueue mBgOffloadBroadcastQueue;
    final BroadcastQueue mFgOffloadBroadcastQueue;
    // Convenient for easy iteration over the queues. Foreground is first
    // so that dispatch of foreground broadcasts gets precedence.
    final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[4];

    public ActivityManagerService(Context systemContext, ActivityTaskManagerService atm) {
        ...

        // Broadcast policy parameters
        final BroadcastConstants foreConstants = new BroadcastConstants(
                Settings.Global.BROADCAST_FG_CONSTANTS);
        //前台广播超时时间是10s
        foreConstants.TIMEOUT = BROADCAST_FG_TIMEOUT;

        final BroadcastConstants backConstants = new BroadcastConstants(
                Settings.Global.BROADCAST_BG_CONSTANTS);
        //后台广播超时时间是60s
        backConstants.TIMEOUT = BROADCAST_BG_TIMEOUT;

        final BroadcastConstants offloadConstants = new BroadcastConstants(
                Settings.Global.BROADCAST_OFFLOAD_CONSTANTS);
        offloadConstants.TIMEOUT = BROADCAST_BG_TIMEOUT;
        // by default, no "slow" policy in this queue
        //没有SLOW_TIME,不使用延迟策略广播
        offloadConstants.SLOW_TIME = Integer.MAX_VALUE;

        //默认使用Offload的广播的
        mEnableOffloadQueue = SystemProperties.getBoolean(
                "persist.device_config.activity_manager_native_boot.offload_queue_enabled", true);

        //这里的mHandler是AMS的MainHandler,优先级是THREAD_PRIORITY_FOREGROUND前台
        mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
                "foreground", foreConstants, false);
        mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
                "background", backConstants, true);
        mBgOffloadBroadcastQueue = new BroadcastQueue(this, mHandler,
                "offload_bg", offloadConstants, true);
        mFgOffloadBroadcastQueue = new BroadcastQueue(this, mHandler,
                "offload_fg", foreConstants, true);
        mBroadcastQueues[0] = mFgBroadcastQueue;
        mBroadcastQueues[1] = mBgBroadcastQueue;
        mBroadcastQueues[2] = mBgOffloadBroadcastQueue;
        mBroadcastQueues[3] = mFgOffloadBroadcastQueue;

        ...
    }

}

广播接收者入队列

enqueueParallelBroadcastLocked

BroadcastQueue.java

final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>();

public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
    r.enqueueClockTime = System.currentTimeMillis();
    r.enqueueTime = SystemClock.uptimeMillis();
    r.enqueueRealTime = SystemClock.elapsedRealtime();
    mParallelBroadcasts.add(r);
    enqueueBroadcastHelper(r);
}

全部丢入广播队列BroadcastQueue的mParallelBroadcasts中。

enqueueOrderedBroadcastLocked

BroadcastQueue.java

final BroadcastDispatcher mDispatcher;

public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
    r.enqueueClockTime = System.currentTimeMillis();
    r.enqueueTime = SystemClock.uptimeMillis();
    r.enqueueRealTime = SystemClock.elapsedRealtime();
    mDispatcher.enqueueOrderedBroadcastLocked(r);
    enqueueBroadcastHelper(r);
}
BroadcastDispatcher.java

private final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<>();

void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
    if (r.receivers == null || r.receivers.isEmpty()) {
        mOrderedBroadcasts.add(r);
        return;
    }

    if (Intent.ACTION_LOCKED_BOOT_COMPLETED.equals(r.intent.getAction())) {
        // Create one BroadcastRecord for each UID that can be deferred.
        final SparseArray<BroadcastRecord> deferred =
                r.splitDeferredBootCompletedBroadcastLocked(mQueue.mService.mInternal,
                        mQueue.mService.mConstants.mDeferBootCompletedBroadcast);
        getDeferredPerUser(r.userId).enqueueBootCompletedBroadcasts(
                Intent.ACTION_LOCKED_BOOT_COMPLETED, deferred);
        if (!r.receivers.isEmpty()) {
            // The non-deferred receivers.
            mOrderedBroadcasts.add(r);
            return;
        }
    } else if (Intent.ACTION_BOOT_COMPLETED.equals(r.intent.getAction())) {
        // Create one BroadcastRecord for each UID that can be deferred.
        final SparseArray<BroadcastRecord> deferred =
                r.splitDeferredBootCompletedBroadcastLocked(mQueue.mService.mInternal,
                        mQueue.mService.mConstants.mDeferBootCompletedBroadcast);
        getDeferredPerUser(r.userId).enqueueBootCompletedBroadcasts(
                Intent.ACTION_BOOT_COMPLETED, deferred);
        if (!r.receivers.isEmpty()) {
            // The non-deferred receivers.
            mOrderedBroadcasts.add(r);
            return;
        }
    } else {
        mOrderedBroadcasts.add(r);
    }
}

这里多了一个中转mDispatcher(BroadcastDispatcher),放入的其实是BroadcastDispatcher的mOrderedBroadcasts中。

广播队列分发

BroadcastQueue.java

public void scheduleBroadcastsLocked() {
    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
            + mQueueName + "]: current="
            + mBroadcastsScheduled);

    // 如果true说明消息队列已经存在一个类型为BROADCAST_INTENT_MSG的消息了,直接返回,因为该消息在执行完毕会自动调用下一条消息
    // AMS就是通过这个BROADCAST_INTENT_MSG消息类
    // 来调度保存在无序广播调度队列mParallelBroadcasts和有序广播调度队列mOrderedBroadcasts中的广播转发任务的
    if (mBroadcastsScheduled) {
        return;
    }
    // 虽然这里只发送了发送广播的消息,但是这一步执行完之后就已经标记广播发送了,因此可以看出广播发送和接
    // 受是异步的,即广播发送者将一个广播发送给AMS后,不会等待AMS将这个广播转发给广播接收者处理
    mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
    mBroadcastsScheduled = true;
}

private final class BroadcastHandler extends Handler {
    public BroadcastHandler(Looper looper) {
        super(looper, null, true);
    }

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case BROADCAST_INTENT_MSG: {
                if (DEBUG_BROADCAST) Slog.v(
                        TAG_BROADCAST, "Received BROADCAST_INTENT_MSG ["
                        + mQueueName + "]");
                //开始处理下一个广播
                processNextBroadcast(true);
            } break;
            case BROADCAST_TIMEOUT_MSG: {
                synchronized (mService) {
                    broadcastTimeoutLocked(true);
                }
            } break;
        }
    }
}

处理分发下一个广播

BroadcastQueue.java

private void processNextBroadcast(boolean fromMsg) {
    synchronized (mService) {
        processNextBroadcastLocked(fromMsg, false);
    }
}

final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
    BroadcastRecord r;

    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast ["
            + mQueueName + "]: "
            + mParallelBroadcasts.size() + " parallel broadcasts; "
            + mDispatcher.describeStateLocked());

    mService.updateCpuStats();

    if (fromMsg) {
        mBroadcastsScheduled = false;
    }

    // First, deliver any non-serialized broadcasts right away.
    while (mParallelBroadcasts.size() > 0) {
        r = mParallelBroadcasts.remove(0);
        r.dispatchTime = SystemClock.uptimeMillis();
        r.dispatchRealTime = SystemClock.elapsedRealtime();
        r.dispatchClockTime = System.currentTimeMillis();

        if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
            Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),
                System.identityHashCode(r));
            Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),
                System.identityHashCode(r));
        }

        final int N = r.receivers.size();
        if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
                + mQueueName + "] " + r);
        for (int i=0; i<N; i++) {
            Object target = r.receivers.get(i);
            if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                    "Delivering non-ordered on [" + mQueueName + "] to registered "
                    + target + ": " + r);
            deliverToRegisteredReceiverLocked(r,
                    (BroadcastFilter) target, false, i);
        }
        addBroadcastToHistoryLocked(r);
        if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
                + mQueueName + "] " + r);
    }

    // Now take care of the next serialized one...

    // If we are waiting for a process to come up to handle the next
    // broadcast, then do nothing at this point.  Just in case, we
    // check that the process we're waiting for still exists.
    if (mPendingBroadcast != null) {
        if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
                "processNextBroadcast [" + mQueueName + "]: waiting for "
                + mPendingBroadcast.curApp);

        boolean isDead;
        if (mPendingBroadcast.curApp.getPid() > 0) {
            synchronized (mService.mPidsSelfLocked) {
                ProcessRecord proc = mService.mPidsSelfLocked.get(
                        mPendingBroadcast.curApp.getPid());
                isDead = proc == null || proc.mErrorState.isCrashing();
            }
        } else {
            final ProcessRecord proc = mService.mProcessList.getProcessNamesLOSP().get(
                    mPendingBroadcast.curApp.processName, mPendingBroadcast.curApp.uid);
            isDead = proc == null || !proc.isPendingStart();
        }
        if (!isDead) {
            // It's still alive, so keep waiting
            return;
        } else {
            Slog.w(TAG, "pending app  ["
                    + mQueueName + "]" + mPendingBroadcast.curApp
                    + " died before responding to broadcast");
            mPendingBroadcast.state = BroadcastRecord.IDLE;
            mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
            mPendingBroadcast = null;
        }
    }

    boolean looped = false;

    do {
        final long now = SystemClock.uptimeMillis();
        r = mDispatcher.getNextBroadcastLocked(now);

        if (r == null) {
            // No more broadcasts are deliverable right now, so all done!
            mDispatcher.scheduleDeferralCheckLocked(false);
            synchronized (mService.mAppProfiler.mProfilerLock) {
                mService.mAppProfiler.scheduleAppGcsLPf();
            }
            if (looped && !skipOomAdj) {
                // If we had finished the last ordered broadcast, then
                // make sure all processes have correct oom and sched
                // adjustments.
                mService.updateOomAdjPendingTargetsLocked(
                        OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
            }

            // when we have no more ordered broadcast on this queue, stop logging
            if (mService.mUserController.mBootCompleted && mLogLatencyMetrics) {
                mLogLatencyMetrics = false;
            }

            return;
        }

        boolean forceReceive = false;

        // Ensure that even if something goes awry with the timeout
        // detection, we catch "hung" broadcasts here, discard them,
        // and continue to make progress.
        //
        // This is only done if the system is ready so that early-stage receivers
        // don't get executed with timeouts; and of course other timeout-
        // exempt broadcasts are ignored.
        int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
        if (mService.mProcessesReady && !r.timeoutExempt && r.dispatchTime > 0) {
            if ((numReceivers > 0) &&
                    (now > r.dispatchTime + (2 * mConstants.TIMEOUT * numReceivers))) {
                Slog.w(TAG, "Hung broadcast ["
                        + mQueueName + "] discarded after timeout failure:"
                        + " now=" + now
                        + " dispatchTime=" + r.dispatchTime
                        + " startTime=" + r.receiverTime
                        + " intent=" + r.intent
                        + " numReceivers=" + numReceivers
                        + " nextReceiver=" + r.nextReceiver
                        + " state=" + r.state);
                broadcastTimeoutLocked(false); // forcibly finish this broadcast
                forceReceive = true;
                r.state = BroadcastRecord.IDLE;
            }
        }

        if (r.state != BroadcastRecord.IDLE) {
            if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST,
                    "processNextBroadcast("
                    + mQueueName + ") called when not idle (state="
                    + r.state + ")");
            return;
        }

        // Is the current broadcast is done for any reason?
        if (r.receivers == null || r.nextReceiver >= numReceivers
                || r.resultAbort || forceReceive) {
            // Send the final result if requested
            if (r.resultTo != null) {
                boolean sendResult = true;

                // if this was part of a split/deferral complex, update the refcount and only
                // send the completion when we clear all of them
                if (r.splitToken != 0) {
                    int newCount = mSplitRefcounts.get(r.splitToken) - 1;
                    if (newCount == 0) {
                        // done!  clear out this record's bookkeeping and deliver
                        if (DEBUG_BROADCAST_DEFERRAL) {
                            Slog.i(TAG_BROADCAST,
                                    "Sending broadcast completion for split token "
                                    + r.splitToken + " : " + r.intent.getAction());
                        }
                        mSplitRefcounts.delete(r.splitToken);
                    } else {
                        // still have some split broadcast records in flight; update refcount
                        // and hold off on the callback
                        if (DEBUG_BROADCAST_DEFERRAL) {
                            Slog.i(TAG_BROADCAST,
                                    "Result refcount now " + newCount + " for split token "
                                    + r.splitToken + " : " + r.intent.getAction()
                                    + " - not sending completion yet");
                        }
                        sendResult = false;
                        mSplitRefcounts.put(r.splitToken, newCount);
                    }
                }
                if (sendResult) {
                    if (r.callerApp != null) {
                        mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(
                                r.callerApp);
                    }
                    try {
                        if (DEBUG_BROADCAST) {
                            Slog.i(TAG_BROADCAST, "Finishing broadcast [" + mQueueName + "] "
                                    + r.intent.getAction() + " app=" + r.callerApp);
                        }
                        performReceiveLocked(r.callerApp, r.resultTo,
                                new Intent(r.intent), r.resultCode,
                                r.resultData, r.resultExtras, false, false, r.userId,
                                r.callingUid, r.callingUid);
                        logBootCompletedBroadcastCompletionLatencyIfPossible(r);
                        // Set this to null so that the reference
                        // (local and remote) isn't kept in the mBroadcastHistory.
                        r.resultTo = null;
                    } catch (RemoteException e) {
                        r.resultTo = null;
                        Slog.w(TAG, "Failure ["
                                + mQueueName + "] sending broadcast result of "
                                + r.intent, e);
                    }
                }
            }

            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG");
            cancelBroadcastTimeoutLocked();

            if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
                    "Finished with ordered broadcast " + r);

            // ... and on to the next...
            addBroadcastToHistoryLocked(r);
            if (r.intent.getComponent() == null && r.intent.getPackage() == null
                    && (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
                // This was an implicit broadcast... let's record it for posterity.
                mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage,
                        r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime);
            }
            mDispatcher.retireBroadcastLocked(r);
            r = null;
            looped = true;
            continue;
        }

        // Check whether the next receiver is under deferral policy, and handle that
        // accordingly.  If the current broadcast was already part of deferred-delivery
        // tracking, we know that it must now be deliverable as-is without re-deferral.
        if (!r.deferred) {
            final int receiverUid = r.getReceiverUid(r.receivers.get(r.nextReceiver));
            if (mDispatcher.isDeferringLocked(receiverUid)) {
                if (DEBUG_BROADCAST_DEFERRAL) {
                    Slog.i(TAG_BROADCAST, "Next receiver in " + r + " uid " + receiverUid
                            + " at " + r.nextReceiver + " is under deferral");
                }
                // If this is the only (remaining) receiver in the broadcast, "splitting"
                // doesn't make sense -- just defer it as-is and retire it as the
                // currently active outgoing broadcast.
                BroadcastRecord defer;
                if (r.nextReceiver + 1 == numReceivers) {
                    if (DEBUG_BROADCAST_DEFERRAL) {
                        Slog.i(TAG_BROADCAST, "Sole receiver of " + r
                                + " is under deferral; setting aside and proceeding");
                    }
                    defer = r;
                    mDispatcher.retireBroadcastLocked(r);
                } else {
                    // Nontrivial case; split out 'uid's receivers to a new broadcast record
                    // and defer that, then loop and pick up continuing delivery of the current
                    // record (now absent those receivers).

                    // The split operation is guaranteed to match at least at 'nextReceiver'
                    defer = r.splitRecipientsLocked(receiverUid, r.nextReceiver);
                    if (DEBUG_BROADCAST_DEFERRAL) {
                        Slog.i(TAG_BROADCAST, "Post split:");
                        Slog.i(TAG_BROADCAST, "Original broadcast receivers:");
                        for (int i = 0; i < r.receivers.size(); i++) {
                            Slog.i(TAG_BROADCAST, "  " + r.receivers.get(i));
                        }
                        Slog.i(TAG_BROADCAST, "Split receivers:");
                        for (int i = 0; i < defer.receivers.size(); i++) {
                            Slog.i(TAG_BROADCAST, "  " + defer.receivers.get(i));
                        }
                    }
                    // Track completion refcount as well if relevant
                    if (r.resultTo != null) {
                        int token = r.splitToken;
                        if (token == 0) {
                            // first split of this record; refcount for 'r' and 'deferred'
                            r.splitToken = defer.splitToken = nextSplitTokenLocked();
                            mSplitRefcounts.put(r.splitToken, 2);
                            if (DEBUG_BROADCAST_DEFERRAL) {
                                Slog.i(TAG_BROADCAST,
                                        "Broadcast needs split refcount; using new token "
                                        + r.splitToken);
                            }
                        } else {
                            // new split from an already-refcounted situation; increment count
                            final int curCount = mSplitRefcounts.get(token);
                            if (DEBUG_BROADCAST_DEFERRAL) {
                                if (curCount == 0) {
                                    Slog.wtf(TAG_BROADCAST,
                                            "Split refcount is zero with token for " + r);
                                }
                            }
                            mSplitRefcounts.put(token, curCount + 1);
                            if (DEBUG_BROADCAST_DEFERRAL) {
                                Slog.i(TAG_BROADCAST, "New split count for token " + token
                                        + " is " + (curCount + 1));
                            }
                        }
                    }
                }
                mDispatcher.addDeferredBroadcast(receiverUid, defer);
                r = null;
                looped = true;
                continue;
            }
        }
    } while (r == null);

    // Get the next receiver...
    int recIdx = r.nextReceiver++;

    // Keep track of when this receiver started, and make sure there
    // is a timeout message pending to kill it if need be.
    r.receiverTime = SystemClock.uptimeMillis();
    if (recIdx == 0) {
        r.dispatchTime = r.receiverTime;
        r.dispatchRealTime = SystemClock.elapsedRealtime();
        r.dispatchClockTime = System.currentTimeMillis();

        if (mLogLatencyMetrics) {
            FrameworkStatsLog.write(
                    FrameworkStatsLog.BROADCAST_DISPATCH_LATENCY_REPORTED,
                    r.dispatchClockTime - r.enqueueClockTime);
        }

        if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
            Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),
                System.identityHashCode(r));
            Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),
                System.identityHashCode(r));
        }
        if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing ordered broadcast ["
                + mQueueName + "] " + r);
    }
    if (! mPendingBroadcastTimeoutMessage) {
        long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
                "Submitting BROADCAST_TIMEOUT_MSG ["
                + mQueueName + "] for " + r + " at " + timeoutTime);
        setBroadcastTimeoutLocked(timeoutTime);
    }

    final BroadcastOptions brOptions = r.options;
    final Object nextReceiver = r.receivers.get(recIdx);

    if (nextReceiver instanceof BroadcastFilter) {
        // Simple case: this is a registered receiver who gets
        // a direct call.
        BroadcastFilter filter = (BroadcastFilter)nextReceiver;
        if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                "Delivering ordered ["
                + mQueueName + "] to registered "
                + filter + ": " + r);
        deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
        if (r.receiver == null || !r.ordered) {
            // The receiver has already finished, so schedule to
            // process the next one.
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing ["
                    + mQueueName + "]: ordered="
                    + r.ordered + " receiver=" + r.receiver);
            r.state = BroadcastRecord.IDLE;
            scheduleBroadcastsLocked();
        } else {
            if (filter.receiverList != null) {
                maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
                // r is guaranteed ordered at this point, so we know finishReceiverLocked()
                // will get a callback and handle the activity start token lifecycle.
            }
        }
        return;
    }

    // Hard case: need to instantiate the receiver, possibly
    // starting its application process to host it.

    ResolveInfo info =
        (ResolveInfo)nextReceiver;
    ComponentName component = new ComponentName(
            info.activityInfo.applicationInfo.packageName,
            info.activityInfo.name);

    boolean skip = false;
    if (brOptions != null &&
            (info.activityInfo.applicationInfo.targetSdkVersion
                    < brOptions.getMinManifestReceiverApiLevel() ||
            info.activityInfo.applicationInfo.targetSdkVersion
                    > brOptions.getMaxManifestReceiverApiLevel())) {
        Slog.w(TAG, "Target SDK mismatch: receiver " + info.activityInfo
                + " targets " + info.activityInfo.applicationInfo.targetSdkVersion
                + " but delivery restricted to ["
                + brOptions.getMinManifestReceiverApiLevel() + ", "
                + brOptions.getMaxManifestReceiverApiLevel()
                + "] broadcasting " + broadcastDescription(r, component));
        skip = true;
    }
    if (brOptions != null &&
            !brOptions.testRequireCompatChange(info.activityInfo.applicationInfo.uid)) {
        Slog.w(TAG, "Compat change filtered: broadcasting " + broadcastDescription(r, component)
                + " to uid " + info.activityInfo.applicationInfo.uid + " due to compat change "
                + r.options.getRequireCompatChangeId());
        skip = true;
    }
    if (!skip && !mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid,
            component.getPackageName(), info.activityInfo.applicationInfo.uid)) {
        Slog.w(TAG, "Association not allowed: broadcasting "
                + broadcastDescription(r, component));
        skip = true;
    }
    if (!skip) {
        skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
                r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid);
        if (skip) {
            Slog.w(TAG, "Firewall blocked: broadcasting "
                    + broadcastDescription(r, component));
        }
    }
    int perm = mService.checkComponentPermission(info.activityInfo.permission,
            r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
            info.activityInfo.exported);
    if (!skip && perm != PackageManager.PERMISSION_GRANTED) {
        if (!info.activityInfo.exported) {
            Slog.w(TAG, "Permission Denial: broadcasting "
                    + broadcastDescription(r, component)
                    + " is not exported from uid " + info.activityInfo.applicationInfo.uid);
        } else {
            Slog.w(TAG, "Permission Denial: broadcasting "
                    + broadcastDescription(r, component)
                    + " requires " + info.activityInfo.permission);
        }
        skip = true;
    } else if (!skip && info.activityInfo.permission != null) {
        final int opCode = AppOpsManager.permissionToOpCode(info.activityInfo.permission);
        if (opCode != AppOpsManager.OP_NONE && mService.getAppOpsManager().noteOpNoThrow(opCode,
                r.callingUid, r.callerPackage, r.callerFeatureId,
                "Broadcast delivered to " + info.activityInfo.name)
                != AppOpsManager.MODE_ALLOWED) {
            Slog.w(TAG, "Appop Denial: broadcasting "
                    + broadcastDescription(r, component)
                    + " requires appop " + AppOpsManager.permissionToOp(
                            info.activityInfo.permission));
            skip = true;
        }
    }

    boolean isSingleton = false;
    try {
        isSingleton = mService.isSingleton(info.activityInfo.processName,
                info.activityInfo.applicationInfo,
                info.activityInfo.name, info.activityInfo.flags);
    } catch (SecurityException e) {
        Slog.w(TAG, e.getMessage());
        skip = true;
    }
    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) {
            Slog.w(TAG, "Permission Denial: Receiver " + component.flattenToShortString()
                    + " requests FLAG_SINGLE_USER, but app does not hold "
                    + android.Manifest.permission.INTERACT_ACROSS_USERS);
            skip = true;
        }
    }
    if (!skip && info.activityInfo.applicationInfo.isInstantApp()
            && r.callingUid != info.activityInfo.applicationInfo.uid) {
        Slog.w(TAG, "Instant App Denial: receiving "
                + r.intent
                + " to " + component.flattenToShortString()
                + " due to sender " + r.callerPackage
                + " (uid " + r.callingUid + ")"
                + " Instant Apps do not support manifest receivers");
        skip = true;
    }
    if (!skip && r.callerInstantApp
            && (info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0
            && r.callingUid != info.activityInfo.applicationInfo.uid) {
        Slog.w(TAG, "Instant App Denial: receiving "
                + r.intent
                + " to " + component.flattenToShortString()
                + " requires receiver have visibleToInstantApps set"
                + " due to sender " + r.callerPackage
                + " (uid " + r.callingUid + ")");
        skip = true;
    }
    if (r.curApp != null && r.curApp.mErrorState.isCrashing()) {
        // If the target process is crashing, just skip it.
        Slog.w(TAG, "Skipping deliver ordered [" + mQueueName + "] " + r
                + " to " + r.curApp + ": process 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) {
            // all such failures mean we skip this receiver
            Slog.w(TAG, "Exception getting recipient info for "
                    + info.activityInfo.packageName, e);
        }
        if (!isAvailable) {
            Slog.w(TAG_BROADCAST,
                    "Skipping delivery to " + info.activityInfo.packageName + " / "
                    + info.activityInfo.applicationInfo.uid
                    + " : package no longer available");
            skip = true;
        }
    }

    // If permissions need a review before any of the app components can run, we drop
    // the broadcast and if the calling app is in the foreground and the broadcast is
    // explicit we launch the review UI passing it a pending intent to send the skipped
    // broadcast.
    if (!skip) {
        if (!requestStartTargetPermissionsReviewIfNeededLocked(r,
                info.activityInfo.packageName, UserHandle.getUserId(
                        info.activityInfo.applicationInfo.uid))) {
            Slog.w(TAG_BROADCAST,
                    "Skipping delivery: permission review required for "
                            + broadcastDescription(r, component));
            skip = true;
        }
    }

    // This is safe to do even if we are skipping the broadcast, and we need
    // this information now to evaluate whether it is going to be allowed to run.
    final int receiverUid = info.activityInfo.applicationInfo.uid;
    // If it's a singleton, it needs to be the same app or a special app
    if (r.callingUid != Process.SYSTEM_UID && isSingleton
            && mService.isValidSingletonCall(r.callingUid, receiverUid)) {
        info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0);
    }
    String targetProcess = info.activityInfo.processName;
    ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
            info.activityInfo.applicationInfo.uid);

    if (!skip) {
        final int allowed = mService.getAppStartModeLOSP(
                info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
                info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false, false);
        if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
            // We won't allow this receiver to be launched if the app has been
            // completely disabled from launches, or it was not explicitly sent
            // to it and the app is in a state that should not receive it
            // (depending on how getAppStartModeLOSP has determined that).
            if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
                Slog.w(TAG, "Background execution disabled: receiving "
                        + r.intent + " to "
                        + component.flattenToShortString());
                skip = true;
            } else if (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)
                    || (r.intent.getComponent() == null
                        && r.intent.getPackage() == null
                        && ((r.intent.getFlags()
                                & Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0)
                        && !isSignaturePerm(r.requiredPermissions))) {
                mService.addBackgroundCheckViolationLocked(r.intent.getAction(),
                        component.getPackageName());
                Slog.w(TAG, "Background execution not allowed: receiving "
                        + r.intent + " to "
                        + component.flattenToShortString());
                skip = true;
            }
        }
    }

    if (!skip && !Intent.ACTION_SHUTDOWN.equals(r.intent.getAction())
            && !mService.mUserController
            .isUserRunning(UserHandle.getUserId(info.activityInfo.applicationInfo.uid),
                    0 /* flags */)) {
        skip = true;
        Slog.w(TAG,
                "Skipping delivery to " + info.activityInfo.packageName + " / "
                        + info.activityInfo.applicationInfo.uid + " : user is not running");
    }

    if (!skip && r.excludedPermissions != null && r.excludedPermissions.length > 0) {
        for (int i = 0; i < r.excludedPermissions.length; i++) {
            String excludedPermission = r.excludedPermissions[i];
            try {
                perm = AppGlobals.getPackageManager()
                    .checkPermission(excludedPermission,
                            info.activityInfo.applicationInfo.packageName,
                            UserHandle
                            .getUserId(info.activityInfo.applicationInfo.uid));
            } catch (RemoteException e) {
                perm = PackageManager.PERMISSION_DENIED;
            }

            int appOp = AppOpsManager.permissionToOpCode(excludedPermission);
            if (appOp != AppOpsManager.OP_NONE) {
                // When there is an app op associated with the permission,
                // skip when both the permission and the app op are
                // granted.
                if ((perm == PackageManager.PERMISSION_GRANTED) && (
                            mService.getAppOpsManager().checkOpNoThrow(appOp,
                            info.activityInfo.applicationInfo.uid,
                            info.activityInfo.packageName)
                        == AppOpsManager.MODE_ALLOWED)) {
                    skip = true;
                    break;
                }
            } else {
                // When there is no app op associated with the permission,
                // skip when permission is granted.
                if (perm == PackageManager.PERMISSION_GRANTED) {
                    skip = true;
                    break;
                }
            }
        }
    }

    // Check that the receiver does *not* belong to any of the excluded packages
    if (!skip && r.excludedPackages != null && r.excludedPackages.length > 0) {
        if (ArrayUtils.contains(r.excludedPackages, component.getPackageName())) {
            Slog.w(TAG, "Skipping delivery of excluded package "
                    + r.intent + " to "
                    + component.flattenToShortString()
                    + " excludes package " + component.getPackageName()
                    + " due to sender " + r.callerPackage
                    + " (uid " + r.callingUid + ")");
            skip = true;
        }
    }

    if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
            r.requiredPermissions != null && r.requiredPermissions.length > 0) {
        for (int i = 0; i < r.requiredPermissions.length; i++) {
            String requiredPermission = r.requiredPermissions[i];
            try {
                perm = AppGlobals.getPackageManager().
                        checkPermission(requiredPermission,
                                info.activityInfo.applicationInfo.packageName,
                                UserHandle
                                .getUserId(info.activityInfo.applicationInfo.uid));
            } catch (RemoteException e) {
                perm = PackageManager.PERMISSION_DENIED;
            }
            if (perm != PackageManager.PERMISSION_GRANTED) {
                Slog.w(TAG, "Permission Denial: receiving "
                        + r.intent + " to "
                        + component.flattenToShortString()
                        + " requires " + requiredPermission
                        + " due to sender " + r.callerPackage
                        + " (uid " + r.callingUid + ")");
                skip = true;
                break;
            }
            int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
            if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp) {
                if (!noteOpForManifestReceiver(appOp, r, info, component)) {
                    skip = true;
                    break;
                }
            }
        }
    }
    if (!skip && r.appOp != AppOpsManager.OP_NONE) {
        if (!noteOpForManifestReceiver(r.appOp, r, info, component)) {
            skip = true;
        }
    }

    if (skip) {
        if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                "Skipping delivery of ordered [" + mQueueName + "] "
                + r + " for reason described above");
        r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED;
        r.receiver = null;
        r.curFilter = null;
        r.state = BroadcastRecord.IDLE;
        r.manifestSkipCount++;
        scheduleBroadcastsLocked();
        return;
    }
    r.manifestCount++;

    r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;
    r.state = BroadcastRecord.APP_RECEIVE;
    r.curComponent = component;
    r.curReceiver = info.activityInfo;
    if (DEBUG_MU && r.callingUid > UserHandle.PER_USER_RANGE) {
        Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, "
                + info.activityInfo + ", callingUid = " + r.callingUid + ", uid = "
                + receiverUid);
    }
    final boolean isActivityCapable =
            (brOptions != null && brOptions.getTemporaryAppAllowlistDuration() > 0);
    maybeScheduleTempAllowlistLocked(receiverUid, r, brOptions);

    // Report that a component is used for explicit broadcasts.
    if (r.intent.getComponent() != null && r.curComponent != null
            && !TextUtils.equals(r.curComponent.getPackageName(), r.callerPackage)) {
        mService.mUsageStatsService.reportEvent(
                r.curComponent.getPackageName(), r.userId, Event.APP_COMPONENT_USED);
    }

    // Broadcast is being executed, its package can't be stopped.
    try {
        AppGlobals.getPackageManager().setPackageStoppedState(
                r.curComponent.getPackageName(), false, r.userId);
    } catch (RemoteException e) {
    } catch (IllegalArgumentException e) {
        Slog.w(TAG, "Failed trying to unstop package "
                + r.curComponent.getPackageName() + ": " + e);
    }

    // Is this receiver's application already running?
    if (app != null && app.getThread() != null && !app.isKilled()) {
        try {
            app.addPackage(info.activityInfo.packageName,
                    info.activityInfo.applicationInfo.longVersionCode, mService.mProcessStats);
            maybeAddAllowBackgroundActivityStartsToken(app, r);
            processCurBroadcastLocked(r, app,
                    BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__MANIFEST,
                    BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM);
            return;
        } catch (RemoteException e) {
            Slog.w(TAG, "Exception when sending broadcast to "
                  + r.curComponent, e);
        } catch (RuntimeException e) {
            Slog.wtf(TAG, "Failed sending broadcast to "
                    + r.curComponent + " with " + r.intent, e);
            // If some unexpected exception happened, just skip
            // this broadcast.  At this point we are not in the call
            // from a client, so throwing an exception out from here
            // will crash the entire system instead of just whoever
            // sent the broadcast.
            logBroadcastReceiverDiscardLocked(r);
            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 a dead object exception was thrown -- fall through to
        // restart the application.
    }

    // Not running -- get it started, to be executed when the app comes up.
    if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
            "Need to start app ["
            + mQueueName + "] " + targetProcess + " for broadcast " + r);
    r.curApp = mService.startProcessLocked(targetProcess,
            info.activityInfo.applicationInfo, true,
            r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
            new HostingRecord(HostingRecord.HOSTING_TYPE_BROADCAST, r.curComponent,
                    r.intent.getAction()),
            isActivityCapable ? ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE : ZYGOTE_POLICY_FLAG_EMPTY,
            (r.intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false);
    if (r.curApp == null) {
        // Ah, this recipient is unavailable.  Finish it if necessary,
        // and mark the broadcast record as ready for the next.
        Slog.w(TAG, "Unable to launch app "
                + info.activityInfo.applicationInfo.packageName + "/"
                + receiverUid + " for broadcast "
                + r.intent + ": process is bad");
        logBroadcastReceiverDiscardLocked(r);
        finishReceiverLocked(r, r.resultCode, r.resultData,
                r.resultExtras, r.resultAbort, false);
        scheduleBroadcastsLocked();
        r.state = BroadcastRecord.IDLE;
        return;
    }

    maybeAddAllowBackgroundActivityStartsToken(r.curApp, r);
    mPendingBroadcast = r;
    mPendingBroadcastRecvIndex = recIdx;
}

processNextBroadcastLocked()函数是广播发送的核心内容,代码非常多,下面我们从几个方面来分析:

无序广播

BroadcastRecord r;//BroadcastRecord广播的记录者,需要分发的广播

if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast ["
        + mQueueName + "]: "
        + mParallelBroadcasts.size() + " parallel broadcasts; "
        + mDispatcher.describeStateLocked());

mService.updateCpuStats();

if (fromMsg) {// 否是来自handleMessage的BROADCAST_INTENT_MSG类型消息
    // 前面说到,如果消息队列里面有BROADCAST_INTENT_MSG消息,该标记为true,阻止新的消息加入队列,
    // 这里开始处理这个消息的时候,将mBroadcastsScheduled变量设置为false,开始允许新的消息加入。
    mBroadcastsScheduled = false;
}

// First, deliver any non-serialized broadcasts right away.
// 无序广播之间不存在相互等待,这里处理的是保存在无序广播调度队列mParallelBroadcasts中的广播发送任务,
// 即把保存在无序广播调度队列mParallelBroadcasts中的广播发送给它的目标广播接收者处理
while (mParallelBroadcasts.size() > 0) {
    // 首先获取保存无序广播调度队列mParallelBroadcasts中的每一个BroadcastRecord对象
    r = mParallelBroadcasts.remove(0);
    r.dispatchTime = SystemClock.uptimeMillis();//设置BroadcastRecord r广播分发时间dispatchTime
    r.dispatchRealTime = SystemClock.elapsedRealtime();
    r.dispatchClockTime = System.currentTimeMillis();//System.currentTimeMillis()获取的是系统时钟的时间,修改系统时间这个时间会变化

    if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
        Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
            createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),
            System.identityHashCode(r));
        Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
            createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),
            System.identityHashCode(r));
    }

    //获取BroadcastRecord中的所有广播接收者的数量
    final int N = r.receivers.size();
    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
            + mQueueName + "] " + r);
    for (int i=0; i<N; i++) {//遍历构建 BroadcastRecord 的所有receivers
        Object target = r.receivers.get(i);
        if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                "Delivering non-ordered on [" + mQueueName + "] to registered "
                + target + ": " + r);
        // 调用deliverToRegisteredReceiverLocked向所有的receivers发送广播
        // 将它所描述的每一个无序广播发送给每一个广播接收者,异步处理广播
        // 通过deliverToRegisteredReceiverLocked调用ActivityThread.scheduleRegisteredReceiver处理广播
        deliverToRegisteredReceiverLocked(r,
                (BroadcastFilter) target, false, i);
    }
    addBroadcastToHistoryLocked(r);
    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
            + mQueueName + "] " + r);
}

无序广播接收者不需要等待,所以直接for循环执行,调用deliverToRegisteredReceiverLocked方法发送广播。

deliverToRegisteredReceiverLocked
//执行动态注册的广播接收者的发送接受过程
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
        BroadcastFilter filter, boolean ordered, int index) {
    // 标记是否要跳过该广播接收者
    boolean skip = false;

    //skip的场景
    ...

    // 检查广播发送者的权限
    // Check that the sender has permission to send to this receiver
    if (filter.requiredPermission != null) {
        int perm = mService.checkComponentPermission(filter.requiredPermission,
                r.callingPid, r.callingUid, -1, true);
        if (perm != PackageManager.PERMISSION_GRANTED) {
            Slog.w(TAG, "Permission Denial: broadcasting "
                    + r.intent.toString()
                    + " from " + r.callerPackage + " (pid="
                    + r.callingPid + ", uid=" + r.callingUid + ")"
                    + " requires " + filter.requiredPermission
                    + " due to registered receiver " + filter);
            skip = true;
        } else {
            final int opCode = AppOpsManager.permissionToOpCode(filter.requiredPermission);
            if (opCode != AppOpsManager.OP_NONE
                    && mService.getAppOpsManager().noteOpNoThrow(opCode, r.callingUid,
                    r.callerPackage, r.callerFeatureId, "Broadcast sent to protected receiver")
                    != AppOpsManager.MODE_ALLOWED) {
                Slog.w(TAG, "Appop Denial: broadcasting "
                        + r.intent.toString()
                        + " from " + r.callerPackage + " (pid="
                        + r.callingPid + ", uid=" + r.callingUid + ")"
                        + " requires appop " + AppOpsManager.permissionToOp(
                                filter.requiredPermission)
                        + " due to registered receiver " + filter);
                skip = true;
            }
        }
    }

    // 如果要跳过,则设置该广播结束
    if (!skip && (filter.receiverList.app == null || filter.receiverList.app.isKilled()
            || filter.receiverList.app.mErrorState.isCrashing())) {
        Slog.w(TAG, "Skipping deliver [" + mQueueName + "] " + r
                + " to " + filter.receiverList + ": process gone or crashing");
        skip = true;
    }

    //Instant Apps skip的场景
    ...

    // 检查广播发送者的权限
    // Check that the receiver has the required permission(s) to receive this broadcast.
    if (!skip && r.requiredPermissions != null && r.requiredPermissions.length > 0) {
        for (int i = 0; i < r.requiredPermissions.length; i++) {
            String requiredPermission = r.requiredPermissions[i];
            int perm = mService.checkComponentPermission(requiredPermission,
                    filter.receiverList.pid, filter.receiverList.uid, -1, true);
            if (perm != PackageManager.PERMISSION_GRANTED) {
                Slog.w(TAG, "Permission Denial: receiving "
                        + r.intent.toString()
                        + " to " + filter.receiverList.app
                        + " (pid=" + filter.receiverList.pid
                        + ", uid=" + filter.receiverList.uid + ")"
                        + " requires " + requiredPermission
                        + " due to sender " + r.callerPackage
                        + " (uid " + r.callingUid + ")");
                skip = true;
                break;
            }
            int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
            if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
                    && mService.getAppOpsManager().noteOpNoThrow(appOp,
                    filter.receiverList.uid, filter.packageName, filter.featureId,
                    "Broadcast delivered to registered receiver " + filter.receiverId)
                    != AppOpsManager.MODE_ALLOWED) {
                Slog.w(TAG, "Appop Denial: receiving "
                        + r.intent.toString()
                        + " to " + filter.receiverList.app
                        + " (pid=" + filter.receiverList.pid
                        + ", uid=" + filter.receiverList.uid + ")"
                        + " requires appop " + AppOpsManager.permissionToOp(
                        requiredPermission)
                        + " due to sender " + r.callerPackage
                        + " (uid " + r.callingUid + ")");
                skip = true;
                break;
            }
        }
    }
    if (!skip && (r.requiredPermissions == null || r.requiredPermissions.length == 0)) {
        int perm = mService.checkComponentPermission(null,
                filter.receiverList.pid, filter.receiverList.uid, -1, true);
        if (perm != PackageManager.PERMISSION_GRANTED) {
            Slog.w(TAG, "Permission Denial: security check failed when receiving "
                    + r.intent.toString()
                    + " to " + filter.receiverList.app
                    + " (pid=" + filter.receiverList.pid
                    + ", uid=" + filter.receiverList.uid + ")"
                    + " due to sender " + r.callerPackage
                    + " (uid " + r.callingUid + ")");
            skip = true;
        }
    }

    //permissions to exclude
    //packages to exclude
    //检查
    ...


    //如果要跳过,则设置该广播结束
    if (skip) {
        r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
        return;
    }

    // If permissions need a review before any of the app components can run, we drop
    // the broadcast and if the calling app is in the foreground and the broadcast is
    // explicit we launch the review UI passing it a pending intent to send the skipped
    // broadcast.
    if (!requestStartTargetPermissionsReviewIfNeededLocked(r, filter.packageName,
            filter.owningUserId)) {
        r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
        return;
    }

    r.delivery[index] = BroadcastRecord.DELIVERY_DELIVERED;

    // If this is not being sent as an ordered broadcast, then we
    // don't want to touch the fields that keep track of the current
    // state of ordered broadcasts.
    //order广播,所有的接收者需要依次以一种同步的方式发送广播,
    //可以看到order广播在BroadcastRecord保存了几个状态
    if (ordered) {
        // IBinder类型,代表当前的接收者
        r.receiver = filter.receiverList.receiver.asBinder();
        // 当前正在处理的BroadcastFilter,和上面的receiver是对应好的
        r.curFilter = filter;
        filter.receiverList.curBroadcast = r;
        r.state = BroadcastRecord.CALL_IN_RECEIVE;
        if (filter.receiverList.app != null) {
            // Bump hosting application to no longer be in background
            // scheduling class.  Note that we can't do that if there
            // isn't an app...  but we can only be in that case for
            // things that directly call the IActivityManager API, which
            // are already core system stuff so don't matter for this.
            r.curApp = filter.receiverList.app;
            filter.receiverList.app.mReceivers.addCurReceiver(r);
            mService.enqueueOomAdjTargetLocked(r.curApp);
            mService.updateOomAdjPendingTargetsLocked(
                    OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
        }
    } else if (filter.receiverList.app != null) {
        mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(filter.receiverList.app);
    }

    try {
        if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
                "Delivering to " + filter + " : " + r);
        if (filter.receiverList.app != null && filter.receiverList.app.isInFullBackup()) {
            // Skip delivery if full backup in progress
            // If it's an ordered broadcast, we need to continue to the next receiver.
            if (ordered) {
                // 如果正在备份或者恢复备份跳过,
                // 如果是一个有序广播,则执行下一个广播
                skipReceiverLocked(r);
            }
        } else {
            r.receiverTime = SystemClock.uptimeMillis();
            maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
            maybeScheduleTempAllowlistLocked(filter.owningUid, r, r.options);
            maybeReportBroadcastDispatchedEventLocked(r, filter.owningUid);
            //如果不需要进行权限检查或者通过权限检查,调用performReceiveLocked发送广播
            performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                    new Intent(r.intent), r.resultCode, r.resultData,
                    r.resultExtras, r.ordered, r.initialSticky, r.userId,
                    filter.receiverList.uid, r.callingUid);
            // parallel broadcasts are fire-and-forget, not bookended by a call to
            // finishReceiverLocked(), so we manage their activity-start token here
            if (filter.receiverList.app != null
                    && r.allowBackgroundActivityStarts && !r.ordered) {
                postActivityStartTokenRemoval(filter.receiverList.app, r);
            }
        }
        if (ordered) {
            r.state = BroadcastRecord.CALL_DONE_RECEIVE;
        }
    } catch (RemoteException e) {
        Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
        // Clean up ProcessRecord state related to this broadcast attempt
        if (filter.receiverList.app != null) {
            filter.receiverList.app.removeAllowBackgroundActivityStartsToken(r);
            if (ordered) {
                filter.receiverList.app.mReceivers.removeCurReceiver(r);
                // Something wrong, its oom adj could be downgraded, but not in a hurry.
                mService.enqueueOomAdjTargetLocked(r.curApp);
            }
        }
        // And BroadcastRecord state related to ordered delivery, if appropriate
        if (ordered) {
            r.receiver = null;
            r.curFilter = null;
            filter.receiverList.curBroadcast = null;
        }
    }
}

这个方法中主要做了权限校验,然后派发。

  • 跳过skip的场景
  • 检查广播发送者的权限
//注册者 申请权限
//发送者 未设置权限
11-11 03:24:54.935  2596  2938 W BroadcastQueue: Permission Denial: broadcasting Intent { act=android.intent.action.extfwk.test flg=0x10 } from com.android.extfwk (pid=11568, uid=10205) requires android.permission.extfwk.test due to registered receiver BroadcastFilter{4a03f68 1000/u0 ReceiverList{c0d228b 11361 com.android.systemui/1000/u0 remote:ccee05a}}
  • 检查广播接收者的权限
//注册者 未申请权限
//发送者 设置权限
11-11 03:29:34.723  2596  2938 W BroadcastQueue: Permission Denial: receiving Intent { act=android.intent.action.extfwk.test flg=0x10 } to ProcessRecord{2501df2 12153:com.android.extfwk/u0a205} (pid=12153, uid=10205) requires android.permission.extfwk.test due to sender com.android.bctest (uid 1000)
  • 调用performReceiveLocked()派发

检查权限的调用流程:

mService.checkComponentPermission(), mService是ActivityManagerService
---> ActivityManagerService.checkComponentPermission()
    ---> ActivityManager.checkComponentPermission()
        ---> AppGlobals.getPackageManager().checkUidPermission()
            ---> PackageManagerService.checkUidPermission() , 
                    IPackageManagerImpl iPackageManager = m.new IPackageManagerImpl();
                    ServiceManager.addService("package", iPackageManager);

                    public class IPackageManagerImpl extends IPackageManagerBase {}

                    IPackageManagerBase.checkUidPermission --->  snapshot().checkUidPermission(permName, uid);
                        ---> ComputerEngine.checkUidPermission()
                            ---> PermissionManager.checkUidPermission()
                                ---> PermissionManagerService.checkUidPermission()
performReceiveLocked
void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
        Intent intent, int resultCode, String data, Bundle extras,
        boolean ordered, boolean sticky, int sendingUser,
        int receiverUid, int callingUid) throws RemoteException {
    // Send the intent to the receiver asynchronously using one-way binder calls.
    if (app != null) {
        final IApplicationThread thread = app.getThread();
        if (thread != null) {// 因为是动态注册广播,所以不为空
            // If we have an app thread, do the call through that so it is
            // correctly ordered with other one-way calls.
            try {
                // 调用ApplicationThread对象的Binder代理对象的函数来向它发送广播
                // ActivityThread.java的scheduleRegisteredReceiver(这里已经是app线程了)
                thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                        data, extras, ordered, sticky, sendingUser,
                        app.mState.getReportedProcState());
            // TODO: Uncomment this when (b/28322359) is fixed and we aren't getting
            // DeadObjectException when the process isn't actually dead.
            //} catch (DeadObjectException ex) {
            // Failed to call into the process.  It's dying so just let it die and move on.
            //    throw ex;
            } catch (RemoteException ex) {
                // Failed to call into the process. It's either dying or wedged. Kill it gently.
                synchronized (mService) {
                    Slog.w(TAG, "Can't deliver broadcast to " + app.processName
                            + " (pid " + app.getPid() + "). Crashing it.");
                    app.scheduleCrashLocked("can't deliver broadcast",
                            CannotDeliverBroadcastException.TYPE_ID, /* extras=*/ null);
                }
                throw ex;
            }
        } else {
            // Application has died. Receiver doesn't exist.
            throw new RemoteException("app.thread must not be null");
        }
    } else {
        // 直接调用与它关联的一个InnerReceiver对象的Binder代理对象的成员函数performReceive来向它发送广播
        receiver.performReceive(intent, resultCode, data, extras, ordered,
                sticky, sendingUser);
    }
    FrameworkStatsLog.write(BROADCAST_DELIVERY_EVENT_REPORTED,
            receiverUid == -1 ? Process.SYSTEM_UID : receiverUid,
            callingUid == -1 ? Process.SYSTEM_UID : callingUid,
            ActivityManagerService.getShortAction(intent.getAction()),
            BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__RUNTIME,
            BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM);
}

当一个Activity或者一个Service将一个广播接收者注册到AMS中时,它所在的应用程序进程会先将这个广播接收者封装成一个类型为InnerReceiver的Binder本地对象,然后再注册到AMS中。因此当AMS要将一个广播发给一个目标广播接收者处理时,实际上是将这个广播转发给封装了这个目标广播接收者的一个InnerReceiver对象来处理。

AMS向一个应用程序进程发送一个广播时,采用的是异步进程间通信方式。前面提到,发送给一个Binder实体对象的所有异步事物都是保存在一个异步事物队列中的。由于保存在一个异步事物队列中的异步事物在同一时刻只有一个会得到处理,即只有队列头部的异步事物才会得到处理,因此AMS就可以保证它发送给同一个应用程序的所有广播都是按照这个发送顺序来串行的被接受和处理。

ActivityThread.scheduleRegisteredReceiver
// This function exists to make sure all receiver dispatching is
// correctly ordered, since these are one-way calls and the binder driver
// applies transaction ordering per object for such calls.
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);
}

处理非串行化动态广播,非串化ordered是false,这里的receiver对应的是LoadedApk.ReceiverDispatcher.InnerReceiver对象。从函数里可以看到,这里和第上步的else分支一样,最终还是执行receiver.performReceive方法来发送广播。

InnerReceiver.performReceive
public final class LoadedApk {
    static final class ReceiverDispatcher {

        final static class InnerReceiver extends IIntentReceiver.Stub {
            final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;


            @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) {
                    Log.wtf(TAG, "Null intent received");
                    rd = null;
                } else {
                    //获取rd的实例对象
                    rd = mDispatcher.get();
                }
                if (ActivityThread.DEBUG_BROADCAST) {
                    int seq = intent.getIntExtra("seq", -1);
                    Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction()
                            + " seq=" + seq + " to " + (rd != null ? rd.mReceiver : null));
                }
                if (rd != null) {
                    //存在广播,rd 不为空,调用LoadedApk.ReceiverDispatcher对象的performReceive方法
                    rd.performReceive(intent, resultCode, data, extras,
                            ordered, sticky, sendingUser);
                } else {
                    // The activity manager dispatched a broadcast to a registered
                    // receiver in this process, but before it could be delivered the
                    // receiver was unregistered.  Acknowledge the broadcast on its
                    // behalf so that the system's broadcast sequence can continue.
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing broadcast to unregistered receiver");
                    IActivityManager mgr = ActivityManager.getService();
                    try {
                        if (extras != null) {
                            extras.setAllowFds(false);
                        }
                        //不存在广播,rd为空,调用activityManagerService对象的finishReceiver结束广播的发送接受过程
                        mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
                    } catch (RemoteException e) {
                        throw e.rethrowFromSystemServer();
                    }
                }
            }
        }

    }
}

LoadedApk.ReceiverDispatcher对象封装了广播接收者,如果该广播接收者注册了,那么该对象就会存在,这里就会调用LodedApk.ReceiverDispatcher.performReceive,否则就会调用AMS.finishReceiver方法,这里我们先看存在广播的情况。

ReceiverDispatcher.performReceive
public final class LoadedApk {
    static final class ReceiverDispatcher {


        public void performReceive(Intent intent, int resultCode, String data,
                Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
            // 首先将参数Intent所描述的一个广播封装成一个Args对象,然后将这个Args对象封装成一个消息对象,
            // 然后将这个消息对象发送到应用程序主线程的消息队列中。
            final Args args = new Args(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
            if (intent == null) {
                Log.wtf(TAG, "Null intent received");
            } else {
                if (ActivityThread.DEBUG_BROADCAST) {
                    int seq = intent.getIntExtra("seq", -1);
                    Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction()
                            + " seq=" + seq + " to " + mReceiver);
                }
            }
            // 将args对象post到主线程的消息队列里面,作为一个Runnable调度而不是在handleMessage中处理,
            // 因此这里不久后会调用Args.run函数
            if (intent == null || !mActivityThread.post(args.getRunnable())) {
                if (mRegistered && ordered) {
                    IActivityManager mgr = ActivityManager.getService();
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing sync broadcast to " + mReceiver);
                    args.sendFinished(mgr);
                }
            }
        }

    }
}

初始化了一个Args对象,该对象实现了Runnable接口,在if语句中调用post方法,最终会调用Args中的run方法。

这个方法的重点在于mActivityThread.post(args.getRunnable()),不要被mActivityThread的名字迷惑,其实这是一个Handler,正是在广播动态注册的时候设置的那个handler通过这个post,切换了线程,开始执行receiver。

Args.run
static final class ReceiverDispatcher {

    final class Args extends BroadcastReceiver.PendingResult {
        private Intent mCurIntent;
        private final boolean mOrdered;
        private boolean mDispatched;
        private boolean mRunCalled;

        public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras,
                boolean ordered, boolean sticky, int sendingUser) {
            super(resultCode, resultData, resultExtras,
                    mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered,
                    sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags());
            mCurIntent = intent;
            mOrdered = ordered;
        }

        public final Runnable getRunnable() {
            return () -> {
                //mReceiver指向一个广播接收者
                final BroadcastReceiver receiver = mReceiver;
                final boolean ordered = mOrdered;

                if (ActivityThread.DEBUG_BROADCAST) {
                    int seq = mCurIntent.getIntExtra("seq", -1);
                    Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction()
                            + " seq=" + seq + " to " + mReceiver);
                    Slog.i(ActivityThread.TAG, "  mRegistered=" + mRegistered
                            + " mOrderedHint=" + ordered);
                }

                final IActivityManager mgr = ActivityManager.getService();
                final Intent intent = mCurIntent;
                if (intent == null) {
                    Log.wtf(TAG, "Null intent being dispatched, mDispatched=" + mDispatched
                            + (mRunCalled ? ", run() has already been called" : ""));
                }

                mCurIntent = null;
                mDispatched = true;
                mRunCalled = true;
                if (receiver == null || intent == null || mForgotten) {
                    if (mRegistered && ordered) {
                        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                "Finishing null broadcast to " + mReceiver);
                        //receiver为空直接发送finish
                        sendFinished(mgr);
                    }
                    return;
                }

                if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                            "broadcastReceiveReg: " + intent.getAction());
                }

                try {
                    //这里处理的是动态广播接收者,默认认为接收者BroadcastReceiver已经存在
                    ClassLoader cl = mReceiver.getClass().getClassLoader();
                    intent.setExtrasClassLoader(cl);
                    // TODO: determine at registration time if caller is
                    // protecting themselves with signature permission
                    intent.prepareToEnterProcess(ActivityThread.isProtectedBroadcast(intent),
                            mContext.getAttributionSource());
                    setExtrasClassLoader(cl);
                    receiver.setPendingResult(this);
                    // 终于看到了熟悉的onReceive回调了
                    receiver.onReceive(mContext, intent);
                } catch (Exception e) {
                    if (mRegistered && ordered) {//检查当前广播是否是有序广播,并且广播接收者是否已经注册到AMS中
                        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                "Finishing failed broadcast to " + mReceiver);
                        //通知AMS,它前面转发过来的有序广播已经处理完了,这时AMS就可以继续将这个有序广播转发给下一个目标广播接收者了
                        sendFinished(mgr);
                    }
                    if (mInstrumentation == null ||
                            !mInstrumentation.onException(mReceiver, e)) {
                        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                        throw new RuntimeException(
                                "Error receiving broadcast " + intent
                                        + " in " + mReceiver, e);
                    }
                }

                //只有有序广播才会执行此步骤
                if (receiver.getPendingResult() != null) {
                    finish();
                }
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            };
        }
    }

}

在这里调用BroadcastReceiver.onReceive方法,这样就会执行完一次无序广播的发送接受过程。

如果是有序广播则还需要发送finish。

LodedApk.ReceiverDispatcher.performReceive函数中,如果广播不存在就会调用AMS.finishReceiver方法,所以下面我们看AMS.finishReceiver()流程。

AMS.finishReceiver()
public void finishReceiver(IBinder who, int resultCode, String resultData,
            Bundle resultExtras, boolean resultAbort, int flags) {
    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Finish receiver: " + who);

    // Refuse possible leaked file descriptors
    if (resultExtras != null && resultExtras.hasFileDescriptors()) {
        throw new IllegalArgumentException("File descriptors passed in Bundle");
    }

    final long origId = Binder.clearCallingIdentity();
    try {
        boolean doNext = false;
        BroadcastRecord r;
        BroadcastQueue queue;

        // 首先辨别出当前receiver所在的BroadcastRecord属于前台广播还是后台广播,然后在对应的
        // BroadcastQueue中找出对应的BroadcastRecord,里面的finishReceiverLocked函数在前面介绍过,
        // 主要是重新设置BroadcastRecord里面一些状态变量,以便于BroadcastRecord将广播发送给下一个
        // 接收者。尤其的,如果前面的mAbortBroadcast设置为true,那么BroadcastRecord的成员resultAbort
        // 会设置成true
        synchronized(this) {
            if (isOnFgOffloadQueue(flags)) {
                queue = mFgOffloadBroadcastQueue;
            } else if (isOnBgOffloadQueue(flags)) {
                queue = mBgOffloadBroadcastQueue;
            } else {
                queue = (flags & Intent.FLAG_RECEIVER_FOREGROUND) != 0
                        ? mFgBroadcastQueue : mBgBroadcastQueue;
            }

            r = queue.getMatchingOrderedReceiver(who);
            if (r != null) {
                //结束当前正在发送的广播
                doNext = r.queue.finishReceiverLocked(r, resultCode,
                    resultData, resultExtras, resultAbort, true);
            }
            if (doNext) {
                //立马调度一次发送广播,发送下一次广播,但是processNextBroadcast是一个同步函数,一次只能处理一个请求
                r.queue.processNextBroadcastLocked(/*fromMsg=*/ false, /*skipOomAdj=*/ true);
            }
            // updateOomAdjLocked() will be done here
            trimApplicationsLocked(false, OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
        }

    } finally {
        Binder.restoreCallingIdentity(origId);
    }
}

如果发送广播时接收者不存在,那么要完成该次广播,并且判断是否执行发送给下一个广播接收者,如果需要发送给下个广播接收者要再次调用BroadcastQueue.processNextBroadcast方法,这样就又回到了前面的步骤。

有序广播

BroadcastQueue.processNextBroadcast方法中,该方法在执行完无序广播后开始执行有序广播。

处理Pending Broadcast
// Now take care of the next serialized one...

// If we are waiting for a process to come up to handle the next
// broadcast, then do nothing at this point.  Just in case, we
// check that the process we're waiting for still exists.
// mPendingBroadcast对象是用来描述一个正在等待静态注册的目标广播接收者启动起来的广播转发任务的
if (mPendingBroadcast != null) {
    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
            "processNextBroadcast [" + mQueueName + "]: waiting for "
            + mPendingBroadcast.curApp);

    boolean isDead;
    //是否存在这个进程的pid
    if (mPendingBroadcast.curApp.getPid() > 0) {
        synchronized (mService.mPidsSelfLocked) {
            //如果存在pid,则从mPidsSelfLocked中获取这个进程的ProcessRecord proc
            ProcessRecord proc = mService.mPidsSelfLocked.get(
                    mPendingBroadcast.curApp.getPid());
            //如果proc存在,而且没有发生crash,则isDead = false
            isDead = proc == null || proc.mErrorState.isCrashing();
        }
    } else {
        //进程的pid不存在,则从mProcessList通过名字获取该进程的ProcessRecord proc
        final ProcessRecord proc = mService.mProcessList.getProcessNamesLOSP().get(
                mPendingBroadcast.curApp.processName, mPendingBroadcast.curApp.uid);
        //如果proc存在,而且该进程正在启动中isPendingStart,则isDead = false
        isDead = proc == null || !proc.isPendingStart();
    }
    if (!isDead) {
        // It's still alive, so keep waiting
        // 如果应用已经启动,会调用AMS的函数来处理静态广播,这里直接return
        return;
    } else {
        //如果app死掉了
        Slog.w(TAG, "pending app  ["
                + mQueueName + "]" + mPendingBroadcast.curApp
                + " died before responding to broadcast");
        mPendingBroadcast.state = BroadcastRecord.IDLE;
        //下一次处理这个BroadcastRecord的nextReceiver还是这个recIdx
        mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
        //app死掉了清除mPendingBroadcast = null, 跳过这个mPendingBroadcast
        mPendingBroadcast = null;
    }
}

处理保存在有序广播调度队列mPendingBroadcast中的广播转发任务。从前面可知,有序广播调度队列mOrderedBroadcast描述的目标广播接收者有可能是静态注册的,而这些静态注册的目标广播接收者可能还没有启动起来,因此AMS将一个广播发送给它们处理时,首先将它们启动起来。事实上,AMS只需要将他们所运行在的进程启动起来就可以了,因为当这些进程接收到AMS发送的广播后,就会主动将目标广播接收者启动起来。

取出下一个广播
boolean looped = false;

do {//这里的do-while只会从mOrderedBroadcasts中取出第一个BroadcastRecord进行后续的处理
    final long now = SystemClock.uptimeMillis();
    //从 mOrderedBroadcasts 有序广播队列,依次取出来
    r = mDispatcher.getNextBroadcastLocked(now);

    if (r == null) {
        // No more broadcasts are deliverable right now, so all done!
        // 调度队列mOrderedBroadcasts中的广播已经全部处理完成
        mDispatcher.scheduleDeferralCheckLocked(false);
        synchronized (mService.mAppProfiler.mProfilerLock) {
            //AMS将所有挂起的gc进程mProcessesToGc进行按顺序的gc
            mService.mAppProfiler.scheduleAppGcsLPf();
        }
        if (looped && !skipOomAdj) {
            // If we had finished the last ordered broadcast, then
            // make sure all processes have correct oom and sched
            // adjustments.
            //adj调整
            mService.updateOomAdjPendingTargetsLocked(
                    OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
        }

        // when we have no more ordered broadcast on this queue, stop logging
        if (mService.mUserController.mBootCompleted && mLogLatencyMetrics) {
            mLogLatencyMetrics = false;
        }

        //结束本次processNextBroadcastLocked
        return;
    }

    // 是否需要强制结束recevie
    boolean forceReceive = false;

    // Ensure that even if something goes awry with the timeout
    // detection, we catch "hung" broadcasts here, discard them,
    // and continue to make progress.
    //
    // This is only done if the system is ready so that early-stage receivers
    // don't get executed with timeouts; and of course other timeout-
    // exempt broadcasts are ignored.
    // 接收者的个数
    int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
    // 1. systemReady之后mService.mProcessesReady = true
    // 2. timeoutExempt只有ACTION_PRE_BOOT_COMPLETED才会设置为true
    // 3. r.dispatchTime是开始分发该BroadcastRecord r的时间
    if (mService.mProcessesReady && !r.timeoutExempt && r.dispatchTime > 0) {
        // 1. 接收者的个数 > 0
        // 2. 当前时间now > r.dispatchTime + (2 * mConstants.TIMEOUT(10s/60s) * numReceivers)
        if ((numReceivers > 0) &&
                (now > r.dispatchTime + (2 * mConstants.TIMEOUT * numReceivers))) {
            Slog.w(TAG, "Hung broadcast ["
                    + mQueueName + "] discarded after timeout failure:"
                    + " now=" + now
                    + " dispatchTime=" + r.dispatchTime
                    + " startTime=" + r.receiverTime
                    + " intent=" + r.intent
                    + " numReceivers=" + numReceivers
                    + " nextReceiver=" + r.nextReceiver
                    + " state=" + r.state);
            //出现超时,强制结束
            broadcastTimeoutLocked(false); // forcibly finish this broadcast
            //重置参数,继续处理有序广播调度队列mOrderedBroadcasts的下一个广播转发任务
            forceReceive = true;
            r.state = BroadcastRecord.IDLE;
        }
    }

    if (r.state != BroadcastRecord.IDLE) {
        if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST,
                "processNextBroadcast("
                + mQueueName + ") called when not idle (state="
                + r.state + ")");
        return;
    }

    // Is the current broadcast is done for any reason?
    // r.resultAbort表示广播已经向所有的receiver发送结束或者中途被取消, 如果r.resultAbort为true,会停止处理当前正在发送的BroadcastRecord,这样优先级比较低的接收者也就收不到这个广播了
    // forceReceive检查BroadcastRecord对象r所描述的广播转发任务是否已经处理完成,或者是否已经被强制结束了。
    if (r.receivers == null || r.nextReceiver >= numReceivers
            || r.resultAbort || forceReceive) {
        // Send the final result if requested
        if (r.resultTo != null) {//是否有resultTo,如果有将结果回传resultTo
            boolean sendResult = true;

            // if this was part of a split/deferral complex, update the refcount and only
            // send the completion when we clear all of them
            if (r.splitToken != 0) {
                int newCount = mSplitRefcounts.get(r.splitToken) - 1;
                if (newCount == 0) {
                    // done!  clear out this record's bookkeeping and deliver
                    if (DEBUG_BROADCAST_DEFERRAL) {
                        Slog.i(TAG_BROADCAST,
                                "Sending broadcast completion for split token "
                                + r.splitToken + " : " + r.intent.getAction());
                    }
                    mSplitRefcounts.delete(r.splitToken);
                } else {
                    // still have some split broadcast records in flight; update refcount
                    // and hold off on the callback
                    if (DEBUG_BROADCAST_DEFERRAL) {
                        Slog.i(TAG_BROADCAST,
                                "Result refcount now " + newCount + " for split token "
                                + r.splitToken + " : " + r.intent.getAction()
                                + " - not sending completion yet");
                    }
                    sendResult = false;
                    mSplitRefcounts.put(r.splitToken, newCount);
                }
            }
            if (sendResult) {
                if (r.callerApp != null) {
                    mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(
                            r.callerApp);
                }
                try {
                    if (DEBUG_BROADCAST) {
                        Slog.i(TAG_BROADCAST, "Finishing broadcast [" + mQueueName + "] "
                                + r.intent.getAction() + " app=" + r.callerApp);
                    }
                    //将结果返回给app
                    performReceiveLocked(r.callerApp, r.resultTo,
                            new Intent(r.intent), r.resultCode,
                            r.resultData, r.resultExtras, false, false, r.userId,
                            r.callingUid, r.callingUid);
                    logBootCompletedBroadcastCompletionLatencyIfPossible(r);
                    // Set this to null so that the reference
                    // (local and remote) isn't kept in the mBroadcastHistory.
                    r.resultTo = null;
                } catch (RemoteException e) {
                    r.resultTo = null;
                    Slog.w(TAG, "Failure ["
                            + mQueueName + "] sending broadcast result of "
                            + r.intent, e);
                }
            }
        }

        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG");
        //取消广播超时
        cancelBroadcastTimeoutLocked();

        if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
                "Finished with ordered broadcast " + r);

        // ... and on to the next...
        //添加到广播历史中去,代表完成了
        addBroadcastToHistoryLocked(r);
        if (r.intent.getComponent() == null && r.intent.getPackage() == null
                && (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
            // This was an implicit broadcast... let's record it for posterity.
            mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage,
                    r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime);
        }
        //完成odered的广播后,在retireBroadcastLocked中设置mCurrentBroadcast = null(一般在r == mCurrentBroadcast时)
        mDispatcher.retireBroadcastLocked(r);
        r = null;
        looped = true;
        continue;
    }

    // Check whether the next receiver is under deferral policy, and handle that
    // accordingly.  If the current broadcast was already part of deferred-delivery
    // tracking, we know that it must now be deliverable as-is without re-deferral.
    // 如果这个广播没有进行延迟,则判断一下是否需要延迟
    if (!r.deferred) {
        // 获取下一个nextReceiver的uid
        final int receiverUid = r.getReceiverUid(r.receivers.get(r.nextReceiver));
        if (mDispatcher.isDeferringLocked(receiverUid)) {
            if (DEBUG_BROADCAST_DEFERRAL) {
                Slog.i(TAG_BROADCAST, "Next receiver in " + r + " uid " + receiverUid
                        + " at " + r.nextReceiver + " is under deferral");
            }
            // If this is the only (remaining) receiver in the broadcast, "splitting"
            // doesn't make sense -- just defer it as-is and retire it as the
            // currently active outgoing broadcast.
            BroadcastRecord defer;
            // 下一个Receiver将延迟,再下一个Receiver已经没有了
            if (r.nextReceiver + 1 == numReceivers) {
                if (DEBUG_BROADCAST_DEFERRAL) {
                    Slog.i(TAG_BROADCAST, "Sole receiver of " + r
                            + " is under deferral; setting aside and proceeding");
                }
                defer = r;
                // 下一个Receiver将延迟,再下一个Receiver已经没有了,
                // 则在retireBroadcastLocked中设置mCurrentBroadcast = null(一般在r == mCurrentBroadcast时)
                mDispatcher.retireBroadcastLocked(r);
            } else {
                ...
            }
            //将defer添加到延迟广播中,按照uid放入
            mDispatcher.addDeferredBroadcast(receiverUid, defer);
            r = null;
            looped = true;
            continue;
        }
    }
} while (r == null);
  • 广播已经全部处理完成

  • AMS将所有挂起的gc进程mProcessesToGc进行按顺序的gc

  • adj调整

  • 广播未处理完

  • 获取接收者的个数

  • 判断ANR

  • 接收者的个数 > 0

  • now > r.dispatchTime + (2 * mConstants.TIMEOUT(10s/60s) * numReceivers)

now = 当前时间

r.dispatchTime = 开始分发该BroadcastRecord r的时间

mConstants.TIMEOUT = 10s/60s

numReceivers = 接收者的个数

调用broadcastTimeoutLocked函数来强制结束这个广播转发任务,

  • 如果已经完成了广播发送,而且发送时有设置IIntentReceiver resultTo(结果返回的地方),则调用performReceiveLocked,返回结果给到resultTo

  • 如果已经完成了广播发送,则取消该order的超时设定,输出“Finished with ordered broadcast”类似日志

处理下一个接收者
// Get the next receiver...
//获取下一个将要处理的广播接收者在其列表中的位置
int recIdx = r.nextReceiver++;

// Keep track of when this receiver started, and make sure there
// is a timeout message pending to kill it if need be.
//设置receiver接受时间receiverTime(当前时间)
r.receiverTime = SystemClock.uptimeMillis();
if (recIdx == 0) {// 表示第一个开始处理的接收者,也就是BroadcastRecord对象r所描述的广播任务刚被处理
    r.dispatchTime = r.receiverTime;
    // 接收者开始处理的时间戳,也就是这个接收者开始处理了,要记录开始时间来计算是否超过超时时间
    // 也就是说这是BroadcastRecord中第一个接收者开始被处理的时间戳,也就是上面BroadcastRecord
    // 超时的起点,可以看到上面超时比较的时候用的就是r.dispatchTime
    r.dispatchRealTime = SystemClock.elapsedRealtime();
    //设置分发的系统时间(修改系统时间这个时间会变化)
    r.dispatchClockTime = System.currentTimeMillis();

    if (mLogLatencyMetrics) {//输出日志到FrameworkStatsLog中
        FrameworkStatsLog.write(
                FrameworkStatsLog.BROADCAST_DISPATCH_LATENCY_REPORTED,
                r.dispatchClockTime - r.enqueueClockTime);
    }

    //trace相关
    if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
        Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,
            createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),
            System.identityHashCode(r));
        Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
            createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),
            System.identityHashCode(r));
    }
    //输出开始发送order的广播
    if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing ordered broadcast ["
            + mQueueName + "] " + r);
}
//如果还没有设置超时时间,此处设置超时时间
if (! mPendingBroadcastTimeoutMessage) {
    //设置超时,传入参数是r.receiverTime + mTimeoutPeriod,也就是开始时间加上超时时间
    //mTimeoutPeriod,mTimeoutPeriod初始化是在BroadcastQueue初始化的时候传入的,
    //也就是在AMS(AMS构造函数中)中初始化mFgBroadcastQueue和mBgBroadcastQueue时传入的
    //BROADCAST_FG_TIMEOUT = 10 * 1000和BROADCAST_BG_TIMEOUT = 60 * 1000,
    //这里开始埋了ANR的雷
    long timeoutTime = r.receiverTime + mConstants.TIMEOUT;
    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
            "Submitting BROADCAST_TIMEOUT_MSG ["
            + mQueueName + "] for " + r + " at " + timeoutTime);
    setBroadcastTimeoutLocked(timeoutTime);
}
  • 第一个接收者会设置r.dispatchTime广播分发时间(SystemClock.uptimeMillis当前时间,不受系统时间修改影响)、r.dispatchClockTime分发的系统时间(System.currentTimeMillis,该时间会随系统时间变化而变化)
  • 设置超时时间setBroadcastTimeoutLocked(前台是10s超时,后台是60s超时,针对是单个注册者的时间),每个有序的接受者,都是从取出开始算时间r.receiverTime = SystemClock.uptimeMillis();
  • 开始处理时输出如:"Processing ordered broadcast"类似的日志
发送广播

上面分析的时候对于BroadcastRecord.receivers里面包含两种receiver接收者:order广播下的动态注册接收者和静态接收者,这两种receiver处理的方式是不一样的,对于order广播下的动态注册receiver而言,接收者进程一定是已经启动的,但是对于静态接收者receiver而言,当前的receiver进程可能还没有启动,因此动态和静态的receiver处理的逻辑不一样,需要分开处理,而静态接收者又分为进程已经启动和尚未启动两种情况。

所以发送广播这一部分我们分成三个小点来分析:动态注册有序广播接收者、进程已经启动的静态有序广播接收者、进程还未启动的静态有序广播接收者。

动态注册有序广播接收者
final BroadcastOptions brOptions = r.options;
//获取下一个接受者
final Object nextReceiver = r.receivers.get(recIdx);

// 如果当前nextReceiver是一个BroadcastFilter类型,说明是一个动态注册接收者,不需要启动一个进程,
// 直接调用deliverToRegisteredReceiverLocked函数发送广播
if (nextReceiver instanceof BroadcastFilter) {
    // Simple case: this is a registered receiver who gets
    // a direct call.
    BroadcastFilter filter = (BroadcastFilter)nextReceiver;
    if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
            "Delivering ordered ["
            + mQueueName + "] to registered "
            + filter + ": " + r);
    // 调用deliverToRegisteredReceiverLocked向所有的receivers发送广播
    // 将它所描述的每一个无序广播发送给每一个广播接收者,异步处理广播
    // 通过deliverToRegisteredReceiverLocked调用ActivityThread.scheduleRegisteredReceiver处理广播
    deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
    //如果r.receiver == null(没有正在执行的广播)
    //或者该广播是非order(无序)的
    if (r.receiver == null || !r.ordered) {
        // The receiver has already finished, so schedule to
        // process the next one.
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing ["
                + mQueueName + "]: ordered="
                + r.ordered + " receiver=" + r.receiver);
        // 设置IDLE状态,表示AMS不需要等待它的前一个目标广播接收者处理完成一个广播就可以将该广播
        // 继续发送给它的下一个目标广播接收者处理
        r.state = BroadcastRecord.IDLE;
        // 调用scheduleBroadcastsLocked函数就是为了将一个广播继续发送给BroadcastRecord对象r所描述的广播转发任务的
        // 下一个目标广播接收者处理的
        scheduleBroadcastsLocked();
    } else {
        if (filter.receiverList != null) {
            maybeAddAllowBackgroundActivityStartsToken(filter.receiverList.app, r);
            // r is guaranteed ordered at this point, so we know finishReceiverLocked()
            // will get a callback and handle the activity start token lifecycle.
        }
    }
    //直接返回,代表本次完成,一次处理一个广播中的nextReceiver
    return;
}
进程已经启动的静态有序广播接收者

发送给静态有序广播之前先做一些跳过的逻辑处理。

// Hard case: need to instantiate the receiver, possibly
// starting its application process to host it.

//如果上面if没有进行拦截,说明不是广播接收者动态注册的,而应该是静态注册的,此时进程可能没有启动
ResolveInfo info =
    (ResolveInfo)nextReceiver;
ComponentName component = new ComponentName(
        info.activityInfo.applicationInfo.packageName,
        info.activityInfo.name);

//静态注册者跳过的逻辑,跳过的逻辑较多

boolean skip = false;

//sdk的一些判断
if (brOptions != null &&
        (info.activityInfo.applicationInfo.targetSdkVersion
                < brOptions.getMinManifestReceiverApiLevel() ||
        info.activityInfo.applicationInfo.targetSdkVersion
                > brOptions.getMaxManifestReceiverApiLevel())) {
    Slog.w(TAG, "Target SDK mismatch: receiver " + info.activityInfo
            + " targets " + info.activityInfo.applicationInfo.targetSdkVersion
            + " but delivery restricted to ["
            + brOptions.getMinManifestReceiverApiLevel() + ", "
            + brOptions.getMaxManifestReceiverApiLevel()
            + "] broadcasting " + broadcastDescription(r, component));
    skip = true;
}
if (brOptions != null &&
        !brOptions.testRequireCompatChange(info.activityInfo.applicationInfo.uid)) {
    Slog.w(TAG, "Compat change filtered: broadcasting " + broadcastDescription(r, component)
            + " to uid " + info.activityInfo.applicationInfo.uid + " due to compat change "
            + r.options.getRequireCompatChangeId());
    skip = true;
}
//查看发送者的uid和接受者的uid是否一样,或者是否系统uid,确定一些是否两者有设定关联关系
if (!skip && !mService.validateAssociationAllowedLocked(r.callerPackage, r.callingUid,
        component.getPackageName(), info.activityInfo.applicationInfo.uid)) {
    Slog.w(TAG, "Association not allowed: broadcasting "
            + broadcastDescription(r, component));
    skip = true;
}

if (!skip) {
    //看一下intent防火墙mIntentFirewall是否有block该发送行为
    skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
            r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid);
    if (skip) {
        Slog.w(TAG, "Firewall blocked: broadcasting "
                + broadcastDescription(r, component));
    }
}
//权限相关的的检查
int perm = mService.checkComponentPermission(info.activityInfo.permission,
        r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,
        info.activityInfo.exported);
if (!skip && perm != PackageManager.PERMISSION_GRANTED) {
    if (!info.activityInfo.exported) {
        Slog.w(TAG, "Permission Denial: broadcasting "
                + broadcastDescription(r, component)
                + " is not exported from uid " + info.activityInfo.applicationInfo.uid);
    } else {
        Slog.w(TAG, "Permission Denial: broadcasting "
                + broadcastDescription(r, component)
                + " requires " + info.activityInfo.permission);
    }
    skip = true;
} else if (!skip && info.activityInfo.permission != null) {
    final int opCode = AppOpsManager.permissionToOpCode(info.activityInfo.permission);
    if (opCode != AppOpsManager.OP_NONE && mService.getAppOpsManager().noteOpNoThrow(opCode,
            r.callingUid, r.callerPackage, r.callerFeatureId,
            "Broadcast delivered to " + info.activityInfo.name)
            != AppOpsManager.MODE_ALLOWED) {
        Slog.w(TAG, "Appop Denial: broadcasting "
                + broadcastDescription(r, component)
                + " requires appop " + AppOpsManager.permissionToOp(
                        info.activityInfo.permission));
        skip = true;
    }
}

boolean isSingleton = false;
try {
    isSingleton = mService.isSingleton(info.activityInfo.processName,
            info.activityInfo.applicationInfo,
            info.activityInfo.name, info.activityInfo.flags);
} catch (SecurityException e) {
    Slog.w(TAG, e.getMessage());
    skip = true;
}
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) {
        Slog.w(TAG, "Permission Denial: Receiver " + component.flattenToShortString()
                + " requests FLAG_SINGLE_USER, but app does not hold "
                + android.Manifest.permission.INTERACT_ACROSS_USERS);
        skip = true;
    }
}
if (!skip && info.activityInfo.applicationInfo.isInstantApp()
        && r.callingUid != info.activityInfo.applicationInfo.uid) {
    Slog.w(TAG, "Instant App Denial: receiving "
            + r.intent
            + " to " + component.flattenToShortString()
            + " due to sender " + r.callerPackage
            + " (uid " + r.callingUid + ")"
            + " Instant Apps do not support manifest receivers");
    skip = true;
}
if (!skip && r.callerInstantApp
        && (info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0
        && r.callingUid != info.activityInfo.applicationInfo.uid) {
    Slog.w(TAG, "Instant App Denial: receiving "
            + r.intent
            + " to " + component.flattenToShortString()
            + " requires receiver have visibleToInstantApps set"
            + " due to sender " + r.callerPackage
            + " (uid " + r.callingUid + ")");
    skip = true;
}
//crash的app则直接跳过
if (r.curApp != null && r.curApp.mErrorState.isCrashing()) {
    // If the target process is crashing, just skip it.
    Slog.w(TAG, "Skipping deliver ordered [" + mQueueName + "] " + r
            + " to " + r.curApp + ": process 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) {
        // all such failures mean we skip this receiver
        Slog.w(TAG, "Exception getting recipient info for "
                + info.activityInfo.packageName, e);
    }
    if (!isAvailable) {
        Slog.w(TAG_BROADCAST,
                "Skipping delivery to " + info.activityInfo.packageName + " / "
                + info.activityInfo.applicationInfo.uid
                + " : package no longer available");
        skip = true;
    }
}

// If permissions need a review before any of the app components can run, we drop
// the broadcast and if the calling app is in the foreground and the broadcast is
// explicit we launch the review UI passing it a pending intent to send the skipped
// broadcast.
if (!skip) {
    //判断是否需要权限来启动,如果需要则跳过(如果调用者是前台,而且发送到特定组件,则启动权限申请的ui界面)
    if (!requestStartTargetPermissionsReviewIfNeededLocked(r,
            info.activityInfo.packageName, UserHandle.getUserId(
                    info.activityInfo.applicationInfo.uid))) {
        Slog.w(TAG_BROADCAST,
                "Skipping delivery: permission review required for "
                        + broadcastDescription(r, component));
        skip = true;
    }
}

// This is safe to do even if we are skipping the broadcast, and we need
// this information now to evaluate whether it is going to be allowed to run.
//接收者的uid
final int receiverUid = info.activityInfo.applicationInfo.uid;
// If it's a singleton, it needs to be the same app or a special app
if (r.callingUid != Process.SYSTEM_UID && isSingleton
        && mService.isValidSingletonCall(r.callingUid, receiverUid)) {
    info.activityInfo = mService.getActivityInfoForUser(info.activityInfo, 0);
}
//接受者的进程名字
String targetProcess = info.activityInfo.processName;
//接受者的进程ProcessRecord app,这个可能为null,也就是进程未启动
ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
        info.activityInfo.applicationInfo.uid);

if (!skip) {
    final int allowed = mService.getAppStartModeLOSP(
            info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
            info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false, false);
    if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
        // We won't allow this receiver to be launched if the app has been
        // completely disabled from launches, or it was not explicitly sent
        // to it and the app is in a state that should not receive it
        // (depending on how getAppStartModeLOSP has determined that).
        if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
            Slog.w(TAG, "Background execution disabled: receiving "
                    + r.intent + " to "
                    + component.flattenToShortString());
            skip = true;
        //1. 如果flag设置了FLAG_RECEIVER_EXCLUDE_BACKGROUND则无法让后台接收
        //2. 或者getComponent/getPackage都为null,而且没有设置FLAG_RECEIVER_INCLUDE_BACKGROUND,而且没有requiredPermissions
        //3. 如ACTION_BOOT_COMPLETED是有设置FLAG_RECEIVER_INCLUDE_BACKGROUND,所以静态广播无需权限就可以直接接收

        //这段代码是在AMS.broadcastIntentLocked
        //if (getBackgroundLaunchBroadcasts().contains(action)) {
        //      if (DEBUG_BACKGROUND_CHECK) {
        //          Slog.i(TAG, "Broadcast action " + action + " forcing include-background");
        //      }
        //      intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
        //}

        } else if (((r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)
                || (r.intent.getComponent() == null
                    && r.intent.getPackage() == null
                    && ((r.intent.getFlags()
                            & Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0)
                    && !isSignaturePerm(r.requiredPermissions))) {
            mService.addBackgroundCheckViolationLocked(r.intent.getAction(),
                    component.getPackageName());
            Slog.w(TAG, "Background execution not allowed: receiving "
                    + r.intent + " to "
                    + component.flattenToShortString());
            skip = true;
        }
    }
}

if (!skip && !Intent.ACTION_SHUTDOWN.equals(r.intent.getAction())
        && !mService.mUserController
        .isUserRunning(UserHandle.getUserId(info.activityInfo.applicationInfo.uid),
                0 /* flags */)) {
    skip = true;
    Slog.w(TAG,
            "Skipping delivery to " + info.activityInfo.packageName + " / "
                    + info.activityInfo.applicationInfo.uid + " : user is not running");
}

//处理不包含的权限excludedPermissions
if (!skip && r.excludedPermissions != null && r.excludedPermissions.length > 0) {
    for (int i = 0; i < r.excludedPermissions.length; i++) {
        String excludedPermission = r.excludedPermissions[i];
        try {
            perm = AppGlobals.getPackageManager()
                .checkPermission(excludedPermission,
                        info.activityInfo.applicationInfo.packageName,
                        UserHandle
                        .getUserId(info.activityInfo.applicationInfo.uid));
        } catch (RemoteException e) {
            perm = PackageManager.PERMISSION_DENIED;
        }

        int appOp = AppOpsManager.permissionToOpCode(excludedPermission);
        if (appOp != AppOpsManager.OP_NONE) {
            // When there is an app op associated with the permission,
            // skip when both the permission and the app op are
            // granted.
            if ((perm == PackageManager.PERMISSION_GRANTED) && (
                        mService.getAppOpsManager().checkOpNoThrow(appOp,
                        info.activityInfo.applicationInfo.uid,
                        info.activityInfo.packageName)
                    == AppOpsManager.MODE_ALLOWED)) {
                skip = true;
                break;
            }
        } else {
            // When there is no app op associated with the permission,
            // skip when permission is granted.
            if (perm == PackageManager.PERMISSION_GRANTED) {
                skip = true;
                break;
            }
        }
    }
}

// Check that the receiver does *not* belong to any of the excluded packages
if (!skip && r.excludedPackages != null && r.excludedPackages.length > 0) {
    if (ArrayUtils.contains(r.excludedPackages, component.getPackageName())) {
        Slog.w(TAG, "Skipping delivery of excluded package "
                + r.intent + " to "
                + component.flattenToShortString()
                + " excludes package " + component.getPackageName()
                + " due to sender " + r.callerPackage
                + " (uid " + r.callingUid + ")");
        skip = true;
    }
}

//处理需要包含的权限requiredPermission
if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&
        r.requiredPermissions != null && r.requiredPermissions.length > 0) {
    for (int i = 0; i < r.requiredPermissions.length; i++) {
        String requiredPermission = r.requiredPermissions[i];
        try {
            perm = AppGlobals.getPackageManager().
                    checkPermission(requiredPermission,
                            info.activityInfo.applicationInfo.packageName,
                            UserHandle
                            .getUserId(info.activityInfo.applicationInfo.uid));
        } catch (RemoteException e) {
            perm = PackageManager.PERMISSION_DENIED;
        }
        if (perm != PackageManager.PERMISSION_GRANTED) {
            Slog.w(TAG, "Permission Denial: receiving "
                    + r.intent + " to "
                    + component.flattenToShortString()
                    + " requires " + requiredPermission
                    + " due to sender " + r.callerPackage
                    + " (uid " + r.callingUid + ")");
            skip = true;
            break;
        }
        int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
        if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp) {
            if (!noteOpForManifestReceiver(appOp, r, info, component)) {
                skip = true;
                break;
            }
        }
    }
}
if (!skip && r.appOp != AppOpsManager.OP_NONE) {
    if (!noteOpForManifestReceiver(r.appOp, r, info, component)) {
        skip = true;
    }
}

//上面都是各类判断是否需要跳过的逻辑skip
//如果跳过,直接恢复初始状态,开始下一个广播接收者的处理
if (skip) {
    if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
            "Skipping delivery of ordered [" + mQueueName + "] "
            + r + " for reason described above");
    //如果需要跳过,标定当前r.delivery[recIdx]为skipped
    r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED;
    //跳过的时候清空r.receiver = null
    r.receiver = null;
    r.curFilter = null;
    r.state = BroadcastRecord.IDLE;
    //静态广播跳过++
    r.manifestSkipCount++;
    //继续下一个分发
    scheduleBroadcastsLocked();
    return;
}

这里除了有判断sdk、判断权限等细节,还有一个我们经常遇到的问题:“Background execution not allowed: ”,在前面的“广播能否发给background进程”小节讲到了这个细节。

下面开始分析发送给进程已经启动的静态广播接受者。

//静态广播Count执行++
r.manifestCount++;

//标定当前r.delivery[recIdx]为分发DELIVERED
r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;
//状态修改成app接收APP_RECEIVE,后面该receive finishReceiver返回的时候APP_RECEIVE或BroadcastRecord.CALL_DONE_RECEIVE才会继续处理下一个
r.state = BroadcastRecord.APP_RECEIVE;
//当前接收组件curComponent
r.curComponent = component;
//当前的receiver
r.curReceiver = info.activityInfo;
if (DEBUG_MU && r.callingUid > UserHandle.PER_USER_RANGE) {
    Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, "
            + info.activityInfo + ", callingUid = " + r.callingUid + ", uid = "
            + receiverUid);
}
final boolean isActivityCapable =
        (brOptions != null && brOptions.getTemporaryAppAllowlistDuration() > 0);
maybeScheduleTempAllowlistLocked(receiverUid, r, brOptions);

// Report that a component is used for explicit broadcasts.
if (r.intent.getComponent() != null && r.curComponent != null
        && !TextUtils.equals(r.curComponent.getPackageName(), r.callerPackage)) {
    mService.mUsageStatsService.reportEvent(
            r.curComponent.getPackageName(), r.userId, Event.APP_COMPONENT_USED);
}

// Broadcast is being executed, its package can't be stopped.
try {
    //设置包的stop状态是false(需要启动改应用了,包不再是stop了)
    AppGlobals.getPackageManager().setPackageStoppedState(
            r.curComponent.getPackageName(), false, r.userId);
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
    Slog.w(TAG, "Failed trying to unstop package "
            + r.curComponent.getPackageName() + ": " + e);
}

// Is this receiver's application already running?
//如果当前进程已经运行,则直接发给该进程,然后返回
if (app != null && app.getThread() != null && !app.isKilled()) {
    try {
        app.addPackage(info.activityInfo.packageName,
                info.activityInfo.applicationInfo.longVersionCode, mService.mProcessStats);
        maybeAddAllowBackgroundActivityStartsToken(app, r);
        // app进程存在,通过processCurBroadcastLocked -> ActivityThread.scheduleReceiver -> receiver.onReceive处理当前广播
        processCurBroadcastLocked(r, app,
                BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__MANIFEST,
                BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_WARM);
        //order广播是一种同步处理方式,因此处理完可以直接return
        return;
    } catch (RemoteException e) {
        Slog.w(TAG, "Exception when sending broadcast to "
              + r.curComponent, e);
    } catch (RuntimeException e) {
        Slog.wtf(TAG, "Failed sending broadcast to "
                + r.curComponent + " with " + r.intent, e);
        // If some unexpected exception happened, just skip
        // this broadcast.  At this point we are not in the call
        // from a client, so throwing an exception out from here
        // will crash the entire system instead of just whoever
        // sent the broadcast.
        logBroadcastReceiverDiscardLocked(r);
        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 a dead object exception was thrown -- fall through to
    // restart the application.
}
# processCurBroadcastLocked
private final void processCurBroadcastLocked(BroadcastRecord r,
        ProcessRecord app, int receiverType, int processTemperature) throws RemoteException {
    if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
            "Process cur broadcast " + r + " for app " + app);
    final IApplicationThread thread = app.getThread();
    if (thread == null) {
        throw new RemoteException();
    }
    if (app.isInFullBackup()) {
        skipReceiverLocked(r);
        return;
    }

    //processCurBroadcastLocked的时候,会有r.receiver的设置
    r.receiver = thread.asBinder();
    r.curApp = app;
    final ProcessReceiverRecord prr = app.mReceivers;
    prr.addCurReceiver(r);
    app.mState.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
    // Don't bump its LRU position if it's in the background restricted.
    if (mService.mInternal.getRestrictionLevel(app.info.packageName, app.userId)
            < RESTRICTION_LEVEL_RESTRICTED_BUCKET) {
        mService.updateLruProcessLocked(app, false, null);
    }
    // Make sure the oom adj score is updated before delivering the broadcast.
    // Force an update, even if there are other pending requests, overall it still saves time,
    // because time(updateOomAdj(N apps)) <= N * time(updateOomAdj(1 app)).
    mService.enqueueOomAdjTargetLocked(app);
    mService.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);

    // Tell the application to launch this receiver.
    maybeReportBroadcastDispatchedEventLocked(r, r.curReceiver.applicationInfo.uid);
    //r.curComponent是发送给静态接收者的时候设置的组件名字
    r.intent.setComponent(r.curComponent);

    boolean started = false;
    try {
        if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
                "Delivering to component " + r.curComponent
                + ": " + r);
        mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
                                  PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER);
        //发送给app主线程的scheduleReceiver
        thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
                mService.compatibilityInfoForPackage(r.curReceiver.applicationInfo),
                r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
                app.mState.getReportedProcState());
        if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                "Process cur broadcast " + r + " DELIVERED for app " + app);
        started = true;
        FrameworkStatsLog.write(BROADCAST_DELIVERY_EVENT_REPORTED, app.uid,
                r.callingUid == -1 ? Process.SYSTEM_UID : r.callingUid,
                ActivityManagerService.getShortAction(r.intent.getAction()),
                receiverType, processTemperature);
    } finally {
        if (!started) {
            if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
                    "Process cur broadcast " + r + ": NOT STARTED!");
            r.receiver = null;
            r.curApp = null;
            prr.removeCurReceiver(r);
        }
    }

    // if something bad happens here, launch the app and try again
    if (app.isKilled()) {
        throw new RemoteException("app gets killed during broadcasting");
    }
}
# ActivityThread.scheduleReceiver
public final void scheduleReceiver(Intent intent, ActivityInfo info,
        CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
        boolean sync, int sendingUser, int processState) {
    updateProcessState(processState, false);
    ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
            sync, false, mAppThread.asBinder(), sendingUser);
    r.info = info;
    r.compatInfo = compatInfo;
    sendMessage(H.RECEIVER, r);
}
# ActivityThread.handleReceiver
private void handleReceiver(ReceiverData data) {
    // If we are getting ready to gc after going to the background, well
    // we are back active so skip it.
    unscheduleGcIdler();
    // 1) 创建BroadcastReceiver对象
    // 这里处理的是静态广播接收者,默认认为接收者BroadcastReceiver对象不存在
    // 每次接受都会创建一个新的BroadcastReceiver对象
    String component = data.intent.getComponent().getClassName();

    LoadedApk packageInfo = getPackageInfoNoCheck(
            data.info.applicationInfo, data.compatInfo);

    IActivityManager mgr = ActivityManager.getService();

    Application app;
    BroadcastReceiver receiver;
    ContextImpl context;
    try {
        // 首先从AMS传递的intent中获取当前处理该广播的组件名称,然后通过反射创建一个BroadcastReceiver
        // 对象,从这里可以看出来,静态广播处理的时候,每次都会创建一个新的BroadcastReceiver对象;
        // 创建Application对象,如果进程已经启动,Application对象已经创建
        app = packageInfo.makeApplicationInner(false, mInstrumentation);
        context = (ContextImpl) app.getBaseContext();
        if (data.info.splitName != null) {
            context = (ContextImpl) context.createContextForSplit(data.info.splitName);
        }
        if (data.info.attributionTags != null && data.info.attributionTags.length > 0) {
            final String attributionTag = data.info.attributionTags[0];
            context = (ContextImpl) context.createAttributionContext(attributionTag);
        }
        java.lang.ClassLoader cl = context.getClassLoader();
        data.intent.setExtrasClassLoader(cl);
        data.intent.prepareToEnterProcess(
                isProtectedComponent(data.info) || isProtectedBroadcast(data.intent),
                context.getAttributionSource());
        data.setExtrasClassLoader(cl);
        receiver = packageInfo.getAppFactory()
                .instantiateReceiver(cl, data.info.name, data.intent);
    } catch (Exception e) {
        if (DEBUG_BROADCAST) Slog.i(TAG,
                "Finishing failed broadcast to " + data.intent.getComponent());
        data.sendFinished(mgr);
        throw new RuntimeException(
            "Unable to instantiate receiver " + component
            + ": " + e.toString(), e);
    }

    try {
        if (localLOGV) Slog.v(
            TAG, "Performing receive of " + data.intent
            + ": app=" + app
            + ", appName=" + app.getPackageName()
            + ", pkg=" + packageInfo.getPackageName()
            + ", comp=" + data.intent.getComponent().toShortString()
            + ", dir=" + packageInfo.getAppDir());

        sCurrentBroadcastIntent.set(data.intent);
        //这里还调用了setPendingResult方法,详细内容请看BroadcastReceiver.goAsync方法。
        receiver.setPendingResult(data);
        //终于看到了熟悉的onReceive回调了
        receiver.onReceive(context.getReceiverRestrictedContext(),
                data.intent);
    } catch (Exception e) {
        if (DEBUG_BROADCAST) Slog.i(TAG,
                "Finishing failed broadcast to " + data.intent.getComponent());
        data.sendFinished(mgr);
        if (!mInstrumentation.onException(receiver, e)) {
            throw new RuntimeException(
                "Unable to start receiver " + component
                + ": " + e.toString(), e);
        }
    } finally {
        sCurrentBroadcastIntent.set(null);
    }
    //向AMS发送处理结束消息
    if (receiver.getPendingResult() != null) {
        data.finish();
    }
}

handleReceiver主要包括三步:

  • 创建BroadcastReceiver对象
  • 执行onReceive函数
  • 向AMS发送处理结束消息
进程还未启动的静态有序广播接收者
// Not running -- get it started, to be executed when the app comes up.
if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,
        "Need to start app ["
        + mQueueName + "] " + targetProcess + " for broadcast " + r);
//启动进程 ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE (延迟敏感的)标签用于确定fork进程时是否需要使用usap
r.curApp = mService.startProcessLocked(targetProcess,
        info.activityInfo.applicationInfo, true,
        r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
        new HostingRecord(HostingRecord.HOSTING_TYPE_BROADCAST, r.curComponent,
                r.intent.getAction()),
        isActivityCapable ? ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE : ZYGOTE_POLICY_FLAG_EMPTY,
        (r.intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false);
if (r.curApp == null) {
    // Ah, this recipient is unavailable.  Finish it if necessary,
    // and mark the broadcast record as ready for the next.
    Slog.w(TAG, "Unable to launch app "
            + info.activityInfo.applicationInfo.packageName + "/"
            + receiverUid + " for broadcast "
            + r.intent + ": process is bad");
    //当无法启动app的时候,完成这个广播BroadcastRecord r的分发finishReceiverLocked
    logBroadcastReceiverDiscardLocked(r);
    finishReceiverLocked(r, r.resultCode, r.resultData,
            r.resultExtras, r.resultAbort, false);
    scheduleBroadcastsLocked();
    r.state = BroadcastRecord.IDLE;
    return;
}

maybeAddAllowBackgroundActivityStartsToken(r.curApp, r);
// Need to start app 需要先启动该进程会设置mPendingBroadcast = r;
//启动进程后会调用attachApplicationLocked(AMS)、bindApplication(IApplicationThread)
//attachApplicationLocked(AMS)-> sendPendingBroadcastsLocked 会处理mPendingBroadcast
mPendingBroadcast = r;
//mPendingBroadcastRecvIndex是当前需要处理recevie的recIdx
mPendingBroadcastRecvIndex = recIdx;

静态接收者进程尚未启动,调用AMS的startProcessLocked函数启动该接收者进程,并将当前正在等待进程启动。

# 进程创建流程
ActivityThread.main -> ActivityThread.attach -> AMS.attachApplication -> AMS.attachApplicationLocked -> ActivityThread.bindApplication
-> AMS.sendPendingBroadcastsLocked -> BroadcastQueue.sendPendingBroadcastsLocked -> BroadcastQueue.processCurBroadcastLocked -> ActivityThread.scheduleReceiver -> ActivityThread.handleReceiver -> BroadcastReceiver.onReceive(触发广播接收者的onReceive方法)
-> ReceiverData.finishReceiver -> AMS.finishReceiver

进程的创建流程不是本主题的重点,APP启动后会调用ActivityManagerService的sendPendingBroadcastsLocked方法。

# AMS.sendPendingBroadcastsLocked
// The app just attached; send any pending broadcasts that it should receive
boolean sendPendingBroadcastsLocked(ProcessRecord app) {
    boolean didSomething = false;
    for (BroadcastQueue queue : mBroadcastQueues) {
        didSomething |= queue.sendPendingBroadcastsLocked(app);
    }
    return didSomething;
}
BroadcastQueue.sendPendingBroadcastsLocked
public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
        boolean didSomething = false;
        final BroadcastRecord br = mPendingBroadcast;
        if (br != null && br.curApp.getPid() > 0 && br.curApp.getPid() == app.getPid()) {
            if (br.curApp != app) {
                Slog.e(TAG, "App mismatch when sending pending broadcast to "
                        + app.processName + ", intended target is " + br.curApp.processName);
                return false;
            }
            try {
                mPendingBroadcast = null;
                processCurBroadcastLocked(br, app,
                        BROADCAST_DELIVERY_EVENT_REPORTED__RECEIVER_TYPE__MANIFEST,
                        BROADCAST_DELIVERY_EVENT_REPORTED__PROC_START_TYPE__PROCESS_START_TYPE_COLD);
                didSomething = true;
            } catch (Exception e) {
                Slog.w(TAG, "Exception in new application when starting receiver "
                        + br.curComponent.flattenToShortString(), e);
                logBroadcastReceiverDiscardLocked(br);
                finishReceiverLocked(br, br.resultCode, br.resultData,
                        br.resultExtras, br.resultAbort, false);
                scheduleBroadcastsLocked();
                // We need to reset the state if we failed to start the receiver.
                br.state = BroadcastRecord.IDLE;
                throw new RuntimeException(e.getMessage());
            }
        }
        return didSomething;
    }

又看到熟悉的代码了,调用processCurBroadcastLocked函数进行处理。

扩展

命令

  • dumpsys activity broadcasts

  • Registered Receivers: 列出所有已注册的receivers列表

Registered Receivers:
  * ReceiverList{e27a9e9 7522 com.iflytek.inputmethod.miui/10267/u0 remote:2779270}
    app=7522:com.iflytek.inputmethod.miui/u0a267 pid=7522 uid=10267 user=0
    Filter #0: BroadcastFilter{fde866e}
      Action: "android.intent.action.CLOSE_SYSTEM_DIALOGS"
  * ReceiverList{92b6fe2 7522 com.iflytek.inputmethod.miui/10267/u0 remote:a140ad}
    app=7522:com.iflytek.inputmethod.miui/u0a267 pid=7522 uid=10267 user=0
    Filter #0: BroadcastFilter{e61af73}
      Action: "android.net.conn.CONNECTIVITY_CHANGE"
  • Receiver Resolver Table: receiver的解析表
Receiver Resolver Table:
    android.intent.action.CLOSE_SYSTEM_DIALOGS:
      BroadcastFilter{139a975 1000/u0 ReceiverList{252e8ac 1836 system/1000/u0 local:f0f565f}}
      BroadcastFilter{a385100 1000/u0 ReceiverList{a9b83 1836 system/1000/u0 local:9134232}}
      BroadcastFilter{1da9d23 1000/u-1 ReceiverList{e41c652 1836 system/1000/u-1 local:aba2add}}
      BroadcastFilter{431578f 1000/u0 ReceiverList{7a676ee 3687 com.android.systemui/1000/u0 remote:64f0c69}}
      BroadcastFilter{ed9a812 1000/u0 ReceiverList{6a17b9d 3687 com.android.systemui/1000/u0 remote:11b8a74}}
      BroadcastFilter{c50990f 1000/u-1 ReceiverList{29bce6e 3687 com.android.systemui/1000/u-1 remote:bed11e9}}
      BroadcastFilter{a6b8070 1000/u0 ReceiverList{8b822b3 3687 com.android.systemui/1000/u0 remote:252a822}}
      BroadcastFilter{fde866e 10267/u0 ReceiverList{e27a9e9 7522 com.iflytek.inputmethod.miui/10267/u0 remote:2779270}}
      BroadcastFilter{55a4b6d 1000/u0 ReceiverList{4197784 7416 com.miui.securitycenter.remote/1000/u0 remote:19df997}}
      BroadcastFilter{3e759c8 1000/u0 ReceiverList{7b0aa6b 7416 com.miui.securitycenter.remote/1000/u0 remote:2ee1bba}}
      BroadcastFilter{56d5f61 1000/u0 ReceiverList{24552c8 7416 com.miui.securitycenter.remote/1000/u0 remote:756e76b}}
      BroadcastFilter{3407249 10296/u0 ReceiverList{28ec050 13759 com.journeyOS.edge/10296/u0 remote:322f613}}
      BroadcastFilter{582dd19 10155/u0 ReceiverList{f1fd460 3412 com.miui.systemAdSolution/10155/u0 remote:55a9063}}
      BroadcastFilter{65b4041 10164/u0 ReceiverList{f6cab28 25413 com.miui.voiceassist/10164/u0 remote:35ce54b}}
      BroadcastFilter{2848708 10164/u0 ReceiverList{77d44ab 25413 com.miui.voiceassist/10164/u0 remote:87fb6fa}}
      BroadcastFilter{f601940 10270/u0 ReceiverList{3cf5cc3 32227 com.tencent.mm:appbrand2/10270/u0 remote:a594072}}
      BroadcastFilter{b1ce8e 10171/u0 ReceiverList{3d87e89 23970 com.xiaomi.market/10171/u0 remote:c0a5590}}
  • Historical broadcasts [foreground]: 前台广播历史记录
Historical broadcasts [foreground]:
  Historical Broadcast foreground #1:// 前台广播队列第一条广播
    BroadcastRecord{12fbe7c u-1 android.hardware.usb.action.USB_STATE} to user -1 //-1代表user_all
    Intent { act=android.hardware.usb.action.USB_STATE flg=0x31000010 (has extras) }//flag
      extras: Bundle[{host_connected=false, connected=true, unlocked=false, adb=true, configured=true}]
    caller=android 1836:system/1000 pid=1836 uid=1000//发送广播app的信息
    enqueueClockTime=2022-11-17 15:44:28.352 dispatchClockTime=2022-11-17 15:44:28.681
    dispatchTime=-2m56s517ms (+329ms since enq) finishTime=-2m56s506ms (+11ms since disp)// 分发用时  结束时间 
    resultTo=null resultCode=0 resultData=null// 一般resultCode为0且resultTo为null且无ordered为false表示静态注册的无序广播
    resultAbort=false ordered=false sticky=true initialSticky=false
    nextReceiver=2 receiver=null
    Deliver +5ms #0: (manifest)//派发给静态注册的receiver
      priority=0 preferredOrder=0 match=0x108000 specificIndex=-1 isDefault=false
      ActivityInfo:
        name=com.android.mtp.MtpReceiver
        packageName=com.android.mtp
        processName=android.process.media
        enabled=true exported=true directBootAware=false
        resizeMode=RESIZE_MODE_RESIZEABLE
    Deliver +6ms #1: (manifest)
      priority=0 preferredOrder=0 match=0x108000 specificIndex=-1 isDefault=false//优先级默认为0
      ActivityInfo:// receiver的信息
        name=com.android.settings.connecteddevice.usb.UsbModeChooserReceiver
        packageName=com.android.settings
        enabled=true exported=true directBootAware=true
        resizeMode=RESIZE_MODE_RESIZEABLE

这里没看到“requiredPermissions”,如果需要权限,还应该有如下关键信息

requiredPermissions=[android.permission.READ_NETWORK_USAGE_HISTORY]  appOp=-1

下面再举例有序广播的例子:

Historical Broadcast background #12: //后台广播队列第12条
    BroadcastRecord{23a1e41 u-1 android.intent.action.BATTERY_CHANGED} to user -1 // -1代表user_all
    Intent { act=android.intent.action.BATTERY_CHANGED flg=0x60000010 (has extras) } // intent信息
      extras: Bundle[{technology=Li-poly, icon-small=17303618, max_charging_voltage=5000000, health=2, max_charging_current=3000000, status=2, plugged=1, present=true, seq=1622, charge_counter=3692780, level=91, scale=100, temperature=260, voltage=4433, invalid_charger=0, battery_low=false}]
    caller=null null pid=1836 uid=1000 // 发送广播app的信息
    enqueueClockTime=2022-11-17 15:44:50.357 dispatchClockTime=2022-11-17 15:44:50.357 // 入队时间和分发时间
    dispatchTime=-2m34s878ms (0 since enq) finishTime=-2m34s859ms (+19ms since disp)  // 分发用时 、结束时间
    resultAbort=false ordered=false sticky=true initialSticky=false
    // 分发每一个receiver的分发信息以及状态
    // Deliver代表当前receiver已分发到
    Deliver 0 #0: BroadcastFilter{702009b 1000/u0 ReceiverList{d32caa 3687 com.android.systemui/1000/u0 remote:ca25395}}
    Deliver 0 #1: BroadcastFilter{f3f7b8a 1000/u0 ReceiverList{9a511f5 4320 com.miui.aod/1000/u0 remote:220a32c}}
    Deliver 0 #2: BroadcastFilter{8e36b22 1000/u0 ReceiverList{91b20ed 4580 com.miui.aod:settings/1000/u0 remote:caa3304}}
    Deliver 0 #3: BroadcastFilter{690c74b 1000/u0 ReceiverList{9bb201a 1836 system/1000/u0 local:88d2ec5}}
    Deliver 0 #4: BroadcastFilter{9cd95f1 1000/u0 ReceiverList{c610998 1836 system/1000/u0 local:166f77b}}
    Deliver 0 #5: BroadcastFilter{6bc6320 1000/u0 ReceiverList{5e92223 9024 com.miui.powerkeeper/1000/u0 remote:9133f52}}
    Deliver 0 #6: BroadcastFilter{9d3ab0e 1000/u0 ReceiverList{c1dfd09 1836 system/1000/u0 local:514be10}}
    Deliver 0 #7: BroadcastFilter{281fba8 1000/u0 ReceiverList{82b27cb 1836 system/1000/u0 local:eb8b29a}}
    Deliver 0 #8: BroadcastFilter{750ef2a 1000/u0 ReceiverList{c4b9015 1836 system/1000/u0 local:8b7c5cc}}
    Deliver 0 #9: BroadcastFilter{c620732 1000/u0 ReceiverList{ae1633d 1836 system/1000/u0 local:a91cc94}}
    Deliver 0 #10: BroadcastFilter{f7e5ddf 1000/u0 ReceiverList{1a5647e 1836 system/1000/u0 local:905f639}}
    Deliver 0 #11: BroadcastFilter{6dd8a95 1000/u0 ReceiverList{bc31a4c 1836 system/1000/u0 local:280ca7f}}
    Deliver 0 #12: BroadcastFilter{d7c746e 1000/u0 ReceiverList{4f08fe9 1836 system/1000/u0 local:dc5070}}
    Deliver 0 #13: BroadcastFilter{3bdf32 6110/u0 ReceiverList{11b9b3d 3644 com.xiaomi.finddevice/6110/u0 remote:8f1e494}}
    Deliver 0 #14: BroadcastFilter{ac1e890 1000/u0 ReceiverList{b849753 3687 com.android.systemui/1000/u0 remote:3ab8b42}}
    Deliver 0 #15: BroadcastFilter{6cf0a78 1002/u0 ReceiverList{b7aefdb 3409 com.android.bluetooth/1002/u0 remote:d6950ea}}
    Deliver 0 #16: BroadcastFilter{bed2aee 1000/u0 ReceiverList{1701069 1836 system/1000/u0 local:69f82f0}}
    Deliver 0 #17: BroadcastFilter{f0507fa 1000/u0 ReceiverList{7704a25 1836 system/1000/u0 local:a91de1c}}
    Deliver 0 #18: BroadcastFilter{45519d1 1001/u0 ReceiverList{6c6b0f8 6950 com.miui.dmregservice/1001/u0 remote:87205b}}
    Deliver 0 #19: BroadcastFilter{acde4fa 1000/u0 ReceiverList{58e7b25 7416 com.miui.securitycenter.remote/1000/u0 remote:c76331c}}
    Deliver 0 #20: BroadcastFilter{20bc9b4 1000/u0 ReceiverList{85a7687 7416 com.miui.securitycenter.remote/1000/u0 remote:c8556c6}}
    Deliver 0 #21: BroadcastFilter{8d7795 1000/u0 ReceiverList{1ba9b4c 7416 com.miui.securitycenter.remote/1000/u0 remote:991af7f}}
    Deliver 0 #22: BroadcastFilter{80f07e4 1000/u0 ReceiverList{2680f77 7416 com.miui.securitycenter.remote/1000/u0 remote:4b6fd76}}
    Deliver 0 #23: BroadcastFilter{5db9849 1000/u0 ReceiverList{ba6be50 7416 com.miui.securitycenter.remote/1000/u0 remote:dc42c13}}
    Deliver 0 #24: BroadcastFilter{26eca43 1000/u0 ReceiverList{a43f3f2 9052 com.xiaomi.joyose/1000/u0 remote:180afd}}
    Deliver 0 #25: BroadcastFilter{e790cbf 1000/u0 ReceiverList{8f402de 9024 com.miui.powerkeeper/1000/u0 remote:9cc9219}}
    Deliver 0 #26: BroadcastFilter{bab5a56 10211/u0 ReceiverList{297cf8a 3663 com.qualcomm.qti.devicestatisticsservice/10211/u0 remote:49a35f5}}
    Deliver 0 #27: BroadcastFilter{310764e 10153/u0 ReceiverList{eded49 7119 com.miui.voicetrigger/10153/u0 remote:ae94750}}
    Deliver 0 #28: BroadcastFilter{6a5eb64 1000/u0 ReceiverList{e4650f7 9024 com.miui.powerkeeper/1000/u0 remote:f0754f6}}
    Deliver 0 #29: BroadcastFilter{e22ec6d 10153/u0 ReceiverList{bfc84 7119 com.miui.voicetrigger/10153/u0 remote:5637297}}
    Deliver 0 #30: BroadcastFilter{4a9f7f3 1000/u0 ReceiverList{2bd8a62 6974 com.miui.daemon/1000/u0 remote:c19352d}}
    Deliver 0 #31: BroadcastFilter{dec3de6 10296/u0 ReceiverList{6b43441 13759 com.journeyOS.edge/10296/u0 remote:e80ef28}}
    Deliver 0 #32: BroadcastFilter{a48a509 10296/u0 ReceiverList{c210610 14610 com.journeyOS.edge:push/10296/u0 remote:79fbad3}}
    Deliver 0 #33: BroadcastFilter{6065083 10137/u0 ReceiverList{188ab32 16861 com.xiaomi.metoknlp/10137/u0 remote:fac173d}}
    Deliver 0 #34: BroadcastFilter{1175a18 10270/u0 ReceiverList{5ba39fb 27689 com.tencent.mm:push/10270/u0 remote:28cef8a}}
    Deliver 0 #35: BroadcastFilter{b1b3a5 10270/u0 ReceiverList{ab8fd9c 28651 com.tencent.mm/10270/u0 remote:5fde90f}}
    Deliver 0 #36: BroadcastFilter{1bfe54a 10194/u0 ReceiverList{3220ab5 3621 org.codeaurora.ims/10194/u0 remote:b8706ec}}
    Deliver 0 #37: BroadcastFilter{66951a6 10296/u0 ReceiverList{6ee3f01 850 com.journeyOS.edge:core/10296/u0 remote:2056ce8}}
    Deliver 0 #38: BroadcastFilter{582dd19 10155/u0 ReceiverList{f1fd460 3412 com.miui.systemAdSolution/10155/u0 remote:55a9063}}
    Deliver 0 #39: BroadcastFilter{7dbc345 10270/u0 ReceiverList{54907bc 32227 com.tencent.mm:appbrand2/10270/u0 remote:b3d47af}}
    Deliver 0 #40: BroadcastFilter{c7ceb97 10291/u0 ReceiverList{8233616 4230 com.android.chrome/10291/u0 remote:ee82f31}}
    Deliver 0 #41: BroadcastFilter{d29701e 1000/u0 ReceiverList{16a6c59 3687 com.android.systemui/1000/u0 remote:73b18a0}}
    Deliver 0 #42: BroadcastFilter{b2b2dad 10171/u0 ReceiverList{f737ac4 23970 com.xiaomi.market/10171/u0 remote:65d01d7}}

如果有权限要求,还跟上面的无序广播一样;而且如果接受者没有权限,还有提示派发不成功:

Skipped 0 xxxxxxxxxx
  • Historical broadcasts summary [foreground]: 前台广播历史记录简要
  Historical broadcasts summary [background]:
  #0: act=com.android.server.action.NETWORK_STATS_UPDATED flg=0x40000010
    0 dispatch +1ms finish
    enq=2022-11-17 15:47:08.580 disp=2022-11-17 15:47:08.580 fin=2022-11-17 15:47:08.581 //入队时间、派发时间、结束时间
  • Historical broadcasts [background]:后台广播历史记录
  • Historical broadcasts summary [background]: 后台广播历史记录简要

  • dumpsys activity broadcast-stats

android.intent.action.USER_PRESENT:
  Number received: 0, skipped: 559// 分发0次,跳过559次
  Total dispatch time: +740ms, max: +59ms // 总分发用时,和最大分发用时
  Package com.android.systemui: 107 times
  Bg Check Violation com.journeyOS.edge: 107 times
  Bg Check Violation com.miui.voiceassist: 107 times
  Bg Check Violation ctrip.android.view: 107 times
  Bg Check Violation com.taobao.idlefish: 107 times
  Bg Check Violation com.android.chrome: 14 times
  Bg Check Violation cn.gov.tax.its: 107 times
  Bg Check Violation com.homelink.android: 10 times

flag

  • FLAG_RECEIVER_REGISTERED_ONLY

表示当前广播只允许动态注册的receiver接收,避免避免一些系统广播(如TIME_TICK等)拉起静态注册的app进程。

  • FLAG_RECEIVER_REPLACE_PENDING

如果广播队列中存在没有被处理的相同广播,则直接替换掉之前的广播,无序再入队分发

  • FLAG_RECEIVER_FOREGROUND

发送广播时添加这个flag,广播将会被添加到前台广播队列中。

Reference

评论