基于N源码的广播注册和发送流程分析

来源:互联网 发布:网络平台招商合同 编辑:程序博客网 时间:2024/05/18 01:50

广播可分为普通广播、有序广播和粘性广播,广播的注册方式分为静态注册和动态注册。在N上删除了三项隐式广播,以帮助优化内存使用和电量消耗。这三者广播为:CONNECTIVITY_ACTION;ACTION_NEW_PICTURE;ACTION_NEW_VIDEO。意思就是在AndroidManifest文件中静态注册是无法接受到通知,必须动态注册才可以。

下面看到动态注册的流程:

同样进入ContextImpl.java:

    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());    }
    private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,            IntentFilter filter, String broadcastPermission,            Handler scheduler, Context context) {        IIntentReceiver rd = null;        rd = new LoadedApk.ReceiverDispatcher(                        receiver, context, scheduler, null, true).getIIntentReceiver();        final Intent intent = ActivityManagerNative.getDefault().registerReceiver(                    mMainThread.getApplicationThread(), mBasePackageName,                    rd, filter, broadcastPermission, userId);    }

这里创建了IIntentReceiver对象,进入LoadedApk.java跟踪下该对象的创建:

        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;            mInstrumentation = instrumentation;            mRegistered = registered;            mLocation = new IntentReceiverLeaked(null);            mLocation.fillInStackTrace();        }
        BroadcastReceiver getIntentReceiver() {            return mReceiver;        }

可以看到这个IIntentReceiver对象是IntentReceiver类型:

final static class InnerReceiver extends IIntentReceiver.Stub {

看到继承stub就明白它是服务端的真正实现者。这里先记下。
接着看下面:

            final Intent intent = ActivityManagerNative.getDefault().registerReceiver(                    mMainThread.getApplicationThread(), mBasePackageName,                    rd, filter, broadcastPermission, userId);

这里的ActivityManagerNative.getDefault()是服务端的本地代理ActivityManagerProxy,调用registerReceiver会跨进程进入到服务的实现者AMS,并传递了两个binder对象:ApplicationThread和InnerReceiver,它们身处客户端却也是服务端的实现者。这里不明白的同学可以翻阅我前面几篇文章。
进入AMS的registerReceiver:

public Intent registerReceiver(IApplicationThread caller, String callerPackage,            IIntentReceiver receiver, IntentFilter filter, String permission, int userId) {            ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());            if (rl == null) {                rl = new ReceiverList(this, callerApp, callingPid, callingUid,                        userId, receiver);                mRegisteredReceivers.put(receiver.asBinder(), rl);            }
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,                    permission, callingUid, userId);            rl.add(bf);
    mReceiverResolver.addFilter(bf);            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();                }            }}

这里创建ReceiverList对象,并保存到mRegisteredReceivers键值对中,并且创建BroadcastFilter对象保存起来。allSticky为粘性广播队列,如果不为空,粘性广播就会接收到消息。
下面看下发送普通广播流程:

直接进入ContextImpl.java:

            ActivityManagerNative.getDefault().broadcastIntent(                    mMainThread.getApplicationThread(), intent, resolvedType, null,                    Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,                    getUserId());

跨进程进入AMS中的broadcastIntent,它里面又调用broadcastIntentLocked:

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);        List<BroadcastFilter> registeredReceivers = null;        registeredReceivers = mReceiverResolver.queryIntent(intent,                        resolvedType, false, userId);        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.            final BroadcastQueue queue = broadcastQueueForIntent(intent);            BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,                    callerPackage, callingPid, callingUid, 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);            if (!replaced) {                queue.enqueueParallelBroadcastLocked(r);                queue.scheduleBroadcastsLocked();            }            registeredReceivers = null;            NR = 0;        }}

默认添加FLAG_EXCLUDE_STOPPED_PACKAGES标记位,表示停止的应用无法接收到广播。接着通过mReceiverResolver.queryIntent找到之前注册广播保存的BroadcastFilter。因是普通广播,ordered为false。于是获取BroadcastQueue和广播记录BroadcastRecord,接着调用广播队列的enqueueParallelBroadcastLocked:

    public void enqueueParallelBroadcastLocked(BroadcastRecord r) {        mParallelBroadcasts.add(r);        r.enqueueClockTime = System.currentTimeMillis();    }

将广播信息保存在mParallelBroadcasts队列中。接着调用广播队列的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;    }

可以看到用handler发送消息转到hander中的handleMessage:

        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;

进入processNextBroadcast:

            while (mParallelBroadcasts.size() > 0) {                r = mParallelBroadcasts.remove(0);                r.dispatchTime = SystemClock.uptimeMillis();                r.dispatchClockTime = System.currentTimeMillis();                final int N = r.receivers.size();                if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["                        + mQueueName + "] " + r);                for (int i=0; i<N; i++) {                    Object target = r.receivers.get(i);                    if (DEBUG_BROADCAST)  Slog.v(TAG_BROADCAST,                            "Delivering non-ordered on [" + mQueueName + "] to registered "                            + target + ": " + r);                    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 {        // Send the intent to the receiver asynchronously using one-way binder calls.        if (app != null) {            if (app.thread != null) {                // If we have an app thread, do the call through that so it is                // correctly ordered with other one-way calls.                try {                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,                            data, extras, ordered, sticky, sendingUser, app.repProcState);                // TODO: Uncomment this when (b/28322359) is fixed and we aren't getting                // DeadObjectException when the process isn't actually dead.                //} catch (DeadObjectException ex) {                // Failed to call into the process.  It's dying so just let it die and move on.                //    throw ex;                } catch (RemoteException ex) {                    // Failed to call into the process. It's either dying or wedged. Kill it gently.                    synchronized (mService) {                        Slog.w(TAG, "Can't deliver broadcast to " + app.processName                                + " (pid " + app.pid + "). Crashing it.");                        app.scheduleCrash("can't deliver broadcast");                    }                    throw ex;                }            } else {                // Application has died. Receiver doesn't exist.                throw new RemoteException("app.thread must not be null");            }        } else {            receiver.performReceive(intent, resultCode, data, extras, ordered,                    sticky, sendingUser);        }    }

这里跨进程进入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是之前客户端传递的InnerReceiver类型binder对象,这里既然已经回到了客户端,那就不需要跨进程了。接着调用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) {                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);                }            }            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);                }            }        }    }

这里用handler来post一个runable,接着会走进Args中的run:

            public void run() {                final BroadcastReceiver receiver = mReceiver;                    receiver.setPendingResult(this);                    receiver.onReceive(mContext, intent);}
因InnerReceiver中存在ReceiverDispatcher,而ReceiverDispatcher存在BroadcastReceiver对象,因此receiver不为空,调用onReceive就会进入用户自定义的BroadcastReceiver对象中。








1 0
原创粉丝点击