ActivityManagerService 发送广播(5)

ActivityManagerService 发送广播

简述

AMS主要管理的四大组件,Activity,Service,Broadcast,ContentProvider。其中Activity和Service有一定类似,ContentProvider使用的场景比较少,广播的使用场景还是比较多的,常常用于跨进程通信,在系统中系统应用和系统通信使用的更多。
广播的使用非常方便,比直接使用aidl binder更加容易,所以一般如果通信频率不是非常高,都会通过广播来做进程间通信,我们这一节就来看一下app发送广播SystemServer做了什么。

注册广播

app开发注册广播有两个方案,静态注册和动态注册,静态注册通过AndroidManifest.xml,动态注册通过代码注册。
静态注册后AMS会通过collectReceiverComponents,通过PMS获取来获取静态广播注册的信息。
而动态注册则会记录在AMS侧。

app发送广播

app侧发送广播是从Context.sendBroadcast开始的。

1.1 Context.sendBroadcast
Intent内包含了广播的信息,这里通过binder调用了AMS的broadcastIntentWithFeature。

public void sendBroadcast(Intent intent, String receiverPermission) {
    warnIfCallingFromSystemProcess();
    String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
    String[] receiverPermissions = receiverPermission == null ? null
            : new String[] {receiverPermission};
    try {
        intent.prepareToLeaveProcess(this);
        // 详见1.2
        ActivityManager.getService().broadcastIntentWithFeature(
                mMainThread.getApplicationThread(), getAttributionTag(), intent, resolvedType,
                null, Activity.RESULT_OK, null, null, receiverPermissions,
                null /*excludedPermissions=*/, null, AppOpsManager.OP_NONE, null, false, false,
                getUserId());
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

1.2 ActivityManagerService.broadcastIntentWithFeature
这里已经到了AMS侧。
加上了AMS的大锁,根据call进行鉴权,然后调用broadcastIntentLocked进行广播发送。

public final int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId,
        Intent intent, String resolvedType, IIntentReceiver resultTo,
        int resultCode, String resultData, Bundle resultExtras,
        String[] requiredPermissions, String[] excludedPermissions,
        String[] excludedPackages, int appOp, Bundle bOptions,
        boolean serialized, boolean sticky, int userId) {
    enforceNotIsolatedCaller("broadcastIntent");
    synchronized(this) {
        intent = verifyBroadcastLocked(intent);

        final ProcessRecord callerApp = getRecordForAppLOSP(caller);
        final int callingPid = Binder.getCallingPid();
        final int callingUid = Binder.getCallingUid();

        final ProcessRecord resultToApp = callerApp;

        // 根据callUid鉴权,看是否有发送广播的权限。
        enforceBroadcastOptionPermissionsInternal(bOptions, callingUid);

        final long origId = Binder.clearCallingIdentity();
        try {
            // 调用broadcastIntentLocked,详见1.3
            return broadcastIntentLocked(callerApp,
                    callerApp != null ? callerApp.info.packageName : null, callingFeatureId,
                    intent, resolvedType, resultToApp, resultTo, resultCode, resultData,
                    resultExtras, requiredPermissions, excludedPermissions, excludedPackages,
                    appOp, bOptions, serialized, sticky, callingPid, callingUid, callingUid,
                    callingPid, userId, BackgroundStartPrivileges.NONE, null, null);
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }
}

1.3 ActivityManagerService.broadcastIntentLocked
调用了traceBegin和traceEnd用于记录发送广播的时间,中间调用broadcastIntentLockedTraced。

final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage,
        @Nullable String callerFeatureId, Intent intent, String resolvedType,
        ProcessRecord resultToApp, IIntentReceiver resultTo, int resultCode, String resultData,
        Bundle resultExtras, String[] requiredPermissions,
        String[] excludedPermissions, String[] excludedPackages, int appOp, Bundle bOptions,
        boolean ordered, boolean sticky, int callingPid, int callingUid,
        int realCallingUid, int realCallingPid, int userId,
        BackgroundStartPrivileges backgroundStartPrivileges,
        @Nullable int[] broadcastAllowList,
        @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
    final int cookie = BroadcastQueue.traceBegin("broadcastIntentLockedTraced");
    // 详见1.4
    final int res = broadcastIntentLockedTraced(callerApp, callerPackage, callerFeatureId,
            intent, resolvedType, resultToApp, resultTo, resultCode, resultData, resultExtras,
            requiredPermissions, excludedPermissions, excludedPackages, appOp,
            BroadcastOptions.fromBundleNullable(bOptions), ordered, sticky,
            callingPid, callingUid, realCallingUid, realCallingPid, userId,
            backgroundStartPrivileges, broadcastAllowList, filterExtrasForReceiver);
    BroadcastQueue.traceEnd(cookie);
    return res;
}

1.4 ActivityManagerService.broadcastIntentLockedTraced
这个方法很长,但是实际的逻辑很简单,主要是因为对很多特殊情况都做了特殊处理,所里导致方法很长。
前面做了一些权限检查,以及是否是系统发送广播,是否是受保护广播等。
如果是粘性广播,则由StickyBroadcast记录,有一个二级Map数据结构来记录。
然后需要计算广播等Receiver,分静态广播和动态广播,分别存储在receivers和registeredReceivers。
如果是无序广播且mEnableModernQueue为false,这个时候直接可以直接发送动态广播,然后后续发送静态广播。
否则后续根据优先级合并静态广播和动态广播然后一起入队列发送。
这里发送广播就是通过new BroadcastRecord,然后enqueueBroadcastLocked入队列。

final int broadcastIntentLockedTraced(ProcessRecord callerApp, String callerPackage,
        @Nullable String callerFeatureId, Intent intent, String resolvedType,
        ProcessRecord resultToApp, IIntentReceiver resultTo, int resultCode, String resultData,
        Bundle resultExtras, String[] requiredPermissions,
        String[] excludedPermissions, String[] excludedPackages, int appOp,
        BroadcastOptions brOptions, boolean ordered, boolean sticky, int callingPid,
        int callingUid, int realCallingUid, int realCallingPid, int userId,
        BackgroundStartPrivileges backgroundStartPrivileges,
        @Nullable int[] broadcastAllowList,
        @Nullable BiFunction<Integer, Bundle, Bundle> filterExtrasForReceiver) {
    // Ensure all internal loopers are registered for idle checks
    BroadcastLoopers.addMyLooper();

    // ... 如果caller是沙盒应用,需要通过SdkSandboxManagerLocal判断是否可以发送广播。

    // ...resultapp检查
    // 复制intent
    intent = new Intent(intent);

    // 及时应用不能发送广播给及时应用(及时应用是指不用完整安装即可使用的应用,即快应用)
    final boolean callerInstantApp = isInstantApp(callerApp, callerPackage, callingUid);
    if (callerInstantApp) {
        intent.setFlags(intent.getFlags() & ~Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
    }

    if (userId == UserHandle.USER_ALL && broadcastAllowList != null) {
            Slog.e(TAG, "broadcastAllowList only applies when sending to individual users. "
                    + "Assuming restrictive whitelist.");
            broadcastAllowList = new int[]{};
    }

    // ...

    // ...权限检查

    // 验证受保护的广播是否仅由系统发送,以及系统是否仅发送受保护的播放
    final boolean isProtectedBroadcast;
    try {
        isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
    } catch (RemoteException e) {
        // ...
    }

    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:
        case NETWORK_STACK_UID:
            isCallerSystem = true;
            break;
        default:
            isCallerSystem = (callerApp != null) && callerApp.isPersistent();
            break;
    }

    // 如果非系统应用,不能发送受保护广播
    if (!isCallerSystem) {
        if (isProtectedBroadcast) {
            String msg = "Permission Denial: not allowed to send broadcast "
                    + action + " from pid="
                    + callingPid + ", uid=" + callingUid;
            Slog.w(TAG, msg);
            throw new SecurityException(msg);

        } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
                || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
            if (callerPackage == null) {
                String msg = "Permission Denial: not allowed to send broadcast "
                        + action + " from unknown caller.";
                Slog.w(TAG, msg);
                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;
                    Slog.w(TAG, msg);
                    throw new SecurityException(msg);
                }
            } else {
                intent.setPackage(callerPackage);
            }
        }
    }

    boolean timeoutExempt = false;

    if (action != null) {
        // ...对特殊的一些action做操作,主要是一些PMS信息变更的广播,如app卸载移除,需要kill掉对应进程等。
    }

    final int callerAppProcessState = getRealProcessStateLocked(callerApp, realCallingPid);
    if (sticky) {
        // 粘性广播的权限检查。
        if (userId != UserHandle.USER_ALL) {
            // 如果不是发送给所有用户的广播,和现有的发送给所有用户的广播比较,防止冲突。
        }
        // 这里可以看到粘性广播的数据结构,userId为key,Value也是一个map。Value中key为action,value是StickyBroadcast列表。
        // 这里就是把新的StickyBroadcast添加到数据结构中去。
        ArrayMap<String, ArrayList<StickyBroadcast>> stickies = mStickyBroadcasts.get(userId);
        if (stickies == null) {
            stickies = new ArrayMap<>();
            mStickyBroadcasts.put(userId, stickies);
        }
        ArrayList<StickyBroadcast> list = stickies.get(intent.getAction());
        if (list == null) {
            list = new ArrayList<>();
            stickies.put(intent.getAction(), list);
        }
        final boolean deferUntilActive = BroadcastRecord.calculateDeferUntilActive(
                callingUid, brOptions, resultTo, ordered,
                BroadcastRecord.calculateUrgent(intent, brOptions));
        final int stickiesCount = list.size();
        int i;
        for (i = 0; i < stickiesCount; i++) {
            if (intent.filterEquals(list.get(i).intent)) {
                list.set(i, StickyBroadcast.create(new Intent(intent), deferUntilActive,
                        callingUid, callerAppProcessState));
                break;
            }
        }
        if (i >= stickiesCount) {
            list.add(StickyBroadcast.create(new Intent(intent), deferUntilActive, callingUid,
                    callerAppProcessState));
        }
    }

    int[] users;
    if (userId == UserHandle.USER_ALL) {
        users = mUserController.getStartedUserArray();
    } else {
        users = new int[] {userId};
    }

    final int cookie = BroadcastQueue.traceBegin("queryReceivers");
    List receivers = null;
    // 找出谁会接受这个广播,registeredReceivers里面放动态注册的广播,receivers为静态广播。
    List<BroadcastFilter> registeredReceivers = null;
    // 这个标记静态注册的Recevier收不到
    if ((intent.getFlags() & Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
        // AndroidManifest里面的静态注册的广播
        receivers = collectReceiverComponents(
                intent, resolvedType, callingUid, users, broadcastAllowList);
    }
    if (intent.getComponent() == null) {
        final PackageDataSnapshot snapshot = getPackageManagerInternal().snapshot();
        if (userId == UserHandle.USER_ALL && callingUid == SHELL_UID) {
            for (int i = 0; i < users.length; i++) {
                if (mUserController.hasUserRestriction(
                        UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
                    continue;
                }
                List<BroadcastFilter> registeredReceiversForUser =
                        mReceiverResolver.queryIntent(snapshot, intent,
                                resolvedType, false /*defaultOnly*/, users[i]);
                if (registeredReceivers == null) {
                    registeredReceivers = registeredReceiversForUser;
                } else if (registeredReceiversForUser != null) {
                    registeredReceivers.addAll(registeredReceiversForUser);
                }
            }
        } else {
            registeredReceivers = mReceiverResolver.queryIntent(snapshot, intent,
                    resolvedType, false /*defaultOnly*/, userId);
        }
    }
    BroadcastQueue.traceEnd(cookie);

    final boolean replacePending =
            (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;

    if (registeredReceivers != null && broadcastAllowList != null) {
        for (int i = registeredReceivers.size() - 1; i >= 0; i--) {
            final int owningAppId = UserHandle.getAppId(registeredReceivers.get(i).owningUid);
            if (owningAppId >= Process.FIRST_APPLICATION_UID
                    && Arrays.binarySearch(broadcastAllowList, owningAppId) < 0) {
                registeredReceivers.remove(i);
            }
        }
    }

    filterNonExportedComponents(intent, callingUid, callingPid, registeredReceivers,
            mPlatformCompat, callerPackage, resolvedType);
    int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
    // mEnableModernQueue是一个配置项,如果为true会使用BroadcastQueueModernImpl,否则会使用BroadcastQueueImpl
    if (!ordered && NR > 0 && !mEnableModernQueue) {
        if (isCallerSystem) {
            checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
                    isProtectedBroadcast, registeredReceivers);
        }
        // 如果mEnableModernQueue为false,广播队列有四个
        // BROADCAST_QUEUE_FG,BROADCAST_QUEUE_BG,BROADCAST_QUEUE_BG_OFFLOAD,BROADCAST_QUEUE_FG_OFFLOAD
        // 分别是前台队列,后台队列,前台负载队列,后台负载队列,会有不同的优先级,这里会通过intent的flag获取对应的队列。然后根据广播信息构建BroadcastRecord,放到队列中。  
        // 如果mEnableModernQueue为true,就只有一个BroadcastQueueModernImpl,但实际BroadcastQueueModernImpl里面也会有多个不同的优先级队列。
        final BroadcastQueue queue = broadcastQueueForIntent(intent);
        BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
                callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
                requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
                registeredReceivers, resultToApp, resultTo, resultCode, resultData,
                resultExtras, ordered, sticky, false, userId,
                backgroundStartPrivileges, timeoutExempt, filterExtrasForReceiver,
                callerAppProcessState);
        queue.enqueueBroadcastLocked(r);
        registeredReceivers = null;
        NR = 0;
    }

    // Merge into one list.
    int ir = 0;
    if (receivers != null) {
        // 防止刚安装的包立刻接收安装广播拉起自己来作为一个后门。
        String skipPackages[] = null;
        if (Intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
                || Intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
                || Intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
            Uri data = intent.getData();
            if (data != null) {
                String pkgName = data.getSchemeSpecificPart();
                if (pkgName != null) {
                    skipPackages = new String[] { pkgName };
                }
            }
        } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
            skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
        }
        if (skipPackages != null && (skipPackages.length > 0)) {
            for (String skipPackage : skipPackages) {
                if (skipPackage != null) {
                    int NT = receivers.size();
                    for (int it=0; it<NT; it++) {
                        ResolveInfo curt = (ResolveInfo)receivers.get(it);
                        if (curt.activityInfo.packageName.equals(skipPackage)) {
                            receivers.remove(it);
                            it--;
                            NT--;
                        }
                    }
                }
            }
        }

        int NT = receivers != null ? receivers.size() : 0;
        int it = 0;
        ResolveInfo curt = null;
        BroadcastFilter curr = null;
        // 按照优先级排序,把receivers和registeredReceivers合并放到receivers。
        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 {
                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) {
        // 如果有Receiver,放到对应队列。
        BroadcastQueue queue = broadcastQueueForIntent(intent);
        filterNonExportedComponents(intent, callingUid, callingPid, receivers,
                mPlatformCompat, callerPackage, resolvedType);
        BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage,
                callerFeatureId, callingPid, callingUid, callerInstantApp, resolvedType,
                requiredPermissions, excludedPermissions, excludedPackages, appOp, brOptions,
                receivers, resultToApp, resultTo, resultCode, resultData, resultExtras,
                ordered, sticky, false, userId,
                backgroundStartPrivileges, timeoutExempt, filterExtrasForReceiver,
                callerAppProcessState);

        queue.enqueueBroadcastLocked(r);
    } else {
        // 没有Receiver对这个广播感兴趣,只记录一下。
        if (intent.getComponent() == null && intent.getPackage() == null
                && (intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
            addBroadcastStatLocked(intent.getAction(), callerPackage, 0, 0, 0);
        }
    }

    return ActivityManager.BROADCAST_SUCCESS;
}

