安卓广播发送接收流程

本文基于Andorid 11。

一、registerReceiver

复制代码
registerReceiver(new MyRecevier(), new IntentFilter("com.example.broadcast"));
  • 动态注册广播接收器,参数:BroadcastReceiver, IntentFilter。
xml 复制代码
<receiver android:name=".MyReceiver">
    <intent-filter>
        <action android:name="com.test.broadcast"/>
    </intent-filter>
</receiver>
  • 静态注册广播,安卓8以后除几个特殊的广播外,静态注册方式只能接收显示广播。

查看动态注册广播流程:

1.2 ContextImpl.registerReceiverInternal

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

传入IIntentReceiver对象作为参数,调用AMS.registerReceiverWithFeature方法注册。

1.3 AMS.registerReceiverWithFeature

java 复制代码
// ActivityManagerService.java
	public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,
            String callerFeatureId, 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;
        //	1. 获取Uid, Pid, isInstantApp, actions
        int callingUid;
        int callingPid;
        boolean instantApp;
        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();
            }

            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();
            }
            
			//	2. 收集当前用户下的粘性广播
            // 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);
                        }
                    }
                }
            }
        }

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

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

        // 3. 创建ReceiverList,BroadcastFilter对象,添加到AMS类变量mRegisteredReceivers, mReceiverResolver中维护。
        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) {
                    final int totalReceiversForApp = rl.app.receivers.size();
                    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.receivers.add(rl);
                } else {
                    try {
                        receiver.asBinder().linkToDeath(rl, 0);
                    } catch (RemoteException e) {
                        return sticky;
                    }
                    rl.linkedToDeath = true;
                }
                mRegisteredReceivers.put(receiver.asBinder(), rl);
            } else if (rl.uid != callingUid) {
                throw new IllegalArgumentException(
                        "Receiver requested to register for uid " + callingUid
                        + " was previously registered for uid " + rl.uid
                        + " callerPackage is " + callerPackage);
            } else if (rl.pid != callingPid) {
                throw new IllegalArgumentException(
                        "Receiver requested to register for pid " + callingPid
                        + " was previously registered for pid " + rl.pid
                        + " callerPackage is " + callerPackage);
            } else if (rl.userId != userId) {
                throw new IllegalArgumentException(
                        "Receiver requested to register for user " + userId
                        + " was previously registered for user " + rl.userId
                        + " callerPackage is " + callerPackage);
            }
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
                    permission, callingUid, userId, instantApp, visibleToInstantApps);
            if (rl.containsFilter(filter)) {
                Slog.w(TAG, "Receiver with filter " + filter
                        + " already registered for pid " + rl.pid
                        + ", callerPackage is " + callerPackage);
            } else {
                rl.add(bf);
                mReceiverResolver.addFilter(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, OP_NONE, null, receivers,
                            null, 0, null, null, false, true, true, -1, false,
                            false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);
                    queue.enqueueParallelBroadcastLocked(r);
                    queue.scheduleBroadcastsLocked();
                }
            }

            return sticky;
        }
    }
  1. 获取Uid, Pid, userId, isInstantApp, actions,做一些校验工作
  2. 收集当前用户下的粘性广播
  3. 创建ReceiverList,BroadcastFilter对象,添加到AMS类变量mRegisteredReceivers, mReceiverResolver中维护。
java 复制代码
final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();

final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
            = new IntentResolver<BroadcastFilter, BroadcastFilter>()

mRegisteredReceivers保存了每个IIntentReceiver注册的广播列表,IIntentReceiver对象在1.2小节被contextImple传入,对应一个BroadcastReceiver对象,BroadcastReceiver可能监听多个广播(添加了多个IntentFilter),ReceiverList代表其监听的广播。

ReceiverList类继承ArrayList<BroadcastFilter>,BroadcastFilter类继承IntentFilter,关注一下BroadcastFilter的构造方法:

java 复制代码
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
                    permission, callingUid, userId, instantApp, visibleToInstantApps);

