Android 系统广播监听模块深度剖析(五)

191 阅读8分钟

Android 系统广播监听模块深度剖析

本人掘金号,欢迎点击关注:掘金号地址

本人公众号,欢迎点击关注:公众号地址

一、广播监听模块基础概念

1.1 广播机制概述

Android 系统广播监听模块是基于消息驱动的事件分发系统,它允许应用程序之间或应用与系统之间进行跨进程通信。广播的本质是一种异步通信机制,通过发送特定的 Intent 对象,系统或应用可以通知其他组件某些事件已经发生。

1.2 广播类型

  1. 普通广播:异步发送,所有注册的接收器都能接收到,无法被拦截。
  2. 有序广播:同步发送,接收器按优先级顺序接收,高优先级接收器可以拦截广播。
  3. 粘性广播:已弃用,发送后会一直存在,新注册的接收器也能接收到。

二、广播注册流程分析

2.1 动态注册流程

当应用通过Context.registerReceiver()方法动态注册广播接收器时,具体执行流程如下:

java

// Context.java
public abstract Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter);

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

@Override
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
                               String broadcastPermission, Handler scheduler) {
    // 验证权限
    final String resolvedType = verifyAndAddActionFilter(filter, receiver, callerPackage);
    // 获取ActivityManagerService代理
    final IActivityManager mgr = ActivityManager.getService();
    try {
        // 调用AMS的注册方法
        return mgr.registerReceiver(this, mMainThread.getThreadHandler(), receiver,
                                    filter, broadcastPermission, resolvedType);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

在上述代码中:

  1. verifyAndAddActionFilter方法用于验证和解析 IntentFilter。
  2. 通过ActivityManager.getService()获取 AMS 代理,然后调用 AMS 的registerReceiver方法进行注册。

2.2 AMS 注册处理

AMS 中registerReceiver方法的实现如下:

java

// ActivityManagerService.java
@Override
public Intent registerReceiver(IApplicationThread caller,
                               IIntentReceiver receiver,
                               IntentFilter filter,
                               String broadcastPermission,
                               String callingPackage,
                               String resolvedType) {
    // 检查权限
    enforceCrossUserPermission(BROADCAST_RECEIVE, UserHandle.getCallingUserId(), false,
                               "registerReceiver");
    synchronized (this) {
        // 获取或创建注册信息
        ReceiverList rl = registerReceiverLocked(callerApp,
                                                 callingPackage,
                                                 receiver,
                                                 filter,
                                                 broadcastPermission,
                                                 callingUid,
                                                 userId);
        // 将注册信息添加到全局列表
        mReceiverResolver.addFilter(filter, rl, rl.appInfo.uid,
                                    rl.appInfo.packageName,
                                    callingUid,
                                    userId);
        return null;
    }
}

private ReceiverList registerReceiverLocked(...) {
    // 创建ReceiverList对象
    ReceiverList rl = new ReceiverList(callerApp, callingPackage,
                                       receiver, registered);
    // 加入到应用的注册列表
    if (callerApp != null) {
        rl.app = callerApp;
        callerApp.receivers.add(rl);
    }
    return rl;
}

在 AMS 的注册流程中:

  1. 首先进行权限检查。
  2. 然后通过registerReceiverLocked方法创建ReceiverList对象,该对象包含了注册的接收器信息。
  3. 最后将ReceiverList添加到全局的mReceiverResolver中,以便后续广播匹配使用。

2.3 静态注册流程

静态注册是通过在AndroidManifest.xml文件中声明<receiver>标签实现的。系统在应用安装时解析AndroidManifest.xml,并将注册信息存储在PackageParser中。

xml

<receiver
    android:name=".MyReceiver"
    android:exported="true">
    <intent-filter>
        <action android:name="com.example.ACTION_EXAMPLE" />
    </intent-filter>
</receiver>

系统在安装应用时,会通过PackageParser解析上述配置,并将信息存储到PackageParser.Activity对象中。

java

// PackageParser.java
public Package parsePackage(File packageFile, int flags) {
    // 解析XML文件
    final XmlResourceParser parser = Xml.newPullParser();
    parser.setInput(new FileInputStream(packageFile), null);
    // 遍历XML节点
    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
        if (type == XmlPullParser.START_TAG) {
            if (parser.getName().equals("receiver")) {
                // 解析<receiver>标签
                final Activity receiver = parseActivity(parser, flags,
                                                        false, false, true);
                // 添加到Package对象
                pkg.activities.add(receiver);
            }
        }
    }
    return pkg;
}

三、广播发送流程分析

3.1 普通广播发送

应用通过Context.sendBroadcast()方法发送普通广播:

java

// Context.java
public abstract void sendBroadcast(Intent intent);

// ContextImpl.java
@Override
public void sendBroadcast(Intent intent) {
    warnIfCallingFromSystemProcess();
    // 设置默认发送者
    intent = intent != null ? intent : new Intent();
    intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
    // 调用AMS的发送方法
    mActivityManager.broadcastIntent(this, null, intent, null,
                                     null, 0, null, null, null,
                                     AppOpsManager.OP_NONE, null, false, false,
                                     getUserId());
}

在上述代码中:

  1. 首先对 Intent 进行一些默认设置。
  2. 然后通过 AMS 代理调用broadcastIntent方法发送广播。

3.2 AMS 广播分发处理

AMS 的broadcastIntent方法实现如下:

java

// ActivityManagerService.java
@Override
public final int broadcastIntent(IApplicationThread caller,
                                 String callerPackage,
                                 Intent intent,
                                 String resolvedType,
                                 IIntentReceiver resultTo,
                                 String resultData,
                                 Bundle resultExtras,
                                 int flags,
                                 String[] requiredPermissions,
                                 int appOp,
                                 Bundle bOptions,
                                 boolean serialized,
                                 boolean sticky,
                                 int userId) {
    enforceNotIsolatedCaller("broadcastIntent");
    synchronized (this) {
        // 解析Intent
        intent = verifyBroadcastLocked(intent);
        // 检查权限
        final int callingUid = Binder.getCallingUid();
        enforceCallingPermission(android.Manifest.permission.BROADCAST,
                                 "broadcastIntent");
        // 处理粘性广播
        if (sticky) {
            // 存储粘性广播
            stickyIntents.put(intent, new BroadcastRecord(intent, callerApp,
                                                          callerPackage, callingUid,
                                                          callingPid, userId,
                                                          requiredPermissions, appOp,
                                                          null, null, null,
                                                          null, 0, false, false,
                                                          false, null, false, false));
        }
        // 发送广播
        return broadcastIntentLocked(callerApp, callerPackage, intent, resolvedType,
                                     resultTo, resultData, resultExtras, flags,
                                     requiredPermissions, appOp, bOptions, serialized,
                                     sticky, callingUid, userId);
    }
}

private int broadcastIntentLocked(...) {
    // 查找匹配的接收器
    final List<ResolveInfo> receivers = collectReceiverComponents(intent, resolvedType,
                                                                 callingUid, userId);
    // 创建广播记录
    final BroadcastRecord r = new BroadcastRecord(intent, callerApp,
                                                  callerPackage, callingUid,
                                                  callingPid, userId,
                                                  requiredPermissions, appOp,
                                                  receivers, resultTo, resultData,
                                                  resultExtras, flags,
                                                  serialized, sticky, false,
                                                  null, false, false);
    // 分发广播
    final boolean replaced = enqueueParallelBroadcastLocked(r);
    // 启动广播处理线程
    scheduleBroadcastsLocked();
    return ActivityManager.RESULT_OK;
}

在 AMS 的广播分发流程中:

  1. 首先进行权限检查和 Intent 解析。
  2. 然后通过collectReceiverComponents方法查找匹配的接收器。
  3. 创建BroadcastRecord对象记录广播信息。
  4. 通过enqueueParallelBroadcastLocked方法将广播加入队列,并通过scheduleBroadcastsLocked方法启动广播处理线程。

四、广播接收流程分析

4.1 异步广播接收

当 AMS 完成广播分发后,会通过ActivityThread将广播事件发送到应用主线程。

java

// ActivityThread.java
class H extends Handler {
    public static final int EXECUTE_TRANSACTION = 159;
    public static final int BROADCAST_INTENT = 160;

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case BROADCAST_INTENT:
                // 处理广播事件
                handleBroadcast((BroadcastRecord) msg.obj);
                break;
            // 其他消息处理...
        }
    }
}

