美文网首页
Android 的广播发送跟接收(二)

Android 的广播发送跟接收(二)

作者: zy_zhangyuan88 | 来源:发表于2019-07-11 14:13 被阅读0次

    1、简介

    广播的发送者将广播发送到ActivityManagerService,ActivityManagerService接收到这个广播以后,就会在自己的注册中心查看有哪些广播接收器订阅了该广播,然后把这个广播逐一发送到这些广播接收器中,但是ActivityManagerService并不等待广播接收器处理这些广播就返回了,因此,广播的发送和处理是异步的。广播的发送路径就是从发送者到ActivityManagerService,再从ActivityManagerService 到接收者,这中间的两个过程都是通过Binder进程间通信机制来完成的。
    image.png

    2、源码分析:

    step1、先从调用的地方开始:Activity 中调用sendBroadcast方法,再调用ContextImpl 的sendBroadcast

    @Override
    public void sendBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess(this);
            ActivityManager.getService().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                    getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }
    

    ActivityManager.getService()获取AMS 调用broadcastIntent 方法

    final int broadcastIntentLocked(ProcessRecord callerApp,
            String callerPackage, Intent intent, String resolvedType,
            IIntentReceiver resultTo, int resultCode, String resultData,
            Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
            boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
        intent = new Intent(intent);
    
       
        ........
    
        // Figure out who all will receive this broadcast.
        List receivers = null;
        List<BroadcastFilter> registeredReceivers = null;
    
        if (intent.getComponent() == null) {
    
           
            } else {
                registeredReceivers = mReceiverResolver.queryIntent(intent,resolvedType, false
                 /*defaultOnly*/, userId);//    
            }
        }
        ..........
    
        final boolean replacePending =
                (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
    
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing broadcast: " + intent.getAction()
                + " replacePending=" + replacePending);
    
        int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
       
    
        // Merge into one list.
        int ir = 0;
        if (receivers != null) {
            // A special case for PACKAGE_ADDED: do not allow the package
            // being added to see this broadcast.  This prevents them from
            // using this as a back door to get run as soon as they are
            // installed.  Maybe in the future we want to have a special install
            // broadcast or such for apps, but we'd like to deliberately make
            // this decision.
            String skipPackages[] = null;
            if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
                    || Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
                    || Intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
                Uri data = intent.getData();
                if (data != null) {
                    String pkgName = data.getSchemeSpecificPart();
                    if (pkgName != null) {
                        skipPackages = new String[] { pkgName };
                    }
                }
            } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
                skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
            }
            if (skipPackages != null && (skipPackages.length > 0)) {
                for (String skipPackage : skipPackages) {
                    if (skipPackage != null) {
                        int NT = receivers.size();
                        for (int it=0; it<NT; it++) {
                            ResolveInfo curt = (ResolveInfo)receivers.get(it);
                            if (curt.activityInfo.packageName.equals(skipPackage)) {
                                receivers.remove(it);
                                it--;
                                NT--;
                            }
                        }
                    }
                }
            }
    
            int NT = receivers != null ? receivers.size() : 0;
            int it = 0;
            ResolveInfo curt = null;
            BroadcastFilter curr = null;
            while (it < NT && ir < NR) {
                if (curt == null) {
                    curt = (ResolveInfo)receivers.get(it);
                }
                if (curr == null) {
                    curr = registeredReceivers.get(ir);
                }
                if (curr.getPriority() >= curt.priority) {
                    // Insert this broadcast record into the final list.
                    receivers.add(it, curr);
                    ir++;
                    curr = null;
                    it++;
                    NT++;
                } else {
                    // Skip to the next ResolveInfo in the final list.
                    it++;
                    curt = null;
                }
            }
        }
        while (ir < NR) {
            if (receivers == null) {
                receivers = new ArrayList();
            }
            receivers.add(registeredReceivers.get(ir));
            ir++;
        }
    
        if (isCallerSystem) {
            checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
                    isProtectedBroadcast, receivers);
        }
    
        if ((receivers != null && receivers.size() > 0)
                || resultTo != null) {
            BroadcastQueue queue = broadcastQueueForIntent(intent);
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
                    requiredPermissions, appOp, brOptions, receivers, resultTo, resultCode,
                    resultData, resultExtras, ordered, sticky, false, userId);
    
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r
                    + ": prev had " + queue.mOrderedBroadcasts.size());
            if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
                    "Enqueueing broadcast " + r.intent.getAction());
    
            final BroadcastRecord oldRecord =
                    replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
            if (oldRecord != null) {
                // Replaced, fire the result-to receiver.
                if (oldRecord.resultTo != null) {
                    final BroadcastQueue oldQueue = broadcastQueueForIntent(oldRecord.intent);
                    try {
                        oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo,
                                oldRecord.intent,
                                Activity.RESULT_CANCELED, null, null,
                                false, false, oldRecord.userId);
                    } catch (RemoteException e) {
                        Slog.w(TAG, "Failure ["
                                + queue.mQueueName + "] sending broadcast result of "
                                + intent, e);
    
                    }
                }
            } else {
                queue.enqueueOrderedBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();
            }
        } else {
            // There was nobody interested in the broadcast, but we still want to record
            // that it happened.
            if (intent.getComponent() == null && intent.getPackage() == null
                    && (intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
                // This was an implicit broadcast... let's record it for posterity.
                addBroadcastStatLocked(intent.getAction(), callerPackage, 0, 0, 0);
            }
        }
    
        return ActivityManager.BROADCAST_SUCCESS;
    }
    
    解读一下:1、这里就通过mReceiverResolver.queryIntent函数将这个BroadcastFilter实例取回来。由于注册一个广播类型的接收器可能有多个,所以这里把所有符合条件的的BroadcastFilter实例放在一个List中,然后返回来。在我们这个场景中,这个List就只有一个BroadcastFilter实例。

    2、final boolean replacePending = (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;对这个方法是这里是查看一下这个intent的Intent.FLAG_RECEIVER_REPLACE_PENDING位有没有设置,如果设置了的话,ActivityManagerService就会在当前的系统中查看有没有相同的intent还未被处理,如果有的话,就有当前这个新的intent来替换旧的intent。这里,我们没有设置intent的Intent.FLAG_RECEIVER_REPLACE_PENDING位,因此,这里的replacePending变量为false
    3、最后会调用 queue.enqueueOrderedBroadcastLocked(r);
    queue.scheduleBroadcastsLocked();这个queue是BroadcastQueue类。将BroadcastRecord 加入到队列中。
    4、看看scheduleBroadcastsLocked方法。
    public void scheduleBroadcastsLocked() {
    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
    + mQueueName + "]: current="
    + mBroadcastsScheduled);

        if (mBroadcastsScheduled) {
            return;
        }
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }
    
    private final class BroadcastHandler extends Handler {
        public BroadcastHandler(Looper looper) {
            super(looper, null, true);
        }
    
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case BROADCAST_INTENT_MSG: {
                    if (DEBUG_BROADCAST) Slog.v(
                            TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
                    processNextBroadcast(true);
                } break;
                case BROADCAST_TIMEOUT_MSG: {
                    synchronized (mService) {
                        broadcastTimeoutLocked(true);
                    }
                } break;
            }
        }
    }
    

    然后调用processNextBroadcast 来send 广播消息,具体看这个方法
    public final class ActivityManagerService extends ActivityManagerNative
    implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
    ......

    private final void processNextBroadcast(boolean fromMsg) {
        synchronized(this) {
            BroadcastRecord r;
    
            ......
    
            if (fromMsg) {
                mBroadcastsScheduled = false;
            }
    
            // First, deliver any non-serialized broadcasts right away.
            while (mParallelBroadcasts.size() > 0) {
                r = mParallelBroadcasts.remove(0);
                ......
                final int N = r.receivers.size();
                ......
                for (int i=0; i<N; i++) {
                    Object target = r.receivers.get(i);
                    ......
    
                    deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false);
                }
                addBroadcastToHistoryLocked(r);
                ......
            }
    
            ......
    
        }
    }
    
    ......
    

    }

    这里传进来的参数fromMsg为true,于是把mBroadcastScheduled重新设为false,这样,下一个广播就能进入到消息队列中进行处理了。前面我们在Step 5中,把一个广播记录块BroadcastRecord放在了mParallelBroadcasts中,因此,这里就把它取出来进行处理了。广播记录块BroadcastRecord的receivers列表中包含了要接收这个广播的目标列表,即前面我们注册的广播接收器,用BroadcastFilter来表示,这里while循环中的for循环就是把这个广播发送给每一个订阅了该广播的接收器了,通过deliverToRegisteredReceiverLocked函数执行。


    image.png

    然后调用performReceiveLocked方法,当看到截图中的scheduleRegisteredReceiver,回到ActivityThread中


    image.png

    在上一节我分享过这个receiver.performReceive,这个receiver实际上是LoadedApk.ReceiverDispatcher


    image.png

    然后调用LoadedApk.ReceiverDispatcher.中performReceive方法


    1

    图中截图就是收到消息地方
    public final Runnable getRunnable() {
    return () -> {
    final BroadcastReceiver receiver = mReceiver;
    final boolean ordered = mOrdered;

                    .........
                    try {
                        ClassLoader cl = mReceiver.getClass().getClassLoader();
                        intent.setExtrasClassLoader(cl);
                        intent.prepareToEnterProcess();
                        setExtrasClassLoader(cl);
                        receiver.setPendingResult(this);
                        //回调接收消息的地方
                        receiver.onReceive(mContext, intent);
                    } catch (Exception e) {
                        if (mRegistered && ordered) {
                            if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                    "Finishing failed broadcast to " + mReceiver);
                            sendFinished(mgr);
                        }
                        if (mInstrumentation == null ||
                                !mInstrumentation.onException(mReceiver, e)) {
                            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                            throw new RuntimeException(
                                    "Error receiving broadcast " + intent
                                            + " in " + mReceiver, e);
                        }
                    }
    
                    if (receiver.getPendingResult() != null) {
                        finish();
                    }
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                };
            }
    

    到此处消息发送到接收完成
    最后,我们总结一下这个Android应用程序发送广播的过程:

           1. ,计数器服务CounterService通过sendBroadcast把一个广播通过Binder进程间通信机制发送给ActivityManagerService,ActivityManagerService根据这个广播的Action类型找到相应的广播接收器,然后把这个广播放进自己的消息队列中去,就完成第一阶段对这个广播的异步分发了;
    
        2. ,ActivityManagerService在消息循环中处理这个广播,并通过Binder进程间通信机制把这个广播分发给注册的广播接收分发器ReceiverDispatcher,ReceiverDispatcher把这个广播放进MainActivity所在的线程的消息队列中去,就完成第二阶段对这个广播的异步分发了;
    
        3. , ReceiverDispatcher的内部类Args在MainActivity所在的线程消息循环中处理这个广播,最终是将这个广播分发给所注册的BroadcastReceiver实例的onReceive函数进行处理。
    

    作者:罗升阳
    来源:CSDN
    原文:https://blog.csdn.net/luoshengyang/article/details/6744448
    版权声明:本文为博主原创文章,转载请附上博文链接!

    相关文章

      网友评论

          本文标题:Android 的广播发送跟接收(二)

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