Fuchsia 组件检查概览

Fuchsia 中的组件可能会公开符合 Inspect API 的结构化自身信息。本文档介绍了组件检查的概念、接口、接口的 C++ 语言实现,以及用于与公开信息的组件交互的用户界面工具。

不知道从哪里开始?

概念

组件可能会公开一个 节点 树,每个节点都有一组 属性

图:节点树

节点

节点是组件中导出的实体,可以有 0 个或多个子节点。每个节点都有一个名称,并且节点的每个子节点在子节点中都必须具有唯一的名称。

图:一个节点

属性

节点可以有任意数量的属性。属性具有字符串键和值,该值可以是多种类型中的任意一种:

数值类型

  • UintProperty - 64 位无符号整数。
  • IntProperty - 64 位带符号整数。
  • DoubleProperty - 64 位浮点值。
  • BoolProperty - 布尔值。

字符串类型

  • StringProperty - UTF-8 字符串。
  • ByteVectorProperty - 字节向量。

数组类型

  • UintArrayIntArrayDoubleArray - 相应数值类型的数组。

直方图类型

  • LinearUintHistogramLinearIntHistogramLinearDoubleHistogram

一个直方图,其固定大小的存储分区存储在数组中。

  • ExponentialUintHistogramExponentialIntHistogramExponentialDoubleHistogram

一个直方图,其指数大小的存储分区存储在数组中。

检查文件格式

检查文件格式是一种二进制格式 支持在运行时高效插入、修改和删除节点和 属性。读取器可以获取内容的统一快照,而无需与写入器通信。

文件系统接口

顶层节点在组件的传出目录中以 VmoFiles 的形式公开,并以扩展名 .inspect 结尾。 组件通常将其主树或根树公开为 out/diagnostics/root.inspect

语言库

C++

C++ Inspect 库为 Inspect 文件格式提供完整的 写入读取 支持。

写入检查数据的组件应避免读取该数据。 读取需要遍历整个缓冲区,这非常耗费资源。

Inspector 类提供了一个封装容器,用于创建包含一个根节点的新缓冲区,该根节点可以添加到其中。节点和属性具有类型化 封装容器,当它们超出范围时,会自动从 缓冲区中删除底层数据。

inspect_component 库提供了一个简单的 ComponentInspector 单例接口,以帮助处理从组件公开单个 层次结构的常见情况。

健康功能支持以健康检查工具已知的格式公开结构化健康信息 。

有界列表功能支持在固定容量的 FIFO 节点缓冲区中记录滚动事件历史记录 。

测试匹配器库提供 GMock 匹配器,用于在测试中验证 从 Inspect 层次结构中读取的数据。

读取支持

读取库支持将 Inspect 文件解析为层次结构Hierarchys 包含 NodeValues 和 PropertyValues,它们分别是 Nodes 和 Propertys 的解析版本。

The Hierarchy's NodeValuenode() 返回,子 Hierarchy 在向量中由 children() 返回。GetByPath 函数支持按路径读取特定的子层次结构。

特定 NodeValue 的属性可通过 properties() 访问器获得。您可以通过将相应的 PropertyValue 类型作为 模板参数传递给 Contains<T>() 方法,确定属性是否包含 某种类型:

  // Returns true if the first property of the hierarchy's node is an INT value.
  if (hierarchy.node().properties()[0].Contains<IntPropertyValue>()) {
    // ...
  }

使用 Get<T>() 方法获取属性:

  // Get the IntPropertyValue of the first property on the node.
  // Note: This causes a runtime exception if the property does not contain
  // the given type, crashing the program.
  hierarchy.node().properties()[0].Get<IntPropertyValue>();

您还可以根据不同的可能格式类型进行切换:

  const auto& property = hierarchy.node().properties()[0];
  switch (property.format()) {
    case FormatType::INT:
      const auto& value = property.Get<IntPropertyValue>();
      /* ... */
      break;
    /* ... */
  }

