深入Android系统(十一)AMS-4-广播管理

BroadcastReceiver 管理

Broadcast实质上是提供了一种更灵活的使用Intent的方式。

无论是启动Activity,还是Service,其实都是通过Intent的发送和过滤来调用应用中的功能,但是ActivityServiceContentProvider所完成的功能是固定的

而对于BroadcastReceiver可以做任意的事情,同时广播的发送和接收方式也更加丰富灵活

理解BroadcastReceiver

BroadcastReceiver是一种很简单的组件,甚至在ActivityThread中都没有管理它的数据结构。

BroadcastReceiver的本质就是通过Intent来执行应用中的一个方法,在应用中并不需要一个长期存在的对象

虽然应用中没有专门的数据结构来管理BroadcastReceiver,但是在AMS中还是需要的,因为BroadcastReceiver可以在运行时动态向AMS注册,AMS中需要有数据结构来管理动态接收者

BroadcastReceiver可以通过两种方式接收广播

  • 通过AndroidManifest中的<receiver/>标签注册
  • 通过AMSregisterReceiver()接口注册

关于广播使用上的知识大家可以在官网学习:广播基础知识

我们看下BroadcastReceiver类相关的重要定义:

public abstract class BroadcastReceiver {
    private PendingResult mPendingResult;
    public abstract void onReceive(Context context, Intent intent);
    public final PendingResult goAsync() {
        PendingResult res = mPendingResult;
        mPendingResult = null;
        return res;
    }
}

实现一个广播接收器只需要继承BroadcastReceiver,然后实现它的抽象方法onReceive()就可以了。这也是最简单的广播的用法。

不过从BroadcastReceiver的类定义中还有一个mPendingResult变量和goAsync()方法,它们有什么作用呢?
它们主要是针对当接收到广播后需要做一些耗时操作,而且还有可能需要返回处理结果的情况

  • 我们知道BroadcastReceiver对象的onReceive()如果长时间不返回,会引发ANR
  • 因此如果要执行耗时的操作,必须在其他线程中完成

mPendingResult变量的存在就是为了上述需求。而goAsync()方法提供了获取mPendingResult变量的接口。

goAsync()方法的实现可以看到

  • 方法在将mPendingResult对象的指针返回后。同时也会将mPendingResult的值置为null

按照官方说法:

一旦执行了goAsync()方法,在onReceive()结束前,需要将mPendingResult对象的指针传递到新线程中去,在新线程处理完成后必须调用mPendingResult对象的finish()方法来通知AMS

我们看下PendingResultfinish()方法:

    public final void finish() {
        if (mType == TYPE_COMPONENT) {
            final IActivityManager mgr = ActivityManager.getService();
            if (QueuedWork.hasPendingWork()) {
                QueuedWork.queue(new Runnable() {
                    @Override public void run() {
                        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                "Finishing broadcast after work to component " + mToken);
                        sendFinished(mgr);
                    }
                }, false);
            } else {
                if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                        "Finishing broadcast to component " + mToken);
                sendFinished(mgr);
            }
        } else if (mOrderedHint && mType != TYPE_UNREGISTERED) {
            if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                    "Finishing broadcast to " + mToken);
            final IActivityManager mgr = ActivityManager.getService();
            sendFinished(mgr);
        }
    }
    public void sendFinished(IActivityManager am) {
        synchronized (this) {
            ...
            try {
                ...
                if (mOrderedHint) {
                    am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras,
                            mAbortBroadcast, mFlags);
                } else {
                    am.finishReceiver(mToken, 0, null, null, false, mFlags);
                }
            } catch (RemoteException ex) {
            }
        }
    }

核心操作就是调用AMSfinishReceiver()方法,这才是当前广播接收器的结束的标志。

正常情况下(没有执行过goAsync())当onReceive()调用完成后,AMS检测到mPendingResult不为空,便会自动执行finish()方法,而对于执行过goAsync()的广播接收器,AMS便不会主动执行finish()

这个finish()方法很重要,本章最后也有它的身影

广播的分类

