Android AMS拦截Activity启动

在 Android 开发中,我们常会遇到一些第三方组件(如 GMS)在特定场景下自动弹出 Activity 的情况。这些不合时宜的弹窗往往会干扰产品的正常业务逻辑,而由于我们无法直接修改 GMS 的内部代码,只能另辟蹊径从系统层面寻找解决方案。本文将详细介绍如何在 Framework 层通过拦截 Activity 启动流程,实现对特定 GMS Activity 的屏蔽。

问题背景:无法控制的 GMS 弹窗

GMS(Google Mobile Services)作为安卓生态的重要组成部分,其内部包含了大量服务和组件。在实际使用中,我们发现 GMS 会在某些触发条件下自动弹出特定 Activity(例如本文中涉及的com.google.android.gms.nearby.discovery.fastpair.HalfSheetActivity),这类弹窗并非我们业务所需,却会打断用户操作流程。

由于 GMS 属于闭源组件,我们无法通过常规的代码修改来禁用其弹窗逻辑。因此,我们将解决思路转向 Framework 层 ------ 通过拦截 Activity 的启动流程,对目标 Activity 进行过滤和阻断。

技术调研:Activity 启动流程与拦截点分析

要实现 Activity 的拦截,首先需要深入理解 Android 系统中 Activity 的启动机制。在 Android 的 Framework 层,Activity 的启动逻辑主要封装在ActivityStarter.java中,其中execute()方法是启动流程的核心入口。

scss 复制代码
int execute() {
    // 省略部分代码
    
    if (mRequest.activityInfo == null) {
        mRequest.resolveActivity(mSupervisor);
    }
    // 省略部分代码
    executeRequest()
    
    // 省略部分代码
}

通过分析源码可以发现,execute()方法会先解析待启动的 Activity 信息(mRequest.activityInfo),然后调用executeRequest()执行具体的启动操作。这意味着在executeRequest()调用前,目标 Activity 的相关信息(如组件名、包名等)已经准备完毕,这正是我们实现拦截的理想时机。

executeRequest()作为启动流程的关键节点,在此时进行拦截既能确保获取到完整的 Activity 信息,又能在启动操作执行前阻断流程,避免无效的资源消耗。

实现方案:在 ActivityStarter 中添加拦截逻辑

基于上述分析,我们确定在ActivityStarter.executeRequest()方法中添加拦截逻辑。具体实现步骤如下:

1. 定义拦截列表

首先,我们需要维护一个需要拦截的 Activity 列表(filterList),将目标 GMS Activity 的组件信息(包名 + 类名)纳入其中。组件名可以通过ComponentName.flattenToString()方法获取标准格式(如com.google.android.gms/com.google.android.gms.nearby.discovery.fastpair.HalfSheetActivity)。

2. 在启动流程中添加过滤判断

在executeRequest()方法中,当系统完成 Activity 信息解析且启动状态为START_SUCCESS时,我们对目标 Activity 进行拦截判断:

less 复制代码
if (err == ActivityManager.START_SUCCESS && aInfo != null) {
    for (String pkg : filterList) {
        // 对比当前启动的Activity与拦截列表中的组件信息
        if (pkg.equals(aInfo.getComponentName().flattenToString())) {
            Slog.w(TAG, "filter intent " + intent + "," + aInfo.getComponentName().flattenToString());
            // 将启动状态改为取消状态
            err = START_CANCELED;
        }
    }
}

这段代码的核心逻辑是:当检测到当前启动的 Activity 组件名存在于拦截列表中时,将启动结果err设置为START_CANCELED,从而阻断 Activity 的启动流程。

验证结果:拦截效果测试

为了验证拦截逻辑的有效性,我们通过 ADB 命令直接启动目标 GMS Activity 进行测试:

bash 复制代码
adb shell am start -n com.google.android.gms/com.google.android.gms.nearby.discovery.fastpair.HalfSheetActivity

执行命令后,系统返回如下结果:

vbnet 复制代码
Starting: Intent { cmp=com.google.android.gms/.nearby.discovery.fastpair.HalfSheetActivity }
Error: Activity not started, unknown error code -96

其中,错误码-96对应的正是我们在代码中设置的START_CANCELED状态,这表明拦截逻辑已成功生效 ------ 目标 Activity 的启动请求被系统拒绝,达到了预期的拦截效果。

总结与扩展

通过在 Framework 层的ActivityStarter中添加拦截逻辑,我们成功实现了对特定 GMS Activity 的屏蔽。这种方案的优势在于:

  1. 无需修改 GMS 源码,适用于闭源组件的管控场景;
  1. 拦截点位于 Activity 启动流程的早期阶段,能有效避免无效的页面绘制和资源加载;
  1. 通过列表配置的方式,便于扩展和维护需要拦截的目标 Activity。

在实际应用中,我们可以根据业务需求动态调整filterList,实现对不同场景下弹窗的精细化管控。同时,这种思路也可推广到其他需要拦截系统或第三方组件 Activity 的场景中,为 Android 系统定制提供一种可行的技术方案。

相关推荐
数智工坊33 分钟前
机器人运动控制:采样、优化与学习三大流派深度对比与实战
android·学习·机器人
故渊at2 小时前
第二板块:Android 四大组件标准化学理 | 第八篇:Service 后台执行实体与优先级
android·gitee·service·前台服务·后台服务
会Tk矩阵群控的小木3 小时前
安卓群控系统对于游戏工作室实战教程
android·运维·游戏·adb·开源软件·个人开发
qeen873 小时前
【C++】类与对象之类的默认成员函数(二)
android·c语言·开发语言·c++·笔记·学习
故渊at4 小时前
第二板块:Android 四大组件标准化学理 | 第九篇:BroadcastReceiver 事件分发与有序广播
android·gitee·broadcast·广播·动态注册·静态注册
JohnnyDeng944 小时前
【Android】Room 数据库高级用法与性能调优:从查询瓶颈到毫秒级响应
android·性能优化·kotlin·room
zeqinjie4 小时前
Flutter 折叠屏 iPad / 宽屏适配实践
android·前端·flutter
ab_dg_dp4 小时前
Android 17+ 提取 AIDL 生成 Java 文件的实用脚本
android·java·python
Arrom5 小时前
DLNA 渲染端排障实战:从 20s 卡顿到 stale subscriber 的两周追凶之旅
android·java