| # component manager |
| |
| Reviewed on: 2019-07-12 |
| |
| Component manager is the program which runs and manages v2 components. More |
| about what components are, what semantics they provide, and how to use them is |
| available [here](/docs/the-book/components/README.md). |
| |
| ## Building |
| |
| Component manager should be included in all builds of Fuchsia, but if missing |
| can be added to builds by including `--with //src/sys/component_manager` to the |
| `fx set` invocation. |
| |
| ### Faster builds |
| |
| Rust optimizations (and, in particular, link time optimizations) require a |
| significant amount of time, causing slow builds. For faster local development, |
| adding the following arguments to your `fx set` line will significantly |
| reduce build times by disabling optimizations: |
| |
| ```sh |
| fx set ... --args rust_override_opt='"0"' --args rust_override_lto='"none"' |
| ``` |
| |
| ## Running |
| |
| Component manager runs by default on all Fuchsia builds. |
| |
| ## Testing |
| |
| Unit tests for component manager are available in the `component_manager_tests` |
| package. |
| |
| ``` |
| $ fx test component_manager_tests |
| ``` |
| |
| Integration tests are also available in the following packages: |
| |
| - `hub_integration_test` |
| - `storage_integration_test` |
| - `routing_integration_test` |
| - `elf_runner_test` |
| - `no_pkg_resolver_test` |
| |
| ## Source layout |
| |
| The entrypoint is located in `src/main.rs`, and the core model implementation is |
| under `src/model/`. Unit tests are co-located with the code, with the exception |
| of `src/model/` which has unit tests in `src/model/tests/`. Integration tests |
| live in `tests/`. |
| |
| ## Development best practices |
| |
| ### `Arc<Realm>` and `fasync::spawn` |
| |
| #### Problem |
| |
| Many parts of the code need access to a `Realm`. Some of those are long-running asynchronous |
| operations, such as hosting a pseudo-fs directory with a closure (see `//src/sys/lib/directory_broker`). |
| These operations are executed on the global executor through `fasync::spawn`. |
| |
| These closures should never capture an `Arc<Realm>`, as the closures lifetime is not bound to the `Realm`, |
| even though it is conceptually tied to the life of `Realm`. This can lead to memory leaks / reference cycles. |
| |
| #### Solution |
| |
| Use `WeakRealm`, which wraps a `Weak<Realm>` (weak pointer to `Realm`) along with the `AbsoluteMoniker` of |
| the realm, for good error-reporting when the `Realm` has been destroyed. |
| |
| ``` |
| use crate::model::realm::{Realm, WeakRealm}; |
| |
| let realm: Arc<Realm> = model.look_up_realm(...)?; |
| let captured_realm: WeakRealm = realm.as_weak(); |
| fasync::spawn(async move { |
| let realm = match captured_realm.upgrade() { |
| Ok(realm) => realm, |
| Err(e) => { |
| log::error!("failed to upgrade WeakRealm: {}", e); |
| return; |
| } |
| }; |
| ... |
| }); |
| ``` |