1、标准广播:异步广播,广播发出后,所有注册了的广播接收器都会同时接收到该广播。打个比方:做地铁过程中的语音播报,当列车员(广播发出者)进行语音播报(发送广播)时,所有乘客(注册接收该广播的程序)都可以同时听到语音,不分先后顺序。
sendBroadcast();
2、有序广播:同步发送,广播发出后,按照注册了的广播接收器的优先级顺序广播,优先级的范围是-1000~1000,数字越大,优先级越高,最先接收到该广播,接收器的优先级通过android:priority设置,并且先收到广播的可以修改或者抛弃该广播,后面优先级小的接收器就无法收到了。同级别的广播,动态优先于静态;同级别同类型的广播,静态:先扫描的优先于后扫描的,动态:先注册的优先于后注册的。
sendOrderedBroadcast();
3、粘性广播:粘性广播的机制就是发送广播的时候如果没有找到接收器,就会先保存下来,等有广播接收器注册的时候,再把之前保存的广播发出去。因为从Android 5.0(API 21)开始,因为安全性的问题,官方已经正式废弃了粘性广播。
sendStickyBroadcast();
广播注册方式
1、动态注册:在Context(即Service或Activity)组件中注册,通过registerReceiver()方法注册,在不使用时取消注册unregisterReceiver()。如果广播发送的时候注册Broadcast的组件没有启动的话,是收不到广播的。
2、 静态注册:在l中注册,并在intent-filter
中添加响应的action
,并新建一个Broadcast组件类来处理注册广播。如果广播发送的时候Broadcast的组件类进程没有启动的话,会收到广播并启动进程。
具体实现可参考Android的有序广播和无序广播(解决安卓8.0版本之后有序广播的接收问题) 区分了Android8.0前后的实现方式。
前台广播及后台广播
前台广播:在广播发送的时候添加Intent.FLAG_RECEIVER_FOREGROUND flag。
后台广播:在广播发送的时候没有Intent.FLAG_RECEIVER_FOREGROUND flag。
默认情况下,Intent是不带Intent.FLAG_RECEIVER_FOREGROUND 的flag的,所以我们默认使用的都是后台广播。
frameworks/base/core/java/android/app/ContextImpl.java
@Overridepublic void sendBroadcast(Intent intent) {warnIfCallingFromSystemProcess();String resolvedType = solveTypeIfNeeded(getContentResolver());try {//准备离开现有进程intent.prepareToLeaveProcess(this);//调用 AMS 的broadcastIntentWithFeature方法 false/**表示非有序**/, false/**表示非粘性**/, getUserId());} catch (RemoteException e) {hrowFromSystemServer();}}
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@Overridepublic final int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId,Intent intent, String resolvedType, IIntentReceiver resultTo,int resultCode, String resultData, Bundle resultExtras,String[] requiredPermissions, String[] excludedPermissions,String[] excludedPackages, int appOp, Bundle bOptions,boolean serialized, boolean sticky, int userId) {enforceNotIsolatedCaller("broadcastIntent");synchronized(this) {// 验证广播的有效性intent = verifyBroadcastLocked(intent);final ProcessRecord callerApp = getRecordForAppLOSP(caller);final int callingPid = CallingPid();final int callingUid = CallingUid(); //保留原始的origId final long origId = Binder.clearCallingIdentity();/// M: DuraSpeed @{String suppressAction = ReadyToStartComponent(callerApp != null ? callerApp.info.packageName : null, callingUid,"broadcast", null);if ((suppressAction != null) && suppressAction.equals("skipped")) {storeCallingIdentity(origId);Slog.d(TAG, "broadcastIntentWithFeature, suppress to broadcastIntent!");return ActivityManager.BROADCAST_SUCCESS;}/// @}try {return broadcastIntentLocked(callerApp,callerApp != null ? callerApp.info.packageName : null, callingFeatureId,intent, resolvedType, resultTo, resultCode, resultData, resultExtras,requiredPermissions, excludedPermissions, excludedPackages, appOp, bOptions,serialized, sticky, callingPid, callingUid, callingUid, callingPid, userId);} finally { //恢复origId storeCallingIdentity(origId);}}}
单独罗列 verifyBroadcastLocked 方法:
final Intent verifyBroadcastLocked(Intent intent) {// Refuse possible leaked file descriptors// 拒绝存在有文件描述符的intentif (intent != null && intent.hasFileDescriptors() == true) {throw new IllegalArgumentException("File descriptors passed in Intent");}int flags = Flags();if (!mProcessesReady) { //系统还没有准备好,表示还没有调用systemReady 函数. // if the caller really truly claims to know what they're doing, go// ahead and allow the broadcast without launching any receivers if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) { //包含Intent.FLAG_RECEIVER_REGISTERED_ONLY的flag,可以继续往下走.// This will be turned into a FLAG_RECEIVER_REGISTERED_ONLY later on if needed.} else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent+ " before boot completion");throw new IllegalStateException("Cannot broadcast before boot completed");}}if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) { //禁止携带Intent.FLAG_RECEIVER_BOOT_UPGRADE flag throw new IllegalArgumentException("Can't use FLAG_RECEIVER_BOOT_UPGRADE here");}if ((flags & Intent.FLAG_RECEIVER_FROM_SHELL) != 0) {switch (CallingUid()) {case ROOT_UID:case SHELL_UID:break;default: // 若不是ROOT和SHELL用户,则移除 Intent.FLAG_RECEIVER_FROM_SHELL flag Slog.w(TAG, "Removing FLAG_RECEIVER_FROM_SHELL because caller is UID "+ CallingUid());veFlags(Intent.FLAG_RECEIVER_FROM_SHELL);break;}}return intent;}
单独罗列 getRecordForAppLOSP 方法:
@GuardedBy(anyOf = {"this", "mProcLock"})ProcessRecord getRecordForAppLOSP(IApplicationThread thread) {if (thread == null) {return null;}ProcessRecord record = LRURecordForAppLOSP(thread);if (record != null) return record; // Validation: if it isn't in the LRU list, it shouldn't exist, but let's double-check that. final IBinder threadBinder = thread.asBinder();final ArrayMap<String, SparseArray<ProcessRecord>> pmap ProcessNamesLOSP().getMap();for (int i = pmap.size()-1; i >= 0; i--) {final SparseArray<ProcessRecord> procs = pmap.valueAt(i);for (int j = procs.size()-1; j >= 0; j--) {final ProcessRecord proc = procs.valueAt(j);final IApplicationThread procThread = Thread();if (procThread != null && procThread.asBinder() == threadBinder) {Slog.wtf(TAG, "getRecordForApp: exists in name list but not in LRU list: "+ proc);return proc;}}}return null;}
frameworks/base/services/core/java/com/android/server/am/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,String[] excludedPermissions, String[] excludedPackages, int appOp, Bundle bOptions,boolean ordered, boolean sticky, int callingPid, int callingUid,int realCallingUid, int realCallingPid, int userId,boolean allowBackgroundActivityStarts,@Nullable IBinder backgroundActivityStartsToken,@Nullable int[] broadcastAllowList) {intent = new Intent(intent);//判断是InstantAppfinal boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);// Instant Apps cannot use FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPSif (callerInstantApp) {//取消FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS flag标记intent.Flags() & ~Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);}if (userId == UserHandle.USER_ALL && broadcastAllowList != null) {Slog.e(TAG, "broadcastAllowList only applies when sending to individual users. "+ "Assuming restrictive whitelist.");// userId是USER_ALL ,则不需要此限制.broadcastAllowList = new int[]{};}// By default broadcasts do not go to stopped apps.//默认情况下,不会像已经停止的应用发送广播.intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);// If we have not finished booting, don't allow this to launch new processes.//开机完成之前,不允许开启新的进程.if (!mProcessesReady && (Flags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);}//告知广播的类型if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,(sticky ? "Broadcast sticky: ": "Broadcast: ") + intent+ " ordered=" + ordered + " userid=" + userId);if ((resultTo != null) && !ordered) {Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");}userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,ALLOW_NON_FULL, "broadcast", callerPackage);// Make sure that the user who is receiving this broadcast or its parent is running.// If not, we will just skip it. Make an exception for shutdown broadcasts, upgrade steps.if (userId != UserHandle.USER_ALL && !mUserController.isUserOrItsParentRunning(userId)) {if ((callingUid != SYSTEM_UID|| (Flags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)&& !Intent.ACTION_SHUTDOWN.Action())) {Slog.w(TAG, "Skipping broadcast of " + intent+ ": user " + userId + " and its parent (if any) are stopped");return ActivityManager.BROADCAST_FAILED_USER_STOPPED;}}final String action = Action();BroadcastOptions brOptions = null;if (bOptions != null) {brOptions = new BroadcastOptions(bOptions);if (TemporaryAppAllowlistDuration() > 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(CHANGE_DEVICE_IDLE_TEMP_WHITELIST,realCallingPid, realCallingUid, -1, true)!= PackageManager.PERMISSION_GRANTED&& checkComponentPermission(START_ACTIVITIES_FROM_BACKGROUND,realCallingPid, realCallingUid, -1, true)!= PackageManager.PERMISSION_GRANTED&& checkComponentPermission(START_FOREGROUND_SERVICES_FROM_BACKGROUND,realCallingPid, realCallingUid, -1, true)!= PackageManager.PERMISSION_GRANTED) {String msg = "Permission Denial: " + Action()+ " broadcast from " + callerPackage + " (pid=" + callingPid+ ", uid=" + callingUid + ")"+ " requires "+ CHANGE_DEVICE_IDLE_TEMP_WHITELIST + " or "+ START_ACTIVITIES_FROM_BACKGROUND + " or "+ START_FOREGROUND_SERVICES_FROM_BACKGROUND;Slog.w(TAG, msg);throw new SecurityException(msg);}}// 不能发送给受限的应用if (brOptions.isDontSendToRestrictedApps()&& !isUidActiveLOSP(callingUid)&& isBackgroundRestrictedNoCheck(callingUid, callerPackage)) {Slog.i(TAG, "Not sending broadcast " + action + " - app " + callerPackage+ " has background restrictions");return ActivityManager.START_CANCELED;}if (brOptions.allowsBackgroundActivityStarts()) {// 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.START_ACTIVITIES_FROM_BACKGROUND,realCallingPid, realCallingUid, -1, true)!= PackageManager.PERMISSION_GRANTED) {String msg = "Permission Denial: " + Action()+ " broadcast from " + callerPackage + " (pid=" + callingPid+ ", uid=" + callingUid + ")"+ " requires "+ android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;Slog.w(TAG, msg);throw new SecurityException(msg);} else {allowBackgroundActivityStarts = true;// We set the token to null since if it wasn't for it we'd allow anyway herebackgroundActivityStartsToken = null;}}}// Verify that protected broadcasts are only being sent by system code,// and that system code is only sending protected broadcasts.final boolean isProtectedBroadcast;//判断受保护的广播try {isProtectedBroadcast = PackageManager().isProtectedBroadcast(action);} catch (RemoteException e) {Slog.w(TAG, "Remote exception", e);return ActivityManager.BROADCAST_SUCCESS;}final boolean isCallerSystem;switch (AppId(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://TINNO BEGIN//DATE20221208, Modify By XIBIN,DGF-1148isCallerSystem = (callerApp != null) && callerApp.isPersistent()||("com.android.systemui".equals(callerPackage) && "com.android.settings.flashlight.action.FLASHLIGHT_CHANGED".equals(action));//TINNO ENDbreak;}// First line security check before anything else: stop non-system apps from sending protected broadcasts.// 非系统应用阻止发送系统广播if (!isCallerSystem) {if (isProtectedBroadcast) {//非系统应用发送受保护广播,直接报异常String msg = "Permission Denial: not allowed to send broadcast "+ action + " from pid="+ callingPid + ", uid=" + callingUid;Slog.w(TAG, msg);throw new SecurityException(msg);} else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)|| AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {// Special case for compatibility: we don't want apps to send this,// but historically it has not been protected and apps may be using it// to poke their own app widget. So, instead of making it protected,// just limit it to the caller.if (callerPackage == null) {//若找不到广播的调用者,直接报异常.String msg = "Permission Denial: not allowed to send broadcast "+ action + " from unknown caller.";Slog.w(TAG, msg);throw new SecurityException(msg);} else if (Component() != null) {// They are good enough to send to an verify// it is being sent to the calling app.//对于ACTION_APPWIDGET_CONFIGURE和ACTION_APPWIDGET_UPDATE 了,两个action,需要调用着和显式组件的包名保持一致.if (!Component().getPackageName().equals(callerPackage)) {String msg = "Permission Denial: not allowed to send broadcast "+ action + " to "+ Component().getPackageName() + " from "+ callerPackage;Slog.w(TAG, msg);throw new SecurityException(msg);}} else {// Limit broadcast to their own package.//没有现式组件,则默认使用调用者的包名intent.setPackage(callerPackage);}}}boolean timeoutExempt = false;if (action != null) {//判断是否属于豁免的广播.if (getBackgroundLaunchBroadcasts().contains(action)) {if (DEBUG_BACKGROUND_CHECK) {Slog.i(TAG, "Broadcast action " + action + " forcing include-background");}//增加background 应用接收.intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);}switch (action) {case Intent.ACTION_UID_REMOVED:case Intent.ACTION_PACKAGE_REMOVED:case Intent.ACTION_PACKAGE_CHANGED:case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:case Intent.ACTION_PACKAGES_SUSPENDED:case Intent.ACTION_PACKAGES_UNSUSPENDED:// 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: " + Action()+ " 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 int uid = getUidFromIntent(intent);if (uid >= 0) {veUid(uid);if (BooleanExtra(Intent.EXTRA_REPLACING, false)) {UserId(uid),StringExtra(Intent.EXTRA_PACKAGE_NAME));} else {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[] StringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);//将可以用的应用进行force stopif (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");}//清理 recent task mAtmInternal.cleanupRecentTasksForUser(UserHandle.USER_ALL);//触发GC清理.sendPackageBroadcastLocked(ApplicationThreadConstants.EXTERNAL_STORAGE_UNAVAILABLE,list, userId);}break;case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:mAtmInternal.cleanupRecentTasksForUser(UserHandle.USER_ALL);break;case Intent.ACTION_PACKAGE_REMOVED:case Intent.ACTION_PACKAGE_CHANGED:Uri data = Data();String ssp;if (data != null && (sspSchemeSpecificPart()) != null) {boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(action);final boolean replacing BooleanExtra(Intent.EXTRA_REPLACING, false);final boolean killProcess =!BooleanExtra(Intent.EXTRA_DONT_KILL_APP, false);final boolean fullUninstall = removed && !replacing;if (removed) {if (killProcess) {forceStopPackageLocked(ssp, IntExtra(Intent.EXTRA_UID, -1)),false, true, true, false, fullUninstall, userId,removed ? "pkg removed" : "pkg changed");} else {// Kill any app zygotes always, since they can't fork new// processes with references to the old codeforceStopAppZygoteLocked(ssp, IntExtra(Intent.EXTRA_UID, -1)),userId);}final int cmd = killProcess? ApplicationThreadConstants.PACKAGE_REMOVED: ApplicationThreadConstants.PACKAGE_REMOVED_DONT_KILL;sendPackageBroadcastLocked(cmd,new String[] {ssp}, userId);//完全卸载if (fullUninstall) {mAppOpsService.IntExtra(Intent.EXTRA_UID, -1), ssp);// Remove all permissions granted from/to this package //撤销赋于的权限veUriPermissionsForPackage(ssp, userId,true, false);//移除recent task veRecentTasksByPackageName(ssp, userId); // force stop 对应的packagemServices.forceStopPackageLocked(ssp, userId); //卸载对应的应用PackageUninstalled(ssp); //记录卸载信息PackageUninstalled(ssp);}} else {if (killProcess) {final int extraUid = IntExtra(Intent.EXTRA_UID,-1);synchronized (mProcLock) { //杀掉对应的进程mProcessList.killPackageProcessesLSP(AppId(extraUid),userId, ProcessList.INVALID_ADJ,ApplicationExitInfo.REASON_USER_REQUESTED,ApplicationExitInfo.SUBREASON_UNKNOWN,"change " + ssp);}} //清理disable的包名cleanupDisabledPackageComponentsLocked(ssp, StringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST)); //处理所有此packagename的servicemServices.schedulePendingServiceStartLocked(ssp, userId);}}break;case Intent.ACTION_PACKAGES_SUSPENDED:case Intent.ACTION_PACKAGES_UNSUSPENDED:final boolean suspended = Intent.ACTION_PACKAGES_SUSPENDED.Action());final String[] packageNames = StringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);final int userIdExtra = IntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);PackagesSuspendedChanged(packageNames, suspended,userIdExtra);break;}break;case Intent.ACTION_PACKAGE_REPLACED:{final Uri data = Data();final String ssp;if (data != null && (ssp = SchemeSpecificPart()) != null) {ApplicationInfo aInfo = null;try {aInfo = PackageManager().getApplicationInfo(ssp, STOCK_PM_FLAGS, userId);} catch (RemoteException ignore) {}if (aInfo == null) {Slog.w(TAG, "Dropping ACTION_PACKAGE_REPLACED for non-existent pkg:"+ " ssp=" + ssp + " data=" + data);return ActivityManager.BROADCAST_SUCCESS;}updateAssociationForApp(aInfo);PackageReplaced(aInfo);mServices.updateServiceApplicationInfoLocked(aInfo);sendPackageBroadcastLocked(ApplicationThreadConstants.PACKAGE_REPLACED,new String[] {ssp}, userId);}break;}case Intent.ACTION_PACKAGE_ADDED:{// Special case for adding a package: by default turn on compatibility mode.Uri data = Data();String ssp;if (data != null && (ssp = SchemeSpecificPart()) != null) {final boolean replacing BooleanExtra(Intent.EXTRA_REPLACING, false);PackageAdded(ssp, replacing);try {ApplicationInfo ai = PackageManager().getApplicationInfo(ssp, STOCK_PM_FLAGS, 0);PackageInstalled(ssp,ai != null ? ai.longVersionCode : 0);} catch (RemoteException e) {}}break;}case Intent.ACTION_PACKAGE_DATA_CLEARED:{Uri data = Data();String ssp;if (data != null && (ssp = SchemeSpecificPart()) != null) {PackageDataCleared(ssp);}break;}case Intent.ACTION_TIMEZONE_CHANGED:// If this is the time zone changed action, queue up a message that will reset// the timezone of all currently running processes. This message will get// queued up before the broadcast happens.mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);break;case Intent.ACTION_TIME_CHANGED:// EXTRA_TIME_PREF_24_HOUR_FORMAT is optional so we must distinguish between// the tri-state value it may contain and "unknown".// For convenience we re-use the Intent extra values.final int NO_EXTRA_VALUE_FOUND = -1;final int timeFormatPreferenceMsgValue = IntExtra(Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT,NO_EXTRA_VALUE_FOUND /* defaultValue */);// Only send a message if the time preference is available.if (timeFormatPreferenceMsgValue != NO_EXTRA_VALUE_FOUND) {Message updateTimePreferenceMsg =mHandler.obtainMessage(UPDATE_TIME_PREFERENCE_MSG,timeFormatPreferenceMsgValue, 0);mHandler.sendMessage(updateTimePreferenceMsg);}CurrentTimeChanged();break;case ConnectivityManager.ACTION_CLEAR_DNS_CACHE:mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG);break;case Proxy.PROXY_CHANGE_ACTION:mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG));break;case android.hardware.Camera.ACTION_NEW_PICTURE:case android.hardware.Camera.ACTION_NEW_VIDEO:// In N we just turned these off; in O we are turing them back on partly,// only for registered receivers. This will still address the main problem// (a spam of apps waking up when a picture is taken putting significant// memory pressure on the system at a bad point), while still allowing apps// that are already actively running to know about this happening.intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);break;case android.security.KeyChain.ACTION_TRUST_STORE_CHANGED:mHandler.sendEmptyMessage(HANDLE_TRUST_STORAGE_UPDATE_MSG);break;case "com.android.launcher.action.INSTALL_SHORTCUT":// As of O, we no longer support this broadcasts, even for pre-O apps.// Apps should now be using ShortcutManager.pinRequestShortcut().Log.w(TAG, "Broadcast " + action+ " no longer supported. It will not be delivered.");return ActivityManager.BROADCAST_SUCCESS;case Intent.ACTION_PRE_BOOT_COMPLETED:timeoutExempt = true;break;case Intent.ACTION_CLOSE_SYSTEM_DIALOGS:if (!mAtmInternal.checkCanCloseSystemDialogs(callingPid, callingUid,callerPackage)) {// Returning success seems to be the pattern herereturn ActivityManager.BROADCAST_SUCCESS;}break;}if (Intent.ACTION_PACKAGE_ADDED.equals(action) ||Intent.ACTION_PACKAGE_REMOVED.equals(action) ||Intent.ACTION_PACKAGE_REPLACED.equals(action)) {final int uid = getUidFromIntent(intent);if (uid != -1) {final UidRecord uidRec = UidRecordLOSP(uid);if (uidRec != null) {uidRec.updateHasInternetPermission();}}}}// Add to the sticky list if requested.//粘性广播if (sticky) {//判断是否赋于BROADCAST_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 " + String(requiredPermissions));return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;}//粘性广播不需要指明组件if (Component() != null) {throw new SecurityException("Sticky broadcasts can't target a specific component");}// We use userId directly here, since the "all" target is maintained// as a separate set of sticky broadcasts.if (userId != UserHandle.USER_ALL) {// But first, if this is not a broadcast to all users, then// make sure it doesn't conflict with an existing broadcast to// all users.ArrayMap<String, ArrayList<Intent>> stickies = (UserHandle.USER_ALL);if (stickies != null) {ArrayList<Intent> list = (Action());if (list != null) {int N = list.size();int i;for (i=0; i<N; i++) {if (intent.(i))) {//若粘性广播在队里里面,则报冲突throw new IllegalArgumentException("Sticky broadcast " + intent + " for user "+ userId + " conflicts with existing global broadcast");}}}}}ArrayMap<String, ArrayList<Intent>> stickies = (userId);if (stickies == null) {stickies = new ArrayMap<>();mStickyBroadcasts.put(userId, stickies);}ArrayList<Intent> list = (Action());if (list == null) {list = new ArrayList<>();stickies.Action(), list);}final int stickiesCount = list.size();int i;for (i = 0; i < stickiesCount; i++) {if (intent.(i))) {//若在userId中的队列,出现重复,则替换// 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 = StartedUserArray();} else {// Caller wants broadcast to go to one specific user.users = new int[] {userId};}// Figure out who all will receive this broadcast.//寻找所有接收广播的接收者List receivers = null;List<BroadcastFilter> registeredReceivers = null;// Need to resolve the intent to if ((Flags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)== 0) {//在PMS中去查询对应的广播接收者,获取静态广播接受者的列表receivers = collectReceiverComponents(intent, resolvedType, callingUid, users, broadcastAllowList);}if (Component() == null) {//若不指定广播接收者.则会遍历所有符合条件的接收者if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {// Query one target user at a time, excluding shell-restricted usersfor (int i = 0; i < users.length; i++) {if (mUserController.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {continue;}//查看动态广播接收者List<BroadcastFilter> registeredReceiversForUser =mReceiverResolver.queryIntent(intent,resolvedType, false /*defaultOnly*/, users[i]);if (registeredReceivers == null) {registeredReceivers = registeredReceiversForUser;} else if (registeredReceiversForUser != null) {registeredReceivers.addAll(registeredReceiversForUser);}}} else {//查看动态广播接收者registeredReceivers = mReceiverResolver.queryIntent(intent,resolvedType, false /*defaultOnly*/, userId);}}//支持替换旧的广播final boolean replacePending =(Flags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing broadcast: " + Action()+ " replacePending=" + replacePending);if (registeredReceivers != null && broadcastAllowList != null) {// if a uid whitelist was provided, remove anything in the application space that wasn't// in it.for (int i = registeredReceivers.size() - 1; i >= 0; i--) {final int owningAppId = (i).owningUid);if (owningAppId >= Process.FIRST_APPLICATION_UID&& Arrays.binarySearch(broadcastAllowList, owningAppId) < 0) {ve(i);}}}int NR = registeredReceivers != null ? registeredReceivers.size() : 0;if (!ordered && NR > 0) {// If we are not serializing this broadcast, then send the// registered receivers separately so they don't wait for the// components to be launched.//针对非有序广播,进行并发发送广播.if (isCallerSystem) {//对应system的调用者进行验证checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,isProtectedBroadcast, registeredReceivers);}final BroadcastQueue queue = broadcastQueueForIntent(intent);BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,registeredReceivers, resultTo, resultCode, resultData, resultExtras, ordered,sticky, false, userId, allowBackgroundActivityStarts,backgroundActivityStartsToken, timeoutExempt);if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);final boolean replaced = replacePending&& (placeParallelBroadcastLocked(r) != null);// Note: We assume resultTo is null for non-ordered broadcasts.if (!replaced) {//若不进行旧的广播替换,则开始加入队列进行并行分发.queueParallelBroadcastLocked(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.//过滤ACTION_PACKAGE_ADDED , ACTION_PACKAGE_RESTARTED 和ACTION_PACKAGE_DATA_CLEARED 对应包名String skipPackages[] = null;if (Intent.ACTION_PACKAGE_ADDED.Action())|| Intent.ACTION_PACKAGE_RESTARTED.Action())|| Intent.ACTION_PACKAGE_DATA_CLEARED.Action())) {Uri data = Data();if (data != null) {String pkgName = SchemeSpecificPart();if (pkgName != null) {skipPackages = new String[] { pkgName };}}} else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.Action())) {skipPackages = StringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);}if (skipPackages != null && (skipPackages.length > 0)) {for (String skipPackage : skipPackages) {if (skipPackage != null) {int NT = receivers.size();for (int it=0; it<NT; it++) {ResolveInfo curt = ((it);if (curt.activityInfo.packageName.equals(skipPackage)) {ve(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 = ((it);}if (curr == null) {//其次在动态广播中获取curr = (ir);}if (Priority() >= curt.priority) {//同样的优先级,动态广播优先于静态广播// Insert this broadcast record into the ivers.add(it, curr);ir++;curr = null;it++;NT++;} else {// Skip to the next ResolveInfo in the final list.it++;curt = null;}}}//将所有的动态广播插入final receivers 中while (ir < NR) {if (receivers == null) {receivers = new ArrayList();}receivers.(ir));ir++;}if (isCallerSystem) {checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,isProtectedBroadcast, receivers);}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, excludedPermissions, excludedPackages, appOp, brOptions,receivers, resultTo, resultCode, resultData, resultExtras,ordered, sticky, false, userId, allowBackgroundActivityStarts,backgroundActivityStartsToken, timeoutExempt);if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r);final BroadcastRecord oldRecord =replacePending ? placeOrderedBroadcastLocked(r) : null;if (oldRecord != null) {// Replaced, fire the result-to receiver.if (sultTo != null) {final BroadcastQueue oldQueue = broadcastQueueForIntent(oldRecord.intent);try {//若替代的广播,则更新old的队列oldQueue.performReceiveLocked(oldRecord.callerApp, sultTo,oldRecord.intent,Activity.RESULT_CANCELED, null, null,false, false, oldRecord.userId);} catch (RemoteException e) {Slog.w(TAG, "Failure ["+ queue.mQueueName + "] sending broadcast result of "+ intent, e);}}} else {//分发有序广播queueOrderedBroadcastLocked(r);queue.scheduleBroadcastsLocked();}} else {// There was nobody interested in the broadcast, but we still want to record// that it happened.if (Component() == null && Package() == null&& (Flags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {// This was an let's record it for posterity.Action(), callerPackage, 0, 0, 0);}}return ActivityManager.BROADCAST_SUCCESS;}
小结:
(1) 对粘性广播的处理过程。把粘性广播放在了list列表中,而list以action为键放置在了stickies中,而stickies又以userId为键放在了mStickyBroadcasts中,因此mStickyBroadcasts保存了设备中所有用户粘性广播的Intent相关信息。
(2)静态和动态注册的接收器
[1] 上面这段代码主要是获取静态和动态注册的接收器。其中receivers 表示静态注册接收器列表, registeredReceivers 表示动态注册接收器列表;
[2] Intent.FLAG_RECEIVER_REGISTERED_ONLY该flag表示仅支持动态注册,不支持静态注册,如果在manifest中注册是收不到该广播的;
[3] 如果发送广播不加Component信息会遍历获取所有的当前intent的接收者,因此如果定向发给某个应用的话,要把Component信息加上。
(3) 无序动态注册接收器添加到并发列表中
[1] 上面这段代码是,如果发送的是无序广播,且存在动态注册的广播接收者,就将该广播加入并行处理队列,并进行一次广播发送。简单来说就是【动态注册且接受无序广播的广播接收者】是并行操作,广播发送速度会比较快。
[2] Intent.FLAG_RECEIVER_REPLACE_PENDING 该flag表示是否替换待发出的广播,如果flag为1会进行替换, 位置与待发广播一样。
(4)合并有序动态注册和静态注册接收器
[1] 上面这段代码主要是对【动态注册接受有序广播的广播接收者】和【静态注册的广播接收者】进行合并,如果是有序广播,动态接收者和静态的接收者合并到一个队列里面进行处理,也就是说order广播下,所有的接收者(静态和动态)处理方式都是一样的,都是串行处理;
[2] 对于静态注册的接收者而言,始终是和order广播的处理方式是一样的,也就是说静态的接收者只有order模式(串行化接收);
[3] 在合并过程中,如果一个动态注册的广播接收者和一个静态注册的目标广播接收者的优先级相同,那么动态注册的目标接收者会排在静态注册的目标广播接收者前面,即动态注册的目标广播接收者会优先于静态注册的广播接收者接收到有序广播。
(5)系统广播处理broadcastIntentLocked函数这部分代码逻辑总结:首先是判断是不是系统广播,也就是switch语句中的部分,这部分的广播是系统发出的,根据不同广播做出不同的处理,系统广播我们可以接收但是不能发送,只能由系统发出; 接着是粘性广播的处理; 然后是【动态注册且接受无序广播的广播接收者】的处理,把他们放入到BroadcastQueue的mParallelBroadcasts中,并调用scheduleBroadcastsLocked,BroadcastQueue对mParallelBroadcasts列表中条目的最终处理是通过并行操作来完成的; 最后是【动态注册接受有序广播的广播接收者】和【静态注册的广播接收者】的处理,把他们放入到BroadcastQueue的mOrderedBroadcasts中,并调用scheduleBroadcastsLocked,BroadcastQueue对mOrderedBroadcasts列表中条目的最终处理是通过串行操作来完成的;
frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java
/*** Lists of all active broadcasts that are to be executed immediately* (without waiting for another broadcast to finish). Currently this only* contains broadcasts to registered receivers, to avoid spinning up* a bunch of processes to execute IntentReceiver components. Background-* and foreground-priority broadcasts are queued separately.*/final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>();/*** Tracking of the ordered broadcast queue, including deferral policy and alarm* prioritization.*/final BroadcastDispatcher mDispatcher;
在广播队列中定义了两个处理列表,一个是并发处理列表mParallelBroadcasts,一个是有序处理列表mDispatcher。
BroadcastQueue broadcastQueueForIntent(Intent intent) {if (Flags())) {if (DEBUG_BROADCAST_BACKGROUND) {Slog.i(TAG_BROADCAST,"Broadcast intent " + intent + " on offload queue");}return mOffloadBroadcastQueue;}final boolean isFg = (Flags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;if (DEBUG_BROADCAST_BACKGROUND) Slog.i(TAG_BROADCAST,"Broadcast intent " + intent + " on "+ (isFg ? "foreground" : "background") + " queue");return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue;}public void enqueueParallelBroadcastLocked(BroadcastRecord r) {mParallelBroadcasts.add(r);enqueueBroadcastHelper(r);}public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {queueOrderedBroadcastLocked(r);enqueueBroadcastHelper(r);}
上面的三个方法是上面源码中出现的,broadcastQueueForIntent根据intent是否含有Intent.FLAG_RECEIVER_FOREGROUND来判断是前台广播还是普通后台广播,如果是前台广播返回前台广播处队列。如果是普通后台广播返回后台广播处理队列。
获取队列后,将发给【动态注册且接受无序广播的广播接收者】的广播通过enqueueParallelBroadcastLocked函数添加到该队列的并发处理列表中。将发给【动态注册接受有序广播的广播接收者】和【静态注册的广播接收者】的广播通过enqueueOrderedBroadcastLocked函数添加到该队列的有序处理列表中。
从上面的源码分析中看到最后我们都执行了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);}@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case BROADCAST_INTENT_MSG: {if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Received BROADCAST_INTENT_MSG ["+ mQueueName + "]");//开始处理广播processNextBroadcast(true);} break;case BROADCAST_TIMEOUT_MSG: {synchronized (mService) {broadcastTimeoutLocked(true);}} break;}}}
先判断mBroadcastsScheduled的值,如果true说明消息队列已经存在一个类型为BROADCAST_INTENT_MSG的消息了,直接返回,因为该消息在执行完毕会自动调用下一条消息;
接下来广播的处理逻辑会走到 processNextBroadcast函数中,下面来看下该函数的逻辑。
private void processNextBroadcast(boolean fromMsg) {synchronized (mService) {processNextBroadcastLocked(fromMsg, false);}}
详细分析 processNextBroadcastLocked 函数:
final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {BroadcastRecord r;if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "processNextBroadcast ["+ mQueueName + "]: "+ mParallelBroadcasts.size() + " parallel broadcasts; "+ mDispatcher.describeStateLocked());//更新CPU统计信息mService.updateCpuStats();if (fromMsg) {//来自于BROADCAST_INTENT_MSG, 说明广播已经在处理,可以将此变量标记为falsemBroadcastsScheduled = false;}// First, deliver any non-serialized broadcasts right away.// 无序广播之间不存在相互等待,这里处理的是保存在无序广播调度队列mParallelBroadcasts中的广播发送任务,// 即把保存在无序广播调度队列mParallelBroadcasts中的广播发送给它的目标广播接收者处理while (mParallelBroadcasts.size() > 0) {r = ve(0);r.dispatchTime = SystemClock.uptimeMillis();r.dispatchClockTime = System.currentTimeMillis();if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),System.identityHashCode(r));Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),System.identityHashCode(r));}final int N = r.receivers.size();if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["+ mQueueName + "] " + r);for (int i=0; i<N; i++) {Object target = (i);if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,"Delivering non-ordered on [" + mQueueName + "] to registered "+ target + ": " + r);//通过deliverToRegisteredReceiverLocked调用ActivityThread.scheduleRegisteredReceiver处理广播deliverToRegisteredReceiverLocked(r,(BroadcastFilter) target, false, i);}//记录在历史列表中.addBroadcastToHistoryLocked(r);if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["+ mQueueName + "] " + r);}// Now take care of the next // 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;//等待Broadcast有对应的pidif (Pid() > 0) {synchronized (mService.mPidsSelfLocked) {ProcessRecord proc = (Pid());//等待广播接收者,是否存在或者已经发生了crashisDead = proc == null || proc.mErrorState.isCrashing();}} else {//若没有获取到当前等待广播的pid,则通过进程名称进行搜索.final ProcessRecord proc = ProcessNamesLOSP().get(mPendingBroadcast.curApp.processName, mPendingBroadcast.curApp.uid);//判断接收者是否还存在isDead = proc == null || !proc.isPendingStart();}if (!isDead) {// It's still alive, so keep waiting//若接收者存在,则继续保持. 如果应用已经启动,会调用AMS的函数来处理静态广播,这里直接returnreturn;} else {Slog.w(TAG, "pending app ["+ mQueueName + "]" + mPendingBroadcast.curApp+ " died before responding to broadcast");//若不存在,则记录为idle状态mPendingBroadcast.state = BroadcastRecord.Receiver = mPendingBroadcastRecvIndex;mPendingBroadcast = null;}}boolean looped = false;do {final long now = SystemClock.uptimeMillis();//获取当前时间的BroadcastRecordr = NextBroadcastLocked(now);if (r == null) {// No more broadcasts are deliverable right now, so all done!//没有获取到BroadcastRecord, 说明已经处理完成.//安排延迟广播检查mDispatcher.scheduleDeferralCheckLocked(false);synchronized (mService.mAppProfiler.mProfilerLock) {//触发GCmService.mAppProfiler.scheduleAppGcsLPf();}if (looped && !skipOomAdj) {// If we had finished the last ordered broadcast, then// make sure all processes have correct oom and sched// adjustments.//更新ADJmService.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);}// when we have no more ordered broadcast on this queue, stop logging//因为已经处理完成广播,停止日志记录. if (mService.mUserController.mBootCompleted && mLogLatencyMetrics) {mLogLatencyMetrics = false;}return;}boolean forceReceive = false;// Ensure that even if something goes awry with the timeout// detection, we catch "hung" broadcasts here, discard them,// and continue to make progress.//// This is only done if the system is ready so that early-stage receivers// don't get executed with timeouts; and of course other timeout-// exempt broadcasts are ignored.int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;if (mService.mProcessesReady && !r.timeoutExempt && r.dispatchTime > 0) {//超时广播强制执行if ((numReceivers > 0) &&(now > r.dispatchTime + (2 * mConstants.TIMEOUT * numReceivers)) &&/// M: ANR Debug Mechanism!mService.mAnrManager.isAnrDeferrable()) {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(false); // forcibly finish this broadcast // 重置参数,继续处理有序广播调度队列mOrderedBroadcasts的下一个广播转发任务forceReceive = true;r.state = BroadcastRecord.IDLE;}}if (r.state != BroadcastRecord.IDLE) {//广播不处于IDLE 状态,则直接返回.if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST,"processNextBroadcast("+ mQueueName + ") called when not idle (state="+ r.state + ")");return;}// Is the current broadcast is done for any reason?if (r.receivers == null || r.nextReceiver >= numReceivers|| r.resultAbort || forceReceive) {// Send the final result if requestedif (r.resultTo != null) {boolean sendResult = true;// if this was part of a split/deferral complex, update the refcount and only// send the completion when we clear all of themif (r.splitToken != 0) {int newCount = (r.splitToken) - 1;if (newCount == 0) {// done! clear out this record's bookkeeping and deliverif (DEBUG_BROADCAST_DEFERRAL) {Slog.i(TAG_BROADCAST,"Sending broadcast completion for split token "+ r.splitToken + " : " + Action());}mSplitRefcounts.delete(r.splitToken);} else {// still have some split broadcast records in flight; update refcount// and hold off on the callbackif (DEBUG_BROADCAST_DEFERRAL) {Slog.i(TAG_BROADCAST,"Result refcount now " + newCount + " for split token "+ r.splitToken + " : " + Action()+ " - not sending completion yet");}sendResult = false;mSplitRefcounts.put(r.splitToken, newCount);}}if (sendResult) {if (r.callerApp != null) {mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(r.callerApp);}try {if (DEBUG_BROADCAST) {Slog.i(TAG_BROADCAST, "Finishing broadcast [" + mQueueName + "] "+ Action() + " app=" + r.callerApp);}performReceiveLocked(r.callerApp, r.resultTo,new Intent(r.intent), r.sultData, r.resultExtras, false, false, r.userId);// Set this to null so that the reference// (local and remote) isn't kept in sultTo = 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 //添加在历史记录里面addBroadcastToHistoryLocked(r);if (Component() == null && Package() == null&& (Flags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {// This was an let's record it for posterity.mService.addBroadcastStatLocked(Action(), r.callerPackage,r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime);}ireBroadcastLocked(r);r = null;looped = true;continue;}// Check whether the next receiver is under deferral policy, and handle that// accordingly. If the current broadcast was already part of deferred-delivery// tracking, we know that it must now be deliverable as-is without re-deferral.if (!r.deferred) {final int receiverUid = r.(r.nextReceiver));if (mDispatcher.isDeferringLocked(receiverUid)) {if (DEBUG_BROADCAST_DEFERRAL) {Slog.i(TAG_BROADCAST, "Next receiver in " + r + " uid " + receiverUid+ " at " + r.nextReceiver + " is under deferral");}// If this is the only (remaining) receiver in the broadcast, "splitting"// doesn't make sense -- just defer it as-is and retire it as the// currently active outgoing broadcast.BroadcastRecord defer;if (r.nextReceiver + 1 == numReceivers) {if (DEBUG_BROADCAST_DEFERRAL) {Slog.i(TAG_BROADCAST, "Sole receiver of " + r+ " is under deferral; setting aside and proceeding");}defer = ireBroadcastLocked(r);} else {// Nontrivial case; split out 'uid's receivers to a new broadcast record// and defer that, then loop and pick up continuing delivery of the current// record (now absent those receivers).// The split operation is guaranteed to match at least at 'nextReceiver'defer = r.splitRecipientsLocked(receiverUid, r.nextReceiver);if (DEBUG_BROADCAST_DEFERRAL) {Slog.i(TAG_BROADCAST, "Post split:");Slog.i(TAG_BROADCAST, "Original broadcast receivers:");for (int i = 0; i < r.receivers.size(); i++) {Slog.i(TAG_BROADCAST, " " + (i));}Slog.i(TAG_BROADCAST, "Split receivers:");for (int i = 0; i < ivers.size(); i++) {Slog.i(TAG_BROADCAST, " " + (i));}}// Track completion refcount as well if relevantif (r.resultTo != null) {int token = r.splitToken;if (token == 0) {// first split of this record; refcount for 'r' and 'deferred'r.splitToken = defer.splitToken = nextSplitTokenLocked();mSplitRefcounts.put(r.splitToken, 2);if (DEBUG_BROADCAST_DEFERRAL) {Slog.i(TAG_BROADCAST,"Broadcast needs split refcount; using new token "+ r.splitToken);}} else {// new split from an already-refcounted situation; increment countfinal int curCount = (token);if (DEBUG_BROADCAST_DEFERRAL) {if (curCount == 0) {Slog.wtf(TAG_BROADCAST,"Split refcount is zero with token for " + r);}}mSplitRefcounts.put(token, curCount + 1);if (DEBUG_BROADCAST_DEFERRAL) {Slog.i(TAG_BROADCAST, "New split count for token " + token+ " is " + (curCount + 1));}}}}mDispatcher.addDeferredBroadcast(receiverUid, defer);r = null;looped = true;continue;}}} while (r == null);// Get the //获取下一个将要处理的广播接收者在其列表中的位置int recIdx = r.nextReceiver++;// Keep track of when this receiver started, and make sure there// is a timeout message pending to kill it if need be.//记录receiver 时间r.receiverTime = SystemClock.uptimeMillis();if (recIdx == 0) {//记录分发时间戳,便于判断超时r.dispatchTime = r.receiverTime;r.dispatchClockTime = System.currentTimeMillis();if (mLogLatencyMetrics) {FrameworkStatsLog.write(FrameworkStatsLog.BROADCAST_DISPATCH_LATENCY_REPORTED,r.dispatchClockTime - r.enqueueClockTime);}if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {Trace.asyncTraceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER,createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_PENDING),System.identityHashCode(r));Trace.asyncTraceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,createBroadcastTraceTitle(r, BroadcastRecord.DELIVERY_DELIVERED),System.identityHashCode(r));}if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing ordered broadcast ["+ mQueueName + "] " + r);}if (! mPendingBroadcastTimeoutMessage) {long timeoutTime = r.receiverTime + mConstants.TIMEOUT;if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,"Submitting BROADCAST_TIMEOUT_MSG ["+ mQueueName + "] for " + r + " at " + timeoutTime);//设置ANR的超时时间. 在这里可以为某个应用定制ANR 时间.setBroadcastTimeoutLocked(timeoutTime);}final BroadcastOptions brOptions = r.options;final Object nextReceiver = (recIdx);// 如果当前nextReceiver是一个BroadcastFilter类型,说明是一个动态注册接收者,不需要启动一个进程if (nextReceiver instanceof BroadcastFilter) {// Simple case: this is a registered receiver who gets// a direct call.BroadcastFilter filter = (BroadcastFilter)nextReceiver;if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,"Delivering ordered ["+ mQueueName + "] to registered "+ filter + ": " + r);// 调用deliverToRegisteredReceiverLocked向所有的receivers发送广播// 将它所描述的每一个无序广播发送给每一个广播接收者,异步处理广播// 通过deliverToRegisteredReceiverLocked调用deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);if (r.receiver == null || !r.ordered) {// The receiver has already finished, so schedule to// process the next one.if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing ["+ mQueueName + "]: ordered="+ r.ordered + " receiver=" + r.receiver);r.state = BroadcastRecord.IDLE;scheduleBroadcastsLocked();} else {if (iverList != null) {iverList.app, r);// r is guaranteed ordered at this point, so we know finishReceiverLocked()// will get a callback and handle the activity start token lifecycle.}}return;}// Hard case: need to instantiate the receiver, possibly// starting its application process to host it.// 如果上面if没有进行拦截,说明不是广播接收者动态注册的,而应该是静态注册的// 此时进程可能没有启动ResolveInfo info =(ResolveInfo)nextReceiver;ComponentName component = new ComponentName(info.activityInfo.applicationInfo.packageName,info.activityInfo.name);boolean skip = false;if (brOptions != null &&(info.activityInfo.applicationInfo.targetSdkVersion< MinManifestReceiverApiLevel() ||info.activityInfo.applicationInfo.targetSdkVersion> MaxManifestReceiverApiLevel())) {//不符合要求直接跳过Slog.w(TAG, "Target SDK mismatch: receiver " + info.activityInfo+ " targets " + info.activityInfo.applicationInfo.targetSdkVersion+ " but delivery restricted to ["+ MinManifestReceiverApiLevel() + ", "+ MaxManifestReceiverApiLevel()+ "] broadcasting " + broadcastDescription(r, component));skip = true;}if (!skip && !mService.validateAssociationAllowedLocked(r.callerPackage, r.PackageName(), info.activityInfo.applicationInfo.uid)) {Slog.w(TAG, "Association not allowed: broadcasting "+ broadcastDescription(r, component));skip = true;}if (!skip) {skip = !mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,r.callingPid, r.resolvedType, info.activityInfo.applicationInfo.uid);if (skip) {Slog.w(TAG, "Firewall blocked: broadcasting "+ broadcastDescription(r, component));}}int perm = mService.checkComponentPermission(info.activityInfo.permission,r.callingPid, r.callingUid, info.activityInfo.applicationInfo.uid,ported);if (!skip && perm != PackageManager.PERMISSION_GRANTED) {if (!ported) {Slog.w(TAG, "Permission Denial: broadcasting "+ broadcastDescription(r, component)+ " is not exported from uid " + info.activityInfo.applicationInfo.uid);} else {Slog.w(TAG, "Permission Denial: broadcasting "+ broadcastDescription(r, component)+ " requires " + info.activityInfo.permission);}skip = true;} else if (!skip && info.activityInfo.permission != null) {final int opCode = AppOpsManager.permissionToOpCode(info.activityInfo.permission);if (opCode != AppOpsManager.OP_NONE && AppOpsManager().noteOpNoThrow(opCode,r.callingUid, r.callerPackage, r.callerFeatureId,"Broadcast delivered to " + info.activityInfo.name)!= AppOpsManager.MODE_ALLOWED) {Slog.w(TAG, "Appop Denial: broadcasting "+ broadcastDescription(r, component)+ " requires appop " + AppOpsManager.permissionToOp(info.activityInfo.permission));skip = true;}}boolean isSingleton = false;try {isSingleton = mService.isSingleton(info.activityInfo.processName,info.activityInfo.applicationInfo,info.activityInfo.name, info.activityInfo.flags);} catch (SecurityException e) {Slog.w(TAG, e.getMessage());skip = true;}if ((info.activityInfo.flags&ActivityInfo.FLAG_SINGLE_USER) != 0) {if (ActivityManager.checkUidPermission(android.Manifest.permission.INTERACT_ACROSS_USERS,info.activityInfo.applicationInfo.uid)!= PackageManager.PERMISSION_GRANTED) {Slog.w(TAG, "Permission Denial: Receiver " + component.flattenToShortString()+ " requests FLAG_SINGLE_USER, but app does not hold "+ android.Manifest.permission.INTERACT_ACROSS_USERS);skip = true;}}if (!skip && info.activityInfo.applicationInfo.isInstantApp()&& r.callingUid != info.activityInfo.applicationInfo.uid) {Slog.w(TAG, "Instant App Denial: receiving "+ r.intent+ " to " + component.flattenToShortString()+ " due to sender " + r.callerPackage+ " (uid " + r.callingUid + ")"+ " Instant Apps do not support manifest receivers");skip = true;}if (!skip && r.callerInstantApp&& (info.activityInfo.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) == 0&& r.callingUid != info.activityInfo.applicationInfo.uid) {Slog.w(TAG, "Instant App Denial: receiving "+ r.intent+ " to " + component.flattenToShortString()+ " requires receiver have visibleToInstantApps set"+ " due to sender " + r.callerPackage+ " (uid " + r.callingUid + ")");skip = true;}if (r.curApp != null && r.curApp.mErrorState.isCrashing()) {// If the target process is crashing, just skip it.Slog.w(TAG, "Skipping deliver ordered [" + mQueueName + "] " + r+ " to " + r.curApp + ": process crashing");skip = true;}if (!skip) {boolean isAvailable = false;try {isAvailable = PackageManager().isPackageAvailable(info.activityInfo.UserId(info.activityInfo.applicationInfo.uid));} catch (Exception e) {// all such failures mean we skip this receiverSlog.w(TAG, "Exception getting recipient info for "+ info.activityInfo.packageName, e);}if (!isAvailable) {Slog.w(TAG_BROADCAST,"Skipping delivery to " + info.activityInfo.packageName + " / "+ info.activityInfo.applicationInfo.uid+ " : package no longer available");skip = true;}}// If permissions need a review before any of the app components can run, we drop// the broadcast and if the calling app is in the foreground and the broadcast is// explicit we launch the review UI passing it a pending intent to send the skipped// broadcast.if (!skip) {if (!requestStartTargetPermissionsReviewIfNeededLocked(r,info.activityInfo.packageName, UserId(info.activityInfo.applicationInfo.uid))) {Slog.w(TAG_BROADCAST,"Skipping delivery: permission review required for "+ broadcastDescription(r, component));skip = true;}}// This is safe to do even if we are skipping the broadcast, and we need// this information now to evaluate whether it is going to be allowed to run.final int receiverUid = info.activityInfo.applicationInfo.uid;// If it's a singleton, it needs to be the same app or a special appif (r.callingUid != Process.SYSTEM_UID && isSingleton&& mService.isValidSingletonCall(r.callingUid, receiverUid)) {info.activityInfo = ActivityInfoForUser(info.activityInfo, 0);}// 得到ResolveInfo对象info所描述的广播接收者的android:process属性值,// 即它需要运行在的应用程序进程的名称,并且保存在变量targetProcess中String targetProcess = info.activityInfo.processName;// 获取当前广播接收者的进程记录,也就是该静态广播接收者是否已经运行ProcessRecord app = ProcessRecordLocked(targetProcess,info.activityInfo.applicationInfo.uid);if (!skip) {final int allowed = AppStartModeLOSP(info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false, false);if (allowed != ActivityManager.APP_START_MODE_NORMAL) {// We won't allow this receiver to be launched if the app has been// completely disabled from launches, or it was not explicitly sent// to it and the app is in a state that should not receive it// (depending on how getAppStartModeLOSP has determined that).if (allowed == ActivityManager.APP_START_MODE_DISABLED) {Slog.w(TAG, "Background execution disabled: receiving "+ r.intent + " to "+ component.flattenToShortString());skip = true;} else if (((Flags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0)|| (Component() == null&& Package() == null&& ((Flags()& Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0)&& !quiredPermissions))) {mService.addBackgroundCheckViolationLocked(Action(),PackageName());Slog.w(TAG, "Background execution not allowed: receiving "+ r.intent + " to "+ component.flattenToShortString());skip = true;}}}if (!skip && !Intent.ACTION_SHUTDOWN.equals(Action())&& !mService.mUserController.UserId(info.activityInfo.applicationInfo.uid),0 /* flags */)) {skip = true;Slog.w(TAG,"Skipping delivery to " + info.activityInfo.packageName + " / "+ info.activityInfo.applicationInfo.uid + " : user is not running");}/// M: DuraSpeed @{boolean isSuppress = false;isSuppress = BeforeStartProcessForStaticReceiver(info.activityInfo.packageName);if (isSuppress) {//快霸进行定制Slog.d(TAG, "processNextBroadcastLocked, suppress to start process of staticReceiver"+ " for package:" + info.activityInfo.packageName);skip = true;}/// @}if (!skip && r.excludedPermissions != null && r.excludedPermissions.length > 0) {for (int i = 0; i < r.excludedPermissions.length; i++) {String excludedPermission = r.excludedPermissions[i];try {perm = PackageManager().checkPermission(excludedPermission,info.activityInfo.applicationInfo.UserId(info.activityInfo.applicationInfo.uid));} catch (RemoteException e) {perm = PackageManager.PERMISSION_DENIED;}int appOp = AppOpsManager.permissionToOpCode(excludedPermission);if (appOp != AppOpsManager.OP_NONE) {// When there is an app op associated with the permission,// skip when both the permission and the app op are// granted.if ((perm == PackageManager.PERMISSION_GRANTED) && (AppOpsManager().checkOpNoThrow(appOp,info.activityInfo.applicationInfo.uid,info.activityInfo.packageName)== AppOpsManager.MODE_ALLOWED)) {skip = true;break;}} else {// When there is no app op associated with the permission,// skip when permission is granted.if (perm == PackageManager.PERMISSION_GRANTED) {skip = true;break;}}}}// Check that the receiver does *not* belong to any of the excluded packagesif (!skip && r.excludedPackages != null && r.excludedPackages.length > 0) {if (ludedPackages, PackageName())) {Slog.w(TAG, "Skipping delivery of excluded package "+ r.intent + " to "+ component.flattenToShortString()+ " excludes package " + PackageName()+ " due to sender " + r.callerPackage+ " (uid " + r.callingUid + ")");skip = true;}}if (!skip && info.activityInfo.applicationInfo.uid != Process.SYSTEM_UID &&quiredPermissions != null && r.requiredPermissions.length > 0) {for (int i = 0; i < r.requiredPermissions.length; i++) {String requiredPermission = r.requiredPermissions[i];try {perm = PackageManager().checkPermission(requiredPermission,info.activityInfo.applicationInfo.UserId(info.activityInfo.applicationInfo.uid));} catch (RemoteException e) {perm = PackageManager.PERMISSION_DENIED;}if (perm != PackageManager.PERMISSION_GRANTED) {Slog.w(TAG, "Permission Denial: receiving "+ r.intent + " to "+ component.flattenToShortString()+ " requires " + requiredPermission+ " due to sender " + r.callerPackage+ " (uid " + r.callingUid + ")");skip = true;break;}int appOp = AppOpsManager.permissionToOpCode(requiredPermission);if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp) {if (!noteOpForManifestReceiver(appOp, r, info, component)) {skip = true;break;}}}}if (!skip && r.appOp != AppOpsManager.OP_NONE) {if (!noteOpForManifestReceiver(r.appOp, r, info, component)) {skip = true;}}if (skip) {if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,"Skipping delivery of ordered [" + mQueueName + "] "+ r + " for reason described above");r.delivery[recIdx] = BroadcastRecord.DELIVERY_iver = null;r.curFilter = null;r.state = BroadcastRecord.IDLE;r.manifestSkipCount++;scheduleBroadcastsLocked();return;}r.manifestCount++;r.delivery[recIdx] = BroadcastRecord.DELIVERY_DELIVERED;r.state = BroadcastRecord.APP_RECEIVE;r.curComponent = component;r.curReceiver = info.activityInfo;if (DEBUG_MU && r.callingUid > UserHandle.PER_USER_RANGE) {Slog.v(TAG_MU, "Updated broadcast record activity info for secondary user, "+ info.activityInfo + ", callingUid = " + r.callingUid + ", uid = "+ receiverUid);}final boolean isActivityCapable =(brOptions != null && TemporaryAppAllowlistDuration() > 0);//临时白名单maybeScheduleTempAllowlistLocked(receiverUid, r, brOptions);// Report that a component is used for explicit broadcasts.if (Component() != null && r.curComponent != null&& !TextUtils.equals(PackageName(), r.callerPackage)) {//记录显式广播portEvent(PackageName(), r.userId, Event.APP_COMPONENT_USED);}// Broadcast is being executed, its package can't {//广播被接收,不能将接收者设置为stop 状态.PackageManager().setPackageStoppedState(PackageName(), false, r.userId);} catch (RemoteException e) {} catch (IllegalArgumentException e) {Slog.w(TAG, "Failed trying to unstop package "+ PackageName() + ": " + e);}// Is this receiver's application already running?//判断当前接收者的应用是否在运行.if (app != null && Thread() != null && !app.isKilled()) {try {app.addPackage(info.activityInfo.packageName,info.activityInfo.applicationInfo.longVersionCode, mService.mProcessStats);maybeAddAllowBackgroundActivityStartsToken(app, r);//处理当前广播// app进程存在,通过processCurBroadcastLocked -> ActivityThread.scheduleReceiver -> Receive处理当前广播 processCurBroadcastLocked(r, app);//若进程还是一直活着,当前接收者处理完成,直接结束// 静态广播是order广播是一种同步处理方式,因此处理完可以直接returnreturn;} catch (RemoteException e) {Slog.w(TAG, "Exception when sending broadcast to "+ r.curComponent, e);} catch (RuntimeException e) {Slog.wtf(TAG, "Failed sending broadcast to "+ r.curComponent + " with " + r.intent, e);// If some unexpected exception happened, just skip// this broadcast. At this point we are not in the call// from a client, so throwing an exception out from here// will crash the entire system instead of just whoever// sent the broadcast.logBroadcastReceiverDiscardLocked(r);finishReceiverLocked(r, r.resultCode, r.sultExtras, r.resultAbort, false);scheduleBroadcastsLocked();// We need to reset the state if we failed to start state = BroadcastRecord.IDLE;return;}// If a dead object exception was thrown -- fall through to// restart the application.}// Not running -- get it started, to be executed when the app comes up.if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,"Need to start app ["+ mQueueName + "] " + targetProcess + " for broadcast " + r);//当前接收者应用没有存活,则直接启动它.r.curApp = mService.startProcessLocked(targetProcess,info.activityInfo.applicationInfo, true,Flags() | Intent.FLAG_FROM_BACKGROUND,new HostingRecord("broadcast", r.curComponent), isActivityCapable? ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE : ZYGOTE_POLICY_FLAG_EMPTY,(Flags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false);//启动应用失败.if (r.curApp == null) {// Ah, this recipient is unavailable. Finish it if necessary,// and mark the broadcast record as ready for the next.//若启动失败,则丢失信息,并记录.Slog.w(TAG, "Unable to launch app "+ info.activityInfo.applicationInfo.packageName + "/"+ receiverUid + " for broadcast "+ r.intent + ": process is bad");logBroadcastReceiverDiscardLocked(r);finishReceiverLocked(r, r.resultCode, r.sultExtras, r.resultAbort, false);scheduleBroadcastsLocked();r.state = BroadcastRecord.IDLE;return;}// 将BroadcastRecord赋值为mPendingBroadcast,等待应用启动完成后处理// 正在启动接收者进程,将正在启动的BroadcastRecord记录存储到mPendingBroadcast中,同时将当前正在// 启动的接收者进程在所有接收者中的索引存储到mPendingBroadcastRecvIndex,如果当前广播接收者处理// 完,需要继续从mPendingBroadcastRecvIndex计算到下一个接收者发送当前广播maybeAddAllowBackgroundActivityStartsToken(r.curApp, r);mPendingBroadcast = r;mPendingBroadcastRecvIndex = recIdx;}
(1)上面这段代码逻辑:对并行处理列表中的广播调用deliverToRegisteredReceiverLocked
将每一个无序广播发送给每一个广播接收者,异步处理广播。注意入参ordered
值为false
。
(2)上面这段代码是在处理广播前对一些特殊情况进行处理,例如,处理列表为空,直接返回;当前广播正在处理中返回;下一个接收者为空或者当前接受者设置了resultAbort
等异常情况处理。
(3)上面代码开始对广播进行处理,先进行了计时操作,然后根据接收者不同,先对动态注册接收器进行处理(BroadcastFilter类型)。逻辑最后通过deliverToRegisteredReceiverLocked调用ActivityThread.scheduleRegisteredReceiver处理广播。上面有分析这个函数,此时入参ordered是true,用来执行动态注册的广播接收者的发送接收过程。
上面代码是对静态广播的处理,静态广播又分为两种,静态接收者所在进程是启动状态,静态接收者所在进程是未启动状态。根据所在进程的启动状态分别来进行处理。
app进程存在,通过processCurBroadcastLocked -> ActivityThread.scheduleReceiver -> Receive处理当前广播。
app进程不存在,会先创建该进程。
APP存在,调用BroadcastQueue的processCurBroadcastLocked方法处理有序广播
private final void processCurBroadcastLocked(BroadcastRecord r,ProcessRecord app) throws RemoteException {//LOG打印if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,"Process cur broadcast " + r + " for app " + app);final IApplicationThread thread = Thread();if (thread == null) {//若没有找到ApplicationThread 对象,则报异常.throw new RemoteException();}if (app.isInFullBackup()) {//若是FULL备份,则忽略此广播skipReceiverLocked(r);return;}// 将进程的相关信息写入当前BroadcastRecord中相关的接收者 r.receiver = thread.asBinder();r.curApp = app;final ProcessReceiverRecord prr = app.mReceivers;prr.addCurReceiver(r);app.mState.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);mService.updateLruProcessLocked(app, false, null);// Make sure the oom adj score is updated before delivering the broadcast.// Force an update, even if there are other pending requests, overall it still saves time,// because time(updateOomAdj(N apps)) <= N * time(updateOomAdj(1 app)).queueOomAdjTargetLocked(app);mService.updateOomAdjPendingTargetsLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);// Tell the application to launch this receiver.//告知启动的组件r.intent.setComponent(r.curComponent);boolean started = false;try {if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,"Delivering to component " + r.curComponent+ ": " + r);ifyPackageUse(Component().getPackageName(),PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER);//处理广播发送.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,mServicepatibilityInfoForPackage(r.curReceiver.applicationInfo),r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,ReportedProcState());if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,"Process cur broadcast " + r + " DELIVERED for app " + app);started = true;} finally {if (!started) {//若启动失败,则打印对应的信息if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,"Process cur broadcast " + r + ": NOT STARTED!");r.receiver = null;r.curApp = veCurReceiver(r);}}}
APP存在,调用ApplicationThread的scheduleReceiver方法
android/frameworks/base/core/java/android/app/ActivityThread.java
private class ApplicationThread extends IApplicationThread.Stub {private static final String DB_INFO_FORMAT = " %8s %8s %14s %14s %s";public final void scheduleReceiver(Intent intent, ActivityInfo info,CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,boolean sync, int sendingUser, int processState) {updateProcessState(processState, false);ReceiverData r = new ReceiverData(intent, resultCode, data, extras,sync, false, mAppThread.asBinder(), sendingUser);r.info = info;rpatInfo = compatInfo;sendMessage(H.RECEIVER, r);}public void handleMessage(Message msg) {if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));case aceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp");//使用handleReceiver函数handleReceiver((ReceiverData)msg.obj);aceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
APP存在,调用ApplicationThread的handleReceiver方法
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)private void handleReceiver(ReceiverData data) {// If we are getting ready to gc after going to the background, well// we are back active so skip it.unscheduleGcIdler();// 1) 创建BroadcastReceiver对象// 这里处理的是静态广播接收者,默认认为接收者BroadcastReceiver对象不存在// 每次接受都会创建一个新的BroadcastReceiver对象//获取组件String component = Component().getClassName();//获取packageinfo 对象LoadedApk packageInfo = getPackageInfoNoCheck(data.info.applicationInfo, datapatInfo);IActivityManager mgr = Service();Application app;BroadcastReceiver receiver;ContextImpl context;try {// 首先从AMS传递的intent中获取当前处理该广播的组件名称,然后通过反射创建一个BroadcastReceiver// 对象,从这里可以看出来,静态广播处理的时候,每次都会创建一个新的BroadcastReceiver对象;// 创建Application对象,如果进程已经启动,Application对象已经创建app = packageInfo.makeApplication(false, mInstrumentation);context = (ContextImpl) BaseContext();if (data.info.splitName != null) {context = (ContextImpl) ateContextForSplit(data.info.splitName);}if (data.info.attributionTags != null && data.info.attributionTags.length > 0) {final String attributionTag = data.info.attributionTags[0];context = (ContextImpl) ateAttributionContext(attributionTag);}java.lang.ClassLoader cl = ClassLoader();data.intent.setExtrasClassLoader(cl);data.intent.prepareToEnterProcess(isProtectedComponent(data.info) || isProtectedBroadcast(data.intent),AttributionSource());data.setExtrasClassLoader(cl);receiver = AppFactory().instantiateReceiver(cl, data.info.name, data.intent);} catch (Exception e) {if (DEBUG_BROADCAST) Slog.i(TAG,"Finishing failed broadcast to " + Component());data.sendFinished(mgr);throw new RuntimeException("Unable to instantiate receiver " + component+ ": " + e.toString(), e);}// 2) 执行onReceive函数try {if (localLOGV) Slog.v(TAG, "Performing receive of " + data.intent+ ": app=" + app+ ", appName=" + PackageName()+ ", pkg=" + PackageName()+ ", comp=" + Component().toShortString()+ ", dir=" + AppDir());sCurrentBroadcastIntent.set(data.intent);// 调用接收者的onReceive方法,这里还调用了setPendingResult方法,详细内容请看Async方法。receiver.setPendingResult(data);ReceiverRestrictedContext(),data.intent);} catch (Exception e) {if (DEBUG_BROADCAST) Slog.i(TAG,"Finishing failed broadcast to " + Component());data.sendFinished(mgr);if (!Exception(receiver, e)) {throw new RuntimeException("Unable to start receiver " + component+ ": " + e.toString(), e);}} finally {sCurrentBroadcastIntent.set(null);}if (PendingResult() != null) {// 3) 向AMS发送处理结束消息data.finish();}}
上面代码主要干了三件事情:
APP未启动,先创建该进程
如果静态广播接收者进程尚未启动,会直接调用AMS的startProcessLocked函数启动该接收者进程,并将当前正在等待进程
启动的BroadcastRecord存储到mPendingBroadcast里面,这个就是静态广播拉起应用的原理。
在app进程启动之后,会先调用application的attach和onCreate方法,然后才会调用ActivityManagerService的sendPendingBroadcastsLocked方法。
// The app just attached; send any pending broadcasts that it should receiveboolean sendPendingBroadcastsLocked(ProcessRecord app) {boolean didSomething = false;for (BroadcastQueue queue : mBroadcastQueues) {//调用BroadcastQueue的sendPendingBroadcastsLocked方法didSomething |= queue.sendPendingBroadcastsLocked(app);}return didSomething;}
mBroadcastQueues是包含前台和后台广播队列,这里分别调用前台和后台优先级广播的BroadcastQueue.sendPendingBroadcastsLocked方法。
调用BroadcastQueue的sendPendingBroadcastsLocked方法
// 未启动进程的广播接收者需要先启动进程,最后到达这个函数public boolean sendPendingBroadcastsLocked(ProcessRecord app) {boolean didSomething = false;final BroadcastRecord br = mPendingBroadcast;if (br != null && Pid() > 0 && Pid() == Pid()) {if (br.curApp != app) {Slog.e(TAG, "App mismatch when sending pending broadcast to "+ app.processName + ", intended target is " + br.curApp.processName);return false;}try {//启动完成设置为nullmPendingBroadcast = null;//调用processCurBroadcastLocked方法进行处理processCurBroadcastLocked(br, app);didSomething = true;} catch (Exception e) {Slog.w(TAG, "Exception in new application when starting receiver "+ br.curComponent.flattenToShortString(), e);logBroadcastReceiverDiscardLocked(br);finishReceiverLocked(br, br.resultCode, br.sultExtras, br.resultAbort, false);scheduleBroadcastsLocked();// We need to reset the state if we failed to start the receiver.br.state = BroadcastRecord.IDLE;throw new Message());}}return didSomething;}
这里是找到等待处理的广播并且判断是否为空,以及是否和当前进程的pid相同,也就是不是这个进程的等待广播,如果是就调用processCurBroadcastLocked
方法进行处理,后面的处理和上面app已启动的流程一致了。
上面流程大体流程图:
执行时序图:
三、总结
看完源码再来看下一开始的问题:
1、广播为啥会阻塞呢?发送给接收器就行了,为啥还要等着接收器处理完才处理下一个?
从上面的源码分析可知,广播的处理分为并行和有序两个队列,出问题的无序广播静态接收器放在了有序处理列表中,而有序处理列表的执行是串行的,只有前面的执行完,才会轮到下一个处理,所以前面的广播如果在onReceive中有耗时操作,后面的广播就会堵塞。
2、 由普通的后台广播改为前台广播后,为啥处理的会更快?
在上面源码中有个变量的注释:mTimeoutPeriod。这个变量初始化是在BroadcastQueue初始化的时候传入的,也就是在AMS(AMS构造函数中)中初始化mFgBroadcastQueue和mBgBroadcastQueue时传入的,前台广播的超时时间是10s,后台的超时时间是60s。 也会出现一种问题,就是产生发生ANR的时间段时间不一样.
BROADCAST_FG_TIMEOUT = 10 * 1000
BROADCAST_BG_TIMEOUT = 60 * 1000
后台广播的设计思想就是当前应用优先,尽可能多让收到广播的应用有充足的时间把事件做完。
而前台广播的目的是紧急通知,设计上就倾向于当前应用赶快处理完,尽快传给下一个。
也就是说在设计上前台广播主要用于响应性能较高的场景,因为ANR时间是10s,所以开发设计的时候应该尽可能少用。因为前台广播使用的比较少,所以队列相对空闲,响应速度快。
3、对照源码分析总结:
(1) 前后台队列都有自己并行和有序广播队列,互相不影响;
(2) 并行队列里是无序广播+动态注册接收者;
(3) 有序队列里是有序广播+动态接收者和静态接收者,静态接收者默认就是有序的;
(4) 有序广播+动态接收者执行优于静态接收者先执行,综合起来就是广播相同的情况下,动态接收器优于静态接收器;
(5) Android版本高的,很多系统广播只支持动态注册,静态注册的话收不到广播,例如:息屏亮屏广播。因为静态注册的话,发广播的时候会把所有注册未启动的app全部拉起来,静态处理器又默认串行处理,增加了广播的处理时间。
知识点介绍:
1. instant app :谷歌推出的类似于微信小程序(或者说小程序类似于instant app)的一项技术,用户无须安装应用,用完就走,同时兼备h5的便捷和原生应用的优质体验。
本文发布于:2024-01-28 10:17:20,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/17064082446715.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |