Android-广播的注册

642 阅读3分钟

广播分为动态注册和静态注册,其中静态注册是在AndroidManifeat中声明,然后应用安装时由PackageManagerService来注册。动态注册是调用registerReceiver方法来注册。

下面来看看动态注册的时序图

1626532934431.jpg

当调用registerReceiver的时候会调用到ContextImpl的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();
    }
}

这里会先判断LoadedApk类型的mPackageInfo是否为null,context是否为null,如果都不为null,则通过mPackageInfo的getReceiverDispatcher方法获取IIntentReceiver。IIntentReceiver是一个Binder接口,用于广播的跨进程通信。他的实现在LoadedApk.ReceiverDispatcher.InnerReceiver。否则会创建一个新的IIntentReceiver。最后调用AMS的registerReceiver方法并将获取到的IIntentReceiver传入。

public Intent registerReceiver(IApplicationThread caller, String callerPackage,
        IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
        int flags) {
    enforceNotIsolatedCaller("registerReceiver");
    ArrayList<Intent> stickyIntents = null;
    ProcessRecord callerApp = null;
    final boolean visibleToInstantApps
            = (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;
    int callingUid;
    int callingPid;
    boolean instantApp;
    synchronized(this) {
        if (caller != null) {
            //获取到ProcessRecord,这个用来描述注册广播的Activity所在进程的信息
            callerApp = getRecordForAppLocked(caller);
            if (callerApp == null) {
                throw new SecurityException(
                        "Unable to find app for caller " + caller
                        + " (pid=" + Binder.getCallingPid()
                        + ") when registering receiver " + receiver);
            }
            if (callerApp.info.uid != SYSTEM_UID &&
                    !callerApp.pkgList.containsKey(callerPackage) &&
                    !"android".equals(callerPackage)) {
                throw new SecurityException("Given caller package " + callerPackage
                        + " is not running in process " + callerApp);
            }
            //获取uid,pid
            callingUid = callerApp.info.uid;
            callingPid = callerApp.pid;
        } else {
            callerPackage = null;
            callingUid = Binder.getCallingUid();
            callingPid = Binder.getCallingPid();
        }

        instantApp = isInstantApp(callerApp, callerPackage, callingUid);
        userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
                ALLOW_FULL_ONLY, "registerReceiver", callerPackage);

        //获取所有设置的action,如果没有,则添加一个null进去
        Iterator<String> actions = filter.actionsIterator();
        if (actions == null) {
            ArrayList<String> noAction = new ArrayList<String>(1);
            noAction.add(null);
            actions = noAction.iterator();
        }

        // Collect stickies of users
        int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
        //遍历所有action
        while (actions.hasNext()) {
            String action = actions.next();
            for (int id : userIds) {
                //获取该id对的到所有黏性广播,id为应用程序id
                ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
                if (stickies != null) {
                    ArrayList<Intent> intents = stickies.get(action);
                    if (intents != null) {
                        if (stickyIntents == null) {
                            stickyIntents = new ArrayList<Intent>();
                        }
                        //将对应的黏性广播加入到stickyIntents中
                        stickyIntents.addAll(intents);
                    }
                }
            }
        }
    }

    ArrayList<Intent> allSticky = null;
    if (stickyIntents != null) {
        final ContentResolver resolver = mContext.getContentResolver();
        //遍历所有粘性广播的Intent
        for (int i = 0, N = stickyIntents.size(); i < N; i++) {
            Intent intent = stickyIntents.get(i);
            // 免安装应用直接跳过
            if (instantApp &&
                    (intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
                continue;
            }

            if (filter.match(resolver, intent, true, TAG) >= 0) {
                if (allSticky == null) {
                    allSticky = new ArrayList<Intent>();
                }
                //将所有的intent加入到allSticky中
                allSticky.add(intent);
            }
        }
    }

    //如果传过来的IIntentReceiver为null,则会直接把第一个黏性广播的Intent传给客户端。
    //这里应该是静态注册的情况,动态注册IIntentReceiver不为null
    Intent sticky = allSticky != null ? allSticky.get(0) : null;
    if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Register receiver " + filter + ": " + sticky);
    if (receiver == null) {
        return sticky;
    }

    synchronized (this) {
        //判断一下注册广播的Activity是否还存在,如果已经不存在,直接返回null。
        if (callerApp != null && (callerApp.thread == null
                || callerApp.thread.asBinder() != caller.asBinder())) {
            // Original caller already died
            return null;
        }
        //获取广播接收者列表,ReceiverList是继承于ArrayList的集合
        ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
        //如果列表为null,则直接创建一个
        if (rl == null) {
            rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                    userId, receiver);
            //如果前面获取的ProcessRecord不为null,则将新创建的ReceiverList
            //添加到ProcessRecord的receivers当中
            if (rl.app != null) {
                rl.app.receivers.add(rl);
            } else {
                try {
                    receiver.asBinder().linkToDeath(rl, 0);
                } catch (RemoteException e) {
                    return sticky;
                }
                rl.linkedToDeath = true;
            }
            //将新创建的ReceiverList也加入到mRegisteredReceivers中
            //mRegisteredReceivers是一个map,key的类型是IBinder,这里传入的是IIntentReceiver
            //这个IIntentReceiver是注册广播的时候客户端传过来的InnerReceiver
            mRegisteredReceivers.put(receiver.asBinder(), rl);
        } 
        ...
        //将传过来的IntentFilter和获取到的ReceiverList等参数用来创建BroadcastFilter
        BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                permission, callingUid, userId, instantApp, visibleToInstantApps);
        将新创建的BroadcastFilter添加到ReceiverList中
        rl.add(bf);
        if (!bf.debugCheck()) {
            Slog.w(TAG, "==> For Dynamic broadcast");
        }
        //将BroadcastFilter添加到IntentResolver类型的mReceiverResolver中
        //当AMS收到广播的时候就可以从mReceiverResolver中找到对应的广播接收者。
        //到这里注册广播就完成了
        mReceiverResolver.addFilter(bf);

        //将和BroadcastFilter匹配的所有粘性广播加入到队列
        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, false, null, null, AppOpsManager.OP_NONE, null, receivers,
                        null, 0, null, null, false, true, true, -1);
                queue.enqueueParallelBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();
            }
        }

        return sticky;
    }
}

到这里动态广播的注册就完成了。