blob: 11264cd7b2eb2bd95ff0780e2af3e47398706b41 [file] [log] [blame] [view] [edit]
# Overview
Runtime Probe is essentially a command line tool that consumes the
[probe syntax](https://chromium.googlesource.com/chromiumos/platform/factory/+/HEAD/py/probe/README.md#detail-usage-the-syntax-of-a-probe-config-file)
and outputs the
[probe result](https://chromium.googlesource.com/chromiumos/platform/factory/+/HEAD/py/probe/README.md#output-format).
This command line tool will gradually replace fields in HWID (i.e. less fields
will be encoded into HWID) as it reflects the status of a device in a more
timely approach. **We are not aiming to be a daemon service**, instead, we pose
ourselves as a one-shot call tool, just like the `ping` command, the D-Bus
method introduced later is also on-demand and expected to exit immediately after
one call.
Currently, the reported data is purely hardware information. For example, the
model of storage, the remaining capacity of battery, the screen resolution..etc.
To serve clients that are not able to call the command line directly, we offer a
simple, restricted D-Bus interface with only one method
`org.chromium.RuntimeProbe.ProbeCategories`. This D-Bus method follows the
[Chrome OS D-Bus Best Practices](https://chromium.googlesource.com/chromiumos/docs/+/HEAD/dbus_best_practices.md#limit-use-of-d_bus-to-start-services-on_demand),
proper `minijail0`, `secomp policy` are applied inside
`dbus/org.chromium.RuntimeProbe.conf`.
# Motivation
To better reflect hardware configuration on users system, we need a tool in
release image that is able to reflect the truth of the moment in the field.
Traditionally, this need has been satisfied by
[factory's probe framework](https://chromium.googlesource.com/chromiumos/platform/factory/+/HEAD/py/probe/README.md),
because we assume rare components replacement after mass production. However, we
have seen more and more requests from partners to switch components after
devices left the factory process.
This work is also related to the evolution of HWID. Instead of going into
details on the complicated plan, we would like to use an example to let the
reader get a high level concept on how this work helps cases in HWID.
Let's look into a typical scenario here: After years' love into the Chromebook,
a user has one of the DRAM broken in slots, and would like to replace it.
However, the original part is already EOL (End Of Life), ODM has no choice but
to pick another part from the
[AVL (Approved Vendor List)](https://www.google.com/chromeos/partner/fe/#avl),
while this new DRAM is installed, the original probe result (HWID) in factory is
violated. Hence, even after the factory process, we would like to get the probe
result to reflect the truth of the moment under release image. Runtime is used
to convey the concept of dynamic.
# Contribute to Runtime Probe
## Environment
Runtime Probe has a significant different logic when working with
`cros_debug=0`, in order to test the behavior under so, you might try to setup a
device like the following:
* CCD Unlock
* Build locally a test image for your device and flash it to ensure your USE
flags are aligned. Image is suggested to build with rootfs verification
disabled in `build_image` step.
* Flash the latest dev-signed firmware, for Googler, it might be easier to get
it from
[GoldenEye](https://cros-goldeneye.corp.google.com/chromeos/console/listFFBuild?type=firmware#).
Suggest to use the following for flashing while keeping the VPD: `futility
update --force -i $FILE`
* Switch on/off developer mode
Besides the
[developer
doc](https://chromium.googlesource.com/chromiumos/docs/+/HEAD/developer_mode.md)
describing how to enter/leave developer mode, following is another useful
hack to prevent some long running check while switching mode for the first
time.
* Before switching on developer mode
* `touch /mnt/stateful_partition/.developer_mode`
* `sync`
* Before switching off developer mode
* `rm /mnt/stateful_partition/.developer_mode`
* `sync`
* Hack[^1] to keep developer tools (For example: python, emerge for `cros
deploy`) while mocking `cros_debug=0`
* Switch off developer mode
* `sed -i 's/CROS_DEBUG=/CROS_DEBUG=1 #/g' /sbin/chromeos_startup`
* Reboot
* Toggle the `cros_debug` to 0
* `cd /usr/share/vboot/bin/`
* `./make_dev_ssd.sh --save_config /tmp/foo --partitions 2`
* `sed -i 's/cros_debug//g' /tmp/foo.2`
* `./make_dev_ssd.sh --set_config /tmp/foo --partitions 2`
* Toggle the `cros_debug` to 1
* `cd /usr/share/vboot/bin/`
* `./make_dev_ssd.sh --save_config /tmp/foo --partitions 2`
* `sed -i 's/cros_secure/cros_secure cros_debug/g' /tmp/foo.2`
* `./make_dev_ssd.sh --set_config /tmp/foo --partitions 2`
## Development
* `cros_workon-$BOARD start runtime_probe`
* `emerge-$BOARD runtime_probe`
* `cros deploy $ACTIVE_DUT runtime_probe`
* On the device:
* `runtime_probe --vebosity_level=3`
## Testing
Runtime Probe provides CLI and a D-Bus interface, and our goal is to **make sure
using Runtime Probe by both interface works correctly**. The main runtime\_probe
binary executed via CLI is free of minijail and hence is useful for testing the
correctness of probe function. D-Bus call to Runtime Probe is the main entry
point we expect in most use cases. It is guarded by minijail, and the main goal
is to ensure the integrity of this entry point.
### Via CLI
Simply run the following:
```shell
localhost ~ # runtime_probe [--verbosity_level=<level>]
```
This command will produce the probe result in json format, also it verifies the
correctness of probe results and tests the sandbox args of each probe function
(if `cros_debug` is set to 1).
### Via D-Bus call
The following script tests the D-Bus entry of runtime\_probe remotely. Besides
the output of the following script, the protocol buffer would also be shown in
`/var/log/messages` by changing the `verbosity_level` in
`runtime_probe/init/runtime_probe.conf` to 3. (And deploy to DUT by
`emerge-${BOARD} runtime_probe && cros deploy "$ACTIVE_DUT" runtime_probe`)
```shell
#!/bin/sh
PROTO_DIR_PATH="$HOME/trunk/src/platform2/system_api/dbus/runtime_probe/"
PROTO_PATH="$PROTO_DIR_PATH/runtime_probe.proto"
# Executing the following commands in cros_sdk or change the proto paths above
CATEGORIES="categories:battery\ncategories:vpd_cached\ncategories:storage"
PROTO_BYTES=$(echo -e "$CATEGORIES" | \
protoc --encode runtime_probe.ProbeRequest --proto_path="$PROTO_DIR_PATH" "$PROTO_PATH" | \
hexdump -v -e '/1 "%d,"')
RAW_HEX_PROBE_RESULT=$(ssh root@$ACTIVE_DUT sudo -u chronos \
dbus-send --system --print-reply=literal \
--type=method_call --dest=org.chromium.RuntimeProbe \
/org/chromium/RuntimeProbe org.chromium.RuntimeProbe.ProbeCategories \
array:byte:"$PROTO_BYTES")
echo "$RAW_HEX_PROBE_RESULT" | sed -e '1d;$d' | \
xxd -r -p | \
protoc --decode runtime_probe.ProbeResult --proto_path="$PROTO_DIR_PATH" "$PROTO_PATH"
```
Sample output:
```
storage {
name: "generic"
values {
path: "/sys/class/block/nvme0n1"
sectors: 1234567890
size: 123456789012
type: "NVMe"
pci_vendor: 9876
pci_device: 5432
pci_class: 67890
}
}
...
probe_config_checksum: "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"
```
### Per probe function
The probe statement of Runtime Probe could be customized for any supported probe
function. The following script tests each function via debugd and use the
corresponding sandbox environment for each probe function.
```shell
#!/bin/sh
# on DUT with cros_debug = 1
# "generic_battery" could be replace with any supported probe function.
cat << EOF > per_function.json
{"CUSTOM_CATEGORY": {"CUSTOM_COMPONENT_NAME": {"eval": {"some_new_probe_function": {}}}}}
EOF
runtime_probe --config_file_path=./per_function.json
```
On DUT with `cros_debug` = 0 we cannot use `--config_file_path` option. However,
we could leverage `/etc/runtime_probe/$MODEL/probe_config.json` like the
following:
```shell
#!/bin/sh
# backup probe_config.json
cat << EOF > /etc/runtime_probe/$MODEL/probe_config.json
{"CUSTOM_CATEGORY": {"CUSTOM_COMPONENT_NAME": {"eval": {"some_new_probe_function": {}}}}}
EOF
runtime_probe # or via D-Bus as described earlier
```
### On Recovery image
* Get the following from the [image folder](http://go/goldeneye) of a Live,
where xxx is the channel [beta, dev, stable] and yyy is the board name and
zzz is the version info.
* xxx-channel\_yyy\_zzz\_ChromeOS-firmware-...tar.bz2
* image-yyy.bin
* xxx-channel\_yyy\_zzz\_ChromeOS-recovery-...tar.xz
* recovery\_image.bin
* Flash the dev-signed firmware, image-yyy.bin by using futility.
* Flash to the USB and trigger a recovery install [ Ctrl + Alt + D ]
* Switch to developer mode and login into console [ Ctrl + Alt + F2 ]
* Disable rootfs verification
* `cd /usr/share/vboot/bin/`
* `./make_dev_ssd.sh --remove_rootfs_verification --partitions 2`
* Reboot the system
* Enable Developer Console login in normal mode
* Delete the following lines in `/etc/init/boot-splash.conf`
* `if is_developer_end_user; then`
* `fi`
* Login as root and change the password to non-empty (might just use `test0000`)
* Reboot the system and disable developer switch
* You should be able to login as root with the password set before
* Clear the `/var/log/message` for better check
* `echo 0 > /var/log/messages`
* Acts as chronos
* `su chronos`
* Either execute a script or type manually on DUT
```shell
#!/bin/sh
PROTO_BYTES="10,2,1,2"
PROBO_BYTES="10,1,3" # for devices report vpd_cached only
dbus-send --system --print-reply \
--type=method_call --dest=org.chromium.RuntimeProbe \
/org/chromium/RuntimeProbe org.chromium.RuntimeProbe.ProbeCategories \
array:byte:"$PROTO_BYTES"
```
* `10,2,1,2` is the generated ProbeRequest, which should depend on the version
of image. For example `10,1,3` for devices only reporting vpd\_cached. These
value could be encoded by `protoc --encode` command mentioned in [via D-Bus
call](#via-d_bus-call).
* Check the `/var/log/message` if the ProbeResult dumps every field in the
protocol buffer.
* Again this ProbeResult could be decoded from local machine in a way similar to
the test script described in [via D-Bus call](#via-d_bus-call)
### Via Tast
[Tast](https://chromium.googlesource.com/chromiumos/platform/tast/+/HEAD/README.md)
is a golang-based test framework. Currently tast-tests for Runtime Probe check
if the probe result matches the cros labels we decoded from the HWID of DUT.
Please refer to `cros_runtime_probe_*.go` under [platform
tests](https://chromium.googlesource.com/chromiumos/platform/tast-tests/+/HEAD/src/chromiumos/tast/local/bundles/cros/platform/).
Note that Runtime Probe uses the probe statements at
`/etc/runtime_probe/$MODEL/probe_config.json` on DUT. The names of probed
components are directly under the probe categories (e.g. component
"MODEL\_COMPONENT1" under category "battery"). This is an
[example](http://go/runtime-probe-component-example-probe-statement) for such
component name.
On the other hand, we will compare the above probed component name with one
described in HWID DB file which is used to generate HWID string. This is an
[example](http://go/runtime-probe-component-example-hwid) for the same component
name described in HWID DB. These component names will be cros labels and be
passed from `-varsfiles` option of tast. We can manually create one and run
tast tests with it in cros\_sdk.
```bash
#!/bin/sh
# in cros_sdk
cat << EOF > labels.yaml
autotesthostinfolabels: '["model:MODEL", "hwid_component:battery/MODEL_COMPONENT1", "hwid_component:storage/MODEL_COMPONENT2"]'
EOF
tast -verbose=true -logtime=false run -build=true -logtime=false -varsfile=labels.yaml "$ACTIVE_DUT" '(!disabled && "group:runtime_probe")'
```
In the output there will be the probed component names and expected component
names for clarification.
Example output:
```
Using SSH key ...
Using SSH dir ...
Writing results to /tmp/tast/results/20200220-172233
Connecting to $ACTIVE_DUT
Getting architecture from target
Building local_test_runner, cros, remote_test_runner, cros
Built in 2.778s
Pushing executables to target
Pushed executables in 4.104s (sent 9.4 MB)
Getting data file list from target
Got data file list with 0 file(s)
Getting DUT info
Software features supported by DUT: ...
Getting initial system state
[01:22:42.048] Devserver status: [[http://127.0.0.1:28082 UP]]
[01:22:42.048] Found 0 external linked data file(s), need to download 0
Started test platform.CrosRuntimeProbeBattery
[01:22:42.173] Probed battery:MODEL_COMPONENT1
[01:22:42.173] Skip known generic probe result
Completed test platform.CrosRuntimeProbeBattery in 89ms with 0 error(s)
Ran 1 local test(s) in 481ms
Starting /tmp/tast/build/host/remote_test_runner locally
Ran 0 remote test(s) in 26ms
Collecting system information
--------------------------------------------------------------------------------
platform.CrosRuntimeProbeBattery [ PASS ]
--------------------------------------------------------------------------------
Results saved to /tmp/tast/results/20200220-172233
```
# Documents
* Design doc: [go/cros-probe](http://go/cros-probe)
* Consolidated summary for all supported component types and probing fields:
[go/cros-runtime-probe-fields](http://go/cros-runtime-probe-fields)
# Useful Reference
* minijail0 manpage (`man 1 minijail0` in cros\_sdk)
* [docs/sandboxing.md](https://chromium.googlesource.com/chromiumos/docs/+/HEAD/sandboxing.md)
* [debugd/src/](https://chromium.googlesource.com/chromiumos/platform2/+/HEAD/debugd/src/)
<!-- Footnotes themselves at the bottom. -->
# Notes
[^1]: Subject to change based on the other program, after this quick hack, you
will not able to switch to developer mode easily.