安卓广播发送接收流程

本文基于Andorid 11。

一、registerReceiver

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

查看动态注册广播流程:

1.2 ContextImpl.registerReceiverInternal

// ContextImpl.java    private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,IntentFilter filter, String broadcastPermission,Handler scheduler, Context context, int flags) {IIntentReceiver rd = null;if (receiver != null) {if (mPackageInfo != null && context != null) {if (scheduler == null) {scheduler = mMainThread.getHandler();}rd = mPackageInfo.getReceiverDispatcher(receiver, context, scheduler,mMainThread.getInstrumentation(), true);} else {if (scheduler == null) {scheduler = mMainThread.getHandler();}rd = new LoadedApk.ReceiverDispatcher(receiver, context, scheduler, null, true).getIIntentReceiver();}}try {final Intent intent = ActivityManager.getService().registerReceiverWithFeature(mMainThread.getApplicationThread(), mBasePackageName, getAttributionTag(), rd,filter, broadcastPermission, userId, flags);if (intent != null) {intent.setExtrasClassLoader(getClassLoader());intent.prepareToEnterProcess();}return intent;} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}

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

1.3 AMS.registerReceiverWithFeature

// ActivityManagerService.javapublic Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage,String callerFeatureId, IIntentReceiver receiver, IntentFilter filter,String permission, int userId, int flags) {enforceNotIsolatedCaller("registerReceiver");ArrayList<Intent> stickyIntents = null;ProcessRecord callerApp = null;final boolean visibleToInstantApps= (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;//	1. 获取Uid, Pid, isInstantApp, actionsint callingUid;int callingPid;boolean instantApp;synchronized(this) {if (caller != null) {callerApp = getRecordForAppLocked(caller);if (callerApp == null) {throw new SecurityException("Unable to find app for caller " + caller+ " (pid=" + Binder.getCallingPid()+ ") when registering receiver " + receiver);}if (callerApp.info.uid != SYSTEM_UID &&!callerApp.pkgList.containsKey(callerPackage) &&!"android".equals(callerPackage)) {throw new SecurityException("Given caller package " + callerPackage+ " is not running in process " + callerApp);}callingUid = callerApp.info.uid;callingPid = callerApp.pid;} else {callerPackage = null;callingUid = Binder.getCallingUid();callingPid = Binder.getCallingPid();}instantApp = isInstantApp(callerApp, callerPackage, callingUid);userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,ALLOW_FULL_ONLY, "registerReceiver", callerPackage);Iterator<String> actions = filter.actionsIterator();if (actions == null) {ArrayList<String> noAction = new ArrayList<String>(1);noAction.add(null);actions = noAction.iterator();}//	2. 收集当前用户下的粘性广播// Collect stickies of usersint[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };while (actions.hasNext()) {String action = actions.next();for (int id : userIds) {ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);if (stickies != null) {ArrayList<Intent> intents = stickies.get(action);if (intents != null) {if (stickyIntents == null) {stickyIntents = new ArrayList<Intent>();}stickyIntents.addAll(intents);}}}}}ArrayList<Intent> allSticky = null;if (stickyIntents != null) {final ContentResolver resolver = mContext.getContentResolver();// Look for any matching sticky broadcasts...for (int i = 0, N = stickyIntents.size(); i < N; i++) {Intent intent = stickyIntents.get(i);// Don't provided intents that aren't available to instant apps.if (instantApp &&(intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {continue;}// If intent has scheme "content", it will need to acccess// provider that needs to lock mProviderMap in ActivityThread// and also it may need to wait application response, so we// cannot lock ActivityManagerService here.if (filter.match(resolver, intent, true, TAG) >= 0) {if (allSticky == null) {allSticky = new ArrayList<Intent>();}allSticky.add(intent);}}}// The first sticky in the list is returned directly back to the client.Intent sticky = allSticky != null ? allSticky.get(0) : null;if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Register receiver " + filter + ": " + sticky);if (receiver == null) {return sticky;}// 3. 创建ReceiverList,BroadcastFilter对象,添加到AMS类变量mRegisteredReceivers, mReceiverResolver中维护。synchronized (this) {if (callerApp != null && (callerApp.thread == null|| callerApp.thread.asBinder() != caller.asBinder())) {// Original caller already diedreturn null;}ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());if (rl == null) {rl = new ReceiverList(this, callerApp, callingPid, callingUid,userId, receiver);if (rl.app != null) {final int totalReceiversForApp = rl.app.receivers.size();if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) {throw new IllegalStateException("Too many receivers, total of "+ totalReceiversForApp + ", registered for pid: "+ rl.pid + ", callerPackage: " + callerPackage);}rl.app.receivers.add(rl);} else {try {receiver.asBinder().linkToDeath(rl, 0);} catch (RemoteException e) {return sticky;}rl.linkedToDeath = true;}mRegisteredReceivers.put(receiver.asBinder(), rl);} else if (rl.uid != callingUid) {throw new IllegalArgumentException("Receiver requested to register for uid " + callingUid+ " was previously registered for uid " + rl.uid+ " callerPackage is " + callerPackage);} else if (rl.pid != callingPid) {throw new IllegalArgumentException("Receiver requested to register for pid " + callingPid+ " was previously registered for pid " + rl.pid+ " callerPackage is " + callerPackage);} else if (rl.userId != userId) {throw new IllegalArgumentException("Receiver requested to register for user " + userId+ " was previously registered for user " + rl.userId+ " callerPackage is " + callerPackage);}BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,permission, callingUid, userId, instantApp, visibleToInstantApps);if (rl.containsFilter(filter)) {Slog.w(TAG, "Receiver with filter " + filter+ " already registered for pid " + rl.pid+ ", callerPackage is " + callerPackage);} else {rl.add(bf);mReceiverResolver.addFilter(bf);}// Enqueue broadcasts for all existing stickies that match// this filter.if (allSticky != null) {ArrayList receivers = new ArrayList();receivers.add(bf);final int stickyCount = allSticky.size();for (int i = 0; i < stickyCount; i++) {Intent intent = allSticky.get(i);BroadcastQueue queue = broadcastQueueForIntent(intent);BroadcastRecord r = new BroadcastRecord(queue, intent, null,null, null, -1, -1, false, null, null, OP_NONE, null, receivers,null, 0, null, null, false, true, true, -1, false,false /* only PRE_BOOT_COMPLETED should be exempt, no stickies */);queue.enqueueParallelBroadcastLocked(r);queue.scheduleBroadcastsLocked();}}return sticky;}}
  1. 获取Uid, Pid, userId, isInstantApp, actions,做一些校验工作
  2. 收集当前用户下的粘性广播
  3. 创建ReceiverList,BroadcastFilter对象,添加到AMS类变量mRegisteredReceivers, mReceiverResolver中维护。