从广播的发送方式来划分,有4类广播。

  • 普通广播:通过Context中的方法sendBroadcast()sendBroadcastAsUser()发送的广播属于普通广播。
    • 普通广播的特点是发送给系统当前的所有注册的接收者
    • 接收者接收到广播的顺序也是不确定的
  • 有序广播:通过Context中的方法sendOrderedBroadcast()sendOrderedBroadcastAsUser()发送的广播属于有序广播。
    • 有序广播的发送顺序是按照接收者的优先级来决定的,系统默认范围是-1000-1000,但实际上没有明确的数值限定,可以到int最大值
    • 接收器的优先级通过匹配的intent-filterandroid:priority属性来控制
    • 具有相同优先级的接收器将按随机顺序运行(这部分书中和官网的描述并不一致,看完源码再说啦)
    • 当接收器逐个顺序执行时,接收器可以向下传递结果,也可以完全中止广播,使其不再传递给其他接收器
  • 粘性广播:通过Context中的方法sendStickyBroadcast()sendOrderedBroadcastAsUser()发送的广播属于粘性广播。
    • 和前两个广播不同,粘性广播能将广播发送给系统中以后注册的接收者,甚至是新安装应用中的接收者
    • 官网解释出于安全因素,在Android 9上,这两个接口被标记为了Deprecated
    • 不过这并不影响它在Framework中的使用,我们看个官网的例子:
        IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
        // 对于一个粘性广播来说,注册监听时便可以得到当前电池状态的 Intent
        Intent batteryStatus = context.registerReceiver(null, ifilter);
    
  • 本地广播:通过LocalBroadcastManager.sendBroadcast发送的广播属于本地广播
    • 本地广播会将广播发送给与发送者位于同一应用中的接收者
    • 当不需要跨应用发送广播时,建议使用本地广播
    • 这种实现方法的效率更高(无需进行进程间通信)
    • 而且无需担心其他应用在收发广播时带来的任何安全问题

广播的数据结构

AMS中,所有注册的广播接收者都放在成员变量mRegisteredReceivers中,定义如下:

final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();

mRegisteredReceivers是一个HashMap,其中

  • key为接收者的IBinder对象

  • value为接收者的对象ReceiverList

    • 因为一个接收者中可能包含多个IntentFilter,所以ReceiverList是一个数组
    final class ReceiverList extends ArrayList<BroadcastFilter>
    
    • BroadcastFilter则是继承了IntentFilter,定义如下:
    final class BroadcastFilter extends IntentFilter {
        final ReceiverList receiverList; // 所属 receiver 的引用
        final String packageName;        // 所在应用的包名
        final String requiredPermission; // 发送广播时需要声明的权限字符串
        final int owningUid;             // 所在应用的 uid
        final int owningUserId;          // 所在应用的 userid
        ...
    }
    

ReceiverList的关键定义如下:

final class ReceiverList extends ArrayList<BroadcastFilter>
        implements IBinder.DeathRecipient {
    final ActivityManagerService owner;
    public final IIntentReceiver receiver; // 用户进程中定义的 IntentReceiver
    public final ProcessRecord app;        // 所属用户进程的 ProcessRecord 对象
    public final int pid;                  // 所属用户进程的pid
    public final int uid;                  // 所属用户进程的uid
    public final int userId;               // 用户id
    BroadcastRecord curBroadcast = null;   //
    boolean linkedToDeath = false;         // 是否注册了 binder 死亡监听
}

发送广播时,AMS中收到的广播消息首先会保存在mBroadcastQueues对象中,然后再发送给用户进程中的接收者。mBroadcastQueues是一个只有两个元素的数组,定义如下:

final BroadcastQueue[] mBroadcastQueues = new BroadcastQueue[2];

此外,AMS中还定义了两个变量:

    BroadcastQueue mFgBroadcastQueue;
    BroadcastQueue mBgBroadcastQueue;

AMS在构造方法中将这两个变量和mBroadcastQueues集合进行了关联:

    public ActivityManagerService(Context systemContext) {
        ...
        mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
                "foreground", BROADCAST_FG_TIMEOUT, false);
        mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
                "background", BROADCAST_BG_TIMEOUT, true);
        mBroadcastQueues[0] = mFgBroadcastQueue;
        mBroadcastQueues[1] = mBgBroadcastQueue;
        ...
    }
  • mFgBroadcastQueue用来保存带有FLAG_RECEIVER_FOREGROUND标志的广播,它要求接收者进程以foreground的优先级运行,这样执行的更快。
  • 如果不特别指定,一般的广播都会保存在mBgBroadcastQueue

