基于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);            }        }    }}

  这里以一张简单的不规范类图来说明。
Android广播机制——广播的注册_第1张图片
  另外,一个应用可以动态注册多个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是一一对应。
Android广播机制——广播的注册_第2张图片

  在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在发送广播时获取动态注册广播接收器时使用;
- 最后,发送相应的粘性广播;

Android广播机制——广播的注册_第3张图片

  结合LoadedApk和ActivityManagerService的代码和上面的小图,可以最后得到一张总体的图,如下:
Android广播机制——广播的注册_第4张图片

更多相关文章

  1. Android原理之动态墙纸
  2. Windows Phone 7 不温不火学习之《Control Toolkit--静态和动态
  3. Android 如何动态设置View参数,LayoutParams.addRules详解,TypedVa
  4. 如何动态获取Android系统属性
  5. Android动态请求权限的工具类(可请求多个,并且功能完善)
  6. Android原理揭秘系列之动态墙纸
  7. 【Android】动态注册广播接收器
  8. Android产品研发(二十三)-->Android中保存静态秘钥实践
  9. Android动态权限(懒人自用)

随机推荐

  1. Android中的sp和dp的区别
  2. android,内存优化详解
  3. android效率为什么这么的高呢
  4. android进程间服务通信示例
  5. Unity3D研究院之与Android相互传递消息(十
  6. Android(安卓)内存优化
  7. Android(安卓)VideoView如何播放RTSP的流
  8. Android利用硬解硬编和OpenGLES来高效的
  9. Android中Styles、Themes、attrs介绍
  10. 轻松搞定 android MVP 架构、okHttp 网络