BroadcastReceiver

一.广播的使用
(一)广播的注册
(1)静态注册
(2)动态注册
(二)广播的发送
(1)按照广播发送的类型分类
有序广播,无序广播,粘性广播
(2)按照广播所处的进程分类
前台广播,后台广播
(三)广播的Debug

二.源码中广播的实现方式
(一)广播的注册
(1)静态广播的注册

静态广播的注册是在AndroidManifest.xml中,AndroidManifest.xml跟随着apk的安装被保存到相应的目录下。每次开机的过程或者apk安装的过程,PackageManagerService都会去扫描apk的安装包,把此apk相关的应用和组件信息保存起来。静态广播的相关信息最后就保存在PackageManagerService的一个集合ActivityIntentResolver mReceivers中。我们就从PackageManagerService解析apk安装包的过程开始分析,先来看下PackageManagerService解析的时序图:

pms启动后逐个扫描apk的相关文件夹,当扫描到AndroidManifest.xml时,从AndroidManifest.xml中解析相关的信息,比如activity,receiver,service,provider四大组件的解析如下:
private boolean parseBaseApplication(Package owner, Resources res,
XmlResourceParser parser, int flags, String[] outError)
throws XmlPullParserException, IOException {
final ApplicationInfo ai = owner.applicationInfo;
final String pkgName = owner.applicationInfo.packageName;
……
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}

        String tagName = parser.getName();
        if (tagName.equals("activity")) {
            Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs, false,
                    owner.baseHardwareAccelerated);
            if (a == null) {
                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                return false;
            }

            owner.activities.add(a);

        } else if (tagName.equals("receiver")) {
            Activity a = parseActivity(owner, res, parser, flags, outError, cachedArgs,
                    true, false);
            if (a == null) {
                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                return false;
            }

            owner.receivers.add(a);

        } else if (tagName.equals("service")) {
            Service s = parseService(owner, res, parser, flags, outError, cachedArgs);
            if (s == null) {
                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                return false;
            }

            owner.services.add(s);
        } else if (tagName.equals("provider")) {
            Provider p = parseProvider(owner, res, parser, flags, outError, cachedArgs);
            if (p == null) {
                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                return false;
            }

            owner.providers.add(p);

        } else if (tagName.equals("activity-alias")) {


        } else if (parser.getName().equals("meta-data")) {

        } else if (tagName.equals("static-library")) {

        } else if (tagName.equals("library")) {

        } else if (tagName.equals("uses-static-library")) {

        } else if (tagName.equals("uses-library")) {

        } else if (tagName.equals("uses-package")) {
        } else {
        }
    }
    return true;
}

解析receiver标签后,把receiver标签中的内容保存到Activity.java中,receiver标签的解析过程如下:

private Activity parseActivity(Package owner, Resources res,
        XmlResourceParser parser, int flags, String[] outError, CachedComponentArgs cachedArgs,
        boolean receiver, boolean hardwareAccelerated)
        throws XmlPullParserException, IOException {
    TypedArray sa = res.obtainAttributes(parser, R.styleable.AndroidManifestActivity);
    ......
    cachedArgs.mActivityArgs.tag = receiver ? "<receiver>" : "<activity>";
    cachedArgs.mActivityArgs.sa = sa;
    cachedArgs.mActivityArgs.flags = flags;
    Activity a = new Activity(cachedArgs.mActivityArgs, new ActivityInfo());
    ......
    String str;
    str = sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_permission, 0);
    if (str == null) {
        a.info.permission = owner.applicationInfo.permission;
    } else {
        a.info.permission = str.length() > 0 ? str.toString().intern() : null;
    }

    str = sa.getNonConfigurationString(
            R.styleable.AndroidManifestActivity_taskAffinity,
            Configuration.NATIVE_CONFIG_VERSION);
    a.info.taskAffinity = buildTaskAffinityName(owner.applicationInfo.packageName,
            owner.applicationInfo.taskAffinity, str, outError);

    a.info.splitName =
            sa.getNonConfigurationString(R.styleable.AndroidManifestActivity_splitName, 0);
    ......
    int outerDepth = parser.getDepth();
    int type;
    while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
           && (type != XmlPullParser.END_TAG
                   || parser.getDepth() > outerDepth)) {
        if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
            continue;
        }
        if (parser.getName().equals("intent-filter")) {
            ActivityIntentInfo intent = new ActivityIntentInfo(a);
            if (!parseIntent(res, parser, true /*allowGlobs*/, true /*allowAutoVerify*/,
                    intent, outError)) {
                return null;
            }
            if (intent.countActions() == 0) {
                Slog.w(TAG, "No actions in intent filter at "
                        + mArchiveSourcePath + " "
                        + parser.getPositionDescription());
            } else {
                a.intents.add(intent);
            }

            // adjust activity flags when we implicitly expose it via a browsable filter
            final int visibility = visibleToEphemeral
                    ? IntentFilter.VISIBILITY_EXPLICIT
                    : !receiver && isImplicitlyExposedIntent(intent)
                            ? IntentFilter.VISIBILITY_IMPLICIT
                            : IntentFilter.VISIBILITY_NONE;
            intent.setVisibilityToInstantApp(visibility);
            if (intent.isVisibleToInstantApp()) {
                a.info.flags |= ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP;
            }
            if (intent.isImplicitlyVisibleToInstantApp()) {
                a.info.flags |= ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP;
            }
            if (LOG_UNSAFE_BROADCASTS && receiver
                    && (owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.O)) {
                for (int i = 0; i < intent.countActions(); i++) {
                    final String action = intent.getAction(i);
                    if (action == null || !action.startsWith("android.")) continue;
                    if (!SAFE_BROADCASTS.contains(action)) {
                        Slog.w(TAG, "Broadcast " + action + " may never be delivered to "
                                + owner.packageName + " as requested at: "
                                + parser.getPositionDescription());
                    }
                }
            }
        } else if (!receiver && parser.getName().equals("preferred")) {
        ......
        } 
        ......
    }
    ......
} 

apk解析完成后,其信息全部封装在Package.java中,为了方便读取静态注册的广播的相关Receivers信息,PackageManagerService使用一个集合ActivityIntentResolver mReceivers来收集Package.java中的广播信息。
如下:

// All available receivers, for your resolving pleasure.
final ActivityIntentResolver mReceivers =
        new ActivityIntentResolver();
private void commitPackageSettings(PackageParser.Package pkg, PackageSetting pkgSetting,
        UserHandle user, int scanFlags, boolean chatty) throws PackageManagerException {
    final String pkgName = pkg.packageName;
    if (mCustomResolverComponentName != null &&
            mCustomResolverComponentName.getPackageName().equals(pkg.packageName)) {
        setUpCustomResolverActivity(pkg);
    }
    ......
        N = pkg.receivers.size();
        r = null;
        for (i=0; i<N; i++) {
            PackageParser.Activity a = pkg.receivers.get(i);
            a.info.processName = fixProcessName(pkg.applicationInfo.processName,
                    a.info.processName);
            mReceivers.addActivity(a, "receiver");
            if (chatty) {
                if (r == null) {
                    r = new StringBuilder(256);
                } else {
                    r.append(' ');
                }
                r.append(a.info.name);
            }
        }
     ......
  }

Package.java中的属性如下:

public final static class Package implements Parcelable {
    public String packageName;
    public ApplicationInfo applicationInfo = new ApplicationInfo();

    public final ArrayList<Permission> permissions = new ArrayList<Permission>(0);
    public final ArrayList<PermissionGroup> permissionGroups = new ArrayList<PermissionGroup>(0);
    public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
    public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
    public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
    public final ArrayList<Service> services = new ArrayList<Service>(0);
}

Activity.java的属性如下:

public final static class Activity extends Component<ActivityIntentInfo> implements Parcelable {
    public final ActivityInfo info;
    private boolean mHasMaxAspectRatio;
}
public static abstract class Component<II extends IntentInfo> {
    public final ArrayList<II> intents;
    public final String className;

    public Bundle metaData;
    public Package owner;

    ComponentName componentName;
    String componentShortName;
}

PackageManagerService提供了接口,方便外部获取当前系统内静态注册的广播:

@Override
public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
    if (!sUserManager.exists(userId)) return null;
    final int callingUid = Binder.getCallingUid();
    flags = updateFlagsForComponent(flags, userId, component);
    enforceCrossUserPermission(callingUid, userId,
            false /* requireFullPermission */, false /* checkShell */, "get receiver info");
    synchronized (mPackages) {
        PackageParser.Activity a = mReceivers.mActivities.get(component);
        if (DEBUG_PACKAGE_INFO) Log.v(
            TAG, "getReceiverInfo " + component + ": " + a);
        if (a != null && mSettings.isEnabledAndMatchLPr(a.info, flags, userId)) {
            PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
            if (ps == null) return null;
            if (filterAppAccessLPr(ps, callingUid, component, TYPE_RECEIVER, userId)) {
                return null;
            }
            return PackageParser.generateActivityInfo(
                    a, flags, ps.readUserState(userId), userId);
        }
    }
    return null;
}

@Override
public @NonNull ParceledListSlice<ResolveInfo> queryIntentReceivers(Intent intent,
        String resolvedType, int flags, int userId) {
    return new ParceledListSlice<>(
            queryIntentReceiversInternal(intent, resolvedType, flags, userId,
                    false /*allowDynamicSplits*/));
}

private @NonNull List<ResolveInfo> queryIntentReceiversInternal(Intent intent,
        String resolvedType, int flags, int userId, boolean allowDynamicSplits) {
    if (!sUserManager.exists(userId)) return Collections.emptyList();
    final int callingUid = Binder.getCallingUid();
    enforceCrossUserPermission(callingUid, userId,
            false /*requireFullPermission*/, false /*checkShell*/,
            "query intent receivers");
    final String instantAppPkgName = getInstantAppPackageName(callingUid);
    flags = updateFlagsForResolve(flags, userId, intent, callingUid,
            false /*includeInstantApps*/);
    ComponentName comp = intent.getComponent();
    if (comp == null) {
        if (intent.getSelector() != null) {
            intent = intent.getSelector();
            comp = intent.getComponent();
        }
    }
    if (comp != null) {
        final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
        final ActivityInfo ai = getReceiverInfo(comp, flags, userId);
        if (ai != null) {
            ......
            if (!blockResolution) {
                ResolveInfo ri = new ResolveInfo();
                ri.activityInfo = ai;
                list.add(ri);
            }
        }
        return applyPostResolutionFilter(
                list, instantAppPkgName, allowDynamicSplits, callingUid, userId);
    }
    // reader
    synchronized (mPackages) {
        String pkgName = intent.getPackage();
        if (pkgName == null) {
            final List<ResolveInfo> result =
                    mReceivers.queryIntent(intent, resolvedType, flags, userId);
            return applyPostResolutionFilter(
                    result, instantAppPkgName, allowDynamicSplits, callingUid, userId);
        }
        final PackageParser.Package pkg = mPackages.get(pkgName);
        if (pkg != null) {
            final List<ResolveInfo> result = mReceivers.queryIntentForPackage(
                    intent, resolvedType, flags, pkg.receivers, userId);
            return applyPostResolutionFilter(
                    result, instantAppPkgName, allowDynamicSplits, callingUid, userId);
        }
        return Collections.emptyList();
    }
}

PackageManagerService扫描当前系统内的所有apk,读取AndroidManifest.xml,把相关的四大组件信息保存起来,并提供接口让外部获取相关的四大组件的信息。

(2)动态广播的注册