我们看下BroadcastQueue类的主要结构:

public final class BroadcastQueue {
    final ArrayList<BroadcastRecord> mParallelBroadcasts = new ArrayList<>();
    final ArrayList<BroadcastRecord> mOrderedBroadcasts = new ArrayList<>();
}
  • mParallelBroadcasts用来保存所有的普通广播
  • mOrderedBroadcasts用来保存所有的有序广播

粘性广播在哪里呢?
系统中所有的粘性广播都保存在AMS的成员变量mStickyBroadcasts中,定义如下:

    final SparseArray<ArrayMap<String, ArrayList<Intent>>> mStickyBroadcasts =
            new SparseArray<ArrayMap<String, ArrayList<Intent>>>();
  • mStickyBroadcasts是一个SparseArray类型的数组,使用用户Id作为索引,保存的是ArrayMap对象
  • ArrayMap对象储存的是某个用户发送的所有的粘性广播,每条记录以Intentaction字符串作为索引,保存的内容是一个ArrayList对象
  • ArrayList对象其中储存了包含该actionIntent

广播的注册过程

动态注册是通过接口registerReceiver()完成的。应用注册receiver时,并不是直接调用AMS的接口来完成的,而是通过Context类中的方法,因为AMS的接口需要提供应用的ApplicationThread类的IBinder对象来作为参数,应用中得到这个对象比较麻烦。

Context中的registerReceiver()最终调用的是ContextImplregisterReceiverInternal()方法,代码如下:

class ContextImpl{
    private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
            IntentFilter filter, String broadcastPermission,
            Handler scheduler, Context context, int flags) {
        ...
        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();
        }
    }
}

registerReceiverInternal()方法最终调用的是AMSregisterReceiver()方法,代码如下:

    public Intent registerReceiver(IApplicationThread caller, String callerPackage,
            IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
            int flags) {
        // 确保不是 isolated 进程
        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) {
            ...
            // 从注册信息中获取 action 信息
            Iterator<String> actions = filter.actionsIterator();
            if (actions == null) {
                ArrayList<String> noAction = new ArrayList<String>(1);
                noAction.add(null);
                actions = noAction.iterator();
            }
            // 获取 user ID
            int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
            // 循环遍历 action
            while (actions.hasNext()) {
                String action = actions.next();
                // 遍历每个userID下的粘性广播Map
                for (int id : userIds) {
                    // 获取特定userID下的粘性广播Map
                    ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
                    if (stickies != null) {
                        // 从Map中查找集合中符合当前action信息的Intent集合
                        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 (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;
        // 如果注册时传入的 receiver 为空
        // 此处直接返回 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;
            }
            // 检查注册的 receiver 是否已经注册过了
            ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
            if (rl == null) {
                // rl为空说明没有注册过
                // 新建对象
                rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                        userId, receiver);
                if (rl.app != null) {
                    // 如果指定了进程对象,则把receiver保存在进程对象中
                    // 方便进程销毁时能及时释放该对象
                    final int totalReceiversForApp = rl.app.receivers.size();
                    if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) {
                        throw new IllegalStateException(...);
                    }
                    rl.app.receivers.add(rl);
                } else {
                    // 如果没有指定进程对象,则注册receiver的死亡通知
                    try {
                        receiver.asBinder().linkToDeath(rl, 0);
                    } catch (RemoteException e) {
                        return sticky;
                    }
                    rl.linkedToDeath = true;
                }
                mRegisteredReceivers.put(receiver.asBinder(), rl);// 保存新建的 rl
            }
            ...
            // 下面主要是针对 receiver 重复注册的情况
            BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage,
                    permission, callingUid, userId, instantApp, visibleToInstantApps);
            if (rl.containsFilter(filter)) {
                // 已经包含了本次提交filter,简单打印,不做其他处理
                Slog.w(TAG, "Receiver with filter " + filter
                        + " already registered for pid " + rl.pid
                        + ", callerPackage is " + callerPackage);
            } else {
                // 未包含本次提交的filter,添加到集合中
                rl.add(bf);
                if (!bf.debugCheck()) {
                    Slog.w(TAG, "==> For Dynamic broadcast");
                }
                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);
                    // 根据 intent 中的标志获取发送队列(bg还是fg)
                    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);
                    // 发送 Intent 到指定进程
                    queue.scheduleBroadcastsLocked();
                }
            }
            return sticky;
        }
    }

