美文网首页
跨进程广播的工作原理(1)

跨进程广播的工作原理(1)

作者: snake_6d77 | 来源:发表于2019-06-13 17:15 被阅读0次

    广播的注册

    从实现原理看上,Android中的广播使用了观察者模式,基于消息的发布/订阅事件模型。因此,从实现的角度来看,Android中的广播将广播的发送者和接受者极大程度上解耦,使得系统能够方便集成,更易扩展。

    分析android跨进程广播,此次从动态广播使用流程来深入阅读源码,毕竟相比静态广播而言动态广播的使用有头有尾,比较容易找到切入口。

    从registerReceiver开始

    通常我们动态注册广播都会调用Context.registerReceiver(BroadcastReceiver receiver,IntentFilter filter)方法,Context可以是Activity、Application以及Service等继承ContextWrapper的类,ContextWrapper实现了Context中的抽象方法registerReceiver(BroadcastReceiver receiver,IntentFilter filter);

    image.png

    如果你花时间详细研究,你会发现Activity、Application、Service等类的mBase都是ContextImpl的实例化对象,所以调用Context.registerReceiver(BroadcastReceiver receiver,IntentFilter filter)方法都会跑到ContextImpl类的registerReceiver方法,而沿着registerReceiver一直找下去最终会走到ContextImpl类的registerReceiverInternal方法:

        private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
                IntentFilter filter, String broadcastPermission,
                Handler scheduler, Context context, int flags) {
            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 = ActivityManager.getService().registerReceiver(
                        mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
                        broadcastPermission, userId, flags);
                if (intent != null) {
                    intent.setExtrasClassLoader(getClassLoader());
                    intent.prepareToEnterProcess();
                }
                return intent;
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    

    从上面的源码可以看出,应用进程端只做了两件事:
    1、创建广播分发器,可能用来后续分发广播,此处暂时不关注分发器究竟干了什么,等发送广播并分发到应用进程后再分析;
    2、调用系统服务接口触发真正的广播注册,并把广播分发器传递到系统服务中。

    所以接下来我们要看系统服务端运行的代码,主要是对ActivityManagerService里面的逻辑进行分析,ActivityManagerService 类继承AIDL接口IActivityManager.Stub,是各应用进程与系统服务交互的接口之一,应用进程内很多功能都与之息息相关。接下来我们继续研读ActivityManagerService的registerReceiver方法:

        public Intent registerReceiver(IApplicationThread caller, String callerPackage,
                IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
                int flags) {
            enforceNotIsolatedCaller("registerReceiver");
            ArrayList<Intent> stickyIntents = null;
            ProcessRecord callerApp = null;
            final boolean visibleToInstantApps
                    = (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;
            int callingUid;
            int callingPid;
            boolean instantApp;
            synchronized(this) {
                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 != 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();
                }
                //判断是不是Instant APP
                instantApp = isInstantApp(callerApp, callerPackage, callingUid);
                //获取当前请求的用户Id
                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();
                }
    
                // Collect stickies of users 通过action获取所有的粘性广播意图
                int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
                while (actions.hasNext()) {
                    String action = actions.next();
                    for (int id : userIds) {
                        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);
                            }
                        }
                    }
                }
            }
            //在匹配action的所有意图里筛选出匹配filter的粘性意图
            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);
                    // Don't provided intents that aren't available to instant apps.
                    if (instantApp &&
                            (intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
                        continue;
                    }
                    // 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);
            if (receiver == null) {
                return sticky;
            }
    
            synchronized (this) {
                if (callerApp != null && (callerApp.thread == null
                        || callerApp.thread.asBinder() != caller.asBinder())) {
                    // Original caller already died
                    return null;
                }
                //mRegisteredReceivers是HashMap<IBinder, ReceiverList>对象
                ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
                if (rl == null) {
                    //ReceiverList保存了关键的ProcessRecord进程记录对象以及应用进程的广播分发器
                    rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                            userId, receiver);
                    if (rl.app != null) {
                      //此处的 rl.app就是callerApp,也就是ProcessRecord实例化对象,
                      //里面保存了相应进程的所有广播接收者
                        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
                            + " callerPackage is " + callerPackage);
                } else if (rl.pid != callingPid) {
                    throw new IllegalArgumentException(
                            "Receiver requested to register for pid " + callingPid
                            + " was previously registered for pid " + rl.pid
                            + " callerPackage is " + callerPackage);
                } else if (rl.userId != userId) {
                    throw new IllegalArgumentException(
                            "Receiver requested to register for user " + userId
                            + " was previously registered for user " + rl.userId
                            + " callerPackage is " + callerPackage);
                }
                //生成广播过滤器,并添加进广播意图解析器中
                BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                        permission, callingUid, userId, instantApp, visibleToInstantApps);
                rl.add(bf);
                if (!bf.debugCheck()) {
                    Slog.w(TAG, "==> For Dynamic broadcast");
                }
                mReceiverResolver.addFilter(bf);
    
                // Enqueue broadcasts for all existing stickies that match this filter.
                // 遍历已经存在的且匹配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);
                        //根据Intent的FLAG来获取前台广播或后台广播队列
                        BroadcastQueue queue = broadcastQueueForIntent(intent);
                        //创建广播记录对象
                        BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                                null, -1, -1, false, null, null, AppOpsManager.OP_NONE, null, receivers,
                                null, 0, null, null, false, true, true, -1);
                        queue.enqueueParallelBroadcastLocked(r);
                        //此方法里面一顿操作,然后把能发的粘性广播发出去了....
                        queue.scheduleBroadcastsLocked();
                    }
                }
                return sticky;
            }
        }
    

    基本上把上面的注册源码读完后,我们可以总结上面到底干了什么:
    1、获取并处理ProcessRecord应用进程记录对象,ProcessRecord对象与广播接收者的注册可谓是息息相关。ProcessRecord对象估计是在进程创建的时候就已经创建了,ProcessRecord里面保存了四大组件等许多重要信息。后续的广播回调应用进程估计都会围绕ProcessRecord对象做处理。
    2、整个方法花了很大的篇幅去处理粘性广播;通过IntentFilter里面的action去找已经存在的粘性广播,最后在广播接收者注册成功后把匹配的粘性广播发给了这次注册的广播接收者
    3、整个方法最重要的估计就是mRegisteredReceivers.put(receiver.asBinder(), rl)和mReceiverResolver.addFilter(bf)了,在各种封装后终于把IIntentReceiver广播分发器和ApplicationThread保存了起来。

    相关文章

      网友评论

          本文标题:跨进程广播的工作原理(1)

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