Android组件管理框架—广播接收者BroadcastReceiver之动态注册流程(Android P)

一 前言

        接收广播(Broadcast),必须先要注册接收广播的组件——广播接收者(receiver),广播接收者的注册分为动态注册和静态注册,注册中心是AMS,AMS再把广播分发到各个广播接收者(receiver)。

静态动态广播的区别

        1 动态注册广播不是常驻型广播,广播跟随Activity的生命周期,在Activity结束前,需要移除广播接收器。

           静态注册是常驻型,当应用程序关闭后,如果有信息广播来,程序也会被系统调用自动运行。

       2 动态注册在程序中使用Context.registerReceiver注册。

          静态注册在应用安装时由PackageManagerService来完成注册过程。   

 

二 图示调用流程

 

《Android组件管理框架—广播接收者BroadcastReceiver之动态注册流程(Android P)》

 

三 代码具体流程

1 frameworks/base/core/java/android/content/ContextWrapper.java

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

mBase指向就是ContextImpl,可以返回看Activity的启动流程:Android组件管理框架—视图容器Activity之启动流程(Android P)

2 frameworks/base/core/java/android/app/ContextImpl.java

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

继续看registerReceiver方法。

@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) {
        //mPackageInfo是LoadedApk类型
        if (mPackageInfo != null && context != null) {
            if (scheduler == null) {
                scheduler = mMainThread.getHandler();
            }
            //获取ReceiverDispatcher对象
            rd = mPackageInfo.getReceiverDispatcher(
                receiver, context, scheduler,
                mMainThread.getInstrumentation(), true);
        } else {
            if (scheduler == null) {
                scheduler = mMainThread.getHandler();
            }
            //创建ReceiverDispatcher对象
            rd = new LoadedApk.ReceiverDispatcher(
                    receiver, context, scheduler, null, true).getIIntentReceiver();
        }
    }
    try {
        //将ReceiverDispatcher,IntentFilter等发送给AMS
        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();
    }
}

       传进来的receiver不是直接发送给AMS的,首先会把receiver封装成一个IIntentReceiver的对象rd,rd是一个binder本地对象,便具备了跨进程通信的能力。

       mPackageInfo是LoadedApk的类型,LoadedApk类包含了当前加载的apk的主要的信息。 如果mPackageInfo不为空,则通过mPackageInfo.getReceiverDispatcher获取ReceiverDispatcher对象,否则通过new LoadedApk.ReceiverDispatcher来创建ReceiverDispatcher对象。

3 frameworks/base/core/java/android/app/LoadedApk.java

public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
        Context context, Handler handler,
        Instrumentation instrumentation, boolean registered) {
    synchronized (mReceivers) {
        LoadedApk.ReceiverDispatcher rd = null;
        //位置1
        ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
        //位置2 如果注册过直接取出map
        if (registered) {
            map = mReceivers.get(context);
            if (map != null) {
                rd = map.get(r);
            }
        }
        if (rd == null) {
            rd = new ReceiverDispatcher(r, context, handler,
                    instrumentation, registered);
            if (registered) {
                if (map == null) {
                    //位置3 把map创建出来,后面存到mReceivers中
                    map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
                    //位置4 把map放到mReceivers中
                    mReceivers.put(context, map);
                }
                //位置5 把ReceiverDispatcher放到map中
                map.put(r, rd);
            }
        } else {
            //检查广播分发者的context、handler是否一致
            rd.validate(context, handler);
        }
        rd.mForgotten = false;
        return rd.getIIntentReceiver();
    }
}

       位置1的 ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map ,每一个BroadcastReceiver(广播接收者)对应一个ReceiverDispatcher(广播分发者)。 当AMS向app发送广播时会调用到app进程的广播分发者,然后再将广播以message形式post到app的主线程,来执行onReceive()方法。

       位置4的mReceivers.put(context, map),mReceivers以Context为key,如果是在Activity中发送的,这个Context就指向与这个Activity,如果是在Service中发送的,这个Context就指向了这个Service。mReceivers是LoadedApk的成员变量,mReceivers表记录了所有动态注册的receiver。

 private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
    = new ArrayMap<>();

        假如一个app只有两个Activity(MainActivity和SecondActivity),该app被打包成xxx.apk,在内存中,该xxx.apk由LoadedApk来描述,如果MainActivity和SecondActivity都注册了广播,那么LoadedApk内部维持的mReceivers的长度就为2。