registerReceiver()方法看上去比较复杂,其实很多都是针对粘性(sticky)广播的:

  • 如果没有处理粘性(sticky)广播,只需要检查receiver是否已经注册

    • 没有注册过,就可以创建用来保存receiver的对象ReceiverList,并把它添加到mRegisteredReceivers集合中
    • 注册过的receiver可以重复注册,只要pid、``uiduserid相同就可以
      • 重复注册用于向某个receiver增加新的IntentFilter
  • 而对于粘性(sticky)广播

    • 如果调用registerReceiver()时参数receivernull,则立刻返回找到的第一个粘性广播的Intent
    • 否则,将查找系统中所有和注册时传入的Intent匹配的粘性广播,并通过BroadcastQueue来发送

我们再来看下广播的发送过程

广播的发送过程

应用发送广播调用的是Context类中的方法,发送广播的方法虽然很多,最后都是调用AMSbroadcastIntent()方法。

broadcastIntent()方法简单检查了调用者的权限后,转调内部方法broadcastIntentLocked()来完成广播发送。

broadcastIntentLocked()方法会

  • 先检查要广播的Intent

    • 如果是一些系统Intent,则调用相应的方法处理
    • 如果是粘性广播,则把广播的Intent加入AMS的粘性广播列表中
  • 最后查找所有的接收者,逐个调用它们

广播发送的时序图如下:
image

AMS.broadcastIntentLocked

