This directory contains the aconfig flag definitions and the associated build files for Android Audio features.
There are several global namespaces involved with flagging which must be maintained:
media_audio
. Associated with mdb group and used by gantry. All aconfig flags in this namespace should be defined in this directory, and all flags defined in this directory should belong to this namespace.aconfig_declarations
with packages which intersect, these libraries are incompatible to be linked together (and equivalent in cc). If the library is included in the framework, it is on the bootclasspath, so no other library for that package can exist. Additionally, the cpp backend generates header files with the same name as the unqualified name of the package which means include path conflicts are possible.Given above, follow the following naming convention (given a {PACKAGE}
).
Generally, aconfig_declarations
and {backend}_aconfig_library
should be 1-1, except in cases where different package configurations are needed with pre-processing with different classpaths. This is because multiple libraries with the same aconfig package cannot compile together.
aconfig_declarations { name: "{PACKAGE}-aconfig", package: "{PACKAGE}", srcs: ["{PACKAGE}.aconfig"] } {backend}_aconfig_library { name: "{PACKAGE}-aconfig-{backend}", aconfig_declarations: "{PACKAGE}-aconfig", defaults: ["audio-aconfig-{backend}-defaults"], }
If the flags are required as part of the framework, the java backend is ingested into the framework via srcjar for cyclic dependency/simplicity reasons. Add the following
":{PACKAGE}-aconfig-java{.generated_srcjars}"
as a source in audio-framework-aconfig
. This target is included in the file-list which compiles the framework. If a lib is included in this list, it is unecessary to add it in any other blueprint file for platform code (for non-host). For tests, the library should be statically linked (which shadows the bootclasspath), to get around @hide restrictions (this approach may change).
Visibility should be controlled (private) so that flag cleanup remains maintainable by the team. This constraints the locations where extant flags need to be chased for removal.
As a rule, prefer the most constrained package appropriate for a particular flag. This limits viral dependencies on a flag library which restricts where/how testing can occur. It also speeds up incremental rebuilds. Packages which end up in the framework should be avoided as much as possible, since they require rebuilding the framework, pollute the bootclasspath, and require special build handling to operate (srcjar generation, jarjar to access in CTS).
Utilize "java-like" package naming for all packages, to ensure packages are globally unique, and to avoid class conflicts if these flags are later included in java code.
In general, prefer flags at the integration level, rather than at the implementation level. This allows flags to be queried in as few locations as possible such as by (parametrizing functions, classes, types, etc.) It also allows callers to make different decisions on when behavior can/should be changed (e.g. different flags could be used for different libraries). This follows dependency injection principles and ensures that global state has a smaller blast radius, and also makes it easier to test code by relying less on infrastructure. The more places a flag is queried, the more its implementation should be deferred upwards, either by the injection interfaces, or by explicit parametrization.
In general, flags should be scoped as precisely as possible while retaining orthogonality. If flags are too specific (multiple flags interact together to encompass a single change), then reasoning about independently switching flags becomes difficult. Other than all-on and all-of configurations, there is limited soak for flag combinations, so it is critical that flags interact with each other minimally (although emergent properties are inevitable). However, if flags are too general, graduating/reverting flags can carry too much behavior change, the build graph degenerates, and
In general, it is recommended that the moment a flag is added to the tree, it should be moved to staging on gantry. There is no benefit to adding a flag but not moving into staging. This allows:
FlaggedApi operates differently than other types of flags since these flags only graduate at the next API bump. These flags also must be exposed through the framework. FlaggedApis should only operate over the same set of flags as an implementation if the implementation is entirely related to the feature. Given the constraints on the flag lifetime, it is preferable to use a "regular" flag for implementation, which can integrate/soak/ship/clean-up faster.
Additionally, unlike "regular" flags, @FlaggedApis are not effectively soaked, so like non-trunk API development, they are heavily reliant on CTS to integrate.
On non-next configs, @FlaggedApi has no runtime control, but it is undefined for callers to call a FlaggedApi without querying the status of the flag. The build itself is not changed on staging. Anything which builds against the platform can see all @FlaggedApis.
Methods annotated FlaggedApis are changed for release finalization -- if an API is not in next, it is stripped from the Sdk (and left @hide). If an API graduated to next, it is included fully included in the Sdk, and the @FlaggedApi annotation is stripped.
TestApis do not require flagging, since their existence in the tree implies that they should be accessible to callers (xTS not building on trunk enables this).
Currently, the flag infra does not support any type of Api modification (arguments, annotation, renaming, deletion, etc.) In any of these cases (including for SystemApi), exceptions will need to be granted.