Android-广播的发送和接收

1,114 阅读2分钟

广播的发送有几种类型,我们这次主要看无序广播的发送。

要发送无序广播,我们会调用sendBroadcast方法,这个方法最终还是会调用ContextImpl里面的sendBroadcast方法。

ContextImpl到AMS

时序图:

1626791527770.jpg

先来看看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) {
    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();
        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的broadcastIntent方法中,我们会先调用verifyBroadcastLocked方法来检查广播是否合法。

我们先来看看是如何检测的

final Intent verifyBroadcastLocked(Intent intent) {
    // 先判断intent中是否有描述符
    if (intent != null && intent.hasFileDescriptors() == true) {
        throw new IllegalArgumentException("File descriptors passed in Intent");
    }
    //获取intent设置的flag
    int flags = intent.getFlags();

    if (!mProcessesReady) {
        //如果系统正在启动中,会进入到这个方法
        
        //判断如果intent设置了FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT,则不做处理
        if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
            // This will be turned into a FLAG_RECEIVER_REGISTERED_ONLY later on if needed.
        } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
            //如果intent没有设置FLAG_RECEIVER_REGISTERED_ONLY,就会报错。
            Slog.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
                    + " before boot completion");
            throw new IllegalStateException("Cannot broadcast before boot completed");
        }
    }

    if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
        throw new IllegalArgumentException(
                "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
    }

    if ((flags & Intent.FLAG_RECEIVER_FROM_SHELL) != 0) {
        switch (Binder.getCallingUid()) {
            case ROOT_UID:
            case SHELL_UID:
                break;
            default:
                Slog.w(TAG, "Removing FLAG_RECEIVER_FROM_SHELL because caller is UID "
                        + Binder.getCallingUid());
                intent.removeFlags(Intent.FLAG_RECEIVER_FROM_SHELL);
                break;
        }
    }

    return intent;
}

在检查完后,我们会调用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) {
...
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
        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) {
            //将创建的BroadcastRecord加入到队列中
            queue.enqueueParallelBroadcastLocked(r);
            //调用BroadcastQueue的scheduleBroadcastsLocked方法
            queue.scheduleBroadcastsLocked();
        }
        registeredReceivers = null;
        NR = 0;
    }
    ...
    return ActivityManager.BROADCAST_SUCCESS;
}

接下来就会讲需要发送的广播从AMS传送到BroadcastReceiver的进程中

AMS到BroadcastReceiver过程

时序图:

1626794695097.jpg

先来继续看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;
}

像BroadcastHandler类型的mHandler发送标识为BROADCAST_INTENT_MSG的消息

case BROADCAST_INTENT_MSG: {
    if (DEBUG_BROADCAST) Slog.v(
            TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
    processNextBroadcast(true);
} break;

在Handler中又调用了processNextBroadcast方法。processNextBroadcast方法对无序广播和有序广播都做了处理。

final void processNextBroadcast(boolean fromMsg) {
    ...
    if (fromMsg) {
        mBroadcastsScheduled = false;
    }

    // 遍历存储的无序广播
    while (mParallelBroadcasts.size() > 0) {
        //获取到无序广播
        r = mParallelBroadcasts.remove(0);
        r.dispatchTime = SystemClock.uptimeMillis();
        r.dispatchClockTime = System.currentTimeMillis();

        ...
        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);
        }
        addBroadcastToHistoryLocked(r);
        if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Done with parallel broadcast ["
                + mQueueName + "] " + r);
    }
}

这里先是获取到无序广播,然后调用deliverToRegisteredReceiverLocked方法,并将获取到的广播实例传入进去。下面来看看deliverToRegisteredReceiverLocked方法

private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
        BroadcastFilter filter, boolean ordered, int index) {
    ...
    try {
        if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
                "Delivering to " + filter + " : " + r);
        if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
            // Skip delivery if full backup in progress
            // If it's an ordered broadcast, we need to continue to the next receiver.
            if (ordered) {
                skipReceiverLocked(r);
            }
        } else {
            performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                    new Intent(r.intent), r.resultCode, r.resultData,
                    r.resultExtras, r.ordered, r.initialSticky, r.userId);
        }
        if (ordered) {
            r.state = BroadcastRecord.CALL_DONE_RECEIVE;
        }
    } catch (RemoteException e) {
        Slog.w(TAG, "Failure sending broadcast " + r.intent, e);
        if (ordered) {
            r.receiver = null;
            r.curFilter = null;
            filter.receiverList.curBroadcast = null;
            if (filter.receiverList.app != null) {
                filter.receiverList.app.curReceivers.remove(r);
            }
        }
    }
}

这里省略了大部分代码,这些代码是用来检测广播权限相关的东西,如果检测都通过了,会调用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);
}

这里调用的是IIntentReceiver对象的performReceive方法。IIntentReceiver用于广播跨进程通信。实现为LoadedApk.ReceiverDispatcher.InnerReceiver。

@Override
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 (ActivityThread.DEBUG_BROADCAST) {
        int seq = intent.getIntExtra("seq", -1);
        Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction()
                + " seq=" + seq + " to " + (rd != null ? rd.mReceiver : null));
    }
    if (rd != null) {
        rd.performReceive(intent, resultCode, data, extras,
                ordered, sticky, sendingUser);
    } else {
    ...
    }
}

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

}

先将广播的intent等参数封装成Args,然后调用mActivityThread的post方法将Args传入。mActivityThread是一个Handler,指向的就是H。因为传入的是args.getRunnable(),下面看看getRunnable做了什么

final class Args extends BroadcastReceiver.PendingResult {
    ...
    public final Runnable getRunnable() {
        return () -> {
            ...
            try {
                ClassLoader cl = mReceiver.getClass().getClassLoader();
                intent.setExtrasClassLoader(cl);
                intent.prepareToEnterProcess();
                setExtrasClassLoader(cl);
                receiver.setPendingResult(this);
                receiver.onReceive(mContext, intent);
            } catch (Exception e) {
                ...
            }
            ...
        };
    }
}

这里调用了receiver的onReceive方法,这样注册的广播就可以收到通知了。