应用程序调用registerReceiver()方法时注册广播接收器传递的IntentFilter参数filter被传递给BroadcastFilter对象,通过此参数指明感兴趣的广播;创建的BroadcastFilter对象被添加到ReceiverList中:rl.add(bf);;添加到mReceiverResolver中:mReceiverResolver.addFilter(bf);,mReceiverResolver是一个IntentResolver对象,从命名就可以看出来IntentResolver负责Intent的处理解析工作,Intent在安卓各个组件中传递消息,IntentResolver负责将消息交给对应的组件。

IntentResolver维护几个Filter对象处理Intent解析工作:

java 复制代码
// All of the MIME types that have been registered, such as "image/jpeg",
private final ArrayMap<String, F[]> mTypeToFilter = new ArrayMap<String, F[]>();
java 复制代码
// All of the URI schemes (such as http) that have been registered.
private final ArrayMap<String, F[]> mSchemeToFilter = new ArrayMap<String, F[]>();
java 复制代码
// All of the actions that have been registered, but only those that did not specify data.
private final ArrayMap<String, F[]> mActionToFilter = new ArrayMap<String, F[]>();

这里负责广播Intent解析工作的就是mActionToFiltermActionToFilter使用ArrayMap<String, F[]>()数据结构保存action和IntentFilter[]的对应关系,发送广播时便从mActionToFilter对象维护的ArrayMap中找到对应的IntentFilter,将信息封装成ResolveInfo对象就好了。

二、sendBroadcast

2.1 AMS.broadcastIntentLocked

java 复制代码
// ActivityManagerService.java
@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, int appOp, Bundle bOptions,
        boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,
        int realCallingPid, int userId, boolean allowBackgroundActivityStarts,
        @Nullable int[] broadcastWhitelist) {
    
    intent = new Intent(intent);
    intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
    
    // 1. 处理安全问题,ProtectedBroadcast
    final String action = intent.getAction();
    final boolean isProtectedBroadcast;
    isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
    
    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;
    }
    
    if (!isCallerSystem) {
        if (isProtectedBroadcast) {
            throw new SecurityException(msg);
        } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
                    || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
            //...
        }
    }
    
    // 2. 粘性广播,安卓5.0后被弃用,不关注。
    if (sticky) {
    }

    
    // 3. 计算广播接收者
    List receivers = null;
    List<BroadcastFilter> registeredReceivers = null;
    // 3.1 FLAG_RECEIVER_REGISTERED_ONLY指定必须动态注册广播接收器才能接收,如果未指定,通过PMS通过Intent参数的component或者package查找接收器
    if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)  == 0) {
        receivers = collectReceiverComponents(
                intent, resolvedType, callingUid, users, broadcastWhitelist);
    }
    // 3.2 隐式广播,查找动态注册广播接收器,mReceiverResolver维护了在应用程序调用registerReceiver()添加的对应接收器
    if (intent.getComponent() == null) {
        if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
            // ...
        } else {
            registeredReceivers = mReceiverResolver.queryIntent(intent,
                        resolvedType, false /*defaultOnly*/, userId);
        }
    }
    
    final boolean replacePending =
            (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
    
    // 4. 获取BroadcastQueue, 创建BroadcastRecord对象,添加到mParallelBroadcasts发送。
    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.
        final BroadcastQueue queue = broadcastQueueForIntent(intent);
        BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
                callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
                requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
                resultCode, resultData, resultExtras, ordered, sticky, false, userId,
                allowBackgroundActivityStarts, timeoutExempt);
        final boolean replaced = replacePending
                && (queue.replaceParallelBroadcastLocked(r) != null);
        // Note: We assume resultTo is null for non-ordered broadcasts.
        if (!replaced) {
            queue.enqueueParallelBroadcastLocked(r);// 添加到mParallelBroadcasts队列。
            queue.scheduleBroadcastsLocked();		// 发送mParallelBroadcasts队列中的平行广播。
        }
        registeredReceivers = null;
        NR = 0;										// 将registeredReceivers和NR变量重置,避免后续合并到receivers中。
    }
    
    // 5. 合并receivers(静态注册),registeredReceivers(动态注册)到receivers变量中。
    if (receivers != null) {
        int NT = receivers != null ? receivers.size() : 0;
        int it = 0;
        ResolveInfo curt = null;
        BroadcastFilter curr = null;
        while (it < NT && ir < NR) {	// 动态注册无序广播 NR == 0。
            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++;
    }
    
    // 6. 将合并的静态注册广播根据优先级,添加到mOrderedBroadcasts发送。
    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, appOp, brOptions, receivers, resultTo, resultCode,
                resultData, resultExtras, ordered, sticky, false, userId,
                allowBackgroundActivityStarts, timeoutExempt);
        final BroadcastRecord oldRecord =
                replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
        if (oldRecord != null) {
            if (oldRecord.resultTo != null) {
                final BroadcastQueue oldQueue = broadcastQueueForIntent(oldRecord.intent);
                oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo,
                                oldRecord.intent,
                                Activity.RESULT_CANCELED, null, null,
                                false, false, oldRecord.userId);
            }
        } else {
            queue.enqueueOrderedBroadcastLocked(r);
            queue.scheduleBroadcastsLocked();
        }
    }
}

发送广播:

  1. 检查是否protected广播,system app发送隐式广播需要是protected的,否则抛出wtf异常,发送显示广播没有这个限制;非system app没有权限发送protected广播,否则crash。

  2. 粘性广播处理,安卓5.0后被弃用,不关注。

  3. 查找计算广播接收者,注册广播接收有静态和动态两种方式。

    1. 没有指定Intent.FLAG_RECEIVER_REGISTERED_ONLY,可以发送给静态注册的接收器,collectReceiverComponents计算静态广播接收器,保存到receivers变量。
    2. 隐式广播,查找动态注册广播接收器,从1.3小节中可以看到,mReceiverResolver变量维护了在应用程序调用registerReceiver()添加的对应接收器。
  4. 发送动态注册的无序广播,静态注册的广播都认为是有序广播,所以这里处理的是动态注册的广播接收器,获取BroadcastQueue, 创建BroadcastRecord对象,添加到mParallelBroadcasts,开始广播发送工作。将registeredReceivers和NR变量重置,避免后续合并到receivers中。

    BroadcastQueue分为前台广播队列,后台广播队列,指定了Intent.FLAG_RECEIVER_FOREGROUND被添加到前台广播队列,否则为后台队列。

    • 前台广播:前台广播数量较少,广播超时时间10S。
    • 后台广播:默认为后台广播,广播数量较多,超时时间60S,后台广播在当前用户后台启动服务超过阈值时会暂停广播,等待服务启动完成再开始发送。
  5. 合并receivers(静态注册),registeredReceivers(动态注册的有序广播)到receivers变量中。

  6. 将合并的静态注册广播根据优先级,添加到mOrderedBroadcasts发送。从4、5、6三个步骤可以看出,动态注册的无序广播优先级更高,优先处理接收工作,动态注册有序广播和静态注册广播优点级较低,在动态注册的无序广播(平行广播)处理完之后开始处理。

2.2 collectReceiverComponents

java 复制代码
// ActivityManagerService.java
	private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,
            int callingUid, int[] users, int[] broadcastWhitelist) {
        
        List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
                        .queryIntentReceivers(intent, resolvedType, pmFlags, user).getList();
    }
java 复制代码
// PackageManagerService.java
    @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) {
        ComponentName comp = intent.getComponent();
        // 1. 显式广播,指定接收者ComponentName
        if (comp != null) {
            final List<ResolveInfo> list = new ArrayList<>(1);
            final ActivityInfo ai = getReceiverInfo(comp, flags, userId);
            ResolveInfo ri = new ResolveInfo();
            ri.activityInfo = ai;
            list.add(ri);
            return applyPostResolutionFilter(
                    list, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
                    intent);
        }
        // 2. 隐式广播,只能通过ComponentResolver查找接收者。
        synchronized (mLock) {
            String pkgName = intent.getPackage();
            if (pkgName == null) {
                final List<ResolveInfo> result =
                        mComponentResolver.queryReceivers(intent, resolvedType, flags, userId);
                return applyPostResolutionFilter(
                        result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
                        intent);
            }
            
            final AndroidPackage pkg = mPackages.get(pkgName);
            if (pkg != null) {
                final List<ResolveInfo> result = mComponentResolver.queryReceivers(
                        intent, resolvedType, flags, pkg.getReceivers(), userId);
                return applyPostResolutionFilter(
                        result, instantAppPkgName, allowDynamicSplits, callingUid, false, userId,
                        intent);
            }
            return Collections.emptyList();
        }
    }

