Android广播之注册广播(包括静态广播和动态广播的注册)源码分析
来源:互联网 发布:淘宝卖大米 编辑:程序博客网 时间:2024/05/09 19:37
Android广播按发送方式分类有三种:无序广播、有序广播(OrderedBroadcast)和粘性广播(StickyBroadcast)。
静态广播的注册流程:
在系统服务启动时会添加PackageManagerService,在该类的构造方法中就会对各个应用安装目录的apk文件进行扫描解析。先看下时序图:
先看PackageManagerService类的构造方法:
// Keys are String (package name), values are Package. This also serves// as the lock for the global state. Methods that must be called with// this lock held have the prefix "LP".@GuardedBy("mPackages")// 域注解:是对类里面成员变量加的注解.受与mPackages引用相关联的锁保护final ArrayMap<String, PackageParser.Package> mPackages = new ArrayMap<String, PackageParser.Package>();public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { . . . // Collect ordinary system packages. final File systemAppDir = new File(Environment.getRootDirectory(), "app"); scanDirLI(systemAppDir, PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0); // 扫描其他路径 . . .}private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) { final File[] files = dir.listFiles(); if (ArrayUtils.isEmpty(files)) { Log.d(TAG, "No files in app dir " + dir); return; } if (DEBUG_PACKAGE_SCANNING) { Log.d(TAG, "Scanning app dir " + dir + " scanFlags=" + scanFlags + " flags=0x" + Integer.toHexString(parseFlags)); } Log.d(TAG, "start scanDirLI:"+dir); // use multi thread to speed up scanning int iMultitaskNum = SystemProperties.getInt("persist.pm.multitask", 6); Log.d(TAG, "max thread:" + iMultitaskNum); final MultiTaskDealer dealer = (iMultitaskNum > 1) ? MultiTaskDealer.startDealer( MultiTaskDealer.PACKAGEMANAGER_SCANER, iMultitaskNum) : null; for (File file : files) { final boolean isPackage = (isApkFile(file) || file.isDirectory()) && !PackageInstallerService.isStageName(file.getName()); if (!isPackage) { // Ignore entries which are not packages continue; } if (RegionalizationEnvironment.isSupported()) { if (RegionalizationEnvironment.isExcludedApp(file.getName())) { Slog.d(TAG, "Regionalization Excluded:" + file.getName()); continue; } } final File ref_file = file; final int ref_parseFlags = parseFlags; final int ref_scanFlags = scanFlags; final long ref_currentTime = currentTime; Runnable scanTask = new Runnable() { public void run() { try { // 扫描文件 scanPackageLI(ref_file, ref_parseFlags | PackageParser.PARSE_MUST_BE_APK, ref_scanFlags, ref_currentTime, null); } catch (PackageManagerException e) { Slog.w(TAG, "Failed to parse " + ref_file + ": " + e.getMessage()); // Delete invalid userdata apps if ((ref_parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 && e.error == PackageManager.INSTALL_FAILED_INVALID_APK) { logCriticalInfo(Log.WARN, "Deleting invalid package at " + ref_file); if (ref_file.isDirectory()) { mInstaller.rmPackageDir(ref_file.getAbsolutePath()); } else { ref_file.delete(); } } } } }; if (dealer != null) dealer.addTask(scanTask); else scanTask.run(); } if (dealer != null) dealer.waitAll(); Log.d(TAG, "end scanDirLI:"+dir);}/* * Scan a package and return the newly parsed package. * Returns null in case of errors and the error code is stored in mLastScanError */private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { if (DEBUG_INSTALL) Slog.d(TAG, "Parsing: " + scanFile); parseFlags |= mDefParseFlags; PackageParser pp = new PackageParser(); pp.setSeparateProcesses(mSeparateProcesses); pp.setOnlyCoreApps(mOnlyCore); pp.setDisplayMetrics(mMetrics); if ((scanFlags & SCAN_TRUSTED_OVERLAY) != 0) { parseFlags |= PackageParser.PARSE_TRUSTED_OVERLAY; } final PackageParser.Package pkg; try { // 根据文件路径解析文件 pkg = pp.parsePackage(scanFile, parseFlags); } catch (PackageParserException e) { throw PackageManagerException.from(e); } . . . // Note that we invoke the following method only if we are about to unpack an application PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags | SCAN_UPDATE_SIGNATURE, currentTime, user); . . . return scannedPkg;}
上面scanPackageLI方法中主要执行两个方法:PackageParser类中的parsePackage方法和PackageManagerService类中的scanPackageLI重载方法,这里按顺序看,先看parsePackage方法:
/** File name in an APK for the Android manifest. */private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";/** Path prefix for apps on expanded storage */private static final String MNT_EXPAND = "/mnt/expand/";/** * Parse the package at the given location. Automatically detects if the * package is a monolithic style (single APK file) or cluster style * (directory of APKs). */public Package parsePackage(File packageFile, int flags) throws PackageParserException { if (packageFile.isDirectory()) { // 解析文件夹下所有apk文件 return parseClusterPackage(packageFile, flags); } else { // 解析apk文件 return parseMonolithicPackage(packageFile, flags); }}/** * Parse all APKs contained in the given directory, treating them as a * single package. This also performs sanity checking, such as requiring * identical package name and version codes, a single base APK, and unique * split names. */private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException { // 解析文件夹下所有apk文件的基本信息 final PackageLite lite = parseClusterPackageLite(packageDir, 0); if (mOnlyCoreApps && !lite.coreApp) { throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED, "Not a coreApp: " + packageDir); } final AssetManager assets = new AssetManager(); try { // Load the base and all splits into the AssetManager // so that resources can be overriden when parsing the manifests. loadApkIntoAssetManager(assets, lite.baseCodePath, flags); if (!ArrayUtils.isEmpty(lite.splitCodePaths)) { for (String path : lite.splitCodePaths) { // 把文件夹下所有apk文件都添加到assets中 loadApkIntoAssetManager(assets, path, flags); } } final File baseApk = new File(lite.baseCodePath); // 解析apk文件返回一个Package对象 final Package pkg = parseBaseApk(baseApk, assets, flags); if (pkg == null) { throw new PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, "Failed to parse base APK: " + baseApk); } if (!ArrayUtils.isEmpty(lite.splitNames)) { final int num = lite.splitNames.length; pkg.splitNames = lite.splitNames; pkg.splitCodePaths = lite.splitCodePaths; pkg.splitRevisionCodes = lite.splitRevisionCodes; pkg.splitFlags = new int[num]; pkg.splitPrivateFlags = new int[num]; for (int i = 0; i < num; i++) { // 解析分包apk,后续流程跟parseBaseApk类似,这里不再详解 parseSplitApk(pkg, i, assets, flags); } } pkg.codePath = packageDir.getAbsolutePath(); return pkg; } finally { IoUtils.closeQuietly(assets); }}private Package parseBaseApk(File apkFile, AssetManager assets, int flags) throws PackageParserException { final String apkPath = apkFile.getAbsolutePath(); String volumeUuid = null; if (apkPath.startsWith(MNT_EXPAND)) { final int end = apkPath.indexOf('/', MNT_EXPAND.length()); volumeUuid = apkPath.substring(MNT_EXPAND.length(), end); } mParseError = PackageManager.INSTALL_SUCCEEDED; mArchiveSourcePath = apkFile.getAbsolutePath(); if (DEBUG_JAR) Slog.d(TAG, "Scanning base APK: " + apkPath); final int cookie = loadApkIntoAssetManager(assets, apkPath, flags); Resources res = null; XmlResourceParser parser = null; try { res = new Resources(assets, mMetrics, null); assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Build.VERSION.RESOURCES_SDK_INT); parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME); final String[] outError = new String[1]; // 解析apk文件的AndroidManifest.xml final Package pkg = parseBaseApk(res, parser, flags, outError); if (pkg == null) { throw new PackageParserException(mParseError, apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]); } pkg.volumeUuid = volumeUuid; pkg.applicationInfo.volumeUuid = volumeUuid; pkg.baseCodePath = apkPath; pkg.mSignatures = null; return pkg; } catch (PackageParserException e) { throw e; } catch (Exception e) { throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION, "Failed to read manifest from " + apkPath, e); } finally { IoUtils.closeQuietly(parser); }}/** * Parse the manifest of a <em>base APK</em>. */private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags, String[] outError) throws XmlPullParserException, IOException { final boolean trustedOverlay = (flags & PARSE_TRUSTED_OVERLAY) != 0; AttributeSet attrs = parser; final String pkgName; final String splitName; try { // parsePackageSplitNames方法校验包名的有效性 Pair<String, String> packageSplit = parsePackageSplitNames(parser, attrs, flags); pkgName = packageSplit.first; splitName = packageSplit.second; } catch (PackageParserException e) { mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; return null; } . . . int type; if (!TextUtils.isEmpty(splitName)) { outError[0] = "Expected base APK, but found split " + splitName; mParseError = PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME; return null; } final Package pkg = new Package(pkgName); boolean foundApp = false; int outerDepth = parser.getDepth(); while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { continue; } String tagName = parser.getName(); // 解析application节点 if (tagName.equals("application")) { if (foundApp) { if (RIGID_PARSER) { outError[0] = "<manifest> has more than one <application>"; mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return null; } else { Slog.w(TAG, "<manifest> has more than one <application>"); XmlUtils.skipCurrentTag(parser); continue; } } foundApp = true; if (!parseBaseApplication(pkg, res, parser, attrs, flags, outError)) { return null; } // 中间还有好多节点的解析,这里省略了 . . . } else { Slog.w(TAG, "Unknown element under <manifest>: " + parser.getName() + " at " + mArchiveSourcePath + " " + parser.getPositionDescription()); XmlUtils.skipCurrentTag(parser); continue; } } if (!foundApp && pkg.instrumentation.size() == 0) { outError[0] = "<manifest> does not contain an <application> or <instrumentation>"; mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_EMPTY; } . . . return pkg;}/** * Parse the {@code application} XML tree at the current parse location in a * <em>base APK</em> manifest. */private boolean parseBaseApplication(Package owner, Resources res, XmlPullParser parser, AttributeSet attrs, int flags, String[] outError) throws XmlPullParserException, IOException { . . . final int innerDepth = parser.getDepth(); int type; 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")) { . . . } else if (tagName.equals("receiver")) { Activity a = parseActivity(owner, res, parser, attrs, flags, outError, true, false); if (a == null) { mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return false; } // 静态注册的广播都添加在receivers列表中 owner.receivers.add(a); // 后面还有解析其他节点,这里不再讲解 . . . } else { if (!RIGID_PARSER) { Slog.w(TAG, "Unknown element under <application>: " + tagName + " at " + mArchiveSourcePath + " " + parser.getPositionDescription()); XmlUtils.skipCurrentTag(parser); continue; } else { outError[0] = "Bad element under <application>: " + tagName; mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED; return false; } } } . . . return true;}
经过上面方法解析后,所有静态注册的广播都被添加到了receivers列表中了,再来看PackageManagerService类中的scanPackageLI方法:
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { boolean success = false; try { final PackageParser.Package res = scanPackageDirtyLI(pkg, parseFlags, scanFlags, currentTime, user); success = true; return res; } finally { if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) { removeDataDirsLI(pkg.volumeUuid, pkg.packageName); } }}
private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags, int scanFlags, long currentTime, UserHandle user) throws PackageManagerException { // writer synchronized (mPackages) { . . . 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, pkg.applicationInfo.uid); // 把所有静态注册的广播添加到mReceivers里面 mReceivers.addActivity(a, "receiver"); if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { if (r == null) { r = new StringBuilder(256); } else { r.append(' '); } r.append(a.info.name); } } if (r != null) { if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Receivers: " + r); } . . . } return pkg;}
上面方法会把PackageParser类中解析好的广播又添加到mReceivers中,以便后续发送广播。
动态注册广播的流程
惯例先看时序图:
根据时序图显示,先看ContextWrapper类的registerReceiver方法:
@Overridepublic Intent registerReceiver( BroadcastReceiver receiver, IntentFilter filter) { return mBase.registerReceiver(receiver, filter);}
调用ContextImpl类中的registerReceiver方法:
@Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { return registerReceiver(receiver, filter, null, null);}@Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) { return registerReceiverInternal(receiver, getUserId(), filter, broadcastPermission, scheduler, getOuterContext());}private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId, IntentFilter filter, String broadcastPermission, Handler scheduler, Context context) { IIntentReceiver rd = null; if (receiver != null) { // mPackageInfo 是LoadedApk类的实例,在构造方法中赋值 if (mPackageInfo != null && context != null) { if (scheduler == null) { scheduler = mMainThread.getHandler(); } // 返回一个IIntentReceiver接口对象,它是一个Binder对象 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 { return ActivityManagerNative.getDefault().registerReceiver( mMainThread.getApplicationThread(), mBasePackageName, rd, filter, broadcastPermission, userId); } catch (RemoteException e) { return null; }}
上面方法中rd是一个IIntentReceiver对象,这是一个Binder对象,接下来会把它传递给ActivityManagerService,AMS在收到相应的广播时,就是通过这个Binder对象来通知各接收者的。
下面先看下LoadedApk类中的getReceiverDispatcher方法:
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) { // 要获取的ReceiverDispatcher对象已经存在,直接获取并返回 rd = map.get(r); } } if (rd == null) { // 要获取的ReceiverDispatcher不存在,则新建并保存 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 { // 校验context和handler的有效性 rd.validate(context, handler); } rd.mForgotten = false; return rd.getIIntentReceiver(); }}static final class ReceiverDispatcher { final static class InnerReceiver extends IIntentReceiver.Stub { final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher; final LoadedApk.ReceiverDispatcher mStrongRef; InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) { mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd); mStrongRef = strong ? rd : null; } . . . } final IIntentReceiver.Stub mIIntentReceiver; final BroadcastReceiver mReceiver; final Context mContext; final Handler mActivityThread; final Instrumentation mInstrumentation; final boolean mRegistered; final IntentReceiverLeaked mLocation; RuntimeException mUnregisterLocation; boolean mForgotten; 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; // 保存activityThread以便后面在发布广播时使用 mActivityThread = activityThread; mInstrumentation = instrumentation; mRegistered = registered; mLocation = new IntentReceiverLeaked(null); mLocation.fillInStackTrace(); } void validate(Context context, Handler activityThread) { if (mContext != context) { throw new IllegalStateException( "Receiver " + mReceiver + " registered with differing Context (was " + mContext + " now " + context + ")"); } if (mActivityThread != activityThread) { throw new IllegalStateException( "Receiver " + mReceiver + " registered with differing handler (was " + mActivityThread + " now " + activityThread + ")"); } } IIntentReceiver getIIntentReceiver() { return mIIntentReceiver; } . . .}
上面getReceiverDispatcher方法中的map是以BroadcastReceiver对象r为key,以ReceiverDispatcher对象rd为value保存在一个ArrayMap中,而这个ArrayMap又以Context为key,自己为value保存在LoadedApk类中的成员变量mReceivers中。这样,只要给定Context和BroadcastReceiver就可以查看LoadedApk中是否已经存在相应的广播接收分发器ReceiverDispatcher了。
在新建广播接收分发器ReceiverDispatcher时,会在构造方法中创建一个InnerReceiver类的实例,这是一个Binder对象,实现了IIntentReceiver接口,可以通过ReceiverDispatcher.getIIntentReceiver方法来获得,获得后会把它传给AMS,以便接收广播。
下面看AMS类中的registerReceiver方法:
public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission, int userId) { // 执行根据调用者uid判断调用者不是独立进程的操作 enforceNotIsolatedCaller("registerReceiver"); ArrayList<Intent> stickyIntents = null; ProcessRecord callerApp = null; int callingUid; int callingPid; synchronized(this) { if (caller != null) { // 获取调用者的ProcessRecord对象callerApp 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 != Process.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(); } // 处理调用者的uid userId = handleIncomingUser(callingPid, callingUid, userId, true, ALLOW_FULL_ONLY, "registerReceiver", callerPackage); // 迭代filter中所有的action 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 // 根据uid获取调用者所有的粘性广播Intents并添加到stickyIntents列表中 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); // 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. // 判断filter和intent是否匹配 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; } synchronized (this) { if (callerApp != null && (callerApp.thread == null || callerApp.thread.asBinder() != caller.asBinder())) { // Original caller already died return null; } // 根据Binder对象获取已注册的ReceiverList ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder()); if (rl == null) { // 这里其实是把广播接收器receiver保存在一个ReceiverList列表中 rl = new ReceiverList(this, callerApp, callingPid, callingUid, userId, receiver); // rl.app是ReceiverList列表的宿主进程 if (rl.app != null) { // rl.app.receivers是宿主进程中的一个列表,专门用来保存这个进程注册的广播 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); } else if (rl.pid != callingPid) { throw new IllegalArgumentException( "Receiver requested to register for pid " + callingPid + " was previously registered for pid " + rl.pid); } else if (rl.userId != userId) { throw new IllegalArgumentException( "Receiver requested to register for user " + userId + " was previously registered for user " + rl.userId); } // 创建BroadcastFilter把广播接收器列表rl和filter关联起来 BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission, callingUid, userId); rl.add(bf); if (!bf.debugCheck()) { Slog.w(TAG, "==> For Dynamic broadcast"); } // 所有动态注册的广播都放在mReceiverResolver中,以便以后能够接收到广播并进行处理 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, -1, -1, null, null, AppOpsManager.OP_NONE, null, receivers, null, 0, null, null, false, true, true, -1); queue.enqueueParallelBroadcastLocked(r); queue.scheduleBroadcastsLocked(); } } return sticky; }}
执行完上面方法后,所有动态注册的广播都添加到mReceiverResolver中了。
这里介绍下StickyIntent:在最后一次调用sendStickyBroadcast方法来发送某个Action类型的广播时,系统会把代表这个广播的Intent保存下来,这样后来调用registerReceiver来注册相同Action类型的广播接收器时,就会得到这个最后发出的广播。这个最后发出的广播虽然被处理完了,但是仍然被粘住在AMS中,以便下一个注册相应Action类型的广播接收器还能继续处理。
下面看下IntentFilter类中的actionsIterator方法和match方法:
// mActions在构造方法中进行创建初始化private final ArrayList<String> mActions;/** * Add a new Intent action to match against. If any actions are included * in the filter, then an Intent's action must be one of those values for * it to match. If no actions are included, the Intent action is ignored. * * @param action Name of the action to match, i.e. Intent.ACTION_VIEW. */public final void addAction(String action) { if (!mActions.contains(action)) { mActions.add(action.intern()); }}/** * Return an iterator over the filter's actions. If there are no actions, * returns null. */public final Iterator<String> actionsIterator() { return mActions != null ? mActions.iterator() : null;}. . ./** * Test whether this filter matches the given <var>intent</var>. * * @param intent The Intent to compare against. * @param resolve If true, the intent's type will be resolved by calling * Intent.resolveType(); otherwise a simple match against * Intent.type will be performed. * @param logTag Tag to use in debugging messages. * * @return Returns either a valid match constant (a combination of * {@link #MATCH_CATEGORY_MASK} and {@link #MATCH_ADJUSTMENT_MASK}), * or one of the error codes {@link #NO_MATCH_TYPE} if the type didn't match, * {@link #NO_MATCH_DATA} if the scheme/path didn't match, * {@link #NO_MATCH_ACTION} if the action didn't match, or * {@link #NO_MATCH_CATEGORY} if one or more categories didn't match. * * @see #match(String, String, String, android.net.Uri , Set, String) */public final int match(ContentResolver resolver, Intent intent, boolean resolve, String logTag) { String type = resolve ? intent.resolveType(resolver) : intent.getType(); return match(intent.getAction(), type, intent.getScheme(), intent.getData(), intent.getCategories(), logTag);}/** * Test whether this filter matches the given intent data. A match is * only successful if the actions and categories in the Intent match * against the filter, as described in {@link IntentFilter}; in that case, * the match result returned will be as per {@link #matchData}. */public final int match(String action, String type, String scheme, Uri data, Set<String> categories, String logTag) { if (action != null && !matchAction(action)) { if (false) Log.v( logTag, "No matching action " + action + " for " + this); return NO_MATCH_ACTION; } int dataMatch = matchData(type, scheme, data); if (dataMatch < 0) { if (false) { if (dataMatch == NO_MATCH_TYPE) { Log.v(logTag, "No matching type " + type + " for " + this); } if (dataMatch == NO_MATCH_DATA) { Log.v(logTag, "No matching scheme/path " + data + " for " + this); } } return dataMatch; } String categoryMismatch = matchCategories(categories); if (categoryMismatch != null) { if (false) { Log.v(logTag, "No matching category " + categoryMismatch + " for " + this); } return NO_MATCH_CATEGORY; } // It would be nice to treat container activities as more // important than ones that can be embedded, but this is not the way... if (false) { if (categories != null) { dataMatch -= mCategories.size() - categories.size(); } } return dataMatch;}
到这里动态注册广播的流程就执行完了。
- Android广播之注册广播(包括静态广播和动态广播的注册)源码分析
- Android静态注册广播和动态注册广播的区别
- myapplication991静态广播注册和动态广播
- Android-动态注册广播和注销广播
- 动态广播注册源码分析
- android中广播的使用(动态和静态注册)
- Android的广播Receiver动态注册和静态注册
- Android静态注册和动态注册广播的区别
- Android进阶之路 - BroadcaseReceiver(自定义广播、有序广播、无序广播、广播拦截、动态注册、静态注册)的详细使用方式
- Android广播的静态与动态注册
- Android静态/动态注册广播的区别
- android 注册静态广播接收器VS注册动态广播接收器
- android 静态注册广播
- #android# 广播静态注册 动态注册
- android 动态注册广播
- android动态注册广播
- Android动态注册广播
- 静态/动态注册广播的区别,静态动态广播区别
- get提交中文,post提交中文乱码问题
- IntelliJ强制更新Maven Dependencies
- 函数
- 字符串转换成数字
- ios 键盘右上角添加完成按钮
- Android广播之注册广播(包括静态广播和动态广播的注册)源码分析
- Android优秀开源库1000+,你值得拥有
- springmvc批量文件打包成zip下载功能
- oracle 11g安装与部署
- 山东浪潮齐鲁软件产业股份有限公司-高级Java软件工程师笔试题
- 博客园+CSDN文章
- 装饰器模式(Decorator)
- LeetCode-242:Valid Anagram
- 简评relife