IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android 9.0系统源码分析(一)广播的注册 -> 正文阅读

[移动开发]Android 9.0系统源码分析(一)广播的注册

1、我们在Activity种动态注册广播,首先会触发ContextImpl的registerReceiver方法:

framework/base/core/java/android/app/ContextImpl.java

class ContextImpl extends Context {
	...
    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
            String broadcastPermission, Handler scheduler, int flags) {
        return registerReceiverInternal(receiver, getUserId(),
                filter, broadcastPermission, scheduler, getOuterContext(), flags);
    }
	...
	     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();
                }
                //0101调用LoadedApk对象的方法,将广播接收者receiver封装成一个实现了IIntentReceiver接口的Binder对象rd(ReceiverDispatcher)
                rd = mPackageInfo.getReceiverDispatcher(
                        receiver, context, scheduler,
                        mMainThread.getInstrumentation(), true);
            } else {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                // 0102将广播接收者receiver封装成一个实现了IIntentReceiver接口的Binder对象rd(ReceiverDispatcher)
                rd = new LoadedApk.ReceiverDispatcher(
                        receiver, context, scheduler, null, true).getIIntentReceiver();
            }
        }
        try {
            //0103调用ActivityManagerService对象的方法来进行注册
            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();
        }
    }
    ...
}

2、在ContextImpl的registerReceiverInternal方法中,首先会在【注释0101】或者【注释0102】处获取LoadApk的内部类ReceiverDispatcher的实例,该对象是一个实现了IIntentReceiver接口的Binder对象,然后在【注释0103处】调用ActivityManagerService对象的registerReceiver方法:

framework/base/service/java/com/android/service/am/ActivityManagerService.java

