美文网首页
Android源码学习-BroadcastReceiver工作流

Android源码学习-BroadcastReceiver工作流

作者: m1Ku | 来源:发表于2019-07-09 17:55 被阅读0次

    介绍

    广播接收者作为四大组件之一,使用时需继承BroadcastReceiver并实现onReceive方法,再将其进行注册后,就可以发送和接收广播了。

    private class MyBroadcastReceiver extends BroadcastReceiver{
    
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.e("m1ku","接收到广播");
        }
    }
    
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction("com.m1ku.MyBroadcastReceiver");
    registerReceiver(new MyBroadcastReceiver(),intentFilter);
    
    Intent intent = new Intent();
    intent.setAction("com.m1ku.MyBroadcastReceiver");
    sendBroadcast(intent);
    

    源码分析

    广播的主要工作流程分为注册以及发送接收广播,这里分析普通广播的两个工作流程的源码。

    广播的动态注册

    调用ContextWrapper的registerReceiver

    @Override
    public Intent registerReceiver(
        BroadcastReceiver receiver, IntentFilter filter) {
        return mBase.registerReceiver(receiver, filter);
    }
    

    具体实现还是由ContextImpl的方法完成

    @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(), 0);
    }
    

    继续调用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();
        }
    }
    

    由于这里涉及到IPC通信,而广播接收者不能跨进程传输,所以这里通过getReceiverDispatcher方法将其转换为ReceiverDispatcher.InnerReceiver对象,它继承自IIntentReceiver.Stub是一个Binder接口,可以进行跨进程传递,而IntentFilter本身就实现了Parcelable接口。接下来远程调用了AMS的registerReceiver方法。

    public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
                                   int flags) {
          //...
          mRegisteredReceivers.put(receiver.asBinder(), rl);
          //...
          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);
          //...
    }
    

    在该方法中将ReceiverDispatcher.InnerReceiver对象和IntentFilter对象保存起来就完成广播的动态注册过程。

    广播发送和接收

    调用sendBroadcast方法发送广播

    @Override
    public void sendBroadcast(Intent intent) {
        mBase.sendBroadcast(intent);
    }
    

    实现依然在ContextImpl中

    @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();
        }
    }
    

    远程调用AMS的broadcastIntent方法

    public final int broadcastIntent(IApplicationThread caller,
            Intent intent, String resolvedType, IIntentReceiver resultTo,
            int resultCode, String resultData, Bundle resultExtras,
            String[] requiredPermissions, int appOp, Bundle bOptions,
            boolean serialized, boolean sticky, int userId) {
            //...
        synchronized(this) {
            //...
            int res = broadcastIntentLocked(callerApp,
                    callerApp != null ? callerApp.info.packageName : null,
                    intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
                    requiredPermissions, appOp, bOptions, serialized, sticky,
                    callingPid, callingUid, userId);
            Binder.restoreCallingIdentity(origId);
            return res;
        }
    }
    
    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) {
      //...
      // By default broadcasts do not go to stopped apps.
            intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
      //...
        int[] users;
            if (userId == UserHandle.USER_ALL) {
                // Caller wants broadcast to go to all started users.
                users = mUserController.getStartedUserArrayLocked();
            } else {
                // Caller wants broadcast to go to one specific user.
                users = new int[] {userId};
            }
    
            // Figure out who all will receive this broadcast.
            List receivers = null;
            List<BroadcastFilter> registeredReceivers = null;
            // Need to resolve the intent to interested receivers...
            if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
                     == 0) {
                receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
            }
            if (intent.getComponent() == null) {
                if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
                    // Query one target user at a time, excluding shell-restricted users
                    for (int i = 0; i < users.length; i++) {
                        if (mUserController.hasUserRestriction(
                                UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
                            continue;
                        }
                        List<BroadcastFilter> registeredReceiversForUser =
                                mReceiverResolver.queryIntent(intent,
                                        resolvedType, false /*defaultOnly*/, users[i]);
                        if (registeredReceivers == null) {
                            registeredReceivers = registeredReceiversForUser;
                        } else if (registeredReceiversForUser != null) {
                            registeredReceivers.addAll(registeredReceiversForUser);
                        }
                    }
                } 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;
            if (!ordered && NR > 0) {
                // If we are not serializing this broadcast, then send the
                // registered receivers separately so they don't wait for the
                // components to be launched.
                if (isCallerSystem) {
                    checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
                            isProtectedBroadcast, registeredReceivers);
                }
                final BroadcastQueue queue = broadcastQueueForIntent(intent);
                BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                        callerPackage, callingPid, callingUid, callerInstantApp, resolvedType,
                        requiredPermissions, appOp, brOptions, registeredReceivers, resultTo,
                        resultCode, resultData, resultExtras, ordered, sticky, false, userId);
                if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
                final boolean replaced = replacePending
                        && (queue.replaceParallelBroadcastLocked(r) != null);
                // Note: We assume resultTo is null for non-ordered broadcasts.
                if (!replaced) {
                    queue.enqueueParallelBroadcastLocked(r);
                    queue.scheduleBroadcastsLocked();
                }
                registeredReceivers = null;
                NR = 0;
            }
    }
    

    首先为intent添加一个flag:FLAG_EXCLUDE_STOPPED_PACKAGES,这个flag意思是已经结束的应用不会收到广播。mReceiverResolver已经在注册广播时进行保存赋值,调用mReceiverResolver.queryIntent方法根据传递来的广播的intent查找到匹配的intent-filter列表registeredReceiversForUser,然后使用广播队列queue和registeredReceivers构建了一个BroadcastRecord对象,调用queue.enqueueParallelBroadcastLocked将这个BroadcastRecord保存到mParallelBroadcasts集合中。最后调用queue.scheduleBroadcastsLocked方法将广播发送给指定的接收者

    public void scheduleBroadcastsLocked() {
        //...
        if (mBroadcastsScheduled) {
            return;
        }
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }
    

    使用mHandler发送一个BROADCAST_INTENT_MSG的消息,在handleMessage中调用processNextBroadcast方法

    final void processNextBroadcast(boolean fromMsg) {
      BroadcastRecord r;
      //...
        // First, deliver any non-serialized broadcasts right away.
                while (mParallelBroadcasts.size() > 0) {
                    r = mParallelBroadcasts.remove(0);
                    r.dispatchTime = SystemClock.uptimeMillis();
                    r.dispatchClockTime = System.currentTimeMillis();
                                    //...
                    final int N = r.receivers.size();
                    for (int i=0; i<N; i++) {
                        Object target = r.receivers.get(i);
                        //...
                        deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
                    }
                                //...
                }
    }
    

    遍历接收者并调用deliverToRegisteredReceiverLocked方法

    private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
                                                   BroadcastFilter filter, boolean ordered, int index) {
      //...
                      performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                            new Intent(r.intent), r.resultCode, r.resultData,
                            r.resultExtras, r.ordered, r.initialSticky, r.userId);
      //...
    }
    

    调用performReceiveLocked方法

    void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
            Intent intent, int resultCode, String data, Bundle extras,
                              boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
      //...
      app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                                data, extras, ordered, sticky, sendingUser, app.repProcState);
      //...
    }
    

    这里又调用了ApplicationThread的scheduleRegisteredReceiver

    public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
            int resultCode, String dataStr, Bundle extras, boolean ordered,
            boolean sticky, int sendingUser, int processState) throws RemoteException {
        updateProcessState(processState, false);
        receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                sticky, sendingUser);
    }
    

    在注册流程中我们知道receiver是一个ReceiverDispatcher.InnerReceiver对象,它的performReceive方法如下

    @Override
    public void performReceive(Intent intent, int resultCode, String data,
            Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
        final LoadedApk.ReceiverDispatcher rd;
      //...
      rd.performReceive(intent, resultCode, data, extras,
                                ordered, sticky, sendingUser);
      //...
    }
    

    调用ReceiverDispatcher的performReceive方法

    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.getRunnable())) {
                    if (mRegistered && ordered) {
                        IActivityManager mgr = ActivityManager.getService();
                        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                "Finishing sync broadcast to " + mReceiver);
                        args.sendFinished(mgr);
                    }
              }
      //...
    }
    

    mActivityThread是ActivityThread中mH这个Handler对象,用它执行args里的Runnable

    public final Runnable getRunnable() {
        return () -> {
            final BroadcastReceiver receiver = mReceiver;
          //...
            ClassLoader cl = mReceiver.getClass().getClassLoader();
            intent.setExtrasClassLoader(cl);
            intent.prepareToEnterProcess();
            setExtrasClassLoader(cl);
            receiver.setPendingResult(this);
            receiver.onReceive(mContext, intent);
          //...
        }
    }
    

    在run方法中,调用了BroadcastReceiver的onReceive方法,广播接收者就接收到了广播,这就完成了广播的发送和接收。而由于这里使用的是主线程的mH对象执行的Runnable,所以onReceive执行在主线程中,当然这里是不能做耗时操作的。

    相关文章

      网友评论

          本文标题:Android源码学习-BroadcastReceiver工作流

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