动态注册的方法registerReceiver()是在Context.java中定义的一个抽象方法,其实现类是ContextImpl.java。所以只有在Context类的子类中或者是获取了相应的Context子类的对象,才能使用此方法进行动态注册。Activity,Service都是Context的子类,因此其内部可以直接使用其方法。

动态注册广播的时序图如下:

Context.java

@Nullable
public abstract Intent registerReceiver(@Nullable BroadcastReceiver receiver,
                                        IntentFilter filter);

ContextWrapper.java

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

ContextImpl.java

这里的重点是

1.mMainThread.getHandler(),获取当前调用registerReceiver()进行注册的进程的主线程的Handler,以便后续再分发广播的时候使用(后面详细讲)。

2.IIntentReceiver对象的获取。要动态注册,我们传入一个广播接收者BroadcastReceiver,这个BroadcastReceiver的对象所处的进程和ActivityManagerService所处的进程不同,跨进程通讯需要使用到Binder,而IIntentReceiver正好实现了AIDL接口得以使用Binder跨进程通讯,IIntentReceiver封装了我们传入的BroadcastReceiver对象,实现了跨进程传递消息。

3.mMainThread.getApplicationThread(),把当前当前调用registerReceiver()进行注册的进程的ApplicationThread对象传递到AMS。

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

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

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 {
        final Intent intent = ActivityManager.getService().registerReceiver(
                mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
                broadcastPermission, userId, flags);
        if (intent != null) {
            intent.setExtrasClassLoader(getClassLoader());
            intent.prepareToEnterProcess();
        }
        return intent;
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
} 

ActivityManagerService.java

AMS中把广播分为无序广播,有序广播和粘性广播。
重点讲一下粘性广播:
当我们使用sendStickyBroadcast()发送广播时,其Intent对象会被保存在AMS的集合mStickyBroadcasts中。(后面会详细讲),所以当我们动态注册广播时,会查询当前注册监听的广播是否在mStickyBroadcasts中存在,如果存在,那我们此次动态注册监听的广播就是一个粘性广播,

final SparseArray<ArrayMap<String, ArrayList<Intent>>> mStickyBroadcasts =
        new SparseArray<ArrayMap<String, ArrayList<Intent>>>();

public Intent registerReceiver(IApplicationThread caller, String callerPackage,
        IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
        int flags) {
    enforceNotIsolatedCaller("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;
    //根据传进来的ApplicationThread对象获取进程代码块信息getRecordForAppLocked()
    synchronized(this) {
        if (caller != null) {
            callerApp = getRecordForAppLocked(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.pkgList.containsKey(callerPackage) &&
                    !"android".equals(callerPackage)) {
                throw new SecurityException("Given caller package " + callerPackage
                        + " is not running in process " + callerApp);
            }
            callingUid = callerApp.info.uid;
            callingPid = callerApp.pid;
        } else {
            callerPackage = null;
            callingUid = Binder.getCallingUid();
            callingPid = Binder.getCallingPid();
        }
        //当前注册监听的广播可能有多个,查询每一个监听的广播是否是粘性广播(mStickyBroadcasts是否保存有此广播)。如果是粘性广播,添加到stickyIntents集合中。
        Iterator<String> actions = filter.actionsIterator();
        if (actions == null) {
            ArrayList<String> noAction = new ArrayList<String>(1);
            noAction.add(null);
            actions = noAction.iterator();
        }

        // Collect stickies of users
        int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
        while (actions.hasNext()) {
            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);
                    }
                }
            }
        }
    }
    //对当前注册监听的粘性广播进行进一步的筛选。已安装过的apk且此粘性广播的flag为FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS,跳过。否则,此粘性广播继续和注册监听的filter适配,适配成功添加到allSticky集合。
    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 acccess
            // 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);
            }
        }
    }
    //ReceiverList封装了要动态监听广播的receiver对象,并且也封装了receiver所在的进程代码块信息:ProcessRecord对象。如果此receiver曾经注册监听过,则把封装了receiver对象的ReceiverList保存到mRegisteredReceivers集合中,如果此receiver是第一次监听,则构建一个ReceiverList新对象。这些都是为了方便在收到广播时,快速找到对应的广播接收器的。
    synchronized (this) {
        if (callerApp != null && (callerApp.thread == null
                || callerApp.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) {
                rl.app.receivers.add(rl);
            } else {
                try {
                    receiver.asBinder().linkToDeath(rl, 0);
                } catch (RemoteException e) {
                    return sticky;
                }
                rl.linkedToDeath = true;
            }
            mRegisteredReceivers.put(receiver.asBinder(), rl);
        } else if (rl.uid != callingUid) {
            throw new IllegalArgumentException(
                    "Receiver requested to register for uid " + callingUid
                    + " was previously registered for uid " + rl.uid
                    + " callerPackage is " + callerPackage);
        }
        ......
        //把ReceiverList和IntentFilter关联起来,用BroadcastFilter封装,并保存在mReceiverResolver集合中
        BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                permission, callingUid, userId, instantApp, visibleToInstantApps);
        rl.add(bf);
        if (!bf.debugCheck()) {
            Slog.w(TAG, "==> For Dynamic broadcast");
        }
        mReceiverResolver.addFilter(bf);

        //如果监听的是粘性广播,把此监听者receiver加入到广播队列BroadcastQueue中
        // 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, -1, -1, false, null, null, AppOpsManager.OP_NONE, null, receivers,
                        null, 0, null, null, false, true, true, -1);
                queue.enqueueParallelBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();
            }
        }

        return sticky;
    }
}