我们看下具体实现:

    final int broadcastIntentLocked(...) {
        intent = new Intent(intent);
        ...
        userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
                ALLOW_NON_FULL, "broadcast", callerPackage);
        // 检查发送广播的用户是否正在运行
        if (userId != UserHandle.USER_ALL && !mUserController.isUserOrItsParentRunning(userId)) {
            if ((callingUid != SYSTEM_UID
                    || (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)
                    && !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
                return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
            }
        }
        final String action = intent.getAction();
        ...
        // 检查广播是否为 protected
        final boolean isProtectedBroadcast;
        try {
            isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
        } catch (RemoteException e) {
            Slog.w(TAG, "Remote exception", e);
            return ActivityManager.BROADCAST_SUCCESS;
        }
        // 确认发送广播的进程是否为 system
        final boolean isCallerSystem;
        switch (UserHandle.getAppId(callingUid)) {
            case ROOT_UID:
            case SYSTEM_UID:
            case PHONE_UID:
            case BLUETOOTH_UID:
            case NFC_UID:
            case SE_UID:
                isCallerSystem = true;
                break;
            default:
                isCallerSystem = (callerApp != null) && callerApp.persistent;
                break;
        }
        if (!isCallerSystem) {
            if (isProtectedBroadcast) {
                // 不是system进程,但是发送的广播却是 protected 的情况
                // 抛出安全异常
                ...
                throw new SecurityException(msg);
            } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
                    || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
                // 不是 system 进程,也不是 protected 广播
                // 但是,有一些特殊的广播还是不能发送,这里做一些限制
                if (callerPackage == null) {
                    ...
                    throw new SecurityException(msg);
                } else if (intent.getComponent() != null) {
                    if (!intent.getComponent().getPackageName().equals(
                            callerPackage)) {
                        String msg = "Permission Denial: not allowed to send broadcast "
                                + action + " to "
                                + intent.getComponent().getPackageName() + " from "
                                + callerPackage;
                        ...
                        throw new SecurityException(msg);
                    }
                } else {
                    // Limit broadcast to their own package.
                    intent.setPackage(callerPackage);
                }
            }
        }
        if (action != null) {
            // 从 SystemConfig 中查询当前 action 是否在 allow-implicit-broadcast 标签中
            // 就是查查当前 action 是否支持隐式广播
            if (getBackgroundLaunchBroadcasts().contains(action)) {
                ...
                // 如果是,增加一个Flag标记
                // 这个标记就表明这个广播可以作为隐式广播发送
                intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
            }
            switch (action) {
                // 检查处理一些特殊的 action
                // 这部分主要是检查和 PMS 有关的一些操作
                case Intent.ACTION_UID_REMOVED:
                case Intent.ACTION_PACKAGE_REMOVED:
                case Intent.ACTION_PACKAGE_CHANGED:
                ...
                    // 如果这个广播时从 PMS 来的,而且是关于应用删除或应用变化
                    // 需要从 task 中移除所有和该应用管理的 Activity 
                    break;
                ...
                case "com.android.launcher.action.INSTALL_SHORTCUT":
                    // As of O, we no longer support this broadcasts, even for pre-O apps.
                    // Apps should now be using ShortcutManager.pinRequestShortcut().
                    Log.w(TAG, "Broadcast " + action
                            + " no longer supported. It will not be delivered.");
                    return ActivityManager.BROADCAST_SUCCESS;
            }
            ...
        }
        // 对于粘性广播
        if (sticky) {
            // 检查广播发送方是否声明了 android.permission.BROADCAST_STICKY 权限
            if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
                    callingPid, callingUid)
                    != PackageManager.PERMISSION_GRANTED) {
                ...
                throw new SecurityException(msg);
            }
            if (requiredPermissions != null && requiredPermissions.length > 0) {
                // 发送粘性广播不能指定 permission
                return ActivityManager.BROADCAST_STICKY_CANT_HAVE_PERMISSION;
            }
            if (intent.getComponent() != null) {
                // 粘性广播不能指定特定组件名
                throw new SecurityException(
                        "Sticky broadcasts can't target a specific component");
            }
            if (userId != UserHandle.USER_ALL) {
                // 如果广播不是发给所有用户,先检查是否存在一个发给所有用户的相同的广播
                ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(UserHandle.USER_ALL);
                if (stickies != null) {
                    ArrayList<Intent> list = stickies.get(intent.getAction());
                    if (list != null) {
                        int N = list.size();
                        int i;
                        for (i=0; i<N; i++) {
                            if (intent.filterEquals(list.get(i))) {
                                // 检测到存在相同的广播,抛出异常
                                throw new IllegalArgumentException(
                                        "Sticky broadcast " + intent + " for user "
                                        + userId + " conflicts with existing global broadcast");
                            }
                        }
                    }
                }
            }
            // 将广播保存到 mStickyBroadcasts 中
            ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
            if (stickies == null) {
                stickies = new ArrayMap<>();
                mStickyBroadcasts.put(userId, stickies);
            }
            // 添加 Intent 信息列表
            ArrayList<Intent> list = stickies.get(intent.getAction());
            if (list == null) {
                list = new ArrayList<>();
                stickies.put(intent.getAction(), list);
            }
            final int stickiesCount = list.size();
            int i;
            for (i = 0; i < stickiesCount; i++) {
                if (intent.filterEquals(list.get(i))) {
                    // 如果 Intent 已经存在,覆盖
                    list.set(i, new Intent(intent));
                    break;
                }
            }
            if (i >= stickiesCount) {
                list.add(new Intent(intent));
            }
        }
        int[] users;
        if (userId == UserHandle.USER_ALL) {
            // 广播给所有用户的情况,获取所有的用户id
            users = mUserController.getStartedUserArray();
        } else {
            // 广播给特定用户
            users = new int[] {userId};
        }
        // 计算所有接收该 Intent 的 receiver
        List receivers = null;
        List<BroadcastFilter> registeredReceivers = null;
        if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
            // 如果 Intent 中没有指定 FLAG_RECEIVER_REGISTERED_ONLY 
            // 收集静态接收者
            receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
        }
        if (intent.getComponent() == null) {
            // 如果没有指定 Component,则查找匹配该 Intent 的所有 receiver
            if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
                // 针对发送给所有用户的广播,并且发送广播的 user 是 shell
                for (int i = 0; i < users.length; i++) {
                    // 遍历 userID 
                    ...
                    // 从 mReceiverResolver 中查找,动态注册的广播接收者都在这里
                    List<BroadcastFilter> registeredReceiversForUser = mReceiverResolver.queryIntent(intent, resolvedType, false /*defaultOnly*/, users[i]);
                    if (registeredReceivers == null) {
                        registeredReceivers = registeredReceiversForUser;
                    } else if (registeredReceiversForUser != null) {
                        registeredReceivers.addAll(registeredReceiversForUser);
                    }
                }
            } else {
                registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false /*defaultOnly*/, userId);
            }
        }
        final boolean replacePending =
                (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
        int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
        if (!ordered && NR > 0) {
            // 如果不是有序广播,也就是普通广播的情况
            if (isCallerSystem) {
                checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
                        isProtectedBroadcast, registeredReceivers);
            }
            // 获取发送队列
            final BroadcastQueue queue = broadcastQueueForIntent(intent);
            // 创建 BroadcastRecord 对象
            BroadcastRecord r = new BroadcastRecord(...);
            ...
            if (!replaced) {
                queue.enqueueParallelBroadcastLocked(r); // 加入到并行队列中
                queue.scheduleBroadcastsLocked(); // 发送广播
            }
            registeredReceivers = null;
            NR = 0;
        }
        int ir = 0;
        if (receivers != null) {
            // 说明存在静态注册的接收者
            ...
            int NT = receivers != null ? receivers.size() : 0;
            int it = 0;
            ResolveInfo curt = null;
            BroadcastFilter curr = null;
            while (it < NT && ir < NR) {
                if (curt == null) {
                    // 获取静态广播接收者
                    curt = (ResolveInfo)receivers.get(it);
                }
                if (curr == null) {
                    // 获取动态广播接收者
                    curr = registeredReceivers.get(ir);
                }
                if (curr.getPriority() >= curt.priority) {
                    // 优先把动态广播接收者插入到静态广播接收者
                    // 同优先级下,动态接受者会被插入到静态接收者后面
                    receivers.add(it, curr);
                    ir++;
                    curr = null;
                    it++;
                    NT++;
                } else {
                    // Skip to the next ResolveInfo in the final list.
                    it++;
                    curt = null;
                }
            }
        }
        // 在队列中加入剩下的动态接受者
        while (ir < NR) {
            if (receivers == null) {
                receivers = new ArrayList();
            }
            receivers.add(registeredReceivers.get(ir));
            ir++;
        }
        ...
        if ((receivers != null && receivers.size() > 0) || resultTo != null) {
            // 获取广播发送队列
            BroadcastQueue queue = broadcastQueueForIntent(intent);
            // 创建广播对象
            BroadcastRecord r = new BroadcastRecord(...);
            ...
            final BroadcastRecord oldRecord =
                    replacePending ? queue.replaceOrderedBroadcastLocked(r) : null;
            if (oldRecord != null) {
                // 如果存在旧的广播,调用 performReceiveLocked 执行广播
                if (oldRecord.resultTo != null) {
                    final BroadcastQueue oldQueue = broadcastQueueForIntent(oldRecord.intent);
                    try {
                        // 这个方法就会调用到 onReceived()
                        oldQueue.performReceiveLocked(...);
                    } catch (RemoteException e) {
                        ...
                    }
                }
            } else {
                queue.enqueueOrderedBroadcastLocked(r); // 将广播加入到order队列
                queue.scheduleBroadcastsLocked();       // 发送广播
            }
        } 
        ...
        return ActivityManager.BROADCAST_SUCCESS;
    }

