架构

healthreporter.sys.mjs 包含 FHR 的主要接口,即 HealthReporter 类型。该类型的实例由 data_reporting_service 创建。

providers.sys.mjs 包含许多用于收集应用程序指标的 Metrics.ProviderMetrics.Measurement。如果您正在寻找 FHR 探针,它们就在这里。

存储

Firefox 健康报告将数据存储在 3 个位置

  • 指标测量和提供程序状态存储在 SQLite 数据库中(通过 Metrics.Storage)。

  • 服务状态(例如上传文档的 ID)存储在磁盘上的 JSON 文件中(通过 OS.File)。

  • 较少的状态和运行时选项存储在首选项中。

首选项

控制 Firefox 健康报告行为的首选项位于 datareporting.healthreport.* 分支中。

服务和数据控制

以下首选项控制服务和数据上传的行为。

service.enabled

控制整个健康报告服务是否运行。整体服务执行数据收集、存储和提交。

这是在构建系统变量之外禁用 Firefox 健康报告的主要开关。例如,如果您使用的是正式的 Firefox 版本并希望禁用 FHR,则应将其设置为 false 以防止 FHR 不仅提交数据,还收集数据。

uploadEnabled

是否启用数据上传。这是首选项 UI 中复选框反映的首选项。如果禁用此选项,FHR 仍会收集数据,只是不上传它。

service.loadDelayMsec

应用程序初始启动后,FHR 应等待多长时间(以毫秒为单位)才能初始化。

如果请求 FHR 服务,FHR 可能会比此时间更早初始化。例如,如果用户访问 about:healthreport,就会发生这种情况。

service.loadDelayFirstRunMsec

在第一次应用程序运行时,FHR 应等待多长时间(以毫秒为单位)才能初始化。

FHR 在第一次应用程序运行时等待的时间比正常时间长,因为首次初始化可能会使用大量的 I/O 来初始化 SQLite 数据库,并且此 I/O 不应干扰首次运行的用户体验。

documentServerURI

FHR 应与之交互以提交文档的 Bagheera 服务器的 URI。

您通常不需要更改此项。

documentServerNamespace

FHR 应将文档上传到的文档服务器上的命名空间。

您通常不需要更改此项。

infoURL

包含有关 FHR、其隐私政策等更多信息的页面的 URL。

about.reportUrl

about:healthreport 中加载的 URL。

about.reportUrlUnified

about:healthreport 中加载的 URL。当 UnifiedTelemetry 不是选择加入时,此项用于代替 reportUrl

service.providerCategories

包含已注册 Metrics.Provider 记录的类别管理器类别的逗号分隔列表。请参阅下文了解提供程序注册的工作原理。

如果禁用了整个服务,则会丢失数据收集。这意味着**本地**数据分析将不可用,因为没有数据可供分析!请记住,即使 Firefox 健康报告未将数据提交到远程服务器,它也可能很有用!

日志记录

以下首选项允许您控制 Firefox 健康报告的日志记录行为。

logging.consoleEnabled

是否将日志消息写入 Web 控制台。默认情况下为 true。

logging.consoleLevel

FHR 消息必须具有的最低日志级别才能写入 Web 控制台。默认情况下,只有 FHR 警告或错误才会写入 Web 控制台。在正常/预期操作期间,不应生成此类型的消息。

logging.dumpEnabled

是否通过 dump() 写入日志消息。如果为 true,FHR 将消息写入 stdout/stderr。

这通常仅在开发 FHR 时启用。

logging.dumpLevel

消息必须具有的最低日志级别才能通过 dump() 写入。

状态

currentDaySubmissionFailureCount

客户端在尝试上传最新文档时遇到的提交失败次数。

lastDataSubmissionFailureTime

上次文档上传失败的时间。

lastDataSubmissionRequestedTime

上次文档上传尝试的时间。

lastDataSubmissionSuccessfulTime

上次文档上传成功的时间。

nextDataSubmissionTime

计划下次数据提交的时间。FHR 不会在此时间之前尝试上传新文档。

pendingDeleteRemoteData

客户端当前是否有一个挂起的删除远程数据的请求。如果为 true,则客户端将在执行上传之前尝试删除所有远程数据。

FHR 在首选项中存储各种状态。

注册提供程序

Firefox 健康报告提供程序通过类别管理器注册。请参阅 HealthReportComponents.manifest 以了解在此目录中定义的提供程序。

本质上,类别管理器接收 JS 类型的名称和要导入的 sys.mjs 的 URI,该 URI 导出此符号。在运行时,将实例化在类别管理器中注册的提供程序。

提供程序通过类别管理器注册,以使注册变得简单且不易出错。任何 XPCOM 组件都可以创建类别管理器条目。因此,可以添加新的数据提供程序,而无需触及核心 Firefox 健康报告代码。此外,类别管理器注册意味着提供程序更有可能在 FHR 的条件下注册,即在 FHR 需要时注册。如果提供程序在应用程序运行时在代码中注册,则其他组件可能会过早实例化 FHR(如果在不合适的时间执行会导致性能下降)或围绕观察者或侦听器的半复杂的代码。类别管理器条目每个提供程序只有一行,并让 FHR 保持控制:它们简单且安全。

文档生成和生命周期

FHR 将尝试每隔 24 个墙上时钟小时提交包含数据的 JSON 文档。

在上传时,FHR 将查询数据库以获取过去 180 天的**所有**信息,并将这些数据组合到一个 JSON 文档中。我们尝试使用客户端生成的 UUID 将此 JSON 文档上传到配置的服务器。

在尝试上传之前,生成的 UUID 会存储在本地磁盘上的 JSON 状态文件中。此时,客户端假设具有该 UUID 的文档已成功存储在服务器上。

如果客户端知道其他可能存在于服务器上的文档 UUID,则这些 UUID 会与上传请求一起发送,以便客户端可以请求删除这些 UUID。这有助于确保每个客户端在任何给定时间在服务器上只有一个文档/UUID。

持久化 UUID 的重要性

文档 UUID 的存储和更新方式、位置和时间的选择非常重要。除非她非常详细地了解事情为何如此,否则不应尝试更改任何内容。

客户端有意地对忘记生成的 UUID 非常保守。换句话说,一旦生成 UUID,客户端就会故意保留该 UUID,直到它非常确定该 UUID 不再存储在服务器上。我们这样做的原因是因为服务器上的孤立文档/UUID 会导致错误的分析,例如过度报告停止使用的 Firefox 安装数量。

在上传新 UUID 时,我们在上传尝试之前更新状态并将状态文件保存到磁盘,因为如果上传成功但响应从未返回到客户端,我们希望客户端知道已上传的 UUID,以便它以后可以删除它以防止孤立。

我们在本地维护 UUID 列表(而不仅仅是最后一个 UUID),因为多次上传尝试可能会像上一段所述那样失败,我们无法知道哪次(如果有)实际上成功了。最安全的方法是假设每个生成的文档都设法以某种方式上传了。

我们将 UUID 存储在磁盘上的文件中,而不是其他任何地方,因为我们希望存储健壮。我们最初将 UUID 存储在首选项中,这些首选项仅定期刷新到磁盘。显然,写入首选项丢失了。我们切换到直接写入文件以消除此窗口。