final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver= new IntentResolver<BroadcastFilter, BroadcastFilter>()

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

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

BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,permission, callingUid, userId, instantApp, visibleToInstantApps);

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

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

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

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

二、sendBroadcast

2.1 AMS.broadcastIntentLocked

// ActivityManagerService.java
@GuardedBy("this")
final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage,@Nullable String callerFeatureId, Intent intent, String resolvedType,IIntentReceiver resultTo, int resultCode, String resultData,Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,boolean ordered, boolean sticky, int callingPid, int callingUid, int realCallingUid,int realCallingPid, int userId, boolean allowBackgroundActivityStarts,@Nullable int[] broadcastWhitelist) {intent = new Intent(intent);intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);// 1. 处理安全问题,ProtectedBroadcastfinal String action = intent.getAction();final boolean isProtectedBroadcast;isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);final boolean isCallerSystem;switch (UserHandle.getAppId(callingUid)) {case ROOT_UID:case SYSTEM_UID:case PHONE_UID:case BLUETOOTH_UID:case NFC_UID:case SE_UID:case NETWORK_STACK_UID:isCallerSystem = true;break;default:isCallerSystem = (callerApp != null) && callerApp.isPersistent();break;}if (!isCallerSystem) {if (isProtectedBroadcast) {throw new SecurityException(msg);} else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)|| AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {//...}}// 2. 粘性广播,安卓5.0后被弃用,不关注。if (sticky) {}// 3. 计算广播接收者List receivers = null;List<BroadcastFilter> registeredReceivers = null;// 3.1 FLAG_RECEIVER_REGISTERED_ONLY指定必须动态注册广播接收器才能接收,如果未指定,通过PMS通过Intent参数的component或者package查找接收器if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)  == 0) {receivers = collectReceiverComponents(intent, resolvedType, callingUid, users, broadcastWhitelist);}// 3.2 隐式广播,查找动态注册广播接收器,mReceiverResolver维护了在应用程序调用registerReceiver()添加的对应接收器if (intent.getComponent() == null) {if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {// ...} else {registeredReceivers = mReceiverResolver.queryIntent(intent,resolvedType, false /*defaultOnly*/, userId);}}final boolean replacePending =(intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;// 4. 获取BroadcastQueue, 创建BroadcastRecord对象,添加到mParallelBroadcasts发送。int NR = registeredReceivers != null ? registeredReceivers.size() : 0;if (!ordered && NR > 0) {	// 无序广播// If we are not serializing this broadcast, then send the// registered receivers separately so they don't wait for the// components to be launched.final BroadcastQueue queue = broadcastQueueForIntent(intent);BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,resultCode, resultData, resultExtras, ordered, sticky, false, userId,allowBackgroundActivityStarts, timeoutExempt);final boolean replaced = replacePending&& (queue.replaceParallelBroadcastLocked(r) != null);// Note: We assume resultTo is null for non-ordered broadcasts.if (!replaced) {queue.enqueueParallelBroadcastLocked(r);// 添加到mParallelBroadcasts队列。queue.scheduleBroadcastsLocked();		// 发送mParallelBroadcasts队列中的平行广播。}registeredReceivers = null;NR = 0;										// 将registeredReceivers和NR变量重置,避免后续合并到receivers中。}// 5. 合并receivers(静态注册),registeredReceivers(动态注册)到receivers变量中。if (receivers != null) {int NT = receivers != null ? receivers.size() : 0;int it = 0;ResolveInfo curt = null;BroadcastFilter curr = null;while (it < NT && ir < NR) {	// 动态注册无序广播 NR == 0。if (curt == null) {curt = (ResolveInfo)receivers.get(it);}if (curr == null) {curr = registeredReceivers.get(ir);}if (curr.getPriority() >= curt.priority) {// Insert this broadcast record into the final list.receivers.add(it, curr);ir++;curr = null;it++;NT++;} else {// Skip to the next ResolveInfo in the final list.it++;curt = null;}}}while (ir < NR) {if (receivers == null) {receivers = new ArrayList();}receivers.add(registeredReceivers.get(ir));ir++;}// 6. 将合并的静态注册广播根据优先级,添加到mOrderedBroadcasts发送。if ((receivers != null && receivers.size() > 0)|| resultTo != null) {BroadcastQueue queue = broadcastQueueForIntent(intent);BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,resultData, resultExtras, ordered, sticky, false, userId,allowBackgroundActivityStarts, timeoutExempt);final BroadcastRecord oldRecord =replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;if (oldRecord != null) {if (oldRecord.resultTo != null) {final BroadcastQueue oldQueue = broadcastQueueForIntent(oldRecord.intent);oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo,oldRecord.intent,Activity.RESULT_CANCELED, null, null,false, false, oldRecord.userId);}} else {queue.enqueueOrderedBroadcastLocked(r);queue.scheduleBroadcastsLocked();}}
}

