Google 收紧权限政策,后台启动又难了
Google 收紧权限政策,后台启动又难了
从一条 crash 日志说起
去年十月份,我维护的一个工具类 App 在 Pixel 7 上突然报了一批 SecurityException。堆栈信息指向一个很常见的操作:后台 Service 通过 startActivity 拉起一个前台界面。错误消息写得明明白白——Background activity start not allowed。用户系统版本是 Android 14,API 34。
这行代码在 Android 13 上跑得好好的,到了 14 就直接崩。没有 deprecation 警告,没有编译期提示,运行时才给你一巴掌。我当时的第一反应是查文档,结果官方文档里关于这个改动的描述藏在 "Behavior changes: all apps" 页面的某个折叠段落里,措辞平淡得像在说今天天气不错。Google 管这叫 "增强后台启动活动的限制",我管这叫"不声不响砍你一刀"。
这已经不是 Android 第一次收紧后台权限了。从 Android 8 的后台执行限制,到 10 的 Activity 后台启动限制,再到 12 的 exact alarm 权限和 Notification trampoline 限制,每一次大版本更新,后台这块蛋糕都在被一点点切走。但 Android 14 这次尤其狠,因为它把限制范围扩大到了所有应用,包括那些 target API 还没到 34 的老应用。以前好歹还有个"target 低版本可以苟一苟"的缓冲期,现在连这条退路都堵死了。
官方说辞与实际体感
Google 的官方理由永远那么正确:保护用户隐私、减少干扰、提升电池续航。Android 14 的变更日志里,产品经理腔调十足的句子占了大半篇幅。比如什么"确保用户始终掌控设备上发生的活动",翻译成工程师语言就是"你们这些做后台的,以后都给我老实点"。
电池续航这个借口用了快十年。Android 8 引入后台限制时说是为了 Doze 模式省电,Android 10 砍后台定位时说是为了减少功耗,Android 12 限制 exact alarm 时说是为了降低唤醒次数。每次都有数据支撑,每次都有实验室测试。但真实用户的手机续航真的变好了吗?我观察到的现象是,Google 自己的 Google Play Services 永远在后台活跃,系统级应用的电池消耗排名常年霸榜,第三方开发者却被 increasingly 苛刻的规则捆住手脚。
这里有个具体的数字对比。Android 14 的兼容性文档提到,后台启动 Activity 的拒绝率在某些测试场景下提升了 40%。但文档没说的是,这 40% 里有多少是恶意应用,有多少是正经工具。比如我做的那个 App,核心功能是在检测到特定蓝牙设备连接时弹出一个快捷操作面板。用户明确授权过,功能也是刚需,但现在这个流程在 Android 14 上直接断裂。解决方案?去适配那个半残不全的 android.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND 权限,或者让用户手动点通知,把原本一步的操作拆成三步。
更讽刺的是,Google 同时在大力推自己的跨设备互联生态。Pixel 手机的 "Nearby Share"、Chromebook 的 "Phone Hub"、Wear OS 的各种联动,这些功能哪一个离得开后台唤醒和跨进程启动?规则是 Google 定的,特权也是 Google 自己拿的。Android 的权限系统越来越像封建时代的行会制度:行会成员(系统应用、Google 签名应用)享有豁免权,外来工匠(第三方开发者)则被层层规章限制。
那个叫 `android:sharedUserId` 的幽灵
说到特权,不得不提一个被 Google 默默埋葬的老机制。android:sharedUserId 曾经是 Android 系统应用之间共享数据、共享权限的常用手段。两个应用声明相同的 sharedUserId,就能在同一个 Linux UID 下运行,互相访问私有数据,甚至共享进程。
这个机制在 Android 10 被标记为 deprecated,Android 14 正式禁止新应用使用。官方理由是"安全风险"——共享 UID 确实有风险,一个应用被攻破,同 UID 下的其他应用跟着遭殃。但看看谁在用这个机制直到最后一刻:Google 自己的 GMS 套件。Google Play Services、Google Play Store、Google Services Framework,这些核心组件长期共享同一个 UID,形成一个紧密耦合的特权集群。第三方开发者从未被鼓励使用这个机制,现在连门都焊死了。
Android 14 的 manifest 解析器里,如果检测到新安装应用带有 android:sharedUserId,直接安装失败。但系统应用的更新包呢?Google 自己的应用呢?我抓过 Pixel 7 的 OTA 包看过,com.google.android.gms 相关的几个 APK 在 Android 14 上依然共享 UID,规则对它们只是纸面上的约束。这种"刑不上大夫"的做法,在 Android 开源社区里讨论过几轮,但声音很快就被淹没。AOSP 的 issue tracker 上,关于 sharedUserId 限制的投诉被标记为 "Won't Fix (Intended Behavior)",关闭得干净利落。
前台 Service 的"类型化"陷阱
Android 14 对前台 Service 的改造是另一个重灾区。以前声明前台 Service 相对简单,在 startForeground() 里传个通知 ID 和 Notification 对象就行。Android 14 强制要求每个前台 Service 必须声明一个具体的类型:dataSync、location、mediaPlayback、mediaProjection、phoneCall、microphone、camera、health、remoteMessaging、shortService、specialUse、systemExempted,一共十二种。
每种类型对应不同的权限要求和运行时行为。比如 dataSync 类型在 Android 14 上有 6 小时的总运行时间限制,超时会被系统强制停止。这个限制不是每个设备都严格执行,Pixel 上抓得紧,有些 OEM 厂商的系统会放宽,但 Google 在兼容性测试套件(CTS)里加了相关用例,意味着未来所有通过 GMS 认证的设备都得跟上。
我专门测试过这个 6 小时限制。写一个最简单的 dataSync 前台 Service,在 Pixel 7 上跑起来,系统日志里能看到 JobScheduler 相关的调度记录。到 6 小时左右,系统会发送 ACTION_FOREGROUND_SERVICE_TIMEOUT 广播,然后你的 Service 的 onTimeout() 回调被触发,紧接着 onDestroy()。如果这时候你还在做数据同步,不好意思,请用 WorkManager 的加急任务(expedited job)替代。
但 WorkManager 的 expedited job 也有配额限制。Android 14 引入了基于应用待机桶(App Standby Bucket)的配额系统,活跃状态的应用每天大约有 10 分钟的前台加急时间,频繁应用更少,罕见应用和受限应用直接归零。这个配额不是固定的,Google 在文档里留了个活口:"具体数值可能因设备和系统版本而异"。翻译过来就是,我说多少就是多少,你别想依赖具体数字做设计。
有个细节很多人没注意到。Android 14 的前台 Service 类型声明是在 manifest 里静态写的,但运行时启动 Service 时传的类型必须匹配。如果 manifest 里声明了 dataSync 和 location 两种,运行时传了个 mediaPlayback,直接 IllegalArgumentException。这种设计把配置分散在两个地方,编译期不检查,运行时炸给你看。我怀疑 Google 自己的团队内部也有不同意见,因为 Android 15 的预览版里,这个错误消息的措辞从 "Service type not declared in manifest" 改成了更详细的提示,说明早期版本确实坑了不少人。
闹钟和唤醒:exact alarm 的权限闹剧
后台启动的限制不止 Activity,exact alarm 的权限演变是另一条线索。Android 12 引入了 SCHEDULE_EXACT_ALARM 权限,从普通权限变成了需要用户手动授予的特殊权限。Android 14 又加了一道锁:如果应用 target API 34 以上,这个权限默认关闭,用户必须去系统设置里手动打开,而且系统设置页面的入口藏得极深——应用信息页 > 权限 > 其他权限 > 闹钟和提醒。
更绝的是,Android 14 新增了 USE_EXACT_ALARM 权限,宣称是"无需用户同意"的替代方案。但文档里紧接着列了四条使用条件:闹钟应用、计时器应用、日历应用、或者展示时钟界面的应用。Google Play 的审核政策把这个范围卡得更死,基本上只有功能完全围绕闹钟/计时器的应用才能通过。我做的一个需要定时提醒的健康类 App,申请 USE_EXACT_ALARM 被 Google Play 拒了三次,理由都是"核心功能不符合要求"。最后被迫改回 SCHEDULE_EXACT_ALARM,然后看着用户评论里一堆"提醒不准时"的投诉——因为 80% 的用户根本不会去那个三级菜单里手动开权限。
这里有个技术细节值得挖。Android 14 的 AlarmManager 源码里,exact alarm 的权限检查逻辑在 com.android.server.alarm 包下的 AlarmManagerService 中。系统应用和持有 android.permission.SCHEDULE_EXACT_ALARM 的系统签名应用走白名单路径,普通应用走 AppOpsManager 检查。这个 AppOps 的开关状态默认继承自 SCHEDULE_EXACT_ALARM 的权限授予状态,但系统可以通过 DevicePolicyManager 强制覆盖。企业环境里的 MDM 策略可以批量开启,个人用户就只能手动折腾。这种设计明显偏向 B 端管控,C 端用户体验被牺牲掉。
OEM 厂商的二次伤害
Google 的原生限制已经够头疼,OEM 厂商还在上面叠 buff。小米的 MIUI 从某个版本开始,后台启动 Activity 需要额外的"自启动"权限,这个权限不在 Android 标准权限框架里,是 MIUI 自己加的。华为的 HarmonyOS 有更激进的"后台纯净模式",默认冻结所有非白名单应用的后台活动。OPPO 的 ColorOS 有个"关联启动"限制,A 应用唤醒 B 应用的场景需要用户单独授权。
这些 OEM 定制和 Android 14 的原生限制交织在一起,形成了一个复杂的兼容矩阵。我维护的 App 现在光是后台启动相关的兼容代码就有 800 多行,分支判断覆盖十几个主流厂商的几十个系统版本。最讽刺的是,有些厂商为了"兼容" Android 14,把 Google 的限制提前实现了,但实现方式有 bug。比如某厂商的 Android 13 定制系统,提前引入了类似 Android 14 的后台启动限制,但判断逻辑写错了,把前台 Service 的 startActivity 也拦截了。这个 bug 在厂商论坛里挂了三个月才修复,期间开发者只能加 workaround 检测厂商和版本号,硬编码跳过。
Google 和 OEM 厂商的关系一直很微妙。Android 兼容性定义文档(CDD)里写满了"必须"和"应该",但执行力度参差不齐。Google 手握 GMS 认证和 Play Store 分发权,理论上能约束 OEM,但实际上对大厂往往网开一面。三星的 One UI 长期有违反 CDD 的行为,比如修改后台任务调度器的默认行为,Google 顶多发个邮件提醒,没见过真的取消认证。小厂商反而容易被卡,因为得罪不起 Google。
开发者社区的沉默与分裂
面对这一轮收紧,开发者社区的反应很有意思。Reddit 的 r/androiddev 上,关于 Android 14 后台限制的讨论帖在发布初期有过几波热度,但很快沉下去。高赞回复大多是"适配 WorkManager 呗"或者"这是趋势,接受现实",一种习得性无助的氛围。Google 的开发者关系团队在各种技术大会上继续推"现代 Android 开发"(MAD)叙事,Jetpack 库被包装成解决一切问题的银弹。
但真实项目里的迁移成本被有意无意地忽略了。一个用了五年后台 Service 架构的老项目,要改成 WorkManager + 前台 Service + 加急任务 + 精确闹钟权限申请的混合架构,涉及的代码改动、测试覆盖、用户教育,工作量以人月计。Google 的文档里永远只有"最佳实践"的终态,没有迁移路径的详细指南。我怀疑写这些文档的人自己没维护过商业项目,或者维护的是那种从零开始的新项目,站着说话不腰疼。
更深层的问题在于,Android 的后台架构正在变得越来越碎片化。JobScheduler、WorkManager、Foreground Service、AlarmManager、BroadcastReceiver、Firebase Cloud Messaging、App Standby Buckets、Doze 模式、Battery Saver、后台启动限制……这些机制和 API 层层叠加,互相之间有重叠、有冲突、有未文档化的交互行为。一个需要后台定时任务 + 网络请求 + 可能唤醒前台的完整流程,现在可能要组合四五个 API,每个都有自己的限制和配额,调试起来像解九连环。
Google 的解决方案是推出更多 Jetpack 库来"简化"——WorkManager 封装了 JobScheduler 和 AlarmManager,Firebase Cloud Messaging 封装了推送唤醒,但封装本身又带来新的限制和依赖。Jetpack 库的更新节奏和 Android 系统版本脱节,某个 Jetpack 版本可能在 Android 14 上有 bug,修复补丁要几周后才发布,这段时间开发者只能干等或者自己 fork 改源码。
对比 iOS:不是想夸苹果
每次聊 Android 后台限制,总有人搬出 iOS 做对比。"iOS 的后台更严格,开发者不也活下来了?"这种话我听得耳朵起茧。
iOS 的后台模型确实严格,但严格得有章法。iOS 7 引入的后台获取(Background Fetch)、iOS 13 的 BackgroundTasks 框架、推送唤醒的 APNs,这些机制从设计之初就是统一的、受限的、文档清晰的。iOS 没有"前台 Service"这种怪胎概念,没有 Activity 和 Service 的生命周期割裂,没有十几个厂商各自加料的混乱。iOS 的严格是一种契约:你按我的规则来,我保证行为一致。Android 的严格是一种层层补丁的债务累积,每次新版本加个新限制,旧机制又不废弃,最后变成一团乱麻。
而且 iOS 的严格是对称的。Apple 自己的应用同样受后台限制约束,iMessage 的推送走 APNs,Siri 的后台处理用同样的 BackgroundTasks 框架。Android 上呢?Google Play Services 有自己的私有 API 和私有通道,GMS Core 的持久连接不受 Doze 模式影响,系统级广播接收器优先投递。这种不对称破坏了公平竞争的环境,也是欧盟 DMA(数字市场法)调查 Google 的切入点之一。
2023 年底,欧盟委员会对 Google 的 Android 系统启动了一项深入调查,其中一项关注点就是 Google 是否利用系统级特权为自己的服务提供不公平优势。调查还在进行中,但 Google 的应对策略已经可见:Android 15 的预览版里,部分之前 Google 私有的后台 API 被标记为 @SystemApi 并开放给更多系统应用,但第三方应用依然够不着。这种"开放"是朝错误方向的妥协,不是真正的平权。
那个被忽视的 FCM 依赖
后台限制的收紧,客观上把更多开发者推向了 Firebase Cloud Messaging。因为后台启动 Activity 难了,后台 Service 存活受限,"等推送来再唤醒"成了最可行的替代方案。FCM 的高优先级消息(priority: high)可以短暂唤醒应用,执行一些工作,然后再次休眠。
这个路径的问题在于,它把 Google 的服务器变成了 Android 生态的事实上的中央调度器。所有应用的后台活动,最终都要经过 FCM 的网关。Google 可以监控这些流量,可以调整优先级策略,可以在某个地区因为政策原因切断服务。2021 年 FCM 在中国以外的某些地区有过一次大规模故障,持续数小时,依赖 FCM 推送的应用集体失声。这种单点依赖的风险,在架构设计里通常是要避免的,但现在 Android 的后台限制把开发者逼进了这个角落。
国内开发者更熟悉这种困境。FCM 在中国大陆不可用,大家早就转向了各厂商的推送联盟:小米推送、华为推送、OPPO 推送、vivo 推送、魅族推送。一个应用要集成五六个 SDK,维护各自的接入文档和更新节奏。Android 14 的后台限制收紧后,这个趋势在国际市场也开始显现,只是换成了 FCM 一家独大。从分散的厂商推送联盟,到集中的 Google 推送服务,很难说哪种垄断更优。
代码层面的具体伤害
说点具体的代码感受。Android 14 的后台启动限制在 AOSP 源码里,核心判断在 ActivityTaskManagerService 的 isBackgroundActivityStartsAllowed 方法中。这个方法有超过 200 行的条件判断,覆盖各种豁免场景:是否有可见窗口、是否在前台任务的最近任务列表里、是否有 SYSTEM_ALERT_WINDOW 权限、是否是系统应用、是否是设备所有者、是否满足临时白名单条件……
这些条件里,"临时白名单"是个黑洞。应用在后台时,如果收到 FCM 高优先级消息、或者执行了 JobScheduler 任务、或者触发了某些系统广播,会被加入一个持续数秒到数分钟的临时白名单,期间允许后台启动 Activity。但这个白名单的时长、触发条件、优先级排序,在 AOSP 源码里是硬编码或者通过系统属性配置的,没有公开 API 查询。开发者只能黑盒测试,猜系统行为。
我做过一个测试:在 Pixel 7 的 Android 14 上,通过 FCM 高优先级消息唤醒应用,测量从收到消息到允许 startActivity 的时间窗口。结果不稳定,短则 3 秒,长则 10 秒,和系统负载、电池状态、应用待机桶都有关系。这意味着依赖这个窗口的代码,必须加各种容错和重试,代码复杂度直线上升。更糟的是,OEM 厂商可以修改这个窗口时长,某厂商的系统把这个窗口缩短到 1 秒,导致大量依赖 FCM 唤醒的应用出现偶现失败。
对特定应用类型的绞杀
后台限制收紧,对某些应用类型是毁灭性的。闹钟应用、自动化工具、健身追踪、防盗定位、家长控制——这些功能天然需要后台存活和定时唤醒。Android 14 的文档里建议用 USE_EXACT_ALARM 或者 SCHEDULE_EXACT_ALARM 替代,但前面说过,Google Play 的审核把 USE_EXACT_ALARM 卡得很死。
有个具体案例:Tasker,Android 平台上最老牌的自动化工具之一,在 Android 14 上经历了大量功能降级。它的开发者 João Dias 在博客上详细记录过适配过程,包括某些触发条件(如特定蓝牙事件)在后台不再可靠,需要改用手动轮询或者放弃支持。Tasker 的付费用户群体很大,但即便如此,一个独立开发者对抗系统级限制的能力有限。João 的某些适配方案是牺牲功能换取存活,用户不满,但别无选择。
另一个被影响的领域是企业应用。MDM(移动设备管理)应用需要后台监控设备状态、强制执行策略、在违规时提醒用户。Android 14 的后台限制让这些流程变得脆弱。Google 的应对是提供 DEVICE_OWNER 和 PROFILE_OWNER 特权,但这两个模式的设置门槛很高,需要设备出厂预装或者通过 ADB 命令配置,普通企业部署成本巨大。而且 DEVICE_OWNER 模式下,应用虽然获得了后台特权,但也被限制了很多正常功能,比如不能使用某些 Jetpack 库,不能接入 Google Play 的某些 API。这种"要么全特权要么全受限"的二元设计,缺乏中间地带。
Android 15 的预告:更紧还是松动?
Android 15 的开发者预览版已经放出,后台相关的变更还在继续。目前可见的几个方向:前台 Service 的 dataSync 类型在 Android 15 上可能有更细分的子类型,或者更严格的超时机制;BOOT_COMPLETED 广播的接收延迟在某些场景下被进一步拉长;新的 PACKAGE_RESTARTED 行为变化可能影响应用被系统杀死后重启的策略。
但也有少数松动的迹象。Android 15 预览版里,START_FOREGROUND_SERVICES_FROM_BACKGROUND 权限的授予流程有简化,某些场景下系统会弹出一个更明显的授权对话框,而不是让用户去三级菜单里找。这个改动很小,而且只针对特定权限,但说明 Google 可能也意识到之前的某些设计过于激进,用户在设置里根本找不到开关。
我对此不乐观。Android 的权限政策演变有个规律:收紧是系统性的、不可逆的,松动是局部的、实验性的。Android 10 的后台定位限制推出后,"始终允许"的选项从首屏隐藏到二级菜单,后来虽然加了个"如果多次选择'仅在使用时允许',下次会提示升级权限"的引导,但核心限制没动摇。这次 Android 14 的后台启动限制,大概率也会走同样的路:小修小补的 UX 优化,不会动摇"限制后台"的大方向。
一个老开发者的困惑
写这些的时候,我一直在想一个问题:Android 的后台限制,边界到底在哪里?
如果最终目标是所有应用都变成"需要时才存在",用完即走,后台不留痕迹,那和 iOS 模型的区别只剩实现路径的混乱程度。Android 曾经的开放性,允许应用真正在后台运行、与其他应用交互、响应系统事件,这些特性是早期 Android 生态繁荣的基础。Tasker、IFTTT、各种自动化工具、防盗软件、健康监测应用,都依赖这个基础。
Google 现在的做法,是在不宣布放弃开放性的前提下,用技术手段一点点收紧,直到开放性名存实亡。这比直接声明"Android 以后走 iOS 路线"更消耗开发者信任,因为每次版本更新都要重新评估哪些功能还能用、哪些 API 又加了限制,没有稳定的预期。
我维护的那个触发蓝牙连接弹窗的 App,最终方案是改成通知触发:检测到蓝牙设备后发一个通知,用户下拉点击通知后才打开界面。功能还在,体验降级了。用户反馈里有人理解,有人抱怨,我在版本更新说明里写"适配 Android 14 新限制",尽量解释清楚。
但下一个 Android 版本呢?如果通知渠道也被进一步限制,如果点击通知的延迟被拉长,如果系统开始折叠或者静默某些"不重要的"通知,这条退路还能走多久?
Google 的权限收紧没有终点,只有下一个版本。