public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
        ...
	        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) {
                // 0201 根据caller从ProcessRecord缓存列表中查询ProcessRecord对象caller,用来描述正在请求AMS注册广播接收者的一个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);
                }
                callingUid = callerApp.info.uid;
                callingPid = callerApp.pid;
            } else {
                callerPackage = null;
                callingUid = Binder.getCallingUid();
                callingPid = Binder.getCallingPid();
            }

            instantApp = isInstantApp(callerApp, callerPackage, callingUid);
            // 0203 获取注册广播的用户的userId(UserController是多用户功能的用户管理,一些系统包含访客模式,或者多用户,每个用户就会有一个id)
            userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
                    ALLOW_FULL_ONLY, "registerReceiver", callerPackage);

            // 获取需要注册广播的IntentFilter中所有的action
            Iterator<String> actions = filter.actionsIterator();
            // 如果注册广播没有Action则添加一个null
            if (actions == null) {
                ArrayList<String> noAction = new ArrayList<String>(1);
                noAction.add(null);
                actions = noAction.iterator();
            }

            // Activity组件在注册一个广播接收者时,并不是直接将这个广播接收者注册到了AMS中,而是将与它关联
            // 的一个InnerReceiver对象注册到了AMS中。当AMS接收到一个广播时,它就会根据这个广播的类型在内
            // 部知道对应的InnerReceiver对象,然后再通过这个对象将这个广播发送给对应的广播接收者。AMS中每
            // 一个广播接收者都是使用一个BroadcastFilter对象来描述的,而每一个BroadcastFilter对象又是根
            // 据它所描述的广播接收者所关联的一个BroadcastFilter对象,以及所要接受的广播类型来创建。由于在
            // 一个应用程序中,不同的Activity组件可能会使用同一个BroadcastFilter对象来注册不同的广播接收
            // 者,因此AMS会使用一个ReceiverList列表来保存这些使用了相同InnerReceiver对象来注册的广播接
            // 收者,并且以它们所使用的InnerReceiver对象为关键字。

            // Collect stickies of users
            // 收集与注册用户userId相关的所有已经被广播过的Intent,存储在stickyIntents中
            // 包含所有用户以及注册广播进程对应的用户
            // 第一个UserHandle.USER_ALL表示设备上所有的用户,
            // 第二个是callingUid对应用户的userId(当前用户的userId)
            int[] userIds = {UserHandle.USER_ALL, UserHandle.getUserId(callingUid)};
            // 这里只通过action进行过滤
            while (actions.hasNext()) {
                String action = actions.next();
                // 遍历与调度进程相关的用户id
                for (int id : userIds) {
                    // 根据userId查询已经发送过的对应的Intent列表
                    ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(id);
                    // 如果已经发送的Intent里包含上面要注册的广播的action的Intent,将其保存到stickyIntents中
                    if (stickies != null) {
                        // 根据action查询Intent列表
                        ArrayList<Intent> intents = stickies.get(action);
                        if (intents != null) {
                            if (stickyIntents == null) {
                                stickyIntents = new ArrayList<Intent>();
                            }
                            stickyIntents.addAll(intents);
                        }
                    }
                }
            }
        }

        // 下面对通过action过滤出来粘性广播的Intent列表,包括:action,type,scheme,data,categories
        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.
                // 查找与IntentFilter匹配的Intent
                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);
        // 如果广播接收器为null,则直接返回第一个Intent结束注册
        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(ArrayList<BroadcastFilter>),
            // 第一次注册为null,receiver对应的是一个BroadcastFilter列表,也就是说可以通过调用
            // registerReceiver来为receiver注册不同的广播条件。
            ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
            // 缓存中没有,说明还没有注册过
            if (rl == null) {
                // 如果没有就创建新的广播接收者(里面包含广播过滤器列表)列表
                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;
                }
                // 将receiver以及对应的ReceiverList列表放到mRegisteredReceivers中
                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);
            }
            // 创建BroadcastFilter对象bf,用来描述正在注册的广播接收者,并添加到ReceiverList队列rl中
            // 以及mReceiverResolver中
            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 {
                rl.add(bf);
                if (!bf.debugCheck()) {
                    Slog.w(TAG, "==> For Dynamic broadcast");
                }
                // 添加到已注册接收器的广播解析器中,注册完成
                mReceiverResolver.addFilter(bf);
            }

            // Enqueue broadcasts for all existing stickies that match
            // this filter.
            // 上面注册结束以后,如果筛选出了与当前注册的IntentFilter匹配的粘性广播的Intent列表,
            // 就将所有匹配的Intent逐条发送广播给当前的注册者receiver,可以看到这里的接受者receivers
            // 里面就只有当前创建的一个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);
                    // 根据Intent返回广播队列
                    BroadcastQueue queue = broadcastQueueForIntent(intent);
                    // 需要发送的一条广播记录,receivers包含了所有能接收该条广播的接收器
                    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);
                    // 0204调度广播,发送BROADCAST_INTENT_MSG消息,触发处理下一个广播。但是如果目前有广播还在发送的处理过程中,这次推动不会起作用
                    queue.scheduleBroadcastsLocked();
                }
            }

            return sticky;
        }
    }
    ...
     //0202 通过for循环来从mLruProcesses列表中遍历是否存在该IApplicationThread,如果存在返回对应的Index,否则返回-1.
    private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
        final IBinder threadBinder = thread.asBinder();
        // Find the application record.
        for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
            final ProcessRecord rec = mLruProcesses.get(i);
            if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
                return i;
            }
        }
        return -1;
    }

    // 0201获取进程信息
    ProcessRecord getRecordForAppLocked(IApplicationThread thread) {
        if (thread == null) {
            return null;
        }
        //0202 调用方法获取app的索引
        int appIndex = getLRURecordIndexForAppLocked(thread);
        if (appIndex >= 0) {
            return mLruProcesses.get(appIndex);
        }

        // Validation: if it isn't in the LRU list, it shouldn't exist, but let's
        // double-check that.
        final IBinder threadBinder = thread.asBinder();
        final ArrayMap<String, SparseArray<ProcessRecord>> pmap = mProcessNames.getMap();
        for (int i = pmap.size() - 1; i >= 0; i--) {
            final SparseArray<ProcessRecord> procs = pmap.valueAt(i);
            for (int j = procs.size() - 1; j >= 0; j--) {
                final ProcessRecord proc = procs.valueAt(j);
                if (proc.thread != null && proc.thread.asBinder() == threadBinder) {
                    Slog.wtf(TAG, "getRecordForApp: exists in name list but not in LRU list: "
                            + proc);
                    return proc;
                }
            }
        }

        return null;
    }
	...
}  
  • 在【注释0201】处调用getRecordForAppLocked来查询ProcessRecord对象是否存在。
  • 在【注释0202】处调用getLRURecordIndexForAppLocked方法获取app的索引。

上面时注册广播的核心代码,主要是先判断注册的广播的Action是不是已经存在AMS中的粘性广播中,如果存在就将这些Intent单独保存到一个列表中,然后处理广播接收器,上面代码和注释写的很清楚了,广播注册不是直接将receiver保存在AMS中,而是先将其封装到实现了IIntentReceiver接口的Binder对象rd中,然后将这个对象放到ReceiverList对象中,这个ReceiverList对象是一个对应receiver的IntentFilter列表,但是这个列表对象也包含了该receiver对象,也就是将receiver以及其对应的IntentFilter列表封装到了ReceiverList对象中,这样每个广播接收者以及其Action都封装好了,然后将其放到该应用所在进程的ReceiverList对象列表中,这样整个广播注册就完成了。

其实缕清了这个结构就看懂广播注册了:首先是一个进程对象ProcessRecord,里面有一个广播的列表ArraySet,这个列表表示该进程注册的所有广播接收者,每个ReceiverList对象包含了一个广播接收者(实现了IIntentReceiver接口的Binder对象)封装和与该广播接收者对应的多个Action对应的IntentFilter对象的封装BroadcastFilter列表,这个ReceiverList对象是将注册的广播接收者以及对应的多个Action对应起来,这样就能查找对应的广播接收者,怎么调用我们下一篇发送广播会详细讲解。

3、在【注释0203】处调用UserController的handleIncomingUser方法获取注册广播的用户id

