finalintbroadcastIntentLocked(ProcessRecord callerApp, String callerPackage, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions, boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) { intent = newIntent(intent);
// By default broadcasts do not go to stopped apps. // 增加下面flag,默认不发送广播到已经停止的app intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
// If we have not finished booting, don't allow this to launch new processes. // 如果该进程还没有完成启动,并且不是发送给启动升级的广播,则添只发送给已注册的广播接收者标签 if (!mProcessesReady && (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) { intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);// 只发给注册的receiver }
// Make sure that the user who is receiving this broadcast is running. // If not, we will just skip it. Make an exception for shutdown broadcasts // and upgrade steps. if (userId != UserHandle.USER_ALL && !mUserController.isUserRunningLocked(userId, 0)) { return ActivityManager.BROADCAST_FAILED_USER_STOPPED; } }
...
// Verify that protected broadcasts are only being sent by system code, // and that system code is only sending protected broadcasts. finalStringaction= intent.getAction(); finalboolean isProtectedBroadcast; try { // 验证是不是受保护的广播(是不是系统广播) isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action); } catch (RemoteException e) { ... return ActivityManager.BROADCAST_SUCCESS; }
// 检查是不是系统调用 finalboolean isCallerSystem; switch (UserHandle.getAppId(callingUid)) { case Process.ROOT_UID: case Process.SYSTEM_UID: case Process.PHONE_UID: case Process.BLUETOOTH_UID: case Process.NFC_UID: isCallerSystem = true; break; default: isCallerSystem = (callerApp != null) && callerApp.persistent; break; }
// First line security check before anything else: stop non-system apps from // sending protected broadcasts. if (!isCallerSystem) {// 不是系统发送的广播 if (isProtectedBroadcast) {// 非系统进程发送受保护广播抛出异常 thrownewSecurityException(msg); } elseif (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action) || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) { // 如果是配置小部件或者升级小部件的广播 // Special case for compatibility: we don't want apps to send this, // but historically it has not been protected and apps may be using it // to poke their own app widget. So, instead of making it protected, // just limit it to the caller. if (callerPackage == null) { thrownewSecurityException(msg); } elseif (intent.getComponent() != null) { // They are good enough to send to an explicit component... verify // it is being sent to the calling app. if (!intent.getComponent().getPackageName().equals( callerPackage)) { thrownewSecurityException(msg); } } else { // Limit broadcast to their own package. // 限制发送广播给自己包里 intent.setPackage(callerPackage); } } }
// 下面主要是针对系统广播的处理 if (action != null) { switch (action) { case Intent.ACTION_UID_REMOVED:// 移除uid case Intent.ACTION_PACKAGE_REMOVED:// 卸载应用 case Intent.ACTION_PACKAGE_CHANGED:// 应用更改,比如:停用,启动等 case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:// 外部应用不可用,比如安装到sd卡的应用,卸载了sd卡 case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:// 外部应用可用 case Intent.ACTION_PACKAGES_SUSPENDED:// 暂停应用 case Intent.ACTION_PACKAGES_UNSUSPENDED:// 应用可用 switch (action) { case Intent.ACTION_UID_REMOVED:// 移除系统userId(删除一个用户) ... break; case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:// 外部应用不可用,一般是卸载SD卡 ... break; case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:// 外部应用可用,一般是插入SD卡 ... break; case Intent.ACTION_PACKAGE_REMOVED:// 卸载 case Intent.ACTION_PACKAGE_CHANGED:// 更新 ... break; case Intent.ACTION_PACKAGES_SUSPENDED: case Intent.ACTION_PACKAGES_UNSUSPENDED: ... break; } break; case Intent.ACTION_PACKAGE_REPLACED: {// 升级应用 ... break; } case Intent.ACTION_PACKAGE_ADDED: {// 安装应用 ... break; } case Intent.ACTION_PACKAGE_DATA_CLEARED: {// 清理应用数据 ... break; } case Intent.ACTION_TIMEZONE_CHANGED:// 时区改变 ... break; case Intent.ACTION_TIME_CHANGED:// 时间改变 ... break; case Intent.ACTION_CLEAR_DNS_CACHE:// 清理DNS缓存 ... break; case Proxy.PROXY_CHANGE_ACTION:// 代理改变 ... break; case android.hardware.Camera.ACTION_NEW_PICTURE:// 新照片 case android.hardware.Camera.ACTION_NEW_VIDEO:// 新视频 ... return ActivityManager.BROADCAST_SUCCESS; } }
// Add to the sticky list if requested. if (sticky) {// 判断是否是粘性广播,如果是,AMS就需要保存这个广播,以便后面注册要接收此类型广播的接收者可以获得这个广播 // 检查粘性广播是否申请了权限 ... if (requiredPermissions != null && requiredPermissions.length > 0) { ... return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION; } // sticky广播不能指定目标组件 ... // We use userId directly here, since the "all" target is maintained(维护) // as a separate set of sticky broadcasts. if (userId != UserHandle.USER_ALL) {// 不是发送给所有用户的广播 // But first, if this is not a broadcast to all users, then // make sure it doesn't conflict(冲突) with an existing broadcast to // all users. ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get( UserHandle.USER_ALL); ...// 检查是否和存在的发给所有用户的粘性广播一样的广播 } // 在AMS中所有的粘性广播都保存在一个列表中,这些列表最终保存在AMS的成员变量mStickyBroadcasts // 所描述的一个HashMap中,并且以它们的广播类型为关键字 // 首先检查mStickyBroadcasts是否有改用户的粘性广播列表 ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId); // 该广播列表中没有该用户的stick广播列表 if (stickies == null) { stickies = newArrayMap<>(); mStickyBroadcasts.put(userId, stickies); } // 获取注册广播的Action对应的粘性广播的Intent列表 ArrayList<Intent> list = stickies.get(intent.getAction()); if (list == null) {// 如果为空 list = newArrayList<>();// 创建一个列表 stickies.put(intent.getAction(), list);// 以action为键保存该列表 } // 获取该action对应粘性广播Intent列表的个数 finalintstickiesCount= list.size(); int i; // 检查在粘性广播列表中是否保存了一个与参数Intent一致的广播。如果存在直接替换,否则将参数 // Intent描述的广播添加到粘性广播列表list中 for (i = 0; i < stickiesCount; i++) { if (intent.filterEquals(list.get(i))) { // This sticky already exists, replace it. list.set(i, newIntent(intent)); break; } } if (i >= stickiesCount) {// 如果该列表中不存在该粘性广播的Intent加入进去 list.add(newIntent(intent)); // 我们看到粘性广播放在了list中,而list以action为键放置在了stickies中,而stickies // 又以userId为键放在了mStickyBroadcasts中,因此mStickyBroadcasts保存了设备中所有 // 用户粘性广播的Intent } }
int[] users; if (userId == UserHandle.USER_ALL) {// 发送广播给全部用户 // Caller wants broadcast to go to all started users. // 获取所有已启动用户的列表 users = mUserController.getStartedUserArrayLocked(); } else {// 发送广播给指定用户 // Caller wants broadcast to go to one specific user. users = newint[]{userId}; }
// Figure out who all will receive this broadcast. Listreceivers=null;// 静态注册接收者 List<BroadcastFilter> registeredReceivers = null;// 动态注册接收者 // Need to resolve the intent to interested receivers... if ((intent.getFlags() & Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {// 如果当前的广播Intent没有指定FLAG_RECEIVER_REGISTERED_ONLY标记,也就是允许静态注册 // 允许静态注册的Intent,需要从PMS中去查询对应的广播接收者 receivers = collectReceiverComponents(intent, resolvedType, callingUid, users); } // 如果参数intent没有指定广播接收者的组件名,说明是发送给所有已注册并且要接收该广播的接收者的 if (intent.getComponent() == null) { if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) { // Query one target user at a time, excluding shell-restricted users // 查找每一个用户的广播注册者 for (inti=0; i < users.length; i++) { if (mUserController.hasUserRestriction( UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) { continue; } // registeredReceiver快结束前将注册的BroadcastFilter放入mReceiverResolver中 // 里面包含了对应的动态注册的广播接收者 List<BroadcastFilter> registeredReceiversForUser = mReceiverResolver.queryIntent(intent, resolvedType, false, users[i]); if (registeredReceivers == null) { registeredReceivers = registeredReceiversForUser; } elseif (registeredReceiversForUser != null) { registeredReceivers.addAll(registeredReceiversForUser); } } } else {// 查找当前用户的所有广播接收者 // 查询所有动态注册广播接收者 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false, userId); } } // 由于AMS是通过消息机制将接收到的广播发送给目标广播接收者的,因此可能会出现一种情况:上次接收 // 的广播还没有来得及发送给广播接收者,又马上接收到一个同样的广播,在这种情况下,如果现在接收的 // 广播标志位FLAG_RECEIVER_REPLACE_PENDING等于1,那么AMS就会用新的广播代替旧的广播。 finalbooleanreplacePending= (intent.getFlags() & Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
// 在BroadcastQueue中等待发送广播中搜索是否有相同的BroadcastRecord并且是否替换 booleanreplaced= replacePending && queue.replaceOrderedBroadcastLocked(r); if (!replaced) {// 存在需要AMS的有序广播调用队列中增加新的额广播任务 // ---------!!!重要!!!----------包含动态和静态接收者 // 也就是说静态广播都放在BroadcastQueue的mOrderedBroadcasts中,这里也有orderd动态广播 queue.enqueueOrderedBroadcastLocked(r); // 执行发送广播 queue.scheduleBroadcastsLocked(); } } else { // There was nobody interested in the broadcast, but we still want to record // that it happened. if (intent.getComponent() == null && intent.getPackage() == null && (intent.getFlags() & Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { // This was an implicit broadcast... let's record it for posterity. addBroadcastStatLocked(intent.getAction(), callerPackage, 0, 0, 0); } }
// 表示广播已经向所有的receiver发送结束或者中途被取消, 如果r.resultAbort为true,会停止处理 // 当前正在发送的BroadcastRecord,这样优先级比较低的接收者也就收不到这个广播了 // 检查BroadcastRecord对象r所描述的广播转发任务是否已经处理完成,或者是否已经被强制结束了。 // 如果是,那么调用函数cancelBroadcastTimeoutLocked来删除前面发送到AMS所运行在的线程的消息 // 队列中的一个BROADCAST_TIMEOUT_MSG消息,表示BroadcastRecord对象r所描述的广播转发任务已经 // 在规定时间内处理完成了。接下来就讲改广播BroadcastRecord对象从队列中删除,然后赋值为null 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 { ... performReceiveLocked(r.callerApp, r.resultTo, newIntent(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) { ... } } ... // ... and on to the next... ... // BroadcastRecord处理完移除 mOrderedBroadcasts.remove(0); r = null; looped = true; continue; } } while (r == null);// 如果第一次取出的r不为空,则退出循环
// Get the next receiver...(获取下一个将要处理的广播接收者在其列表中的位置) intrecIdx= r.nextReceiver++;
// Keep track of when this receiver started, and make sure there // is a timeout message pending to kill it if need be. // 保存当前时间, r.receiverTime = SystemClock.uptimeMillis(); if (recIdx == 0) {// 表示第一个开始处理的接收者,也就是BroadcastRecord对象r所描述的广播任务刚被处理 // 接收者开始处理的时间戳,也就是这个接收者开始处理了,要记录开始时间来计算是否超过超时时间 // 也就是说这是BroadcastRecord中第一个接收者开始被处理的时间戳,也就是上面BroadcastRecord // 超时的起点,可以看到上面超时比较的时候用的就是r.dispatchTime r.dispatchTime = r.receiverTime; r.dispatchClockTime = System.currentTimeMillis(); ... } // 检查AMS是否已经向它所在的线程的消息队列发送了类型为BROADCAST_TIMEOUT_MSG的消息,如果没有发送, // 那么会调用setBroadcastTimeoutLocked函数向这个线程发送一个类型为setBroadcastTimeoutLocked // 的消息,并且制定在timeoutTime毫秒后处理。上面指定了r.receiverTime为当前时间表示AMS将一个有序 // 广播发送给BroadcastRecord对象r所描述的广播转发任务的下一个目标广播接收者处理的时间。如果这个 // 广播接收者不能再timeoutTime之内完成这个有序广播,AMS就会任务它超时。 if (!mPendingBroadcastTimeoutMessage) { longtimeoutTime= r.receiverTime + mTimeoutPeriod; ... // 设置超时,传入参数是r.receiverTime + mTimeoutPeriod,也就是开始时间加上超时时间 // mTimeoutPeriod,mTimeoutPeriod初始化是在BroadcastQueue初始化的时候传入的, // 也就是在AMS(AMS构造函数中)中初始化mFgBroadcastQueue和mBgBroadcastQueue时传入的 // BROADCAST_FG_TIMEOUT = 10 * 1000和BROADCAST_BG_TIMEOUT = 60 * 1000, // 这里开始埋了ANR的雷 setBroadcastTimeoutLocked(timeoutTime); }
// 如果当前nextReceiver是一个BroadcastFilter类型,说名是一个动态注册接收者,不需要启动一个进程, // 直接调用deliverToRegisteredReceiverLocked函数发送广播 if (nextReceiver instanceof BroadcastFilter) { // Simple case: this is a registered receiver who gets // a direct call. BroadcastFilterfilter= (BroadcastFilter) nextReceiver; ... // 上面已经分析 deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx); // 检查BroadcastRecord对象r所描述的广播转发任务是否用来转发无序广播的。 if (r.receiver == null || !r.ordered) {// 如果是 ... // 设置IDLE状态,表示AMS不需要等待它的前一个目标广播接收者处理完成一个广播就可以将该广播 // 继续发送给它的下一个目标广播接收者处理 r.state = BroadcastRecord.IDLE; // 调用下面函数就是为了将一个广播继续发送给BroadcastRecord对象r所描述的广播转发任务的 // 下一个目标广播接收者处理的 scheduleBroadcastsLocked(); } else { ... } return; }
// Hard case: need to instantiate the receiver, possibly // starting its application process to host it. // 如果不是动态的说明是一个静态注册接收者(如果动态的上面if中处理并进行拦截),此时进程可能没有启动 ResolveInfoinfo= (ResolveInfo) nextReceiver; ComponentNamecomponent=newComponentName( info.activityInfo.applicationInfo.packageName, info.activityInfo.name);
// 处理非串行化动态广播,非串化ordered是false,这里的receiver对应的是 // LoadedApk.ReceiverDispatcher.InnerReceiver对象 // This function exists to make sure all receiver dispatching is // correctly ordered, since these are one-way calls and the binder driver // applies transaction ordering per object for such calls. publicvoidscheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent, int resultCode, String dataStr, Bundle extras, boolean ordered, boolean sticky, int sendingUser, int processState)throws RemoteException { updateProcessState(processState, false); // 调用LoadedApk.ReceiverDispatcher.InnerReceiver.performReceive函数 receiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky, sendingUser); }
longtimeoutTime= r.receiverTime + mTimeoutPeriod; // 举个例子: // 假设receiverA在100s的时候开始处理,超时时间为10s,那么receiverA的超时时间点就是110s, // 但是receiverA在105s的时候已经处理完了,于是在105s的时候开始receiverB,但是并没有取消 // receiverA的超时消息,也就是在110s的时候仍然会走到这里的broadcastTimeoutLocked函数, // receiverB开始处理,这时候r.receiverTime就是105s,对于receiverB而言超时时间应该是115s, // 假设receiverB需要在112s才能处理完,在110s的时候broadcastTimeoutLocked函数处理的时候 // timeoutTime=115s,now=110s,这时候不会进行实际的超时处理,因为还没有到真实的超时时间, // 所以重新设置超时时间点在115s。就这样根据当前BroadcastRecord.receiverTime的时间反复调整。 if (timeoutTime > now) {// 判断超时时间点和现在时间的关系,此处还没有超时 // We can observe premature timeouts because we do not cancel and reset the // broadcast timeout message after each receiver finishes. Instead, we set up // an initial timeout then kick it down the road a little further as needed // when it expires. // 因为没有在每个广播处理完之后取消或者重置超时时间,从而导致提前检测到超时消息。取而代之, // 设置一个初始超时时间点,然后每次出现超时事件的时候根据需要进行处理或者调整超时机制。 ... setBroadcastTimeoutLocked(timeoutTime); return; } }
// 主要包括三步: // 1) 创建BroadcastReceiver对象 // 2) 执行onReceive函数 // 3) 向AMS发送处理结束消息 privatevoidhandleReceiver(ReceiverData data) { // If we are getting ready to gc after going to the background, well // we are back active so skip it. unscheduleGcIdler();
privatefinalbooleanattachApplicationLocked(IApplicationThread thread, int pid) {
... // Check if a next-broadcast receiver is in this process... if (!badApp && isPendingBroadcastProcessLocked(pid)) { try { didSomething |= sendPendingBroadcastsLocked(app); } catch (Exception e) { // If the app died trying to launch the receiver we declare it 'bad' Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e); badApp = true; } } ... }
// The app just attached; send any pending broadcasts that it should receive booleansendPendingBroadcastsLocked(ProcessRecord app) { booleandidSomething=false; for (BroadcastQueue queue : mBroadcastQueues) { didSomething |= queue.sendPendingBroadcastsLocked(app); } return didSomething; }