ReceiverList.java的属性:

final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();
final class ReceiverList extends ArrayList<BroadcastFilter>
    implements IBinder.DeathRecipient {
    final ActivityManagerService owner;
    public final IIntentReceiver receiver;
    public final ProcessRecord app;
    public final int pid;
    public final int uid;
    public final int userId;
    BroadcastRecord curBroadcast = null;
    boolean linkedToDeath = false;

    String stringName;
}

动态注册的整个流程,在AMS里面,大致的结果如下:
1.正常广播(包括有序和无序)。如果动态注册监听的是正常广播,则封装好ReceiverList对象和IntentFilter对象,加入到mReceiverResolver集合中等待处理。
2.粘性广播。如果动态注册监听的是粘性广播,除了加入到mReceiverResolver集合中等待处理,还判断mStickyBroadcasts中是否存在此粘性广播,如果存在,说明此粘性广播之前被发送过,将会自动将此粘性广播添加到广播队列BroadcastQueue等待处理。

(二)广播的发送

final int broadcastIntentLocked(ProcessRecord callerApp,
        String callerPackage, Intent intent, String resolvedType,
        IIntentReceiver resultTo, int resultCode, String resultData,
        Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
        boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
    intent = new Intent(intent);
    //设置flag
    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);
    }

    // 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);
    }
    //确保receiver在运行,否则直接return(关机广播和系统升级广播除外)
    // Make sure that the user who is receiving this broadcast is running.
    // If not, we will just skip it. Make an exception for shutdown broadcasts
    // and upgrade steps.

    if (userId != UserHandle.USER_ALL && !mUserController.isUserRunningLocked(userId, 0)) {
        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 + " is stopped");
            return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
        }
    }
    //广播校验,确保system发出的是protected broadcasts ,protected broadcasts只能由system发出。如果非system发出了protected broadcasts,抛出SecurityException。针对ACTION_APPWIDGET_CONFIGURE和ACTION_APPWIDGET_UPDATE广播进行特殊处理。
    // Verify that protected broadcasts are only being sent by system code,
    // and that system code is only sending protected broadcasts.
    final String action = intent.getAction();
    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:
            isCallerSystem = true;
            break;
        default:
            isCallerSystem = (callerApp != null) && callerApp.persistent;
            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);
            }
        }
    }
    //系统广播的处理(权限检查以及后续的处理)。如果是发送的是后台广播,设置相关flag。
    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);
        }

        switch (action) {
            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:   
            ......
        }
    } 
    //粘性广播的处理。权限检查,粘性广播不能设置Component,否则抛出SecurityException。粘性广播保存在一个ArrayMap中(mStickyBroadcasts),key为Intent中的Action。
    // 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));
        }
    }
    //查询接收者receivers。由于广播的注册有两种方式,广播静态注册的接收者在PMS的mReceivers集合中保存,广播动态注册的接收者在AMS的mReceiverResolver集合中保存,因此要分开处理。
    // 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);//查询广播静态注册的接收者
    }
    if (intent.getComponent() == null) {
        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(intent,
                                resolvedType, false /*defaultOnly*/, users[i]);//查询广播动态注册的接收者
                if (registeredReceivers == null) {
                    registeredReceivers = registeredReceiversForUser;
                } else if (registeredReceiversForUser != null) {
                    registeredReceivers.addAll(registeredReceiversForUser);
                }
            }
        } else {
            registeredReceivers = mReceiverResolver.queryIntent(intent,
                    resolvedType, false /*defaultOnly*/, userId);
        }
    }   
    //无序广播且是广播动态注册的接收者处理。 ordered=true为有序,false为无序。把广播动态注册的接收者加入到广播队列BroadcastQueue中,queue.enqueueParallelBroadcastLocked(r):并行处理。
    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, callingPid, callingUid, callerInstantApp, resolvedType,
                requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
                resultCode, resultData, resultExtras, ordered, sticky, false, userId);
        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;
    }
    //处理有序广播,需要加入BroadcastQueue广播队列中做串行处理,按照priority优先级逐个发送。静态注册的广播接收者,也要按照有序广播来处理,因为PMS扫描解析全部的apk需要花费不少时间,如果按照无序广播处理,那么先解析的apk发送的广播,后解析的apk接收者将无法接收到。因此,这里需要把静态注册的广播接收者和动态注册的有序的广播接收者整合成一个list集合,统一处理。
    // 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);
    }
    //有序广播的处理。把广播接收者加入到BroadcastQueue广播队列中,queue.enqueueOrderedBroadcastLocked(r):串行处理。
    if ((receivers != null && receivers.size() > 0)
            || resultTo != null) {
        BroadcastQueue queue = broadcastQueueForIntent(intent);
        BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
                requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
                resultData, resultExtras, ordered, sticky, false, userId);

        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r
                + ": prev had " + queue.mOrderedBroadcasts.size());
        if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
                "Enqueueing broadcast " + r.intent.getAction());

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

(三)BroadcastQueue广播队列

广播发送的时候,可以使用sendBroadcast()发送无序广播,也可以使用sendOrderedBroadcast()发送有序广播。其有序无序的原理在BroadcastQueue广播队列中实现。

无序广播的处理:

            queue.enqueueParallelBroadcastLocked(r);
            queue.scheduleBroadcastsLocked();

final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>();
public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
    mParallelBroadcasts.add(r);
    enqueueBroadcastHelper(r);
}

有序广播的处理:

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

final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<>();
public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
    mOrderedBroadcasts.add(r);
    enqueueBroadcastHelper(r);
}

scheduleBroadcastsLocked():

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

    if (mBroadcastsScheduled) {
        return;
    }
    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");
                processNextBroadcast(true);
            } break;
            case BROADCAST_TIMEOUT_MSG: {
                synchronized (mService) {
                    broadcastTimeoutLocked(true);
                }
            } break;
        }
    }
}

https://blog.csdn.net/luoshengyang/article/details/6737352
https://blog.csdn.net/luoshengyang/article/details/6730748
https://blog.csdn.net/luoshengyang/article/details/6744448
https://blog.csdn.net/s394500839/article/details/77606384

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值