小结

AMS发送广播逻辑比较简单,主要是计算有多少Receivers,然后将广播信息封装至BroadcastRecord,放入队列。
处理方法较长,除去有一些权限检查,还有一些特殊Action的逻辑处理,但是总体逻辑还是比较简单。

### ActivityManagerService 工作原理 ActivityManagerService (AMS)Android 系统中的核心组件之一,负责管理应用程序的生命周期以及资源分配。作为系统服务的一部分,AMS 运行在 system_server 中并提供了一系列 API 来控制和监控应用活动。 #### 生命周期管理 当一个新的 activity 被启动时,AMS 会接收到相应的请求并通过一系列内部机制来创建、暂停、恢复或销毁这些 activities。这涉及到与 WindowManager 和其他系统服务之间的交互[^1]。 #### 广播分发流程 广播发送过程中存在两个 Handler 消息传递环节:一是在 `system_server` 内部用于更新 BroadcastQueue;二是向目标应用程序发出 onReceive 接口调用的通知。这种设计使得整个广播事件能够被高效地异步处理[^2]。 ### 源码解析 对于 AMS 的实现细节,在源文件中可以找到如下关键函数: ```java // 启动新 Activity 请求入口 public final class ActivityManagerService extends IActivityManager.Stub { ... private void startActivityLocked(IApplicationThread caller, String callingPackage, Intent intent, ...) { ... } } ``` 此方法定义了如何响应来自客户端发起的新 activity 启动命令,并通过复杂的逻辑链路最终完成任务栈管理和界面切换操作。 另外还有关于广播注册的部分代码片段展示了广播接收器是如何被加入到队列等待执行的: ```java private boolean broadcastIntentLocked(...) throws RemoteException { // 将广播意图添加至相应队列... mH.sendMessage(PRIORITY_BROADCAST_INTENT); return true; } ``` 这里利用了一个名为 `mH` 的 Handler 对象来进行消息循环调度,从而实现了上述提到过的两次异步处理过程。 ### 使用方法 开发者通常不需要直接与 AMS 打交道,因为大多数功能都已经被封装到了更高层次的应用框架里。然而,在某些特殊情况下(比如自定义 ROM 开发),理解其工作机制可以帮助更好地优化性能或者解决问题。 如果确实需要访问底层接口,则可以通过 AIDL 定义的服务端 stub 类 (`IActivityManager`) 实现远程过程调用(RPC),进而间接操控 AMS 提供的功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值