广播是android四大组件之一,所以广播的重要性也是显而易见的,最近需要做个功能,需要对广播的机制深入了解,所以我就整理下思路。平时我们写代码的时候,广播只是用来通知机制的,不是用来通信机制,通信机制还是要用binder机制来实现。但是现在市场上的第三方app大部分都是滥用广播,用广播来监听一些事件来实现自启动或者后台启动。这就误解了谷歌的意思。本来很好的组件,被大家滥用,导致用户老是感觉手机的程序控制不住,老是后台偷偷启动。小白用户甚至更不理解了。好了现在言归正传。
android广播按发送方式分为三种:
- 无序广播
- 有序广播 :OrderedBroadcast
- 粘连广播 :StickyBroadcast
广播按照注册方式分为两种:
- 静态广播
动态广播
摘录老罗文章“广播机制是一种基于消息发布和订阅的事件驱动模型,即广播发送者负责发布消息,而广播接收者需要先订阅消息,然后才能接收到消息。在广播机制中,广播发送者事先不需要知道广播接收者的存在的,这样就能大大降低广播发送者和广播接收者之间的耦合度,进而提高系统的可扩展性和可维护性。”
广播的正真机制就两种情况,注册广播的机制,和接收广播的机制,我们先来谈谈注册广播的流程。
注册广播的流程:分为动态注册和静态注册两种;
(1)先来说说动态注册广播
Step1:说明: ReceiverDispatcher是frameworks/base/core/java/android/app/LoadedApk.java的内部类,这个类是保存广播接收者的组件(Activity或者Service),负责将这个被注册的广播接收者和注册它的组件关联在一起。
static final class ReceiverDispatcher { final static class InnerReceiver extends IIntentReceiver.Stub { . . . . . . . . . . . . } // 请注意这个域!它就是传到外面的rd。 final IIntentReceiver.Stub mIIntentReceiver; final BroadcastReceiver mReceiver; final Context mContext; final Handler mActivityThread; final Instrumentation mInstrumentation; final boolean mRegistered; final IntentReceiverLeaked mLocation; RuntimeException mUnregisterLocation; boolean mForgotten; . . . . . .
Step2:好了先说说需要了解的知识。registerReceiver(),是通过context来注册的,调用过程最后调用到ContextImpl这个对象中,
@Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { return registerReceiver(receiver, filter, null, null);}@Overridepublic Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) { return registerReceiverInternal(receiver, filter, broadcastPermission, scheduler, getOuterContext());}
Step3:我们接着来看看registerReceiverInternal()这个方法:
private Intent registerReceiverInternal(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler, Context context) { IIntentReceiver rd = null; if (receiver != null) { if (mPackageInfo != null && context != null) { if (scheduler == null) { scheduler = mMainThread.getHandler(); } // 查找和context对应的“子哈希表”里的ReceiverDispatcher,//如果找不到,就重新new一个 rd = mPackageInfo.getReceiverDispatcher(receiver, context, scheduler, mMainThread.getInstrumentation(), true); } else { if (scheduler == null) { scheduler = mMainThread.getHandler(); } rd = new LoadedApk.ReceiverDispatcher(..., ...); } . . . . . . } try { return ActivityManagerNative.getDefault().registerReceiver( mMainThread.getApplicationThread(), mBasePackageName, rd, filter, broadcastPermission); } catch (RemoteException e) { return null; }}
Step4:大家注意那个rd对象(IIntentReceiver rd),首先调用成员变量mPackageInfo的成员函数(是LoadedApk的一个对象)getReceiverDispatcher()将广播接收者receiver封装成一个实现了IIntentReceiver接口的Binder的本地对象rd,最后将这个对象发送给AcitivityManagerService。
接着来看看getReceiverDispatcher()这个方法:
public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r, Context context, Handler handler, Instrumentation instrumentation, boolean registered) { synchronized (mReceivers) { LoadedApk.ReceiverDispatcher rd = null; //注册过广播接收者与注册它的组件关联在一起 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null; //已经注册过了 if (registered) { 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<BroadcastReceiver, LoadedApk.ReceiverDispatcher>(); mReceivers.put(context, map); } map.put(r, rd); } } else { rd.validate(context, handler); } rd.mForgotten = false; //来获得一个实现了IIntentReceiver接口的Binder的本地对象 return rd.getIIntentReceiver(); } }IIntentReceiver getIIntentReceiver() { return mIIntentReceiver; }
Step5:接着来看看给mIIntentReceiver赋值的地方,
static final class ReceiverDispatcher { final static class InnerReceiver extends IIntentReceiver.Stub { final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher; final LoadedApk.ReceiverDispatcher mStrongRef; 。。。 。。。}ReceiverDispatcher(BroadcastReceiver receiver, Context context, Handler activityThread, Instrumentation instrumentation, boolean registered) { if (activityThread == null) { throw new NullPointerException("Handler must not be null"); } //指向了一个实现IIntentReceiver接口的Binder的本地对象 mIIntentReceiver = new InnerReceiver(this, !registered); mReceiver = receiver; mContext = context; mActivityThread = activityThread; mInstrumentation = instrumentation; mRegistered = registered; mLocation = new IntentReceiverLeaked(null); mLocation.fillInStackTrace(); }}
Step6:注意:这个InnerReceiver对象内部有一个类型为ReceiverDispatcher的弱引用mDispatcher,它指向一个外部的ReceiverDispatcher对象。
接着就注册到AMS中去了。代码如下:
public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission, int userId) { enforceNotIsolatedCaller("registerReceiver"); int callingUid; int callingPid; synchronized(this) { ProcessRecord callerApp = null; if (caller != null) {//得到调用者的ProcessRecord 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 != Process.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(); } userId = this.handleIncomingUser(callingPid, callingUid, userId, true, ALLOW_FULL_ONLY, "registerReceiver", callerPackage); List allSticky = null; // Look for any matching sticky broadcasts... Iterator actions = filter.actionsIterator(); if (actions != null) { while (actions.hasNext()) { String action = (String)actions.next(); allSticky = getStickiesLocked(action, filter, allSticky, UserHandle.USER_ALL); allSticky = getStickiesLocked(action, filter, allSticky, UserHandle.getUserId(callingUid)); } } else { allSticky = getStickiesLocked(null, filter, allSticky, UserHandle.USER_ALL); allSticky = getStickiesLocked(null, filter, allSticky, UserHandle.getUserId(callingUid)); } // The first sticky in the list is returned directly back to // the client.//判断黏性广播是否为null Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null; if (DEBUG_BROADCAST) Slog.v(TAG, "Register receiver " + filter + ": " + sticky); if (receiver == null) { return sticky; } ReceiverList rl //这段代码注意看,很有研究价值。 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder()); if (rl == null) {//如果rl为空就new一个 rl = new ReceiverList(this, callerApp, callingPid, callingUid, userId, receiver); if (rl.app != null) { rl.app.receivers.add(rl); } else { try { receiver.asBinder().linkToDeath(rl, 0); } catch (RemoteException e) { return sticky; } rl.linkedToDeath = true; } //把ReceiverList加入到mRegisteredReceivers mRegisteredReceivers.put(receiver.asBinder(), rl); } else if (rl.uid != callingUid) { throw new IllegalArgumentException( "Receiver requested to register for uid " + callingUid + " was previously registered for uid " + rl.uid); } else if (rl.pid != callingPid) { throw new IllegalArgumentException( "Receiver requested to register for pid " + callingPid + " was previously registered for pid " + rl.pid); } else if (rl.userId != userId) { throw new IllegalArgumentException( "Receiver requested to register for user " + userId + " was previously registered for user " + rl.userId); } BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission, callingUid, userId); rl.add(bf); if (!bf.debugCheck()) { Slog.w(TAG, "==> For Dynamic broadast"); } mReceiverResolver.addFilter(bf); // Enqueue broadcasts for all existing stickies that match // this filter. if (allSticky != null) { ArrayList receivers = new ArrayList(); receivers.add(bf); int N = allSticky.size(); for (int i=0; i<N; i++) { Intent intent = (Intent)allSticky.get(i); BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, null, null, -1, -1, null, null, AppOpsManager.OP_NONE, receivers, null, 0, null, null, false, true, true, -1); //发送黏连广播,和发送广播的流程一样 queue.enqueueParallelBroadcastLocked(r); queue.scheduleBroadcastsLocked(); } } return sticky; } }
好了今天就到这里吧,后续再整理。。。
(2)上面说的是动态注册广播的过程,接着我来谈谈静态注册广播的过程。
静态注册广播的信息会在手机启动时,由PackageManagerService(PMS)解析并记录下来,准备好数据。当AMS调用PMS的接口来查询“和intent匹配的组件”时,PMS内部就会去查询当初记录下来的数据,并把结果返回AMS。有的同学认为静态receiver是常驻内存的,这种说法并不准确。因为常驻内存的只是静态receiver的描述性信息,并不是receiver实体本身。
举个栗子:
List<ResolveInfo> newReceivers = AppGlobals.getPackageManager() .queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, user);
具体的queryIntentReceivers的实现就要参考PackageManagerService.java
在这个类中的实现,这里就不阐述这么多了。