| <!-- mdformat off(templates not supported) --> |
| {% set rfcid = "RFC-0115" %} |
| {% include "docs/contribute/governance/rfcs/_common/_rfc_header.md" %} |
| # {{ rfc.name }}: {{ rfc.title }} |
| <!-- SET the `rfcid` VAR ABOVE. DO NOT EDIT ANYTHING ELSE ABOVE THIS LINE. --> |
| |
| <!-- mdformat on --> |
| |
| ## Summary |
| |
| This document describes the different product build types for Fuchsia: |
| `eng`, `userdebug`, and, `user`. |
| |
| A build type in Fuchsia refers to build time and runtime settings for a |
| [product configuration][doc-products]: |
| |
| * Build time settings include packages, tools, signing configuration, |
| and flags that define system behavior. |
| |
| * Runtime settings include flags passed to the running kernel or software |
| modulating runtime behavior based on the build type. |
| |
| The intent of this document is to formally ratify the design decisions |
| that have been made for Fuchsia products that are already using these |
| build types. It also serves as a formal definition for the different |
| build types in the Fuchsia platform. |
| |
| ## Motivation |
| |
| Fuchsia defines several build types for use by a diverse set of users |
| that include developers, testers, and end-users. Each of these user |
| groups has certain expectations about the behavior of a running |
| Fuchsia system. |
| |
| A specific build type codifies and guarantees certain Fuchsia system |
| behavior for different use cases such as development or a product |
| shipped to end-users. |
| |
| Furthermore, build time decisions, such as inclusion of a certain |
| [package flavor][doc-package-flavor] can be made based on the product |
| build type. See the [Package Flavors](#flavors) section for more details |
| and an example. |
| |
| Thus, the different build types provide the necessary flexibility for |
| the Fuchsia platform and its users supporting the full lifecycle of a |
| Fuchsia product. |
| |
| ## Design |
| |
| This section outlines the current common convention of build types on |
| Fuchsia. It details the different attributes of each type and the |
| runtime constraints where applicable. |
| |
| A constraint is also kept in mind around the number of build types that |
| are defined due the complexity and implementation cost. See the |
| [Drawbacks](#drawbacks) section for more details. |
| |
| For the purposes of Fuchsia's current requirements, there are three |
| build types: |
| |
| * `user` |
| * `userdebug` |
| * `eng` |
| |
| The build types are further explained in the [Definitions](#definitions) |
| section below. |
| |
| Additional build types will require a proposal that goes through the |
| [RFC process][docs-rfc] and is approved by the Fuchsia Engineering |
| Council (FEC). |
| |
| ### Goals |
| |
| The primary goals for the design are: |
| |
| * Formalize a common convention for build types that supports developer |
| needs as well as final product shipping requirements. |
| * Build types are implemented to be as similar as possible to avoid |
| additional divergence in the behavior of the product. |
| * Build types are released and qualified with the same criteria and |
| cadence. |
| |
| ### Definitions {#definitions} |
| |
| #### `user` |
| |
| The `user` build type is used in production devices that are shipped to |
| end-users. |
| |
| For `user` builds, the platform enforces the highest security guarantees |
| at runtime and only includes necessary components for the product |
| during build time. |
| |
| #### `userdebug` |
| |
| The `userdebug` build type behaves the same as `user` by default but allows |
| for additional debug and instrumentation behavior. |
| |
| The `userdebug` builds are primarily used in development devices for |
| end-user product testing and qualification. |
| |
| #### `eng` |
| |
| The `eng` build type is primarily for developers and testers and boots |
| to the full product experience as defined by the product [session][rfc-session]. |
| |
| The `eng` builds of various product configurations are available in-tree, |
| and as prebuilt system images alongside the [Fuchsia SDK][sdk]. |
| |
| ### Product Configuration |
| |
| The build types are defined as product specific configurations. To maintain |
| similarity across build types, the configurations inherit and include |
| from the *core* product of Fuchsia and selectively add or remove packages |
| and configurations. |
| |
| The build type relationships can be summarized as such: |
| |
|  |
| |
| **Figure 1: Build type as product configurations.** |
| |
| Notes: |
| |
| * The *eng* build type inherits *core* and can include additional |
| packages that are specific to the product. |
| |
| * The *user* build type directly inherits *core* but removes any extra |
| packages, debug capabilities, and other instrumentation properties. |
| |
| * The *userdebug* then inherits *user* and is only slightly different to |
| enable additional capabilities required for debugging and |
| instrumentation. |
| |
| * The reverse inheritance between *userdebug* and *user* ensures that |
| any changes to *user* that are required for the end-user product are |
| automatically reflected in *userdebug* builds. |
| |
| * The design roughly reflects the product cycle, with `eng` being the |
| first product configuration defined that is built on top of the `core` |
| Fuchsia product. Then, when the product goes further along its |
| lifecycle, `userdebug` and `user` are defined to reflect those |
| use cases and requirements. |
| |
| ## Implementation |
| |
| The section below documents the implementation details for each build type as |
| organized in the major areas of the platform. |
| |
| ### Assertions |
| |
| [Zircon][doc-zircon] is the core platform that powers Fuchsia and is |
| composed of the kernel and a small set of userspace services, drivers, |
| and libraries. |
| |
| There are several different assert-like mechanism used throughout the |
| code base. There are kernel and [usermode asserts][doc-zx-assert] which |
| are enabled or disabled depending on the build type. As an example, |
| `ZX_ASSERT` is always on for all build types and must be cheaper to |
| avoid impacting performance. |
| |
| In another example, `assert_level` is `2` in `eng` builds and enables |
| all asserts while this is `0` in `userdebug` and `user` builds, which |
| disables standard C `assert()` and `ZX_DEBUG_ASSERT`. |
| |
| The following table outlines the asserts in the kernel: |
| |
| | Attribute | *eng* | *userdebug, user* | |
| | --------- | ----- | ----------------- | |
| | ASSERT | on | on | |
| | DEBUG_ASSERT | on | off | |
| | assert() | on | off | |
| |
| ### Recovery Partition |
| |
| A Fuchsia end-user product uses an A/B/R update and recovery scheme. |
| |
| In summary, the system updates via an Over-The-Air (OTA) mechanism, |
| leverages the A/B update scheme in which two copies of the system are |
| present(one active and the other inactive). This ensures that a system |
| has a fallback in case of a failed update. If however, the fallback is |
| not able to boot, the system uses the recovery image stored in the |
| recovery partition in an attempt to recover the system. |
| |
| Each product can define their own recovery image. By default, in `eng` |
| builds, [`zedboot`][glossary-zedboot] is used. Since *zedboot* is used |
| for [paving][doc-paving] a Fuchsia system, it makes available a debug |
| port and other facilities to recover the system. |
| |
| Note: `Zedboot` is being deprecated in favor of `Fastboot` as outlined |
| in [RFC-0075][rfc-zedboot]. This further aligns the different build |
| types to use the same way for provisioning. |
| |
| In `userdebug` and `user` a different recovery image is used that is |
| minimal and meets security requirements of an end-user product. |
| |
| | Attribute | *eng* | *userdebug, user* | |
| | --------- | ----- | ----------------- | |
| | Recovery (R) | zedboot | *minimal recovery image* | |
| |
| ### Packages and Updates |
| |
| #### Auto Update of Packages |
| |
| In the `eng` build type, [`auto_update_packages`][doc-auto-update] is enabled |
| by default. Thus, when resolving a component (i.e., via running the component), |
| an attempt to update the component's package is first made through |
| `fuchsia.pkg.PackageResolver`. |
| |
| In day-to-day development, this facility is useful to ensure the system is |
| always running the latest components from the developer's environment. |
| |
| For `userdebug` and `user` builds this feature is disabled. Any changes |
| to the components and packages must be done through a System Update, |
| which changes packages in the [`base`][doc-base-packages] system and |
| triggers a reboot. |
| |
| | Attribute | *eng* | *userdebug, user* | |
| | --------- | ----- | ----------------- | |
| | auto_update_packages | true | false | |
| |
| #### Package Flavors {#flavors} |
| |
| [Package flavors][doc-package-flavor] are used to specify an `eng` |
| flavor of a package that then includes an `eng` flavor of the |
| component. The package is then included in the product configuration |
| that defines the `eng` build type. |
| |
| For example: |
| |
| ```gn |
| package_flavor_selections += [ |
| { |
| name = "my_component_pkg" |
| flavor = "eng" |
| }, |
| ] |
| ``` |
| |
| Similarly, a `user` flavor of the package is included in the `user` |
| build for the product. |
| |
| #### System Update |
| |
| Fuchsia uses an Over-The-Air (OTA) update mechanism for operating |
| [system updates][doc-otas]. There are two entry points, the |
| `omaha-client` or the `system-update-checker` components: |
| |
| |
| | Attribute | *eng* | *userdebug, user* | |
| | --------- | ----- | ----------------- | |
| | Auto System OTA | false | true | |
| | Update Checker | `system-update-checker` | `omaha-client` | |
| | Omaha Configuration | n/a | defined | |
| |
| Omaha Configuration defines a server side configuration for performing |
| system updates which is suitable for end-user builds such as `userdebug` |
| and `user`. |
| |
| The Omaha configuration contains information that is stored in |
| the [`VBMeta`][vbmeta] to ensure the full root of trust of the software |
| is verified before execution. |
| |
| #### Package Sets, Runnable Components, and Allowlists |
| |
| Fuchsia boards and products definitions augment three lists of dependencies, |
| [Base, Cache and Universe][doc-dependency-sets]. Thus, the |
| [packages][doc-base-packages] that are defined within these sets |
| determine how they are managed in Fuchsia. |
| |
| For example, changes to packages in the `base` set are only possible via |
| a system OTA update. Thus, requires a reboot of the system. |
| |
| Since the `universe` set allows for access to the entire Fuchsia |
| software set, it is not allowed in `user` builds. |
| |
| Note: The allowlist for `userdebug` and `user` can be different depending |
| on the product requirements. |
| |
| | Attribute | *eng* | *userdebug* | *user* | |
| | --------- | ----- | ----------- | ------ | |
| | Available Sets | base, cache, universe | base, cache, universe | base | |
| | Allowlist | all packages allowed | base + allowlist | only base | |
| |
| An [allowlist](/src/security/policy/README.md) is a policy that |
| determines which component can be run (based on the component URL) or |
| which component can access certain services at runtime. This is useful |
| to ensure `user` build, for example, does not run a development |
| component or service meant for `eng` builds. |
| |
| In another example, the `userdebug` build allows for a limited set of |
| tools to run for inspecting the system such as [`iquery`][doc-iquery] |
| to inspect properties of the running components. |
| |
| In `user`, only the software required for the running of the product is |
| allowed. In the current design, this software is restricted to what is |
| included in the `base` set. |
| |
| ### Software Sources |
| |
| Fuchsia software is delivered through packages that are hosted in a |
| software [repository][fuchsia-repository]. These software sources must |
| be known to Fuchsia and are verified cryptographically through a chain |
| of trust. |
| |
| For `eng` builds, there are no restrictions to which software sources |
| can be added to the system at runtime. |
| |
| For `userdebug` builds, software sources can only be added when the |
| target system is connected via a direct interface to the developer's |
| host workstation. |
| |
| The software sources in `user` builds are fixed and unmodifiable. |
| |
| Note: Adding, removing, and inspecting software resources is done using |
| the `pkgctl` tool. |
| |
| ### Debug, Logs, and Shell |
| |
| `eng` builds enable full access to the Fuchsia system and make available |
| all debug ports and logs. `user` builds restrict all access and logs while |
| `userdebug` looks to enable only limited access for debugging purposes. |
| |
| | Attribute | *eng* | *userdebug* | *user* | |
| | --------- | ----- | ----------- | ------ | |
| | ssh | enabled | enabled | disabled | |
| | serial | enabled | r/o bootloader and kernel | r/o in bootloader | |
| | debug_agent | enabled | disabled | disabled | |
| | k commands | enabled | disabled | disabled | |
| | ffx runtime | enabled | enabled | disabled | |
| |
| Note: [`ffx`][docs-ffx] is the primary Fuchsia workflow tool that leverages |
| FIDL APIs exposed by the Fuchsia system in a set of sub-commands on the |
| host side. Most facilities are available via `ffx` without requiring |
| shell access. |
| |
| Note: [`k commands`][k-commands] are useful for debugging the kernel at |
| runtime. More information can be found in `k help`. |
| |
| ### Crash Reporting |
| |
| Crash reporting services are available and provided by the `fuchsia.feedback` |
| [API][fidl-crash-reporter]. By default, crash upload is disabled for `eng` |
| builds. For `user` and `userdebug` builds, user consent must be explicitly |
| provided to enable crash report upload. |
| |
| Crash reports are still captured and stored in the local crash report |
| database by default for all builds. |
| |
| | Attribute | *eng* | *userdebug, user* | |
| | --------- | ----- | ---------------- | |
| | Crash reporting | enabled | enabled | |
| | Crash upload | disabled | allowed on user consent | |
| |
| Crash uploads includes system and kernel log files, and component |
| inspect data to help with issue triage. These data files can contain |
| Personal Identifiable Information (PII) and are scrubbed before |
| upload. |
| |
| ### Telemetry |
| |
| The Fuchsia platform provides a service to log, collect, and analyze |
| metrics. This service is provided by [`fuchsia.metrics`][fidl-metrics]. |
| The two main pillars of Cobalt are protecting user |
| privacy and providing high-quality, aggregate metrics to serve the |
| system and component software developers' needs. |
| |
| | Attribute | *eng* | *userdebug, user* | |
| | --------- | ----- | ---------------- | |
| | Metrics collection | enabled | enabled | |
| | Metrics upload | enabled | allowed on user consent | |
| |
| ### Verified Execution |
| |
| Verified execution is a central design of Fuchsia security and ensures |
| that all executed code is trustworthy. Trustworthiness is recursively |
| asserted through the verification of hashes and the verification of |
| digital signatures from trustworthy entities, beginning with an |
| immutable trust anchor. |
| |
| ### Verified Boot |
| |
| Verified boot is a phase of verified execution in which the bootloader |
| validates that the Fuchsia [`zbi`][glossary-zbi] is trusted for |
| execution by the bootloader. |
| |
| Local builds (whether `eng`, `userdebug`, or `user`) use an in-tree |
| development key, while builds produced for release are signed by more |
| secure keys obtained from a secure key management service. |
| |
| ### Prebuilt System Images |
| |
| Prebuilt `eng` images are available in the Fuchsia [`SDK`][sdk] while |
| `userdebug` and `user` builds are downloadable directly from Fuchsia |
| [Global Integration builders][luci-gi]. |
| |
| ### Build Time Optimizations |
| |
| General build optimizations flags for the Fuchsia platform are kept the |
| same across all build types to maintain alignment across the builds. |
| |
| In `eng` builds, [`is_debug`](/build/config/compiler.gni) is set to |
| `true` which sets the default flags to `debug` instead of `speed` as |
| set in `user` and `userdebug` builds. The flags are carried and used in |
| various configurations in the global [`BUILD.gn`][optimization-flags] file. |
| |
| For components, `eng` [package flavors][doc-package-flavor] can include |
| components that are compiled using special flags. For example, |
| [`DCHECK`][chromium-dcheck] assertions are often enabled in developer |
| builds and bot configurations to help catch unexpected issues in C++ |
| components. |
| |
| ## Performance |
| |
| It is understood that `eng` builds may induce performance penalties when |
| compared to `userdebug` builds, though the actual penalty varies by |
| product and board type. The primary impact comes from enabling extra |
| assertions in the platform. This is tested using |
| [`/zircon/system/ulib/perftest`](/zircon/system/ulib/perftest). |
| |
| In components, `eng` flavors that enable `DCHECK` also will result in |
| a significant performance impact when these components are heavily |
| used during benchmarking and testing. |
| |
| There is very little performance difference between `userdebug` and |
| `user` builds. When benchmarking performance, prefer a `userdebug` |
| build over an `eng` build. There are drawbacks to this approach which |
| are noted in the [Drawbacks](#drawbacks) section below. |
| |
| ## Security considerations |
| |
| Security implications were heavily considered in the design of Fuchsia |
| build types. The following approaches are used throughout to enforce |
| highest level of security guarantees for all users: |
| |
| * Leveraging verified execution to establish a full verified trust |
| chain from boot with separate signing keys for cryptographic |
| signatures. |
| |
| * Leveraging allowlist security policies in the Component Framework to |
| ensure only the allowed components are resolved and executed. |
| |
| * Only including the necessary packages and components for end-user |
| builds. |
| |
| * Disabling all access ports and facilities in end-user builds. |
| |
| ## Privacy considerations |
| |
| Privacy considerations were also heavily considered in the design of |
| Fuchsia build types. All logs on end-user builds are scrubbed for PII |
| and user consent MUST be provided to upload crash, logs, and metrics. |
| |
| ## Documentation |
| |
| The build types will be further documented in |
| [Fuchsia > Concepts > Build System](/docs/development/build/build_system/index.md) |
| so there is a canonical reference for the different attributes and |
| behaviors as they apply to products in Fuchsia. |
| |
| ## Testing |
| |
| ### Emulator |
| |
| The simplest and most straightforward way to test the behavior of |
| different build types is by leveraging the [Fuchsia Emulator][docs-femu]. |
| |
| Emulating the build types with the emulator allows the developer to |
| compare and test different behaviors of the platform and applications. |
| The downside is testing certain areas of the system such as system |
| updates or verified boot properties is currently not possible in an |
| emulator environment. |
| |
| ### Release Process |
| |
| Fuchsia leverages a [CI (Continuous Integration)][luci-gi] and CQ |
| (Commit Queue) pipeline that ensures code changes are built and tested |
| before a CL (changelist) has landed and during final integration |
| when the CL has merged. |
| |
| * A CQ pipeline, builds and tests a CL across different product |
| configurations and environments before the CL lands. |
| |
| * A CI pipeline, builds and tests code that have been checked in at |
| the same integration commit, across different product configurations. |
| |
| Since build types are also implemented as product configurations, all |
| build type configurations are built, tested, and released at the same |
| time via the same CI/CQ pipeline. |
| |
| Note that only the `eng` build type product configurations are tested as |
| part of CI/CQ. However, `user` and `userdebug` are still part of the |
| continuous build process. |
| |
| ### Facilities |
| |
| Testing frameworks and facilities are available in the *universe* set in |
| `eng` and `userdebug` builds. These services are not enabled by default |
| but are allowlisted for resolution and execution at runtime. |
| |
| For `user` builds, testing facilities are not enabled nor allowed by |
| security policies. |
| |
| For example, Fuchsia has the [`SL4F`][docs-testing] framework for |
| end-to-end tests and [`test_runner`][docs-test-runner] for Component |
| Framework testing. |
| |
| For automated testing use cases, the above frameworks can be used. But |
| if additional packages or additional tools are required, the use of `eng` |
| builds is recommended. |
| |
| ## Drawbacks, alternatives, and unknowns {#drawbacks} |
| |
| The design documented in this RFC has been implemented and reflects the |
| current state of Fuchsia product build types. |
| |
| By leveraging product configurations to implement build types, existing |
| implementations could be leveraged and re-used. The primary drawback is |
| the lack of scalability and flexibility to this approach. For example, |
| for each new product, a minimum of three product configurations |
| matching the three build types is required. There is cost associated |
| with this approach in the redundancy of the implementation and the extra |
| resources required in the Fuchsia infrastructure to spin up builders |
| for these new configurations. |
| |
| An additional drawback includes testing of `userdebug` builds. Since |
| `userdebug` builds include specific flavors of packages, different |
| system update configurations, and do not enable debug flags, they are |
| desirable for running end-to-end tests. But due to security restrictions, |
| it is not possible to run [SL4F][docs-testing] in official `userdebug` |
| builds. |
| |
| As an alternative, the [Standalone System Assembly][rfc-assembly] |
| provides the ability to modify assembled images and it can be leveraged |
| to assemble local `userdebug` builds that allow access to test |
| frameworks and are less restrictive. |
| |
| In the future, we should leverage a more scalable approach that allows |
| `eng`, `userdebug`, and `user` build type profiles to be applied |
| across the different product configurations. This avoids a linear |
| scaling problem in which new products require multiple product |
| configurations to accommodate build types. |
| |
| It is also worth noting the current implementation blends product and |
| platform, which is not the long term desire of the Fuchsia platform. |
| As discussed, it is advisable to consider a more flexible design in |
| the future. |
| |
| ## Prior art and references |
| |
| The Android operating system: |
| |
| * [Defines][android-build-types] `eng`, `userdebug`, and `user` builds. |
| * Published [guidelines][android-userdebug] for best practices in |
| modifying `userdebug` builds. |
| |
| [android-build-types]: https://source.android.com/setup/build/building |
| [android-userdebug]: https://source.android.com/setup/develop/new-device#userdebug-guidelines |
| [chromium-dcheck]: https://chromium.googlesource.com/chromium/src/+/HEAD/styleguide/c++/c++.md |
| [doc-auto-update]: /docs/gen/build_arguments.md#auto_update_packages |
| [doc-base-packages]: /docs/concepts/packages/package.md#base-packages |
| [doc-debugger]: /docs/development/idk/documentation/debugger.md |
| [doc-dependency-sets]: /docs/development/build/build_system/boards_and_products.md#dependency_sets |
| [doc-iquery]: /docs/reference/diagnostics/consumers/iquery.md |
| [doc-otas]: /docs/concepts/packages/ota.md |
| [doc-package-flavor]: /docs/gen/build_arguments.md#package_flavor_selections |
| [doc-paving]: /docs/development/build/fx.md#what-is-paving |
| [doc-products]: /docs/development/build/build_system/boards_and_products.md |
| [doc-zircon]: /docs/concepts/kernel/README.md |
| [doc-zx-assert]: /docs/gen/build_arguments.md#zx_assert_level |
| [docs-femu]: /docs/get-started/set_up_femu.md |
| [docs-ffx]: /docs/development/tools/ffx/overview.md |
| [docs-rfc]: /docs/contribute/governance/rfcs/README.md |
| [docs-test-runner]: /docs/development/testing/components/test_runner_framework.md |
| [docs-testing]: /docs/development/testing/sl4f.md |
| [fidl-metrics]: https://fuchsia.dev/reference/fidl/fuchsia.metrics |
| [fidl-crash-reporter]: https://fuchsia.dev/reference/fidl/fuchsia.feedback#CrashReporter |
| [fuchsia-repository]: /docs/concepts/packages/package_url.md#repository_root_verification_known_sources |
| [glossary-zbi]: /docs/glossary/README.md#zircon-boot-image |
| [glossary-zedboot]: /docs/glossary/README.md#zedboot |
| [k-commands]: /docs/development/debugging/tips.md |
| [luci-gi]: https://ci.chromium.org/p/fuchsia/g/global_ci/console |
| [optimization-flags]: https://fuchsia.googlesource.com/fuchsia/+/refs/heads/main/build/config/BUILD.gn#287 |
| [rfc-assembly]: /docs/contribute/governance/rfcs/0072_standalone_image_assembly_tool.md |
| [rfc-session]: /docs/contribute/governance/rfcs/0092_sessions.md |
| [rfc-zedboot]: /docs/contribute/governance/rfcs/0075_deprecate_zedboot_paving.md |
| [sdk]: /docs/development/idk/download.md |
| [vbmeta]: /src/lib/assembly/vbmeta/README.md |