|  | // 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 ( | 
|  | "bytes" | 
|  | "encoding/gob" | 
|  | "errors" | 
|  | "fmt" | 
|  | "net/url" | 
|  | "path/filepath" | 
|  | "reflect" | 
|  | "slices" | 
|  | "sort" | 
|  | "strings" | 
|  |  | 
|  | "github.com/google/blueprint" | 
|  | "github.com/google/blueprint/proptools" | 
|  | ) | 
|  |  | 
|  | var ( | 
|  | DeviceSharedLibrary = "shared_library" | 
|  | DeviceStaticLibrary = "static_library" | 
|  | jarJarPrefixHandler func(ctx ModuleContext) | 
|  | ) | 
|  |  | 
|  | 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(ctx ConfigurableEvaluatorContext) 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 | 
|  | InstallInOdm() bool | 
|  | InstallInProduct() bool | 
|  | InstallInVendor() bool | 
|  | InstallForceOS() (*OsType, *ArchType) | 
|  | PartitionTag(DeviceConfig) string | 
|  | HideFromMake() | 
|  | IsHideFromMake() bool | 
|  | IsSkipInstall() bool | 
|  | MakeUninstallable() | 
|  | ReplacedByPrebuilt() | 
|  | IsReplacedByPrebuilt() bool | 
|  | ExportedToMake() bool | 
|  | EffectiveLicenseKinds() []string | 
|  | EffectiveLicenseFiles() Paths | 
|  |  | 
|  | AddProperties(props ...interface{}) | 
|  | GetProperties() []interface{} | 
|  |  | 
|  | 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(ctx ConfigurableEvaluatorContext) []string | 
|  | HostRequiredModuleNames() []string | 
|  | TargetRequiredModuleNames() []string | 
|  | VintfFragmentModuleNames(ctx ConfigurableEvaluatorContext) []string | 
|  |  | 
|  | ConfigurableEvaluator(ctx ConfigurableEvaluatorContext) proptools.ConfigurableEvaluator | 
|  | } | 
|  |  | 
|  | // 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] | 
|  | } | 
|  |  | 
|  | 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 proptools.Configurable[bool] `android:"arch_variant,replace_instead_of_append"` | 
|  |  | 
|  | // 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/+/main/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 proptools.Configurable[[]string] `android:"arch_variant,path"` | 
|  |  | 
|  | // VINTF manifest fragments to be installed if this module is installed | 
|  | Vintf_fragments proptools.Configurable[[]string] `android:"path"` | 
|  |  | 
|  | // names of other modules to install if this module is installed | 
|  | Required proptools.Configurable[[]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"` | 
|  |  | 
|  | // Set to true after the arch mutator has run on this module and set CompileTarget, | 
|  | // CompileMultiTargets, and CompilePrimary | 
|  | ArchReady bool `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"` | 
|  |  | 
|  | // When set to true, this module is not installed to the full install path (ex: under | 
|  | // out/target/product/<name>/<partition>). It can be installed only to the packaging | 
|  | // modules like android_filesystem. | 
|  | No_full_install *bool | 
|  |  | 
|  | // 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"` | 
|  |  | 
|  | // The team (defined by the owner/vendor) who owns the property. | 
|  | Team *string `android:"path"` | 
|  |  | 
|  | // vintf_fragment Modules required from this module. | 
|  | Vintf_fragment_modules proptools.Configurable[[]string] `android:"path"` | 
|  |  | 
|  | // List of module names that are prevented from being installed when this module gets | 
|  | // installed. | 
|  | Overrides []string | 
|  | } | 
|  |  | 
|  | 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"` | 
|  | } | 
|  |  | 
|  | type TeamDepTagType struct { | 
|  | blueprint.BaseDependencyTag | 
|  | } | 
|  |  | 
|  | var teamDepTag = TeamDepTagType{} | 
|  |  | 
|  | // Dependency tag for required, host_required, and target_required modules. | 
|  | var RequiredDepTag = struct { | 
|  | blueprint.BaseDependencyTag | 
|  | InstallAlwaysNeededDependencyTag | 
|  | // Requiring disabled module has been supported (as a side effect of this being implemented | 
|  | // in Make). We may want to make it an error, but for now, let's keep the existing behavior. | 
|  | AlwaysAllowDisabledModuleDependencyTag | 
|  | }{} | 
|  |  | 
|  | // 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 hostCrossProperties struct { | 
|  | // If set to true, build a variant of the module for the host cross.  Defaults to true. | 
|  | Host_cross_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) | 
|  | } | 
|  |  | 
|  | if hod&hostCrossSupported != 0 { | 
|  | m.AddProperties(&base.hostCrossProperties) | 
|  | } | 
|  |  | 
|  | 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 | 
|  | } | 
|  |  | 
|  | // 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 | 
|  | hostCrossProperties     hostCrossProperties | 
|  |  | 
|  | // 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{} | 
|  |  | 
|  | // 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 | 
|  |  | 
|  | hooks hooks | 
|  |  | 
|  | registerProps []interface{} | 
|  |  | 
|  | // For tests | 
|  | buildParams []BuildParams | 
|  | ruleParams  map[blueprint.Rule]blueprint.RuleParams | 
|  | variables   map[string]string | 
|  | } | 
|  |  | 
|  | 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) {} | 
|  |  | 
|  | func (m *ModuleBase) baseDepsMutator(ctx BottomUpMutatorContext) { | 
|  | if m.Team() != "" { | 
|  | ctx.AddDependency(ctx.Module(), teamDepTag, m.Team()) | 
|  | } | 
|  |  | 
|  | // TODO(jiyong): remove below case. This is to work around build errors happening | 
|  | // on branches with reduced manifest like aosp_kernel-build-tools. | 
|  | // In the branch, a build error occurs as follows. | 
|  | // 1. aosp_kernel-build-tools is a reduced manifest branch. It doesn't have some git | 
|  | // projects like external/bouncycastle | 
|  | // 2. `boot_signer` is `required` by modules like `build_image` which is explicitly list as | 
|  | // the top-level build goal (in the shell file that invokes Soong). | 
|  | // 3. `boot_signer` depends on `bouncycastle-unbundled` which is in the missing git project. | 
|  | // 4. aosp_kernel-build-tools invokes soong with `--skip-make`. Therefore, the absence of | 
|  | // ALLOW_MISSING_DEPENDENCIES didn't cause a problem. | 
|  | // 5. Now, since Soong understands `required` deps, it tries to build `boot_signer` and the | 
|  | // absence of external/bouncycastle fails the build. | 
|  | // | 
|  | // Unfortunately, there's no way for Soong to correctly determine if it's running in a | 
|  | // reduced manifest branch. Instead, here, we use the absence of DeviceArch or DeviceName as | 
|  | // a strong signal, because that's very common across reduced manifest branches. | 
|  | pv := ctx.Config().productVariables | 
|  | fullManifest := pv.DeviceArch != nil && pv.DeviceName != nil | 
|  | if fullManifest { | 
|  | addRequiredDeps(ctx) | 
|  | addVintfFragmentDeps(ctx) | 
|  | } | 
|  | } | 
|  |  | 
|  | // addRequiredDeps adds required, target_required, and host_required as dependencies. | 
|  | func addRequiredDeps(ctx BottomUpMutatorContext) { | 
|  | addDep := func(target Target, depName string) { | 
|  | if !ctx.OtherModuleExists(depName) { | 
|  | if ctx.Config().AllowMissingDependencies() { | 
|  | return | 
|  | } | 
|  | } | 
|  |  | 
|  | // If Android native module requires another Android native module, ensure that | 
|  | // they have the same bitness. This mimics the policy in select-bitness-of-required-modules | 
|  | // in build/make/core/main.mk. | 
|  | // TODO(jiyong): the Make-side does this only when the required module is a shared | 
|  | // library or a native test. | 
|  | bothInAndroid := ctx.Device() && target.Os.Class == Device | 
|  | nativeArch := InList(ctx.Arch().ArchType.Multilib, []string{"lib32", "lib64"}) && | 
|  | InList(target.Arch.ArchType.Multilib, []string{"lib32", "lib64"}) | 
|  | sameBitness := ctx.Arch().ArchType.Multilib == target.Arch.ArchType.Multilib | 
|  | if bothInAndroid && nativeArch && !sameBitness { | 
|  | return | 
|  | } | 
|  |  | 
|  | // ... also don't make a dependency between native bridge arch and non-native bridge | 
|  | // arches. b/342945184 | 
|  | if ctx.Target().NativeBridge != target.NativeBridge { | 
|  | return | 
|  | } | 
|  |  | 
|  | variation := target.Variations() | 
|  | if ctx.OtherModuleFarDependencyVariantExists(variation, depName) { | 
|  | ctx.AddFarVariationDependencies(variation, RequiredDepTag, depName) | 
|  | } | 
|  | } | 
|  |  | 
|  | var deviceTargets []Target | 
|  | deviceTargets = append(deviceTargets, ctx.Config().Targets[Android]...) | 
|  | deviceTargets = append(deviceTargets, ctx.Config().AndroidCommonTarget) | 
|  |  | 
|  | var hostTargets []Target | 
|  | hostTargets = append(hostTargets, ctx.Config().Targets[ctx.Config().BuildOS]...) | 
|  | hostTargets = append(hostTargets, ctx.Config().BuildOSCommonTarget) | 
|  |  | 
|  | if ctx.Device() { | 
|  | for _, depName := range ctx.Module().RequiredModuleNames(ctx) { | 
|  | for _, target := range deviceTargets { | 
|  | addDep(target, depName) | 
|  | } | 
|  | } | 
|  | for _, depName := range ctx.Module().HostRequiredModuleNames() { | 
|  | for _, target := range hostTargets { | 
|  | addDep(target, depName) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if ctx.Host() { | 
|  | for _, depName := range ctx.Module().RequiredModuleNames(ctx) { | 
|  | for _, target := range hostTargets { | 
|  | // When a host module requires another host module, don't make a | 
|  | // dependency if they have different OSes (i.e. hostcross). | 
|  | if ctx.Target().HostCross != target.HostCross { | 
|  | continue | 
|  | } | 
|  | addDep(target, depName) | 
|  | } | 
|  | } | 
|  | for _, depName := range ctx.Module().TargetRequiredModuleNames() { | 
|  | for _, target := range deviceTargets { | 
|  | addDep(target, depName) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | var vintfDepTag = struct { | 
|  | blueprint.BaseDependencyTag | 
|  | InstallAlwaysNeededDependencyTag | 
|  | }{} | 
|  |  | 
|  | func addVintfFragmentDeps(ctx BottomUpMutatorContext) { | 
|  | // Vintf manifests in the recovery partition will be ignored. | 
|  | if !ctx.Device() || ctx.Module().InstallInRecovery() { | 
|  | return | 
|  | } | 
|  |  | 
|  | deviceConfig := ctx.DeviceConfig() | 
|  |  | 
|  | mod := ctx.Module() | 
|  | vintfModules := ctx.AddDependency(mod, vintfDepTag, mod.VintfFragmentModuleNames(ctx)...) | 
|  |  | 
|  | modPartition := mod.PartitionTag(deviceConfig) | 
|  | for _, vintf := range vintfModules { | 
|  | if vintfModule, ok := vintf.(*vintfFragmentModule); ok { | 
|  | vintfPartition := vintfModule.PartitionTag(deviceConfig) | 
|  | if modPartition != vintfPartition { | 
|  | ctx.ModuleErrorf("Module %q(%q) and Vintf_fragment %q(%q) are installed to different partitions.", | 
|  | mod.Name(), modPartition, | 
|  | vintfModule.Name(), vintfPartition) | 
|  | } | 
|  | } else { | 
|  | ctx.ModuleErrorf("Only vintf_fragment type module should be listed in vintf_fragment_modules : %q", vintf.Name()) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // 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) | 
|  |  | 
|  | distFileForTagFromProvider, err := outputFilesForModuleFromProvider(ctx, m.module, tag) | 
|  | if err != OutputFilesProviderNotSet { | 
|  | if err != nil && tag != DefaultDistTag { | 
|  | ctx.PropertyErrorf("dist.tag", "%s", err.Error()) | 
|  | } else { | 
|  | distFiles = distFiles.addPathsForTag(tag, distFileForTagFromProvider...) | 
|  | continue | 
|  | } | 
|  | } | 
|  | } | 
|  | return distFiles | 
|  | } | 
|  |  | 
|  | func (m *ModuleBase) ArchReady() bool { | 
|  | return m.commonProperties.ArchReady | 
|  | } | 
|  |  | 
|  | 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.CompileOS == CommonOS | 
|  | } | 
|  |  | 
|  | // 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) | 
|  |  | 
|  | // Default true for the Host_cross_supported property | 
|  | hostCrossEnabled := proptools.BoolDefault(m.hostCrossProperties.Host_cross_supported, true) | 
|  |  | 
|  | return hod&hostCrossSupported != 0 && hostEnabled && hostCrossEnabled | 
|  | } | 
|  |  | 
|  | 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(ctx ConfigurableEvaluatorContext) bool { | 
|  | if m.commonProperties.ForcedDisabled { | 
|  | return false | 
|  | } | 
|  | return m.commonProperties.Enabled.GetOrDefault(m.ConfigurableEvaluator(ctx), !m.Os().DefaultDisabled) | 
|  | } | 
|  |  | 
|  | // Returns a copy of the enabled property, useful for passing it on to sub-modules | 
|  | func (m *ModuleBase) EnabledProperty() proptools.Configurable[bool] { | 
|  | if m.commonProperties.ForcedDisabled { | 
|  | return proptools.NewSimpleConfigurable(false) | 
|  | } | 
|  | return m.commonProperties.Enabled.Clone() | 
|  | } | 
|  |  | 
|  | 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. | 
|  | info := OtherModuleProviderOrDefault(ctx, dep, InstallFilesProvider) | 
|  | if !dep.IsHideFromMake() && !dep.IsSkipInstall() { | 
|  | installDeps = append(installDeps, info.TransitiveInstallFiles) | 
|  | } | 
|  | // 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, info.TransitivePackagingSpecs) | 
|  | } | 
|  | }) | 
|  |  | 
|  | 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) 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) InstallInOdm() bool { | 
|  | return false | 
|  | } | 
|  |  | 
|  | func (m *ModuleBase) InstallInProduct() bool { | 
|  | return false | 
|  | } | 
|  |  | 
|  | 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) Team() string { | 
|  | return String(m.commonProperties.Team) | 
|  | } | 
|  |  | 
|  | 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(ctx ConfigurableEvaluatorContext) []string { | 
|  | return m.base().commonProperties.Required.GetOrDefault(m.ConfigurableEvaluator(ctx), nil) | 
|  | } | 
|  |  | 
|  | 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) VintfFragmentModuleNames(ctx ConfigurableEvaluatorContext) []string { | 
|  | return m.base().commonProperties.Vintf_fragment_modules.GetOrDefault(m.ConfigurableEvaluator(ctx), nil) | 
|  | } | 
|  |  | 
|  | func (m *ModuleBase) generateVariantTarget(ctx *moduleContext) { | 
|  | namespacePrefix := ctx.Namespace().id | 
|  | if namespacePrefix != "" { | 
|  | namespacePrefix = namespacePrefix + "-" | 
|  | } | 
|  |  | 
|  | if !ctx.uncheckedModule { | 
|  | name := namespacePrefix + ctx.ModuleName() + "-" + ctx.ModuleSubDir() + "-checkbuild" | 
|  | ctx.Phony(name, ctx.checkbuildFiles...) | 
|  | ctx.checkbuildTarget = PathForPhony(ctx, name) | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | func (m *ModuleBase) generateModuleTarget(ctx *moduleContext) { | 
|  | var allInstalledFiles InstallPaths | 
|  | var allCheckbuildTargets Paths | 
|  | ctx.VisitAllModuleVariants(func(module Module) { | 
|  | a := module.base() | 
|  | var checkbuildTarget Path | 
|  | var uncheckedModule bool | 
|  | if a == m { | 
|  | allInstalledFiles = append(allInstalledFiles, ctx.installFiles...) | 
|  | checkbuildTarget = ctx.checkbuildTarget | 
|  | uncheckedModule = ctx.uncheckedModule | 
|  | } else { | 
|  | info := OtherModuleProviderOrDefault(ctx, module, InstallFilesProvider) | 
|  | allInstalledFiles = append(allInstalledFiles, info.InstallFiles...) | 
|  | checkbuildTarget = info.CheckbuildTarget | 
|  | uncheckedModule = info.UncheckedModule | 
|  | } | 
|  | // 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(ctx, a)) && !uncheckedModule && checkbuildTarget != nil { | 
|  | allCheckbuildTargets = append(allCheckbuildTargets, checkbuildTarget) | 
|  | } | 
|  | }) | 
|  |  | 
|  | var deps Paths | 
|  |  | 
|  | var namespacePrefix string | 
|  | nameSpace := ctx.Namespace().Path | 
|  | if nameSpace != "." { | 
|  | namespacePrefix = strings.ReplaceAll(nameSpace, "/", ".") + "-" | 
|  | } | 
|  |  | 
|  | var info FinalModuleBuildTargetsInfo | 
|  |  | 
|  | if len(allInstalledFiles) > 0 { | 
|  | name := namespacePrefix + ctx.ModuleName() + "-install" | 
|  | ctx.Phony(name, allInstalledFiles.Paths()...) | 
|  | info.InstallTarget = PathForPhony(ctx, name) | 
|  | deps = append(deps, info.InstallTarget) | 
|  | } | 
|  |  | 
|  | if len(allCheckbuildTargets) > 0 { | 
|  | name := namespacePrefix + ctx.ModuleName() + "-checkbuild" | 
|  | ctx.Phony(name, allCheckbuildTargets...) | 
|  | deps = append(deps, PathForPhony(ctx, name)) | 
|  | } | 
|  |  | 
|  | if len(deps) > 0 { | 
|  | suffix := "" | 
|  | if ctx.Config().KatiEnabled() { | 
|  | suffix = "-soong" | 
|  | } | 
|  |  | 
|  | ctx.Phony(namespacePrefix+ctx.ModuleName()+suffix, deps...) | 
|  |  | 
|  | info.BlueprintDir = ctx.ModuleDir() | 
|  | SetProvider(ctx, FinalModuleBuildTargetsProvider, info) | 
|  | } | 
|  | } | 
|  |  | 
|  | 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, | 
|  | archModuleContext:  m.archModuleContextFactory(ctx), | 
|  | earlyModuleContext: m.earlyModuleContextFactory(ctx), | 
|  | } | 
|  | } | 
|  |  | 
|  | type archModuleContextFactoryContext interface { | 
|  | Config() interface{} | 
|  | } | 
|  |  | 
|  | func (m *ModuleBase) archModuleContextFactory(ctx archModuleContextFactoryContext) archModuleContext { | 
|  | config := ctx.Config().(Config) | 
|  | target := m.Target() | 
|  | primaryArch := false | 
|  | if len(config.Targets[target.Os]) <= 1 { | 
|  | primaryArch = true | 
|  | } else { | 
|  | primaryArch = target.Arch.ArchType == config.Targets[target.Os][0].Arch.ArchType | 
|  | } | 
|  |  | 
|  | return archModuleContext{ | 
|  | ready:         m.commonProperties.ArchReady, | 
|  | os:            m.commonProperties.CompileOS, | 
|  | target:        m.commonProperties.CompileTarget, | 
|  | targetPrimary: m.commonProperties.CompilePrimary, | 
|  | multiTargets:  m.commonProperties.CompileMultiTargets, | 
|  | primaryArch:   primaryArch, | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | type InstallFilesInfo struct { | 
|  | InstallFiles     InstallPaths | 
|  | CheckbuildFiles  Paths | 
|  | CheckbuildTarget Path | 
|  | UncheckedModule  bool | 
|  | PackagingSpecs   []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 | 
|  | TestData                 []DataPath | 
|  | TransitivePackagingSpecs *DepSet[PackagingSpec] | 
|  | LicenseMetadataFile      WritablePath | 
|  |  | 
|  | // The following fields are private before, make it private again once we have | 
|  | // better solution. | 
|  | TransitiveInstallFiles *DepSet[InstallPath] | 
|  | // katiInitRcInstalls and katiVintfInstalls track the install rules created by Soong that are | 
|  | // allowed to have duplicates across modules and variants. | 
|  | KatiInitRcInstalls           katiInstalls | 
|  | KatiVintfInstalls            katiInstalls | 
|  | InitRcPaths                  Paths | 
|  | VintfFragmentsPaths          Paths | 
|  | InstalledInitRcPaths         InstallPaths | 
|  | InstalledVintfFragmentsPaths InstallPaths | 
|  |  | 
|  | // The files to copy to the dist as explicitly specified in the .bp file. | 
|  | DistFiles TaggedDistFiles | 
|  | } | 
|  |  | 
|  | var InstallFilesProvider = blueprint.NewProvider[InstallFilesInfo]() | 
|  |  | 
|  | type FinalModuleBuildTargetsInfo struct { | 
|  | // 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 | 
|  | } | 
|  |  | 
|  | var FinalModuleBuildTargetsProvider = blueprint.NewProvider[FinalModuleBuildTargetsInfo]() | 
|  |  | 
|  | func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) { | 
|  | ctx := &moduleContext{ | 
|  | module:            m.module, | 
|  | bp:                blueprintCtx, | 
|  | baseModuleContext: m.baseModuleContextFactory(blueprintCtx), | 
|  | variables:         make(map[string]string), | 
|  | phonies:           make(map[string]Paths), | 
|  | } | 
|  |  | 
|  | setContainerInfo(ctx) | 
|  | if ctx.Config().Getenv("DISABLE_CONTAINER_CHECK") != "true" { | 
|  | checkContainerViolations(ctx) | 
|  | } | 
|  |  | 
|  | ctx.licenseMetadataFile = PathForModuleOut(ctx, "meta_lic") | 
|  |  | 
|  | dependencyInstallFiles, dependencyPackagingSpecs := m.computeInstallDeps(ctx) | 
|  | // set the TransitiveInstallFiles 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. | 
|  | ctx.TransitiveInstallFiles = 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, _ := ModuleProvider(ctx, ApexInfoProvider); !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]) | 
|  | } | 
|  |  | 
|  | var installFiles InstallFilesInfo | 
|  |  | 
|  | if m.Enabled(ctx) { | 
|  | // 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, false) | 
|  | } | 
|  | }) | 
|  |  | 
|  | if m.Device() { | 
|  | // Handle any init.rc and vintf fragment files requested by the module.  All files installed by this | 
|  | // module will automatically have a dependency on the installed init.rc or vintf fragment file. | 
|  | // The same init.rc or vintf fragment file may be requested by multiple modules or variants, | 
|  | // so instead of installing them now just compute the install path and store it for later. | 
|  | // The full list of all init.rc and vintf fragment install rules will be deduplicated later | 
|  | // so only a single rule is created for each init.rc or vintf fragment file. | 
|  |  | 
|  | if !m.InVendorRamdisk() { | 
|  | ctx.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc.GetOrDefault(ctx, nil)) | 
|  | rcDir := PathForModuleInstall(ctx, "etc", "init") | 
|  | for _, src := range ctx.initRcPaths { | 
|  | installedInitRc := rcDir.Join(ctx, src.Base()) | 
|  | ctx.katiInitRcInstalls = append(ctx.katiInitRcInstalls, katiInstall{ | 
|  | from: src, | 
|  | to:   installedInitRc, | 
|  | }) | 
|  | ctx.PackageFile(rcDir, src.Base(), src) | 
|  | ctx.installedInitRcPaths = append(ctx.installedInitRcPaths, installedInitRc) | 
|  | } | 
|  | installFiles.InitRcPaths = ctx.initRcPaths | 
|  | installFiles.KatiInitRcInstalls = ctx.katiInitRcInstalls | 
|  | installFiles.InstalledInitRcPaths = ctx.installedInitRcPaths | 
|  | } | 
|  |  | 
|  | ctx.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments.GetOrDefault(ctx, nil)) | 
|  | vintfDir := PathForModuleInstall(ctx, "etc", "vintf", "manifest") | 
|  | for _, src := range ctx.vintfFragmentsPaths { | 
|  | installedVintfFragment := vintfDir.Join(ctx, src.Base()) | 
|  | ctx.katiVintfInstalls = append(ctx.katiVintfInstalls, katiInstall{ | 
|  | from: src, | 
|  | to:   installedVintfFragment, | 
|  | }) | 
|  | ctx.PackageFile(vintfDir, src.Base(), src) | 
|  | ctx.installedVintfFragmentsPaths = append(ctx.installedVintfFragmentsPaths, installedVintfFragment) | 
|  | } | 
|  | installFiles.VintfFragmentsPaths = ctx.vintfFragmentsPaths | 
|  | installFiles.KatiVintfInstalls = ctx.katiVintfInstalls | 
|  | installFiles.InstalledVintfFragmentsPaths = ctx.installedVintfFragmentsPaths | 
|  | } | 
|  |  | 
|  | licensesPropertyFlattener(ctx) | 
|  | if ctx.Failed() { | 
|  | return | 
|  | } | 
|  |  | 
|  | if jarJarPrefixHandler != nil { | 
|  | jarJarPrefixHandler(ctx) | 
|  | if ctx.Failed() { | 
|  | return | 
|  | } | 
|  | } | 
|  |  | 
|  | // Call aconfigUpdateAndroidBuildActions to collect merged aconfig files before being used | 
|  | // in m.module.GenerateAndroidBuildActions | 
|  | aconfigUpdateAndroidBuildActions(ctx) | 
|  | if ctx.Failed() { | 
|  | return | 
|  | } | 
|  |  | 
|  | m.module.GenerateAndroidBuildActions(ctx) | 
|  | if ctx.Failed() { | 
|  | return | 
|  | } | 
|  |  | 
|  | if x, ok := m.module.(IDEInfo); ok { | 
|  | var result IdeInfo | 
|  | x.IDEInfo(ctx, &result) | 
|  | result.BaseModuleName = x.BaseModuleName() | 
|  | SetProvider(ctx, IdeInfoProviderKey, result) | 
|  | } | 
|  |  | 
|  | // 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. | 
|  | installFiles.DistFiles = m.GenerateTaggedDistFiles(ctx) | 
|  | if ctx.Failed() { | 
|  | return | 
|  | } | 
|  |  | 
|  | m.generateVariantTarget(ctx) | 
|  |  | 
|  | installFiles.LicenseMetadataFile = ctx.licenseMetadataFile | 
|  | installFiles.InstallFiles = ctx.installFiles | 
|  | installFiles.CheckbuildFiles = ctx.checkbuildFiles | 
|  | installFiles.CheckbuildTarget = ctx.checkbuildTarget | 
|  | installFiles.UncheckedModule = ctx.uncheckedModule | 
|  | installFiles.PackagingSpecs = ctx.packagingSpecs | 
|  | installFiles.KatiInstalls = ctx.katiInstalls | 
|  | installFiles.KatiSymlinks = ctx.katiSymlinks | 
|  | installFiles.TestData = ctx.testData | 
|  | } 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 | 
|  | } | 
|  | } | 
|  |  | 
|  | ctx.TransitiveInstallFiles = NewDepSet[InstallPath](TOPOLOGICAL, ctx.installFiles, dependencyInstallFiles) | 
|  | installFiles.TransitiveInstallFiles = ctx.TransitiveInstallFiles | 
|  | installFiles.TransitivePackagingSpecs = NewDepSet[PackagingSpec](TOPOLOGICAL, ctx.packagingSpecs, dependencyPackagingSpecs) | 
|  |  | 
|  | SetProvider(ctx, InstallFilesProvider, installFiles) | 
|  | buildLicenseMetadata(ctx, ctx.licenseMetadataFile) | 
|  |  | 
|  | if ctx.moduleInfoJSON != nil { | 
|  | var installed InstallPaths | 
|  | installed = append(installed, ctx.katiInstalls.InstallPaths()...) | 
|  | installed = append(installed, ctx.katiSymlinks.InstallPaths()...) | 
|  | installed = append(installed, ctx.katiInitRcInstalls.InstallPaths()...) | 
|  | installed = append(installed, ctx.katiVintfInstalls.InstallPaths()...) | 
|  | installedStrings := installed.Strings() | 
|  |  | 
|  | var targetRequired, hostRequired []string | 
|  | if ctx.Host() { | 
|  | targetRequired = m.commonProperties.Target_required | 
|  | } else { | 
|  | hostRequired = m.commonProperties.Host_required | 
|  | } | 
|  |  | 
|  | var data []string | 
|  | for _, d := range ctx.testData { | 
|  | data = append(data, d.ToRelativeInstallPath()) | 
|  | } | 
|  |  | 
|  | if ctx.moduleInfoJSON.Uninstallable { | 
|  | installedStrings = nil | 
|  | if len(ctx.moduleInfoJSON.CompatibilitySuites) == 1 && ctx.moduleInfoJSON.CompatibilitySuites[0] == "null-suite" { | 
|  | ctx.moduleInfoJSON.CompatibilitySuites = nil | 
|  | ctx.moduleInfoJSON.TestConfig = nil | 
|  | ctx.moduleInfoJSON.AutoTestConfig = nil | 
|  | data = nil | 
|  | } | 
|  | } | 
|  |  | 
|  | ctx.moduleInfoJSON.core = CoreModuleInfoJSON{ | 
|  | RegisterName:       m.moduleInfoRegisterName(ctx, ctx.moduleInfoJSON.SubName), | 
|  | Path:               []string{ctx.ModuleDir()}, | 
|  | Installed:          installedStrings, | 
|  | ModuleName:         m.BaseModuleName() + ctx.moduleInfoJSON.SubName, | 
|  | SupportedVariants:  []string{m.moduleInfoVariant(ctx)}, | 
|  | TargetDependencies: targetRequired, | 
|  | HostDependencies:   hostRequired, | 
|  | Data:               data, | 
|  | Required:           append(m.RequiredModuleNames(ctx), m.VintfFragmentModuleNames(ctx)...), | 
|  | } | 
|  | SetProvider(ctx, ModuleInfoJSONProvider, ctx.moduleInfoJSON) | 
|  | } | 
|  |  | 
|  | m.buildParams = ctx.buildParams | 
|  | m.ruleParams = ctx.ruleParams | 
|  | m.variables = ctx.variables | 
|  |  | 
|  | outputFiles := ctx.GetOutputFiles() | 
|  | if outputFiles.DefaultOutputFiles != nil || outputFiles.TaggedOutputFiles != nil { | 
|  | SetProvider(ctx, OutputFilesProvider, outputFiles) | 
|  | } | 
|  |  | 
|  | if len(ctx.phonies) > 0 { | 
|  | SetProvider(ctx, ModulePhonyProvider, ModulePhonyInfo{ | 
|  | Phonies: ctx.phonies, | 
|  | }) | 
|  | } | 
|  | buildComplianceMetadataProvider(ctx, m) | 
|  | } | 
|  |  | 
|  | func SetJarJarPrefixHandler(handler func(ModuleContext)) { | 
|  | if jarJarPrefixHandler != nil { | 
|  | panic("jarJarPrefixHandler already set") | 
|  | } | 
|  | jarJarPrefixHandler = handler | 
|  | } | 
|  |  | 
|  | func (m *ModuleBase) moduleInfoRegisterName(ctx ModuleContext, subName string) string { | 
|  | name := m.BaseModuleName() | 
|  |  | 
|  | prefix := "" | 
|  | if ctx.Host() { | 
|  | if ctx.Os() != ctx.Config().BuildOS { | 
|  | prefix = "host_cross_" | 
|  | } | 
|  | } | 
|  | suffix := "" | 
|  | arches := slices.Clone(ctx.Config().Targets[ctx.Os()]) | 
|  | arches = slices.DeleteFunc(arches, func(target Target) bool { | 
|  | return target.NativeBridge != ctx.Target().NativeBridge | 
|  | }) | 
|  | if len(arches) > 0 && ctx.Arch().ArchType != arches[0].Arch.ArchType { | 
|  | if ctx.Arch().ArchType.Multilib == "lib32" { | 
|  | suffix = "_32" | 
|  | } else { | 
|  | suffix = "_64" | 
|  | } | 
|  | } | 
|  | return prefix + name + subName + suffix | 
|  | } | 
|  |  | 
|  | func (m *ModuleBase) moduleInfoVariant(ctx ModuleContext) string { | 
|  | variant := "DEVICE" | 
|  | if ctx.Host() { | 
|  | if ctx.Os() != ctx.Config().BuildOS { | 
|  | variant = "HOST_CROSS" | 
|  | } else { | 
|  | variant = "HOST" | 
|  | } | 
|  | } | 
|  | return variant | 
|  | } | 
|  |  | 
|  | // 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.") | 
|  | } | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | // 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 | 
|  | } | 
|  |  | 
|  | func (p *katiInstall) GobEncode() ([]byte, error) { | 
|  | w := new(bytes.Buffer) | 
|  | encoder := gob.NewEncoder(w) | 
|  | err := errors.Join(encoder.Encode(p.from), encoder.Encode(p.to), | 
|  | encoder.Encode(p.implicitDeps), encoder.Encode(p.orderOnlyDeps), | 
|  | encoder.Encode(p.executable), encoder.Encode(p.extraFiles), | 
|  | encoder.Encode(p.absFrom)) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  |  | 
|  | return w.Bytes(), nil | 
|  | } | 
|  |  | 
|  | func (p *katiInstall) GobDecode(data []byte) error { | 
|  | r := bytes.NewBuffer(data) | 
|  | decoder := gob.NewDecoder(r) | 
|  | err := errors.Join(decoder.Decode(&p.from), decoder.Decode(&p.to), | 
|  | decoder.Decode(&p.implicitDeps), decoder.Decode(&p.orderOnlyDeps), | 
|  | decoder.Decode(&p.executable), decoder.Decode(&p.extraFiles), | 
|  | decoder.Decode(&p.absFrom)) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  |  | 
|  | return nil | 
|  | } | 
|  |  | 
|  | type extraFilesZip struct { | 
|  | zip Path | 
|  | dir InstallPath | 
|  | } | 
|  |  | 
|  | func (p *extraFilesZip) GobEncode() ([]byte, error) { | 
|  | w := new(bytes.Buffer) | 
|  | encoder := gob.NewEncoder(w) | 
|  | err := errors.Join(encoder.Encode(p.zip), encoder.Encode(p.dir)) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  |  | 
|  | return w.Bytes(), nil | 
|  | } | 
|  |  | 
|  | func (p *extraFilesZip) GobDecode(data []byte) error { | 
|  | r := bytes.NewBuffer(data) | 
|  | decoder := gob.NewDecoder(r) | 
|  | err := errors.Join(decoder.Decode(&p.zip), decoder.Decode(&p.dir)) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  |  | 
|  | return nil | 
|  | } | 
|  |  | 
|  | 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 | 
|  | } | 
|  |  | 
|  | // 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) | 
|  | } | 
|  |  | 
|  | type ConfigContext interface { | 
|  | Config() Config | 
|  | } | 
|  |  | 
|  | type ConfigurableEvaluatorContext interface { | 
|  | OtherModuleProviderContext | 
|  | Config() Config | 
|  | OtherModulePropertyErrorf(module Module, property string, fmt string, args ...interface{}) | 
|  | HasMutatorFinished(mutatorName string) bool | 
|  | } | 
|  |  | 
|  | type configurationEvalutor struct { | 
|  | ctx ConfigurableEvaluatorContext | 
|  | m   Module | 
|  | } | 
|  |  | 
|  | func (m *ModuleBase) ConfigurableEvaluator(ctx ConfigurableEvaluatorContext) proptools.ConfigurableEvaluator { | 
|  | return configurationEvalutor{ | 
|  | ctx: ctx, | 
|  | m:   m.module, | 
|  | } | 
|  | } | 
|  |  | 
|  | func (e configurationEvalutor) PropertyErrorf(property string, fmt string, args ...interface{}) { | 
|  | e.ctx.OtherModulePropertyErrorf(e.m, property, fmt, args...) | 
|  | } | 
|  |  | 
|  | func (e configurationEvalutor) EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue { | 
|  | ctx := e.ctx | 
|  | m := e.m | 
|  |  | 
|  | if !ctx.HasMutatorFinished("defaults") { | 
|  | ctx.OtherModulePropertyErrorf(m, property, "Cannot evaluate configurable property before the defaults mutator has run") | 
|  | return proptools.ConfigurableValueUndefined() | 
|  | } | 
|  |  | 
|  | switch condition.FunctionName() { | 
|  | case "release_flag": | 
|  | if condition.NumArgs() != 1 { | 
|  | ctx.OtherModulePropertyErrorf(m, property, "release_flag requires 1 argument, found %d", condition.NumArgs()) | 
|  | return proptools.ConfigurableValueUndefined() | 
|  | } | 
|  | if ty, ok := ctx.Config().productVariables.BuildFlagTypes[condition.Arg(0)]; ok { | 
|  | v := ctx.Config().productVariables.BuildFlags[condition.Arg(0)] | 
|  | switch ty { | 
|  | case "unspecified", "obsolete": | 
|  | return proptools.ConfigurableValueUndefined() | 
|  | case "string": | 
|  | return proptools.ConfigurableValueString(v) | 
|  | case "bool": | 
|  | return proptools.ConfigurableValueBool(v == "true") | 
|  | default: | 
|  | panic("unhandled release flag type: " + ty) | 
|  | } | 
|  | } | 
|  | return proptools.ConfigurableValueUndefined() | 
|  | case "product_variable": | 
|  | if condition.NumArgs() != 1 { | 
|  | ctx.OtherModulePropertyErrorf(m, property, "product_variable requires 1 argument, found %d", condition.NumArgs()) | 
|  | return proptools.ConfigurableValueUndefined() | 
|  | } | 
|  | variable := condition.Arg(0) | 
|  | switch variable { | 
|  | case "debuggable": | 
|  | return proptools.ConfigurableValueBool(ctx.Config().Debuggable()) | 
|  | case "use_debug_art": | 
|  | // TODO(b/234351700): Remove once ART does not have separated debug APEX | 
|  | return proptools.ConfigurableValueBool(ctx.Config().UseDebugArt()) | 
|  | default: | 
|  | // TODO(b/323382414): Might add these on a case-by-case basis | 
|  | ctx.OtherModulePropertyErrorf(m, property, fmt.Sprintf("TODO(b/323382414): Product variable %q is not yet supported in selects", variable)) | 
|  | return proptools.ConfigurableValueUndefined() | 
|  | } | 
|  | case "soong_config_variable": | 
|  | if condition.NumArgs() != 2 { | 
|  | ctx.OtherModulePropertyErrorf(m, property, "soong_config_variable requires 2 arguments, found %d", condition.NumArgs()) | 
|  | return proptools.ConfigurableValueUndefined() | 
|  | } | 
|  | namespace := condition.Arg(0) | 
|  | variable := condition.Arg(1) | 
|  | if n, ok := ctx.Config().productVariables.VendorVars[namespace]; ok { | 
|  | if v, ok := n[variable]; ok { | 
|  | ty := "" | 
|  | if namespaces, ok := ctx.Config().productVariables.VendorVarTypes[namespace]; ok { | 
|  | ty = namespaces[variable] | 
|  | } | 
|  | switch ty { | 
|  | case "": | 
|  | // strings are the default, we don't bother writing them to the soong variables json file | 
|  | return proptools.ConfigurableValueString(v) | 
|  | case "bool": | 
|  | return proptools.ConfigurableValueBool(v == "true") | 
|  | default: | 
|  | panic("unhandled soong config variable type: " + ty) | 
|  | } | 
|  |  | 
|  | } | 
|  | } | 
|  | return proptools.ConfigurableValueUndefined() | 
|  | case "arch": | 
|  | if condition.NumArgs() != 0 { | 
|  | ctx.OtherModulePropertyErrorf(m, property, "arch requires no arguments, found %d", condition.NumArgs()) | 
|  | return proptools.ConfigurableValueUndefined() | 
|  | } | 
|  | if !m.base().ArchReady() { | 
|  | ctx.OtherModulePropertyErrorf(m, property, "A select on arch was attempted before the arch mutator ran") | 
|  | return proptools.ConfigurableValueUndefined() | 
|  | } | 
|  | return proptools.ConfigurableValueString(m.base().Arch().ArchType.Name) | 
|  | case "os": | 
|  | if condition.NumArgs() != 0 { | 
|  | ctx.OtherModulePropertyErrorf(m, property, "os requires no arguments, found %d", condition.NumArgs()) | 
|  | return proptools.ConfigurableValueUndefined() | 
|  | } | 
|  | // the arch mutator runs after the os mutator, we can just use this to enforce that os is ready. | 
|  | if !m.base().ArchReady() { | 
|  | ctx.OtherModulePropertyErrorf(m, property, "A select on os was attempted before the arch mutator ran (arch runs after os, we use it to lazily detect that os is ready)") | 
|  | return proptools.ConfigurableValueUndefined() | 
|  | } | 
|  | return proptools.ConfigurableValueString(m.base().Os().Name) | 
|  | case "boolean_var_for_testing": | 
|  | // We currently don't have any other boolean variables (we should add support for typing | 
|  | // the soong config variables), so add this fake one for testing the boolean select | 
|  | // functionality. | 
|  | if condition.NumArgs() != 0 { | 
|  | ctx.OtherModulePropertyErrorf(m, property, "boolean_var_for_testing requires 0 arguments, found %d", condition.NumArgs()) | 
|  | return proptools.ConfigurableValueUndefined() | 
|  | } | 
|  |  | 
|  | if n, ok := ctx.Config().productVariables.VendorVars["boolean_var"]; ok { | 
|  | if v, ok := n["for_testing"]; ok { | 
|  | switch v { | 
|  | case "true": | 
|  | return proptools.ConfigurableValueBool(true) | 
|  | case "false": | 
|  | return proptools.ConfigurableValueBool(false) | 
|  | default: | 
|  | ctx.OtherModulePropertyErrorf(m, property, "testing:my_boolean_var can only be true or false, found %q", v) | 
|  | } | 
|  | } | 
|  | } | 
|  | return proptools.ConfigurableValueUndefined() | 
|  | default: | 
|  | ctx.OtherModulePropertyErrorf(m, property, "Unknown select condition %s", condition.FunctionName) | 
|  | return proptools.ConfigurableValueUndefined() | 
|  | } | 
|  | } | 
|  |  | 
|  | // ModuleNameWithPossibleOverride returns the name of the OverrideModule that overrides the current | 
|  | // variant of this OverridableModule, or ctx.ModuleName() if this module is not an OverridableModule | 
|  | // or if this variant is not overridden. | 
|  | func ModuleNameWithPossibleOverride(ctx BaseModuleContext) string { | 
|  | if overridable, ok := ctx.Module().(OverridableModule); ok { | 
|  | if o := overridable.GetOverriddenBy(); o != "" { | 
|  | return o | 
|  | } | 
|  | } | 
|  | return ctx.ModuleName() | 
|  | } | 
|  |  | 
|  | // 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 | 
|  | AlwaysPropagateAconfigValidationDependencyTag | 
|  |  | 
|  | // The name of the module. | 
|  | moduleName string | 
|  |  | 
|  | // The tag that will be used to get the specific output file(s). | 
|  | 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 | 
|  | } | 
|  |  | 
|  | // OutputFilesForModule returns the output file paths 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 output file paths 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) { | 
|  | outputFilesFromProvider, err := outputFilesForModuleFromProvider(ctx, module, tag) | 
|  | if outputFilesFromProvider != nil || err != OutputFilesProviderNotSet { | 
|  | return outputFilesFromProvider, err | 
|  | } | 
|  | if sourceFileProducer, ok := module.(SourceFileProducer); ok { | 
|  | if tag != "" { | 
|  | return nil, fmt.Errorf("module %q is a SourceFileProducer, which does not support tag %q", pathContextName(ctx, module), tag) | 
|  | } | 
|  | paths := sourceFileProducer.Srcs() | 
|  | return paths, nil | 
|  | } else { | 
|  | return nil, fmt.Errorf("module %q is not a SourceFileProducer or having valid output file for tag %q", pathContextName(ctx, module), tag) | 
|  | } | 
|  | } | 
|  |  | 
|  | // This method uses OutputFilesProvider for output files | 
|  | // *inter-module-communication*. | 
|  | // If mctx module is the same as the param module the output files are obtained | 
|  | // from outputFiles property of module base, to avoid both setting and | 
|  | // reading OutputFilesProvider before GenerateBuildActions is finished. | 
|  | // If a module doesn't have the OutputFilesProvider, nil is returned. | 
|  | func outputFilesForModuleFromProvider(ctx PathContext, module blueprint.Module, tag string) (Paths, error) { | 
|  | var outputFiles OutputFilesInfo | 
|  | fromProperty := false | 
|  |  | 
|  | type OutputFilesProviderModuleContext interface { | 
|  | OtherModuleProviderContext | 
|  | Module() Module | 
|  | GetOutputFiles() OutputFilesInfo | 
|  | } | 
|  |  | 
|  | if mctx, isMctx := ctx.(OutputFilesProviderModuleContext); isMctx { | 
|  | if mctx.Module() != module { | 
|  | outputFiles, _ = OtherModuleProvider(mctx, module, OutputFilesProvider) | 
|  | } else { | 
|  | outputFiles = mctx.GetOutputFiles() | 
|  | fromProperty = true | 
|  | } | 
|  | } else if cta, isCta := ctx.(*singletonContextAdaptor); isCta { | 
|  | providerData, _ := cta.otherModuleProvider(module, OutputFilesProvider) | 
|  | outputFiles, _ = providerData.(OutputFilesInfo) | 
|  | } else { | 
|  | return nil, fmt.Errorf("unsupported context %q in method outputFilesForModuleFromProvider", reflect.TypeOf(ctx)) | 
|  | } | 
|  |  | 
|  | if outputFiles.isEmpty() { | 
|  | return nil, OutputFilesProviderNotSet | 
|  | } | 
|  |  | 
|  | if tag == "" { | 
|  | return outputFiles.DefaultOutputFiles, nil | 
|  | } else if taggedOutputFiles, hasTag := outputFiles.TaggedOutputFiles[tag]; hasTag { | 
|  | return taggedOutputFiles, nil | 
|  | } else { | 
|  | if fromProperty { | 
|  | return nil, fmt.Errorf("unsupported tag %q for module getting its own output files", tag) | 
|  | } else { | 
|  | return nil, fmt.Errorf("unsupported module reference tag %q", tag) | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | func (o OutputFilesInfo) isEmpty() bool { | 
|  | return o.DefaultOutputFiles == nil && o.TaggedOutputFiles == nil | 
|  | } | 
|  |  | 
|  | type OutputFilesInfo struct { | 
|  | // default output files when tag is an empty string "" | 
|  | DefaultOutputFiles Paths | 
|  |  | 
|  | // the corresponding output files for given tags | 
|  | TaggedOutputFiles map[string]Paths | 
|  | } | 
|  |  | 
|  | var OutputFilesProvider = blueprint.NewProvider[OutputFilesInfo]() | 
|  |  | 
|  | // This is used to mark the case where OutputFilesProvider is not set on some modules. | 
|  | var OutputFilesProviderNotSet = fmt.Errorf("No output files from provider") | 
|  |  | 
|  | // 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 | 
|  | } | 
|  |  | 
|  | func init() { | 
|  | RegisterParallelSingletonType("buildtarget", BuildTargetSingleton) | 
|  | } | 
|  |  | 
|  | 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) { | 
|  | info := OtherModuleProviderOrDefault(ctx, module, FinalModuleBuildTargetsProvider) | 
|  |  | 
|  | if info.CheckbuildTarget != nil { | 
|  | checkbuildDeps = append(checkbuildDeps, info.CheckbuildTarget) | 
|  | modulesInDir[info.BlueprintDir] = append(modulesInDir[info.BlueprintDir], info.CheckbuildTarget) | 
|  | } | 
|  |  | 
|  | if info.InstallTarget != nil { | 
|  | modulesInDir[info.BlueprintDir] = append(modulesInDir[info.BlueprintDir], info.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(ctx) { | 
|  | key := osAndCross{os: module.Target().Os, hostCross: module.Target().HostCross} | 
|  | osDeps[key] = append(osDeps[key], OtherModuleProviderOrDefault(ctx, module, InstallFilesProvider).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(ctx BaseModuleContext, 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 | 
|  | } | 
|  |  | 
|  | // Collect information for opening IDE project files in java/jdeps.go. | 
|  | type IdeInfo struct { | 
|  | BaseModuleName    string   `json:"-"` | 
|  | 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"` | 
|  | } | 
|  |  | 
|  | // Merge merges two IdeInfos and produces a new one, leaving the origional unchanged | 
|  | func (i IdeInfo) Merge(other IdeInfo) IdeInfo { | 
|  | return IdeInfo{ | 
|  | Deps:              mergeStringLists(i.Deps, other.Deps), | 
|  | Srcs:              mergeStringLists(i.Srcs, other.Srcs), | 
|  | Aidl_include_dirs: mergeStringLists(i.Aidl_include_dirs, other.Aidl_include_dirs), | 
|  | Jarjar_rules:      mergeStringLists(i.Jarjar_rules, other.Jarjar_rules), | 
|  | Jars:              mergeStringLists(i.Jars, other.Jars), | 
|  | Classes:           mergeStringLists(i.Classes, other.Classes), | 
|  | Installed_paths:   mergeStringLists(i.Installed_paths, other.Installed_paths), | 
|  | SrcJars:           mergeStringLists(i.SrcJars, other.SrcJars), | 
|  | Paths:             mergeStringLists(i.Paths, other.Paths), | 
|  | Static_libs:       mergeStringLists(i.Static_libs, other.Static_libs), | 
|  | Libs:              mergeStringLists(i.Libs, other.Libs), | 
|  | } | 
|  | } | 
|  |  | 
|  | // mergeStringLists appends the two string lists together and returns a new string list, | 
|  | // leaving the originals unchanged. Duplicate strings will be deduplicated. | 
|  | func mergeStringLists(a, b []string) []string { | 
|  | return FirstUniqueStrings(Concat(a, b)) | 
|  | } | 
|  |  | 
|  | var IdeInfoProviderKey = blueprint.NewProvider[IdeInfo]() | 
|  |  | 
|  | func CheckBlueprintSyntax(ctx BaseModuleContext, filename string, contents string) []error { | 
|  | bpctx := ctx.blueprintBaseModuleContext() | 
|  | return blueprint.CheckBlueprintSyntax(bpctx.ModuleFactories(), filename, contents) | 
|  | } |