美文网首页androidAndroid源码解析Android技术知识
Android源码解析四大组件系列(五)---广播的注册过程

Android源码解析四大组件系列(五)---广播的注册过程

作者: LooperJing | 来源:发表于2017-07-17 17:41 被阅读815次

广播这个篇幅打算用四篇文章来写,分别为广播注册、广播处理、广播的发送,广播深入细节理解,如果都写到一篇文章会比较长,所以拆分成四篇来写。

第一篇
Android源码解析---广播的注册过程
第二篇
Android源码解析---广播的处理过程
第三篇
Android源码解析---广播的发送过程
第四篇
Android源码解析---广播深入细节理解

想收到广播(Broadcast),必须先要注册接收广播的组件---广播接收者(receiver),广播接收者的注册分为动态注册和静态注册,而注册中心就是AMS,AMS再把广播分发到各个广播接收者(receiver)。

image.png

一个广播可以有多个receiver来接收它,注册的方式分为两种,一种是静态注册,一种是动态注册,动态注册广播不是常驻型广播,也就是说广播跟随Activity的生命周期,在Activity结束前,需要移除广播接收器。 静态注册是常驻型,也就是说当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。

1.1 动态广播注册

动态注册是由ContextImpl的registerReceiver方法调用registerReceiverInternal来注册的

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) {
                 //AMS并不是直接给广播接收者发送广播的,当广播到达应用程序进程的时候,
      //会被封装成一个Message,然后push到主线程消息队列中,然后才会给接
      //收者处理,你也可以指定一个处理的Handler,将onReceive()调度在非主线程执行。
                   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 {
         //将rd,filter等发送给AMS
           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();
       }
   }

传进来的receiver不是直接发送给AMS的,首先会把receiver封装成一个IIntentReceiver对象rd,这个rd是一个binder本地对象,具备了跨进程通信的能力。mPackageInfo是LoadedApk,LoadedApk这个类包含了当前加载的apk的主要的信息,其中成员变量mReceivers表就记录了所有动态注册的receiver。

private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
      = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();

rd的获取有两种,当mPackageInfo存在时候,就通过mPackageInfo.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;
        //registered传进来的是true
           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 {
           //检查广播分发者的context、handler是否一致
               rd.validate(context, handler);
           }
           rd.mForgotten = false;
           return rd.getIIntentReceiver();
       }
   }

这个方法内部维护了一张表 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null,每一个广播接收者对应一个ReceiverDispatcher(广播分发者),并且把最后把这个map以Context为key存在mReceivers中,而这个Context跟广播的发送方有关系,如果是在Activity中发送的,这个Context就指向与这个Activity,如果是在Service中发送的,这个Context就指向了这个Service。那么这个广播分发者有什么用呢?用map来存储,表示ReceiverDispatcher跟BroadcastReceiver是一一对应的,每个广播接收者对应一个广播分发者, 当AMS向app发送广播时会调用到app进程的广播分发者,然后再将广播以message形式post到app的主线程,来执行onReceive()方法。

假设我的app只有两个Activity(HomeActivity和DetailActivity),这个app被打包成xxx.apk,那么在内存中,这个xxx.apk由LoadedApk来描述,如果HomeActivity和DetailActivity都注册了广播,那么LoadedApk内部维持的mReceivers的长度就为2。现在梳理一下上面的代码,当一个BroadcastReceiver要注册的时候,会优先使用Context查看一下,这个组件有没有注册过广播,如果有就取出来,类型是一个ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> 的map。如果没有,就把map创建出来,并且存到mReceivers中。有了map之后,需要把ReceiverDispatcher(广播分发者)存到map里面去。第一次注册时候,肯定走的是if(rd==null)的代码块里面,这样rd对象被创建出来。现在分析一下ReceiverDispatcher这个类。

static final class ReceiverDispatcher {

       final static class InnerReceiver extends IIntentReceiver.Stub {
           final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
           final LoadedApk.ReceiverDispatcher mStrongRef;

           InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
               mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
               mStrongRef = strong ? rd : null;
           }

       .......

       final IIntentReceiver.Stub mIIntentReceiver;
       final BroadcastReceiver mReceiver;
       final Context mContext;
       final Handler mActivityThread;
       .......
       ReceiverDispatcher(BroadcastReceiver receiver, Context context,
               Handler activityThread, Instrumentation instrumentation,
               boolean registered) {
           if (activityThread == null) {
               throw new NullPointerException("Handler must not be null");
           }
           mIIntentReceiver = new InnerReceiver(this, !registered);
           //广播接收者
           mReceiver = receiver;
           //表示哪个发送的广播
           mContext = context;
           //主线程
           mActivityThread = activityThread;
            .......
       }
       .......
       IIntentReceiver getIIntentReceiver() {
           return mIIntentReceiver;
       }
      .......
   }