发送广播:

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

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

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

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

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

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

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

2.2 collectReceiverComponents

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

收集广播接收者:

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

看下IntentResolver的处理过程:

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

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

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

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

2.3 processNextBroadcastLocked

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

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

2.4 processCurBroadcastLocked

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

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

2.4.1 handleReceiver

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/821809.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Backend - Django Swagger

目录 一、安装依赖 二、配置环境 三、路由&#xff08;urls&#xff09; 四、swagger UI 界面 &#xff08;一&#xff09;UI 界面 &#xff08;二&#xff09;单引号问题&#xff1a;Expecting property name enclosed in double quotes 1. 原因 2. 解决 五、自定义s…

java正则表达式教程

什么是正则表达式&#xff1a; 正则表达式是一种用来描述字符串模式的语法。在 Java 中&#xff0c;正则表达式通常是一个字符串&#xff0c;它由普通字符&#xff08;例如字母、数字、标点符号等&#xff09;和特殊字符&#xff08;称为元字符&#xff09;组成。这些特殊字符可…

Qt 实战(2)搭建开发环境 | 2.1、Windows下安装QT

一、Windows下安装QT 1、QT官网 QT官网&#xff1a;https://download.qt.io/&#xff0c;打开官网地址&#xff0c;如下&#xff1a; 目录结构介绍 目录说明snapshots预览版&#xff0c;最新的开发测试中的 Qt 库和开发工具onlineQt 在线安装源official_releases正式发布版&am…