收集广播接收者:

  1. 显示广播,Intent setComponent()方法指定接收者。
  2. 隐式广播,需要PMS通过IntentResolver查找广播接受者。

看下IntentResolver的处理过程:

2.2.1 queryIntent
java 复制代码
// IntentResolver.java    
	public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly,
            int userId) {
        String scheme = intent.getScheme();
        ArrayList<R> finalList = new ArrayList<R>();
        F[] firstTypeCut = null;
        F[] secondTypeCut = null;
        F[] thirdTypeCut = null;
        F[] schemeCut = null;
        
        // 1.处理MIME type,资源类型包括文本、图片、音视频等等。// Intent.setType("image/*");
        // If the intent includes a MIME type, then we want to collect all of
        // the filters that match that MIME type.
        if (resolvedType != null) {
            int slashpos = resolvedType.indexOf('/');
            if (slashpos > 0) {
                final String baseType = resolvedType.substring(0, slashpos);
                if (!baseType.equals("*")) {
                    if (resolvedType.length() != slashpos+2
                            || resolvedType.charAt(slashpos+1) != '*') {
                        // Not a wild card, so we can just look for all filters that
                        // completely match or wildcards whose base type matches.
                        firstTypeCut = mTypeToFilter.get(resolvedType);
                        secondTypeCut = mWildTypeToFilter.get(baseType);
                    } else {
                        // We can match anything with our base type.
                        firstTypeCut = mBaseTypeToFilter.get(baseType);
                        secondTypeCut = mWildTypeToFilter.get(baseType);
                    }
                    // Any */* types always apply, but we only need to do this
                    // if the intent type was not already */*.
                    thirdTypeCut = mWildTypeToFilter.get("*");
                } else if (intent.getAction() != null) {
                    // The intent specified any type ({@literal *}/*).  This
                    // can be a whole heck of a lot of things, so as a first
                    // cut let's use the action instead.
                    firstTypeCut = mTypedActionToFilter.get(intent.getAction());
                }
            }
        }
        // 2.处理scheme, 指定特定的模式,例如:content,http。// Intent.setData(Uri.fromFile(new File("/sdcard/test.3gp")));
        // If the intent includes a data URI, then we want to collect all of
        // the filters that match its scheme (we will further refine matches
        // on the authority and path by directly matching each resulting filter).
        if (scheme != null) {
            schemeCut = mSchemeToFilter.get(scheme);
        }
        // 3.没有指定任何数据,通过action查找。// Intent.setAction("com.test.broadcast");
        // If the intent does not specify any data -- either a MIME type or
        // a URI -- then we will only be looking for matches against empty
        // data.
        if (resolvedType == null && scheme == null && intent.getAction() != null) {
            firstTypeCut = mActionToFilter.get(intent.getAction());
        }

        // 4.处理category,category代表类别,定义了Activity的类别,Activity可以设置一个或者多个category标签。DEFAULT,HOME,LAUNCHER
        FastImmutableArraySet<String> categories = getFastIntentCategories(intent);
        if (firstTypeCut != null) {
            buildResolveList(intent, categories, debug, defaultOnly, resolvedType,
                    scheme, firstTypeCut, finalList, userId);
        }
        if (secondTypeCut != null) {
            buildResolveList(intent, categories, debug, defaultOnly, resolvedType,
                    scheme, secondTypeCut, finalList, userId);
        }
        if (thirdTypeCut != null) {
            buildResolveList(intent, categories, debug, defaultOnly, resolvedType,
                    scheme, thirdTypeCut, finalList, userId);
        }
        if (schemeCut != null) {
            buildResolveList(intent, categories, debug, defaultOnly, resolvedType,
                    scheme, schemeCut, finalList, userId);
        }
        filterResults(finalList);
        sortResults(finalList);
        return finalList;
    }

总结一下:对Intent的处理主要分为4个部分:MIME,scheme,action,category。

  1. 处理MIME type,资源类型包括文本、图片、音视频等等。// Intent.setType("image/*");
  2. 处理scheme, 指定特定的模式,例如:content,http。// Intent.setData(Uri.fromFile(new File("/sdcard/test.3gp")));
  3. 处理action,没有指定任何数据,通过action查找。// Intent.setAction("com.test.broadcast");
  4. 处理category,category代表了Activity的类别,Activity可以设置一个或者多个category标签。DEFAULT,HOME,LAUNCHER。// Intent.addCategory(Intent.CATEGORY_LAUNCHER);

隐式广播在这个过程中找到之前已经注册的广播接收器。

2.3 processNextBroadcastLocked

整理好广播接收者后,BroadcastQueue.scheduleBroadcastsLocked()执行广播发送。

java 复制代码
// BroadcastQueue.java
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
    BroadcastRecord r;
    
    // 1. mParallelBroadcasts,并行广播立即执行,不需要等待上个广播接收完成,目前只针对动态注册的广播接受者。
    while (mParallelBroadcasts.size() > 0) {
        r = mParallelBroadcasts.remove(0);
        r.dispatchTime = SystemClock.uptimeMillis();
        r.dispatchClockTime = System.currentTimeMillis();
        
        final int N = r.receivers.size();
        for (int i=0; i<N; i++) {
            Object target = r.receivers.get(i);
            deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
        }
    }
    
    // 2.mPendingBroadcast,如果存在mPendingBroadcast,且进程正在启动过程中,return等待进程启动完成接收广播,完成接收后使mPendingBroadcast=null。
    if (mPendingBroadcast != null) {
        boolean isDead;
        if (mPendingBroadcast.curApp.pid > 0) {
            synchronized (mService.mPidsSelfLocked) {
                ProcessRecord proc = mService.mPidsSelfLocked.get(
                        mPendingBroadcast.curApp.pid);
                isDead = proc == null || proc.isCrashing();
            }
        } else {
            final ProcessRecord proc = mService.mProcessList.mProcessNames.get(
                    mPendingBroadcast.curApp.processName, mPendingBroadcast.curApp.uid);
            isDead = proc == null || !proc.pendingStart;
        }
        if (!isDead) {
            // It's still alive, so keep waiting
            return;
        } else {
            mPendingBroadcast.state = BroadcastRecord.IDLE;
            mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
            mPendingBroadcast = null;
        }
    }
    
    // 3. 从mOrderedBroadcasts获取下一个BroadcastRecord对象
    do {
        final long now = SystemClock.uptimeMillis();
        r = mDispatcher.getNextBroadcastLocked(now);
    } while (r == null);
    
    // 4.发送广播
    ResolveInfo info =
        (ResolveInfo)nextReceiver;
    ComponentName component = new ComponentName(
            info.activityInfo.applicationInfo.packageName,
            info.activityInfo.name);
    final int receiverUid = info.activityInfo.applicationInfo.uid;
    String targetProcess = info.activityInfo.processName;
    ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
            info.activityInfo.applicationInfo.uid, false);
    r.manifestCount++;
    r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;
    r.state = BroadcastRecord.APP_RECEIVE;
    r.curComponent = component;
    r.curReceiver = info.activityInfo;
    // 4.1 广播接收进程已启动,processCurBroadcastLocked
    if (app != null && app.thread != null && !app.killed) {
        app.addPackage(info.activityInfo.packageName,
                info.activityInfo.applicationInfo.longVersionCode, mService.mProcessStats);
        maybeAddAllowBackgroundActivityStartsToken(app, r);
        processCurBroadcastLocked(r, app, skipOomAdj);
        return;
    }
    // 4.2 广播接收进程未启动,startProcessLocked,mPendingBroadcast = r;
    if ((r.curApp=mService.startProcessLocked(targetProcess,
        info.activityInfo.applicationInfo, true,
        r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
        new HostingRecord("broadcast", r.curComponent),
        isActivityCapable ? ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE : ZYGOTE_POLICY_FLAG_EMPTY,
        (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
                == null) {
        // 启动失败
    }
    // 赋值mPendingBroadcast
    mPendingBroadcast = r;
}
  1. 处理动态注册的广播接收者mParallelBroadcasts,并行广播立即执行,不需要等待上个广播接收完成,目前只针对动态注册的广播接收者,因为动态注册说明这个接收者的应用进程已经启动了。
  2. 处理mPendingBroadcast,如果存在mPendingBroadcast,且进程正在启动过程中,return等待进程启动完成接收广播,一些静态注册的广播接收者在广播发送后可能应用进程还未启动,所以先拉起应用进程,在应用进程启动后再执行广播接收,完成接收后使mPendingBroadcast=null。
  3. 从mOrderedBroadcasts获取下一个BroadcastRecord对象。
  4. 发送广播,发送广播分为两种情况:a.接受者应用进程已经启动(常见于动态注册);b.接收者进程未启动(常见于静态注册),如果进程未启动,需要先拉起应用进程,将广播赋值给mPendingBroadcast变量记录下来,然后回到上面说的第2种情况。应用进程启动后会调用AMS的attachApplicationLocked方法通知应用启动完成,然后调用sendPendingBroadcastsLocked处理待接收的广播,同样Activity和Service也是这样处理,处理顺序是Activity->Service->Broadcast。

2.4 processCurBroadcastLocked

java 复制代码
// BroadcastQueue.java    
	private final void processCurBroadcastLocked(BroadcastRecord r,
            ProcessRecord app, boolean skipOomAdj) throws RemoteException {
        r.receiver = app.thread.asBinder();
        r.curApp = app;
        app.curReceivers.add(r);
        app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
        mService.mProcessList.updateLruProcessLocked(app, false, null);
        // Tell the application to launch this receiver.
        r.intent.setComponent(r.curComponent);
        
        mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
                                  PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER);
        app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
                mService.compatibilityInfoForPackage(r.curReceiver.applicationInfo),
                r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
                app.getReportedProcState());
    }