private void handleBroadcast(BroadcastRecord r) {
    final int N = r.receivers.size();
    for (int i = 0; i < N; i++) {
        final ReceiverList rec = r.receivers.get(i);
        final int delivery = rec.deliver;
        if (delivery > 0) {
            // 创建广播分发器
            final ReceiverDispatcher dispatcher = createReceiverDispatcher(
                    rec.receiverList, r, i,
                    r.callingPid, r.callingUid,
                    getPermissionsController());
            rec.dispatcher = dispatcher;
            // 触发接收回调
            dispatcher.performReceive(r.intent, r.resultCode, r.resultData,
                                      r.resultExtras, r.ordered,
                                      r.initialSticky, r.userId);
        }
    }
}

在上述代码中:

  1. ActivityThreadH类接收广播事件消息。
  2. 通过handleBroadcast方法遍历匹配的接收器列表。
  3. 为每个接收器创建ReceiverDispatcher对象。
  4. 调用performReceive方法触发接收器的onReceive回调。

4.2 有序广播接收

有序广播的处理流程与异步广播类似,但在 AMS 中会按照优先级顺序依次分发广播,并且高优先级接收器可以通过abortBroadcast方法拦截广播。

java

// ActivityManagerService.java
private int broadcastIntentLocked(...) {
    if (serialized) {
        // 有序广播处理
        final boolean replaced = enqueueOrderedBroadcastLocked(r);
        scheduleBroadcastsLocked();
    } else {
        // 异步广播处理
        final boolean replaced = enqueueParallelBroadcastLocked(r);
        scheduleBroadcastsLocked();
    }
    return ActivityManager.RESULT_OK;
}

