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 系统定制提供一种可行的技术方案。

相关推荐
阿巴斯甜10 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker11 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952712 小时前
Andorid Google 登录接入文档
android
黄林晴13 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android