broadcastIntentLocked()方法比较长,我们再简单梳理下:

  • 首先是检查发送的广播是否为一些特殊的广播
    • 尤其是从PMS中发出的有关应用安装变化相关的广播
  • 接下来是判断是否为粘性广播,如果是
    • 先是检查一些相关的权限,比如粘性广播不能带有permission,而且Intent必须指定Component
    • 然后创建对应的数据结构,并添加到mStickyBroadcasts集合中
  • 然后查找该广播对应的广播接收者
    • 如果是普通广播,会优先发给动态接收者
    • 如果是有序广播,会将动态接收者和静态接收者一起根据优先级排序,然后再创建BroadcastRecord对象并添加到有序广播队列中
  • 最后,通过scheduleBroadcastsLocked()发送广播

从上面的代码实现上可以看到,无论哪种广播,静态接收者之间一定会排序,而且相同优先级下,静态接收者会排在动态接收者之前。

为什么静态接收者一定要放到有序队列呢?
对于静态接收者来说,它所属的进程可能已经在运行,也可能没有。如果进程没有运行,就需要先启动它。首先进程的启动是一个耗时过程,而且启动有可能失败,这个过程只能逐一处理,不能简单的群发消息。

到这里,广播接收者和广播内容都已经检查准备好了,我们继续学习scheduleBroadcastsLocked()广播发送的过程

