使用“检查驱动程序”

先决条件

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

简介

司机可以使用 Inspect。不过,鉴于驱动程序不是组件,因此必须考虑一些特殊事项。

请参考以下系统拓扑图:

系统拓扑图,显示了通过 VMO 和树服务公开检查数据的组件和驱动程序。

图表图例:

灰色:组件。 蓝色:显示 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. 在 BUILD.gn 中将 zircon inspect 库添加到驱动程序依赖项:

    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");
    }
    

    Inspect 目前支持多种属性类型,例如整数、字符串、数组、布尔值、双精度浮点数、直方图。

    检查是 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 时,拍摄快照并不是很有用。在这些情况下,建议使用 iquery,该命令可在 bootfs 中使用(在启动时,如果您在其他产品中工作,请参阅下文)。

在 bootfs 中包含 iquery

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

如果您正在开发其他产品,并且需要在 bootfs 中提供 iquery,请将以下内容添加到 fx set 中:

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