在内部会创建InnerReceiver,InnerReceiver是ReceiverDispatcher的内部类,是一个实现Binder的本地对象,前面也说过了,最终是将一个InnerReceiver对象注册到了AMS中。

OK,绕了这么一大圈子,其实就是为了封装一个InnerReceiver用于和AMS通信,我也不知道谷歌这帮程序员怎么想的,有点麻烦。忽略跨进程的代码,现在由用户进程走到SystemServer进程了,即走到AMS的registerReceiver方法。

public Intent registerReceiver(IApplicationThread caller, String callerPackage,
           IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {
       enforceNotIsolatedCaller("registerReceiver");
       ArrayList<Intent> stickyIntents = null;
       ProcessRecord callerApp = null;
       int callingUid;
       int callingPid;
       synchronized(this) {
           if (caller != null) {
             //由caller获取当前进程对象
               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 = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
                   ALLOW_FULL_ONLY, "registerReceiver", callerPackage);

          //获取IntentFilter中的action
           Iterator<String> actions = filter.actionsIterator();
           if (actions == null) {
               ArrayList<String> noAction = new ArrayList<String>(1);
               noAction.add(null);
               actions = noAction.iterator();
           }

           //从actions中,先把粘性广播帅选出来,放进stickyIntents中
           int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
           while (actions.hasNext()) {
               String action = actions.next();
               for (int id : userIds) {
               //从mStickyBroadcasts中查看用户的sticky Intent,mStickyBroadcasts存了系统所有的粘性广播
                   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);
               // 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);
       //如果receiver为空,就直接返回了
       if (receiver == null) {
           return sticky;
       }

       synchronized (this) {
           if (callerApp != null && (callerApp.thread == null
                   || callerApp.thread.asBinder() != caller.asBinder())) {
               // 进程不存在(死亡了),也是不能注册成功的
               return null;
           }
          //mRegisteredReceivers表存了所有动态注册的广播接收者,
     //由receiver作为key,获取到ReceiverList,为什么是ReceiverList,
    //而不是一个Receiver呢,因为一个广播可能会有多个接收者,
     //最好整成一个队列或者链表的形式,而ReceiverList继承ArrayList,满足这个需求。
     //每个ReceiverList都对应着Client端的一个ReceiverDispatcher。
           ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
           if (rl == null) {
               rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                       userId, receiver);
               if (rl.app != null) {
                   //把广播接收者列表加到这个进程对象的receivers中
                   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);
           } 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);
           }
         //在AMS内部,广播接收者实际上是BroadcastFilter来描述的,
    //由filter等参数创建BroadcastFilter对象,并添加到接收者队列,
    //注意只有registerReceiver()过程才会创建BroadcastFilter,也就是该对
    //象用于动态注册的广播Receiver;,静态的接收者对象不是BroadcastFilter。
           BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                   permission, callingUid, userId);
           rl.add(bf);
           if (!bf.debugCheck()) {
               Slog.w(TAG, "==> For Dynamic broadcast");
           }
           mReceiverResolver.addFilter(bf);

           //如果是粘性广播,创建BroadcastRecord,并添加到
   //BroadcastQueue的并行广播队列(mParallelBroadcasts),
    //注册后调用AMS来尽快处理该广播。
           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();
               }
           }

         //返回值是一个Intent
           return sticky;
       }
   }

总结一下:动态注册是调用registerReceiver来注册的,大致流程如下:

在Android系统中,系统每加载一个apk,就会有一个LoadedApk对象。而每个LoadedApk对象里会有一张名字为mReceivers的HashMap,用来记录每个apk里面动态注册了那些广播接收者。mReceivers的类型是ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>>,泛型中的Context代表是谁注册的,后面的值也是个map ,ArrayMap<BroadcastReceiver, ReceiverDispatcher>表示BroadcastReceiver与ReceiverDispatcher一一对应,一个BroadcastReceiver对应一个ReceiverDispatcher,通过这个定义可以知道,不管一个Activity注册了多少BroadcastReceiver,ReceiverDispatcher只有一个。ReceiverDispatcher内部有一个InnerReceiver的Binder对象,最终是把这个InnerReceiver发送给了AMS,AMS内部也维护了一张表mRegisteredReceivers,用来记录所有动态注册的接收者,首先会根据传进来的InnerReceiver对象取出来一个ReceiverList,ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder()),所以实质上每个ReceiverList都对应着Client端的一个ReceiverDispatcher。最后把创建的对象BroadcastFilter(AMS内部广播接收者用BroadcastFilter来表示)加到ReceiverList接收者队列中,注册完毕!