getReceiverDispatcher的代码逻辑

       位置2 当一个BroadcastReceiver要注册时,会优先使用Context查看一下,这个组件有没有注册过广播,如果有就取出来,类型是一个ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> 的map。

      位置3 如果没有,就把map创建出来,并且存到mReceivers中。

      位置5 有了map之后,就需要把ReceiverDispatcher(广播分发者)存到map里面去。

      第一次注册时走的是if(rd==null),这样rd对象被创建出来。

ReceiverDispatcher的实现在LoadedApk.ReceiverDispatcher.InnerReceiver。

static final class ReceiverDispatcher {

    final static class InnerReceiver extends IIntentReceiver.Stub {
        final WeakReference<LoadedApk.ReceiverDispatcher> mDispatcher;
        final LoadedApk.ReceiverDispatcher mStrongRef;

        InnerReceiver(LoadedApk.ReceiverDispatcher rd, boolean strong) {
            mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
            mStrongRef = strong ? rd : null;
        }

        @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 {
                // The activity manager dispatched a broadcast to a registered
                // receiver in this process, but before it could be delivered the
                // receiver was unregistered.  Acknowledge the broadcast on its
                // behalf so that the system's broadcast sequence can continue.
                if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                        "Finishing broadcast to unregistered receiver");
                IActivityManager mgr = ActivityManager.getService();
                try {
                    if (extras != null) {
                        extras.setAllowFds(false);
                    }
                    mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
        }
    }
    ...
}

       其中IIntentReceiver是一个Binder接口,通过它可以进行跨进程的通信。InnerReceiver是ReceiverDispatcher的内部类,是一个实现Binder的本地对象,最终是将一个InnerReceiver对象注册到了AMS中。

      用户进程走到SystemServer进程。继续看ActivityManagerService的registerReceiver。

4 frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

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) {
            //由caller获取当前进程对象
            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);
            }
            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);
        //根据传进来的IntentFilter得到actions列表(ArrayList)
        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
        //从actions中,先把粘性广播选出来放进stickyIntents中
        int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
        while (actions.hasNext()) {
            String action = actions.next();
            for (int id : userIds) {
                //从mStickyBroadcasts中查看用户的sticky Intent,mStickyBroadcasts存了系统所有的粘性广播
                ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
                if (stickies != null) {
                    //获取所有粘性广播的intent
                    ArrayList<Intent> intents = stickies.get(action);
                    if (intents != null) {
                        if (stickyIntents == null) {
                            stickyIntents = new ArrayList<Intent>();
                        }
                        stickyIntents.addAll(intents);
                    }
                }
            }
        }
    }

    ArrayList<Intent> allSticky = null;
    if (stickyIntents != null) {
        final ContentResolver resolver = mContext.getContentResolver();
        // Look for any matching sticky broadcasts...
        for (int i = 0, N = stickyIntents.size(); i < N; i++) {
            Intent intent = stickyIntents.get(i);
            // Don't provided intents that aren't available to instant apps.
            if (instantApp &&
                    (intent.getFlags() & Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS) == 0) {
                continue;
            }
            // If intent has scheme "content", it will need to acccess
            // provider that needs to lock mProviderMap in ActivityThread
            // and also it may need to wait application response, so we
            // cannot lock ActivityManagerService here.
            if (filter.match(resolver, intent, true, TAG) >= 0) {
                if (allSticky == null) {
                    allSticky = new ArrayList<Intent>();
                }
                allSticky.add(intent);
            }
        }
    }

    // The first sticky in the list is returned directly back to the client.
    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) {
        if (callerApp != null && (callerApp.thread == null
                || callerApp.thread.asBinder() != caller.asBinder())) {
            // Original caller already died
            return null;
        }
        //位置1 获取ReceiverList列表,用来存储广播接收者
        //mRegisteredReceivers存了所有动态注册的广播接收者
        //由receiver作为key,因为一个广播可能会有多个接收者所以是ReceiverList
        //而不是一个Receiver
        ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
        if (rl == null) {
            //如果为空则创建ReceiverList对象
            rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                    userId, receiver);
            if (rl.app != null) {
                final int totalReceiversForApp = rl.app.receivers.size();
                if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) {
                    throw new IllegalStateException("Too many receivers, total of "
                            + totalReceiversForApp + ", registered for pid: "
                            + rl.pid + ", callerPackage: " + callerPackage);
                }
                rl.app.receivers.add(rl);
            } else {
                try {
                    receiver.asBinder().linkToDeath(rl, 0);
                } catch (RemoteException e) {
                    return sticky;
                }
                rl.linkedToDeath = true;
            }
            mRegisteredReceivers.put(receiver.asBinder(), rl);
        } else if (rl.uid != callingUid) {
            throw new IllegalArgumentException(
                    "Receiver requested to register for uid " + callingUid
                    + " was previously registered for uid " + rl.uid
                    + " callerPackage is " + callerPackage);
        } else if (rl.pid != callingPid) {
            throw new IllegalArgumentException(
                    "Receiver requested to register for pid " + callingPid
                    + " was previously registered for pid " + rl.pid
                    + " callerPackage is " + callerPackage);
        } else if (rl.userId != userId) {
            throw new IllegalArgumentException(
                    "Receiver requested to register for user " + userId
                    + " was previously registered for user " + rl.userId
                    + " callerPackage is " + callerPackage);
        }
        //位置2 创建BroadcastFilter并传入之前创建的ReceiverList
        //在AMS内部,广播接收者实际上是BroadcastFilter来描述的
        BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                permission, callingUid, userId, instantApp, visibleToInstantApps);
        if (rl.containsFilter(filter)) {
            Slog.w(TAG, "Receiver with filter " + filter
                    + " already registered for pid " + rl.pid
                    + ", callerPackage is " + callerPackage);
        } else {
            //将BroadcastFilter添加到ReceiverList中
            rl.add(bf);
            if (!bf.debugCheck()) {
                Slog.w(TAG, "==> For Dynamic broadcast");
            }
            //位置3 将BroadcastFilter添加到mReceiverResolver
            mReceiverResolver.addFilter(bf);
        }

        // Enqueue broadcasts for all existing stickies that match
        // this filter.
        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, OP_NONE, null, receivers,
                        null, 0, null, null, false, true, true, -1);
                queue.enqueueParallelBroadcastLocked(r);
                queue.scheduleBroadcastsLocked();
            }
        }

        return sticky;
    }
}

         位置1的ReceiverList继承ArrayList,用来存储广播接收者。位置2的BroadcastFilter用来描述注册的广播接收者。位置3 将BroadcastFilter添加到mReceiverResolver中,这样当AMS接收到广播时就可以从mReceiverResolver中找到对应的广播接收者了。

 

