blob: b45799d998999456e7328c559c33a9dd1f1b5384 [file] [log] [blame] [view] [edit]
# Starnix
Starnix runs unmodified Linux binaries on Fuchsia. We have tested Starnix with
glibc and bionic based binaries. Patches that improve Linux compatibility are
welcome!
## How to run starnix
### Configure your build
In order to run starnix, we need to build `//src/starnix`.
For faster iteration, configure your build with incremental compilation:
```sh
fx set workbench_eng.x64 --args 'rust_incremental="incremental"' --with //src/starnix:tests --with //src/starnix/containers
fx build
```
> Note: While we recommend using incremental compilation, you may experience a rust
> internal compiler error.
> If so, simply `rm -rf out/default/incremental/*` and try again.
> Note: If you have `//vendor/google` in your source tree, you might want to add
> `//vendor/google/starnix:tests` to the `fx set` command above to include some
> additional, non-public tests.
### Run Fuchsia
Run Fuchsia as normal, for example using `fx serve` and `ffx emu start --headless`.
To monitor starnix, look for log messages with the `starnix` tag:
```sh
ffx log --filter starnix --severity TRACE --set-severity "core/starnix_runner/kernels*#TRACE"
```
When running tests, you will need to pass the log selection parameters to fx test instead:
```sh
fx test <test name> --min-severity-logs TRACE
```
The `--set-severity` arguments contain the moniker for the starnix instance whose minimum severity
log level you want to change. This affects the logs emitted by starnix, as opposed to `--severity`,
which affects which logs are filtered for viewing. The changed log level only persists for the
duration of the `ffx log` command.
If you do not care about detailed logging, you can leave out the `--severity` and just do:
```sh
ffx log --filter starnix
```
Starnix produces a large amount of logs and this can overload archivist's ability to
retain them, instead printing messages with `[dropped=N]` or `[rolled=N]` like:
```text
[00251.246717][149962][179421][starnix][19:19[sleep],starnix] TRACE: readlinkat:267(0xffffff9c, 0x1b5a6891270, 0x1b5a6890270, 0xfff, 0xffffffffffffffff, 0x0) [dropped=15]
...
[00311.111743][149962][289720][starnix][100:100[binder:100_2],starnix] TRACE: Reading 92 bytes of memory from UserAddress(0x2f33f942770) [rolled=67]
```
If you see this, you can reduce or eliminate the lost messages by setting a
custom value for the GN arg which controls the size of retained logs in
archivist:
```
fx set ... --args=archivist_max_cached_logs_bytes=41943040
```
A value of `41943040` (10x the default) seems to work well.
This can also be added to [`$FUCHSIA_DIR/local/args.gn`][local-args] if you want
it to apply to all of your builds.
### Run a Linux binary
Running a Linux binary manually involves two steps. First, you need to start the
container in which the binary will run. This step is analogous to booting a
virtual machine:
```sh
ffx component run /core/starnix_runner/playground:<container-name> <container-url>
```
In this command, you pick a `<container-name>` that you can use to refer to
this container later. You can run as many instances of a container as you wish
as long as you given them different names.
The `<container-url>` is the component URL for the container you wish to run.
For example, `fuchsia-pkg://fuchsia.com/starless#meta/empty_container.cm` is
the component URL for the empty container, which does not have a `libc.so`
and, therefore, cannot run dynamicly linked C binaries.
Once the container is running, you can run Linux binaries inside that
container using the component URL for that binary:
```sh
ffx component run --connect-stdio \
/core/starnix_runner/playground:<container-name>/daemons:<component-name> \
<component-url>
```
The `--connect-stdio` flag is optional, but specifying this flag will cause
stdio, stdout, and stderr from your terminal to be connected to the binary.
Notice that this command re-uses the `<container-name>` you picked for the
previous command. This name indicates the container in which the process
will run.
Similar to the previous command, you pick a `<component-name>` for the
component that represents this process. When the process exits, this component
will disappear from the component topology.
The `<component-url>` is the component URL for the binary you wish to run. For
example, `fuchsia-pkg://fuchsia.com/hello_starnix#meta/hello_starnix.cm` is the
component URL for the `hello_starnix` binary. The component manifest specifies
which binary to run. The binary can be inside the container (e.g., `/bin/sh`)
or the binary can be in the package that contains the component.
To terminate the container, use the `ffx component stop` command.
See [`hello_starnix`](../examples/hello_starnix/README.md) for how to run a
minimal binary in an empty container.
### Getting a shell
Running a shell first requires running a container that has a shell binary. In
this example, let's use the Alpine container:
```
ffx component run /core/starnix_runner/playground:alpine fuchsia-pkg://fuchsia.com/alpine#meta/alpine_container.cm
```
Note that the alpine container is not included in the build by default, so
you'll need to add `//src/starnix/containers/alpine:alpine_package` to your
build targets.
Once you have this Starnix container running, you can attach a console to that
container and run a shell by running:
```sh
ffx starnix console -m /core/starnix_runner/playground:alpine /bin/sh
```
This command assumes the container has a shell binary at `/bin/sh`. If you wish
to run another binary, you have to specify the full path.
If you omit the `-m` argument, `ffx starnix console` will look for a Starnix
container in the Fuchsia session.
### Run a Linux test binary
Linux test binaries can also be run using the Starnix test runner using the
standard `fx test` command:
```sh
fx test exit_test --output
```
You should see output like:
```text
[==========] Running 3 tests from 1 test suite.
[----------] Global test environment set-up.
[----------] 3 tests from ExitTest
[ RUN ] ExitTest.Success
[ OK ] ExitTest.Success (4 ms)
[ RUN ] ExitTest.Failure
[ OK ] ExitTest.Failure (3 ms)
[ RUN ] ExitTest.CloseFds
```
If you set the log level to `TRACE` (e.g., `ffx log --severity TRACE --set-severity "core/test*/*/starnix*#TRACE"`), you should see the system call handling in the device logs:
```text
[629.603][starnix][D] 1[/data/tests/exit_test] wait4(0x3, 0x1c48095b950, 0x0, 0x0, 0x10, 0x10)
[629.603][starnix][D] 3[/data/tests/exit_test] prctl(0x53564d41, 0x0, 0x700d5ea000, 0x3000, 0x3a506c7a34b, 0xc06913ece9)
[629.603][starnix][D] 3[/data/tests/exit_test] -> 0x0
[629.604][starnix][D] 3[/data/tests/exit_test] exit_group(0x1, 0x3, 0x2b18e3464f8, 0x3000, 0x3a506c7a34b, 0xc06913ece9)
[629.604][starnix][I] exit_group: pid=3 exit_code=1
```
For GUnit tests (such as the syscall tests in //src/starnix/tests/gvisor),
you can run specific tests with the `--test-filter` flag. For example,
```sh
fx test epoll_test --output --test-filter="EpollTest.AllWritable"
```
Specifying `*` as the filter turns on all tests in the binary.
### Copying files to and from a container
Suppose you have a container running as follows:
```sh
ffx component run /core/starnix_runner/playground:debian fuchsia-pkg://fuchsia.com/debian#meta/debian_container.cm
```
You can use the `ffx component copy` command to copy files to and from the container's root file
system:
```sh
ffx component copy myfile.txt core/starnix_runner/playground:debian::out::fs_root/tmp
```
This command copies the local `myfile.txt` file to `/tmp/myfile.txt` in that container.
### Making changes to Starnix when using ffx
The Starnix instances that `ffx` connects are static in the component hieararchy. This means that
they need to be stopped explicitly in order to be updated when changes have been made to the Starnix
runner code.
```sh
ffx component stop starnix_kernel
```
If more than one Starnix instance is running, the above command will list the running Starnix instances and you can stop them individually.
Alternatively, use the following command to stop all the instances at once:
```sh
ffx target ssh killall starnix_kernel.cm
```
## Testing
### Writing in-process unit tests
Decorate your test function with the `#[::fuchsia::test]` macro instead of the standard `#[test]`
macro. `#[::fuchsia::test]` will initialize logging so that failing tests can be debugged more
easily.
### Running the in-process unit tests
Starnix also has in-process unit tests that can interact with its internals
during the test. To run those tests, use the following command:
```sh
fx test starnix-tests
```
### Using a locally built syscalls test binary
The `syscalls_test` test runs a prebuilt binary that has been built with the
Android NDK. You can substitute your own prebuilt binary using the
`starnix_syscalls_test_label` GN argument:
```sh
fx set core.x64 --args 'starnix_syscalls_test_label="//local/starnix/syscalls"' --with //src/starnix,//src/starnix:tests
```
Build your `syscalls` binary and put the file in `//local/starnix/syscalls`.
(If you are building using the Google-internal build system, be sure to
specific the `--config=android_x86_64` build flag to build an NDK binary.)
You can then build and run your test as usual:
```sh
fx build
fx test syscalls_test
```
### Viewing Inspect for debugging
You can view Inspect data exposed by starnix using `ffx inspect`.
To view the thread groups currently running, run:
```
ffx inspect show core/starnix_runner/alpine:root/container/kernel/thread_groups
```
## Logging
By default, starnix compiles-out trace and debug logging in release builds for
performance reasons. To compile-in trace and debug logging in release builds,
set the `starnix_enable_trace_and_debug_logs_in_release` GN arg to `true` and
rebuild.
## Tracing
By default, starnix compiles-out tracing. To compile-in tracking, set the
`starnix_enable_tracing` GN arg to `true` and rebuild.
To start a trace with an increased buffer size, run:
```
ffx trace start --categories "kernel:meta,starnix" --buffer-size 64
```
To include Zircon task runtime stats at each restricted enter/exit transition,
include the `starnix:task_runtime` category:
```
ffx trace start --categories "kernel:meta,starnix,starnix:task_runtime" --buffer-size 64
```
Trace files can be visualized and queried with Perfetto. For example, to see the average
time spent in starnix during a `clock_getres` syscall, run the query:
```
select avg(dur), count(*)
from slice join args using (arg_set_id)
where key='name' and display_value='clock_getres' and name='RunTaskLoop'
```
[adb.docs]: https://developer.android.com/studio/command-line/adb#copyfiles
[local-args]: /docs/development/build/fx.md#defining_persistent_local_build_arguments