framework/base/service/java/com/android/service/am/UserController.java

class UserController implements Handler.Callback {
	...
    int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll,
            int allowMode, String name, String callerPackage) {
        final int callingUserId = UserHandle.getUserId(callingUid);
        if (callingUserId == userId) {
            return userId;
        }

        // Note that we may be accessing mCurrentUserId outside of a lock...
        // shouldn't be a big deal, if this is being called outside
        // of a locked context there is intrinsically a race with
        // the value the caller will receive and someone else changing it.
        // We assume that USER_CURRENT_OR_SELF will use the current user; later
        // we will switch to the calling user if access to the current user fails.
        int targetUserId = unsafeConvertIncomingUser(userId);

        if (callingUid != 0 && callingUid != SYSTEM_UID) {
            final boolean allow;
            if (mInjector.isCallerRecents(callingUid)
                    && callingUserId == getCurrentUserId()
                    && isSameProfileGroup(callingUserId, targetUserId)) {
                // If the caller is Recents and it is running in the current user, we then allow it
                // to access its profiles.
                allow = true;
            } else if (mInjector.checkComponentPermission(INTERACT_ACROSS_USERS_FULL, callingPid,
                    callingUid, -1, true) == PackageManager.PERMISSION_GRANTED) {
                // If the caller has this permission, they always pass go.  And collect $200.
                allow = true;
            } else if (allowMode == ALLOW_FULL_ONLY) {
                // We require full access, sucks to be you.
                allow = false;
            } else if (mInjector.checkComponentPermission(INTERACT_ACROSS_USERS, callingPid,
                    callingUid, -1, true) != PackageManager.PERMISSION_GRANTED) {
                // If the caller does not have either permission, they are always doomed.
                allow = false;
            } else if (allowMode == ALLOW_NON_FULL) {
                // We are blanket allowing non-full access, you lucky caller!
                allow = true;
            } else if (allowMode == ALLOW_NON_FULL_IN_PROFILE) {
                // We may or may not allow this depending on whether the two users are
                // in the same profile.
                allow = isSameProfileGroup(callingUserId, targetUserId);
            } else {
                throw new IllegalArgumentException("Unknown mode: " + allowMode);
            }
            if (!allow) {
                if (userId == UserHandle.USER_CURRENT_OR_SELF) {
                    // In this case, they would like to just execute as their
                    // owner user instead of failing.
                    targetUserId = callingUserId;
                } else {
                    StringBuilder builder = new StringBuilder(128);
                    builder.append("Permission Denial: ");
                    builder.append(name);
                    if (callerPackage != null) {
                        builder.append(" from ");
                        builder.append(callerPackage);
                    }
                    builder.append(" asks to run as user ");
                    builder.append(userId);
                    builder.append(" but is calling from user ");
                    builder.append(UserHandle.getUserId(callingUid));
                    builder.append("; this requires ");
                    builder.append(INTERACT_ACROSS_USERS_FULL);
                    if (allowMode != ALLOW_FULL_ONLY) {
                        builder.append(" or ");
                        builder.append(INTERACT_ACROSS_USERS);
                    }
                    String msg = builder.toString();
                    Slog.w(TAG, msg);
                    throw new SecurityException(msg);
                }
            }
        }
        if (!allowAll) {
            ensureNotSpecialUser(targetUserId);
        }
        // Check shell permission
        if (callingUid == Process.SHELL_UID && targetUserId >= UserHandle.USER_SYSTEM) {
            if (hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, targetUserId)) {
                throw new SecurityException("Shell does not have permission to access user "
                        + targetUserId + "\n " + Debug.getCallers(3));
            }
        }
        return targetUserId;
    }
}

4 在【注释0204】处调用BroadcastQueue的scheduleBroadcastsLocked方法来驱动广播。

framework/base/service/java/com/android/service/am/BroadcastQueue.java

public final class BroadcastQueue {
    // 驱动广播,所有广播都应该从这里走,然后会到processNextBroadcast
    public void scheduleBroadcastsLocked() {
        if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
                + mQueueName + "]: current="
                + mBroadcastsScheduled);
        // mBroadcastsScheduled用来描述AMS是否已经向它所运行在的线程的消息队列发送了一个类型为
        // BROADCAST_INTENT_MSG的消息。AMS就是通过这个BROADCAST_INTENT_MSG消息类调度保存在无
        // 序广播调度队列mParallelBroadcasts和有序广播调度队列mOrderedBroadcasts中的广播转发任务的
        if (mBroadcastsScheduled) {// 如果true说明消息队列已经存在一个类型为BROADCAST_INTENT_MSG的消息了
            return;
        }
        // 虽然这里只发送了发送广播的消息,但是这一步执行完之后就已经标记广播发送了,因此可以看出广播发送和接
        // 受是异步的,即广播发送者将一个广播发送给AMS后,不会等待AMS将这个广播转发给广播接收者处理
        mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
        mBroadcastsScheduled = true;
    }
}
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-07-04 23:03:58  更:2022-07-04 23:04:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 2:55:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码