| # Using Inspect for drivers |
| |
| Caution: This page may contain information that is specific to the legacy |
| version of the driver framework (DFv1). |
| |
| ## Pre-requisites |
| |
| In case you are not familiarized with Inspect, it is recommend that you read the |
| following pages: |
| |
| - [Inspect overview][inspect_overview] |
| - [Inspect codelab][inspect_codelab] |
| |
| <!-- TODO(fxbug.dev/60811): link to the selectors doc when it's submitted --> |
| |
| ## Introduction |
| |
| Inspect can be used by drivers. However, there are some special considerations that must be made |
| given that drivers are not components. |
| |
| Note: There is work being done to represent drivers as components using Components V2. For more |
| information, see [Implementing drivers as components][roadmap-drivers-components]. |
| |
| Consider the following system topology diagram: |
| |
|  |
| |
| Diagram legend: |
| |
| *Gray*: Components. |
| *Blue*: Component namespace that shows the out/diagnostics directory contents. |
| *Purple*: Contents of the `out/diagnostics/*` inspect files. |
| |
| Components can expose inspect data in the following ways: |
| |
| - VMO file: Typically called `root.inspect` |
| - Tree service: A service file for the `fuchsia.inspect.Tree` protocol |
| |
| A component can expose one or more of these files. In the diagram above, components `foo` and |
| `echo` expose a single file. However, `driver_manager` exposes multiple files, one VMO file for |
| each device. |
| |
| The reason for this is that each device is not a component, therefore `driver_manager` aggregates |
| their inspect VMOs and publishes them itself. This is a major difference between exposing inspect |
| data from a component and from a driver that has implications in how the data can be queried |
| through selectors. |
| |
| If you wanted to query data for the `foo` and `echo` components, you can express that in a |
| specific selector. For example, `core/foo:root/child1:prop1`, `core/echo:root/child1:prop1`. You |
| have a unique way of querying each even if the properties and nodes are called the same way given |
| that you can uniquely identify them using their moniker. |
| |
| However, when it comes to drivers, it’s recommended that all devices expose an inspect hierarchy |
| where the root has a single child with the name of the device for a better experience using |
| selectors to query their data. All other properties and nodes are children of this child. |
| |
| In the diagram above, you can query: `bootstrap/driver_manager:root/device_a:failures` and |
| `bootstrap/driver_manager:root/device_b:failures` uniquely. If neither `device_a` nor `device_b` |
| exposed their inspect VMO with a `root/{device name}` node where all properties are located, you |
| wouldn’t have a way of differencing between both and the selector |
| `bootstrap/driver_manager:root:failures` would match both of them. |
| |
| ## Including Inspect in drivers |
| |
| These steps walk you through how to include Inspect in your drivers. For a full example of a driver |
| with Inspect included, see the following [example test driver][example_test_driver]. |
| |
| 1. Add the zircon inspect library to your driver dependencies in BUILD.gn: |
| |
| ``` |
| deps = [ |
| ... |
| "//zircon/system/ulib/inspect", |
| ], |
| ``` |
| |
| 1. Include this header in your driver: |
| |
| ``` |
| #include <lib/inspect/cpp/inspect.h> |
| ``` |
| |
| 1. Create an Inspector instance in your device class: |
| |
| ``` |
| class TestDevice { |
| … |
| private: |
| inspect::Inspector inspect_; |
| } |
| ``` |
| |
| Use this to create properties and children to build the inspect tree: |
| |
| ``` |
| 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 currently supports a variety of [property types][property_types] like integers, strings, |
| arrays, bool, double, histograms. |
| |
| Inspect is RAII so remember to hold references to properties that you will update, otherwise |
| they’ll be removed from the inspect VMO. |
| |
| ``` |
| class TestDevice { |
| … |
| private: |
| inspect::Inspector inspect_; |
| inspect::StringProperty state_; |
| inspect::Node performance_; |
| inspect::UintProperty call_count_; |
| inspect::UintProperty total_time_; |
| } |
| ``` |
| |
| You can add properties and nodes to an `inspect::ValueList` instead of holding references to them. |
| This will tie the lifetime of the properties and nodes with the lifetime of the |
| `inspect::ValueList`. Note that `inspect::Inspector` happens to be a ValueList for convenience. |
| |
| ``` |
| inspect_.GetRoot().CreateString("name","test device",&inspect_); |
| inspect_.GetRoot().CreateString("config_params",config,&inspect_); |
| ``` |
| |
| 1. Export inspect VMO to driver manager. |
| |
| ``` |
| zx_status Bind() { |
| … |
| DdkAdd(ddk::DeviceAddArgs("test").set_inspect_vmo(inspect_.DuplicateVmo())); |
| } |
| ``` |
| |
| You can publish one inspect VMO per device. |
| |
| 1. Done. Now you can view Inspect data for the driver. |
| |
| - The device inspect file is hosted in `class/<protocol>/xxx.inspect` |
| - Check the inspect data using `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 |
| ``` |
| |
| 1. Run `fx snapshot` and check if your inspect data is present in `inspect.json`. Note that the |
| feedback component is not part of bringup, so taking snapshots is not very useful when working |
| only with a bringup build. For these situations, prefer using `iquery` which is available in bootfs. |
| |
| Note: Don’t forget to write tests for the inspect code. You can look at the inspect |
| [codelab][inspect_codelab] or [the driver host inspect test][driver_host_inspect_test] for some |
| examples. |
| |
| |
| |
| [selectors]: https://docs.google.com/document/d/1gI3FizKlTlth9DL8l7Ja9f7xuY_GKDffa5x1uZesLMY/edit |
| [inspect_overview]: /docs/development/diagnostics/inspect/README.md |
| [Inspect codelab]: /docs/development/diagnostics/inspect/codelab.md |
| [roadmap_drivers_components]: /docs/contribute/roadmap/2020/overview.md#implementing_drivers_as_components |
| [example_test_driver]: /src/devices/tests/driver-inspect-test/test-driver.cc |
| [property_types]: /docs/development/diagnostics/inspect/README.md#property |
| [inspect_codelab]: /docs/development/diagnostics/inspect/codelab/README.md |
| [driver_host_inspect_test]: /src/devices/bin/driver_host/inspect_test.cc |