详解Android广播Broadcast的启动流程

这篇文章主要为大家介绍了Android广播Broadcast启动流程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

正文

本文整体阅读下来相对ActivityService的启动流程较容易,比较贴近我们日常代码开发习惯。我们曾经有个整机项目,多个APP跨进程交互,本来想采用AIDL进行的,但最终考虑到项目工期和其他同事的能力,最终在采用广播方式进行IPC。

那时,自己也在想,这么多个APP相互发信息,数据量也大,对整机性能有影响么?会不会存在丢失和内存问题。一脸茫然,网上也不会有类似信息告诉总结这种情况,本文也不会总结这个答案,因为看完之后心中自然有数了。

在AMS中持有集合用于存储所有的广播,应用程序可以从向其注册和解注册广播。当应用发送广播时,AMS检查相关权限和特殊的Intent。然后再根据对应IntentFilter匹配到一个或多个Receiver,在应用进程回调其onReceive函数。

阅读源码本身就是一份苦活,不可能一次就读懂,或者了解透的。只有反复的阅读,输入与输出,才会越来越轻松。所以个人建议,先粗读,了解个大概的思路就行。收藏或点赞,等自己ready,再好好结合源码阅读。一定要Fuck Code!

广播的注册

我们常在ActivityService、甚至Application中调用registerReceiver函数来注册动态广播,该函数其实来自它们共同的父类ContextWrapper中。ContextWrapperContext的子类,我们会在介绍Context的文章介绍它们的关系。

public Intent registerReceiver( BroadcastReceiver receiver, IntentFilter filter) { return mBase.registerReceiver(receiver, filter); } 

这里Context类型的mBase,在Activity的创建过程实际被赋值为ContextImpl实例。

 public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { return registerReceiver(receiver, filter, null, null); } public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) { return registerReceiverInternal(receiver, getUserId(), filter, broadcastPermission, scheduler, getOuterContext(), 0); } 

经过registerReceiver重载函数,调用了registerReceiverInternal函数。

    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(); } } 

分析一:

传递进来的BroadcastReceiver不为nullLoadedApk类型的mPackageInfo只要应用进程启动,该属性就会被赋值,context这里指向Activityschedulernull,赋值为主线程的H类型mH对象。分析一,主要通过上面的变量来获得IIntentReceiver类型rd对象。

getReceiverDispatcher函数先从缓存检测是否有相同类型的BroadcastReceiver对应的ReceiverDispatcher。没有的话,则新建并缓存起来。 一个context对应多个BroadcastReceiver,而一个BroadcastReceiver对应用一个ReceiverDispatcher

ReceiverDispatcherLoadedDispatcher的静态内部类,其内部还有一个AIDL类型本地实现静态类InnerReceiver。在ReceiverDispatcher的构造函数中会创建InnerReceiver的实例。

public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r, Context context, Handler handler, Instrumentation instrumentation, boolean registered) { synchronized (mReceivers) { LoadedApk.ReceiverDispatcher rd = null; ArrayMap map = null; if (registered) { map = mReceivers.get(context); if (map != null) { rd = map.get(r); } } if (rd == null) { rd = new ReceiverDispatcher(r, context, handler, instrumentation, registered); if (registered) { if (map == null) { map = new ArrayMap(); mReceivers.put(context, map); } map.put(r, rd); } } else { rd.validate(context, handler); } rd.mForgotten = false; return rd.getIIntentReceiver(); } } 

回到registerReceiverInternal函数的分析二,调用了AMSregisterReceiverWithFeature函数。

该函数是Broadcast整个注册过程结束的地方,根据新注册的BroadcastReceiver,处理粘性广播的发送和当前注册Receiver的添加。

分析一:

粘性广播存储在AMS的SparseArray>>类型的 mStickyBroadcasts中。SparseArraykeyuserId,而ArrayMapkeyaction,valueIntent。即我们可以通过用户id在mStickyBroadcasts找到当前进程对应所有粘性广播(和针对所有进程的粘性广播),然后根据对应的action找到对应的Intent。这里将他们收集到stickyIntents集合中。

分析二:

所有广播的接收者BroacastReceiver存储在AMSHashMap类型的mRegisteredReceivers中。这里的IBinder类型就是应用进程前面创建的InnerReceiver类实例在AMS的引用。因为广播接收者BroadcastReceiver对应一个或多个Broadcast,所以这里通过继承自ArrayListReceiverList来表达这种关系。通过BroadcastFilter来表示当前接收者感兴趣的广播。

分析三:

对匹配到的粘性Intent进入广播队列广播。

    public Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage, String callerFeatureId, IIntentReceiver receiver, IntentFilter filter, String permission, int userId, int flags) { enforceNotIsolatedCaller("registerReceiver"); //粘性Intent ArrayList stickyIntents = null; ProcessRecord callerApp = null; final boolean visibleToInstantApps = (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0; int callingUid; int callingPid; boolean instantApp; synchronized(this) { if (caller != null) { //获得当前引用进程的ProcessRecord callerApp = getRecordForAppLocked(caller); ... 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); //分析一:当前注册广播中感兴趣的action列表 Iterator actions = filter.actionsIterator(); if (actions == null) { ArrayList noAction = new ArrayList(1); noAction.add(null); actions = noAction.iterator(); } //从历史粘性广播中查找与当前注册的action一致的intent //添加到stickyIntents // Collect stickies of users int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) }; while (actions.hasNext()) { String action = actions.next(); for (int id : userIds) { ArrayMap> stickies = mStickyBroadcasts.get(id); if (stickies != null) { ArrayList intents = stickies.get(action); if (intents != null) { if (stickyIntents == null) { stickyIntents = new ArrayList(); } stickyIntents.addAll(intents); } } } } } //处理content类型的Intent ArrayList allSticky = null; if (stickyIntents != null) { final ContentResolver resolver = mContext.getContentResolver(); // Look for any matching sticky broadcasts... for (int i = 0, N = stickyIntents.size(); i = 0) { if (allSticky == null) { allSticky = new ArrayList(); } allSticky.add(intent); } } } //receiver为null,直接返回null或者第一个粘性intent Intent sticky = allSticky != null ? allSticky.get(0) : null; if (receiver == null) { return sticky; } synchronized (this) { ... //分析二: //从缓存或新建ReceiverList对象,与Receiver绑定 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); } //添加到ProcessRecord记录中 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); } ... //新建BroadcastFilter,并添加到BroadcastList BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId, permission, callingUid, userId, instantApp, visibleToInstantApps); if (rl.containsFilter(filter)) { ... } else { rl.add(bf); //添加到接收者解析器 mReceiverResolver.addFilter(bf); } // Enqueue broadcasts for all existing stickies that match // this filter. //分析三:对匹配到action的粘性广播进行广播 if (allSticky != null) { ArrayList receivers = new ArrayList(); receivers.add(bf); final int stickyCount = allSticky.size(); for (int i = 0; i 

广播的解注册

回到ContextWrapperunregisterReceiver函数。

#ContextWrapper public void unregisterReceiver(BroadcastReceiver receiver) { mBase.unregisterReceiver(receiver); } #ContextImpl public void unregisterReceiver(BroadcastReceiver receiver) { if (mPackageInfo != null) { IIntentReceiver rd = mPackageInfo.forgetReceiverDispatcher( getOuterContext(), receiver); try { ActivityManager.getService().unregisterReceiver(rd); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } else { throw new RuntimeException("Not supported in system context"); } } 

这里通过receivercontext获得IIntentReceiver实例rd,然后调用AMS的unregisterReceiver函数。其中LoadedApkforgetReceiverDispatcher函数,主要是从mReceivers获取IIntentReceiver的实例,并将receiver对应的内容从缓存移除。

AMS的unregisterReceiver函数。主要是将注册过程添加到mRegisteredReceiversProcessProcess.Receivers、mReceiverResolver中对应的内容移除。并终止正在发送的广播。

   public void unregisterReceiver(IIntentReceiver receiver) { ... final long origId = Binder.clearCallingIdentity(); try { boolean doTrim = false; synchronized(this) { //获得当前对应的ReceiverList ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder()); if (rl != null) { //默认情况为null,看看广播发送是否会赋值 //从处理逻辑来看,就是广播内容 final BroadcastRecord r = rl.curBroadcast; if (r != null && r == r.queue.getMatchingOrderedReceiver(r)) { final boolean doNext = r.queue.finishReceiverLocked( r, r.resultCode, r.resultData, r.resultExtras, r.resultAbort, false); if (doNext) { doTrim = true; r.queue.processNextBroadcast(false); } } //从processRecord中移除 if (rl.app != null) { rl.app.receivers.remove(rl); } //从mRegisteredReceivers和mReceiverResolver移除 removeReceiverLocked(rl); if (rl.linkedToDeath) { rl.linkedToDeath = false; rl.receiver.asBinder().unlinkToDeath(rl, 0); } } } // If we actually concluded any broadcasts, we might now be able // to trim the recipients' apps from our working set if (doTrim) { trimApplications(OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER); return; } } finally { Binder.restoreCallingIdentity(origId); } } void removeReceiverLocked(ReceiverList rl) { mRegisteredReceivers.remove(rl.receiver.asBinder()); for (int i = rl.size() - 1; i >= 0; i--) { mReceiverResolver.removeFilter(rl.get(i)); } } 

广播的发送

定位到ContextWrappersendBroadcast函数。

public void sendBroadcast(Intent intent) { mBase.sendBroadcast(intent); } public void sendBroadcast(Intent intent) { warnIfCallingFromSystemProcess(); String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { intent.prepareToLeaveProcess(this); ActivityManager.getService().broadcastIntentWithFeature(mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,null, Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false,false, getUserId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } 

调用AMSbroadcastIntentWithFeature函数。内部又调用了broadcastIntentLocked函数。是所有Intent处理的地方,很长很长。有对特殊类型的Intent处理,例如Intent.ACTION_PACKAGE_REMOVEDIntent.ACTION_TIME_CHANGED。该函数主要将有序和无序广播接收者(匹配Intent)添加到receivers列表,并创建BroadcastRecord对象r,持有receivers列表。并根据intent获得对应的广播队列queue,将r添加到queue中,执行queue.scheduleBroadcastsLocked函数。

#AMS xxm @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); ... int[] users; if (userId == UserHandle.USER_ALL) { // Caller wants broadcast to go to all started users. users = mUserController.getStartedUserArray(); } 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 registeredReceivers = null; // Need to resolve the intent to interested receivers... if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { receivers = collectReceiverComponents( intent, resolvedType, callingUid, users, broadcastWhitelist); } if (intent.getComponent() == null) { if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) { // Query one target user at a time, excluding shell-restricted users for (int i = 0; i  registeredReceiversForUser = mReceiverResolver.queryIntent(intent, resolvedType, false /*defaultOnly*/, users[i]); if (registeredReceivers == null) { registeredReceivers = registeredReceiversForUser; } else if (registeredReceiversForUser != null) { registeredReceivers.addAll(registeredReceiversForUser); } } } else { //查询已注册的Receiver,在注册过程会被添加 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false /*defaultOnly*/, userId); } } final boolean replacePending = (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0; ... int NR = registeredReceivers != null ? registeredReceivers.size() : 0; if (!ordered && NR > 0) { ... //通过intent获得广播队列 final BroadcastQueue queue = broadcastQueueForIntent(intent); //将所有数据都封装到BroadcastRecord中 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); if (!replaced) { //将广播添加到queue的mParallelBroadcasts数组列表中 queue.enqueueParallelBroadcastLocked(r); queue.scheduleBroadcastsLocked(); } registeredReceivers = null; NR = 0; } ... return ActivityManager.BROADCAST_SUCCESS; } 

enqueueParallelBroadcastLocked函数将BroadcastRecord对象r添加到ArrayList类型的mParallelBroadcasts,后续执行队列事务会从其中取出。

scheduleBroadcastsLocked函数。调用BroadcastHandler类型的mHandler发送一个BROADCAST_INTENT_MSG消息。

#BroadcastQueue xxm public void scheduleBroadcastsLocked() { if (mBroadcastsScheduled) { return; } mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this)); mBroadcastsScheduled = true; } 

BroadcastHandlerhandleMessage函数。执行了processNextBroadcast函数。

#BroadcastHandler xxm public void handleMessage(Message msg) { switch (msg.what) { case BROADCAST_INTENT_MSG: { processNextBroadcast(true); } break; case BROADCAST_TIMEOUT_MSG: { synchronized (mService) { broadcastTimeoutLocked(true); } } break; } } 

processNextBroadcast函数内容太长了,主要是将粘性广播和无序广播发送给接收者。这里只看函数前半部分对无序广播的处理。其中无序广播是从mParallelBroadcasts取出所有广播,并遍历每个广播的过滤器filter,将广播和广播filter传递给deliverToRegisteredReceiverLocked函数

#BroadcastQueue xxm if (fromMsg) { mBroadcastsScheduled = false; } //遍历无序广播数组 while (mParallelBroadcasts.size() > 0) { r = mParallelBroadcasts.remove(0); ... final int N = r.receivers.size(); ... for (int i=0; i

deliverToRegisteredReceiverLocked函数。主要进行权限检查。

#BroadcastQueue xxm private void deliverToRegisteredReceiverLocked(BroadcastRecord r, BroadcastFilter filter, boolean ordered, int index) { boolean skip = false; ... //广播filter进行权限检查,不通过skip=true ... if (skip) { r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED; return; } ... r.delivery[index] = BroadcastRecord.DELIVERY_DELIVERED; ... performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver, new Intent(r.intent), r.resultCode, r.resultData, r.resultExtras, r.ordered, r.initialSticky, r.userId); ... } 

performReceiveLocked函数。如果接收者所在的进程已经启动,直接调用 app.thread.scheduleRegisteredReceiver,如果未启动,则直接回调 receiver.performReceive

#BroadcastQueue xxm void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver, Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) throws RemoteException { if (app != null) { if (app.thread != null) { try { app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode, data, extras, ordered, sticky, sendingUser, app.getReportedProcState()); } catch (RemoteException ex) { synchronized (mService) { app.scheduleCrash("can't deliver broadcast"); } throw ex; } } else { throw new RemoteException("app.thread must not be null"); } } else { receiver.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser); } } 

如果进程已经启动,则调用ApplicationThreadscheduleRegisteredReceiver函数。

public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent, int resultCode, String dataStr, Bundle extras, boolean ordered, boolean sticky, int sendingUser, int processState) throws RemoteException { updateProcessState(processState, false); receiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky, sendingUser); } 

调用了LoadedApk.ReceiverDispatcher.InnerReceiver类的performReceive函数。

public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { final LoadedApk.ReceiverDispatcher rd; if (intent == null) { rd = null; } else { rd = mDispatcher.get(); } if (rd != null) { //分析一 rd.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser); } else { IActivityManager mgr = ActivityManager.getService(); try { if (extras != null) { extras.setAllowFds(false); } mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } 

调用了分析 一ReceiverDispatcherperformReceive函数

public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { //分析1 final Args args = new Args(intent, resultCode, data, extras, ordered, sticky, sendingUser); ... //分析2 if (intent == null || !mActivityThread.post(args.getRunnable())) { if (mRegistered && ordered) { IActivityManager mgr = ActivityManager.getService(); args.sendFinished(mgr); } } } 

ReceiverDispatcher.performReceive函数中分析1将相关数据封装成内部类Args类型的args,然后在分析2通过Handler类型的mActivityThread执行getRunnable返回的Runable对象的run函数。这时切换到应用进程的主线程。

Args.getRunnable函数回调了我们注册广播是复写的onReceiver函数。

public final Runnable getRunnable() { return () -> { ... ClassLoader cl = mReceiver.getClass().getClassLoader(); intent.setExtrasClassLoader(cl); intent.prepareToEnterProcess(); setExtrasClassLoader(cl); receiver.setPendingResult(this); //调用广播接收者的onReceive receiver.onReceive(mContext, intent); ... } } 

总结

大道至简,所谓注册就是在每个地方维持一个集合,实现所谓的增删改查,根据业务需求增加不同逻辑,例如权限检查,接收者所在进程的状态。

以上就是详解Android广播Broadcast的启动流程的详细内容,更多关于Android Broadcast启动流程的资料请关注0133技术站其它相关文章!

以上就是详解Android广播Broadcast的启动流程的详细内容,更多请关注0133技术站其它相关文章!

赞(0) 打赏
未经允许不得转载:0133技术站首页 » 移动