GeckoView 中的重大更改¶
Agi sferro <agi@sferro.dev>
摘要¶
本文档介绍了 GeckoView 弃用策略背后的原因,我们目前所处的位置以及我们未来想要达成的目标。
背景¶
以下部分说明了重大更改作为 GeckoView 的使用者、Gecko 工程师和外部使用者来说是多么昂贵且令人沮丧,它们如何占用 Fenix 团队的时间并将 Nightly 的平均测试时间减少高达 30%。最后,重大更改如何否定使我们能够构建当前模块化体系结构的优势。
简介¶
GeckoView 是一个库,它允许使用者访问 Gecko,并且是 Mozilla 的 Android 产品中使用 Gecko 的主要方式。
GeckoView 提供 Nightly、Beta 和 Release 渠道,这些渠道的更新频率与 Firefox 桌面版相同。
适用于 Android 的 Firefox(代号为 Fenix)在 GitHub 上的独立存储库中开发,并通过 Android Components(简称 AC),一个也在其自己的独立存储库中开发的 Android 库,使用 GeckoView。
Fenix 还提供 Nightly、Beta 和 Release 更新,这些更新镜像了 GeckoView 和 Firefox 桌面的更新。
测试日¶
所有基于 Firefox Gecko 的产品每 4 周发布一个新主版本。这意味着,平均而言,在发布周期中的随机日期提交的提交将在 Nightly 用户群中获得 2 周的测试时间。
我们试图通过在每个合并日之前设置几个“软”代码冻结日来增加 Nightly 上的平均测试时间,在这些日子里,工程师不应该推送有风险的更改,但没有强制执行,并且由每个工程师决定他们的更改是否有风险。
Nightly 构建延迟的每一天,当前 Nightly 周期中包含的每个更改平均获得的测试时间减少 7%(1/14 天)。假设问题会立即得到报告,并且该报告会立即转交给正确的工程团队。
假设报告延迟 4 天,则由于重大更改等原因导致 Nightly 构建延迟的每一天,都会使平均测试时间减少 10%。
Nightly 更新¶
Fenix Nightly 通过 Android Components 间接使用 GeckoView。每天,一个自动化脚本都会对 Fenix 的代码库进行更改以更新 AC 的版本。然后,此更改将提交到 Fenix 的 CI,如果所有测试都通过,则会自动合并到代码库中。
然后生成一个新的 Fenix Nightly 构建,并自动发布到 Google 的 Play 商店,从那里分发到 Android 上的所有 Nightly 用户。
Android Components 有一个类似的自动化流程,每天发布新版本,获取新的 GeckoView nightly 构建。
更新过程有时会失败。故障原因主要归结于以下三个类别之一。
间歇性测试失败
最新 AC 或 GeckoView 更新中引入的导致测试失败的错误
在 AC 或 GeckoView 中进行了向后不兼容的更改,导致构建失败。
1 的当前缓解措施是禁用或修复间歇性失败的测试,类似于 mozilla-central 中发生的情况。
2 和 3 是 Fenix 和 AC 独有的问题(与 Firefox 桌面版相比),并且是 Fenix 多包基础架构的直接结果。
构建中断¶
当自动 Nightly 更新失败时,Fenix 团队的工程师需要手动干预以解除构建阻塞。
当故障发生在非工作时间时,手动干预的需求会自动增加一天的 Nightly 构建延迟,当故障发生在周五晚上时,会增加 2 或 3 天的延迟。
因此,即使假设修复构建中断不需要任何时间,每次发生的构建中断也会使平均测试时间减少 7-30%。
如果修复中断需要几天甚至更长时间,则平均测试时间可能会减少到无中断 Nightly 周期的一半。
构建中断给 Fenix 团队带来了不必要的负担,他们必须处理中断,并且必须放弃他们当前的工作以避免损失额外的测试日。
减少中断¶
由上游团队(如 GeckoView)引起的中断可以分为两类
导致下游测试失败的行为更改
导致构建失败的 API 中的重大更改。
为了减少第 1 组的中断,GeckoView 团队维护了一套广泛的集成测试,这些测试仅在 GeckoView API 上运行,因此很少因重构而中断。
对于第 2 组,GeckoView 团队制定了一项弃用策略,该策略要求每个向后不兼容的更改保留旧代码 3 个版本,从而使下游使用者(如 Fenix)能够异步迁移到新代码而不会中断构建。
功能测试和原型设计¶
GeckoView 提供了一个名为 GeckoViewExample(或 GVE)的测试浏览器应用程序,该应用程序在树中开发,因此始终可用于测试本地更改。
GVE 是 Gecko 和 GeckoView 工程师的主要测试工具,他们想要开发新代码,但是,经常会出现无法在 GVE 上测试或需要直接在 Fenix 上测试的新功能或问题。
为了在 Fenix 中测试新代码,构建系统提供了一种简单的方法来交换 Fenix 中本地构建的 GeckoView。
在 Fenix 中测试新 Gecko 代码的过程必须简单明了,因为它经常被不熟悉 Android 和 Fenix 本身的平台工程师使用,并且不太可能保留从 Android 上运行代码获得的知识,并且可能需要 GeckoView 或 Fenix 团队的帮助才能做到这一点。
构建中断的副作用¶
当中断出现在 mozilla-central 中并且在 Fenix 代码库中修复该中断之前,本地构建的 GeckoView 与 Fenix 的最新版本不兼容。
这对不熟悉 Fenix 的工程师来说可能会令人困惑,并可能导致沮丧和浪费时间来弄清楚为什么上游代码在没有修改的情况下无法编译。
除了困惑之外,GeckoView/Fenix 组合历史记录中的不兼容性还否定了在单独的包中构建 Fenix 的主要优势:将 Gecko 与 Android 前端分离。
从源代码构建旧版本也比较困难,因为彼此兼容的版本对(GeckoView、Fenix)的集合在任何地方都没有明确记录。
外部使用者¶
对于有兴趣为 Android 构建浏览器的应用程序,GeckoView 提供了现代 Web 引擎与相对稳定的 API 的独特组合。
相比之下,GeckoView 的替代方案包括
WebView,Android 在 Android 应用程序中嵌入网页的方式。对于浏览器开发者来说,WebView 有几个缺点,包括
为构建浏览器提供的 API 有限,因为它不公开现代 Web 功能或书签、密码等浏览器特定 API;
不允许开发人员控制底层 Chromium 版本。WebView 用户将获得设备上安装的任何 WebView 版本。
另一方面,使用 WebView 的优点是可以提供更小的下载包,因为引擎的大部分内容已安装在设备上。
分叉 Chromium,这有以下缺点:要么必须重写整个浏览器前端,要么本地修补 Chrome 前端,这涉及频繁的更改和更新才能保持最新。使用 Chromium 的优点是可以提供市场上最稳定、性能最高且兼容性最好的 Web 引擎。
如果由于频繁的 API 更改导致更新 GeckoView 的成本过高,则使用 GeckoView 的优势就会消失。
现有技术¶
许多公共库提供了与 GeckoView 相似或更好的弃用策略。例如,Android API 需要弃用几个版本才能被考虑删除,并且仅在特殊情况下才能完全删除。Google 产品的弃用 API 在删除之前会得到一年的支持。Ebay 要求在删除之前弃用 API。
现状¶
目前强烈不建议对 GeckoView API 进行向后不兼容的更改,并且需要 GeckoView 团队的批准。
但是,我们确实偶尔会进行重大更改。上次重大更改是在 2021 年 6 月,是对权限 API 的重构,我们认为没有必要以向后兼容的方式执行。在此之前,上次重大更改是在 2020 年 9 月。
跟踪重大更改¶
在内部,GeckoView 使用 apilint 跟踪 API。每个触及 API 的更改都需要额外的 GeckoView 同行来审查补丁以及变更日志中的更改说明。
Apilint 还跟踪已弃用的 API 并强制执行其删除,以便旧的、已弃用的 API 不会在代码库中停留过久。
未来¶
GeckoView 的理想最终状态是没有任何向后不兼容的更改。我们的经验是,在有限的时间内支持旧 API 是我们开发中的一小部分开销,并且具有向后兼容 API 的好处远大于其成本。
但是,我们无法预测 GeckoView 和 Firefox 的所有未来需求,因此我们不能排除将来可能出现新的重大更改的可能性。