Assembling structured configuration

Structured configuration allows developers to package components with different values in different contexts. Product assembly allows developers to define structured configuration values based on high-level platform and product configuration.

To vary your component's configuration by product or build type you must declare a schema, identify how values will be derived from a product's configuration, and generate your component's config.

Define a configuration schema

Your component must have a declared configuration schema in its manifest. For example:

    ...
    config: {
        enable_foo: { type: "bool" },
    },

For more information see the documentation for structured config.

Identify product assembly configuration

Many configuration options can be represented as the difference between eng builds and non-eng builds.

If the configuration of your component can't be deduced solely from build type, email the Software Assembly list to discuss the schema which should be used (note that this list is publicly viewable, please use Google-internal lists to discuss internal-only configuration). Once a schema has been decided, add it to the product configuration library.

Configure the package

Determine your package's name and your component's manifest resource path. Define logic to populate configuration for it in the product assembly tool. For example, to configure a value based on the build type:

use crate::subsystems::prelude::*;
use assembly_config_schema::platform_config::example_config::ExampleConfig;

pub(crate) struct ExampleSubsystemConfig;
impl DefineSubsystemConfiguration<ExampleConfig> for ExampleSubsystemConfig {
    fn define_configuration(
        context: &ConfigurationContext<'_>,
        example_config: &ExampleConfig,
        builder: &mut dyn ConfigurationBuilder,
    ) -> anyhow::Result<()> {
        // If the build-type is eng, enabled "foo" for the example component.
        builder
            .package("configured_by_assembly")
            .component("meta/to_configure.cm")?
            .field("enable_foo", matches!(context.build_type, BuildType::Eng))?;

        if example_config.include_example_aib {
            builder.platform_bundle("example_assembly_bundle");
        }

        Ok(())
    }
}

Update size limits configuration (if any)

When producing configuration values for a package, product assembly must write its outputs to a different location in the build directory than the path normally produced by the build system. There are binary size checks that rely on paths to package manifests that exist in the build directory, so it is important that you update the package's output path in the build configuration rules.

For example, before having its configuration generated by product assembly, the session_manager package was listed in the core product's size limits as:

{
  component = "Component Framework"
  src = [
    # ...

    "packages/base/session_manager",
  ]

  # ...
},

When using product assembly for its config, session_manager must now be specified in size limits as:

{
  component = "Component Framework"
  pkgs = [
    # ...

    "session_manager",
  ]

  # ...
},