1.2 静态广播注册

静态注册就是在manifest中注册。

<receiver android:name=".MyReceiver">
   <intent-filter>
       <action android:name="android.intent.action.MY_BROADCAST"/>
       <category android:name="android.intent.category.DEFAULT" />
   </intent-filter>
</receiver>

它们的信息会在系统启动时,由PackageManagerService(PMS)解析(在该类的构造方法中会对各个应用安装目录的apk文件进行扫描解析)并记录下来。

if (tagName.equals("activity")) {
               Activity a = parseActivity(owner, res, parser, flags, outError, false,
                       owner.baseHardwareAccelerated);
               if (a == null) {
                   mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                   return false;
               }
               owner.activities.add(a);
           } else if (tagName.equals("receiver")) {
               Activity a = parseActivity(owner, res, parser, flags, outError, true, false);
               if (a == null) {
                   mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                   return false;
               }
               owner.receivers.add(a);
           } else if (tagName.equals("service")) {
               Service s = parseService(owner, res, parser, flags, outError);
               if (s == null) {
                   mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                   return false;
               }
               owner.services.add(s);
           } else if (tagName.equals("provider")) {
               Provider p = parseProvider(owner, res, parser, flags, outError);
               if (p == null) {
                   mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
                   return false;
               }
               owner.providers.add(p);
           }

经过上面的解析receiver就被保存到了owner.receivers中去了。然后AM会调用PMS的接口来查询“和intent匹配的组件”时,PMS内部就会去查询当初记录下来的数据,并把结果返回AMS。

 List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
                       .queryIntentReceivers(intent, resolvedType, pmFlags, user).getList();
@Override
   public @NonNull ParceledListSlice<ResolveInfo> queryIntentReceivers(Intent intent,
           String resolvedType, int flags, int userId) {
       return new ParceledListSlice<>(
               queryIntentReceiversInternal(intent, resolvedType, flags, userId));
   }

   private @NonNull List<ResolveInfo> queryIntentReceiversInternal(Intent intent,
           String resolvedType, int flags, int userId) {
       if (!sUserManager.exists(userId)) return Collections.emptyList();
       flags = updateFlagsForResolve(flags, userId, intent);
       ComponentName comp = intent.getComponent();
       if (comp == null) {
           if (intent.getSelector() != null) {
               intent = intent.getSelector();
               comp = intent.getComponent();
           }
       }
       if (comp != null) {
           List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
           ActivityInfo ai = getReceiverInfo(comp, flags, userId);
           if (ai != null) {
               ResolveInfo ri = new ResolveInfo();
               ri.activityInfo = ai;
               list.add(ri);
           }
           return list;
       }

       // reader
       synchronized (mPackages) {
           String pkgName = intent.getPackage();
           if (pkgName == null) {
               return mReceivers.queryIntent(intent, resolvedType, flags, userId);
           }
           final PackageParser.Package pkg = mPackages.get(pkgName);
           if (pkg != null) {
               return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers,
                       userId);
           }
           return Collections.emptyList();
       }
   }

因为涉及PMS,这段逻辑想写清楚篇幅会比较大,所以,不深入讨论,以上关于广播的动态注册和静态注册就介绍完了。

相关文章

网友评论

  • 刘佳阔:Ams的registerReceiver中应该有错误, "由receiver作为key,获取到ReceiverList,为什么是ReceiverList,
        //而不是一个Receiver呢,因为一个广播可能会有多个接收者,
         //最好整成一个队列或者链表的形式,而ReceiverList继承ArrayList,"
    这里的ReceiverList是BroadcastFilter的集合,其实就是IntentFilter的封装.这里的一对多指的应该是一个广播接收者可能接受多个广播发射,也就是一个BroadcastReceiver对应多个IntentFilter才对.
  • jeffiano:文中提到 “ 表示BroadcastReceiver与ReceiverDispatcher一一对应,一个BroadcastReceiver对应一个ReceiverDispatcher,通过这个定义可以知道,不管一个Activity注册了多少BroadcastReceiver,ReceiverDispatcher只有一个。”前半句说是一对一的关系,后面说是多对一,是我理解有误差么??
    刘佳阔:我理解是原文表述的问题.BroadcastReceiver和ReceiverDispatcher是一对一的关系,如果一个Activity注册多个BroadcastReceiver,那么同时会有多个ReceiverDispatcher 才对.

本文标题:Android源码解析四大组件系列(五)---广播的注册过程

本文链接:https://www.haomeiwen.com/subject/ludfkxtx.html