撰写于 2018 年 4 月

应用内更新流程

本文档详细介绍了 Firefox 如何检查和安装更新。重点关注它在 Windows 操作系统中如何执行此操作。本文档是在准备创建后台更新代理时编写的,因此没有涵盖该更新机制。

定义

MAR 文件

包含更新数据的归档格式。它们已签名以防止被篡改。

部分 MAR 文件

包含 Firefox 已安装版本和更新版本之间二进制差异的 MAR 文件。这是首选的更新机制,因为文件大小要小得多。

完整 MAR 文件

包含应用程序完整副本的 MAR 文件。如果从部分 MAR 更新失败,或者用户从非常旧的版本更新,并且不存在可直接从该版本升级到当前版本的任何部分 MAR,则通常会使用此方法。

更新目录

保存更新文件的目录。位置特定于平台,但可以使用此代码确定。

Services.dirsvc.get("UpdRootD", Ci.nsIFile);

更新状态文件

部分用于 Firefox 和更新程序之间通信的文件。该文件将包含一个简短的字符串,指示当前状态。如果该状态为“失败”,它还将包含错误代码。可以在 此处找到已识别状态字符串的列表。用于失败状态的错误代码可以在 此处找到。

文档

详细更新步骤

  1. Firefox 启动后不久就会启动更新检查。首先,通过内部 XHR 请求检索更新 XML 文档。XML 保存到 更新目录 中。执行一些非常基本的健全性检查以确保该文件有效并描述应应用的更新。

    1. 用于下载更新 XML 的 URL 需要一些变量替换,并向服务器传达有关系统和当前安装的 Firefox 版本的信息:https://aus5.mozilla.org/update/6/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%(noBug1296630v1)(nowebsense)/%SYSTEM_CAPABILITIES%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml 在我的系统上,这变成了:https://aus5.mozilla.org/update/6/Firefox/61.0a1/20180419100148/WINNT_x86_64-msvc-x64/en-US/nightly/Windows_NT 10.0.0.0.16299.371 (x64)(noBug1296630v1)(nowebsense)/ISET:SSE4_2,MEM:32676/default/default/update.xml

    2. Balrog 使用此信息来确定要发送什么 XML 数据作为响应。做出此决定的常用标准包括

      1. 系统是否能够使用 64 位 MAR?它是否有足够的 RAM 使其“值得”?

      2. 系统是否支持更新版本的 Firefox 所需的处理器功能?

      3. 更新是否正在被限制?如果是,Balrog 可能会指示某些客户端尚未更新。请注意,手动检查更新将添加一个“force”查询参数,这将强制 Balrog 报告所有更新,而不管是否限制。

    3. Balrog 将发送一个 XML 文档作为响应。如果更新可用,它将包含 完整 MAR 的 URL。如果 部分 MAR 可用,则其 URL 也将包含在内。

  2. 如果更新可用,Firefox 将下载更新 MAR 文件。

    1. 目前,下载使用 nsIIncrementalDownloader 执行,但理想情况下,我们会使用一个不太特殊的可恢复下载程序 (Bug 1348087)

    2. 文件存储在“更新目录”中(见上文定义)。

    3. 如果 Firefox 在下载完成之前关闭,则下次 Firefox 启动时下载将恢复。

    4. 在此期间,更新状态文件将包含“正在下载”。

  3. 下载完成后,MAR 文件保留在 更新目录 中。签名/文件完整性尚未验证。

    1. 现在采取的操作取决于更新暂存是否启用(由首选项:app.update.staging.enabled 控制)。在所有情况下,暂存目前默认启用。

    2. 如果启用暂存

      1. Firefox 运行更新程序,后者将安装文件复制到安装目录内的目录中并更新它们。

      2. 如果需要提升权限并且 Mozilla 维护服务可用,则更新状态文件现在将包含“applied-service”。

      3. 否则,更新状态文件现在将包含“applied”。

    3. 如果禁用暂存

      1. 如果不需要提升权限即可安装更新,则更新状态文件现在将包含“pending”。

      2. 如果需要提升权限并且 Mozilla 维护服务可用,则更新状态文件现在将包含“pending-service”。

      3. 如果需要提升权限并且 Mozilla 维护服务不可用,则更新状态文件现在将包含“pending”(在 Windows 上)或“pending-elevate”(在 Mac 上)。

  4. 发送更新 ping,原因是“ready”。

  5. Firefox 等待关闭,以便安装更新。

    1. 如果用户将浏览器保持打开状态超过 4 天,则菜单图标上将显示一个绿色箭头,提示用户重新启动以更新。

    2. 如果用户将浏览器保持打开状态 8 天,则会显示一个悬挂式提示,提示重新启动。

    3. (注意:这些是发布渠道的延迟,控制此延迟的首选项在其他渠道中具有不同的值。例如,在 Nightly 中,绿色箭头没有延迟,悬挂式提示延迟为 12 小时)

  6. 下次 Firefox 启动时,它会在启动的早期读取更新状态文件。在发现其中一个“pending”状态后,它将启动更新程序并退出。此更新程序进程将以非提升权限运行。

  7. 更新程序读取更新状态文件,如果状态是“pending”状态,则将其更改为“applying”。

  8. 如果读取的状态为“pending-service”或“applied-service”,则更新程序将联系 Mozilla 维护服务并请求启动特权更新程序。

    1. 如果发生错误,此过程将重试,但如果多次尝试都导致失败,则更新程序将继续。

    2. 原始更新程序等待特权更新程序进程退出。

  9. 如果读取的状态为“pending-elevate”或“applied”,或者更新程序无法从 Mozilla 维护服务获取特权更新程序,则将以提升权限启动一个新进程。这将导致显示 UAC 提示。原始更新程序等待特权更新程序退出。

    1. 如果拒绝了 UAC 提示,则更新程序将写入错误状态并退出。

    2. Firefox 启动时,它会将状态恢复为“pending”状态,然后返回步骤 5。

    3. 如果此过程重复 2 次,我们将提示用户下载 Firefox 安装程序以进行更新(但 Firefox 仍会返回步骤 5)。

  10. 现在尝试更新。如果状态是“pending”状态之一,则将涉及使用 MAR 文件中的数据修补或覆盖安装文件。如果状态是“applied”状态之一,则将涉及使用更新目录中修补(暂存)的文件覆盖安装目录中的文件。

    1. 如果不需要特权更新程序,则原始更新程序进程将尝试安装更新。

    2. 如果启动了特权更新程序,它将尝试安装更新。之后它退出,原始的非特权更新程序进程恢复。

  11. 更新程序将状态写入更新状态文件(“succeeded”或“failed”),启动 Firefox 并退出。

  12. Firefox 启动并读取更新状态文件。

    1. 更新成功时

      1. 发送更新 ping(原因是“success”)。

      2. Firefox 从 更新目录 中读取 XML 文件,如果它指示在该更新后应显示特定 URL,则会执行此操作。

    2. 更新失败时,Firefox 通过检查 XML 中的“selected”属性来检查这是 部分 MAR 还是 完整 MAR

      1. 如果是部分 MAR,则 Firefox 将下载完整 MAR 并重试更新(即返回步骤 2,但下载不同的 MAR)。

      2. 如果是完整 MAR,则 Firefox 会通知用户失败并提供当前版本的链接。