1// Copyright 2023 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package android 16 17import ( 18 "github.com/google/blueprint" 19 "github.com/google/blueprint/proptools" 20) 21 22func init() { 23 RegisterApexContributionsBuildComponents(InitRegistrationContext) 24} 25 26func RegisterApexContributionsBuildComponents(ctx RegistrationContext) { 27 ctx.RegisterModuleType("apex_contributions", apexContributionsFactory) 28 ctx.RegisterModuleType("apex_contributions_defaults", apexContributionsDefaultsFactory) 29 ctx.RegisterModuleType("all_apex_contributions", allApexContributionsFactory) 30} 31 32type apexContributions struct { 33 ModuleBase 34 DefaultableModuleBase 35 properties contributionProps 36} 37 38type contributionProps struct { 39 // Name of the mainline module 40 Api_domain *string 41 // A list of module names that should be used when this contribution 42 // is selected via product_config 43 // The name should be explicit (foo or prebuilt_foo) 44 Contents []string 45} 46 47func (m *apexContributions) ApiDomain() string { 48 return proptools.String(m.properties.Api_domain) 49} 50 51func (m *apexContributions) Contents() []string { 52 return m.properties.Contents 53} 54 55// apex_contributions contains a list of module names (source or 56// prebuilt) belonging to the mainline module 57// An apex can have multiple apex_contributions modules 58// with different combinations of source or prebuilts, but only one can be 59// selected via product_config. 60func apexContributionsFactory() Module { 61 module := &apexContributions{} 62 module.AddProperties(&module.properties) 63 InitAndroidModule(module) 64 InitDefaultableModule(module) 65 return module 66} 67 68// This module type does not have any build actions. 69// It provides metadata that is used in post-deps mutator phase for source vs 70// prebuilts selection. 71func (m *apexContributions) GenerateAndroidBuildActions(ctx ModuleContext) { 72} 73 74type apexContributionsDefaults struct { 75 ModuleBase 76 DefaultsModuleBase 77} 78 79func apexContributionsDefaultsFactory() Module { 80 module := &apexContributionsDefaults{} 81 module.AddProperties(&contributionProps{}) 82 InitDefaultsModule(module) 83 return module 84} 85 86// A container for apex_contributions. 87// Based on product_config, it will create a dependency on the selected 88// apex_contributions per mainline module 89type allApexContributions struct { 90 ModuleBase 91} 92 93func allApexContributionsFactory() Module { 94 module := &allApexContributions{} 95 InitAndroidModule(module) 96 return module 97} 98 99type apexContributionsDepTag struct { 100 blueprint.BaseDependencyTag 101} 102 103var ( 104 AcDepTag = apexContributionsDepTag{} 105) 106 107// Set PrebuiltSelectionInfoProvider in post deps phase 108func (a *allApexContributions) SetPrebuiltSelectionInfoProvider(ctx BottomUpMutatorContext) { 109 addContentsToProvider := func(p *PrebuiltSelectionInfoMap, m *apexContributions) { 110 for _, content := range m.Contents() { 111 // Verify that the module listed in contents exists in the tree 112 // Remove the prebuilt_ prefix to account for partner worksapces where the source module does not 113 // exist, and PrebuiltRenameMutator renames `prebuilt_foo` to `foo` 114 if !ctx.OtherModuleExists(content) && !ctx.OtherModuleExists(RemoveOptionalPrebuiltPrefix(content)) && !ctx.Config().AllowMissingDependencies() { 115 ctx.ModuleErrorf("%s listed in apex_contributions %s does not exist\n", content, m.Name()) 116 } 117 pi := &PrebuiltSelectionInfo{ 118 selectedModuleName: content, 119 metadataModuleName: m.Name(), 120 apiDomain: m.ApiDomain(), 121 } 122 p.Add(ctx, pi) 123 } 124 } 125 126 p := PrebuiltSelectionInfoMap{} 127 // Skip apex_contributions if BuildApexContributionContents is true 128 // This product config var allows some products in the same family to use mainline modules from source 129 // (e.g. shiba and shiba_fullmte) 130 // Eventually these product variants will have their own release config maps. 131 if !proptools.Bool(ctx.Config().BuildIgnoreApexContributionContents()) { 132 deps := ctx.AddDependency(ctx.Module(), AcDepTag, ctx.Config().AllApexContributions()...) 133 for _, child := range deps { 134 if child == nil { 135 continue 136 } 137 if m, ok := child.(*apexContributions); ok { 138 addContentsToProvider(&p, m) 139 } else { 140 ctx.ModuleErrorf("%s is not an apex_contributions module\n", child.Name()) 141 } 142 } 143 } 144 SetProvider(ctx, PrebuiltSelectionInfoProvider, p) 145} 146 147// A provider containing metadata about whether source or prebuilt should be used 148// This provider will be used in prebuilt_select mutator to redirect deps 149var PrebuiltSelectionInfoProvider = blueprint.NewMutatorProvider[PrebuiltSelectionInfoMap]("prebuilt_select") 150 151// Map of selected module names to a metadata object 152// The metadata contains information about the api_domain of the selected module 153type PrebuiltSelectionInfoMap map[string]PrebuiltSelectionInfo 154 155// Add a new entry to the map with some validations 156func (pm *PrebuiltSelectionInfoMap) Add(ctx BaseModuleContext, p *PrebuiltSelectionInfo) { 157 if p == nil { 158 return 159 } 160 (*pm)[p.selectedModuleName] = *p 161} 162 163type PrebuiltSelectionInfo struct { 164 // e.g. (libc|prebuilt_libc) 165 selectedModuleName string 166 // Name of the apex_contributions module 167 metadataModuleName string 168 // e.g. com.android.runtime 169 apiDomain string 170} 171 172// Returns true if `name` is explicitly requested using one of the selected 173// apex_contributions metadata modules. 174func (p *PrebuiltSelectionInfoMap) IsSelected(name string) bool { 175 _, exists := (*p)[name] 176 return exists 177} 178 179// Return the list of soong modules selected for this api domain 180// In the case of apexes, it is the canonical name of the apex on device (/apex/<apex_name>) 181func (p *PrebuiltSelectionInfoMap) GetSelectedModulesForApiDomain(apiDomain string) []string { 182 selected := []string{} 183 for _, entry := range *p { 184 if entry.apiDomain == apiDomain { 185 selected = append(selected, entry.selectedModuleName) 186 } 187 } 188 return selected 189} 190 191// This module type does not have any build actions. 192func (a *allApexContributions) GenerateAndroidBuildActions(ctx ModuleContext) { 193 if ctx.ModuleName() != "all_apex_contributions" { 194 ctx.ModuleErrorf("There can only be 1 all_apex_contributions module in build/soong") 195 } 196} 197