Android 12:在 ActivityStarter 层拦截分享、搜索与 HTTP 外链

场景:客户自研 Launcher,需要在系统侧限制第三方应用通过 TextView 链接跳转、文本/图片分享等路径离开业务界面。Android 12 起,与「能否启动 Activity」强相关的逻辑集中在 wm 模块的 ActivityStarter 中,适合在此做统一拦截。

1. 背景与入口位置

  • Android 12 变更 :应用启动相关逻辑中,ActivityStarter 已从传统 am 侧迁移到窗口管理侧,源码路径为:
    frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
  • 拦截思路 :在解析 Intent、得到可启动目标(ResolveInfo 等)之后,根据 actiondata 等特征直接放弃解析结果(例如将 rInfo 置空),使后续流程无法找到可启动组件,等价于「禁止启动」。

2. 拦截分享、网页搜索与 http(s) 浏览

ActivityStarter 中合适位置(需与你们工程里 errintentrInfo 等变量生命周期一致)增加类似逻辑:对 ACTION_SEND / ACTION_SEND_MULTIPLE / ACTION_WEB_SEARCH 一律忽略;对 ACTION_VIEW 且 data scheme 为 http/https 的,除打日志外可在主线程弹出提示,并同样清空解析结果。

frameworks\base\services\core\java\com\android\server\wm\ActivityStarter.java

java 复制代码
// 屏蔽发送、分享及搜索
String action = intent.getAction();
Context context = mService.mUiContext;  // 获取可用于弹 Toast 等的 UI 上下文
if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)
        || Intent.ACTION_WEB_SEARCH.equals(action)) {
    Slog.w(TAG, "ignore an intent: " + intent);
    rInfo = null;
} else if (Intent.ACTION_VIEW.equals(action) && intent.getData() != null) {
    String scheme = intent.getData().getScheme();
    if (scheme != null && scheme.startsWith("http")) {
        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(context, "该功能暂不可使用", Toast.LENGTH_SHORT).show();
            }
        });
        rInfo = null;
        Slog.w(TAG, "ignore an intent: " + intent);
    }
}

说明要点:

  • ACTION_SEND / ACTION_SEND_MULTIPLE:覆盖系统分享、多选分享等入口。
  • ACTION_WEB_SEARCH:覆盖「网页搜索」类 Intent。
  • ACTION_VIEW + http:覆盖浏览器打开链接;若业务仍允许 tel:mailto: 等,可在分支中按 scheme 细化。
  • rInfo = null 后需保证与原有错误码、err 赋值逻辑一致,避免出现不一致的启动结果(需结合你们补丁前后完整编译与 CTS/冒烟验证)。

3. mUiContext 从何而来(ActivityTaskManagerService)

截图对应 ActivityTaskManagerService 构造函数片段:系统在创建 ATMS 时会保存当前系统进程的 ActivityThread,并从中取出 系统 UI 上下文 ,供需要与用户界面交互的系统服务使用(例如上述 Toast)。

frameworks\base\services\core\java\com\android\server\wm\ActivityTaskManagerService.java

java 复制代码
public ActivityTaskManagerService(Context context) {
    mContext = context;
    mFactoryTest = FactoryTest.getMode();
    mSystemThread = ActivityThread.currentActivityThread();
    mUiContext = mSystemThread.getSystemUiContext();
    // ... ClientLifecycleManager、WindowOrganizerController 等初始化
}

因此 ActivityStarter 里通过 mService.mUiContext(具体字段名以你们分支为准)拿到的,本质上是 ActivityThread.currentActivityThread() 关联的 getSystemUiContext(),与「普通应用进程里用 Activity 拿到的 Context」不是同一路径,但足以支撑系统侧轻量 UI 提示(仍须遵守多用户、显示层级等系统限制)。

4. 验证建议

  • 合并冲突ActivityStarter 在版本迭代中 diff 较多,建议基于同一 Android 12 基线打补丁并做 rebase 记录。
  • 日志 :保留 Slog.w(TAG, "ignore an intent: " + intent) 便于现场抓取完整 Intent,排查误杀。
  • 范围 :若仅针对「指定包名」拦截,可在上述判断外再增加 callingPackage / userid 等条件,避免影响系统组件或白名单应用。
相关推荐
海兰几秒前
【SpringBoot 】AOP企业级权限控制方案(二)
android·java·spring boot
阿pin2 分钟前
Android随笔-启动Zygote的rc文件是什么?
android·zygote·rc
帅次10 小时前
Android 高级工程师面试:Java 基础知识 近1年高频追问 22 题
android·java·面试
私人珍藏库11 小时前
[Android] zip解压缩管理-全格式压缩包一键解压+打包
android·app·生活·工具·多功能
雨白11 小时前
C语言:动态内存分配
android
Android-Flutter12 小时前
android compose 自定义Painter绘制图形 使用
android·kotlin·compose
我是一颗柠檬12 小时前
【Java项目技术亮点】覆盖索引与索引下推优化
android·java·开发语言
vigor51213 小时前
MySQL通过Mango实现分库分表
android·数据库·mysql
程序边界14 小时前
lac_agent自愈链路下篇——从systemd托管到真正的自愈
前端·javascript·chrome