首页 > 程序开发 > 移动开发 > 其他 >

广播流程2--发送广播

2017-06-20

广播流程2--发送广播。

4.发送广播sendBroadcast

下图采用的品茗论道说广播悠然红茶的图片
https://my.oschina.net/youranhongcha/blog/226274
直观的解释了广播队列分发广播的流程

其实还是在ContextImpl中:

    @Override
    public void sendBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess(this);
            //跳转到AMS中发送广播,广播表现形式就是intent
            ActivityManagerNative.getDefault().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();
        }
    }
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) {
    enforceNotIsolatedCaller("broadcastIntent");
    synchronized(this) {
        intent = verifyBroadcastLocked(intent);

        final ProcessRecord callerApp = getRecordForAppLocked(caller);
        final int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        //在AMS中进行广播的分发
        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;
    }
}

在AMS中broadcastIntentLocked, 首先完成这几件事情:
1.intent添加FLAG_EXCLUDE_STOPPED_PACKAGES标记
保证已停止app不会收到该广播

        intent = new Intent(intent);
        intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

2.广播权限验证
isCallerSystem根据这个判断是不是系统,是系统可以发送任何广播,不是的话受限广播是不能发送的,没有权限的了

3.处理Package级别的广播
例如:

    case Intent.ACTION_UID_REMOVED:
    case Intent.ACTION_PACKAGE_REMOVED:
    case Intent.ACTION_PACKAGE_CHANGED:
    case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
    case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
    case Intent.ACTION_PACKAGES_SUSPENDED:
    case Intent.ACTION_PACKAGES_UNSUSPENDED:

3.处理黏性广播列表mStickyBoradcast

5.主要广播分发的流程

同样在AMS中broadcastIntentLocked方法在完成以上的几个事件之后,就开始进行广播队列的分发:

// Figure out who all will receive this broadcast.
        List receivers = null;
        List registeredReceivers = null;
        // Need to resolve the intent to interested receivers...
        if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
                 == 0) {
            //当前intent的所有静态注册广播接收者
            receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
        }
        if (intent.getComponent() == null) {
            if (userId == UserHandle.USER_ALL && callingUid == Process.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 registeredReceiversForUser =
                            mReceiverResolver.queryIntent(intent,
                                    resolvedType, false, users[i]);
                    if (registeredReceivers == null) {
                        registeredReceivers = registeredReceiversForUser;
                    } else if (registeredReceiversForUser != null) {
                        registeredReceivers.addAll(registeredReceiversForUser);
                    }
                }
            } else {
                registeredReceivers = mReceiverResolver.queryIntent(intent,
                        resolvedType, false, userId);
            }
        }

registeredReceivers 就记录了所有动态注册的广播接收者,接下来就处理动态广播:

        final boolean replacePending =
                (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;

        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueing 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&#39;t wait for the
            // components to be launched.
            //根据intent来返回广播队列,广播队列分为mFgBroadcastQueue 和mBgBroadcastQueue。
            final BroadcastQueue queue = broadcastQueueForIntent(intent);
            //将intent包装起来,变成BroadcastRecord对象
            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
                    callerPackage, callingPid, callingUid, resolvedType, requiredPermissions,
                    //registeredReceivers这个属性比较重要,将动态注册的BroadcastReceiver传进去
                    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);
            if (!replaced) {
             //将BroadcastRecord插入到广播队列中mParallelBroadcasts,这里mParallelBroadcasts是处理并行广播的,就是sendBroadcast方法发送的广播
                queue.enqueueParallelBroadcastLocked(r);
                //对广播进行处理,找到广播BroadcastRecord对象,对应的BroadcastFilter,然后在找ReceiverList,最后找到BroadcastReceiver,然后进行广播的处理
                queue.scheduleBroadcastsLocked();
            }
            registeredReceivers = null;
            NR = 0;
        }

队列分为mFgBroadcastQueue 和mBgBroadcastQueue,如下所示:

    BroadcastQueue broadcastQueueForIntent(Intent intent) {
        final boolean isFg = (intent.getFlags() & Intent.FLAG_RECEIVER_FOREGROUND) != 0;
        if (DEBUG_BROADCAST_BACKGROUND) Slog.i(TAG_BROADCAST,
                "Broadcast intent " + intent + " on "
                + (isFg ? "foreground" : "background") + " queue");
        return (isFg) ? mFgBroadcastQueue : mBgBroadcastQueue;
    }

每个队列mFgBroadcastQueue或者mBgBroadcastQueue,都有
final ArrayList mParallelBroadcasts = new ArrayList<>();
final ArrayList mOrderedBroadcasts = new ArrayList<>();
这两个属性分别处理并行和串行广播。

在队列里面进行广播的处理都是一条主线(不管串行和并行流程都是相似的):

queue.scheduleBroadcastsLocked(); mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this)) processNextBroadcast(true); deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false,
i); performReceiveLocked(…)

app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, app.repProcState);
调到具体的注册广播的应用里面,然后在应用内进行处理。根据之前注册的IIntentReceiver进行对应的广播处理。

ActivityThread:

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

LoadedApk.ReceiverDispatcher.InnerReceiver:

    public void performReceive(Intent intent, int resultCode, String data,
            Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
        final LoadedApk.ReceiverDispatcher rd;
        if (intent == null) {
            Log.wtf(TAG, "Null intent received");
            rd = null;
        } else {
            rd = mDispatcher.get();
        }
        if (rd != null) {
            //rd就是LoadedApk.ReceiverDispatcher,通过这个LoadedApk.ReceiverDispatcher,再进行performReceive
            rd.performReceive(intent, resultCode, data, extras,
                    ordered, sticky, sendingUser);
        }

    }

LoadedApk.ReceiverDispatcher:

        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) {
                Log.wtf(TAG, "Null intent received");
            } else {
                if (ActivityThread.DEBUG_BROADCAST) {
                    int seq = intent.getIntExtra("seq", -1);
                    Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction()
                            + " seq=" + seq + " to " + mReceiver);
                }
            }
            //args是一个实现了Runnable的类,执行其中的run方法
            if (intent == null || !mActivityThread.post(args)) {
                if (mRegistered && ordered) {
                    IActivityManager mgr = ActivityManagerNative.getDefault();
                    if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                            "Finishing sync broadcast to " + mReceiver);
                    args.sendFinished(mgr);
                }
            }
        }

Args:

    public void run() {
        final BroadcastReceiver receiver = mReceiver;
        try {
            ClassLoader cl =  mReceiver.getClass().getClassLoader();
            intent.setExtrasClassLoader(cl);
            intent.prepareToEnterProcess();
            setExtrasClassLoader(cl);
            receiver.setPendingResult(this);
            //这个就是找到了对应的广播接受者,执行广播接受者的onReceive方法,其中的context是注册广播接受者注册时的context
            receiver.onReceive(mContext, intent);
        } 
    }

注:1.并发广播先于有序广播,先进行并发广播的分发,然后再进行有序广播的分发;
2.有序广播有动态注册的广播,也有静态注册的广播。由于静态广播在AndroidManifest中配置,接受广播的时候
可能进程没有起来,所以要一个个启动进程(一下子启动大量进程可能系统无法做出反应吧)。

相关文章
最新文章
热点推荐