美文网首页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