使用“检查驱动程序”

先决条件

如果您不熟悉 Inspect,建议您阅读以下页面:

简介

驱动程序可以使用检查。不过,考虑到驱动程序不是组件,必须考虑一些特殊因素。

请参考以下系统拓扑图:

图 1:示例拓扑

图表图例:

灰色:组件。 蓝色:显示 out/diagnostics 目录内容的组件命名空间。 紫色out/diagnostics/* 检查文件的内容。

组件可以通过以下方式公开检查数据:

  • VMO 文件:通常称为 root.inspect
  • 树服务:fuchsia.inspect.Tree 协议的服务文件

组件可以公开其中一个或多个文件。在上图中,组件 fooecho 公开了单个文件。不过,driver_manager 会公开多个文件,每个设备对应一个 VMO 文件。

这是因为每个设备都不是一个组件,因此 driver_manager 会汇总其检查 VMO 并自行发布它们。这是公开组件和驱动程序的检查数据之间的主要区别,这会影响如何通过选择器查询数据。

如果您要查询 fooecho 组件的数据,可以在特定选择器中表达这一点。例如,core/foo:root/child1:prop1core/echo:root/child1:prop1。即使您可以使用与属性和节点相同的名称进行调用,因为您可以使用其名称唯一标识它们,因此您可以使用独特的方法来查询它们。

不过,对于驱动程序,建议所有设备都公开一个检查层次结构,其中根位置有一个子项(使用设备名称),以便更好地使用选择器查询其数据。所有其他属性和节点都是该子项的子项。

在上图中,您可以按唯一方式查询 bootstrap/driver_manager:root/device_a:failuresbootstrap/driver_manager:root/device_b:failures。如果 device_adevice_b 均未使用 root/{device name} 节点(所有属性都位于这些节点)公开其检查 VMO,那么这两者之间将无法区分,且选择器 bootstrap/driver_manager:root:failures 与这两个节点都匹配。

在驱动程序中包含检查

以下步骤介绍了如何在驱动程序中添加 Inspect。如需查看包含 Inspect 的驱动程序的完整示例,请参阅以下测试驱动程序示例

  1. 将 zircon 检查库添加到 BUILD.gn 中的驱动程序依赖项:

    deps = [
        ...
        "//zircon/system/ulib/inspect",
    ],
    
  2. 请在驱动程序中添加以下标头:

    #include <lib/inspect/cpp/inspect.h>
    
  3. 在设备类中创建 Inspector 实例:

    class TestDevice {
     …
     private:
         inspect::Inspector inspect_;
    }
    

    使用此方法创建属性和子级以构建检查树:

    TestDevice::TestDevice() {
        state_ = inspect_.GetRoot().CreateString("state","invalid");
        // inspect is a tree; You can add children and structure your data.
        performance_ = inspect_.GetRoot().CreateChild("performance");
        call_count_ = performance_.CreateUint("call_count",0);
        total_time_ = performance_.CreateUint("total_time(ms)",0);
        ...
    }
    
    TestDevice::SetState(State s) {
      call_count_.Add(1);
      ...
        case kActive:
          state_.Set("active");
    }
    

    检查目前支持各种属性类型,例如整数、字符串、数组、布尔值、双精度和直方图。

    检查属于 RAII,因此请务必保留对要更新的属性的引用,否则它们将从检查 VMO 中移除。

    class TestDevice {
     …
     private:
         inspect::Inspector inspect_;
         inspect::StringProperty state_;
         inspect::Node performance_;
         inspect::UintProperty call_count_;
         inspect::UintProperty total_time_;
    }
    

    您可以向 inspect::ValueList 添加属性和节点,而不是保留对它们的引用。这会将属性和节点的生命周期与 inspect::ValueList 的生命周期相关联。请注意,为方便起见,inspect::Inspector 恰好是一个 ValueList。

    inspect_.GetRoot().CreateString("name","test device",&inspect_);
    inspect_.GetRoot().CreateString("config_params",config,&inspect_);
    
  4. 将检查 VMO 导出到驱动程序管理器。

    zx_status Bind() {
      …
        DdkAdd(ddk::DeviceAddArgs("test").set_inspect_vmo(inspect_.DuplicateVmo()));
    }
    

    您可以为每台设备发布一个检查 VMO。

  5. 完成。现在,您可以查看驱动程序的检查数据。

    • 设备检查文件托管在 class/<protocol>/xxx.inspect
    • 使用 iquery 检查检查数据
    fx iquery show bootstrap/driver_manager --file class/ethernet/000.inspect
    
    // To view all of driver_manager and driver host
    fx iquery show bootstrap/driver_manager
    
  6. 运行 fx snapshot 并检查您的检查数据是否存在于 inspect.json 中。请注意,反馈组件不是启动组件,因此在仅使用启动 build 时,截取快照不是很有用。对于这些情况,最好使用 bootfs 中提供的 iquery(如果您使用的是其他产品,请在启动中使用,请参阅下文)。

在 bootfs 中包含 iquery

bringup 产品和所有 *_eng 产品均已在 bootfs 中包含 iquery,因此,如果您使用的是这些产品,则可以跳过此部分。

如果您使用的是其他一些产品,并且需要在 bootfs 中提供 iquery,请将以下代码添加到 fx set

fx set core.x64 --args='product_bootfs_labels+=["//bundles:diagnostics-eng"]'