场景:客户自研 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等)之后,根据action、data等特征直接放弃解析结果(例如将rInfo置空),使后续流程无法找到可启动组件,等价于「禁止启动」。
2. 拦截分享、网页搜索与 http(s) 浏览
在 ActivityStarter 中合适位置(需与你们工程里 err、intent、rInfo 等变量生命周期一致)增加类似逻辑:对 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
1 | // 屏蔽发送、分享及搜索 |
说明要点:
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
1 | public ActivityTaskManagerService(Context context) { |
因此 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等条件,避免影响系统组件或白名单应用。
本文链接:
http://longzhiye.top/2025/12/07/2025-12-07/