四 总结

1 关键类与对象

LoadedApk    包含了当前加载的apk的主要的信息。

mReceivers   ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>>, LoadedApk的成员变量,一张表记录了所有动态注册的receiver。

IIntentReceiver   一个binder本地对象,具备了跨进程通信的能力。

InnerReceiver    ReceiverDispatcher的内部类,是一个实现Binder的本地对象,最终是将InnerReceiver对象注册到AMS中。

ReceiverDispatcher   广播分发者,ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>,每个广播接收者对应一个广播分发者, 当AMS向app发送广播时会调用到app进程(Client端)的广播分发者,然后再将广播以message形式post到app的主线程,来执行onReceive()方法。

mRegisteredReceivers    HashMap<IBinder, ReceiverList>,存了所有动态注册的广播接收者。

BroadcastFilter   AMS内部广播接收者用BroadcastFilter来描述。

ReceiverList   用来存储广播接收者。

mReceiverResolver    AMS接收到广播时就可以从mReceiverResolver中找到对应的广播接收者。

2 注册流程

        在Android系统中,系统每加载一个apk,会有一个LoadedApk对象。

       每个LoadedApk对象里会有mReceivers表,类型为ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>>,用来记录每个apk里面动态注册了哪些广播接收者。

       Context代表是谁注册的,后面的值也是个map ,ArrayMap<BroadcastReceiver, ReceiverDispatcher>表示一个BroadcastReceiver对应一个ReceiverDispatcher。不管一个Activity注册了多少BroadcastReceiver,ReceiverDispatcher只有一个。

       ReceiverDispatcher内部有一个InnerReceiver的Binder对象,最终是把这个InnerReceiver发送给了AMS。

       AMS内部维护一张表mRegisteredReceivers,记录所有动态注册的接收者,首先会根据传进来的InnerReceiver对象取出来一个ReceiverList,ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder()),所以实质上每个ReceiverList都对应着Client端的一个ReceiverDispatcher。

      最后把创建的对象BroadcastFilter(AMS内部广播接收者用BroadcastFilter来描述)添加到ReceiverList接收者队列中。

 

    原文作者:BrighterLi
    原文地址: https://blog.csdn.net/weixin_42093428/article/details/85225956
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