Android广播机制——广播的注册
基于Android 7.0源码,分析Android广播机制的注册过程。
一、概述
简单地说,Android广播机制的主要工作是为了实现一处发生事情,多处得到通知的效果,这种通知工作常常要牵涉跨进程通讯,实现广播的功能时,需要一方注册广播接收器,另外一方需要发送广播。由于注册广播接收器和发送广播的过程比较长,这里分成两篇文章讲解,本篇主要说说注册广播接收器的过程。
注册广播接收器可以通过两种方式————静态注册、动态注册。
二、静态注册
静态注册时,是通过在AndroidManifest.xml中配置
<receiver android:name="com.example.my_broadcast.MyBroadcastReceiver" > <intent-filter> <action android:name="com.android.broadcasttest.NEW_LIFEFROM" /> intent-filter>receiver>
配置了以上信息之后,只要是com.android.broadcasttest.NEW_LIFEFROM这个地址的广播,MyBroadcastReceiver都能够接收的到。
注意,这种方式的注册是常驻型的,也就是说当应用进程不存在时,如果有该粘性广播信息传来,MyBroadcastReceiver所在的应用进程会先被系统拉起,随后自动运行。
另外,还有如下intent-filter
<intent-filter . . . > <category android:name="android.Intent.Category.DEFAULT" /> <category android:name="android.Intent.Category.BROWSABLE" />intent-filter><intent-filter . . . > <data android:type="video/mpeg" android:scheme="http" . . . /> <data android:type="audio/mpeg" android:scheme="http" . . . />intent-filter>
它们的信息会在系统启动时,由PackageManagerService解析并记录下来。以后,当AMS调用PKMS的接口来查询“和intent匹配的组件”时,PKMS内部就会去查询当初记录下来的数据,并把结果返回AMS。有的同学认为静态receiver是常驻内存的,这种说法并不准确。因为常驻内存的只是静态receiver的描述性信息,并不是receiver实体本身。
静态注册的具体过程需要比较熟悉包管理的代码,这里暂时略去,后面详细看过PackageManagerService的代码后,在回来补上。
三、动态注册
动态注册需要在代码中动态的指定广播地址并注册,通常我们是在Activity或Service使用registerReceiver注册广播接收器:
registerReceiver(BroadcastReceiver receiver, IntentFilter filter)registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler)
IntentFileter类成员:
private int mPriority;private final ArrayList mActions;private ArrayList mCategories = null;private ArrayList mDataSchemes = null;private ArrayList mDataSchemeSpecificParts = null;private ArrayList mDataAuthorities = null;private ArrayList mDataPaths = null;private ArrayList mDataTypes = null;
注意,动态注册方式与静态注册相反,不是常驻型的,也就是说广播接收器的生命周期会跟随程序的生命周期。
我们以两个参数的registerReceiver接口为例,来分析一下动态注册的具体流程。
registerReceiver是android.content.ContextWrapper类中的方法,Activity和Service都继承了ContextWrapper,而ContextWrapper的具体实现者又是ContextImpl。
1. ContextImpl.registerReceiver
[===>frameworks\base\core\java\android\app\ContextImpl.java]
@Override public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) { return registerReceiver(receiver, filter, null, null); } @Override public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler) { return registerReceiverInternal(receiver, getUserId(), filter, broadcastPermission, scheduler, getOuterContext()); }
传入的receiver参数一般是用户自定义并继承自BroadcastReceiver类。
2. ContextImpl.registerReceiverInternal
[===>frameworks\base\core\java\android\app\ContextImpl.java]
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId, 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(); } 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 = ActivityManagerNative.getDefault().registerReceiver( mMainThread.getApplicationThread(), mBasePackageName, rd, filter, broadcastPermission, userId); if (intent != null) { intent.setExtrasClassLoader(getClassLoader()); intent.prepareToEnterProcess(); } return intent; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
从以上的代码可以看出,动态注册的BroadcastReceiver和ReceiverDispatcher存在着一一对应的关系。
广播最终是通过AMS递送出去,AMS利用binder机制,将语义传递给各个应用进程,应用进程再辗转调用到receiver的onReceive()中以完成这次广播。而IIntentReceiver类型的rd对象正是承担“语义传递工作“的binder实体。
ReceiverDispatcher类就可以看成是这类binder实体的管理者或者是承载者。
static final class ReceiverDispatcher { final static class InnerReceiver extends IIntentReceiver.Stub { final WeakReference mDispatcher; final LoadedApk.ReceiverDispatcher mStrongRef; InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) { mDispatcher = new WeakReference(rd); mStrongRef = strong ? rd : null; } @Override public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { final LoadedApk.ReceiverDispatcher rd; if (intent == null) { Log.wtf(TAG, "Null intent received"); rd = null; } else { rd = mDispatcher.get(); } if (rd != null) { rd.performReceive(intent, resultCode, data, extras, ordered, sticky, sendingUser); } else { IActivityManager mgr = ActivityManagerNative.getDefault(); try { if (extras != null) { extras.setAllowFds(false); } mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } } final IIntentReceiver.Stub mIIntentReceiver; //注意,它就是传到外面的rd final BroadcastReceiver mReceiver; final Context mContext; final Handler mActivityThread; final Instrumentation mInstrumentation; ReceiverDispatcher(BroadcastReceiver receiver, Context context, Handler activityThread, Instrumentation instrumentation, boolean registered) { mIIntentReceiver = new InnerReceiver(this, !registered); mReceiver = receiver; mContext = context; mActivityThread = activityThread; mInstrumentation = instrumentation; } public void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered, boolean sticky, int sendingUser) { final Args args = new Args(intent, resultCode, data, extras, ordered, sticky, sendingUser); if (intent == null || !mActivityThread.post(args)) { if (mRegistered && ordered) { IActivityManager mgr = ActivityManagerNative.getDefault(); if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG, "Finishing sync broadcast to " + mReceiver); args.sendFinished(mgr); } } }}
这里以一张简单的不规范类图来说明。
另外,一个应用可以动态注册多个BroadcastReceiver,即应用和BroadcastReceiver是一个一对多的关系,反映这种关系的代码位于LoadedApk中,在LoadedApk中有一个成员变量mReceivers。应用进程里是使用LoadedApk来指代一个apk的,进程里有多少个apk,就有多少个LoadedApk。
private final ArrayMap> mReceivers = new ArrayMap>();
该表的key项是Context,也就是说可以是Activity、Service或Application。而value项则是另一张“子ArrayMap”。这是个“表中表”的形式。言下之意就是,每个Context(比如一个activity),是可以注册多个receiver的,这个很好理解。mReceivers里的“子ArrayMap”的key值为BroadcastReceiver,value项为ReceiverDispatcher,即反映了动态BroadcastReceiver和ReceiverDispatcher是一一对应。
在ContextImpl.registerReceiverInternal的最后,会调用:
final Intent intent = ActivityManagerNative.getDefault().registerReceiver( mMainThread.getApplicationThread(), mBasePackageName, rd, filter, broadcastPermission, userId);
通过Binder机制会最终调用到ActivityManagerService.registerReceiver中。
3. ActivityManagerService.registerReceiver
[===>frameworks\base\services\core\java\com\android\server\am\ActivityManagerService.java]
public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { final HashMap mRegisteredReceivers = new HashMap<>(); final IntentResolver mReceiverResolver = new IntentResolver() { ... };//发送广播时,获取动态注册广播接收器时使用 final SparseArray>> mStickyBroadcasts = new SparseArray>>(); public Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String permission, int userId) { ArrayList stickyIntents = null; ProcessRecord callerApp = null; int callingUid; int callingPid; synchronized(this) { // 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); } } } } } 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 < N; i++) { Intent intent = stickyIntents.get(i); if (filter.match(resolver, intent, true, TAG) >= 0) { if (allSticky == null) { allSticky = new ArrayList(); } 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 (receiver == null) { return sticky; } synchronized (this) { ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder()); if (rl == null) { 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; } mRegisteredReceivers.put(receiver.asBinder(), rl); } BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, permission, callingUid, userId); 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, -1, -1, null, null, AppOpsManager.OP_NONE, null, receivers, null, 0, null, null, false, true, true, -1); queue.enqueueParallelBroadcastLocked(r); queue.scheduleBroadcastsLocked(); } } return sticky; } }}
我们知道,对于同一个BroadcastReceiver对象,是可以注册多个IntentFilter的,这些IntentFilter信息会存放到AMS的mRegisteredReceivers表中。
在AMS端,可以通过以下代码访问相应的汇总表:
ReceiverList rl = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
其中的receiver参数为IIntentReceiver类型,正对应着ReceiverDispatcher中那个binder实体成员变量mIIntentReceiver。换句话说就是,每个客户端的ReceiverDispatcher,会对应AMS端的一个ReceiverList。
final class ReceiverList extends ArrayList<BroadcastFilter> implements IBinder.DeathRecipient { ...}
final class BroadcastFilter extends IntentFilter { // Back-pointer to the list this filter is in. final ReceiverList receiverList; ...}
ReceiverList继承自ArrayList,BroadcastFilter继承自IntentFilter,那么ReceiverList可以看成是IntentFilter数组列表。
上面代码的大致工作主要是以下四个:
- 根据userId和intentfiler过滤后,得到相应的粘性广播列表;
- 根据userId、IIntentReceiver等信息创建ReceiverList,存放到AMS.mRegisteredReceivers中,key值为IIntentReceiver;
- 创建BroadcastFilter,将它分别添加到ReceiverList中,同时添加到AMS.mReceiverResolver中,mReceiverResolver在发送广播时获取动态注册广播接收器时使用;
- 最后,发送相应的粘性广播;
结合LoadedApk和ActivityManagerService的代码和上面的小图,可以最后得到一张总体的图,如下:
更多相关文章
- Android原理之动态墙纸
- Windows Phone 7 不温不火学习之《Control Toolkit--静态和动态
- Android 如何动态设置View参数,LayoutParams.addRules详解,TypedVa
- 如何动态获取Android系统属性
- Android动态请求权限的工具类(可请求多个,并且功能完善)
- Android原理揭秘系列之动态墙纸
- 【Android】动态注册广播接收器
- Android产品研发(二十三)-->Android中保存静态秘钥实践
- Android动态权限(懒人自用)