跟TED演讲学英文:How AI can bring on a second Industrial Revolution by Kevin Kelly

How AI can bring on a second Industrial Revolution Link: https://www.ted.com/talks/kevin_kelly_how_ai_can_bring_on_a_second_industrial_revolution Speaker: Kevin Kelly Date: June 2016 文章目录 How AI can bring on a second Industrial RevolutionIntroduction…

UE 录屏自动化上传阿里云OSS

前言 最近在做一个功能&#xff0c;然后就发现了一个很有趣的东西&#xff0c;虽然在一定程度上属于偷懒&#xff0c;但是在一些短频快的应用中还是很适用的&#xff0c;下面我就针对于这个测试做一些简单的分享&#xff0c;希望帮助到大家&#xff0c;在实际的开发中获得一些灵…

计算机视觉——OpenCV Python基于颜色识别的目标检测

1. 计算机视觉中的颜色空间 颜色空间在计算机视觉领域的应用非常广泛&#xff0c;它们在图像和视频处理、物体检测等任务中扮演着重要角色。颜色空间的主要作用是将颜色以数值形式表示出来&#xff0c;这样计算机算法就能够对其进行处理和分析。不同的颜色空间有着不同的特点和…

Pytorch搭建GoogleNet神经网络

一、创建卷积模板文件 因为每次使用卷积层都需要调用Con2d和relu激活函数&#xff0c;每次都调用非常麻烦&#xff0c;就将他们打包在一起写成一个类。 in_channels&#xff1a;输入矩阵深度作为参数输入 out_channels: 输出矩阵深度作为参数输入 经过卷积层和relu激活函数…

0基础如何入门编程?

0基础如何进入IT行业 &#xff1f; 前言 简介&#xff1a;对于没有任何相关背景知识的人来说&#xff0c;如何才能成功进入IT行业&#xff1f;是否有一些特定的方法或技巧可以帮助他们实现这一目标&#xff1f; 主要方法有如下几点建议提供给宝子们 目录 免费视频网课学习…

36、二叉树-二叉树的中序遍历

思路&#xff1a; 二叉树的遍历可以有 前序&#xff0c;中序&#xff0c;后序&#xff0c;层序遍历。 前序&#xff1a;头左右中序&#xff1a;左头右后序&#xff1a;左右头层序:从左往右依次遍历 实现方式&#xff1a; 递归通过栈结构便于回溯 代码如下&#xff1a; c…

3D模型处理的并行化

今天我们将讨论如何使用 Python 多进程来处理大量3D数据。 我将讲述一些可能在手册中找到的一般信息&#xff0c;并分享我发现的一些小技巧&#xff0c;例如将 tqdm 与多处理 imap 结合使用以及并行处理存档。 那么我们为什么要诉诸并行计算呢&#xff1f; 使用数据有时会出现…

Backend - DRF 序列化(django-rest-framework)

