Android中广播注册与接收流程
当我们通过registerReceiver注册广播的时候,其实是使用的Context来注册的,前面”activity启动流程”,我们已经知道Context的实现类是ContextImpl,所以广播的注册是从ContextImpl中开始的
广播的注册流程
@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());}@Overridepublic Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user, IntentFilter filter, String broadcastPermission, Handler scheduler) { return registerReceiverInternal(receiver, user.getIdentifier(), 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实例,一个应用进程,就对应一个LoadedApk实例 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 { // 通过AMS注册广播,并且传递上面获取的InnerReceiver对象 return ActivityManagerNative.getDefault().registerReceiver( mMainThread.getApplicationThread(), mBasePackageName, rd, filter, broadcastPermission, userId); } catch (RemoteException e) { return null; }}
可以看到所有的处理都来自registerReceiverInternal方法,可以看到上面一大段操作都是给IIntentReceiver赋值,说明这个对象很重要,我们来看看IIntentReceiver
rd = mPackageInfo.getReceiverDispatcher( receiver, context, scheduler, mMainThread.getInstrumentation(), true);
ReceiverDispatcher是LoadedApk的一个内部类,其内部有一个InnerReceiver类
final static class InnerReceiver extends IIntentReceiver.Stub
我们看下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) { // 先从mReceivers集合中取出当前应用BroadcastReceiver对应的ReceiverDispatcher map = mReceivers.get(context); if (map != null) { rd = map.get(r); } } // 若系统中的mReceivers集合中,么有当前BroadcastReceiver对应的ReceiverDispatcher,则创建并put到mReceivers if (rd == null) { rd = new ReceiverDispatcher(r, context, handler, instrumentation, registered); if (registered) { if (map == null) { map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); mReceivers.put(context, map); } map.put(r, rd); } } else { // 验证广播发送者的context和handler是否一致 rd.validate(context, handler); } rd.mForgotten = false; return rd.getIIntentReceiver(); // 返回一个InnerReceiver对象,这个对象是在ReceiverDispatcher构造方法中被初始化的。 } }
在LoadedApk中维护了两个map集合,每一个Context对象对应唯一的ArrayMap,也就是说对于每一个应用,都又一个唯一的ArrayMap来保存其注册的广播
private final ArrayMap> mReceivers = new ArrayMap>();private final ArrayMap> mUnregisteredReceivers = new ArrayMap>();
看下InnerReceiver类
final static class InnerReceiver extends IIntentReceiver.Stub { final WeakReference mDispatcher; final LoadedApk.ReceiverDispatcher mStrongRef; InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) { mDispatcher = new WeakReference(rd); mStrongRef = strong ? rd : null; } public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { LoadedApk.ReceiverDispatcher rd = mDispatcher.get(); if (ActivityThread.DEBUG_BROADCAST) { int seq = intent.getIntExtra("seq", -1); Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction() + " seq=" + seq + " to " + (rd != null ? rd.mReceiver : null)); } if (rd != null) { rd.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser); } else { // The activity manager dispatched a broadcast to a registered // receiver in this process, but before it could be delivered the // receiver was unregistered. Acknowledge the broadcast on its // behalf so that the system's broadcast sequence can continue. if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, "Finishing broadcast to unregistered receiver"); IActivityManager mgr = ActivityManagerNative.getDefault(); try { if (extras != null) { extras.setAllowFds(false); } mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags()); } catch (RemoteException e) { Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver"); } } } }
最终还是交给了AMS处理注册广播的操作
首先在AMS中维护了下面两个集合
final SparseArray>> mStickyBroadcasts = new SparseArray>>();final HashMap mRegisteredReceivers = new HashMap<>();public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission, int userId) { enforceNotIsolatedCaller("registerReceiver"); ArrayList stickyIntents = null; ProcessRecord callerApp = null; int callingUid; int callingPid; synchronized(this) { ..... // 对当前调用进程做权限检查 userId = handleIncomingUser(callingPid, callingUid, userId, true, ALLOW_FULL_ONLY, "registerReceiver", callerPackage); // 这个filter就是我们通过registerReceiver(BroadcastReceiver receiver, IntentFilter filter)传递进来的filter Iterator actions = filter.actionsIterator(); if (actions == null) { ArrayList noAction = new ArrayList(1); noAction.add(null); actions = noAction.iterator(); } // 保存当前所有粘性广播的intent int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) }; while (actions.hasNext()) { String action = actions.next(); for (int id : userIds) { ArrayMap> stickies = mStickyBroadcasts.get(id); if (stickies != null) { ArrayList intents = stickies.get(action); if (intents != null) { if (stickyIntents == null) { stickyIntents = new ArrayList(); } stickyIntents.addAll(intents); } } } } } // 添加所有有对应处理者的粘性广播到allSticky集合中 ArrayList 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. if (filter.match(resolver, intent, true, TAG) >= 0) { if (allSticky == null) { allSticky = new ArrayList(); } allSticky.add(intent); } } } // 当receiver为null,直接返回第一个粘性广播 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())) { // 调用者已经死亡,直接返回 return null; } // 第一次注册某个广播,这里返回值是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集合中 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 bf = new BroadcastFilter(filter, rl, callerPackage, permission, callingUid, userId); rl.add(bf); if (!bf.debugCheck()) { Slog.w(TAG, "==> For Dynamic broadcast"); } mReceiverResolver.addFilter(bf); //所有匹配该filter的sticky广播执行入队操作 //如果没有使用sendStickyBroadcast,则allSticky=null。 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); //调度广播,发送BROADCAST_INTENT_MSG消息,触发处理下一个广播。 queue.scheduleBroadcastsLocked(); } } return sticky; }}
广播注册流程总结
广播的注册过程:
1. ContextImpl#registerReceiver——-> ContextImpl#registerReceiverInternal
在registerReceiverInternal方法中,创建IIntentReceiver,IIntentReceiver主要用来和AMS服务段远程通信的。
A. 创建IIntentReceiver
在LoadedApk#getReceiverDispatcher方法中,通过rd.getIIntentReceiver()返回一个IIntentReceiver实现类,其实就是InnerReceiver,
在返回之前做了下面的操作:
map.put(r, rd);
一个InnerReceiver对应一个ReceiverDispatcher,这个在后面广播接收的时候会使用到。
B. 通过AMS的registerReceiver注册广播,并且传递创建好的InnerReceiver对象
C. 在AMS中,添加InnerReceiver和接收者队列到mRegisteredReceivers集合中
rl = new ReceiverList(this, callerApp, callingPid, callingUid,
userId, receiver);
mRegisteredReceivers.put(receiver.asBinder(), rl);
广播的发送过程
同样的首先看下ContextImpl类
@Overridepublic void sendBroadcast(Intent intent) { warnIfCallingFromSystemProcess(); String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { intent.prepareToLeaveProcess(); // 通过AMS的broadcastIntent方法发送广播 ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false, getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); }}
进入AMS
public final int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle options, boolean serialized, boolean sticky, int userId) { // 检查当前inent的合法性 enforceNotIsolatedCaller("broadcastIntent"); synchronized(this) { intent = verifyBroadcastLocked(intent); final ProcessRecord callerApp = getRecordForAppLocked(caller); final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); // 通过broadcastIntentLocked发送广播 int res = broadcastIntentLocked(callerApp, callerApp != null ? callerApp.info.packageName : null, intent, resolvedType, resultTo, resultCode, resultData, resultExtras, requiredPermissions, appOp, null, serialized, sticky, callingPid, callingUid, userId); Binder.restoreCallingIdentity(origId); return res; }}
继续看下ActivityManagerService#broadcastIntentLocked方法:
private final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle options, boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) { intent = new Intent(intent); // 被stop的包不会接收广播 intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES); // 必须等到开机结束 if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) { intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); } userId = handleIncomingUser(callingPid, callingUid, userId, true, ALLOW_NON_FULL, "broadcast", callerPackage); // 确保接收该广播的user处于running状态,否则直接跳过 if (userId != UserHandle.USER_ALL && !isUserRunningLocked(userId, false)) { if ((callingUid != Process.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; } } BroadcastOptions brOptions = null; if (options != null) { brOptions = new BroadcastOptions(options); if (brOptions.getTemporaryAppWhitelistDuration() > 0) { // See if the caller is allowed to do this. Note we are checking against // the actual real caller (not whoever provided the operation as say a // PendingIntent), because that who is actually supplied the arguments. if (checkComponentPermission( android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, Binder.getCallingPid(), Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) { String msg = "Permission Denial: " + intent.getAction() + " broadcast from " + callerPackage + " (pid=" + callingPid + ", uid=" + callingUid + ")" + " requires " + android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST; Slog.w(TAG, msg); throw new SecurityException(msg); } } } // 判断当前包是否又权限发送该广播 int callingAppId = UserHandle.getAppId(callingUid); if (callingAppId == Process.SYSTEM_UID || callingAppId == Process.PHONE_UID || callingAppId == Process.SHELL_UID || callingAppId == Process.BLUETOOTH_UID || callingAppId == Process.NFC_UID || callingUid == 0) { // Always okay. } else if (callerApp == null || !callerApp.persistent) { try { if (AppGlobals.getPackageManager().isProtectedBroadcast( intent.getAction())) { String msg = "Permission Denial: not allowed to send broadcast " + intent.getAction() + " from pid=" + callingPid + ", uid=" + callingUid; Slog.w(TAG, msg); throw new SecurityException(msg); } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(intent.getAction())) { // 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 (callerApp == null) { String msg = "Permission Denial: not allowed to send broadcast " + intent.getAction() + " 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( callerApp.info.packageName)) { String msg = "Permission Denial: not allowed to send broadcast " + intent.getAction() + " to " + intent.getComponent().getPackageName() + " from " + callerApp.info.packageName; Slog.w(TAG, msg); throw new SecurityException(msg); } } else { // Limit broadcast to their own package. intent.setPackage(callerApp.info.packageName); } } } catch (RemoteException e) { Slog.w(TAG, "Remote exception", e); return ActivityManager.BROADCAST_SUCCESS; } } // 处理和package相关的,如果当前包被移除,则需要移除对应的activity等 final String action = intent.getAction(); if (action != null) { 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: // Handle special intents: if this broadcast is from the package // manager about a package being removed, we need to remove all of // its activities from the history stack. if (checkComponentPermission( android.Manifest.permission.BROADCAST_PACKAGE_REMOVED, callingPid, callingUid, -1, true) != PackageManager.PERMISSION_GRANTED) { String msg = "Permission Denial: " + intent.getAction() + " broadcast from " + callerPackage + " (pid=" + callingPid + ", uid=" + callingUid + ")" + " requires " + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED; Slog.w(TAG, msg); throw new SecurityException(msg); } switch (action) { case Intent.ACTION_UID_REMOVED: final Bundle intentExtras = intent.getExtras(); final int uid = intentExtras != null ? intentExtras.getInt(Intent.EXTRA_UID) : -1; if (uid >= 0) { mBatteryStatsService.removeUid(uid); mAppOpsService.uidRemoved(uid); } break; case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE: // If resources are unavailable just force stop all those packages // and flush the attribute cache as well. String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); if (list != null && list.length > 0) { for (int i = 0; i < list.length; i++) { forceStopPackageLocked(list[i], -1, false, true, true, false, false, userId, "storage unmount"); } mRecentTasks.cleanupLocked(UserHandle.USER_ALL); sendPackageBroadcastLocked( IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE, list, userId); } break; case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE: mRecentTasks.cleanupLocked(UserHandle.USER_ALL); break; case Intent.ACTION_PACKAGE_REMOVED: case Intent.ACTION_PACKAGE_CHANGED: Uri data = intent.getData(); String ssp; if (data != null && (ssp=data.getSchemeSpecificPart()) != null) { boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(action); boolean fullUninstall = removed && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); final boolean killProcess = !intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false); if (killProcess) { forceStopPackageLocked(ssp, UserHandle.getAppId( intent.getIntExtra(Intent.EXTRA_UID, -1)), false, true, true, false, fullUninstall, userId, removed ? "pkg removed" : "pkg changed"); } if (removed) { sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED, new String[] {ssp}, userId); if (fullUninstall) { mAppOpsService.packageRemoved( intent.getIntExtra(Intent.EXTRA_UID, -1), ssp); // Remove all permissions granted from/to this package removeUriPermissionsForPackageLocked(ssp, userId, true); removeTasksByPackageNameLocked(ssp, userId); mBatteryStatsService.notePackageUninstalled(ssp); } } else { cleanupDisabledPackageComponentsLocked(ssp, userId, killProcess, intent.getStringArrayExtra( Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST)); } } break; } break; case Intent.ACTION_PACKAGE_ADDED: // Special case for adding a package: by default turn on compatibility mode. Uri data = intent.getData(); String ssp; if (data != null && (ssp = data.getSchemeSpecificPart()) != null) { final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); mCompatModePackages.handlePackageAddedLocked(ssp, replacing); try { ApplicationInfo ai = AppGlobals.getPackageManager(). getApplicationInfo(ssp, 0, 0); mBatteryStatsService.notePackageInstalled(ssp, ai != null ? ai.versionCode : 0); } catch (RemoteException e) { } } break; case Intent.ACTION_TIMEZONE_CHANGED: // If this is the time zone changed action, queue up a message that will set // the timezone of all currently running processes. This message will get // queued up before the broadcast happens. Message msg = mHandler.obtainMessage(UPDATE_TIME_ZONE); msg.obj = intent.getStringExtra("time-zone"); mHandler.sendMessage(msg); break; // 系统action,时间发生变化,发送消息 case Intent.ACTION_TIME_CHANGED: // If the user set the time, let all running processes know. final int is24Hour = intent.getBooleanExtra(Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT, false) ? 1 : 0; mHandler.sendMessage(mHandler.obtainMessage(UPDATE_TIME, is24Hour, 0)); BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics(); synchronized (stats) { stats.noteCurrentTimeChangedLocked(); } break; case Intent.ACTION_CLEAR_DNS_CACHE: mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG); break; case Proxy.PROXY_CHANGE_ACTION: ProxyInfo proxy = intent.getParcelableExtra(Proxy.EXTRA_PROXY_INFO); mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy)); break; } } // 保存所有的粘性广播到mStickyBroadcasts中 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> stickies = mStickyBroadcasts.get( UserHandle.USER_ALL); if (stickies != null) { ArrayList list = stickies.get(intent.getAction()); if (list != null) { int N = list.size(); int i; for (i=0; iif (intent.filterEquals(list.get(i))) { throw new IllegalArgumentException( "Sticky broadcast " + intent + " for user " + userId + " conflicts with existing global broadcast"); } } } } } ArrayMap> stickies = mStickyBroadcasts.get(userId); if (stickies == null) { stickies = new ArrayMap<>(); mStickyBroadcasts.put(userId, stickies); } ArrayList list = stickies.get(intent.getAction()); if (list == null) { list = new ArrayList<>(); stickies.put(intent.getAction(), list); } final int stickiesCount = list.size(); int i; for (i = 0; i < stickiesCount; i++) { if (intent.filterEquals(list.get(i))) { // This sticky already exists, replace it. list.set(i, new Intent(intent)); break; } } if (i >= stickiesCount) { list.add(new Intent(intent)); } } int[] users; if (userId == UserHandle.USER_ALL) { // Caller wants broadcast to go to all started users. users = mStartedUserArray; } else { // Caller wants broadcast to go to one specific user. users = new int[] {userId}; } // 将所有静态注册的广播接收者保存到receivers中,动态注册的广播保存到registeredReceivers中 List receivers = null; List 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 == Process.SHELL_UID) { // Query one target user at a time, excluding shell-restricted users UserManagerService ums = getUserManagerLocked(); for (int i = 0; i < users.length; i++) { if (ums.hasUserRestriction( UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) { continue; } List registeredReceiversForUser = mReceiverResolver.queryIntent(intent, resolvedType, false, users[i]); if (registeredReceivers == null) { registeredReceivers = registeredReceiversForUser; } else if (registeredReceiversForUser != null) { registeredReceivers.addAll(registeredReceiversForUser); } } } else { registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false, userId); } } // 表示是否替换之前相同的广播,即之前发送过的一个广播,但是接收者还没有接收,此时又发送了一个相同的广播 final boolean replacePending = (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0; if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueing broadcast: " + intent.getAction() + " replacePending=" + replacePending); 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, callingPid, callingUid, 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); if (!replaced) { queue.enqueueParallelBroadcastLocked(r); queue.scheduleBroadcastsLocked(); } registeredReceivers = null; NR = 0; } // Merge into one list. int ir = 0; if (receivers != null) { // A special case for PACKAGE_ADDED: do not allow the package // being added to see this broadcast. This prevents them from // using this as a back door to get run as soon as they are // installed. Maybe in the future we want to have a special install // broadcast or such for apps, but we'd like to deliberately make // this decision. String skipPackages[] = null; if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction()) || Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction()) || Intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) { Uri data = intent.getData(); if (data != null) { String pkgName = data.getSchemeSpecificPart(); if (pkgName != null) { skipPackages = new String[] { pkgName }; } } } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) { skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } if (skipPackages != null && (skipPackages.length > 0)) { for (String skipPackage : skipPackages) { if (skipPackage != null) { int NT = receivers.size(); for (int it=0; itif (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 ((receivers != null && receivers.size() > 0) || resultTo != null) { BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callingPid, callingUid, 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()); boolean replaced = replacePending && queue.replaceOrderedBroadcastLocked(r); if (!replaced) { queue.enqueueOrderedBroadcastLocked(r); // 广播的分发,真正发送广播的地方在BroadcastQueue#scheduleBroadcastsLocked中执行的 queue.scheduleBroadcastsLocked(); } } return ActivityManager.BROADCAST_SUCCESS;}
下面看下BroadcastQueue#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; ...... } }}final void processNextBroadcast(boolean fromMsg) { synchronized(mService) { BroadcastRecord r; if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast [" + mQueueName + "]: " + mParallelBroadcasts.size() + " broadcasts, " + mOrderedBroadcasts.size() + " ordered broadcasts"); mService.updateCpuStats(); if (fromMsg) { mBroadcastsScheduled = false; } // 先发送有序广播 while (mParallelBroadcasts.size() > 0) { r = mParallelBroadcasts.remove(0); r.dispatchTime = SystemClock.uptimeMillis(); r.dispatchClockTime = System.currentTimeMillis(); final int N = r.receivers.size(); if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast [" + mQueueName + "] " + r); for (int i=0; iif (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Delivering non-ordered on [" + mQueueName + "] to registered " + target + ": " + r); // 遍历有序广播,并且逐个发送 deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false); } addBroadcastToHistoryLocked(r); EventLog.writeEvent(EventLogTags.AM_BROADCAST_FINISHED, mQueueName, 0, (r.intent != null) ? r.intent.toString() : "null"); if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast [" + mQueueName + "] " + r); } // Now take care of the next serialized one... // If we are waiting for a process to come up to handle the next // broadcast, then do nothing at this point. Just in case, we // check that the process we're waiting for still exists. if (mPendingBroadcast != null) { if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "processNextBroadcast [" + mQueueName + "]: waiting for " + mPendingBroadcast.curApp); boolean isDead; synchronized (mService.mPidsSelfLocked) { ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid); isDead = proc == null || proc.crashing; } if (!isDead) { // It's still alive, so keep waiting return; } else { Slog.w(TAG, "pending app [" + mQueueName + "]" + mPendingBroadcast.curApp + " died before responding to broadcast"); mPendingBroadcast.state = BroadcastRecord.IDLE; mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex; mPendingBroadcast = null; } } boolean looped = false; // 逐个遍历有序广播队列,发送 do { if (mOrderedBroadcasts.size() == 0) { // No more broadcasts pending, so all done! mService.scheduleAppGcsLocked(); if (looped) { // If we had finished the last ordered broadcast, then // make sure all processes have correct oom and sched // adjustments. mService.updateOomAdjLocked(); } return; } r = mOrderedBroadcasts.get(0); boolean forceReceive = false; // 处理超时的广播,如果当前广播发送的时间超时,则直接跳过,接着发送下一个 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0; if (mService.mProcessesReady && r.dispatchTime > 0) { long now = SystemClock.uptimeMillis(); if ((numReceivers > 0) && (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) { Slog.w(TAG, "Hung broadcast [" + mQueueName + "] discarded after timeout failure:" + " now=" + now + " dispatchTime=" + r.dispatchTime + " startTime=" + r.receiverTime + " intent=" + r.intent + " numReceivers=" + numReceivers + " nextReceiver=" + r.nextReceiver + " state=" + r.state); //在broadcastTimeoutLocked方法中,同样会发送消息到BroadcastHandler,接着处理下一个广播的发送 broadcastTimeoutLocked(false); // forcibly finish this broadcast forceReceive = true; r.state = BroadcastRecord.IDLE; } } if (r.state != BroadcastRecord.IDLE) { if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST, "processNextBroadcast(" + mQueueName + ") called when not idle (state=" + r.state + ")"); return; } if (r.receivers == null || r.nextReceiver >= numReceivers || r.resultAbort || forceReceive) { // No more receivers for this broadcast! Send the final // result if requested... if (r.resultTo != null) { try { if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST, "Finishing broadcast [" + mQueueName + "] " + r.intent.getAction() + " app=" + r.callerApp); // 实现广播接收者的回调就在这里 performReceiveLocked(r.callerApp, r.resultTo, new Intent(r.intent), r.resultCode, r.resultData, r.resultExtras, false, false, r.userId); // Set this to null so that the reference // (local and remote) isn't kept in the mBroadcastHistory. r.resultTo = null; } catch (RemoteException e) { r.resultTo = null; Slog.w(TAG, "Failure [" + mQueueName + "] sending broadcast result of " + r.intent, e); } } if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG"); cancelBroadcastTimeoutLocked(); if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Finished with ordered broadcast " + r); // ... and on to the next... addBroadcastToHistoryLocked(r); EventLog.writeEvent(EventLogTags.AM_BROADCAST_FINISHED, mQueueName, 1, (r.intent != null) ? r.intent.toString() : "null"); // 将已经发送的当前广播从队列中移除 mOrderedBroadcasts.remove(0); r = null; looped = true; continue; } } while (r == null); // Get the next receiver... int recIdx = r.nextReceiver++; .......}
在processNextBroadcast方法中,通过performReceiveLocked最终实现了广播接收者的回调
private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver, Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) throws RemoteException { // Send the intent to the receiver asynchronously using one-way binder calls. if (app != null) { if (app.thread != null) { // If we have an app thread, do the call through that so it is // correctly ordered with other one-way calls. app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode, data, extras, ordered, sticky, sendingUser, app.repProcState); } else { // Application has died. Receiver doesn't exist. throw new RemoteException("app.thread must not be null"); } } else { // 这里的receiver就是之前注册广播的时候的InnerReceiver receiver.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser); }}
前面广播注册过程中,我们已经知道主要是添加广播对应的InnerReceiver和ReceiverList到mRegisteredReceivers集合中,这里就找到对应的根据对应的receiver回调其performReceive方法,InnerReceiver#performReceive
public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { LoadedApk.ReceiverDispatcher rd = mDispatcher.get(); if (ActivityThread.DEBUG_BROADCAST) { int seq = intent.getIntExtra("seq", -1); Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction() + " seq=" + seq + " to " + (rd != null ? rd.mReceiver : null)); } // 实际上通过ReceiverDispatcher#performReceive if (rd != null) { rd.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser); } else { // The activity manager dispatched a broadcast to a registered // receiver in this process, but before it could be delivered the // receiver was unregistered. Acknowledge the broadcast on its // behalf so that the system's broadcast sequence can continue. if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, "Finishing broadcast to unregistered receiver"); IActivityManager mgr = ActivityManagerNative.getDefault(); try { if (extras != null) { extras.setAllowFds(false); } mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags()); } catch (RemoteException e) { Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver"); } }}
在广播注册的过程中,将广播接收者和存入一个map集合中,一个BroadcastReceiver对应一个ReceiverDispatcher,所有的BroadcastReceiver和ReceiverDispatcher对应一个Context,即同一个应用
private final ArrayMap> mReceivers
看下ReceiverDispatcher#performReceive方法:
public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { if (ActivityThread.DEBUG_BROADCAST) { int seq = intent.getIntExtra("seq", -1); Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq + " to " + mReceiver); } // Args是一个线程,这里通过handler和Args线程,在Args线程中实现最终广播接收的回调 Args args = new Args(intent, resultCode, data, extras, ordered, sticky, sendingUser); if (!mActivityThread.post(args)) { if (mRegistered && ordered) { IActivityManager mgr = ActivityManagerNative.getDefault(); if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, "Finishing sync broadcast to " + mReceiver); args.sendFinished(mgr); } }}public void run() { final BroadcastReceiver receiver = mReceiver; final boolean ordered = mOrdered; if (ActivityThread.DEBUG_BROADCAST) { int seq = mCurIntent.getIntExtra("seq", -1); Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction() + " seq=" + seq + " to " + mReceiver); Slog.i(ActivityThread.TAG, " mRegistered=" + mRegistered + " mOrderedHint=" + ordered); } final IActivityManager mgr = ActivityManagerNative.getDefault(); final Intent intent = mCurIntent; mCurIntent = null; if (receiver == null || mForgotten) { if (mRegistered && ordered) { if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, "Finishing null broadcast to " + mReceiver); sendFinished(mgr); } return; } Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg"); try { ClassLoader cl = mReceiver.getClass().getClassLoader(); intent.setExtrasClassLoader(cl); setExtrasClassLoader(cl); receiver.setPendingResult(this); // 回调对应BroadcastReceiver的onReceive方法 receiver.onReceive(mContext, intent); } catch (Exception e) { if (mRegistered && ordered) { if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, "Finishing failed broadcast to " + mReceiver); sendFinished(mgr); } if (mInstrumentation == null || !mInstrumentation.onException(mReceiver, e)) { Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); throw new RuntimeException( "Error receiving broadcast " + intent + " in " + mReceiver, e); } } if (receiver.getPendingResult() != null) { finish(); } Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}
好了到此为止,广播的接收流程也走完了,下面总结一下流程。
广播的发送流程总结
广播的发送流程:
1. 在ContextImpl#sendBroadcast中通过Binder机制,调用ActivityManagerService#broadcastIntent
broadcastIntent —-> broadcastIntentLocked
在broadcastIntentLocked中调用了BroadcastQueue#scheduleBroadcastsLocked方法在BroadcastQueue#scheduleBroadcastsLocked中发送一个”BROADCAST_INTENT_MSG”消息到BroadcastHandler处理
BroadcastHandler处理”BROADCAST_INTENT_MSG”消息时候,调用BroadcastQueue#processNextBroadcast方法
在BroadcastQueue#processNextBroadcast中有一行关键代码:
// 实现广播接收的回调就在这里
performReceiveLocked(r.callerApp, r.resultTo,
new Intent(r.intent), r.resultCode,
r.resultData, r.resultExtras, false, false, r.userId);在BroadcastQueue#performReceiveLocked方法中,通过传递进来的InnerReceiver回调其接收动作
receiver.performReceive(intent, resultCode, data, extras, ordered,
sticky, sendingUser);在InnerReceiver#performReceive中调用与其对应的ReceiverDispatcher#performReceive
在广播注册的时候,我们已经知道一个InnerReceiver对应一个唯一的ReceiverDispatcher在ReceiverDispatcher#performReceive中通过handler和Args线程中回调对应的onReceive方法
receiver.onReceive(mContext, intent);
更多相关文章
- Android的静态注册广播问题
- Android(安卓)NDK之发送短信
- Android(安卓)实现发送短信demo
- android耳机广播接收
- Android使用HttpURLConnection上传文件
- Android(安卓)SmsManager(短信管理器),发送短信息
- Android短信发送器
- 国内目前最全面的介绍——Android中的BroadCastReceiver
- android 注册页面实现