private boolean enqueueOrderedBroadcastLocked(BroadcastRecord r) {
    // 将广播加入有序队列
    r.state = BroadcastRecord.STATE_PENDING;
    r.nextReceiver = 0;
    mOrderedBroadcasts.add(r);
    return true;
}

在有序广播处理中:

  1. AMS 将广播加入mOrderedBroadcasts队列。
  2. 依次分发广播,每次只处理一个接收器。
  3. 接收器可以通过abortBroadcast方法设置广播的aborted标志,从而拦截广播。

五、广播匹配机制

5.1 IntentFilter 匹配规则

IntentFilter用于定义广播接收的条件,其匹配规则基于Intentactioncategorydata属性。

java

// IntentFilter.java
public boolean match(Intent intent, String resolvedType, int matchFlags) {
    // 检查action匹配
    if (mActions != null) {
        final String intentAction = intent.getAction();
        if (intentAction != null) {
            for (int i = 0; i < mActions.size(); i++) {
                if (mActions.get(i).equals(intentAction)) {
                    // 找到匹配的action
                    if ((matchFlags & MATCH_CATEGORY_SCHEME) != 0) {
                        // 检查category和scheme匹配
                        if (matchCategoriesAndSchemes(intent, resolvedType,
                                                      matchFlags)) {
                            return true;
                        }
                    } else {
                        return true;
                    }
                }
            }
        }
    }
    return false;
}

private boolean matchCategoriesAndSchemes(Intent intent,
                                          String resolvedType,
                                          int matchFlags) {
    // 检查category匹配
    if (mCategories != null) {
        final String[] categories = intent.getCategories();
        if (categories != null) {
            for (int i = 0; i < mCategories.size(); i++) {
                boolean found = false;
                for (int j = 0; j < categories.length; j++) {
                    if (mCategories.get(i).equals(categories[j])) {
                        found = true;
                        break;
                    }
                }
                if (!found) {
                    return false;
                }
            }
        }
    }
    // 检查data匹配
    if (mDataSchemes != null || mDataAuthorities != null || mDataPaths != null) {
        // 解析Intent的data
        final Uri data = intent.getData();
        if (data != null) {
            return matchData(data, resolvedType, matchFlags);
        }
    }
    return true;
}