数组类型可以采用特殊格式,以包含直方图。 GetBuckets() 方法支持从 {Int,Uint,Double}ArrayValue 类型返回直方图存储分区数组。如果 底层数组不是采用特殊格式的直方图,则该数组将为空。

Rust

Rust Inspect 库为 Inspect 文件格式提供完整的 写入读取 支持。

写入检查数据的组件应避免读取该数据。 读取需要遍历整个缓冲区,这非常耗费资源。

Inspector 类提供了一个封装容器,用于创建包含一个根节点的新缓冲区,该根节点可以添加到其中。节点和属性具有类型化 封装容器,当它们超出范围时,会自动从 缓冲区中删除底层数据。

组件模块支持简单的 inspector 函数,以 处理从组件公开单个层次结构的常见用法。

健康模块支持以健康检查工具已知的格式公开结构化健康信息 。

contrib crate 提供 BoundedListNodeinspect_log! 和 时间实用程序,用于记录带时间戳的事件。

测试模块支持 assert_data_tree! 宏,以 匹配 Inspect 数据进行测试。

测试

验证器架构介绍了 Inspect 语言库的集成测试框架。

用户空间工具

ffx inspect

如需检查组件的检查层次结构,您可以使用 ffx inspect show 命令:

  • 打印所有检查层次结构:

    ffx inspect show
  • 打印特定组件(例如 core/font_provider)的检查层次结构:

    ffx inspect show core/font_provider

ffx inspect show 还会对其输入执行模糊匹配。例如:

ffx inspect show archivist.cm

只要这是系统中唯一一个网址以 archivist.cm 结尾的组件,该命令就会打印 bootstrap/archivist 的所有检查。

如果输入不够具体,无法识别单个组件,模糊匹配将失败;在这种情况下,该工具将打印与查询匹配的别名列表。

一般来说,此命令接受以下内容:

  • 组件别名,例如 core/network/netstack。如果仅传递别名,则无需转义集合标记,但可以选择转义。

  • 模糊搜索参数,对应于网址片段、清单片段或别名片段。即 ffx inspect show archivist.cm,用于清单为 archivist.cmbootstrap/archivist

  • 组件选择器,例如 core/network/*

  • 完整诊断选择器,例如 core/network/netstack:root/path/to/*:property。在完整选择器的情况下,必须执行转义才能创建有效的选择器。

假设您有组件 bootstrap/driver-hosts:driver-host-337。如果您想要特定属性,一种尽可能避免转义的便捷方法可能如下所示:

ffx inspect driver-host-337 --data root/stats:my_stat

ffx target snapshot

ffx target snapshot 会生成一个 ZIP 归档,其中包含系统的诊断信息,包括检查:

ffx target snapshot

最佳实践

避免嵌套来自其他组件的指标

在设计组件诊断时,请将每个组件的检查层次结构严格限定在该组件生成的数据范围内。避免在中间组件的检查树下转发或嵌套来自客户端或下级组件的检查指标。

在外部组件下转发或嵌套检查指标会给工具、调试和隐私合规性带来几个问题:

  • 开发者体验和工具归因:检查数据按组件别名归因。诊断工具(例如 ffx inspect show)和自动快照分类查询 使用组件别名(例如 core/network/netstack)检查层次结构。当您将多个组件的指标 嵌套在单个中间服务中时,查询生产者组件的 别名不会返回任何数据,而查询中间服务会返回无法管理的聚合层次结构。

  • 隐私审核和许可名单强制执行:Fuchsia 诊断流水线 和快照导出器使用基于别名的 选择器强制执行隐私控制。将多个生产者的指标放在外部别名下会模糊数据来源,阻止精细的数据修订,并使隐私审核验证复杂化。

  • 生命周期和故障隔离:代表其他组件持有 指标的中间组件可以独立于实际指标生产者而存在或终止 。如果中间组件崩溃,这会创建过时的诊断或导致数据丢失。

每个组件都应直接在其自己的别名下发布自己的检查树。