BroadcastQueue.scheduleBroadcastsLocked

scheduleBroadcastsLocked()方法只是发送了一个BROADCAST_INTENT_MSG消息,代码如下:

    public void scheduleBroadcastsLocked() {
        ...
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }

BROADCAST_INTENT_MSG消息的处理是调用processNextBroadcast()方法

    case BROADCAST_INTENT_MSG: {
        ...
        processNextBroadcast(true);
    } break;
    
    final void processNextBroadcast(boolean fromMsg) {
        synchronized (mService) {
            processNextBroadcastLocked(fromMsg, false);
        }
    }

调用到了processNextBroadcastLocked()方法。这个方法比较长,我们简要分析:

final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
    BroadcastRecord r;
    ...
    // 循环处理 mParallelBroadcasts 集合中的消息
    while (mParallelBroadcasts.size() > 0) {
        r = mParallelBroadcasts.remove(0);
        r.dispatchTime = SystemClock.uptimeMillis();
        r.dispatchClockTime = System.currentTimeMillis();
        ...
        final int N = r.receivers.size();
        ...
        for (int i=0; i<N; i++) {
            Object target = r.receivers.get(i);
            ...
            // 调用通知 receiver
            deliverToRegisteredReceiverLocked(r, (BroadcastFilter)target, false, i);
        }
        addBroadcastToHistoryLocked(r);
    }
    // 接下来处理 mPendingBroadcast 集合
    // 这个集合存放的是等待进程启动的广播
    if (mPendingBroadcast != null) {
        ...
        boolean isDead;
        if (mPendingBroadcast.curApp.pid > 0) {
            synchronized (mService.mPidsSelfLocked) {
                ProcessRecord proc = mService.mPidsSelfLocked.get(
                        mPendingBroadcast.curApp.pid);
                isDead = proc == null || proc.crashing;
            }
        } else {
            final ProcessRecord proc = mService.mProcessNames.get(
                    mPendingBroadcast.curApp.processName, mPendingBroadcast.curApp.uid);
            isDead = proc == null || !proc.pendingStart;
        }
        if (!isDead) {
            // It's still alive, so keep waiting
            return;
        } else {
            Slog.w(TAG, "pending app  ["
                    + mQueueName + "]" + mPendingBroadcast.curApp
                    + " died before responding to broadcast");
            mPendingBroadcast.state = BroadcastRecord.IDLE;
            mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
            mPendingBroadcast = null;
        }
    }
    // 处理 mOrderedBroadcasts 中的广播
    boolean looped = false;
    do {
        ...
        r = mOrderedBroadcasts.get(0);
        boolean forceReceive = false;
        ...
        int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
        if (mService.mProcessesReady && r.dispatchTime > 0) {
            long now = SystemClock.uptimeMillis();
            // forground 的 mTimeoutPeriod 超时是 10*1000
            // bgground 的 mTimeoutPeriod  超时是 60*1000
            if ((numReceivers > 0) && (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
                // 如果超时则终止广播
                ...
                broadcastTimeoutLocked(false); // forcibly finish this broadcast
                forceReceive = true;
                r.state = BroadcastRecord.IDLE;
            }
        }
        ...
        if (r.receivers == null || r.nextReceiver >= numReceivers
                || r.resultAbort || forceReceive) {
            // 没有多余的 receiver 了
            if (r.resultTo != null) {
                try {
                    ...
                    // 把广播结果传递给发送广播的进程
                    performReceiveLocked(r.callerApp, r.resultTo,
                        new Intent(r.intent), r.resultCode,
                        r.resultData, r.resultExtras, false, false, r.userId);
                    r.resultTo = null;
                } catch (RemoteException e) {
                    r.resultTo = null;
                    ...

                }
            }
            ...
        }
    } while (r == null);
    ...
    if (nextReceiver instanceof BroadcastFilter) {
        BroadcastFilter filter = (BroadcastFilter)nextReceiver;
        ...
        // 发送给接收者进程
        deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
        if (r.receiver == null || !r.ordered) {
            ...
            // 已经处理完成的情况
            r.state = BroadcastRecord.IDLE;
            // 处理下一条广播
            scheduleBroadcastsLocked();
        } else {
            if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) {
                scheduleTempWhitelistLocked(filter.owningUid,
                        brOptions.getTemporaryAppWhitelistDuration(), r);
            }
        }
        return;
    }
    ...
    ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
            info.activityInfo.applicationInfo.uid, false);
    ...
    if (app != null && app.thread != null && !app.killed) {
        // 如果是静态接收者,并且接收者对应的进程已经启动的情况
        try {
            app.addPackage(info.activityInfo.packageName,
                    info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
            // 调用 processCurBroadcastLocked 通知 receiver
            processCurBroadcastLocked(r, app, skipOomAdj);
            // 直接返回
            return;
        } 
        ...
    }
    ...
    // 走到这里说明进程没有启动,先调用 startProcessLocked 启动进程
    if ((r.curApp=mService.startProcessLocked(...)) == null) {
        ....
        // 如果进程启动失败,处理下一条广播
        scheduleBroadcastsLocked();
        r.state = BroadcastRecord.IDLE;
        return;
    }
    mPendingBroadcast = r;
    mPendingBroadcastRecvIndex = recIdx;
}