在上述代码中:

  1. match方法首先检查Intentaction是否匹配。
  2. 如果action匹配,再根据matchFlags检查categorydata是否匹配。
  3. matchCategoriesAndSchemes方法具体执行categorydata的匹配逻辑。

5.2 AMS 匹配逻辑

AMS 在分发广播时,通过collectReceiverComponents方法查找匹配的接收器:

java

// ActivityManagerService.java
private List<ResolveInfo> collectReceiverComponents(Intent intent,
                                                    String resolvedType,
                                                    int callingUid,
                                                    int userId) {
    final ArrayList<ResolveInfo> results = new ArrayList<>();
    // 查找动态注册的接收器
    final int matchingSize = mReceiverResolver.queryIntent(intent, resolvedType,
                                                           false, userId, results);
    // 查找静态注册的接收器
    final List<PackageParser.Activity> receivers =
            mPackageManager.queryIntentReceivers(intent, resolvedType,
                                                PackageManager.MATCH_ALL, userId);
    for (PackageParser.Activity receiver : receivers) {
        final ResolveInfo info = new ResolveInfo();
        info.activityInfo = receiver.info;
        results.add(info);
    }
    return results;
}

在 AMS 的匹配流程中:

  1. 首先通过mReceiverResolver查找动态注册的接收器。
  2. 然后通过PackageManager查找静态注册的接收器。
  3. 将所有匹配的接收器信息封装成ResolveInfo对象并返回。

六、广播接收器生命周期管理

6.1 动态接收器生命周期

动态注册的广播接收器的生命周期与注册它的组件(如 Activity)相关联。当组件销毁时,应及时调用Context.unregisterReceiver()方法注销接收器。

java

// Context.java
public abstract void unregisterReceiver(BroadcastReceiver receiver);

// ContextImpl.java
@Override
public void unregisterReceiver(BroadcastReceiver receiver) {
    final IActivityManager mgr = ActivityManager.getService();
    try {
        // 调用AMS的注销方法
        mgr.unregisterReceiver(this, receiver);
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

在 AMS 中,unregisterReceiver方法会从全局注册列表中移除对应的接收器信息。

6.2 静态接收器生命周期

静态注册的接收器在应用安装时注册,其生命周期与应用的生命周期相关。系统在需要时会自动创建和销毁静态接收器实例。

七、广播性能优化

7.1 减少不必要的注册

避免在频繁创建和销毁的组件中动态注册广播接收器,尽量在应用启动时进行注册。

7.2 优化 IntentFilter

只定义必要的actioncategorydata匹配条件,减少不必要的匹配计算。

7.3 避免阻塞主线程

onReceive方法中避免执行耗时操作,如需处理耗时任务,应启动 Service 或使用异步任务。

八、总结与展望

8.1 总结

通过对 Android 系统广播监听模块的源码级分析,我们深入了解了广播的注册、发送、接收和匹配机制。广播机制作为 Android 系统中重要的跨进程通信方式,其核心原理包括:

  1. 注册流程:动态注册通过 AMS 进行全局管理,静态注册在应用安装时解析配置。
  2. 发送流程:通过 AMS 实现广播的分发和队列管理。
  3. 接收流程:通过ActivityThread将广播事件发送到应用主线程,并触发接收器回调。
  4. 匹配机制:基于IntentFilter的规则匹配,结合动态和静态注册信息查找接收器。

8.2 展望

随着 Android 系统的不断发展,广播机制也在不断优化:

  1. 权限管理加强:Android 系统对广播权限的管理越来越严格,未来可能会进一步限制敏感广播的使用。
  2. 性能优化