目录 一、restful 、django-rest-framework 、swagger 三者的关系 &#xff08;一&#xff09;restful API&#xff08;REST API&#xff09; 1. rest 2. restful 3. api 4. restfulAPI &#xff08;二&#xff09;django-rest-framework&#xff08;简称DRF&#xff09…

Web3D智慧医院平台(HTML5+Threejs)

智慧医院的建设将借助物联网、云计算、大数据、数字孪生等技术&#xff0c;以轻量化渲染、极简架构、三维可视化“一张屏”的形式&#xff0c;让医院各大子系统管理既独立又链接&#xff0c;数据相互融合及联动。 建设医院物联网应用的目标对象&#xff08;人、物&#xff09;都…

7 pytorch DataLoader, TensorDataset批数据训练方法

前言 本文主要介绍pytorch里面批数据的处理方法&#xff0c;以及这个算法的效果是什么样的。具体就是要弄明白这个批数据选取的算法是在干什么&#xff0c;不会涉及到网络的训练。 from torch.utils.data import DataLoader, TensorDataset主要实现就是上面的数据集和数据载入…

pdf做批注编辑工具 最新pdf reader pro3.3.1.0激活版

PDF Reader Pro是一款功能强大的PDF阅读和编辑工具。它提供了多种工具和功能&#xff0c;帮助用户对PDF文档进行浏览、注释、编辑、转换和签名等操作。以下是PDF Reader Pro的一些主要特色&#xff1a; 最新pdf reader pro3.3.1.0激活版下载 多种查看模式&#xff1a;PDF Reade…

STM32 PB3 PB4 无法作为 GPIO 使用解决办法

如下所示&#xff0c;PA13 PA14 PB3 PB4 PB5, 默认是JTAG SWD的 PIN, 需要引脚ReMap 才能作为GPIO 使用。 HAL库解决办法 // __HAL_AFIO_REMAP_SWJ_ENABLE(); //Full SWJ (JTAG-DP SW-DP):// __HAL_AFIO_REMAP_SWJ_NONJTRST(); //Full SWJ (JTAG-DP SW-DP) but without NJTR…

【代理模式】静态代理-简单例子

在Java中&#xff0c;静态代理是一种设计模式&#xff0c;它涉及到为一个对象提供一个代理以控制对这个对象的访问。静态代理在编译时就已经确定&#xff0c;代理类和被代理类会实现相同的接口或者是代理类继承被代理类。客户端通过代理类来访问&#xff08;调用&#xff09;被…

认识异常(1)

❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; hellohello~&#xff0c;大家好&#x1f495;&#x1f495;&#xff0c;这里是E绵绵呀✋✋ &#xff0c;如果觉得这篇文章还不错的话还请点赞❤️❤️收藏&#x1f49e; &#x1f49e; 关注&#x1f4a5;&a…

计算机网络:MAC地址 IP地址 ARP协议

计算机网络&#xff1a;MAC地址 & IP地址 & ARP协议 MAC地址IP地址ARP协议 MAC地址 如果两台主机通过一条链路通信&#xff0c;它们不需要使用地址就可以通信&#xff0c;因为连接在信道上的主机只有他们两个。换句话说&#xff0c;使用点对点信道的数据链路层不需要使…

开源 Ruo-Yi 项目引入 Mybatis-Plus:3.5.3 报错ClassNotFoundException:

开源 Ruo-Yi 项目引入 Mybatis-Plus:3.5.3 报错ClassNotFoundException&#xff1a; Caused by: java.lang.ClassNotFoundException: com.baomidou.mybatisplus.extension.plugins.MybatisPlusInter1 分析问题 控制台报错说明我们引入的 mybatis-plus 的依赖里找不到com.baom…

数字化转型-工具变量数据集

01、数据介绍 数字化转型是指企业或个人利用数字技术&#xff0c;如大数据、云计算、人工智能等&#xff0c;对其业务流程、运营模式、决策方式等进行全面、深入的变革&#xff0c;以提高效率、降低成本、提升质量、增强竞争力。在这个过程中&#xff0c;工具变量扮演着至关重…