processNextBroadcastLocked()方法也只是对要发送的广播接收者的集合进行的遍历发送处理,真正通知到应用的部分是在deliverToRegisteredReceiverLocked()方法中,我们具体看下。

BroadcastQueue.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);
        ...
    }
    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) {
                ...
                app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                            data, extras, ordered, sticky, sendingUser, app.repProcState);
                ...
            }
        } else {
            receiver.performReceive(intent, resultCode, data, extras, ordered,
                    sticky, sendingUser);
        }
    }

我们已经在performReceiveLocked方法中明显看到app.thread字样了,这也就意味着开始去调用应用进程中的接口了,也就是ActivityThread中的scheduleRegisteredReceiver()接口,如下:

    public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
            int resultCode, String dataStr, Bundle extras, boolean ordered,
            boolean sticky, int sendingUser, int processState) throws RemoteException {
        ...
        receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                sticky, sendingUser);
    }

ActivityThread调用的是IIntentReceiverperformReceive()方法

IIntentReceiver是一个AIDL,跟踪实现是在LoadedApk中,具体的装配过程是在ContextImpl初始化时完成的

我们看下在LoadedApk中的关键定义

LoadedApk.performReceive

代码如下:

class LoadedApk{
    static final class ReceiverDispatcher {
        final static class InnerReceiver extends IIntentReceiver.Stub {
            ...
            @Override
            public void performReceive(...) {
                final LoadedApk.ReceiverDispatcher rd;
                ...
                // 调用内部的 performReceive() 方法
                rd.performReceive(...);
                ...
            }
        }
        ...
        public void performReceive(...) {
            final Args args = new Args(...);
            ...
            // 此处重点是执行通过 Args.getRunnable() 获取的 Runnable 对象
            // Runnable 对象中执行了 onReceive() 方法回调
            if (intent == null || !mActivityThread.post(args.getRunnable())) {
                if (mRegistered && ordered) {
                    IActivityManager mgr = ActivityManager.getService();
                    ...
                    args.sendFinished(mgr);
                }
            }
        }
        final class Args extends BroadcastReceiver.PendingResult {
            ...
            public final Runnable getRunnable() {
                return () -> {
                    final BroadcastReceiver receiver = mReceiver;
                    ...
                    try {
                        ...
                        // onReceive 回调
                        receiver.onReceive(mContext, intent);
                    }
                    ...
                    if (receiver.getPendingResult() != null) {
                        // mPendingResult 不为空,自动执行 finish()
                        finish();
                    }
                };
            }
        }
    }
}

这样一个广播的发送就结束了。。。

AMS的章节终于是磕磕绊绊的学完了,很多细节没有掌握,好在整体流程上暂时还留有印象。留此笔记方便复习

下一篇Android的图形显示系统

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值