blob: acc0c252fdbe39995f8d6bcda328a6a8380cc29e [file] [log] [blame] [view]
# Interoperability Debugging Tool
## Overview
The “Interoperability Debugging Tool” (IDT) is a python-based tool that supports
a variety of commands that are useful in the context of interoperability testing
of Matter devices and app controllers.
### Discovery
While in discovery mode, the tool displays all Matter devices that are in
commission and/or operational mode. This is useful to have a clear understanding
of all Matter devices currently “active” in the testing environment.
See section “4.3. Discovery” of the Matter spec for official documentation.
When run interactively, discovery functions in one of two modes: BLE and DNS-SD.
### Capture
While in capture mode, the tool starts capturing all data of interest (e.g.
video recording of interactions with the mobile app, logs from all components
involved, network packets capture, etc.) while a test is being conducted
manually. It also provides feedback to the user on test setup and execution.
When the test completes, capture mode is stopped and all captured data is zipped
in a file that can then be sent to all parties involved in investigating any
issue uncovered via the manual test. Each ecosystem may implement an analysis
that analyzes capture data, displays info to the user, probes the local
environment and generates additional artifacts.
## Single host installation (no Raspberry Pi)
All features of `idt` are available on macOS and Linux (tested with Debian based
systems).
If you would prefer to execute capture and discovery from a Raspberry Pi, read
the next section instead.
The machine running `idt` should be connected to the same Wi-Fi network used for
testing.
Follow the steps below to execute capture and discovery without a Raspberry Pi:
- From the parent directory of `idt`, run `source idt/scripts/alias.sh`.
- Optionally, run `source idt/scripts/setup_shell.sh` to install aliases
permanently.
- After `idt` aliases are available in your environment, calling any `idt`
command will automatically create a new virtual environment and install
python dependencies.
- If you're missing non-Python dependencies, you'll be prompted to install
them until they're available.
- Bluetooth discovery on macOS will require granting the program where `idt`
is run, e.g. terminal emulator or IDE permission to access bluetooth in
macOS settings.
- Failure to do so may result in any of the following:
- A single `abort` message and no further output in the terminal.
- Failure with a relevant stack trace in the terminal.
- A prompt to allow the application access to bluetooth.
## Raspberry Pi installation
### Environment overview
The execution environment of IDT when using Raspberry Pi is shown in the figure
below.
[TODO] add figure.
The Raspberry Pi is where "discovery" and "capture" are executed.
The "admin" computer is the machine used to connect to and control the RPi, and
to fetch artifacts which were created during capture from the RPi.
This directory contains tools for use on both the admin computer and the RPi.
### Environment details
1. `idt` will be used on both the admin computer and the RPi.
1. `scripts` only points to one installation location at a time. It is ideal to
maintain a single `idt` directory on each (admin and RPi) system accordingly.
1. The expected install location on the RPi is the home directory of the user
specified in `idt/scripts/vars.sh`, which will be generated by running a
script in the next section.
1. Helper scripts may be used on admin computers that support `zsh` and `bash`
(Linux and macOS).
1. Windows may be used as the admin computer via tools like `PowerShell`,
`MobaXterm` and `FileZilla`.
1. This setup is intended to work with the admin computer and RPi connected to
the same Wi-Fi network, which is also the Wi-Fi network used for testing.
1. Corporate networks are not expected to be used as test networks.
### Prepare the RPi
1. A >= 128 GB SD card is recommended.
1. Flash the RPi SD with the debian based distribution of your choice.
1. Plug the SD into the RPi.
1. Ensure the RPi is connected to your network, either via ethernet or with
Wi-Fi configured in the disk image.
1. Boot the RPi.
### Configure admin computer and push to the RPi
#### Linux and macOS admin computers
1. On your admin computer, source the `alias` script from the parent directory
of `idt` to get `idt` commands in your current shell.
```
source idt/scripts/alias.sh
```
- To avoid having to repeat this step for each session, optionally configure
automatic aliases permanently.
- **_NOTE:_** Once run, `idt` commands will be globally and automatically
available. If you need to remove the installation, edit the `.rc` files
mentioned in `setup_shell`.
```
source idt/scripts/setup_shell.sh
```
1. Run `idt_create_vars` and follow the prompts to set IDs for the target RPi.
1. Send `idt` to the RPi:
```
idt_push
```
1. `ssh` to the RPi:
- **_NOTE:_** You may need to wait a few minutes after boot for the `ssh`
server to be available on the RPi. Retry if needed!
```
idt_connect
```
#### Windows admin computers
1. Open `PowerShell`, cd to the directory containing `idt` and send `idt` to the
RPi:
```
scp -r ./idt/* $PIUSER@$PIHOST:/home/$PIUSER/idt
```
1. `ssh` to the RPi, e.g. with `MobaXterm`
- **_NOTE:_** You may need to wait a few minutes after boot for the `ssh`
server to be available on the RPi. Retry if needed!
- Use `$PIUSER@$PIHOST` or `$PIUSER@$ip` where `$ip` is the RPi's IP found
in your router admin panel.
### Configure the RPi
1. Configure passwords or ssh keys.
1. Configure Wi-Fi networks if needed.
1. Set up `idt`:
```
cd ~ # Go to idt parent dir
source idt/scripts/setup_shell.sh # Setup atuo aliases
source idt/scripts/alias.sh # Get aliases now
idt_bootstrap # Initial configuration
idt_build # Build the container image
```
### Install updates
SCP may not overwrite all files. To clear the `idt` dir off of the RPi safely
between pushes, exit the container and:
```
idt_clean
```
NOTE the idt artifacts directory is contained in idt, so running this will
delete any artifacts.
Then from the admin computer:
```
idt_push
```
## User guide
> **_IMPORTANT_**
> `idt_` commands are shell aliases helpful for administrative commands.
> `idt` invokes the `idt` python package.
> Output from `idt` will generally be colorized while output from sub processes
> is generally not.
RPi users, as needed:
- For users with Windows admin computers, reconnect e.g., using `MobaXterm`
- Other users reconnect `ssh` to the RPi (from your admin computer):
```
idt_connect
```
- Run the `idt` container (from the RPi):
```
idt_activate
```
### Capture
> **_IMPORTANT_**
> Ensure you've made it to the log line "Starting real time analysis, press
> enter to stop!" before launching the app under test.
```
idt capture -h
usage: idt capture [-h] [--platform {Android}] [--ecosystem {PlayServicesUser,PlayServices,ALL}] [--pcap {t,f}] [--interface {wlp0s20f3,lo,docker0,any}]
options:
-h, --help show this help message and exit
--platform {Android}, -p {Android}
Run capture for a particular platform (default Android)
--ecosystem {PlayServicesUser,PlayServices,ALL}, -e {PlayServicesUser,PlayServices,ALL}
Run capture for a particular ecosystem or ALL ecosystems (default ALL)
--pcap {t,f}, -c {t,f}
Run packet capture (default t)
--interface {wlp0s20f3,lo,docker0,any}, -i {wlp0s20f3,lo,docker0,any}
Specify packet capture interface (default any)
```
For packet capture interface (`-i`/`--interface`:
- On macOS, the only available interface is `any`.
- On Linux, `idt` checks available interfaces from `/sys/class/net/` as well
as allowing `any`.
#### Artifacts
Each ecosystem and platform involved in the capture will have their own
subdirectory in the root artifact dir.
### Discovery
```
idt discover -h
usage: idt discover [-h] --type {ble,b,dnssd,d}
options:
-h, --help show this help message and exit
--type {ble,b,dnssd,d}, -t {ble,b,dnssd,d}
Specify the type of discovery to execute
```
#### BLE
```
idt discover -t b
```
#### mDNS
```
idt discover -t d
```
#### Artifacts
There is a per device log in `ble` and `dnssd` subdirectory of the root artifact
dir.
### Probe
```
usage: idt probe [-h]
options:
-h, --help show this help message and exit
```
Collect contextually relevant networking info from the local environment and
provide artifacts.
## Troubleshooting
- Wireless `adb` may fail to connect indefinitely depending on network
configuration. Use a wired connection if wireless fails repeatedly.
- Change log level from `INFO` to `DEBUG` in root `config.py` for additional
logging.
- Compiling `tcpdump` for android may require additional dependencies.
- If the build script fails for you, try
`idt_go && source idt/scripts/compilers.sh`.
- You may disable colors and splash by setting `enable_color` in `config.py`
to `False`.
- `idt_clean_child` will kill any stray `tcpdump` and `adb` commands.
- `idt_check_child` will look for leftover processes.
- Not expected to be needed outside of development scenarios.
## Project overview
- The entry point is in `idt.py` which contains simple CLI parsing with
`argparse`.
### `capture`
- `base` contains the base classes for ecosystems and platforms.
- `controller` contains the ecosystem and platform producer and controller
- `loader` is a generic class loader that dynamically imports classes matching
a given super class from a given directory.
- `/platform` and `/ecosystem` contain one package for each platform and
ecosystem, which should each contain one implementation of the respective
base class.
### `discovery`
- `matter_ble` provides a simple ble scanner that shows matter devices being
discovered and lost, as well as their VID/PID, RSSI, etc.
- `matter_dnssd` provides a simple DNS-SD browser that searches for matter
devices and thread border routers.
### `probe`
- `probe` contains the base class for (`idt`'s) host platform specific
implementation.
- Reuses the dnssd discovery implementation to build probe targets.
- Calls platform + addr type specific probe methods for each target.
- `linux` and `mac` contain `probe` implementations for each host platform.
### `utils`
- `log` contains logging utilities used by everything in the project.
- `artifact` contains helper functions for managing artifacts.
- `shell` contains a simple helper class for background and foreground Bash
commands.
- `host_platform` contains helper functions for the interacting with the host
running `idt`.
### Conventions
- `config.py` should be used to hold development configs within the directory
where they are needed.
- It may also hold configs for flaky/cumbersome features that might need
to be disabled in an emergency.
- `config.py` **should not** be used for everyday operation.
- When needed, execute builds in a folder called `BUILD` within the source
tree.
- `idt_clean_all` deletes all `BUILD` dirs and `BUILD` is in `.gitignore`.
## Extending functionality
### Capture
Ecosystem and Platform implementations are dynamically loaded.
For each package in `capture/ecosystem`, the ecosystem loader expects a module
name matching the package name.
This module must contain a single class which is a subclass of
`capture.base.EcosystemCapture`.
`/capture/ecosystem/play_services_user` contains a minimal example
implementation.
As another example, link `/res/plugin_demo/ecosystem/demo_ext_ecosystem`.
```
$ idt_go && ln -s $PWD/idt/res/plugin_demo/ecosystem/demo_ext_ecosystem/ idt/capture/ecosystem
$ idt capture -h
usage: idt capture [-h] [--platform {Android}] [--ecosystem {DemoExtEcosystem...
```
> **IMPORTANT:** Note the following runtime expectations of ecosystems:
> `analyze_capture()` must not block the async event loop excessively and must
> not interact with standard in
The platform loader functions the same as `capture/ecosystem`.
For each package in `capture/platform`, the platform loader expects a module
name matching the package name.
This module must contain a single class which is a subclass of
`capture.base.PlatformLogStreamer`.