| // Copyright 2015 Google Inc. All rights reserved. | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //     http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 |  | 
 | package android | 
 |  | 
 | import ( | 
 | 	"crypto/md5" | 
 | 	"encoding/hex" | 
 | 	"encoding/json" | 
 | 	"fmt" | 
 | 	"net/url" | 
 | 	"os" | 
 | 	"path" | 
 | 	"path/filepath" | 
 | 	"reflect" | 
 | 	"regexp" | 
 | 	"sort" | 
 | 	"strings" | 
 | 	"text/scanner" | 
 |  | 
 | 	"android/soong/bazel" | 
 | 	"android/soong/ui/metrics/bp2build_metrics_proto" | 
 |  | 
 | 	"github.com/google/blueprint" | 
 | 	"github.com/google/blueprint/proptools" | 
 | ) | 
 |  | 
 | var ( | 
 | 	DeviceSharedLibrary = "shared_library" | 
 | 	DeviceStaticLibrary = "static_library" | 
 | ) | 
 |  | 
 | // BuildParameters describes the set of potential parameters to build a Ninja rule. | 
 | // In general, these correspond to a Ninja concept. | 
 | type BuildParams struct { | 
 | 	// A Ninja Rule that will be written to the Ninja file. This allows factoring out common code | 
 | 	// among multiple modules to reduce repetition in the Ninja file of action requirements. A rule | 
 | 	// can contain variables that should be provided in Args. | 
 | 	Rule blueprint.Rule | 
 | 	// Deps represents the depfile format. When using RuleBuilder, this defaults to GCC when depfiles | 
 | 	// are used. | 
 | 	Deps blueprint.Deps | 
 | 	// Depfile is a writeable path that allows correct incremental builds when the inputs have not | 
 | 	// been fully specified by the Ninja rule. Ninja supports a subset of the Makefile depfile syntax. | 
 | 	Depfile WritablePath | 
 | 	// A description of the build action. | 
 | 	Description string | 
 | 	// Output is an output file of the action. When using this field, references to $out in the Ninja | 
 | 	// command will refer to this file. | 
 | 	Output WritablePath | 
 | 	// Outputs is a slice of output file of the action. When using this field, references to $out in | 
 | 	// the Ninja command will refer to these files. | 
 | 	Outputs WritablePaths | 
 | 	// SymlinkOutput is an output file specifically that is a symlink. | 
 | 	SymlinkOutput WritablePath | 
 | 	// SymlinkOutputs is a slice of output files specifically that is a symlink. | 
 | 	SymlinkOutputs WritablePaths | 
 | 	// ImplicitOutput is an output file generated by the action. Note: references to `$out` in the | 
 | 	// Ninja command will NOT include references to this file. | 
 | 	ImplicitOutput WritablePath | 
 | 	// ImplicitOutputs is a slice of output files generated by the action. Note: references to `$out` | 
 | 	// in the Ninja command will NOT include references to these files. | 
 | 	ImplicitOutputs WritablePaths | 
 | 	// Input is an input file to the Ninja action. When using this field, references to $in in the | 
 | 	// Ninja command will refer to this file. | 
 | 	Input Path | 
 | 	// Inputs is a slice of input files to the Ninja action. When using this field, references to $in | 
 | 	// in the Ninja command will refer to these files. | 
 | 	Inputs Paths | 
 | 	// Implicit is an input file to the Ninja action. Note: references to `$in` in the Ninja command | 
 | 	// will NOT include references to this file. | 
 | 	Implicit Path | 
 | 	// Implicits is a slice of input files to the Ninja action. Note: references to `$in` in the Ninja | 
 | 	// command will NOT include references to these files. | 
 | 	Implicits Paths | 
 | 	// OrderOnly are Ninja order-only inputs to the action. When these are out of date, the output is | 
 | 	// not rebuilt until they are built, but changes in order-only dependencies alone do not cause the | 
 | 	// output to be rebuilt. | 
 | 	OrderOnly Paths | 
 | 	// Validation is an output path for a validation action. Validation outputs imply lower | 
 | 	// non-blocking priority to building non-validation outputs. | 
 | 	Validation Path | 
 | 	// Validations is a slice of output path for a validation action. Validation outputs imply lower | 
 | 	// non-blocking priority to building non-validation outputs. | 
 | 	Validations Paths | 
 | 	// Whether to skip outputting a default target statement which will be built by Ninja when no | 
 | 	// targets are specified on Ninja's command line. | 
 | 	Default bool | 
 | 	// Args is a key value mapping for replacements of variables within the Rule | 
 | 	Args map[string]string | 
 | } | 
 |  | 
 | type ModuleBuildParams BuildParams | 
 |  | 
 | // EarlyModuleContext provides methods that can be called early, as soon as the properties have | 
 | // been parsed into the module and before any mutators have run. | 
 | type EarlyModuleContext interface { | 
 | 	// Module returns the current module as a Module.  It should rarely be necessary, as the module already has a | 
 | 	// reference to itself. | 
 | 	Module() Module | 
 |  | 
 | 	// ModuleName returns the name of the module.  This is generally the value that was returned by Module.Name() when | 
 | 	// the module was created, but may have been modified by calls to BaseMutatorContext.Rename. | 
 | 	ModuleName() string | 
 |  | 
 | 	// ModuleDir returns the path to the directory that contains the definition of the module. | 
 | 	ModuleDir() string | 
 |  | 
 | 	// ModuleType returns the name of the module type that was used to create the module, as specified in | 
 | 	// RegisterModuleType. | 
 | 	ModuleType() string | 
 |  | 
 | 	// BlueprintFile returns the name of the blueprint file that contains the definition of this | 
 | 	// module. | 
 | 	BlueprintsFile() string | 
 |  | 
 | 	// ContainsProperty returns true if the specified property name was set in the module definition. | 
 | 	ContainsProperty(name string) bool | 
 |  | 
 | 	// Errorf reports an error at the specified position of the module definition file. | 
 | 	Errorf(pos scanner.Position, fmt string, args ...interface{}) | 
 |  | 
 | 	// ModuleErrorf reports an error at the line number of the module type in the module definition. | 
 | 	ModuleErrorf(fmt string, args ...interface{}) | 
 |  | 
 | 	// PropertyErrorf reports an error at the line number of a property in the module definition. | 
 | 	PropertyErrorf(property, fmt string, args ...interface{}) | 
 |  | 
 | 	// Failed returns true if any errors have been reported.  In most cases the module can continue with generating | 
 | 	// build rules after an error, allowing it to report additional errors in a single run, but in cases where the error | 
 | 	// has prevented the module from creating necessary data it can return early when Failed returns true. | 
 | 	Failed() bool | 
 |  | 
 | 	// AddNinjaFileDeps adds dependencies on the specified files to the rule that creates the ninja manifest.  The | 
 | 	// primary builder will be rerun whenever the specified files are modified. | 
 | 	AddNinjaFileDeps(deps ...string) | 
 |  | 
 | 	DeviceSpecific() bool | 
 | 	SocSpecific() bool | 
 | 	ProductSpecific() bool | 
 | 	SystemExtSpecific() bool | 
 | 	Platform() bool | 
 |  | 
 | 	Config() Config | 
 | 	DeviceConfig() DeviceConfig | 
 |  | 
 | 	// Deprecated: use Config() | 
 | 	AConfig() Config | 
 |  | 
 | 	// GlobWithDeps returns a list of files that match the specified pattern but do not match any | 
 | 	// of the patterns in excludes.  It also adds efficient dependencies to rerun the primary | 
 | 	// builder whenever a file matching the pattern as added or removed, without rerunning if a | 
 | 	// file that does not match the pattern is added to a searched directory. | 
 | 	GlobWithDeps(pattern string, excludes []string) ([]string, error) | 
 |  | 
 | 	Glob(globPattern string, excludes []string) Paths | 
 | 	GlobFiles(globPattern string, excludes []string) Paths | 
 | 	IsSymlink(path Path) bool | 
 | 	Readlink(path Path) string | 
 |  | 
 | 	// Namespace returns the Namespace object provided by the NameInterface set by Context.SetNameInterface, or the | 
 | 	// default SimpleNameInterface if Context.SetNameInterface was not called. | 
 | 	Namespace() *Namespace | 
 | } | 
 |  | 
 | // BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns | 
 | // a Config instead of an interface{}, and some methods have been wrapped to use an android.Module | 
 | // instead of a blueprint.Module, plus some extra methods that return Android-specific information | 
 | // about the current module. | 
 | type BaseModuleContext interface { | 
 | 	EarlyModuleContext | 
 |  | 
 | 	blueprintBaseModuleContext() blueprint.BaseModuleContext | 
 |  | 
 | 	// OtherModuleName returns the name of another Module.  See BaseModuleContext.ModuleName for more information. | 
 | 	// It is intended for use inside the visit functions of Visit* and WalkDeps. | 
 | 	OtherModuleName(m blueprint.Module) string | 
 |  | 
 | 	// OtherModuleDir returns the directory of another Module.  See BaseModuleContext.ModuleDir for more information. | 
 | 	// It is intended for use inside the visit functions of Visit* and WalkDeps. | 
 | 	OtherModuleDir(m blueprint.Module) string | 
 |  | 
 | 	// OtherModuleErrorf reports an error on another Module.  See BaseModuleContext.ModuleErrorf for more information. | 
 | 	// It is intended for use inside the visit functions of Visit* and WalkDeps. | 
 | 	OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) | 
 |  | 
 | 	// OtherModuleDependencyTag returns the dependency tag used to depend on a module, or nil if there is no dependency | 
 | 	// on the module.  When called inside a Visit* method with current module being visited, and there are multiple | 
 | 	// dependencies on the module being visited, it returns the dependency tag used for the current dependency. | 
 | 	OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag | 
 |  | 
 | 	// OtherModuleExists returns true if a module with the specified name exists, as determined by the NameInterface | 
 | 	// passed to Context.SetNameInterface, or SimpleNameInterface if it was not called. | 
 | 	OtherModuleExists(name string) bool | 
 |  | 
 | 	// OtherModuleDependencyVariantExists returns true if a module with the | 
 | 	// specified name and variant exists. The variant must match the given | 
 | 	// variations. It must also match all the non-local variations of the current | 
 | 	// module. In other words, it checks for the module that AddVariationDependencies | 
 | 	// would add a dependency on with the same arguments. | 
 | 	OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool | 
 |  | 
 | 	// OtherModuleFarDependencyVariantExists returns true if a module with the | 
 | 	// specified name and variant exists. The variant must match the given | 
 | 	// variations, but not the non-local variations of the current module. In | 
 | 	// other words, it checks for the module that AddFarVariationDependencies | 
 | 	// would add a dependency on with the same arguments. | 
 | 	OtherModuleFarDependencyVariantExists(variations []blueprint.Variation, name string) bool | 
 |  | 
 | 	// OtherModuleReverseDependencyVariantExists returns true if a module with the | 
 | 	// specified name exists with the same variations as the current module. In | 
 | 	// other words, it checks for the module that AddReverseDependency would add a | 
 | 	// dependency on with the same argument. | 
 | 	OtherModuleReverseDependencyVariantExists(name string) bool | 
 |  | 
 | 	// OtherModuleType returns the type of another Module.  See BaseModuleContext.ModuleType for more information. | 
 | 	// It is intended for use inside the visit functions of Visit* and WalkDeps. | 
 | 	OtherModuleType(m blueprint.Module) string | 
 |  | 
 | 	// OtherModuleProvider returns the value for a provider for the given module.  If the value is | 
 | 	// not set it returns the zero value of the type of the provider, so the return value can always | 
 | 	// be type asserted to the type of the provider.  The value returned may be a deep copy of the | 
 | 	// value originally passed to SetProvider. | 
 | 	OtherModuleProvider(m blueprint.Module, provider blueprint.ProviderKey) interface{} | 
 |  | 
 | 	// OtherModuleHasProvider returns true if the provider for the given module has been set. | 
 | 	OtherModuleHasProvider(m blueprint.Module, provider blueprint.ProviderKey) bool | 
 |  | 
 | 	// Provider returns the value for a provider for the current module.  If the value is | 
 | 	// not set it returns the zero value of the type of the provider, so the return value can always | 
 | 	// be type asserted to the type of the provider.  It panics if called before the appropriate | 
 | 	// mutator or GenerateBuildActions pass for the provider.  The value returned may be a deep | 
 | 	// copy of the value originally passed to SetProvider. | 
 | 	Provider(provider blueprint.ProviderKey) interface{} | 
 |  | 
 | 	// HasProvider returns true if the provider for the current module has been set. | 
 | 	HasProvider(provider blueprint.ProviderKey) bool | 
 |  | 
 | 	// SetProvider sets the value for a provider for the current module.  It panics if not called | 
 | 	// during the appropriate mutator or GenerateBuildActions pass for the provider, if the value | 
 | 	// is not of the appropriate type, or if the value has already been set.  The value should not | 
 | 	// be modified after being passed to SetProvider. | 
 | 	SetProvider(provider blueprint.ProviderKey, value interface{}) | 
 |  | 
 | 	GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module | 
 |  | 
 | 	// GetDirectDepWithTag returns the Module the direct dependency with the specified name, or nil if | 
 | 	// none exists.  It panics if the dependency does not have the specified tag.  It skips any | 
 | 	// dependencies that are not an android.Module. | 
 | 	GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module | 
 |  | 
 | 	// GetDirectDep returns the Module and DependencyTag for the  direct dependency with the specified | 
 | 	// name, or nil if none exists.  If there are multiple dependencies on the same module it returns | 
 | 	// the first DependencyTag. | 
 | 	GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) | 
 |  | 
 | 	ModuleFromName(name string) (blueprint.Module, bool) | 
 |  | 
 | 	// VisitDirectDepsBlueprint calls visit for each direct dependency.  If there are multiple | 
 | 	// direct dependencies on the same module visit will be called multiple times on that module | 
 | 	// and OtherModuleDependencyTag will return a different tag for each. | 
 | 	// | 
 | 	// The Module passed to the visit function should not be retained outside of the visit | 
 | 	// function, it may be invalidated by future mutators. | 
 | 	VisitDirectDepsBlueprint(visit func(blueprint.Module)) | 
 |  | 
 | 	// VisitDirectDeps calls visit for each direct dependency.  If there are multiple | 
 | 	// direct dependencies on the same module visit will be called multiple times on that module | 
 | 	// and OtherModuleDependencyTag will return a different tag for each.  It raises an error if any of the | 
 | 	// dependencies are not an android.Module. | 
 | 	// | 
 | 	// The Module passed to the visit function should not be retained outside of the visit | 
 | 	// function, it may be invalidated by future mutators. | 
 | 	VisitDirectDeps(visit func(Module)) | 
 |  | 
 | 	VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) | 
 |  | 
 | 	// VisitDirectDepsIf calls pred for each direct dependency, and if pred returns true calls visit.  If there are | 
 | 	// multiple direct dependencies on the same module pred and visit will be called multiple times on that module and | 
 | 	// OtherModuleDependencyTag will return a different tag for each.  It skips any | 
 | 	// dependencies that are not an android.Module. | 
 | 	// | 
 | 	// The Module passed to the visit function should not be retained outside of the visit function, it may be | 
 | 	// invalidated by future mutators. | 
 | 	VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) | 
 | 	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module | 
 | 	VisitDepsDepthFirst(visit func(Module)) | 
 | 	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module | 
 | 	VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) | 
 |  | 
 | 	// WalkDeps calls visit for each transitive dependency, traversing the dependency tree in top down order.  visit may | 
 | 	// be called multiple times for the same (child, parent) pair if there are multiple direct dependencies between the | 
 | 	// child and parent with different tags.  OtherModuleDependencyTag will return the tag for the currently visited | 
 | 	// (child, parent) pair.  If visit returns false WalkDeps will not continue recursing down to child.  It skips | 
 | 	// any dependencies that are not an android.Module. | 
 | 	// | 
 | 	// The Modules passed to the visit function should not be retained outside of the visit function, they may be | 
 | 	// invalidated by future mutators. | 
 | 	WalkDeps(visit func(child, parent Module) bool) | 
 |  | 
 | 	// WalkDepsBlueprint calls visit for each transitive dependency, traversing the dependency | 
 | 	// tree in top down order.  visit may be called multiple times for the same (child, parent) | 
 | 	// pair if there are multiple direct dependencies between the child and parent with different | 
 | 	// tags.  OtherModuleDependencyTag will return the tag for the currently visited | 
 | 	// (child, parent) pair.  If visit returns false WalkDeps will not continue recursing down | 
 | 	// to child. | 
 | 	// | 
 | 	// The Modules passed to the visit function should not be retained outside of the visit function, they may be | 
 | 	// invalidated by future mutators. | 
 | 	WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool) | 
 |  | 
 | 	// GetWalkPath is supposed to be called in visit function passed in WalkDeps() | 
 | 	// and returns a top-down dependency path from a start module to current child module. | 
 | 	GetWalkPath() []Module | 
 |  | 
 | 	// PrimaryModule returns the first variant of the current module.  Variants of a module are always visited in | 
 | 	// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from the | 
 | 	// Module returned by PrimaryModule without data races.  This can be used to perform singleton actions that are | 
 | 	// only done once for all variants of a module. | 
 | 	PrimaryModule() Module | 
 |  | 
 | 	// FinalModule returns the last variant of the current module.  Variants of a module are always visited in | 
 | 	// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all | 
 | 	// variants using VisitAllModuleVariants if the current module == FinalModule().  This can be used to perform | 
 | 	// singleton actions that are only done once for all variants of a module. | 
 | 	FinalModule() Module | 
 |  | 
 | 	// VisitAllModuleVariants calls visit for each variant of the current module.  Variants of a module are always | 
 | 	// visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read | 
 | 	// from all variants if the current module == FinalModule().  Otherwise, care must be taken to not access any | 
 | 	// data modified by the current mutator. | 
 | 	VisitAllModuleVariants(visit func(Module)) | 
 |  | 
 | 	// GetTagPath is supposed to be called in visit function passed in WalkDeps() | 
 | 	// and returns a top-down dependency tags path from a start module to current child module. | 
 | 	// It has one less entry than GetWalkPath() as it contains the dependency tags that | 
 | 	// exist between each adjacent pair of modules in the GetWalkPath(). | 
 | 	// GetTagPath()[i] is the tag between GetWalkPath()[i] and GetWalkPath()[i+1] | 
 | 	GetTagPath() []blueprint.DependencyTag | 
 |  | 
 | 	// GetPathString is supposed to be called in visit function passed in WalkDeps() | 
 | 	// and returns a multi-line string showing the modules and dependency tags | 
 | 	// among them along the top-down dependency path from a start module to current child module. | 
 | 	// skipFirst when set to true, the output doesn't include the start module, | 
 | 	// which is already printed when this function is used along with ModuleErrorf(). | 
 | 	GetPathString(skipFirst bool) string | 
 |  | 
 | 	AddMissingDependencies(missingDeps []string) | 
 |  | 
 | 	// getMissingDependencies returns the list of missing dependencies. | 
 | 	// Calling this function prevents adding new dependencies. | 
 | 	getMissingDependencies() []string | 
 |  | 
 | 	// AddUnconvertedBp2buildDep stores module name of a direct dependency that was not converted via bp2build | 
 | 	AddUnconvertedBp2buildDep(dep string) | 
 |  | 
 | 	// AddMissingBp2buildDep stores the module name of a direct dependency that was not found. | 
 | 	AddMissingBp2buildDep(dep string) | 
 |  | 
 | 	Target() Target | 
 | 	TargetPrimary() bool | 
 |  | 
 | 	// The additional arch specific targets (e.g. 32/64 bit) that this module variant is | 
 | 	// responsible for creating. | 
 | 	MultiTargets() []Target | 
 | 	Arch() Arch | 
 | 	Os() OsType | 
 | 	Host() bool | 
 | 	Device() bool | 
 | 	Darwin() bool | 
 | 	Windows() bool | 
 | 	Debug() bool | 
 | 	PrimaryArch() bool | 
 | } | 
 |  | 
 | // Deprecated: use EarlyModuleContext instead | 
 | type BaseContext interface { | 
 | 	EarlyModuleContext | 
 | } | 
 |  | 
 | type ModuleContext interface { | 
 | 	BaseModuleContext | 
 |  | 
 | 	blueprintModuleContext() blueprint.ModuleContext | 
 |  | 
 | 	// Deprecated: use ModuleContext.Build instead. | 
 | 	ModuleBuild(pctx PackageContext, params ModuleBuildParams) | 
 |  | 
 | 	// Returns a list of paths expanded from globs and modules referenced using ":module" syntax.  The property must | 
 | 	// be tagged with `android:"path" to support automatic source module dependency resolution. | 
 | 	// | 
 | 	// Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead. | 
 | 	ExpandSources(srcFiles, excludes []string) Paths | 
 |  | 
 | 	// Returns a single path expanded from globs and modules referenced using ":module" syntax.  The property must | 
 | 	// be tagged with `android:"path" to support automatic source module dependency resolution. | 
 | 	// | 
 | 	// Deprecated: use PathForModuleSrc instead. | 
 | 	ExpandSource(srcFile, prop string) Path | 
 |  | 
 | 	ExpandOptionalSource(srcFile *string, prop string) OptionalPath | 
 |  | 
 | 	// InstallExecutable creates a rule to copy srcPath to name in the installPath directory, | 
 | 	// with the given additional dependencies.  The file is marked executable after copying. | 
 | 	// | 
 | 	// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the | 
 | 	// installed file will be returned by PackagingSpecs() on this module or by | 
 | 	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags | 
 | 	// for which IsInstallDepNeeded returns true. | 
 | 	InstallExecutable(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath | 
 |  | 
 | 	// InstallFile creates a rule to copy srcPath to name in the installPath directory, | 
 | 	// with the given additional dependencies. | 
 | 	// | 
 | 	// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the | 
 | 	// installed file will be returned by PackagingSpecs() on this module or by | 
 | 	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags | 
 | 	// for which IsInstallDepNeeded returns true. | 
 | 	InstallFile(installPath InstallPath, name string, srcPath Path, deps ...Path) InstallPath | 
 |  | 
 | 	// InstallFileWithExtraFilesZip creates a rule to copy srcPath to name in the installPath | 
 | 	// directory, and also unzip a zip file containing extra files to install into the same | 
 | 	// directory. | 
 | 	// | 
 | 	// The installed file will be returned by FilesToInstall(), and the PackagingSpec for the | 
 | 	// installed file will be returned by PackagingSpecs() on this module or by | 
 | 	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags | 
 | 	// for which IsInstallDepNeeded returns true. | 
 | 	InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path, extraZip Path, deps ...Path) InstallPath | 
 |  | 
 | 	// InstallSymlink creates a rule to create a symlink from src srcPath to name in the installPath | 
 | 	// directory. | 
 | 	// | 
 | 	// The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the | 
 | 	// installed file will be returned by PackagingSpecs() on this module or by | 
 | 	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags | 
 | 	// for which IsInstallDepNeeded returns true. | 
 | 	InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath | 
 |  | 
 | 	// InstallAbsoluteSymlink creates a rule to create an absolute symlink from src srcPath to name | 
 | 	// in the installPath directory. | 
 | 	// | 
 | 	// The installed symlink will be returned by FilesToInstall(), and the PackagingSpec for the | 
 | 	// installed file will be returned by PackagingSpecs() on this module or by | 
 | 	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags | 
 | 	// for which IsInstallDepNeeded returns true. | 
 | 	InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath | 
 |  | 
 | 	// PackageFile creates a PackagingSpec as if InstallFile was called, but without creating | 
 | 	// the rule to copy the file.  This is useful to define how a module would be packaged | 
 | 	// without installing it into the global installation directories. | 
 | 	// | 
 | 	// The created PackagingSpec for the will be returned by PackagingSpecs() on this module or by | 
 | 	// TransitivePackagingSpecs() on modules that depend on this module through dependency tags | 
 | 	// for which IsInstallDepNeeded returns true. | 
 | 	PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec | 
 |  | 
 | 	CheckbuildFile(srcPath Path) | 
 |  | 
 | 	InstallInData() bool | 
 | 	InstallInTestcases() bool | 
 | 	InstallInSanitizerDir() bool | 
 | 	InstallInRamdisk() bool | 
 | 	InstallInVendorRamdisk() bool | 
 | 	InstallInDebugRamdisk() bool | 
 | 	InstallInRecovery() bool | 
 | 	InstallInRoot() bool | 
 | 	InstallInVendor() bool | 
 | 	InstallForceOS() (*OsType, *ArchType) | 
 |  | 
 | 	RequiredModuleNames() []string | 
 | 	HostRequiredModuleNames() []string | 
 | 	TargetRequiredModuleNames() []string | 
 |  | 
 | 	ModuleSubDir() string | 
 | 	SoongConfigTraceHash() string | 
 |  | 
 | 	Variable(pctx PackageContext, name, value string) | 
 | 	Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule | 
 | 	// Similar to blueprint.ModuleContext.Build, but takes Paths instead of []string, | 
 | 	// and performs more verification. | 
 | 	Build(pctx PackageContext, params BuildParams) | 
 | 	// Phony creates a Make-style phony rule, a rule with no commands that can depend on other | 
 | 	// phony rules or real files.  Phony can be called on the same name multiple times to add | 
 | 	// additional dependencies. | 
 | 	Phony(phony string, deps ...Path) | 
 |  | 
 | 	// GetMissingDependencies returns the list of dependencies that were passed to AddDependencies or related methods, | 
 | 	// but do not exist. | 
 | 	GetMissingDependencies() []string | 
 |  | 
 | 	// LicenseMetadataFile returns the path where the license metadata for this module will be | 
 | 	// generated. | 
 | 	LicenseMetadataFile() Path | 
 | } | 
 |  | 
 | type Module interface { | 
 | 	blueprint.Module | 
 |  | 
 | 	// GenerateAndroidBuildActions is analogous to Blueprints' GenerateBuildActions, | 
 | 	// but GenerateAndroidBuildActions also has access to Android-specific information. | 
 | 	// For more information, see Module.GenerateBuildActions within Blueprint's module_ctx.go | 
 | 	GenerateAndroidBuildActions(ModuleContext) | 
 |  | 
 | 	// Add dependencies to the components of a module, i.e. modules that are created | 
 | 	// by the module and which are considered to be part of the creating module. | 
 | 	// | 
 | 	// This is called before prebuilts are renamed so as to allow a dependency to be | 
 | 	// added directly to a prebuilt child module instead of depending on a source module | 
 | 	// and relying on prebuilt processing to switch to the prebuilt module if preferred. | 
 | 	// | 
 | 	// A dependency on a prebuilt must include the "prebuilt_" prefix. | 
 | 	ComponentDepsMutator(ctx BottomUpMutatorContext) | 
 |  | 
 | 	DepsMutator(BottomUpMutatorContext) | 
 |  | 
 | 	base() *ModuleBase | 
 | 	Disable() | 
 | 	Enabled() bool | 
 | 	Target() Target | 
 | 	MultiTargets() []Target | 
 |  | 
 | 	// ImageVariation returns the image variation of this module. | 
 | 	// | 
 | 	// The returned structure has its Mutator field set to "image" and its Variation field set to the | 
 | 	// image variation, e.g. recovery, ramdisk, etc.. The Variation field is "" for host modules and | 
 | 	// device modules that have no image variation. | 
 | 	ImageVariation() blueprint.Variation | 
 |  | 
 | 	Owner() string | 
 | 	InstallInData() bool | 
 | 	InstallInTestcases() bool | 
 | 	InstallInSanitizerDir() bool | 
 | 	InstallInRamdisk() bool | 
 | 	InstallInVendorRamdisk() bool | 
 | 	InstallInDebugRamdisk() bool | 
 | 	InstallInRecovery() bool | 
 | 	InstallInRoot() bool | 
 | 	InstallInVendor() bool | 
 | 	InstallForceOS() (*OsType, *ArchType) | 
 | 	PartitionTag(DeviceConfig) string | 
 | 	HideFromMake() | 
 | 	IsHideFromMake() bool | 
 | 	IsSkipInstall() bool | 
 | 	MakeUninstallable() | 
 | 	ReplacedByPrebuilt() | 
 | 	IsReplacedByPrebuilt() bool | 
 | 	ExportedToMake() bool | 
 | 	InitRc() Paths | 
 | 	VintfFragments() Paths | 
 | 	EffectiveLicenseKinds() []string | 
 | 	EffectiveLicenseFiles() Paths | 
 |  | 
 | 	AddProperties(props ...interface{}) | 
 | 	GetProperties() []interface{} | 
 |  | 
 | 	// If this module should not have bazel BUILD definitions generated by bp2build, | 
 | 	// GetUnconvertedReason returns a reason this is the case. | 
 | 	GetUnconvertedReason() *UnconvertedReason | 
 |  | 
 | 	// Bp2buildTargets returns the target(s) generated for Bazel via bp2build for this module | 
 | 	Bp2buildTargets() []bp2buildInfo | 
 | 	GetUnconvertedBp2buildDeps() []string | 
 | 	GetMissingBp2buildDeps() []string | 
 |  | 
 | 	BuildParamsForTests() []BuildParams | 
 | 	RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams | 
 | 	VariablesForTests() map[string]string | 
 |  | 
 | 	// String returns a string that includes the module name and variants for printing during debugging. | 
 | 	String() string | 
 |  | 
 | 	// Get the qualified module id for this module. | 
 | 	qualifiedModuleId(ctx BaseModuleContext) qualifiedModuleName | 
 |  | 
 | 	// Get information about the properties that can contain visibility rules. | 
 | 	visibilityProperties() []visibilityProperty | 
 |  | 
 | 	RequiredModuleNames() []string | 
 | 	HostRequiredModuleNames() []string | 
 | 	TargetRequiredModuleNames() []string | 
 |  | 
 | 	FilesToInstall() InstallPaths | 
 | 	PackagingSpecs() []PackagingSpec | 
 |  | 
 | 	// TransitivePackagingSpecs returns the PackagingSpecs for this module and any transitive | 
 | 	// dependencies with dependency tags for which IsInstallDepNeeded() returns true. | 
 | 	TransitivePackagingSpecs() []PackagingSpec | 
 | } | 
 |  | 
 | // Qualified id for a module | 
 | type qualifiedModuleName struct { | 
 | 	// The package (i.e. directory) in which the module is defined, without trailing / | 
 | 	pkg string | 
 |  | 
 | 	// The name of the module, empty string if package. | 
 | 	name string | 
 | } | 
 |  | 
 | func (q qualifiedModuleName) String() string { | 
 | 	if q.name == "" { | 
 | 		return "//" + q.pkg | 
 | 	} | 
 | 	return "//" + q.pkg + ":" + q.name | 
 | } | 
 |  | 
 | func (q qualifiedModuleName) isRootPackage() bool { | 
 | 	return q.pkg == "" && q.name == "" | 
 | } | 
 |  | 
 | // Get the id for the package containing this module. | 
 | func (q qualifiedModuleName) getContainingPackageId() qualifiedModuleName { | 
 | 	pkg := q.pkg | 
 | 	if q.name == "" { | 
 | 		if pkg == "" { | 
 | 			panic(fmt.Errorf("Cannot get containing package id of root package")) | 
 | 		} | 
 |  | 
 | 		index := strings.LastIndex(pkg, "/") | 
 | 		if index == -1 { | 
 | 			pkg = "" | 
 | 		} else { | 
 | 			pkg = pkg[:index] | 
 | 		} | 
 | 	} | 
 | 	return newPackageId(pkg) | 
 | } | 
 |  | 
 | func newPackageId(pkg string) qualifiedModuleName { | 
 | 	// A qualified id for a package module has no name. | 
 | 	return qualifiedModuleName{pkg: pkg, name: ""} | 
 | } | 
 |  | 
 | type Dist struct { | 
 | 	// Copy the output of this module to the $DIST_DIR when `dist` is specified on the | 
 | 	// command line and any of these targets are also on the command line, or otherwise | 
 | 	// built | 
 | 	Targets []string `android:"arch_variant"` | 
 |  | 
 | 	// The name of the output artifact. This defaults to the basename of the output of | 
 | 	// the module. | 
 | 	Dest *string `android:"arch_variant"` | 
 |  | 
 | 	// The directory within the dist directory to store the artifact. Defaults to the | 
 | 	// top level directory (""). | 
 | 	Dir *string `android:"arch_variant"` | 
 |  | 
 | 	// A suffix to add to the artifact file name (before any extension). | 
 | 	Suffix *string `android:"arch_variant"` | 
 |  | 
 | 	// If true, then the artifact file will be appended with _<product name>. For | 
 | 	// example, if the product is coral and the module is an android_app module | 
 | 	// of name foo, then the artifact would be foo_coral.apk. If false, there is | 
 | 	// no change to the artifact file name. | 
 | 	Append_artifact_with_product *bool `android:"arch_variant"` | 
 |  | 
 | 	// A string tag to select the OutputFiles associated with the tag. | 
 | 	// | 
 | 	// If no tag is specified then it will select the default dist paths provided | 
 | 	// by the module type. If a tag of "" is specified then it will return the | 
 | 	// default output files provided by the modules, i.e. the result of calling | 
 | 	// OutputFiles(""). | 
 | 	Tag *string `android:"arch_variant"` | 
 | } | 
 |  | 
 | // NamedPath associates a path with a name. e.g. a license text path with a package name | 
 | type NamedPath struct { | 
 | 	Path Path | 
 | 	Name string | 
 | } | 
 |  | 
 | // String returns an escaped string representing the `NamedPath`. | 
 | func (p NamedPath) String() string { | 
 | 	if len(p.Name) > 0 { | 
 | 		return p.Path.String() + ":" + url.QueryEscape(p.Name) | 
 | 	} | 
 | 	return p.Path.String() | 
 | } | 
 |  | 
 | // NamedPaths describes a list of paths each associated with a name. | 
 | type NamedPaths []NamedPath | 
 |  | 
 | // Strings returns a list of escaped strings representing each `NamedPath` in the list. | 
 | func (l NamedPaths) Strings() []string { | 
 | 	result := make([]string, 0, len(l)) | 
 | 	for _, p := range l { | 
 | 		result = append(result, p.String()) | 
 | 	} | 
 | 	return result | 
 | } | 
 |  | 
 | // SortedUniqueNamedPaths modifies `l` in place to return the sorted unique subset. | 
 | func SortedUniqueNamedPaths(l NamedPaths) NamedPaths { | 
 | 	if len(l) == 0 { | 
 | 		return l | 
 | 	} | 
 | 	sort.Slice(l, func(i, j int) bool { | 
 | 		return l[i].String() < l[j].String() | 
 | 	}) | 
 | 	k := 0 | 
 | 	for i := 1; i < len(l); i++ { | 
 | 		if l[i].String() == l[k].String() { | 
 | 			continue | 
 | 		} | 
 | 		k++ | 
 | 		if k < i { | 
 | 			l[k] = l[i] | 
 | 		} | 
 | 	} | 
 | 	return l[:k+1] | 
 | } | 
 |  | 
 | // soongConfigTrace holds all references to VendorVars. Uses []string for blueprint:"mutated" | 
 | type soongConfigTrace struct { | 
 | 	Bools   []string `json:",omitempty"` | 
 | 	Strings []string `json:",omitempty"` | 
 | 	IsSets  []string `json:",omitempty"` | 
 | } | 
 |  | 
 | func (c *soongConfigTrace) isEmpty() bool { | 
 | 	return len(c.Bools) == 0 && len(c.Strings) == 0 && len(c.IsSets) == 0 | 
 | } | 
 |  | 
 | // Returns hash of serialized trace records (empty string if there's no trace recorded) | 
 | func (c *soongConfigTrace) hash() string { | 
 | 	// Use MD5 for speed. We don't care collision or preimage attack | 
 | 	if c.isEmpty() { | 
 | 		return "" | 
 | 	} | 
 | 	j, err := json.Marshal(c) | 
 | 	if err != nil { | 
 | 		panic(fmt.Errorf("json marshal of %#v failed: %#v", *c, err)) | 
 | 	} | 
 | 	hash := md5.Sum(j) | 
 | 	return hex.EncodeToString(hash[:]) | 
 | } | 
 |  | 
 | type nameProperties struct { | 
 | 	// The name of the module.  Must be unique across all modules. | 
 | 	Name *string | 
 | } | 
 |  | 
 | type commonProperties struct { | 
 | 	// emit build rules for this module | 
 | 	// | 
 | 	// Disabling a module should only be done for those modules that cannot be built | 
 | 	// in the current environment. Modules that can build in the current environment | 
 | 	// but are not usually required (e.g. superceded by a prebuilt) should not be | 
 | 	// disabled as that will prevent them from being built by the checkbuild target | 
 | 	// and so prevent early detection of changes that have broken those modules. | 
 | 	Enabled *bool `android:"arch_variant"` | 
 |  | 
 | 	// Controls the visibility of this module to other modules. Allowable values are one or more of | 
 | 	// these formats: | 
 | 	// | 
 | 	//  ["//visibility:public"]: Anyone can use this module. | 
 | 	//  ["//visibility:private"]: Only rules in the module's package (not its subpackages) can use | 
 | 	//      this module. | 
 | 	//  ["//visibility:override"]: Discards any rules inherited from defaults or a creating module. | 
 | 	//      Can only be used at the beginning of a list of visibility rules. | 
 | 	//  ["//some/package:__pkg__", "//other/package:__pkg__"]: Only modules in some/package and | 
 | 	//      other/package (defined in some/package/*.bp and other/package/*.bp) have access to | 
 | 	//      this module. Note that sub-packages do not have access to the rule; for example, | 
 | 	//      //some/package/foo:bar or //other/package/testing:bla wouldn't have access. __pkg__ | 
 | 	//      is a special module and must be used verbatim. It represents all of the modules in the | 
 | 	//      package. | 
 | 	//  ["//project:__subpackages__", "//other:__subpackages__"]: Only modules in packages project | 
 | 	//      or other or in one of their sub-packages have access to this module. For example, | 
 | 	//      //project:rule, //project/library:lib or //other/testing/internal:munge are allowed | 
 | 	//      to depend on this rule (but not //independent:evil) | 
 | 	//  ["//project"]: This is shorthand for ["//project:__pkg__"] | 
 | 	//  [":__subpackages__"]: This is shorthand for ["//project:__subpackages__"] where | 
 | 	//      //project is the module's package. e.g. using [":__subpackages__"] in | 
 | 	//      packages/apps/Settings/Android.bp is equivalent to | 
 | 	//      //packages/apps/Settings:__subpackages__. | 
 | 	//  ["//visibility:legacy_public"]: The default visibility, behaves as //visibility:public | 
 | 	//      for now. It is an error if it is used in a module. | 
 | 	// | 
 | 	// If a module does not specify the `visibility` property then it uses the | 
 | 	// `default_visibility` property of the `package` module in the module's package. | 
 | 	// | 
 | 	// If the `default_visibility` property is not set for the module's package then | 
 | 	// it will use the `default_visibility` of its closest ancestor package for which | 
 | 	// a `default_visibility` property is specified. | 
 | 	// | 
 | 	// If no `default_visibility` property can be found then the module uses the | 
 | 	// global default of `//visibility:legacy_public`. | 
 | 	// | 
 | 	// The `visibility` property has no effect on a defaults module although it does | 
 | 	// apply to any non-defaults module that uses it. To set the visibility of a | 
 | 	// defaults module, use the `defaults_visibility` property on the defaults module; | 
 | 	// not to be confused with the `default_visibility` property on the package module. | 
 | 	// | 
 | 	// See https://android.googlesource.com/platform/build/soong/+/master/README.md#visibility for | 
 | 	// more details. | 
 | 	Visibility []string | 
 |  | 
 | 	// Describes the licenses applicable to this module. Must reference license modules. | 
 | 	Licenses []string | 
 |  | 
 | 	// Flattened from direct license dependencies. Equal to Licenses unless particular module adds more. | 
 | 	Effective_licenses []string `blueprint:"mutated"` | 
 | 	// Override of module name when reporting licenses | 
 | 	Effective_package_name *string `blueprint:"mutated"` | 
 | 	// Notice files | 
 | 	Effective_license_text NamedPaths `blueprint:"mutated"` | 
 | 	// License names | 
 | 	Effective_license_kinds []string `blueprint:"mutated"` | 
 | 	// License conditions | 
 | 	Effective_license_conditions []string `blueprint:"mutated"` | 
 |  | 
 | 	// control whether this module compiles for 32-bit, 64-bit, or both.  Possible values | 
 | 	// are "32" (compile for 32-bit only), "64" (compile for 64-bit only), "both" (compile for both | 
 | 	// architectures), or "first" (compile for 64-bit on a 64-bit platform, and 32-bit on a 32-bit | 
 | 	// platform). | 
 | 	Compile_multilib *string `android:"arch_variant"` | 
 |  | 
 | 	Target struct { | 
 | 		Host struct { | 
 | 			Compile_multilib *string | 
 | 		} | 
 | 		Android struct { | 
 | 			Compile_multilib *string | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// If set to true then the archMutator will create variants for each arch specific target | 
 | 	// (e.g. 32/64) that the module is required to produce. If set to false then it will only | 
 | 	// create a variant for the architecture and will list the additional arch specific targets | 
 | 	// that the variant needs to produce in the CompileMultiTargets property. | 
 | 	UseTargetVariants bool   `blueprint:"mutated"` | 
 | 	Default_multilib  string `blueprint:"mutated"` | 
 |  | 
 | 	// whether this is a proprietary vendor module, and should be installed into /vendor | 
 | 	Proprietary *bool | 
 |  | 
 | 	// vendor who owns this module | 
 | 	Owner *string | 
 |  | 
 | 	// whether this module is specific to an SoC (System-On-a-Chip). When set to true, | 
 | 	// it is installed into /vendor (or /system/vendor if vendor partition does not exist). | 
 | 	// Use `soc_specific` instead for better meaning. | 
 | 	Vendor *bool | 
 |  | 
 | 	// whether this module is specific to an SoC (System-On-a-Chip). When set to true, | 
 | 	// it is installed into /vendor (or /system/vendor if vendor partition does not exist). | 
 | 	Soc_specific *bool | 
 |  | 
 | 	// whether this module is specific to a device, not only for SoC, but also for off-chip | 
 | 	// peripherals. When set to true, it is installed into /odm (or /vendor/odm if odm partition | 
 | 	// does not exist, or /system/vendor/odm if both odm and vendor partitions do not exist). | 
 | 	// This implies `soc_specific:true`. | 
 | 	Device_specific *bool | 
 |  | 
 | 	// whether this module is specific to a software configuration of a product (e.g. country, | 
 | 	// network operator, etc). When set to true, it is installed into /product (or | 
 | 	// /system/product if product partition does not exist). | 
 | 	Product_specific *bool | 
 |  | 
 | 	// whether this module extends system. When set to true, it is installed into /system_ext | 
 | 	// (or /system/system_ext if system_ext partition does not exist). | 
 | 	System_ext_specific *bool | 
 |  | 
 | 	// Whether this module is installed to recovery partition | 
 | 	Recovery *bool | 
 |  | 
 | 	// Whether this module is installed to ramdisk | 
 | 	Ramdisk *bool | 
 |  | 
 | 	// Whether this module is installed to vendor ramdisk | 
 | 	Vendor_ramdisk *bool | 
 |  | 
 | 	// Whether this module is installed to debug ramdisk | 
 | 	Debug_ramdisk *bool | 
 |  | 
 | 	// Whether this module is built for non-native architectures (also known as native bridge binary) | 
 | 	Native_bridge_supported *bool `android:"arch_variant"` | 
 |  | 
 | 	// init.rc files to be installed if this module is installed | 
 | 	Init_rc []string `android:"arch_variant,path"` | 
 |  | 
 | 	// VINTF manifest fragments to be installed if this module is installed | 
 | 	Vintf_fragments []string `android:"path"` | 
 |  | 
 | 	// names of other modules to install if this module is installed | 
 | 	Required []string `android:"arch_variant"` | 
 |  | 
 | 	// names of other modules to install on host if this module is installed | 
 | 	Host_required []string `android:"arch_variant"` | 
 |  | 
 | 	// names of other modules to install on target if this module is installed | 
 | 	Target_required []string `android:"arch_variant"` | 
 |  | 
 | 	// The OsType of artifacts that this module variant is responsible for creating. | 
 | 	// | 
 | 	// Set by osMutator | 
 | 	CompileOS OsType `blueprint:"mutated"` | 
 |  | 
 | 	// The Target of artifacts that this module variant is responsible for creating. | 
 | 	// | 
 | 	// Set by archMutator | 
 | 	CompileTarget Target `blueprint:"mutated"` | 
 |  | 
 | 	// The additional arch specific targets (e.g. 32/64 bit) that this module variant is | 
 | 	// responsible for creating. | 
 | 	// | 
 | 	// By default this is nil as, where necessary, separate variants are created for the | 
 | 	// different multilib types supported and that information is encapsulated in the | 
 | 	// CompileTarget so the module variant simply needs to create artifacts for that. | 
 | 	// | 
 | 	// However, if UseTargetVariants is set to false (e.g. by | 
 | 	// InitAndroidMultiTargetsArchModule)  then no separate variants are created for the | 
 | 	// multilib targets. Instead a single variant is created for the architecture and | 
 | 	// this contains the multilib specific targets that this variant should create. | 
 | 	// | 
 | 	// Set by archMutator | 
 | 	CompileMultiTargets []Target `blueprint:"mutated"` | 
 |  | 
 | 	// True if the module variant's CompileTarget is the primary target | 
 | 	// | 
 | 	// Set by archMutator | 
 | 	CompilePrimary bool `blueprint:"mutated"` | 
 |  | 
 | 	// Set by InitAndroidModule | 
 | 	HostOrDeviceSupported HostOrDeviceSupported `blueprint:"mutated"` | 
 | 	ArchSpecific          bool                  `blueprint:"mutated"` | 
 |  | 
 | 	// If set to true then a CommonOS variant will be created which will have dependencies | 
 | 	// on all its OsType specific variants. Used by sdk/module_exports to create a snapshot | 
 | 	// that covers all os and architecture variants. | 
 | 	// | 
 | 	// The OsType specific variants can be retrieved by calling | 
 | 	// GetOsSpecificVariantsOfCommonOSVariant | 
 | 	// | 
 | 	// Set at module initialization time by calling InitCommonOSAndroidMultiTargetsArchModule | 
 | 	CreateCommonOSVariant bool `blueprint:"mutated"` | 
 |  | 
 | 	// If set to true then this variant is the CommonOS variant that has dependencies on its | 
 | 	// OsType specific variants. | 
 | 	// | 
 | 	// Set by osMutator. | 
 | 	CommonOSVariant bool `blueprint:"mutated"` | 
 |  | 
 | 	// When HideFromMake is set to true, no entry for this variant will be emitted in the | 
 | 	// generated Android.mk file. | 
 | 	HideFromMake bool `blueprint:"mutated"` | 
 |  | 
 | 	// When SkipInstall is set to true, calls to ctx.InstallFile, ctx.InstallExecutable, | 
 | 	// ctx.InstallSymlink and ctx.InstallAbsoluteSymlink act like calls to ctx.PackageFile | 
 | 	// and don't create a rule to install the file. | 
 | 	SkipInstall bool `blueprint:"mutated"` | 
 |  | 
 | 	// UninstallableApexPlatformVariant is set by MakeUninstallable called by the apex | 
 | 	// mutator.  MakeUninstallable also sets HideFromMake.  UninstallableApexPlatformVariant | 
 | 	// is used to avoid adding install or packaging dependencies into libraries provided | 
 | 	// by apexes. | 
 | 	UninstallableApexPlatformVariant bool `blueprint:"mutated"` | 
 |  | 
 | 	// Whether the module has been replaced by a prebuilt | 
 | 	ReplacedByPrebuilt bool `blueprint:"mutated"` | 
 |  | 
 | 	// Disabled by mutators. If set to true, it overrides Enabled property. | 
 | 	ForcedDisabled bool `blueprint:"mutated"` | 
 |  | 
 | 	NamespaceExportedToMake bool `blueprint:"mutated"` | 
 |  | 
 | 	MissingDeps        []string `blueprint:"mutated"` | 
 | 	CheckedMissingDeps bool     `blueprint:"mutated"` | 
 |  | 
 | 	// Name and variant strings stored by mutators to enable Module.String() | 
 | 	DebugName       string   `blueprint:"mutated"` | 
 | 	DebugMutators   []string `blueprint:"mutated"` | 
 | 	DebugVariations []string `blueprint:"mutated"` | 
 |  | 
 | 	// ImageVariation is set by ImageMutator to specify which image this variation is for, | 
 | 	// for example "" for core or "recovery" for recovery.  It will often be set to one of the | 
 | 	// constants in image.go, but can also be set to a custom value by individual module types. | 
 | 	ImageVariation string `blueprint:"mutated"` | 
 |  | 
 | 	// Bazel conversion status | 
 | 	BazelConversionStatus BazelConversionStatus `blueprint:"mutated"` | 
 |  | 
 | 	// SoongConfigTrace records accesses to VendorVars (soong_config). The trace will be hashed | 
 | 	// and used as a subdir of PathForModuleOut.  Note that we mainly focus on incremental | 
 | 	// builds among similar products (e.g. aosp_cf_x86_64_phone and aosp_cf_x86_64_foldable), | 
 | 	// and there are variables other than soong_config, which isn't captured by soong config | 
 | 	// trace, but influence modules among products. | 
 | 	SoongConfigTrace     soongConfigTrace `blueprint:"mutated"` | 
 | 	SoongConfigTraceHash string           `blueprint:"mutated"` | 
 | } | 
 |  | 
 | // CommonAttributes represents the common Bazel attributes from which properties | 
 | // in `commonProperties` are translated/mapped; such properties are annotated in | 
 | // a list their corresponding attribute. It is embedded within `bp2buildInfo`. | 
 | type CommonAttributes struct { | 
 | 	// Soong nameProperties -> Bazel name | 
 | 	Name string | 
 |  | 
 | 	// Data mapped from: Required | 
 | 	Data bazel.LabelListAttribute | 
 |  | 
 | 	// SkipData is neither a Soong nor Bazel target attribute | 
 | 	// If true, this will not fill the data attribute automatically | 
 | 	// This is useful for Soong modules that have 1:many Bazel targets | 
 | 	// Some of the generated Bazel targets might not have a data attribute | 
 | 	SkipData *bool | 
 |  | 
 | 	Tags bazel.StringListAttribute | 
 |  | 
 | 	Applicable_licenses bazel.LabelListAttribute | 
 |  | 
 | 	Testonly *bool | 
 |  | 
 | 	// Dir is neither a Soong nor Bazel target attribute | 
 | 	// If set, the bazel target will be created in this directory | 
 | 	// If unset, the bazel target will default to be created in the directory of the visited soong module | 
 | 	Dir *string | 
 | } | 
 |  | 
 | // constraintAttributes represents Bazel attributes pertaining to build constraints, | 
 | // which make restrict building a Bazel target for some set of platforms. | 
 | type constraintAttributes struct { | 
 | 	// Constraint values this target can be built for. | 
 | 	Target_compatible_with bazel.LabelListAttribute | 
 | } | 
 |  | 
 | type distProperties struct { | 
 | 	// configuration to distribute output files from this module to the distribution | 
 | 	// directory (default: $OUT/dist, configurable with $DIST_DIR) | 
 | 	Dist Dist `android:"arch_variant"` | 
 |  | 
 | 	// a list of configurations to distribute output files from this module to the | 
 | 	// distribution directory (default: $OUT/dist, configurable with $DIST_DIR) | 
 | 	Dists []Dist `android:"arch_variant"` | 
 | } | 
 |  | 
 | // CommonTestOptions represents the common `test_options` properties in | 
 | // Android.bp. | 
 | type CommonTestOptions struct { | 
 | 	// If the test is a hostside (no device required) unittest that shall be run | 
 | 	// during presubmit check. | 
 | 	Unit_test *bool | 
 |  | 
 | 	// Tags provide additional metadata to customize test execution by downstream | 
 | 	// test runners. The tags have no special meaning to Soong. | 
 | 	Tags []string | 
 | } | 
 |  | 
 | // SetAndroidMkEntries sets AndroidMkEntries according to the value of base | 
 | // `test_options`. | 
 | func (t *CommonTestOptions) SetAndroidMkEntries(entries *AndroidMkEntries) { | 
 | 	entries.SetBoolIfTrue("LOCAL_IS_UNIT_TEST", Bool(t.Unit_test)) | 
 | 	if len(t.Tags) > 0 { | 
 | 		entries.AddStrings("LOCAL_TEST_OPTIONS_TAGS", t.Tags...) | 
 | 	} | 
 | } | 
 |  | 
 | // The key to use in TaggedDistFiles when a Dist structure does not specify a | 
 | // tag property. This intentionally does not use "" as the default because that | 
 | // would mean that an empty tag would have a different meaning when used in a dist | 
 | // structure that when used to reference a specific set of output paths using the | 
 | // :module{tag} syntax, which passes tag to the OutputFiles(tag) method. | 
 | const DefaultDistTag = "<default-dist-tag>" | 
 |  | 
 | // A map of OutputFile tag keys to Paths, for disting purposes. | 
 | type TaggedDistFiles map[string]Paths | 
 |  | 
 | // addPathsForTag adds a mapping from the tag to the paths. If the map is nil | 
 | // then it will create a map, update it and then return it. If a mapping already | 
 | // exists for the tag then the paths are appended to the end of the current list | 
 | // of paths, ignoring any duplicates. | 
 | func (t TaggedDistFiles) addPathsForTag(tag string, paths ...Path) TaggedDistFiles { | 
 | 	if t == nil { | 
 | 		t = make(TaggedDistFiles) | 
 | 	} | 
 |  | 
 | 	for _, distFile := range paths { | 
 | 		if distFile != nil && !t[tag].containsPath(distFile) { | 
 | 			t[tag] = append(t[tag], distFile) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return t | 
 | } | 
 |  | 
 | // merge merges the entries from the other TaggedDistFiles object into this one. | 
 | // If the TaggedDistFiles is nil then it will create a new instance, merge the | 
 | // other into it, and then return it. | 
 | func (t TaggedDistFiles) merge(other TaggedDistFiles) TaggedDistFiles { | 
 | 	for tag, paths := range other { | 
 | 		t = t.addPathsForTag(tag, paths...) | 
 | 	} | 
 |  | 
 | 	return t | 
 | } | 
 |  | 
 | func MakeDefaultDistFiles(paths ...Path) TaggedDistFiles { | 
 | 	for _, p := range paths { | 
 | 		if p == nil { | 
 | 			panic("The path to a dist file cannot be nil.") | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// The default OutputFile tag is the empty "" string. | 
 | 	return TaggedDistFiles{DefaultDistTag: paths} | 
 | } | 
 |  | 
 | type hostAndDeviceProperties struct { | 
 | 	// If set to true, build a variant of the module for the host.  Defaults to false. | 
 | 	Host_supported *bool | 
 |  | 
 | 	// If set to true, build a variant of the module for the device.  Defaults to true. | 
 | 	Device_supported *bool | 
 | } | 
 |  | 
 | type Multilib string | 
 |  | 
 | const ( | 
 | 	MultilibBoth        Multilib = "both" | 
 | 	MultilibFirst       Multilib = "first" | 
 | 	MultilibCommon      Multilib = "common" | 
 | 	MultilibCommonFirst Multilib = "common_first" | 
 | ) | 
 |  | 
 | type HostOrDeviceSupported int | 
 |  | 
 | const ( | 
 | 	hostSupported = 1 << iota | 
 | 	hostCrossSupported | 
 | 	deviceSupported | 
 | 	hostDefault | 
 | 	deviceDefault | 
 |  | 
 | 	// Host and HostCross are built by default. Device is not supported. | 
 | 	HostSupported = hostSupported | hostCrossSupported | hostDefault | 
 |  | 
 | 	// Host is built by default. HostCross and Device are not supported. | 
 | 	HostSupportedNoCross = hostSupported | hostDefault | 
 |  | 
 | 	// Device is built by default. Host and HostCross are not supported. | 
 | 	DeviceSupported = deviceSupported | deviceDefault | 
 |  | 
 | 	// By default, _only_ device variant is built. Device variant can be disabled with `device_supported: false` | 
 | 	// Host and HostCross are disabled by default and can be enabled with `host_supported: true` | 
 | 	HostAndDeviceSupported = hostSupported | hostCrossSupported | deviceSupported | deviceDefault | 
 |  | 
 | 	// Host, HostCross, and Device are built by default. | 
 | 	// Building Device can be disabled with `device_supported: false` | 
 | 	// Building Host and HostCross can be disabled with `host_supported: false` | 
 | 	HostAndDeviceDefault = hostSupported | hostCrossSupported | hostDefault | | 
 | 		deviceSupported | deviceDefault | 
 |  | 
 | 	// Nothing is supported. This is not exposed to the user, but used to mark a | 
 | 	// host only module as unsupported when the module type is not supported on | 
 | 	// the host OS. E.g. benchmarks are supported on Linux but not Darwin. | 
 | 	NeitherHostNorDeviceSupported = 0 | 
 | ) | 
 |  | 
 | type moduleKind int | 
 |  | 
 | const ( | 
 | 	platformModule moduleKind = iota | 
 | 	deviceSpecificModule | 
 | 	socSpecificModule | 
 | 	productSpecificModule | 
 | 	systemExtSpecificModule | 
 | ) | 
 |  | 
 | func (k moduleKind) String() string { | 
 | 	switch k { | 
 | 	case platformModule: | 
 | 		return "platform" | 
 | 	case deviceSpecificModule: | 
 | 		return "device-specific" | 
 | 	case socSpecificModule: | 
 | 		return "soc-specific" | 
 | 	case productSpecificModule: | 
 | 		return "product-specific" | 
 | 	case systemExtSpecificModule: | 
 | 		return "systemext-specific" | 
 | 	default: | 
 | 		panic(fmt.Errorf("unknown module kind %d", k)) | 
 | 	} | 
 | } | 
 |  | 
 | func initAndroidModuleBase(m Module) { | 
 | 	m.base().module = m | 
 | } | 
 |  | 
 | // InitAndroidModule initializes the Module as an Android module that is not architecture-specific. | 
 | // It adds the common properties, for example "name" and "enabled". | 
 | func InitAndroidModule(m Module) { | 
 | 	initAndroidModuleBase(m) | 
 | 	base := m.base() | 
 |  | 
 | 	m.AddProperties( | 
 | 		&base.nameProperties, | 
 | 		&base.commonProperties, | 
 | 		&base.distProperties) | 
 |  | 
 | 	initProductVariableModule(m) | 
 |  | 
 | 	// The default_visibility property needs to be checked and parsed by the visibility module during | 
 | 	// its checking and parsing phases so make it the primary visibility property. | 
 | 	setPrimaryVisibilityProperty(m, "visibility", &base.commonProperties.Visibility) | 
 |  | 
 | 	// The default_applicable_licenses property needs to be checked and parsed by the licenses module during | 
 | 	// its checking and parsing phases so make it the primary licenses property. | 
 | 	setPrimaryLicensesProperty(m, "licenses", &base.commonProperties.Licenses) | 
 | } | 
 |  | 
 | // InitAndroidArchModule initializes the Module as an Android module that is architecture-specific. | 
 | // It adds the common properties, for example "name" and "enabled", as well as runtime generated | 
 | // property structs for architecture-specific versions of generic properties tagged with | 
 | // `android:"arch_variant"`. | 
 | // | 
 | //	InitAndroidModule should not be called if InitAndroidArchModule was called. | 
 | func InitAndroidArchModule(m Module, hod HostOrDeviceSupported, defaultMultilib Multilib) { | 
 | 	InitAndroidModule(m) | 
 |  | 
 | 	base := m.base() | 
 | 	base.commonProperties.HostOrDeviceSupported = hod | 
 | 	base.commonProperties.Default_multilib = string(defaultMultilib) | 
 | 	base.commonProperties.ArchSpecific = true | 
 | 	base.commonProperties.UseTargetVariants = true | 
 |  | 
 | 	if hod&hostSupported != 0 && hod&deviceSupported != 0 { | 
 | 		m.AddProperties(&base.hostAndDeviceProperties) | 
 | 	} | 
 |  | 
 | 	initArchModule(m) | 
 | } | 
 |  | 
 | // InitAndroidMultiTargetsArchModule initializes the Module as an Android module that is | 
 | // architecture-specific, but will only have a single variant per OS that handles all the | 
 | // architectures simultaneously.  The list of Targets that it must handle will be available from | 
 | // ModuleContext.MultiTargets. It adds the common properties, for example "name" and "enabled", as | 
 | // well as runtime generated property structs for architecture-specific versions of generic | 
 | // properties tagged with `android:"arch_variant"`. | 
 | // | 
 | // InitAndroidModule or InitAndroidArchModule should not be called if | 
 | // InitAndroidMultiTargetsArchModule was called. | 
 | func InitAndroidMultiTargetsArchModule(m Module, hod HostOrDeviceSupported, defaultMultilib Multilib) { | 
 | 	InitAndroidArchModule(m, hod, defaultMultilib) | 
 | 	m.base().commonProperties.UseTargetVariants = false | 
 | } | 
 |  | 
 | // InitCommonOSAndroidMultiTargetsArchModule initializes the Module as an Android module that is | 
 | // architecture-specific, but will only have a single variant per OS that handles all the | 
 | // architectures simultaneously, and will also have an additional CommonOS variant that has | 
 | // dependencies on all the OS-specific variants.  The list of Targets that it must handle will be | 
 | // available from ModuleContext.MultiTargets.  It adds the common properties, for example "name" and | 
 | // "enabled", as well as runtime generated property structs for architecture-specific versions of | 
 | // generic properties tagged with `android:"arch_variant"`. | 
 | // | 
 | // InitAndroidModule, InitAndroidArchModule or InitAndroidMultiTargetsArchModule should not be | 
 | // called if InitCommonOSAndroidMultiTargetsArchModule was called. | 
 | func InitCommonOSAndroidMultiTargetsArchModule(m Module, hod HostOrDeviceSupported, defaultMultilib Multilib) { | 
 | 	InitAndroidArchModule(m, hod, defaultMultilib) | 
 | 	m.base().commonProperties.UseTargetVariants = false | 
 | 	m.base().commonProperties.CreateCommonOSVariant = true | 
 | } | 
 |  | 
 | func (attrs *CommonAttributes) getRequiredWithoutCycles(ctx *bottomUpMutatorContext, props *commonProperties) []string { | 
 | 	// Treat `required` as if it's empty if data should be skipped for this target, | 
 | 	// as `required` is only used for the `data` attribute at this time, and we want | 
 | 	// to avoid lookups of labels that won't actually be dependencies of this target. | 
 | 	// TODO: b/202299295 - Refactor this to use `required` dependencies, once they | 
 | 	// are handled other than passing to `data`. | 
 | 	if proptools.Bool(attrs.SkipData) { | 
 | 		return []string{} | 
 | 	} | 
 | 	// The required property can contain the module itself. This causes a cycle | 
 | 	// when generated as the 'data' label list attribute in Bazel. Remove it if | 
 | 	// it exists. See b/247985196. | 
 | 	_, requiredWithoutCycles := RemoveFromList(ctx.ModuleName(), props.Required) | 
 | 	return FirstUniqueStrings(requiredWithoutCycles) | 
 | } | 
 |  | 
 | func (attrs *CommonAttributes) fillCommonBp2BuildModuleAttrs(ctx *bottomUpMutatorContext, | 
 | 	enabledPropertyOverrides bazel.BoolAttribute) constraintAttributes { | 
 |  | 
 | 	mod := ctx.Module().base() | 
 | 	// Assert passed-in attributes include Name | 
 | 	if len(attrs.Name) == 0 { | 
 | 		if ctx.ModuleType() != "package" { | 
 | 			ctx.ModuleErrorf("CommonAttributes in fillCommonBp2BuildModuleAttrs expects a `.Name`!") | 
 | 		} | 
 | 	} | 
 |  | 
 | 	depsToLabelList := func(deps []string) bazel.LabelListAttribute { | 
 | 		return bazel.MakeLabelListAttribute(BazelLabelForModuleDeps(ctx, deps)) | 
 | 	} | 
 |  | 
 | 	var enabledProperty bazel.BoolAttribute | 
 |  | 
 | 	onlyAndroid := false | 
 | 	neitherHostNorDevice := false | 
 |  | 
 | 	osSupport := map[string]bool{} | 
 |  | 
 | 	// if the target is enabled and supports arch variance, determine the defaults based on the module | 
 | 	// type's host or device property and host_supported/device_supported properties | 
 | 	if mod.commonProperties.ArchSpecific { | 
 | 		moduleSupportsDevice := mod.DeviceSupported() | 
 | 		moduleSupportsHost := mod.HostSupported() | 
 | 		if moduleSupportsHost && !moduleSupportsDevice { | 
 | 			// for host only, we specify as unsupported on android rather than listing all host osSupport | 
 | 			// TODO(b/220874839): consider replacing this with a constraint that covers all host osSupport | 
 | 			// instead | 
 | 			enabledProperty.SetSelectValue(bazel.OsConfigurationAxis, Android.Name, proptools.BoolPtr(false)) | 
 | 		} else if moduleSupportsDevice && !moduleSupportsHost { | 
 | 			enabledProperty.SetSelectValue(bazel.OsConfigurationAxis, Android.Name, proptools.BoolPtr(true)) | 
 | 			// specify as a positive to ensure any target-specific enabled can be resolved | 
 | 			// also save that a target is only android, as if there is only the positive restriction on | 
 | 			// android, it'll be dropped, so we may need to add it back later | 
 | 			onlyAndroid = true | 
 | 		} else if !moduleSupportsHost && !moduleSupportsDevice { | 
 | 			neitherHostNorDevice = true | 
 | 		} | 
 |  | 
 | 		for _, osType := range OsTypeList() { | 
 | 			if osType.Class == Host { | 
 | 				osSupport[osType.Name] = moduleSupportsHost | 
 | 			} else if osType.Class == Device { | 
 | 				osSupport[osType.Name] = moduleSupportsDevice | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if neitherHostNorDevice { | 
 | 		// we can't build this, disable | 
 | 		enabledProperty.Value = proptools.BoolPtr(false) | 
 | 	} else if mod.commonProperties.Enabled != nil { | 
 | 		enabledProperty.SetValue(mod.commonProperties.Enabled) | 
 | 		if !*mod.commonProperties.Enabled { | 
 | 			for oss, enabled := range osSupport { | 
 | 				if val := enabledProperty.SelectValue(bazel.OsConfigurationAxis, oss); enabled && val != nil && *val { | 
 | 					// if this should be disabled by default, clear out any enabling we've done | 
 | 					enabledProperty.SetSelectValue(bazel.OsConfigurationAxis, oss, nil) | 
 | 				} | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	attrs.Applicable_licenses = bazel.MakeLabelListAttribute(BazelLabelForModuleDeps(ctx, mod.commonProperties.Licenses)) | 
 |  | 
 | 	requiredWithoutCycles := attrs.getRequiredWithoutCycles(ctx, &mod.commonProperties) | 
 | 	required := depsToLabelList(requiredWithoutCycles) | 
 | 	archVariantProps := mod.GetArchVariantProperties(ctx, &commonProperties{}) | 
 | 	for axis, configToProps := range archVariantProps { | 
 | 		for config, _props := range configToProps { | 
 | 			if archProps, ok := _props.(*commonProperties); ok { | 
 | 				requiredWithoutCycles := attrs.getRequiredWithoutCycles(ctx, archProps) | 
 | 				required.SetSelectValue(axis, config, depsToLabelList(requiredWithoutCycles).Value) | 
 | 				if !neitherHostNorDevice { | 
 | 					if archProps.Enabled != nil { | 
 | 						if axis != bazel.OsConfigurationAxis || osSupport[config] { | 
 | 							enabledProperty.SetSelectValue(axis, config, archProps.Enabled) | 
 | 						} | 
 | 					} | 
 | 				} | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if !neitherHostNorDevice { | 
 | 		if enabledPropertyOverrides.Value != nil { | 
 | 			enabledProperty.Value = enabledPropertyOverrides.Value | 
 | 		} | 
 | 		for _, axis := range enabledPropertyOverrides.SortedConfigurationAxes() { | 
 | 			configToBools := enabledPropertyOverrides.ConfigurableValues[axis] | 
 | 			for cfg, val := range configToBools { | 
 | 				if axis != bazel.OsConfigurationAxis || osSupport[cfg] || val /*If enabled is explicitly requested via overrides */ { | 
 | 					enabledProperty.SetSelectValue(axis, cfg, &val) | 
 | 				} | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	productConfigEnabledAttribute := bazel.LabelListAttribute{} | 
 | 	// TODO(b/234497586): Soong config variables and product variables have different overriding behavior, we | 
 | 	// should handle it correctly | 
 | 	if !proptools.BoolDefault(enabledProperty.Value, true) && !neitherHostNorDevice { | 
 | 		// If the module is not enabled by default, then we can check if a | 
 | 		// product variable enables it | 
 | 		productConfigEnabledAttribute = productVariableConfigEnableAttribute(ctx) | 
 |  | 
 | 		if len(productConfigEnabledAttribute.ConfigurableValues) > 0 { | 
 | 			// In this case, an existing product variable configuration overrides any | 
 | 			// module-level `enable: false` definition | 
 | 			newValue := true | 
 | 			enabledProperty.Value = &newValue | 
 | 		} | 
 | 	} | 
 |  | 
 | 	platformEnabledAttribute, err := enabledProperty.ToLabelListAttribute( | 
 | 		bazel.LabelList{[]bazel.Label{{Label: "@platforms//:incompatible"}}, nil}, | 
 | 		bazel.LabelList{[]bazel.Label{}, nil}) | 
 | 	if err != nil { | 
 | 		ctx.ModuleErrorf("Error processing platform enabled attribute: %s", err) | 
 | 	} | 
 |  | 
 | 	// if android is the only arch/os enabled, then add a restriction to only be compatible with android | 
 | 	if platformEnabledAttribute.IsNil() && onlyAndroid { | 
 | 		l := bazel.LabelAttribute{} | 
 | 		l.SetValue(bazel.Label{Label: bazel.OsConfigurationAxis.SelectKey(Android.Name)}) | 
 | 		platformEnabledAttribute.Add(&l) | 
 | 	} | 
 |  | 
 | 	attrs.Data.Append(required) | 
 |  | 
 | 	// SkipData is not an attribute of any Bazel target | 
 | 	// Set this to nil so that it does not appear in the generated build file | 
 | 	attrs.SkipData = nil | 
 |  | 
 | 	moduleEnableConstraints := bazel.LabelListAttribute{} | 
 | 	moduleEnableConstraints.Append(platformEnabledAttribute) | 
 | 	moduleEnableConstraints.Append(productConfigEnabledAttribute) | 
 | 	addCompatibilityConstraintForCompileMultilib(ctx, &moduleEnableConstraints) | 
 |  | 
 | 	return constraintAttributes{Target_compatible_with: moduleEnableConstraints} | 
 | } | 
 |  | 
 | var ( | 
 | 	incompatible = bazel.LabelList{[]bazel.Label{{Label: "@platforms//:incompatible"}}, nil} | 
 | ) | 
 |  | 
 | // If compile_mulitilib is set to | 
 | // 1. 32: Add an incompatibility constraint for non-32 arches | 
 | // 1. 64: Add an incompatibility constraint for non-64 arches | 
 | func addCompatibilityConstraintForCompileMultilib(ctx *bottomUpMutatorContext, enabled *bazel.LabelListAttribute) { | 
 | 	mod := ctx.Module().base() | 
 | 	multilib, _ := decodeMultilib(mod, mod.commonProperties.CompileOS, ctx.Config().IgnorePrefer32OnDevice()) | 
 |  | 
 | 	switch multilib { | 
 | 	case "32": | 
 | 		// Add an incompatibility constraint for all known 64-bit arches | 
 | 		enabled.SetSelectValue(bazel.ArchConfigurationAxis, "arm64", incompatible) | 
 | 		enabled.SetSelectValue(bazel.ArchConfigurationAxis, "x86_64", incompatible) | 
 | 		enabled.SetSelectValue(bazel.ArchConfigurationAxis, "riscv64", incompatible) | 
 | 	case "64": | 
 | 		// Add an incompatibility constraint for all known 32-bit arches | 
 | 		enabled.SetSelectValue(bazel.ArchConfigurationAxis, "arm", incompatible) | 
 | 		enabled.SetSelectValue(bazel.ArchConfigurationAxis, "x86", incompatible) | 
 | 	case "both": | 
 | 		// Do nothing: "both" is trivially compatible with 32-bit and 64-bit | 
 | 		// The top level rule (e.g. apex/partition) will be responsible for building this module in both variants via an | 
 | 		// outgoing_transition. | 
 | 	default: // e.g. first, common | 
 | 		// TODO - b/299135307: Add bp2build support for these properties. | 
 | 	} | 
 |  | 
 | } | 
 |  | 
 | // Check product variables for `enabled: true` flag override. | 
 | // Returns a list of the constraint_value targets who enable this override. | 
 | func productVariableConfigEnableAttribute(ctx *bottomUpMutatorContext) bazel.LabelListAttribute { | 
 | 	result := bazel.LabelListAttribute{} | 
 | 	productVariableProps, errs := ProductVariableProperties(ctx, ctx.Module()) | 
 | 	for _, err := range errs { | 
 | 		ctx.ModuleErrorf("ProductVariableProperties error: %s", err) | 
 | 	} | 
 | 	if productConfigProps, exists := productVariableProps["Enabled"]; exists { | 
 | 		for productConfigProp, prop := range productConfigProps { | 
 | 			flag, ok := prop.(*bool) | 
 | 			if !ok { | 
 | 				ctx.ModuleErrorf("Could not convert product variable enabled property") | 
 | 			} | 
 |  | 
 | 			if flag == nil { | 
 | 				// soong config var is not used to set `enabled`. nothing to do. | 
 | 				continue | 
 | 			} else if *flag { | 
 | 				axis := productConfigProp.ConfigurationAxis() | 
 | 				result.SetSelectValue(axis, bazel.ConditionsDefaultConfigKey, bazel.MakeLabelList([]bazel.Label{{Label: "@platforms//:incompatible"}})) | 
 | 				result.SetSelectValue(axis, productConfigProp.SelectKey(), bazel.LabelList{Includes: []bazel.Label{}}) | 
 | 			} else if scp, isSoongConfigProperty := productConfigProp.(SoongConfigProperty); isSoongConfigProperty && scp.value == bazel.ConditionsDefaultConfigKey { | 
 | 				// productVariableConfigEnableAttribute runs only if `enabled: false` is set at the top-level outside soong_config_variables | 
 | 				// conditions_default { enabled: false} is a no-op in this case | 
 | 				continue | 
 | 			} else { | 
 | 				// TODO(b/210546943): handle negative case where `enabled: false` | 
 | 				ctx.ModuleErrorf("`enabled: false` is not currently supported for configuration variables. See b/210546943") | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return result | 
 | } | 
 |  | 
 | // A ModuleBase object contains the properties that are common to all Android | 
 | // modules.  It should be included as an anonymous field in every module | 
 | // struct definition.  InitAndroidModule should then be called from the module's | 
 | // factory function, and the return values from InitAndroidModule should be | 
 | // returned from the factory function. | 
 | // | 
 | // The ModuleBase type is responsible for implementing the GenerateBuildActions | 
 | // method to support the blueprint.Module interface. This method will then call | 
 | // the module's GenerateAndroidBuildActions method once for each build variant | 
 | // that is to be built. GenerateAndroidBuildActions is passed a ModuleContext | 
 | // rather than the usual blueprint.ModuleContext. | 
 | // ModuleContext exposes extra functionality specific to the Android build | 
 | // system including details about the particular build variant that is to be | 
 | // generated. | 
 | // | 
 | // For example: | 
 | // | 
 | //	import ( | 
 | //	    "android/soong/android" | 
 | //	) | 
 | // | 
 | //	type myModule struct { | 
 | //	    android.ModuleBase | 
 | //	    properties struct { | 
 | //	        MyProperty string | 
 | //	    } | 
 | //	} | 
 | // | 
 | //	func NewMyModule() android.Module { | 
 | //	    m := &myModule{} | 
 | //	    m.AddProperties(&m.properties) | 
 | //	    android.InitAndroidModule(m) | 
 | //	    return m | 
 | //	} | 
 | // | 
 | //	func (m *myModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { | 
 | //	    // Get the CPU architecture for the current build variant. | 
 | //	    variantArch := ctx.Arch() | 
 | // | 
 | //	    // ... | 
 | //	} | 
 | type ModuleBase struct { | 
 | 	// Putting the curiously recurring thing pointing to the thing that contains | 
 | 	// the thing pattern to good use. | 
 | 	// TODO: remove this | 
 | 	module Module | 
 |  | 
 | 	nameProperties          nameProperties | 
 | 	commonProperties        commonProperties | 
 | 	distProperties          distProperties | 
 | 	variableProperties      interface{} | 
 | 	hostAndDeviceProperties hostAndDeviceProperties | 
 |  | 
 | 	// Arch specific versions of structs in GetProperties() prior to | 
 | 	// initialization in InitAndroidArchModule, lets call it `generalProperties`. | 
 | 	// The outer index has the same order as generalProperties and the inner index | 
 | 	// chooses the props specific to the architecture. The interface{} value is an | 
 | 	// archPropRoot that is filled with arch specific values by the arch mutator. | 
 | 	archProperties [][]interface{} | 
 |  | 
 | 	// Properties specific to the Blueprint to BUILD migration. | 
 | 	bazelTargetModuleProperties bazel.BazelTargetModuleProperties | 
 |  | 
 | 	// Information about all the properties on the module that contains visibility rules that need | 
 | 	// checking. | 
 | 	visibilityPropertyInfo []visibilityProperty | 
 |  | 
 | 	// The primary visibility property, may be nil, that controls access to the module. | 
 | 	primaryVisibilityProperty visibilityProperty | 
 |  | 
 | 	// The primary licenses property, may be nil, records license metadata for the module. | 
 | 	primaryLicensesProperty applicableLicensesProperty | 
 |  | 
 | 	noAddressSanitizer   bool | 
 | 	installFiles         InstallPaths | 
 | 	installFilesDepSet   *DepSet[InstallPath] | 
 | 	checkbuildFiles      Paths | 
 | 	packagingSpecs       []PackagingSpec | 
 | 	packagingSpecsDepSet *DepSet[PackagingSpec] | 
 | 	// katiInstalls tracks the install rules that were created by Soong but are being exported | 
 | 	// to Make to convert to ninja rules so that Make can add additional dependencies. | 
 | 	katiInstalls katiInstalls | 
 | 	katiSymlinks katiInstalls | 
 |  | 
 | 	// The files to copy to the dist as explicitly specified in the .bp file. | 
 | 	distFiles TaggedDistFiles | 
 |  | 
 | 	// Used by buildTargetSingleton to create checkbuild and per-directory build targets | 
 | 	// Only set on the final variant of each module | 
 | 	installTarget    WritablePath | 
 | 	checkbuildTarget WritablePath | 
 | 	blueprintDir     string | 
 |  | 
 | 	hooks hooks | 
 |  | 
 | 	registerProps []interface{} | 
 |  | 
 | 	// For tests | 
 | 	buildParams []BuildParams | 
 | 	ruleParams  map[blueprint.Rule]blueprint.RuleParams | 
 | 	variables   map[string]string | 
 |  | 
 | 	initRcPaths         Paths | 
 | 	vintfFragmentsPaths Paths | 
 |  | 
 | 	// set of dependency module:location mappings used to populate the license metadata for | 
 | 	// apex containers. | 
 | 	licenseInstallMap []string | 
 |  | 
 | 	// The path to the generated license metadata file for the module. | 
 | 	licenseMetadataFile WritablePath | 
 | } | 
 |  | 
 | // A struct containing all relevant information about a Bazel target converted via bp2build. | 
 | type bp2buildInfo struct { | 
 | 	Dir             string | 
 | 	BazelProps      bazel.BazelTargetModuleProperties | 
 | 	CommonAttrs     CommonAttributes | 
 | 	ConstraintAttrs constraintAttributes | 
 | 	Attrs           interface{} | 
 | } | 
 |  | 
 | // TargetName returns the Bazel target name of a bp2build converted target. | 
 | func (b bp2buildInfo) TargetName() string { | 
 | 	return b.CommonAttrs.Name | 
 | } | 
 |  | 
 | // TargetPackage returns the Bazel package of a bp2build converted target. | 
 | func (b bp2buildInfo) TargetPackage() string { | 
 | 	return b.Dir | 
 | } | 
 |  | 
 | // BazelRuleClass returns the Bazel rule class of a bp2build converted target. | 
 | func (b bp2buildInfo) BazelRuleClass() string { | 
 | 	return b.BazelProps.Rule_class | 
 | } | 
 |  | 
 | // BazelRuleLoadLocation returns the location of the  Bazel rule of a bp2build converted target. | 
 | // This may be empty as native Bazel rules do not need to be loaded. | 
 | func (b bp2buildInfo) BazelRuleLoadLocation() string { | 
 | 	return b.BazelProps.Bzl_load_location | 
 | } | 
 |  | 
 | // BazelAttributes returns the Bazel attributes of a bp2build converted target. | 
 | func (b bp2buildInfo) BazelAttributes() []interface{} { | 
 | 	return []interface{}{&b.CommonAttrs, &b.ConstraintAttrs, b.Attrs} | 
 | } | 
 |  | 
 | func (m *ModuleBase) addBp2buildInfo(info bp2buildInfo) { | 
 | 	m.commonProperties.BazelConversionStatus.Bp2buildInfo = append(m.commonProperties.BazelConversionStatus.Bp2buildInfo, info) | 
 | } | 
 |  | 
 | func (m *ModuleBase) setBp2buildUnconvertible(reasonType bp2build_metrics_proto.UnconvertedReasonType, detail string) { | 
 | 	m.commonProperties.BazelConversionStatus.UnconvertedReason = &UnconvertedReason{ | 
 | 		ReasonType: int(reasonType), | 
 | 		Detail:     detail, | 
 | 	} | 
 | } | 
 |  | 
 | func (m *ModuleBase) GetUnconvertedReason() *UnconvertedReason { | 
 | 	return m.commonProperties.BazelConversionStatus.UnconvertedReason | 
 | } | 
 |  | 
 | // Bp2buildTargets returns the Bazel targets bp2build generated for this module. | 
 | func (m *ModuleBase) Bp2buildTargets() []bp2buildInfo { | 
 | 	return m.commonProperties.BazelConversionStatus.Bp2buildInfo | 
 | } | 
 |  | 
 | // AddUnconvertedBp2buildDep stores module name of a dependency that was not converted to Bazel. | 
 | func (b *baseModuleContext) AddUnconvertedBp2buildDep(dep string) { | 
 | 	unconvertedDeps := &b.Module().base().commonProperties.BazelConversionStatus.UnconvertedDeps | 
 | 	*unconvertedDeps = append(*unconvertedDeps, dep) | 
 | } | 
 |  | 
 | // AddMissingBp2buildDep stores module name of a dependency that was not found in a Android.bp file. | 
 | func (b *baseModuleContext) AddMissingBp2buildDep(dep string) { | 
 | 	missingDeps := &b.Module().base().commonProperties.BazelConversionStatus.MissingDeps | 
 | 	*missingDeps = append(*missingDeps, dep) | 
 | } | 
 |  | 
 | // GetUnconvertedBp2buildDeps returns the list of module names of this module's direct dependencies that | 
 | // were not converted to Bazel. | 
 | func (m *ModuleBase) GetUnconvertedBp2buildDeps() []string { | 
 | 	return FirstUniqueStrings(m.commonProperties.BazelConversionStatus.UnconvertedDeps) | 
 | } | 
 |  | 
 | // GetMissingBp2buildDeps returns the list of module names that were not found in Android.bp files. | 
 | func (m *ModuleBase) GetMissingBp2buildDeps() []string { | 
 | 	return FirstUniqueStrings(m.commonProperties.BazelConversionStatus.MissingDeps) | 
 | } | 
 |  | 
 | func (m *ModuleBase) AddJSONData(d *map[string]interface{}) { | 
 | 	(*d)["Android"] = map[string]interface{}{ | 
 | 		// Properties set in Blueprint or in blueprint of a defaults modules | 
 | 		"SetProperties": m.propertiesWithValues(), | 
 | 	} | 
 | } | 
 |  | 
 | type propInfo struct { | 
 | 	Name   string | 
 | 	Type   string | 
 | 	Value  string | 
 | 	Values []string | 
 | } | 
 |  | 
 | func (m *ModuleBase) propertiesWithValues() []propInfo { | 
 | 	var info []propInfo | 
 | 	props := m.GetProperties() | 
 |  | 
 | 	var propsWithValues func(name string, v reflect.Value) | 
 | 	propsWithValues = func(name string, v reflect.Value) { | 
 | 		kind := v.Kind() | 
 | 		switch kind { | 
 | 		case reflect.Ptr, reflect.Interface: | 
 | 			if v.IsNil() { | 
 | 				return | 
 | 			} | 
 | 			propsWithValues(name, v.Elem()) | 
 | 		case reflect.Struct: | 
 | 			if v.IsZero() { | 
 | 				return | 
 | 			} | 
 | 			for i := 0; i < v.NumField(); i++ { | 
 | 				namePrefix := name | 
 | 				sTyp := v.Type().Field(i) | 
 | 				if proptools.ShouldSkipProperty(sTyp) { | 
 | 					continue | 
 | 				} | 
 | 				if name != "" && !strings.HasSuffix(namePrefix, ".") { | 
 | 					namePrefix += "." | 
 | 				} | 
 | 				if !proptools.IsEmbedded(sTyp) { | 
 | 					namePrefix += sTyp.Name | 
 | 				} | 
 | 				sVal := v.Field(i) | 
 | 				propsWithValues(namePrefix, sVal) | 
 | 			} | 
 | 		case reflect.Array, reflect.Slice: | 
 | 			if v.IsNil() { | 
 | 				return | 
 | 			} | 
 | 			elKind := v.Type().Elem().Kind() | 
 | 			info = append(info, propInfo{Name: name, Type: elKind.String() + " " + kind.String(), Values: sliceReflectionValue(v)}) | 
 | 		default: | 
 | 			info = append(info, propInfo{Name: name, Type: kind.String(), Value: reflectionValue(v)}) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	for _, p := range props { | 
 | 		propsWithValues("", reflect.ValueOf(p).Elem()) | 
 | 	} | 
 | 	sort.Slice(info, func(i, j int) bool { | 
 | 		return info[i].Name < info[j].Name | 
 | 	}) | 
 | 	return info | 
 | } | 
 |  | 
 | func reflectionValue(value reflect.Value) string { | 
 | 	switch value.Kind() { | 
 | 	case reflect.Bool: | 
 | 		return fmt.Sprintf("%t", value.Bool()) | 
 | 	case reflect.Int64: | 
 | 		return fmt.Sprintf("%d", value.Int()) | 
 | 	case reflect.String: | 
 | 		return fmt.Sprintf("%s", value.String()) | 
 | 	case reflect.Struct: | 
 | 		if value.IsZero() { | 
 | 			return "{}" | 
 | 		} | 
 | 		length := value.NumField() | 
 | 		vals := make([]string, length, length) | 
 | 		for i := 0; i < length; i++ { | 
 | 			sTyp := value.Type().Field(i) | 
 | 			if proptools.ShouldSkipProperty(sTyp) { | 
 | 				continue | 
 | 			} | 
 | 			name := sTyp.Name | 
 | 			vals[i] = fmt.Sprintf("%s: %s", name, reflectionValue(value.Field(i))) | 
 | 		} | 
 | 		return fmt.Sprintf("%s{%s}", value.Type(), strings.Join(vals, ", ")) | 
 | 	case reflect.Array, reflect.Slice: | 
 | 		vals := sliceReflectionValue(value) | 
 | 		return fmt.Sprintf("[%s]", strings.Join(vals, ", ")) | 
 | 	} | 
 | 	return "" | 
 | } | 
 |  | 
 | func sliceReflectionValue(value reflect.Value) []string { | 
 | 	length := value.Len() | 
 | 	vals := make([]string, length, length) | 
 | 	for i := 0; i < length; i++ { | 
 | 		vals[i] = reflectionValue(value.Index(i)) | 
 | 	} | 
 | 	return vals | 
 | } | 
 |  | 
 | func (m *ModuleBase) ComponentDepsMutator(BottomUpMutatorContext) {} | 
 |  | 
 | func (m *ModuleBase) DepsMutator(BottomUpMutatorContext) {} | 
 |  | 
 | // AddProperties "registers" the provided props | 
 | // each value in props MUST be a pointer to a struct | 
 | func (m *ModuleBase) AddProperties(props ...interface{}) { | 
 | 	m.registerProps = append(m.registerProps, props...) | 
 | } | 
 |  | 
 | func (m *ModuleBase) GetProperties() []interface{} { | 
 | 	return m.registerProps | 
 | } | 
 |  | 
 | func (m *ModuleBase) BuildParamsForTests() []BuildParams { | 
 | 	// Expand the references to module variables like $flags[0-9]*, | 
 | 	// so we do not need to change many existing unit tests. | 
 | 	// This looks like undoing the shareFlags optimization in cc's | 
 | 	// transformSourceToObj, and should only affects unit tests. | 
 | 	vars := m.VariablesForTests() | 
 | 	buildParams := append([]BuildParams(nil), m.buildParams...) | 
 | 	for i := range buildParams { | 
 | 		newArgs := make(map[string]string) | 
 | 		for k, v := range buildParams[i].Args { | 
 | 			newArgs[k] = v | 
 | 			// Replaces both ${flags1} and $flags1 syntax. | 
 | 			if strings.HasPrefix(v, "${") && strings.HasSuffix(v, "}") { | 
 | 				if value, found := vars[v[2:len(v)-1]]; found { | 
 | 					newArgs[k] = value | 
 | 				} | 
 | 			} else if strings.HasPrefix(v, "$") { | 
 | 				if value, found := vars[v[1:]]; found { | 
 | 					newArgs[k] = value | 
 | 				} | 
 | 			} | 
 | 		} | 
 | 		buildParams[i].Args = newArgs | 
 | 	} | 
 | 	return buildParams | 
 | } | 
 |  | 
 | func (m *ModuleBase) RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams { | 
 | 	return m.ruleParams | 
 | } | 
 |  | 
 | func (m *ModuleBase) VariablesForTests() map[string]string { | 
 | 	return m.variables | 
 | } | 
 |  | 
 | // Name returns the name of the module.  It may be overridden by individual module types, for | 
 | // example prebuilts will prepend prebuilt_ to the name. | 
 | func (m *ModuleBase) Name() string { | 
 | 	return String(m.nameProperties.Name) | 
 | } | 
 |  | 
 | // String returns a string that includes the module name and variants for printing during debugging. | 
 | func (m *ModuleBase) String() string { | 
 | 	sb := strings.Builder{} | 
 | 	sb.WriteString(m.commonProperties.DebugName) | 
 | 	sb.WriteString("{") | 
 | 	for i := range m.commonProperties.DebugMutators { | 
 | 		if i != 0 { | 
 | 			sb.WriteString(",") | 
 | 		} | 
 | 		sb.WriteString(m.commonProperties.DebugMutators[i]) | 
 | 		sb.WriteString(":") | 
 | 		sb.WriteString(m.commonProperties.DebugVariations[i]) | 
 | 	} | 
 | 	sb.WriteString("}") | 
 | 	return sb.String() | 
 | } | 
 |  | 
 | // BaseModuleName returns the name of the module as specified in the blueprints file. | 
 | func (m *ModuleBase) BaseModuleName() string { | 
 | 	return String(m.nameProperties.Name) | 
 | } | 
 |  | 
 | func (m *ModuleBase) base() *ModuleBase { | 
 | 	return m | 
 | } | 
 |  | 
 | func (m *ModuleBase) qualifiedModuleId(ctx BaseModuleContext) qualifiedModuleName { | 
 | 	return qualifiedModuleName{pkg: ctx.ModuleDir(), name: ctx.ModuleName()} | 
 | } | 
 |  | 
 | func (m *ModuleBase) visibilityProperties() []visibilityProperty { | 
 | 	return m.visibilityPropertyInfo | 
 | } | 
 |  | 
 | func (m *ModuleBase) Dists() []Dist { | 
 | 	if len(m.distProperties.Dist.Targets) > 0 { | 
 | 		// Make a copy of the underlying Dists slice to protect against | 
 | 		// backing array modifications with repeated calls to this method. | 
 | 		distsCopy := append([]Dist(nil), m.distProperties.Dists...) | 
 | 		return append(distsCopy, m.distProperties.Dist) | 
 | 	} else { | 
 | 		return m.distProperties.Dists | 
 | 	} | 
 | } | 
 |  | 
 | func (m *ModuleBase) GenerateTaggedDistFiles(ctx BaseModuleContext) TaggedDistFiles { | 
 | 	var distFiles TaggedDistFiles | 
 | 	for _, dist := range m.Dists() { | 
 | 		// If no tag is specified then it means to use the default dist paths so use | 
 | 		// the special tag name which represents that. | 
 | 		tag := proptools.StringDefault(dist.Tag, DefaultDistTag) | 
 |  | 
 | 		if outputFileProducer, ok := m.module.(OutputFileProducer); ok { | 
 | 			// Call the OutputFiles(tag) method to get the paths associated with the tag. | 
 | 			distFilesForTag, err := outputFileProducer.OutputFiles(tag) | 
 |  | 
 | 			// If the tag was not supported and is not DefaultDistTag then it is an error. | 
 | 			// Failing to find paths for DefaultDistTag is not an error. It just means | 
 | 			// that the module type requires the legacy behavior. | 
 | 			if err != nil && tag != DefaultDistTag { | 
 | 				ctx.PropertyErrorf("dist.tag", "%s", err.Error()) | 
 | 			} | 
 |  | 
 | 			distFiles = distFiles.addPathsForTag(tag, distFilesForTag...) | 
 | 		} else if tag != DefaultDistTag { | 
 | 			// If the tag was specified then it is an error if the module does not | 
 | 			// implement OutputFileProducer because there is no other way of accessing | 
 | 			// the paths for the specified tag. | 
 | 			ctx.PropertyErrorf("dist.tag", | 
 | 				"tag %s not supported because the module does not implement OutputFileProducer", tag) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return distFiles | 
 | } | 
 |  | 
 | func (m *ModuleBase) Target() Target { | 
 | 	return m.commonProperties.CompileTarget | 
 | } | 
 |  | 
 | func (m *ModuleBase) TargetPrimary() bool { | 
 | 	return m.commonProperties.CompilePrimary | 
 | } | 
 |  | 
 | func (m *ModuleBase) MultiTargets() []Target { | 
 | 	return m.commonProperties.CompileMultiTargets | 
 | } | 
 |  | 
 | func (m *ModuleBase) Os() OsType { | 
 | 	return m.Target().Os | 
 | } | 
 |  | 
 | func (m *ModuleBase) Host() bool { | 
 | 	return m.Os().Class == Host | 
 | } | 
 |  | 
 | func (m *ModuleBase) Device() bool { | 
 | 	return m.Os().Class == Device | 
 | } | 
 |  | 
 | func (m *ModuleBase) Arch() Arch { | 
 | 	return m.Target().Arch | 
 | } | 
 |  | 
 | func (m *ModuleBase) ArchSpecific() bool { | 
 | 	return m.commonProperties.ArchSpecific | 
 | } | 
 |  | 
 | // True if the current variant is a CommonOS variant, false otherwise. | 
 | func (m *ModuleBase) IsCommonOSVariant() bool { | 
 | 	return m.commonProperties.CommonOSVariant | 
 | } | 
 |  | 
 | // supportsTarget returns true if the given Target is supported by the current module. | 
 | func (m *ModuleBase) supportsTarget(target Target) bool { | 
 | 	switch target.Os.Class { | 
 | 	case Host: | 
 | 		if target.HostCross { | 
 | 			return m.HostCrossSupported() | 
 | 		} else { | 
 | 			return m.HostSupported() | 
 | 		} | 
 | 	case Device: | 
 | 		return m.DeviceSupported() | 
 | 	default: | 
 | 		return false | 
 | 	} | 
 | } | 
 |  | 
 | // DeviceSupported returns true if the current module is supported and enabled for device targets, | 
 | // i.e. the factory method set the HostOrDeviceSupported value to include device support and | 
 | // the device support is enabled by default or enabled by the device_supported property. | 
 | func (m *ModuleBase) DeviceSupported() bool { | 
 | 	hod := m.commonProperties.HostOrDeviceSupported | 
 | 	// deviceEnabled is true if the device_supported property is true or the HostOrDeviceSupported | 
 | 	// value has the deviceDefault bit set. | 
 | 	deviceEnabled := proptools.BoolDefault(m.hostAndDeviceProperties.Device_supported, hod&deviceDefault != 0) | 
 | 	return hod&deviceSupported != 0 && deviceEnabled | 
 | } | 
 |  | 
 | // HostSupported returns true if the current module is supported and enabled for host targets, | 
 | // i.e. the factory method set the HostOrDeviceSupported value to include host support and | 
 | // the host support is enabled by default or enabled by the host_supported property. | 
 | func (m *ModuleBase) HostSupported() bool { | 
 | 	hod := m.commonProperties.HostOrDeviceSupported | 
 | 	// hostEnabled is true if the host_supported property is true or the HostOrDeviceSupported | 
 | 	// value has the hostDefault bit set. | 
 | 	hostEnabled := proptools.BoolDefault(m.hostAndDeviceProperties.Host_supported, hod&hostDefault != 0) | 
 | 	return hod&hostSupported != 0 && hostEnabled | 
 | } | 
 |  | 
 | // HostCrossSupported returns true if the current module is supported and enabled for host cross | 
 | // targets, i.e. the factory method set the HostOrDeviceSupported value to include host cross | 
 | // support and the host cross support is enabled by default or enabled by the | 
 | // host_supported property. | 
 | func (m *ModuleBase) HostCrossSupported() bool { | 
 | 	hod := m.commonProperties.HostOrDeviceSupported | 
 | 	// hostEnabled is true if the host_supported property is true or the HostOrDeviceSupported | 
 | 	// value has the hostDefault bit set. | 
 | 	hostEnabled := proptools.BoolDefault(m.hostAndDeviceProperties.Host_supported, hod&hostDefault != 0) | 
 | 	return hod&hostCrossSupported != 0 && hostEnabled | 
 | } | 
 |  | 
 | func (m *ModuleBase) Platform() bool { | 
 | 	return !m.DeviceSpecific() && !m.SocSpecific() && !m.ProductSpecific() && !m.SystemExtSpecific() | 
 | } | 
 |  | 
 | func (m *ModuleBase) DeviceSpecific() bool { | 
 | 	return Bool(m.commonProperties.Device_specific) | 
 | } | 
 |  | 
 | func (m *ModuleBase) SocSpecific() bool { | 
 | 	return Bool(m.commonProperties.Vendor) || Bool(m.commonProperties.Proprietary) || Bool(m.commonProperties.Soc_specific) | 
 | } | 
 |  | 
 | func (m *ModuleBase) ProductSpecific() bool { | 
 | 	return Bool(m.commonProperties.Product_specific) | 
 | } | 
 |  | 
 | func (m *ModuleBase) SystemExtSpecific() bool { | 
 | 	return Bool(m.commonProperties.System_ext_specific) | 
 | } | 
 |  | 
 | // RequiresStableAPIs returns true if the module will be installed to a partition that may | 
 | // be updated separately from the system image. | 
 | func (m *ModuleBase) RequiresStableAPIs(ctx BaseModuleContext) bool { | 
 | 	return m.SocSpecific() || m.DeviceSpecific() || | 
 | 		(m.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) | 
 | } | 
 |  | 
 | func (m *ModuleBase) PartitionTag(config DeviceConfig) string { | 
 | 	partition := "system" | 
 | 	if m.SocSpecific() { | 
 | 		// A SoC-specific module could be on the vendor partition at | 
 | 		// "vendor" or the system partition at "system/vendor". | 
 | 		if config.VendorPath() == "vendor" { | 
 | 			partition = "vendor" | 
 | 		} | 
 | 	} else if m.DeviceSpecific() { | 
 | 		// A device-specific module could be on the odm partition at | 
 | 		// "odm", the vendor partition at "vendor/odm", or the system | 
 | 		// partition at "system/vendor/odm". | 
 | 		if config.OdmPath() == "odm" { | 
 | 			partition = "odm" | 
 | 		} else if strings.HasPrefix(config.OdmPath(), "vendor/") { | 
 | 			partition = "vendor" | 
 | 		} | 
 | 	} else if m.ProductSpecific() { | 
 | 		// A product-specific module could be on the product partition | 
 | 		// at "product" or the system partition at "system/product". | 
 | 		if config.ProductPath() == "product" { | 
 | 			partition = "product" | 
 | 		} | 
 | 	} else if m.SystemExtSpecific() { | 
 | 		// A system_ext-specific module could be on the system_ext | 
 | 		// partition at "system_ext" or the system partition at | 
 | 		// "system/system_ext". | 
 | 		if config.SystemExtPath() == "system_ext" { | 
 | 			partition = "system_ext" | 
 | 		} | 
 | 	} | 
 | 	return partition | 
 | } | 
 |  | 
 | func (m *ModuleBase) Enabled() bool { | 
 | 	if m.commonProperties.ForcedDisabled { | 
 | 		return false | 
 | 	} | 
 | 	if m.commonProperties.Enabled == nil { | 
 | 		return !m.Os().DefaultDisabled | 
 | 	} | 
 | 	return *m.commonProperties.Enabled | 
 | } | 
 |  | 
 | func (m *ModuleBase) Disable() { | 
 | 	m.commonProperties.ForcedDisabled = true | 
 | } | 
 |  | 
 | // HideFromMake marks this variant so that it is not emitted in the generated Android.mk file. | 
 | func (m *ModuleBase) HideFromMake() { | 
 | 	m.commonProperties.HideFromMake = true | 
 | } | 
 |  | 
 | // IsHideFromMake returns true if HideFromMake was previously called. | 
 | func (m *ModuleBase) IsHideFromMake() bool { | 
 | 	return m.commonProperties.HideFromMake == true | 
 | } | 
 |  | 
 | // SkipInstall marks this variant to not create install rules when ctx.Install* are called. | 
 | func (m *ModuleBase) SkipInstall() { | 
 | 	m.commonProperties.SkipInstall = true | 
 | } | 
 |  | 
 | // IsSkipInstall returns true if this variant is marked to not create install | 
 | // rules when ctx.Install* are called. | 
 | func (m *ModuleBase) IsSkipInstall() bool { | 
 | 	return m.commonProperties.SkipInstall | 
 | } | 
 |  | 
 | // Similar to HideFromMake, but if the AndroidMk entry would set | 
 | // LOCAL_UNINSTALLABLE_MODULE then this variant may still output that entry | 
 | // rather than leaving it out altogether. That happens in cases where it would | 
 | // have other side effects, in particular when it adds a NOTICE file target, | 
 | // which other install targets might depend on. | 
 | func (m *ModuleBase) MakeUninstallable() { | 
 | 	m.commonProperties.UninstallableApexPlatformVariant = true | 
 | 	m.HideFromMake() | 
 | } | 
 |  | 
 | func (m *ModuleBase) ReplacedByPrebuilt() { | 
 | 	m.commonProperties.ReplacedByPrebuilt = true | 
 | 	m.HideFromMake() | 
 | } | 
 |  | 
 | func (m *ModuleBase) IsReplacedByPrebuilt() bool { | 
 | 	return m.commonProperties.ReplacedByPrebuilt | 
 | } | 
 |  | 
 | func (m *ModuleBase) ExportedToMake() bool { | 
 | 	return m.commonProperties.NamespaceExportedToMake | 
 | } | 
 |  | 
 | func (m *ModuleBase) EffectiveLicenseKinds() []string { | 
 | 	return m.commonProperties.Effective_license_kinds | 
 | } | 
 |  | 
 | func (m *ModuleBase) EffectiveLicenseFiles() Paths { | 
 | 	result := make(Paths, 0, len(m.commonProperties.Effective_license_text)) | 
 | 	for _, p := range m.commonProperties.Effective_license_text { | 
 | 		result = append(result, p.Path) | 
 | 	} | 
 | 	return result | 
 | } | 
 |  | 
 | // computeInstallDeps finds the installed paths of all dependencies that have a dependency | 
 | // tag that is annotated as needing installation via the isInstallDepNeeded method. | 
 | func (m *ModuleBase) computeInstallDeps(ctx ModuleContext) ([]*DepSet[InstallPath], []*DepSet[PackagingSpec]) { | 
 | 	var installDeps []*DepSet[InstallPath] | 
 | 	var packagingSpecs []*DepSet[PackagingSpec] | 
 | 	ctx.VisitDirectDeps(func(dep Module) { | 
 | 		if isInstallDepNeeded(dep, ctx.OtherModuleDependencyTag(dep)) { | 
 | 			// Installation is still handled by Make, so anything hidden from Make is not | 
 | 			// installable. | 
 | 			if !dep.IsHideFromMake() && !dep.IsSkipInstall() { | 
 | 				installDeps = append(installDeps, dep.base().installFilesDepSet) | 
 | 			} | 
 | 			// Add packaging deps even when the dependency is not installed so that uninstallable | 
 | 			// modules can still be packaged.  Often the package will be installed instead. | 
 | 			packagingSpecs = append(packagingSpecs, dep.base().packagingSpecsDepSet) | 
 | 		} | 
 | 	}) | 
 |  | 
 | 	return installDeps, packagingSpecs | 
 | } | 
 |  | 
 | // isInstallDepNeeded returns true if installing the output files of the current module | 
 | // should also install the output files of the given dependency and dependency tag. | 
 | func isInstallDepNeeded(dep Module, tag blueprint.DependencyTag) bool { | 
 | 	// Don't add a dependency from the platform to a library provided by an apex. | 
 | 	if dep.base().commonProperties.UninstallableApexPlatformVariant { | 
 | 		return false | 
 | 	} | 
 | 	// Only install modules if the dependency tag is an InstallDepNeeded tag. | 
 | 	return IsInstallDepNeededTag(tag) | 
 | } | 
 |  | 
 | func (m *ModuleBase) FilesToInstall() InstallPaths { | 
 | 	return m.installFiles | 
 | } | 
 |  | 
 | func (m *ModuleBase) PackagingSpecs() []PackagingSpec { | 
 | 	return m.packagingSpecs | 
 | } | 
 |  | 
 | func (m *ModuleBase) TransitivePackagingSpecs() []PackagingSpec { | 
 | 	return m.packagingSpecsDepSet.ToList() | 
 | } | 
 |  | 
 | func (m *ModuleBase) NoAddressSanitizer() bool { | 
 | 	return m.noAddressSanitizer | 
 | } | 
 |  | 
 | func (m *ModuleBase) InstallInData() bool { | 
 | 	return false | 
 | } | 
 |  | 
 | func (m *ModuleBase) InstallInTestcases() bool { | 
 | 	return false | 
 | } | 
 |  | 
 | func (m *ModuleBase) InstallInSanitizerDir() bool { | 
 | 	return false | 
 | } | 
 |  | 
 | func (m *ModuleBase) InstallInRamdisk() bool { | 
 | 	return Bool(m.commonProperties.Ramdisk) | 
 | } | 
 |  | 
 | func (m *ModuleBase) InstallInVendorRamdisk() bool { | 
 | 	return Bool(m.commonProperties.Vendor_ramdisk) | 
 | } | 
 |  | 
 | func (m *ModuleBase) InstallInDebugRamdisk() bool { | 
 | 	return Bool(m.commonProperties.Debug_ramdisk) | 
 | } | 
 |  | 
 | func (m *ModuleBase) InstallInRecovery() bool { | 
 | 	return Bool(m.commonProperties.Recovery) | 
 | } | 
 |  | 
 | func (m *ModuleBase) InstallInVendor() bool { | 
 | 	return Bool(m.commonProperties.Vendor) || Bool(m.commonProperties.Soc_specific) || Bool(m.commonProperties.Proprietary) | 
 | } | 
 |  | 
 | func (m *ModuleBase) InstallInRoot() bool { | 
 | 	return false | 
 | } | 
 |  | 
 | func (m *ModuleBase) InstallForceOS() (*OsType, *ArchType) { | 
 | 	return nil, nil | 
 | } | 
 |  | 
 | func (m *ModuleBase) Owner() string { | 
 | 	return String(m.commonProperties.Owner) | 
 | } | 
 |  | 
 | func (m *ModuleBase) setImageVariation(variant string) { | 
 | 	m.commonProperties.ImageVariation = variant | 
 | } | 
 |  | 
 | func (m *ModuleBase) ImageVariation() blueprint.Variation { | 
 | 	return blueprint.Variation{ | 
 | 		Mutator:   "image", | 
 | 		Variation: m.base().commonProperties.ImageVariation, | 
 | 	} | 
 | } | 
 |  | 
 | func (m *ModuleBase) getVariationByMutatorName(mutator string) string { | 
 | 	for i, v := range m.commonProperties.DebugMutators { | 
 | 		if v == mutator { | 
 | 			return m.commonProperties.DebugVariations[i] | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return "" | 
 | } | 
 |  | 
 | func (m *ModuleBase) InRamdisk() bool { | 
 | 	return m.base().commonProperties.ImageVariation == RamdiskVariation | 
 | } | 
 |  | 
 | func (m *ModuleBase) InVendorRamdisk() bool { | 
 | 	return m.base().commonProperties.ImageVariation == VendorRamdiskVariation | 
 | } | 
 |  | 
 | func (m *ModuleBase) InDebugRamdisk() bool { | 
 | 	return m.base().commonProperties.ImageVariation == DebugRamdiskVariation | 
 | } | 
 |  | 
 | func (m *ModuleBase) InRecovery() bool { | 
 | 	return m.base().commonProperties.ImageVariation == RecoveryVariation | 
 | } | 
 |  | 
 | func (m *ModuleBase) RequiredModuleNames() []string { | 
 | 	return m.base().commonProperties.Required | 
 | } | 
 |  | 
 | func (m *ModuleBase) HostRequiredModuleNames() []string { | 
 | 	return m.base().commonProperties.Host_required | 
 | } | 
 |  | 
 | func (m *ModuleBase) TargetRequiredModuleNames() []string { | 
 | 	return m.base().commonProperties.Target_required | 
 | } | 
 |  | 
 | func (m *ModuleBase) InitRc() Paths { | 
 | 	return append(Paths{}, m.initRcPaths...) | 
 | } | 
 |  | 
 | func (m *ModuleBase) VintfFragments() Paths { | 
 | 	return append(Paths{}, m.vintfFragmentsPaths...) | 
 | } | 
 |  | 
 | func (m *ModuleBase) CompileMultilib() *string { | 
 | 	return m.base().commonProperties.Compile_multilib | 
 | } | 
 |  | 
 | // SetLicenseInstallMap stores the set of dependency module:location mappings for files in an | 
 | // apex container for use when generation the license metadata file. | 
 | func (m *ModuleBase) SetLicenseInstallMap(installMap []string) { | 
 | 	m.licenseInstallMap = append(m.licenseInstallMap, installMap...) | 
 | } | 
 |  | 
 | func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) { | 
 | 	var allInstalledFiles InstallPaths | 
 | 	var allCheckbuildFiles Paths | 
 | 	ctx.VisitAllModuleVariants(func(module Module) { | 
 | 		a := module.base() | 
 | 		allInstalledFiles = append(allInstalledFiles, a.installFiles...) | 
 | 		// A module's -checkbuild phony targets should | 
 | 		// not be created if the module is not exported to make. | 
 | 		// Those could depend on the build target and fail to compile | 
 | 		// for the current build target. | 
 | 		if !ctx.Config().KatiEnabled() || !shouldSkipAndroidMkProcessing(a) { | 
 | 			allCheckbuildFiles = append(allCheckbuildFiles, a.checkbuildFiles...) | 
 | 		} | 
 | 	}) | 
 |  | 
 | 	var deps Paths | 
 |  | 
 | 	namespacePrefix := ctx.Namespace().id | 
 | 	if namespacePrefix != "" { | 
 | 		namespacePrefix = namespacePrefix + "-" | 
 | 	} | 
 |  | 
 | 	if len(allInstalledFiles) > 0 { | 
 | 		name := namespacePrefix + ctx.ModuleName() + "-install" | 
 | 		ctx.Phony(name, allInstalledFiles.Paths()...) | 
 | 		m.installTarget = PathForPhony(ctx, name) | 
 | 		deps = append(deps, m.installTarget) | 
 | 	} | 
 |  | 
 | 	if len(allCheckbuildFiles) > 0 { | 
 | 		name := namespacePrefix + ctx.ModuleName() + "-checkbuild" | 
 | 		ctx.Phony(name, allCheckbuildFiles...) | 
 | 		m.checkbuildTarget = PathForPhony(ctx, name) | 
 | 		deps = append(deps, m.checkbuildTarget) | 
 | 	} | 
 |  | 
 | 	if len(deps) > 0 { | 
 | 		suffix := "" | 
 | 		if ctx.Config().KatiEnabled() { | 
 | 			suffix = "-soong" | 
 | 		} | 
 |  | 
 | 		ctx.Phony(namespacePrefix+ctx.ModuleName()+suffix, deps...) | 
 |  | 
 | 		m.blueprintDir = ctx.ModuleDir() | 
 | 	} | 
 | } | 
 |  | 
 | func determineModuleKind(m *ModuleBase, ctx blueprint.EarlyModuleContext) moduleKind { | 
 | 	var socSpecific = Bool(m.commonProperties.Vendor) || Bool(m.commonProperties.Proprietary) || Bool(m.commonProperties.Soc_specific) | 
 | 	var deviceSpecific = Bool(m.commonProperties.Device_specific) | 
 | 	var productSpecific = Bool(m.commonProperties.Product_specific) | 
 | 	var systemExtSpecific = Bool(m.commonProperties.System_ext_specific) | 
 |  | 
 | 	msg := "conflicting value set here" | 
 | 	if socSpecific && deviceSpecific { | 
 | 		ctx.PropertyErrorf("device_specific", "a module cannot be specific to SoC and device at the same time.") | 
 | 		if Bool(m.commonProperties.Vendor) { | 
 | 			ctx.PropertyErrorf("vendor", msg) | 
 | 		} | 
 | 		if Bool(m.commonProperties.Proprietary) { | 
 | 			ctx.PropertyErrorf("proprietary", msg) | 
 | 		} | 
 | 		if Bool(m.commonProperties.Soc_specific) { | 
 | 			ctx.PropertyErrorf("soc_specific", msg) | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if productSpecific && systemExtSpecific { | 
 | 		ctx.PropertyErrorf("product_specific", "a module cannot be specific to product and system_ext at the same time.") | 
 | 		ctx.PropertyErrorf("system_ext_specific", msg) | 
 | 	} | 
 |  | 
 | 	if (socSpecific || deviceSpecific) && (productSpecific || systemExtSpecific) { | 
 | 		if productSpecific { | 
 | 			ctx.PropertyErrorf("product_specific", "a module cannot be specific to SoC or device and product at the same time.") | 
 | 		} else { | 
 | 			ctx.PropertyErrorf("system_ext_specific", "a module cannot be specific to SoC or device and system_ext at the same time.") | 
 | 		} | 
 | 		if deviceSpecific { | 
 | 			ctx.PropertyErrorf("device_specific", msg) | 
 | 		} else { | 
 | 			if Bool(m.commonProperties.Vendor) { | 
 | 				ctx.PropertyErrorf("vendor", msg) | 
 | 			} | 
 | 			if Bool(m.commonProperties.Proprietary) { | 
 | 				ctx.PropertyErrorf("proprietary", msg) | 
 | 			} | 
 | 			if Bool(m.commonProperties.Soc_specific) { | 
 | 				ctx.PropertyErrorf("soc_specific", msg) | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	if productSpecific { | 
 | 		return productSpecificModule | 
 | 	} else if systemExtSpecific { | 
 | 		return systemExtSpecificModule | 
 | 	} else if deviceSpecific { | 
 | 		return deviceSpecificModule | 
 | 	} else if socSpecific { | 
 | 		return socSpecificModule | 
 | 	} else { | 
 | 		return platformModule | 
 | 	} | 
 | } | 
 |  | 
 | func (m *ModuleBase) earlyModuleContextFactory(ctx blueprint.EarlyModuleContext) earlyModuleContext { | 
 | 	return earlyModuleContext{ | 
 | 		EarlyModuleContext: ctx, | 
 | 		kind:               determineModuleKind(m, ctx), | 
 | 		config:             ctx.Config().(Config), | 
 | 	} | 
 | } | 
 |  | 
 | func (m *ModuleBase) baseModuleContextFactory(ctx blueprint.BaseModuleContext) baseModuleContext { | 
 | 	return baseModuleContext{ | 
 | 		bp:                 ctx, | 
 | 		earlyModuleContext: m.earlyModuleContextFactory(ctx), | 
 | 		os:                 m.commonProperties.CompileOS, | 
 | 		target:             m.commonProperties.CompileTarget, | 
 | 		targetPrimary:      m.commonProperties.CompilePrimary, | 
 | 		multiTargets:       m.commonProperties.CompileMultiTargets, | 
 | 	} | 
 | } | 
 |  | 
 | func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) { | 
 | 	ctx := &moduleContext{ | 
 | 		module:            m.module, | 
 | 		bp:                blueprintCtx, | 
 | 		baseModuleContext: m.baseModuleContextFactory(blueprintCtx), | 
 | 		variables:         make(map[string]string), | 
 | 	} | 
 |  | 
 | 	m.licenseMetadataFile = PathForModuleOut(ctx, "meta_lic") | 
 |  | 
 | 	dependencyInstallFiles, dependencyPackagingSpecs := m.computeInstallDeps(ctx) | 
 | 	// set m.installFilesDepSet to only the transitive dependencies to be used as the dependencies | 
 | 	// of installed files of this module.  It will be replaced by a depset including the installed | 
 | 	// files of this module at the end for use by modules that depend on this one. | 
 | 	m.installFilesDepSet = NewDepSet[InstallPath](TOPOLOGICAL, nil, dependencyInstallFiles) | 
 |  | 
 | 	// Temporarily continue to call blueprintCtx.GetMissingDependencies() to maintain the previous behavior of never | 
 | 	// reporting missing dependency errors in Blueprint when AllowMissingDependencies == true. | 
 | 	// TODO: This will be removed once defaults modules handle missing dependency errors | 
 | 	blueprintCtx.GetMissingDependencies() | 
 |  | 
 | 	// For the final GenerateAndroidBuildActions pass, require that all visited dependencies Soong modules and | 
 | 	// are enabled. Unless the module is a CommonOS variant which may have dependencies on disabled variants | 
 | 	// (because the dependencies are added before the modules are disabled). The | 
 | 	// GetOsSpecificVariantsOfCommonOSVariant(...) method will ensure that the disabled variants are | 
 | 	// ignored. | 
 | 	ctx.baseModuleContext.strictVisitDeps = !m.IsCommonOSVariant() | 
 |  | 
 | 	if ctx.config.captureBuild { | 
 | 		ctx.ruleParams = make(map[blueprint.Rule]blueprint.RuleParams) | 
 | 	} | 
 |  | 
 | 	desc := "//" + ctx.ModuleDir() + ":" + ctx.ModuleName() + " " | 
 | 	var suffix []string | 
 | 	if ctx.Os().Class != Device && ctx.Os().Class != Generic { | 
 | 		suffix = append(suffix, ctx.Os().String()) | 
 | 	} | 
 | 	if !ctx.PrimaryArch() { | 
 | 		suffix = append(suffix, ctx.Arch().ArchType.String()) | 
 | 	} | 
 | 	if apexInfo := ctx.Provider(ApexInfoProvider).(ApexInfo); !apexInfo.IsForPlatform() { | 
 | 		suffix = append(suffix, apexInfo.ApexVariationName) | 
 | 	} | 
 |  | 
 | 	ctx.Variable(pctx, "moduleDesc", desc) | 
 |  | 
 | 	s := "" | 
 | 	if len(suffix) > 0 { | 
 | 		s = " [" + strings.Join(suffix, " ") + "]" | 
 | 	} | 
 | 	ctx.Variable(pctx, "moduleDescSuffix", s) | 
 |  | 
 | 	// Some common property checks for properties that will be used later in androidmk.go | 
 | 	checkDistProperties(ctx, "dist", &m.distProperties.Dist) | 
 | 	for i := range m.distProperties.Dists { | 
 | 		checkDistProperties(ctx, fmt.Sprintf("dists[%d]", i), &m.distProperties.Dists[i]) | 
 | 	} | 
 |  | 
 | 	if m.Enabled() { | 
 | 		// ensure all direct android.Module deps are enabled | 
 | 		ctx.VisitDirectDepsBlueprint(func(bm blueprint.Module) { | 
 | 			if m, ok := bm.(Module); ok { | 
 | 				ctx.validateAndroidModule(bm, ctx.OtherModuleDependencyTag(m), ctx.baseModuleContext.strictVisitDeps) | 
 | 			} | 
 | 		}) | 
 |  | 
 | 		licensesPropertyFlattener(ctx) | 
 | 		if ctx.Failed() { | 
 | 			return | 
 | 		} | 
 |  | 
 | 		if mixedBuildMod, handled := m.isHandledByBazel(ctx); handled { | 
 | 			mixedBuildMod.ProcessBazelQueryResponse(ctx) | 
 | 		} else { | 
 | 			m.module.GenerateAndroidBuildActions(ctx) | 
 | 		} | 
 | 		if ctx.Failed() { | 
 | 			return | 
 | 		} | 
 |  | 
 | 		m.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc) | 
 | 		rcDir := PathForModuleInstall(ctx, "etc", "init") | 
 | 		for _, src := range m.initRcPaths { | 
 | 			ctx.PackageFile(rcDir, filepath.Base(src.String()), src) | 
 | 		} | 
 |  | 
 | 		m.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments) | 
 | 		vintfDir := PathForModuleInstall(ctx, "etc", "vintf", "manifest") | 
 | 		for _, src := range m.vintfFragmentsPaths { | 
 | 			ctx.PackageFile(vintfDir, filepath.Base(src.String()), src) | 
 | 		} | 
 |  | 
 | 		// Create the set of tagged dist files after calling GenerateAndroidBuildActions | 
 | 		// as GenerateTaggedDistFiles() calls OutputFiles(tag) and so relies on the | 
 | 		// output paths being set which must be done before or during | 
 | 		// GenerateAndroidBuildActions. | 
 | 		m.distFiles = m.GenerateTaggedDistFiles(ctx) | 
 | 		if ctx.Failed() { | 
 | 			return | 
 | 		} | 
 |  | 
 | 		m.installFiles = append(m.installFiles, ctx.installFiles...) | 
 | 		m.checkbuildFiles = append(m.checkbuildFiles, ctx.checkbuildFiles...) | 
 | 		m.packagingSpecs = append(m.packagingSpecs, ctx.packagingSpecs...) | 
 | 		m.katiInstalls = append(m.katiInstalls, ctx.katiInstalls...) | 
 | 		m.katiSymlinks = append(m.katiSymlinks, ctx.katiSymlinks...) | 
 | 	} else if ctx.Config().AllowMissingDependencies() { | 
 | 		// If the module is not enabled it will not create any build rules, nothing will call | 
 | 		// ctx.GetMissingDependencies(), and blueprint will consider the missing dependencies to be unhandled | 
 | 		// and report them as an error even when AllowMissingDependencies = true.  Call | 
 | 		// ctx.GetMissingDependencies() here to tell blueprint not to handle them. | 
 | 		ctx.GetMissingDependencies() | 
 | 	} | 
 |  | 
 | 	if m == ctx.FinalModule().(Module).base() { | 
 | 		m.generateModuleTarget(ctx) | 
 | 		if ctx.Failed() { | 
 | 			return | 
 | 		} | 
 | 	} | 
 |  | 
 | 	m.installFilesDepSet = NewDepSet[InstallPath](TOPOLOGICAL, m.installFiles, dependencyInstallFiles) | 
 | 	m.packagingSpecsDepSet = NewDepSet[PackagingSpec](TOPOLOGICAL, m.packagingSpecs, dependencyPackagingSpecs) | 
 |  | 
 | 	buildLicenseMetadata(ctx, m.licenseMetadataFile) | 
 |  | 
 | 	m.buildParams = ctx.buildParams | 
 | 	m.ruleParams = ctx.ruleParams | 
 | 	m.variables = ctx.variables | 
 | } | 
 |  | 
 | func (m *ModuleBase) isHandledByBazel(ctx ModuleContext) (MixedBuildBuildable, bool) { | 
 | 	if mixedBuildMod, ok := m.module.(MixedBuildBuildable); ok { | 
 | 		if mixedBuildMod.IsMixedBuildSupported(ctx) && (MixedBuildsEnabled(ctx) == MixedBuildEnabled) { | 
 | 			return mixedBuildMod, true | 
 | 		} | 
 | 	} | 
 | 	return nil, false | 
 | } | 
 |  | 
 | // Check the supplied dist structure to make sure that it is valid. | 
 | // | 
 | // property - the base property, e.g. dist or dists[1], which is combined with the | 
 | // name of the nested property to produce the full property, e.g. dist.dest or | 
 | // dists[1].dir. | 
 | func checkDistProperties(ctx *moduleContext, property string, dist *Dist) { | 
 | 	if dist.Dest != nil { | 
 | 		_, err := validateSafePath(*dist.Dest) | 
 | 		if err != nil { | 
 | 			ctx.PropertyErrorf(property+".dest", "%s", err.Error()) | 
 | 		} | 
 | 	} | 
 | 	if dist.Dir != nil { | 
 | 		_, err := validateSafePath(*dist.Dir) | 
 | 		if err != nil { | 
 | 			ctx.PropertyErrorf(property+".dir", "%s", err.Error()) | 
 | 		} | 
 | 	} | 
 | 	if dist.Suffix != nil { | 
 | 		if strings.Contains(*dist.Suffix, "/") { | 
 | 			ctx.PropertyErrorf(property+".suffix", "Suffix may not contain a '/' character.") | 
 | 		} | 
 | 	} | 
 |  | 
 | } | 
 |  | 
 | type earlyModuleContext struct { | 
 | 	blueprint.EarlyModuleContext | 
 |  | 
 | 	kind   moduleKind | 
 | 	config Config | 
 | } | 
 |  | 
 | func (e *earlyModuleContext) Glob(globPattern string, excludes []string) Paths { | 
 | 	return Glob(e, globPattern, excludes) | 
 | } | 
 |  | 
 | func (e *earlyModuleContext) GlobFiles(globPattern string, excludes []string) Paths { | 
 | 	return GlobFiles(e, globPattern, excludes) | 
 | } | 
 |  | 
 | func (e *earlyModuleContext) IsSymlink(path Path) bool { | 
 | 	fileInfo, err := e.config.fs.Lstat(path.String()) | 
 | 	if err != nil { | 
 | 		e.ModuleErrorf("os.Lstat(%q) failed: %s", path.String(), err) | 
 | 	} | 
 | 	return fileInfo.Mode()&os.ModeSymlink == os.ModeSymlink | 
 | } | 
 |  | 
 | func (e *earlyModuleContext) Readlink(path Path) string { | 
 | 	dest, err := e.config.fs.Readlink(path.String()) | 
 | 	if err != nil { | 
 | 		e.ModuleErrorf("os.Readlink(%q) failed: %s", path.String(), err) | 
 | 	} | 
 | 	return dest | 
 | } | 
 |  | 
 | func (e *earlyModuleContext) Module() Module { | 
 | 	module, _ := e.EarlyModuleContext.Module().(Module) | 
 | 	return module | 
 | } | 
 |  | 
 | func (e *earlyModuleContext) Config() Config { | 
 | 	return e.EarlyModuleContext.Config().(Config) | 
 | } | 
 |  | 
 | func (e *earlyModuleContext) AConfig() Config { | 
 | 	return e.config | 
 | } | 
 |  | 
 | func (e *earlyModuleContext) DeviceConfig() DeviceConfig { | 
 | 	return DeviceConfig{e.config.deviceConfig} | 
 | } | 
 |  | 
 | func (e *earlyModuleContext) Platform() bool { | 
 | 	return e.kind == platformModule | 
 | } | 
 |  | 
 | func (e *earlyModuleContext) DeviceSpecific() bool { | 
 | 	return e.kind == deviceSpecificModule | 
 | } | 
 |  | 
 | func (e *earlyModuleContext) SocSpecific() bool { | 
 | 	return e.kind == socSpecificModule | 
 | } | 
 |  | 
 | func (e *earlyModuleContext) ProductSpecific() bool { | 
 | 	return e.kind == productSpecificModule | 
 | } | 
 |  | 
 | func (e *earlyModuleContext) SystemExtSpecific() bool { | 
 | 	return e.kind == systemExtSpecificModule | 
 | } | 
 |  | 
 | func (e *earlyModuleContext) Namespace() *Namespace { | 
 | 	return e.EarlyModuleContext.Namespace().(*Namespace) | 
 | } | 
 |  | 
 | type baseModuleContext struct { | 
 | 	bp blueprint.BaseModuleContext | 
 | 	earlyModuleContext | 
 | 	os            OsType | 
 | 	target        Target | 
 | 	multiTargets  []Target | 
 | 	targetPrimary bool | 
 | 	debug         bool | 
 |  | 
 | 	walkPath []Module | 
 | 	tagPath  []blueprint.DependencyTag | 
 |  | 
 | 	strictVisitDeps bool // If true, enforce that all dependencies are enabled | 
 |  | 
 | 	bazelConversionMode bool | 
 | } | 
 |  | 
 | func (b *baseModuleContext) isBazelConversionMode() bool { | 
 | 	return b.bazelConversionMode | 
 | } | 
 | func (b *baseModuleContext) OtherModuleName(m blueprint.Module) string { | 
 | 	return b.bp.OtherModuleName(m) | 
 | } | 
 | func (b *baseModuleContext) OtherModuleDir(m blueprint.Module) string { return b.bp.OtherModuleDir(m) } | 
 | func (b *baseModuleContext) OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) { | 
 | 	b.bp.OtherModuleErrorf(m, fmt, args...) | 
 | } | 
 | func (b *baseModuleContext) OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag { | 
 | 	return b.bp.OtherModuleDependencyTag(m) | 
 | } | 
 | func (b *baseModuleContext) OtherModuleExists(name string) bool { return b.bp.OtherModuleExists(name) } | 
 | func (b *baseModuleContext) OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool { | 
 | 	return b.bp.OtherModuleDependencyVariantExists(variations, name) | 
 | } | 
 | func (b *baseModuleContext) OtherModuleFarDependencyVariantExists(variations []blueprint.Variation, name string) bool { | 
 | 	return b.bp.OtherModuleFarDependencyVariantExists(variations, name) | 
 | } | 
 | func (b *baseModuleContext) OtherModuleReverseDependencyVariantExists(name string) bool { | 
 | 	return b.bp.OtherModuleReverseDependencyVariantExists(name) | 
 | } | 
 | func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string { | 
 | 	return b.bp.OtherModuleType(m) | 
 | } | 
 | func (b *baseModuleContext) OtherModuleProvider(m blueprint.Module, provider blueprint.ProviderKey) interface{} { | 
 | 	return b.bp.OtherModuleProvider(m, provider) | 
 | } | 
 | func (b *baseModuleContext) OtherModuleHasProvider(m blueprint.Module, provider blueprint.ProviderKey) bool { | 
 | 	return b.bp.OtherModuleHasProvider(m, provider) | 
 | } | 
 | func (b *baseModuleContext) Provider(provider blueprint.ProviderKey) interface{} { | 
 | 	return b.bp.Provider(provider) | 
 | } | 
 | func (b *baseModuleContext) HasProvider(provider blueprint.ProviderKey) bool { | 
 | 	return b.bp.HasProvider(provider) | 
 | } | 
 | func (b *baseModuleContext) SetProvider(provider blueprint.ProviderKey, value interface{}) { | 
 | 	b.bp.SetProvider(provider, value) | 
 | } | 
 |  | 
 | func (b *baseModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module { | 
 | 	return b.bp.GetDirectDepWithTag(name, tag) | 
 | } | 
 |  | 
 | func (b *baseModuleContext) blueprintBaseModuleContext() blueprint.BaseModuleContext { | 
 | 	return b.bp | 
 | } | 
 |  | 
 | type moduleContext struct { | 
 | 	bp blueprint.ModuleContext | 
 | 	baseModuleContext | 
 | 	packagingSpecs  []PackagingSpec | 
 | 	installFiles    InstallPaths | 
 | 	checkbuildFiles Paths | 
 | 	module          Module | 
 | 	phonies         map[string]Paths | 
 |  | 
 | 	katiInstalls []katiInstall | 
 | 	katiSymlinks []katiInstall | 
 |  | 
 | 	// For tests | 
 | 	buildParams []BuildParams | 
 | 	ruleParams  map[blueprint.Rule]blueprint.RuleParams | 
 | 	variables   map[string]string | 
 | } | 
 |  | 
 | // katiInstall stores a request from Soong to Make to create an install rule. | 
 | type katiInstall struct { | 
 | 	from          Path | 
 | 	to            InstallPath | 
 | 	implicitDeps  Paths | 
 | 	orderOnlyDeps Paths | 
 | 	executable    bool | 
 | 	extraFiles    *extraFilesZip | 
 |  | 
 | 	absFrom string | 
 | } | 
 |  | 
 | type extraFilesZip struct { | 
 | 	zip Path | 
 | 	dir InstallPath | 
 | } | 
 |  | 
 | type katiInstalls []katiInstall | 
 |  | 
 | // BuiltInstalled returns the katiInstalls in the form used by $(call copy-many-files) in Make, a | 
 | // space separated list of from:to tuples. | 
 | func (installs katiInstalls) BuiltInstalled() string { | 
 | 	sb := strings.Builder{} | 
 | 	for i, install := range installs { | 
 | 		if i != 0 { | 
 | 			sb.WriteRune(' ') | 
 | 		} | 
 | 		sb.WriteString(install.from.String()) | 
 | 		sb.WriteRune(':') | 
 | 		sb.WriteString(install.to.String()) | 
 | 	} | 
 | 	return sb.String() | 
 | } | 
 |  | 
 | // InstallPaths returns the install path of each entry. | 
 | func (installs katiInstalls) InstallPaths() InstallPaths { | 
 | 	paths := make(InstallPaths, 0, len(installs)) | 
 | 	for _, install := range installs { | 
 | 		paths = append(paths, install.to) | 
 | 	} | 
 | 	return paths | 
 | } | 
 |  | 
 | func (m *moduleContext) ninjaError(params BuildParams, err error) (PackageContext, BuildParams) { | 
 | 	return pctx, BuildParams{ | 
 | 		Rule:            ErrorRule, | 
 | 		Description:     params.Description, | 
 | 		Output:          params.Output, | 
 | 		Outputs:         params.Outputs, | 
 | 		ImplicitOutput:  params.ImplicitOutput, | 
 | 		ImplicitOutputs: params.ImplicitOutputs, | 
 | 		Args: map[string]string{ | 
 | 			"error": err.Error(), | 
 | 		}, | 
 | 	} | 
 | } | 
 |  | 
 | func (m *moduleContext) ModuleBuild(pctx PackageContext, params ModuleBuildParams) { | 
 | 	m.Build(pctx, BuildParams(params)) | 
 | } | 
 |  | 
 | func validateBuildParams(params blueprint.BuildParams) error { | 
 | 	// Validate that the symlink outputs are declared outputs or implicit outputs | 
 | 	allOutputs := map[string]bool{} | 
 | 	for _, output := range params.Outputs { | 
 | 		allOutputs[output] = true | 
 | 	} | 
 | 	for _, output := range params.ImplicitOutputs { | 
 | 		allOutputs[output] = true | 
 | 	} | 
 | 	for _, symlinkOutput := range params.SymlinkOutputs { | 
 | 		if !allOutputs[symlinkOutput] { | 
 | 			return fmt.Errorf( | 
 | 				"Symlink output %s is not a declared output or implicit output", | 
 | 				symlinkOutput) | 
 | 		} | 
 | 	} | 
 | 	return nil | 
 | } | 
 |  | 
 | // Convert build parameters from their concrete Android types into their string representations, | 
 | // and combine the singular and plural fields of the same type (e.g. Output and Outputs). | 
 | func convertBuildParams(params BuildParams) blueprint.BuildParams { | 
 | 	bparams := blueprint.BuildParams{ | 
 | 		Rule:            params.Rule, | 
 | 		Description:     params.Description, | 
 | 		Deps:            params.Deps, | 
 | 		Outputs:         params.Outputs.Strings(), | 
 | 		ImplicitOutputs: params.ImplicitOutputs.Strings(), | 
 | 		SymlinkOutputs:  params.SymlinkOutputs.Strings(), | 
 | 		Inputs:          params.Inputs.Strings(), | 
 | 		Implicits:       params.Implicits.Strings(), | 
 | 		OrderOnly:       params.OrderOnly.Strings(), | 
 | 		Validations:     params.Validations.Strings(), | 
 | 		Args:            params.Args, | 
 | 		Optional:        !params.Default, | 
 | 	} | 
 |  | 
 | 	if params.Depfile != nil { | 
 | 		bparams.Depfile = params.Depfile.String() | 
 | 	} | 
 | 	if params.Output != nil { | 
 | 		bparams.Outputs = append(bparams.Outputs, params.Output.String()) | 
 | 	} | 
 | 	if params.SymlinkOutput != nil { | 
 | 		bparams.SymlinkOutputs = append(bparams.SymlinkOutputs, params.SymlinkOutput.String()) | 
 | 	} | 
 | 	if params.ImplicitOutput != nil { | 
 | 		bparams.ImplicitOutputs = append(bparams.ImplicitOutputs, params.ImplicitOutput.String()) | 
 | 	} | 
 | 	if params.Input != nil { | 
 | 		bparams.Inputs = append(bparams.Inputs, params.Input.String()) | 
 | 	} | 
 | 	if params.Implicit != nil { | 
 | 		bparams.Implicits = append(bparams.Implicits, params.Implicit.String()) | 
 | 	} | 
 | 	if params.Validation != nil { | 
 | 		bparams.Validations = append(bparams.Validations, params.Validation.String()) | 
 | 	} | 
 |  | 
 | 	bparams.Outputs = proptools.NinjaEscapeList(bparams.Outputs) | 
 | 	bparams.ImplicitOutputs = proptools.NinjaEscapeList(bparams.ImplicitOutputs) | 
 | 	bparams.SymlinkOutputs = proptools.NinjaEscapeList(bparams.SymlinkOutputs) | 
 | 	bparams.Inputs = proptools.NinjaEscapeList(bparams.Inputs) | 
 | 	bparams.Implicits = proptools.NinjaEscapeList(bparams.Implicits) | 
 | 	bparams.OrderOnly = proptools.NinjaEscapeList(bparams.OrderOnly) | 
 | 	bparams.Validations = proptools.NinjaEscapeList(bparams.Validations) | 
 | 	bparams.Depfile = proptools.NinjaEscape(bparams.Depfile) | 
 |  | 
 | 	return bparams | 
 | } | 
 |  | 
 | func (m *moduleContext) Variable(pctx PackageContext, name, value string) { | 
 | 	if m.config.captureBuild { | 
 | 		m.variables[name] = value | 
 | 	} | 
 |  | 
 | 	m.bp.Variable(pctx.PackageContext, name, value) | 
 | } | 
 |  | 
 | func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams, | 
 | 	argNames ...string) blueprint.Rule { | 
 |  | 
 | 	if m.config.UseRemoteBuild() { | 
 | 		if params.Pool == nil { | 
 | 			// When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict | 
 | 			// jobs to the local parallelism value | 
 | 			params.Pool = localPool | 
 | 		} else if params.Pool == remotePool { | 
 | 			// remotePool is a fake pool used to identify rule that are supported for remoting. If the rule's | 
 | 			// pool is the remotePool, replace with nil so that ninja runs it at NINJA_REMOTE_NUM_JOBS | 
 | 			// parallelism. | 
 | 			params.Pool = nil | 
 | 		} | 
 | 	} | 
 |  | 
 | 	rule := m.bp.Rule(pctx.PackageContext, name, params, argNames...) | 
 |  | 
 | 	if m.config.captureBuild { | 
 | 		m.ruleParams[rule] = params | 
 | 	} | 
 |  | 
 | 	return rule | 
 | } | 
 |  | 
 | func (m *moduleContext) Build(pctx PackageContext, params BuildParams) { | 
 | 	if params.Description != "" { | 
 | 		params.Description = "${moduleDesc}" + params.Description + "${moduleDescSuffix}" | 
 | 	} | 
 |  | 
 | 	if missingDeps := m.GetMissingDependencies(); len(missingDeps) > 0 { | 
 | 		pctx, params = m.ninjaError(params, fmt.Errorf("module %s missing dependencies: %s\n", | 
 | 			m.ModuleName(), strings.Join(missingDeps, ", "))) | 
 | 	} | 
 |  | 
 | 	if m.config.captureBuild { | 
 | 		m.buildParams = append(m.buildParams, params) | 
 | 	} | 
 |  | 
 | 	bparams := convertBuildParams(params) | 
 | 	err := validateBuildParams(bparams) | 
 | 	if err != nil { | 
 | 		m.ModuleErrorf( | 
 | 			"%s: build parameter validation failed: %s", | 
 | 			m.ModuleName(), | 
 | 			err.Error()) | 
 | 	} | 
 | 	m.bp.Build(pctx.PackageContext, bparams) | 
 | } | 
 |  | 
 | func (m *moduleContext) Phony(name string, deps ...Path) { | 
 | 	addPhony(m.config, name, deps...) | 
 | } | 
 |  | 
 | func (m *moduleContext) GetMissingDependencies() []string { | 
 | 	var missingDeps []string | 
 | 	missingDeps = append(missingDeps, m.Module().base().commonProperties.MissingDeps...) | 
 | 	missingDeps = append(missingDeps, m.bp.GetMissingDependencies()...) | 
 | 	missingDeps = FirstUniqueStrings(missingDeps) | 
 | 	return missingDeps | 
 | } | 
 |  | 
 | func (b *baseModuleContext) AddMissingDependencies(deps []string) { | 
 | 	if deps != nil { | 
 | 		missingDeps := &b.Module().base().commonProperties.MissingDeps | 
 | 		*missingDeps = append(*missingDeps, deps...) | 
 | 		*missingDeps = FirstUniqueStrings(*missingDeps) | 
 | 	} | 
 | } | 
 |  | 
 | func (b *baseModuleContext) checkedMissingDeps() bool { | 
 | 	return b.Module().base().commonProperties.CheckedMissingDeps | 
 | } | 
 |  | 
 | func (b *baseModuleContext) getMissingDependencies() []string { | 
 | 	checked := &b.Module().base().commonProperties.CheckedMissingDeps | 
 | 	*checked = true | 
 | 	var missingDeps []string | 
 | 	missingDeps = append(missingDeps, b.Module().base().commonProperties.MissingDeps...) | 
 | 	missingDeps = append(missingDeps, b.bp.EarlyGetMissingDependencies()...) | 
 | 	missingDeps = FirstUniqueStrings(missingDeps) | 
 | 	return missingDeps | 
 | } | 
 |  | 
 | type AllowDisabledModuleDependency interface { | 
 | 	blueprint.DependencyTag | 
 | 	AllowDisabledModuleDependency(target Module) bool | 
 | } | 
 |  | 
 | func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, tag blueprint.DependencyTag, strict bool) Module { | 
 | 	aModule, _ := module.(Module) | 
 |  | 
 | 	if !strict { | 
 | 		return aModule | 
 | 	} | 
 |  | 
 | 	if aModule == nil { | 
 | 		b.ModuleErrorf("module %q (%#v) not an android module", b.OtherModuleName(module), tag) | 
 | 		return nil | 
 | 	} | 
 |  | 
 | 	if !aModule.Enabled() { | 
 | 		if t, ok := tag.(AllowDisabledModuleDependency); !ok || !t.AllowDisabledModuleDependency(aModule) { | 
 | 			if b.Config().AllowMissingDependencies() { | 
 | 				b.AddMissingDependencies([]string{b.OtherModuleName(aModule)}) | 
 | 			} else { | 
 | 				b.ModuleErrorf("depends on disabled module %q", b.OtherModuleName(aModule)) | 
 | 			} | 
 | 		} | 
 | 		return nil | 
 | 	} | 
 | 	return aModule | 
 | } | 
 |  | 
 | type dep struct { | 
 | 	mod blueprint.Module | 
 | 	tag blueprint.DependencyTag | 
 | } | 
 |  | 
 | func (b *baseModuleContext) getDirectDepsInternal(name string, tag blueprint.DependencyTag) []dep { | 
 | 	var deps []dep | 
 | 	b.VisitDirectDepsBlueprint(func(module blueprint.Module) { | 
 | 		if aModule, _ := module.(Module); aModule != nil { | 
 | 			if aModule.base().BaseModuleName() == name { | 
 | 				returnedTag := b.bp.OtherModuleDependencyTag(aModule) | 
 | 				if tag == nil || returnedTag == tag { | 
 | 					deps = append(deps, dep{aModule, returnedTag}) | 
 | 				} | 
 | 			} | 
 | 		} else if b.bp.OtherModuleName(module) == name { | 
 | 			returnedTag := b.bp.OtherModuleDependencyTag(module) | 
 | 			if tag == nil || returnedTag == tag { | 
 | 				deps = append(deps, dep{module, returnedTag}) | 
 | 			} | 
 | 		} | 
 | 	}) | 
 | 	return deps | 
 | } | 
 |  | 
 | func (b *baseModuleContext) getDirectDepInternal(name string, tag blueprint.DependencyTag) (blueprint.Module, blueprint.DependencyTag) { | 
 | 	deps := b.getDirectDepsInternal(name, tag) | 
 | 	if len(deps) == 1 { | 
 | 		return deps[0].mod, deps[0].tag | 
 | 	} else if len(deps) >= 2 { | 
 | 		panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q", | 
 | 			name, b.ModuleName())) | 
 | 	} else { | 
 | 		return nil, nil | 
 | 	} | 
 | } | 
 |  | 
 | func (b *baseModuleContext) getDirectDepFirstTag(name string) (blueprint.Module, blueprint.DependencyTag) { | 
 | 	foundDeps := b.getDirectDepsInternal(name, nil) | 
 | 	deps := map[blueprint.Module]bool{} | 
 | 	for _, dep := range foundDeps { | 
 | 		deps[dep.mod] = true | 
 | 	} | 
 | 	if len(deps) == 1 { | 
 | 		return foundDeps[0].mod, foundDeps[0].tag | 
 | 	} else if len(deps) >= 2 { | 
 | 		// this could happen if two dependencies have the same name in different namespaces | 
 | 		// TODO(b/186554727): this should not occur if namespaces are handled within | 
 | 		// getDirectDepsInternal. | 
 | 		panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q", | 
 | 			name, b.ModuleName())) | 
 | 	} else { | 
 | 		return nil, nil | 
 | 	} | 
 | } | 
 |  | 
 | func (b *baseModuleContext) GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module { | 
 | 	var deps []Module | 
 | 	b.VisitDirectDepsBlueprint(func(module blueprint.Module) { | 
 | 		if aModule, _ := module.(Module); aModule != nil { | 
 | 			if b.bp.OtherModuleDependencyTag(aModule) == tag { | 
 | 				deps = append(deps, aModule) | 
 | 			} | 
 | 		} | 
 | 	}) | 
 | 	return deps | 
 | } | 
 |  | 
 | func (m *moduleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module { | 
 | 	module, _ := m.getDirectDepInternal(name, tag) | 
 | 	return module | 
 | } | 
 |  | 
 | // GetDirectDep returns the Module and DependencyTag for the direct dependency with the specified | 
 | // name, or nil if none exists. If there are multiple dependencies on the same module it returns the | 
 | // first DependencyTag. | 
 | func (b *baseModuleContext) GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) { | 
 | 	return b.getDirectDepFirstTag(name) | 
 | } | 
 |  | 
 | func (b *baseModuleContext) ModuleFromName(name string) (blueprint.Module, bool) { | 
 | 	if !b.isBazelConversionMode() { | 
 | 		panic("cannot call ModuleFromName if not in bazel conversion mode") | 
 | 	} | 
 | 	var m blueprint.Module | 
 | 	var ok bool | 
 | 	if moduleName, _ := SrcIsModuleWithTag(name); moduleName != "" { | 
 | 		m, ok = b.bp.ModuleFromName(moduleName) | 
 | 	} else { | 
 | 		m, ok = b.bp.ModuleFromName(name) | 
 | 	} | 
 | 	if !ok { | 
 | 		return m, ok | 
 | 	} | 
 | 	// If this module is not preferred, tried to get the prebuilt version instead | 
 | 	if a, aOk := m.(Module); aOk && !IsModulePrebuilt(a) && !IsModulePreferred(a) { | 
 | 		return b.ModuleFromName("prebuilt_" + name) | 
 | 	} | 
 | 	return m, ok | 
 | } | 
 |  | 
 | func (b *baseModuleContext) VisitDirectDepsBlueprint(visit func(blueprint.Module)) { | 
 | 	b.bp.VisitDirectDeps(visit) | 
 | } | 
 |  | 
 | func (b *baseModuleContext) VisitDirectDeps(visit func(Module)) { | 
 | 	b.bp.VisitDirectDeps(func(module blueprint.Module) { | 
 | 		if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil { | 
 | 			visit(aModule) | 
 | 		} | 
 | 	}) | 
 | } | 
 |  | 
 | func (b *baseModuleContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) { | 
 | 	b.bp.VisitDirectDeps(func(module blueprint.Module) { | 
 | 		if b.bp.OtherModuleDependencyTag(module) == tag { | 
 | 			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil { | 
 | 				visit(aModule) | 
 | 			} | 
 | 		} | 
 | 	}) | 
 | } | 
 |  | 
 | func (b *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) { | 
 | 	b.bp.VisitDirectDepsIf( | 
 | 		// pred | 
 | 		func(module blueprint.Module) bool { | 
 | 			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil { | 
 | 				return pred(aModule) | 
 | 			} else { | 
 | 				return false | 
 | 			} | 
 | 		}, | 
 | 		// visit | 
 | 		func(module blueprint.Module) { | 
 | 			visit(module.(Module)) | 
 | 		}) | 
 | } | 
 |  | 
 | func (b *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) { | 
 | 	b.bp.VisitDepsDepthFirst(func(module blueprint.Module) { | 
 | 		if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil { | 
 | 			visit(aModule) | 
 | 		} | 
 | 	}) | 
 | } | 
 |  | 
 | func (b *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) { | 
 | 	b.bp.VisitDepsDepthFirstIf( | 
 | 		// pred | 
 | 		func(module blueprint.Module) bool { | 
 | 			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil { | 
 | 				return pred(aModule) | 
 | 			} else { | 
 | 				return false | 
 | 			} | 
 | 		}, | 
 | 		// visit | 
 | 		func(module blueprint.Module) { | 
 | 			visit(module.(Module)) | 
 | 		}) | 
 | } | 
 |  | 
 | func (b *baseModuleContext) WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool) { | 
 | 	b.bp.WalkDeps(visit) | 
 | } | 
 |  | 
 | func (b *baseModuleContext) WalkDeps(visit func(Module, Module) bool) { | 
 | 	b.walkPath = []Module{b.Module()} | 
 | 	b.tagPath = []blueprint.DependencyTag{} | 
 | 	b.bp.WalkDeps(func(child, parent blueprint.Module) bool { | 
 | 		childAndroidModule, _ := child.(Module) | 
 | 		parentAndroidModule, _ := parent.(Module) | 
 | 		if childAndroidModule != nil && parentAndroidModule != nil { | 
 | 			// record walkPath before visit | 
 | 			for b.walkPath[len(b.walkPath)-1] != parentAndroidModule { | 
 | 				b.walkPath = b.walkPath[0 : len(b.walkPath)-1] | 
 | 				b.tagPath = b.tagPath[0 : len(b.tagPath)-1] | 
 | 			} | 
 | 			b.walkPath = append(b.walkPath, childAndroidModule) | 
 | 			b.tagPath = append(b.tagPath, b.OtherModuleDependencyTag(childAndroidModule)) | 
 | 			return visit(childAndroidModule, parentAndroidModule) | 
 | 		} else { | 
 | 			return false | 
 | 		} | 
 | 	}) | 
 | } | 
 |  | 
 | func (b *baseModuleContext) GetWalkPath() []Module { | 
 | 	return b.walkPath | 
 | } | 
 |  | 
 | func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag { | 
 | 	return b.tagPath | 
 | } | 
 |  | 
 | func (b *baseModuleContext) VisitAllModuleVariants(visit func(Module)) { | 
 | 	b.bp.VisitAllModuleVariants(func(module blueprint.Module) { | 
 | 		visit(module.(Module)) | 
 | 	}) | 
 | } | 
 |  | 
 | func (b *baseModuleContext) PrimaryModule() Module { | 
 | 	return b.bp.PrimaryModule().(Module) | 
 | } | 
 |  | 
 | func (b *baseModuleContext) FinalModule() Module { | 
 | 	return b.bp.FinalModule().(Module) | 
 | } | 
 |  | 
 | // IsMetaDependencyTag returns true for cross-cutting metadata dependencies. | 
 | func IsMetaDependencyTag(tag blueprint.DependencyTag) bool { | 
 | 	if tag == licenseKindTag { | 
 | 		return true | 
 | 	} else if tag == licensesTag { | 
 | 		return true | 
 | 	} | 
 | 	return false | 
 | } | 
 |  | 
 | // A regexp for removing boilerplate from BaseDependencyTag from the string representation of | 
 | // a dependency tag. | 
 | var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:{}\E(, )?`) | 
 |  | 
 | // PrettyPrintTag returns string representation of the tag, but prefers | 
 | // custom String() method if available. | 
 | func PrettyPrintTag(tag blueprint.DependencyTag) string { | 
 | 	// Use tag's custom String() method if available. | 
 | 	if stringer, ok := tag.(fmt.Stringer); ok { | 
 | 		return stringer.String() | 
 | 	} | 
 |  | 
 | 	// Otherwise, get a default string representation of the tag's struct. | 
 | 	tagString := fmt.Sprintf("%T: %+v", tag, tag) | 
 |  | 
 | 	// Remove the boilerplate from BaseDependencyTag as it adds no value. | 
 | 	tagString = tagCleaner.ReplaceAllString(tagString, "") | 
 | 	return tagString | 
 | } | 
 |  | 
 | func (b *baseModuleContext) GetPathString(skipFirst bool) string { | 
 | 	sb := strings.Builder{} | 
 | 	tagPath := b.GetTagPath() | 
 | 	walkPath := b.GetWalkPath() | 
 | 	if !skipFirst { | 
 | 		sb.WriteString(walkPath[0].String()) | 
 | 	} | 
 | 	for i, m := range walkPath[1:] { | 
 | 		sb.WriteString("\n") | 
 | 		sb.WriteString(fmt.Sprintf("           via tag %s\n", PrettyPrintTag(tagPath[i]))) | 
 | 		sb.WriteString(fmt.Sprintf("    -> %s", m.String())) | 
 | 	} | 
 | 	return sb.String() | 
 | } | 
 |  | 
 | func (m *moduleContext) ModuleSubDir() string { | 
 | 	return m.bp.ModuleSubDir() | 
 | } | 
 |  | 
 | func (m *moduleContext) SoongConfigTraceHash() string { | 
 | 	return m.module.base().commonProperties.SoongConfigTraceHash | 
 | } | 
 |  | 
 | func (b *baseModuleContext) Target() Target { | 
 | 	return b.target | 
 | } | 
 |  | 
 | func (b *baseModuleContext) TargetPrimary() bool { | 
 | 	return b.targetPrimary | 
 | } | 
 |  | 
 | func (b *baseModuleContext) MultiTargets() []Target { | 
 | 	return b.multiTargets | 
 | } | 
 |  | 
 | func (b *baseModuleContext) Arch() Arch { | 
 | 	return b.target.Arch | 
 | } | 
 |  | 
 | func (b *baseModuleContext) Os() OsType { | 
 | 	return b.os | 
 | } | 
 |  | 
 | func (b *baseModuleContext) Host() bool { | 
 | 	return b.os.Class == Host | 
 | } | 
 |  | 
 | func (b *baseModuleContext) Device() bool { | 
 | 	return b.os.Class == Device | 
 | } | 
 |  | 
 | func (b *baseModuleContext) Darwin() bool { | 
 | 	return b.os == Darwin | 
 | } | 
 |  | 
 | func (b *baseModuleContext) Windows() bool { | 
 | 	return b.os == Windows | 
 | } | 
 |  | 
 | func (b *baseModuleContext) Debug() bool { | 
 | 	return b.debug | 
 | } | 
 |  | 
 | func (b *baseModuleContext) PrimaryArch() bool { | 
 | 	if len(b.config.Targets[b.target.Os]) <= 1 { | 
 | 		return true | 
 | 	} | 
 | 	return b.target.Arch.ArchType == b.config.Targets[b.target.Os][0].Arch.ArchType | 
 | } | 
 |  | 
 | // Makes this module a platform module, i.e. not specific to soc, device, | 
 | // product, or system_ext. | 
 | func (m *ModuleBase) MakeAsPlatform() { | 
 | 	m.commonProperties.Vendor = boolPtr(false) | 
 | 	m.commonProperties.Proprietary = boolPtr(false) | 
 | 	m.commonProperties.Soc_specific = boolPtr(false) | 
 | 	m.commonProperties.Product_specific = boolPtr(false) | 
 | 	m.commonProperties.System_ext_specific = boolPtr(false) | 
 | } | 
 |  | 
 | func (m *ModuleBase) MakeAsSystemExt() { | 
 | 	m.commonProperties.Vendor = boolPtr(false) | 
 | 	m.commonProperties.Proprietary = boolPtr(false) | 
 | 	m.commonProperties.Soc_specific = boolPtr(false) | 
 | 	m.commonProperties.Product_specific = boolPtr(false) | 
 | 	m.commonProperties.System_ext_specific = boolPtr(true) | 
 | } | 
 |  | 
 | // IsNativeBridgeSupported returns true if "native_bridge_supported" is explicitly set as "true" | 
 | func (m *ModuleBase) IsNativeBridgeSupported() bool { | 
 | 	return proptools.Bool(m.commonProperties.Native_bridge_supported) | 
 | } | 
 |  | 
 | func (m *moduleContext) InstallInData() bool { | 
 | 	return m.module.InstallInData() | 
 | } | 
 |  | 
 | func (m *moduleContext) InstallInTestcases() bool { | 
 | 	return m.module.InstallInTestcases() | 
 | } | 
 |  | 
 | func (m *moduleContext) InstallInSanitizerDir() bool { | 
 | 	return m.module.InstallInSanitizerDir() | 
 | } | 
 |  | 
 | func (m *moduleContext) InstallInRamdisk() bool { | 
 | 	return m.module.InstallInRamdisk() | 
 | } | 
 |  | 
 | func (m *moduleContext) InstallInVendorRamdisk() bool { | 
 | 	return m.module.InstallInVendorRamdisk() | 
 | } | 
 |  | 
 | func (m *moduleContext) InstallInDebugRamdisk() bool { | 
 | 	return m.module.InstallInDebugRamdisk() | 
 | } | 
 |  | 
 | func (m *moduleContext) InstallInRecovery() bool { | 
 | 	return m.module.InstallInRecovery() | 
 | } | 
 |  | 
 | func (m *moduleContext) InstallInRoot() bool { | 
 | 	return m.module.InstallInRoot() | 
 | } | 
 |  | 
 | func (m *moduleContext) InstallForceOS() (*OsType, *ArchType) { | 
 | 	return m.module.InstallForceOS() | 
 | } | 
 |  | 
 | func (m *moduleContext) InstallInVendor() bool { | 
 | 	return m.module.InstallInVendor() | 
 | } | 
 |  | 
 | func (m *moduleContext) skipInstall() bool { | 
 | 	if m.module.base().commonProperties.SkipInstall { | 
 | 		return true | 
 | 	} | 
 |  | 
 | 	if m.module.base().commonProperties.HideFromMake { | 
 | 		return true | 
 | 	} | 
 |  | 
 | 	// We'll need a solution for choosing which of modules with the same name in different | 
 | 	// namespaces to install.  For now, reuse the list of namespaces exported to Make as the | 
 | 	// list of namespaces to install in a Soong-only build. | 
 | 	if !m.module.base().commonProperties.NamespaceExportedToMake { | 
 | 		return true | 
 | 	} | 
 |  | 
 | 	return false | 
 | } | 
 |  | 
 | func (m *moduleContext) InstallFile(installPath InstallPath, name string, srcPath Path, | 
 | 	deps ...Path) InstallPath { | 
 | 	return m.installFile(installPath, name, srcPath, deps, false, nil) | 
 | } | 
 |  | 
 | func (m *moduleContext) InstallExecutable(installPath InstallPath, name string, srcPath Path, | 
 | 	deps ...Path) InstallPath { | 
 | 	return m.installFile(installPath, name, srcPath, deps, true, nil) | 
 | } | 
 |  | 
 | func (m *moduleContext) InstallFileWithExtraFilesZip(installPath InstallPath, name string, srcPath Path, | 
 | 	extraZip Path, deps ...Path) InstallPath { | 
 | 	return m.installFile(installPath, name, srcPath, deps, false, &extraFilesZip{ | 
 | 		zip: extraZip, | 
 | 		dir: installPath, | 
 | 	}) | 
 | } | 
 |  | 
 | func (m *moduleContext) PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec { | 
 | 	fullInstallPath := installPath.Join(m, name) | 
 | 	return m.packageFile(fullInstallPath, srcPath, false) | 
 | } | 
 |  | 
 | func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, executable bool) PackagingSpec { | 
 | 	licenseFiles := m.Module().EffectiveLicenseFiles() | 
 | 	spec := PackagingSpec{ | 
 | 		relPathInPackage:      Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()), | 
 | 		srcPath:               srcPath, | 
 | 		symlinkTarget:         "", | 
 | 		executable:            executable, | 
 | 		effectiveLicenseFiles: &licenseFiles, | 
 | 		partition:             fullInstallPath.partition, | 
 | 	} | 
 | 	m.packagingSpecs = append(m.packagingSpecs, spec) | 
 | 	return spec | 
 | } | 
 |  | 
 | func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []Path, | 
 | 	executable bool, extraZip *extraFilesZip) InstallPath { | 
 |  | 
 | 	fullInstallPath := installPath.Join(m, name) | 
 | 	m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, false) | 
 |  | 
 | 	if !m.skipInstall() { | 
 | 		deps = append(deps, InstallPaths(m.module.base().installFilesDepSet.ToList()).Paths()...) | 
 |  | 
 | 		var implicitDeps, orderOnlyDeps Paths | 
 |  | 
 | 		if m.Host() { | 
 | 			// Installed host modules might be used during the build, depend directly on their | 
 | 			// dependencies so their timestamp is updated whenever their dependency is updated | 
 | 			implicitDeps = deps | 
 | 		} else { | 
 | 			orderOnlyDeps = deps | 
 | 		} | 
 |  | 
 | 		if m.Config().KatiEnabled() { | 
 | 			// When creating the install rule in Soong but embedding in Make, write the rule to a | 
 | 			// makefile instead of directly to the ninja file so that main.mk can add the | 
 | 			// dependencies from the `required` property that are hard to resolve in Soong. | 
 | 			m.katiInstalls = append(m.katiInstalls, katiInstall{ | 
 | 				from:          srcPath, | 
 | 				to:            fullInstallPath, | 
 | 				implicitDeps:  implicitDeps, | 
 | 				orderOnlyDeps: orderOnlyDeps, | 
 | 				executable:    executable, | 
 | 				extraFiles:    extraZip, | 
 | 			}) | 
 | 		} else { | 
 | 			rule := Cp | 
 | 			if executable { | 
 | 				rule = CpExecutable | 
 | 			} | 
 |  | 
 | 			extraCmds := "" | 
 | 			if extraZip != nil { | 
 | 				extraCmds += fmt.Sprintf(" && ( unzip -qDD -d '%s' '%s' 2>&1 | grep -v \"zipfile is empty\"; exit $${PIPESTATUS[0]} )", | 
 | 					extraZip.dir.String(), extraZip.zip.String()) | 
 | 				extraCmds += " || ( code=$$?; if [ $$code -ne 0 -a $$code -ne 1 ]; then exit $$code; fi )" | 
 | 				implicitDeps = append(implicitDeps, extraZip.zip) | 
 | 			} | 
 |  | 
 | 			m.Build(pctx, BuildParams{ | 
 | 				Rule:        rule, | 
 | 				Description: "install " + fullInstallPath.Base(), | 
 | 				Output:      fullInstallPath, | 
 | 				Input:       srcPath, | 
 | 				Implicits:   implicitDeps, | 
 | 				OrderOnly:   orderOnlyDeps, | 
 | 				Default:     !m.Config().KatiEnabled(), | 
 | 				Args: map[string]string{ | 
 | 					"extraCmds": extraCmds, | 
 | 				}, | 
 | 			}) | 
 | 		} | 
 |  | 
 | 		m.installFiles = append(m.installFiles, fullInstallPath) | 
 | 	} | 
 |  | 
 | 	m.packageFile(fullInstallPath, srcPath, executable) | 
 |  | 
 | 	m.checkbuildFiles = append(m.checkbuildFiles, srcPath) | 
 |  | 
 | 	return fullInstallPath | 
 | } | 
 |  | 
 | func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, srcPath InstallPath) InstallPath { | 
 | 	fullInstallPath := installPath.Join(m, name) | 
 | 	m.module.base().hooks.runInstallHooks(m, srcPath, fullInstallPath, true) | 
 |  | 
 | 	relPath, err := filepath.Rel(path.Dir(fullInstallPath.String()), srcPath.String()) | 
 | 	if err != nil { | 
 | 		panic(fmt.Sprintf("Unable to generate symlink between %q and %q: %s", fullInstallPath.Base(), srcPath.Base(), err)) | 
 | 	} | 
 | 	if !m.skipInstall() { | 
 |  | 
 | 		if m.Config().KatiEnabled() { | 
 | 			// When creating the symlink rule in Soong but embedding in Make, write the rule to a | 
 | 			// makefile instead of directly to the ninja file so that main.mk can add the | 
 | 			// dependencies from the `required` property that are hard to resolve in Soong. | 
 | 			m.katiSymlinks = append(m.katiSymlinks, katiInstall{ | 
 | 				from: srcPath, | 
 | 				to:   fullInstallPath, | 
 | 			}) | 
 | 		} else { | 
 | 			// The symlink doesn't need updating when the target is modified, but we sometimes | 
 | 			// have a dependency on a symlink to a binary instead of to the binary directly, and | 
 | 			// the mtime of the symlink must be updated when the binary is modified, so use a | 
 | 			// normal dependency here instead of an order-only dependency. | 
 | 			m.Build(pctx, BuildParams{ | 
 | 				Rule:        Symlink, | 
 | 				Description: "install symlink " + fullInstallPath.Base(), | 
 | 				Output:      fullInstallPath, | 
 | 				Input:       srcPath, | 
 | 				Default:     !m.Config().KatiEnabled(), | 
 | 				Args: map[string]string{ | 
 | 					"fromPath": relPath, | 
 | 				}, | 
 | 			}) | 
 | 		} | 
 |  | 
 | 		m.installFiles = append(m.installFiles, fullInstallPath) | 
 | 		m.checkbuildFiles = append(m.checkbuildFiles, srcPath) | 
 | 	} | 
 |  | 
 | 	m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{ | 
 | 		relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()), | 
 | 		srcPath:          nil, | 
 | 		symlinkTarget:    relPath, | 
 | 		executable:       false, | 
 | 		partition:        fullInstallPath.partition, | 
 | 	}) | 
 |  | 
 | 	return fullInstallPath | 
 | } | 
 |  | 
 | // installPath/name -> absPath where absPath might be a path that is available only at runtime | 
 | // (e.g. /apex/...) | 
 | func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name string, absPath string) InstallPath { | 
 | 	fullInstallPath := installPath.Join(m, name) | 
 | 	m.module.base().hooks.runInstallHooks(m, nil, fullInstallPath, true) | 
 |  | 
 | 	if !m.skipInstall() { | 
 | 		if m.Config().KatiEnabled() { | 
 | 			// When creating the symlink rule in Soong but embedding in Make, write the rule to a | 
 | 			// makefile instead of directly to the ninja file so that main.mk can add the | 
 | 			// dependencies from the `required` property that are hard to resolve in Soong. | 
 | 			m.katiSymlinks = append(m.katiSymlinks, katiInstall{ | 
 | 				absFrom: absPath, | 
 | 				to:      fullInstallPath, | 
 | 			}) | 
 | 		} else { | 
 | 			m.Build(pctx, BuildParams{ | 
 | 				Rule:        Symlink, | 
 | 				Description: "install symlink " + fullInstallPath.Base() + " -> " + absPath, | 
 | 				Output:      fullInstallPath, | 
 | 				Default:     !m.Config().KatiEnabled(), | 
 | 				Args: map[string]string{ | 
 | 					"fromPath": absPath, | 
 | 				}, | 
 | 			}) | 
 | 		} | 
 |  | 
 | 		m.installFiles = append(m.installFiles, fullInstallPath) | 
 | 	} | 
 |  | 
 | 	m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{ | 
 | 		relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()), | 
 | 		srcPath:          nil, | 
 | 		symlinkTarget:    absPath, | 
 | 		executable:       false, | 
 | 		partition:        fullInstallPath.partition, | 
 | 	}) | 
 |  | 
 | 	return fullInstallPath | 
 | } | 
 |  | 
 | func (m *moduleContext) CheckbuildFile(srcPath Path) { | 
 | 	m.checkbuildFiles = append(m.checkbuildFiles, srcPath) | 
 | } | 
 |  | 
 | func (m *moduleContext) blueprintModuleContext() blueprint.ModuleContext { | 
 | 	return m.bp | 
 | } | 
 |  | 
 | func (m *moduleContext) LicenseMetadataFile() Path { | 
 | 	return m.module.base().licenseMetadataFile | 
 | } | 
 |  | 
 | // SrcIsModule decodes module references in the format ":unqualified-name" or "//namespace:name" | 
 | // into the module name, or empty string if the input was not a module reference. | 
 | func SrcIsModule(s string) (module string) { | 
 | 	if len(s) > 1 { | 
 | 		if s[0] == ':' { | 
 | 			module = s[1:] | 
 | 			if !isUnqualifiedModuleName(module) { | 
 | 				// The module name should be unqualified but is not so do not treat it as a module. | 
 | 				module = "" | 
 | 			} | 
 | 		} else if s[0] == '/' && s[1] == '/' { | 
 | 			module = s | 
 | 		} | 
 | 	} | 
 | 	return module | 
 | } | 
 |  | 
 | // SrcIsModuleWithTag decodes module references in the format ":unqualified-name{.tag}" or | 
 | // "//namespace:name{.tag}" into the module name and tag, ":unqualified-name" or "//namespace:name" | 
 | // into the module name and an empty string for the tag, or empty strings if the input was not a | 
 | // module reference. | 
 | func SrcIsModuleWithTag(s string) (module, tag string) { | 
 | 	if len(s) > 1 { | 
 | 		if s[0] == ':' { | 
 | 			module = s[1:] | 
 | 		} else if s[0] == '/' && s[1] == '/' { | 
 | 			module = s | 
 | 		} | 
 |  | 
 | 		if module != "" { | 
 | 			if tagStart := strings.IndexByte(module, '{'); tagStart > 0 { | 
 | 				if module[len(module)-1] == '}' { | 
 | 					tag = module[tagStart+1 : len(module)-1] | 
 | 					module = module[:tagStart] | 
 | 				} | 
 | 			} | 
 |  | 
 | 			if s[0] == ':' && !isUnqualifiedModuleName(module) { | 
 | 				// The module name should be unqualified but is not so do not treat it as a module. | 
 | 				module = "" | 
 | 				tag = "" | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return module, tag | 
 | } | 
 |  | 
 | // isUnqualifiedModuleName makes sure that the supplied module is an unqualified module name, i.e. | 
 | // does not contain any /. | 
 | func isUnqualifiedModuleName(module string) bool { | 
 | 	return strings.IndexByte(module, '/') == -1 | 
 | } | 
 |  | 
 | // sourceOrOutputDependencyTag is the dependency tag added automatically by pathDepsMutator for any | 
 | // module reference in a property annotated with `android:"path"` or passed to ExtractSourceDeps | 
 | // or ExtractSourcesDeps. | 
 | // | 
 | // If uniquely identifies the dependency that was added as it contains both the module name used to | 
 | // add the dependency as well as the tag. That makes it very simple to find the matching dependency | 
 | // in GetModuleFromPathDep as all it needs to do is find the dependency whose tag matches the tag | 
 | // used to add it. It does not need to check that the module name as returned by one of | 
 | // Module.Name(), BaseModuleContext.OtherModuleName() or ModuleBase.BaseModuleName() matches the | 
 | // name supplied in the tag. That means it does not need to handle differences in module names | 
 | // caused by prebuilt_ prefix, or fully qualified module names. | 
 | type sourceOrOutputDependencyTag struct { | 
 | 	blueprint.BaseDependencyTag | 
 |  | 
 | 	// The name of the module. | 
 | 	moduleName string | 
 |  | 
 | 	// The tag that will be passed to the module's OutputFileProducer.OutputFiles(tag) method. | 
 | 	tag string | 
 | } | 
 |  | 
 | func sourceOrOutputDepTag(moduleName, tag string) blueprint.DependencyTag { | 
 | 	return sourceOrOutputDependencyTag{moduleName: moduleName, tag: tag} | 
 | } | 
 |  | 
 | // IsSourceDepTagWithOutputTag returns true if the supplied blueprint.DependencyTag is one that was | 
 | // used to add dependencies by either ExtractSourceDeps, ExtractSourcesDeps or automatically for | 
 | // properties tagged with `android:"path"` AND it was added using a module reference of | 
 | // :moduleName{outputTag}. | 
 | func IsSourceDepTagWithOutputTag(depTag blueprint.DependencyTag, outputTag string) bool { | 
 | 	t, ok := depTag.(sourceOrOutputDependencyTag) | 
 | 	return ok && t.tag == outputTag | 
 | } | 
 |  | 
 | // Adds necessary dependencies to satisfy filegroup or generated sources modules listed in srcFiles | 
 | // using ":module" syntax, if any. | 
 | // | 
 | // Deprecated: tag the property with `android:"path"` instead. | 
 | func ExtractSourcesDeps(ctx BottomUpMutatorContext, srcFiles []string) { | 
 | 	set := make(map[string]bool) | 
 |  | 
 | 	for _, s := range srcFiles { | 
 | 		if m, t := SrcIsModuleWithTag(s); m != "" { | 
 | 			if _, found := set[s]; found { | 
 | 				ctx.ModuleErrorf("found source dependency duplicate: %q!", s) | 
 | 			} else { | 
 | 				set[s] = true | 
 | 				ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(m, t), m) | 
 | 			} | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | // Adds necessary dependencies to satisfy filegroup or generated sources modules specified in s | 
 | // using ":module" syntax, if any. | 
 | // | 
 | // Deprecated: tag the property with `android:"path"` instead. | 
 | func ExtractSourceDeps(ctx BottomUpMutatorContext, s *string) { | 
 | 	if s != nil { | 
 | 		if m, t := SrcIsModuleWithTag(*s); m != "" { | 
 | 			ctx.AddDependency(ctx.Module(), sourceOrOutputDepTag(m, t), m) | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | // A module that implements SourceFileProducer can be referenced from any property that is tagged with `android:"path"` | 
 | // using the ":module" syntax and provides a list of paths to be used as if they were listed in the property. | 
 | type SourceFileProducer interface { | 
 | 	Srcs() Paths | 
 | } | 
 |  | 
 | // A module that implements OutputFileProducer can be referenced from any property that is tagged with `android:"path"` | 
 | // using the ":module" syntax or ":module{.tag}" syntax and provides a list of output files to be used as if they were | 
 | // listed in the property. | 
 | type OutputFileProducer interface { | 
 | 	OutputFiles(tag string) (Paths, error) | 
 | } | 
 |  | 
 | // OutputFilesForModule returns the paths from an OutputFileProducer with the given tag.  On error, including if the | 
 | // module produced zero paths, it reports errors to the ctx and returns nil. | 
 | func OutputFilesForModule(ctx PathContext, module blueprint.Module, tag string) Paths { | 
 | 	paths, err := outputFilesForModule(ctx, module, tag) | 
 | 	if err != nil { | 
 | 		reportPathError(ctx, err) | 
 | 		return nil | 
 | 	} | 
 | 	return paths | 
 | } | 
 |  | 
 | // OutputFileForModule returns the path from an OutputFileProducer with the given tag.  On error, including if the | 
 | // module produced zero or multiple paths, it reports errors to the ctx and returns nil. | 
 | func OutputFileForModule(ctx PathContext, module blueprint.Module, tag string) Path { | 
 | 	paths, err := outputFilesForModule(ctx, module, tag) | 
 | 	if err != nil { | 
 | 		reportPathError(ctx, err) | 
 | 		return nil | 
 | 	} | 
 | 	if len(paths) == 0 { | 
 | 		type addMissingDependenciesIntf interface { | 
 | 			AddMissingDependencies([]string) | 
 | 			OtherModuleName(blueprint.Module) string | 
 | 		} | 
 | 		if mctx, ok := ctx.(addMissingDependenciesIntf); ok && ctx.Config().AllowMissingDependencies() { | 
 | 			mctx.AddMissingDependencies([]string{mctx.OtherModuleName(module)}) | 
 | 		} else { | 
 | 			ReportPathErrorf(ctx, "failed to get output files from module %q", pathContextName(ctx, module)) | 
 | 		} | 
 | 		// Return a fake output file to avoid nil dereferences of Path objects later. | 
 | 		// This should never get used for an actual build as the error or missing | 
 | 		// dependency has already been reported. | 
 | 		p, err := pathForSource(ctx, filepath.Join("missing_output_file", pathContextName(ctx, module))) | 
 | 		if err != nil { | 
 | 			reportPathError(ctx, err) | 
 | 			return nil | 
 | 		} | 
 | 		return p | 
 | 	} | 
 | 	if len(paths) > 1 { | 
 | 		ReportPathErrorf(ctx, "got multiple output files from module %q, expected exactly one", | 
 | 			pathContextName(ctx, module)) | 
 | 	} | 
 | 	return paths[0] | 
 | } | 
 |  | 
 | func outputFilesForModule(ctx PathContext, module blueprint.Module, tag string) (Paths, error) { | 
 | 	if outputFileProducer, ok := module.(OutputFileProducer); ok { | 
 | 		paths, err := outputFileProducer.OutputFiles(tag) | 
 | 		if err != nil { | 
 | 			return nil, fmt.Errorf("failed to get output file from module %q: %s", | 
 | 				pathContextName(ctx, module), err.Error()) | 
 | 		} | 
 | 		return paths, nil | 
 | 	} else if sourceFileProducer, ok := module.(SourceFileProducer); ok { | 
 | 		if tag != "" { | 
 | 			return nil, fmt.Errorf("module %q is a SourceFileProducer, not an OutputFileProducer, and so does not support tag %q", pathContextName(ctx, module), tag) | 
 | 		} | 
 | 		paths := sourceFileProducer.Srcs() | 
 | 		return paths, nil | 
 | 	} else { | 
 | 		return nil, fmt.Errorf("module %q is not an OutputFileProducer", pathContextName(ctx, module)) | 
 | 	} | 
 | } | 
 |  | 
 | // Modules can implement HostToolProvider and return a valid OptionalPath from HostToolPath() to | 
 | // specify that they can be used as a tool by a genrule module. | 
 | type HostToolProvider interface { | 
 | 	Module | 
 | 	// HostToolPath returns the path to the host tool for the module if it is one, or an invalid | 
 | 	// OptionalPath. | 
 | 	HostToolPath() OptionalPath | 
 | } | 
 |  | 
 | // Returns a list of paths expanded from globs and modules referenced using ":module" syntax.  The property must | 
 | // be tagged with `android:"path" to support automatic source module dependency resolution. | 
 | // | 
 | // Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead. | 
 | func (m *moduleContext) ExpandSources(srcFiles, excludes []string) Paths { | 
 | 	return PathsForModuleSrcExcludes(m, srcFiles, excludes) | 
 | } | 
 |  | 
 | // Returns a single path expanded from globs and modules referenced using ":module" syntax.  The property must | 
 | // be tagged with `android:"path" to support automatic source module dependency resolution. | 
 | // | 
 | // Deprecated: use PathForModuleSrc instead. | 
 | func (m *moduleContext) ExpandSource(srcFile, _ string) Path { | 
 | 	return PathForModuleSrc(m, srcFile) | 
 | } | 
 |  | 
 | // Returns an optional single path expanded from globs and modules referenced using ":module" syntax if | 
 | // the srcFile is non-nil.  The property must be tagged with `android:"path" to support automatic source module | 
 | // dependency resolution. | 
 | func (m *moduleContext) ExpandOptionalSource(srcFile *string, _ string) OptionalPath { | 
 | 	if srcFile != nil { | 
 | 		return OptionalPathForPath(PathForModuleSrc(m, *srcFile)) | 
 | 	} | 
 | 	return OptionalPath{} | 
 | } | 
 |  | 
 | func (m *moduleContext) RequiredModuleNames() []string { | 
 | 	return m.module.RequiredModuleNames() | 
 | } | 
 |  | 
 | func (m *moduleContext) HostRequiredModuleNames() []string { | 
 | 	return m.module.HostRequiredModuleNames() | 
 | } | 
 |  | 
 | func (m *moduleContext) TargetRequiredModuleNames() []string { | 
 | 	return m.module.TargetRequiredModuleNames() | 
 | } | 
 |  | 
 | func init() { | 
 | 	RegisterParallelSingletonType("buildtarget", BuildTargetSingleton) | 
 | 	RegisterParallelSingletonType("soongconfigtrace", soongConfigTraceSingletonFunc) | 
 | 	FinalDepsMutators(registerSoongConfigTraceMutator) | 
 | } | 
 |  | 
 | func BuildTargetSingleton() Singleton { | 
 | 	return &buildTargetSingleton{} | 
 | } | 
 |  | 
 | func parentDir(dir string) string { | 
 | 	dir, _ = filepath.Split(dir) | 
 | 	return filepath.Clean(dir) | 
 | } | 
 |  | 
 | type buildTargetSingleton struct{} | 
 |  | 
 | func AddAncestors(ctx SingletonContext, dirMap map[string]Paths, mmName func(string) string) ([]string, []string) { | 
 | 	// Ensure ancestor directories are in dirMap | 
 | 	// Make directories build their direct subdirectories | 
 | 	// Returns a slice of all directories and a slice of top-level directories. | 
 | 	dirs := SortedKeys(dirMap) | 
 | 	for _, dir := range dirs { | 
 | 		dir := parentDir(dir) | 
 | 		for dir != "." && dir != "/" { | 
 | 			if _, exists := dirMap[dir]; exists { | 
 | 				break | 
 | 			} | 
 | 			dirMap[dir] = nil | 
 | 			dir = parentDir(dir) | 
 | 		} | 
 | 	} | 
 | 	dirs = SortedKeys(dirMap) | 
 | 	var topDirs []string | 
 | 	for _, dir := range dirs { | 
 | 		p := parentDir(dir) | 
 | 		if p != "." && p != "/" { | 
 | 			dirMap[p] = append(dirMap[p], PathForPhony(ctx, mmName(dir))) | 
 | 		} else if dir != "." && dir != "/" && dir != "" { | 
 | 			topDirs = append(topDirs, dir) | 
 | 		} | 
 | 	} | 
 | 	return SortedKeys(dirMap), topDirs | 
 | } | 
 |  | 
 | func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) { | 
 | 	var checkbuildDeps Paths | 
 |  | 
 | 	mmTarget := func(dir string) string { | 
 | 		return "MODULES-IN-" + strings.Replace(filepath.Clean(dir), "/", "-", -1) | 
 | 	} | 
 |  | 
 | 	modulesInDir := make(map[string]Paths) | 
 |  | 
 | 	ctx.VisitAllModules(func(module Module) { | 
 | 		blueprintDir := module.base().blueprintDir | 
 | 		installTarget := module.base().installTarget | 
 | 		checkbuildTarget := module.base().checkbuildTarget | 
 |  | 
 | 		if checkbuildTarget != nil { | 
 | 			checkbuildDeps = append(checkbuildDeps, checkbuildTarget) | 
 | 			modulesInDir[blueprintDir] = append(modulesInDir[blueprintDir], checkbuildTarget) | 
 | 		} | 
 |  | 
 | 		if installTarget != nil { | 
 | 			modulesInDir[blueprintDir] = append(modulesInDir[blueprintDir], installTarget) | 
 | 		} | 
 | 	}) | 
 |  | 
 | 	suffix := "" | 
 | 	if ctx.Config().KatiEnabled() { | 
 | 		suffix = "-soong" | 
 | 	} | 
 |  | 
 | 	// Create a top-level checkbuild target that depends on all modules | 
 | 	ctx.Phony("checkbuild"+suffix, checkbuildDeps...) | 
 |  | 
 | 	// Make will generate the MODULES-IN-* targets | 
 | 	if ctx.Config().KatiEnabled() { | 
 | 		return | 
 | 	} | 
 |  | 
 | 	dirs, _ := AddAncestors(ctx, modulesInDir, mmTarget) | 
 |  | 
 | 	// Create a MODULES-IN-<directory> target that depends on all modules in a directory, and | 
 | 	// depends on the MODULES-IN-* targets of all of its subdirectories that contain Android.bp | 
 | 	// files. | 
 | 	for _, dir := range dirs { | 
 | 		ctx.Phony(mmTarget(dir), modulesInDir[dir]...) | 
 | 	} | 
 |  | 
 | 	// Create (host|host-cross|target)-<OS> phony rules to build a reduced checkbuild. | 
 | 	type osAndCross struct { | 
 | 		os        OsType | 
 | 		hostCross bool | 
 | 	} | 
 | 	osDeps := map[osAndCross]Paths{} | 
 | 	ctx.VisitAllModules(func(module Module) { | 
 | 		if module.Enabled() { | 
 | 			key := osAndCross{os: module.Target().Os, hostCross: module.Target().HostCross} | 
 | 			osDeps[key] = append(osDeps[key], module.base().checkbuildFiles...) | 
 | 		} | 
 | 	}) | 
 |  | 
 | 	osClass := make(map[string]Paths) | 
 | 	for key, deps := range osDeps { | 
 | 		var className string | 
 |  | 
 | 		switch key.os.Class { | 
 | 		case Host: | 
 | 			if key.hostCross { | 
 | 				className = "host-cross" | 
 | 			} else { | 
 | 				className = "host" | 
 | 			} | 
 | 		case Device: | 
 | 			className = "target" | 
 | 		default: | 
 | 			continue | 
 | 		} | 
 |  | 
 | 		name := className + "-" + key.os.Name | 
 | 		osClass[className] = append(osClass[className], PathForPhony(ctx, name)) | 
 |  | 
 | 		ctx.Phony(name, deps...) | 
 | 	} | 
 |  | 
 | 	// Wrap those into host|host-cross|target phony rules | 
 | 	for _, class := range SortedKeys(osClass) { | 
 | 		ctx.Phony(class, osClass[class]...) | 
 | 	} | 
 | } | 
 |  | 
 | // Collect information for opening IDE project files in java/jdeps.go. | 
 | type IDEInfo interface { | 
 | 	IDEInfo(ideInfo *IdeInfo) | 
 | 	BaseModuleName() string | 
 | } | 
 |  | 
 | // Extract the base module name from the Import name. | 
 | // Often the Import name has a prefix "prebuilt_". | 
 | // Remove the prefix explicitly if needed | 
 | // until we find a better solution to get the Import name. | 
 | type IDECustomizedModuleName interface { | 
 | 	IDECustomizedModuleName() string | 
 | } | 
 |  | 
 | type IdeInfo struct { | 
 | 	Deps              []string `json:"dependencies,omitempty"` | 
 | 	Srcs              []string `json:"srcs,omitempty"` | 
 | 	Aidl_include_dirs []string `json:"aidl_include_dirs,omitempty"` | 
 | 	Jarjar_rules      []string `json:"jarjar_rules,omitempty"` | 
 | 	Jars              []string `json:"jars,omitempty"` | 
 | 	Classes           []string `json:"class,omitempty"` | 
 | 	Installed_paths   []string `json:"installed,omitempty"` | 
 | 	SrcJars           []string `json:"srcjars,omitempty"` | 
 | 	Paths             []string `json:"path,omitempty"` | 
 | 	Static_libs       []string `json:"static_libs,omitempty"` | 
 | 	Libs              []string `json:"libs,omitempty"` | 
 | } | 
 |  | 
 | func CheckBlueprintSyntax(ctx BaseModuleContext, filename string, contents string) []error { | 
 | 	bpctx := ctx.blueprintBaseModuleContext() | 
 | 	return blueprint.CheckBlueprintSyntax(bpctx.ModuleFactories(), filename, contents) | 
 | } | 
 |  | 
 | func registerSoongConfigTraceMutator(ctx RegisterMutatorsContext) { | 
 | 	ctx.BottomUp("soongconfigtrace", soongConfigTraceMutator).Parallel() | 
 | } | 
 |  | 
 | // soongConfigTraceMutator accumulates recorded soong_config trace from children. Also it normalizes | 
 | // SoongConfigTrace to make it consistent. | 
 | func soongConfigTraceMutator(ctx BottomUpMutatorContext) { | 
 | 	trace := &ctx.Module().base().commonProperties.SoongConfigTrace | 
 | 	ctx.VisitDirectDeps(func(m Module) { | 
 | 		childTrace := &m.base().commonProperties.SoongConfigTrace | 
 | 		trace.Bools = append(trace.Bools, childTrace.Bools...) | 
 | 		trace.Strings = append(trace.Strings, childTrace.Strings...) | 
 | 		trace.IsSets = append(trace.IsSets, childTrace.IsSets...) | 
 | 	}) | 
 | 	trace.Bools = SortedUniqueStrings(trace.Bools) | 
 | 	trace.Strings = SortedUniqueStrings(trace.Strings) | 
 | 	trace.IsSets = SortedUniqueStrings(trace.IsSets) | 
 |  | 
 | 	ctx.Module().base().commonProperties.SoongConfigTraceHash = trace.hash() | 
 | } | 
 |  | 
 | // soongConfigTraceSingleton writes a map from each module's config hash value to trace data. | 
 | func soongConfigTraceSingletonFunc() Singleton { | 
 | 	return &soongConfigTraceSingleton{} | 
 | } | 
 |  | 
 | type soongConfigTraceSingleton struct { | 
 | } | 
 |  | 
 | func (s *soongConfigTraceSingleton) GenerateBuildActions(ctx SingletonContext) { | 
 | 	outFile := PathForOutput(ctx, "soong_config_trace.json") | 
 |  | 
 | 	traces := make(map[string]*soongConfigTrace) | 
 | 	ctx.VisitAllModules(func(module Module) { | 
 | 		trace := &module.base().commonProperties.SoongConfigTrace | 
 | 		if !trace.isEmpty() { | 
 | 			hash := module.base().commonProperties.SoongConfigTraceHash | 
 | 			traces[hash] = trace | 
 | 		} | 
 | 	}) | 
 |  | 
 | 	j, err := json.Marshal(traces) | 
 | 	if err != nil { | 
 | 		ctx.Errorf("json marshal to %q failed: %#v", outFile, err) | 
 | 		return | 
 | 	} | 
 |  | 
 | 	WriteFileRule(ctx, outFile, string(j)) | 
 | 	ctx.Phony("soong_config_trace", outFile) | 
 | } | 
 |  | 
 | // Interface implemented by xsd_config which has 1:many mappings in bp2build workspace | 
 | // This interface exists because we want to | 
 | // 1. Determine the name of the additional targets generated by the primary soong module | 
 | // 2. Enable distinguishing an xsd_config module from other Soong modules using type assertion | 
 | type XsdConfigBp2buildTargets interface { | 
 | 	CppBp2buildTargetName() string | 
 | 	JavaBp2buildTargetName() string | 
 | } | 
 |  | 
 | // XsdModuleToTargetName is a function that takes an XsdConfigBp2buildTarget | 
 | type XsdModuleToTargetName func(xsd XsdConfigBp2buildTargets) string | 
 |  | 
 | // XsdLabelMapper returns a bazel.LabelMapper for partitioning XSD sources/headers given an | 
 | // XsdModuleToTargetName function. | 
 | func XsdLabelMapper(targetName XsdModuleToTargetName) bazel.LabelMapper { | 
 | 	return func(ctx bazel.OtherModuleContext, label bazel.Label) (string, bool) { | 
 | 		mod, exists := ctx.ModuleFromName(label.OriginalModuleName) | 
 | 		if !exists { | 
 | 			return label.Label, false | 
 | 		} | 
 | 		xsdMod, isXsd := mod.(XsdConfigBp2buildTargets) | 
 | 		if !isXsd { | 
 | 			return label.Label, false | 
 | 		} | 
 |  | 
 | 		// Remove the base module name | 
 | 		ret := strings.TrimSuffix(label.Label, mod.Name()) | 
 | 		// Append the language specific target name | 
 | 		ret += targetName(xsdMod) | 
 | 		return ret, true | 
 | 	} | 
 | } |