更新AMS和PMS中的一些进程状态:ProcessState,Lru,PackageUsage等。

2.4.1 handleReceiver

app.thread.scheduleReceiver()通知应用进程回调onReceive()方法。

java 复制代码
// ActivityThread.java
private void handleReceiver(ReceiverData data) {
    Application app;
    BroadcastReceiver receiver;
    ContextImpl context;
    app = packageInfo.makeApplication(false, mInstrumentation);
    context = (ContextImpl) app.getBaseContext();
        java.lang.ClassLoader cl = context.getClassLoader();
    data.intent.setExtrasClassLoader(cl);
    data.intent.prepareToEnterProcess();
    data.setExtrasClassLoader(cl);
    receiver = packageInfo.getAppFactory()
            .instantiateReceiver(cl, data.info.name, data.intent);

    receiver.setPendingResult(data);
    receiver.onReceive(context.getReceiverRestrictedContext(),
            data.intent);
}
相关推荐
张拭心3 分钟前
春节后,有些公司明确要求 AI 经验了
android·前端·人工智能
张拭心14 分钟前
Android 17 来了!新特性介绍与适配建议
android·前端
SimonKing2 小时前
OpenCode AI辅助编程,不一样的编程思路,不写一行代码
java·后端·程序员
FastBean2 小时前
Jackson View Extension Spring Boot Starter
java·后端
Kapaseker2 小时前
Compose 进阶—巧用 GraphicsLayer
android·kotlin
黄林晴3 小时前
Android17 为什么重写 MessageQueue
android
Seven973 小时前
剑指offer-79、最⻓不含重复字符的⼦字符串
java
皮皮林55112 小时前
Java性能调优黑科技!1行代码实现毫秒级耗时追踪,效率飙升300%!
java
冰_河13 小时前
QPS从300到3100:我靠一行代码让接口性能暴涨10倍,系统性能原地起飞!!
java·后端·性能优化