1*333d2b36SAndroid Build Coastguard Worker// Copyright 2023 Google Inc. All rights reserved. 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Workerpackage android 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Workerimport ( 18*333d2b36SAndroid Build Coastguard Worker "fmt" 19*333d2b36SAndroid Build Coastguard Worker "io" 20*333d2b36SAndroid Build Coastguard Worker "maps" 21*333d2b36SAndroid Build Coastguard Worker "reflect" 22*333d2b36SAndroid Build Coastguard Worker 23*333d2b36SAndroid Build Coastguard Worker "github.com/google/blueprint" 24*333d2b36SAndroid Build Coastguard Worker) 25*333d2b36SAndroid Build Coastguard Worker 26*333d2b36SAndroid Build Coastguard Workervar ( 27*333d2b36SAndroid Build Coastguard Worker mergeAconfigFilesRule = pctx.AndroidStaticRule("mergeAconfigFilesRule", 28*333d2b36SAndroid Build Coastguard Worker blueprint.RuleParams{ 29*333d2b36SAndroid Build Coastguard Worker Command: `${aconfig} dump --dedup --format protobuf --out $out $flags`, 30*333d2b36SAndroid Build Coastguard Worker CommandDeps: []string{"${aconfig}"}, 31*333d2b36SAndroid Build Coastguard Worker }, "flags") 32*333d2b36SAndroid Build Coastguard Worker _ = pctx.HostBinToolVariable("aconfig", "aconfig") 33*333d2b36SAndroid Build Coastguard Worker) 34*333d2b36SAndroid Build Coastguard Worker 35*333d2b36SAndroid Build Coastguard Worker// Provider published by aconfig_value_set 36*333d2b36SAndroid Build Coastguard Workertype AconfigDeclarationsProviderData struct { 37*333d2b36SAndroid Build Coastguard Worker Package string 38*333d2b36SAndroid Build Coastguard Worker Container string 39*333d2b36SAndroid Build Coastguard Worker Exportable bool 40*333d2b36SAndroid Build Coastguard Worker IntermediateCacheOutputPath WritablePath 41*333d2b36SAndroid Build Coastguard Worker IntermediateDumpOutputPath WritablePath 42*333d2b36SAndroid Build Coastguard Worker} 43*333d2b36SAndroid Build Coastguard Worker 44*333d2b36SAndroid Build Coastguard Workervar AconfigDeclarationsProviderKey = blueprint.NewProvider[AconfigDeclarationsProviderData]() 45*333d2b36SAndroid Build Coastguard Worker 46*333d2b36SAndroid Build Coastguard Workertype AconfigReleaseDeclarationsProviderData map[string]AconfigDeclarationsProviderData 47*333d2b36SAndroid Build Coastguard Worker 48*333d2b36SAndroid Build Coastguard Workervar AconfigReleaseDeclarationsProviderKey = blueprint.NewProvider[AconfigReleaseDeclarationsProviderData]() 49*333d2b36SAndroid Build Coastguard Worker 50*333d2b36SAndroid Build Coastguard Workertype ModeInfo struct { 51*333d2b36SAndroid Build Coastguard Worker Container string 52*333d2b36SAndroid Build Coastguard Worker Mode string 53*333d2b36SAndroid Build Coastguard Worker} 54*333d2b36SAndroid Build Coastguard Workertype CodegenInfo struct { 55*333d2b36SAndroid Build Coastguard Worker // AconfigDeclarations is the name of the aconfig_declarations modules that 56*333d2b36SAndroid Build Coastguard Worker // the codegen module is associated with 57*333d2b36SAndroid Build Coastguard Worker AconfigDeclarations []string 58*333d2b36SAndroid Build Coastguard Worker 59*333d2b36SAndroid Build Coastguard Worker // Paths to the cache files of the associated aconfig_declaration modules 60*333d2b36SAndroid Build Coastguard Worker IntermediateCacheOutputPaths Paths 61*333d2b36SAndroid Build Coastguard Worker 62*333d2b36SAndroid Build Coastguard Worker // Paths to the srcjar files generated from the java_aconfig_library modules 63*333d2b36SAndroid Build Coastguard Worker Srcjars Paths 64*333d2b36SAndroid Build Coastguard Worker 65*333d2b36SAndroid Build Coastguard Worker ModeInfos map[string]ModeInfo 66*333d2b36SAndroid Build Coastguard Worker} 67*333d2b36SAndroid Build Coastguard Worker 68*333d2b36SAndroid Build Coastguard Workervar CodegenInfoProvider = blueprint.NewProvider[CodegenInfo]() 69*333d2b36SAndroid Build Coastguard Worker 70*333d2b36SAndroid Build Coastguard Workerfunc propagateModeInfos(ctx ModuleContext, module Module, to, from map[string]ModeInfo) { 71*333d2b36SAndroid Build Coastguard Worker if len(from) > 0 { 72*333d2b36SAndroid Build Coastguard Worker depTag := ctx.OtherModuleDependencyTag(module) 73*333d2b36SAndroid Build Coastguard Worker if tag, ok := depTag.(PropagateAconfigValidationDependencyTag); ok && tag.PropagateAconfigValidation() { 74*333d2b36SAndroid Build Coastguard Worker maps.Copy(to, from) 75*333d2b36SAndroid Build Coastguard Worker } 76*333d2b36SAndroid Build Coastguard Worker } 77*333d2b36SAndroid Build Coastguard Worker} 78*333d2b36SAndroid Build Coastguard Worker 79*333d2b36SAndroid Build Coastguard Workertype aconfigPropagatingDeclarationsInfo struct { 80*333d2b36SAndroid Build Coastguard Worker AconfigFiles map[string]Paths 81*333d2b36SAndroid Build Coastguard Worker ModeInfos map[string]ModeInfo 82*333d2b36SAndroid Build Coastguard Worker} 83*333d2b36SAndroid Build Coastguard Worker 84*333d2b36SAndroid Build Coastguard Workervar AconfigPropagatingProviderKey = blueprint.NewProvider[aconfigPropagatingDeclarationsInfo]() 85*333d2b36SAndroid Build Coastguard Worker 86*333d2b36SAndroid Build Coastguard Workerfunc VerifyAconfigBuildMode(ctx ModuleContext, container string, module blueprint.Module, asError bool) { 87*333d2b36SAndroid Build Coastguard Worker if dep, ok := OtherModuleProvider(ctx, module, AconfigPropagatingProviderKey); ok { 88*333d2b36SAndroid Build Coastguard Worker for k, v := range dep.ModeInfos { 89*333d2b36SAndroid Build Coastguard Worker msg := fmt.Sprintf("%s/%s depends on %s/%s/%s across containers\n", 90*333d2b36SAndroid Build Coastguard Worker module.Name(), container, k, v.Container, v.Mode) 91*333d2b36SAndroid Build Coastguard Worker if v.Container != container && v.Mode != "exported" && v.Mode != "force-read-only" { 92*333d2b36SAndroid Build Coastguard Worker if asError { 93*333d2b36SAndroid Build Coastguard Worker ctx.ModuleErrorf(msg) 94*333d2b36SAndroid Build Coastguard Worker } else { 95*333d2b36SAndroid Build Coastguard Worker fmt.Printf("WARNING: " + msg) 96*333d2b36SAndroid Build Coastguard Worker } 97*333d2b36SAndroid Build Coastguard Worker } else { 98*333d2b36SAndroid Build Coastguard Worker if !asError { 99*333d2b36SAndroid Build Coastguard Worker fmt.Printf("PASSED: " + msg) 100*333d2b36SAndroid Build Coastguard Worker } 101*333d2b36SAndroid Build Coastguard Worker } 102*333d2b36SAndroid Build Coastguard Worker } 103*333d2b36SAndroid Build Coastguard Worker } 104*333d2b36SAndroid Build Coastguard Worker} 105*333d2b36SAndroid Build Coastguard Worker 106*333d2b36SAndroid Build Coastguard Workerfunc aconfigUpdateAndroidBuildActions(ctx ModuleContext) { 107*333d2b36SAndroid Build Coastguard Worker mergedAconfigFiles := make(map[string]Paths) 108*333d2b36SAndroid Build Coastguard Worker mergedModeInfos := make(map[string]ModeInfo) 109*333d2b36SAndroid Build Coastguard Worker 110*333d2b36SAndroid Build Coastguard Worker ctx.VisitDirectDepsProxy(func(module ModuleProxy) { 111*333d2b36SAndroid Build Coastguard Worker if aconfig_dep, ok := OtherModuleProvider(ctx, module, CodegenInfoProvider); ok && len(aconfig_dep.ModeInfos) > 0 { 112*333d2b36SAndroid Build Coastguard Worker maps.Copy(mergedModeInfos, aconfig_dep.ModeInfos) 113*333d2b36SAndroid Build Coastguard Worker } 114*333d2b36SAndroid Build Coastguard Worker 115*333d2b36SAndroid Build Coastguard Worker // If any of our dependencies have aconfig declarations (directly or propagated), then merge those and provide them. 116*333d2b36SAndroid Build Coastguard Worker if dep, ok := OtherModuleProvider(ctx, module, AconfigDeclarationsProviderKey); ok { 117*333d2b36SAndroid Build Coastguard Worker mergedAconfigFiles[dep.Container] = append(mergedAconfigFiles[dep.Container], dep.IntermediateCacheOutputPath) 118*333d2b36SAndroid Build Coastguard Worker } 119*333d2b36SAndroid Build Coastguard Worker // If we were generating on-device artifacts for other release configs, we would need to add code here to propagate 120*333d2b36SAndroid Build Coastguard Worker // those artifacts as well. See also b/298444886. 121*333d2b36SAndroid Build Coastguard Worker if dep, ok := OtherModuleProvider(ctx, module, AconfigPropagatingProviderKey); ok { 122*333d2b36SAndroid Build Coastguard Worker for container, v := range dep.AconfigFiles { 123*333d2b36SAndroid Build Coastguard Worker mergedAconfigFiles[container] = append(mergedAconfigFiles[container], v...) 124*333d2b36SAndroid Build Coastguard Worker } 125*333d2b36SAndroid Build Coastguard Worker propagateModeInfos(ctx, module, mergedModeInfos, dep.ModeInfos) 126*333d2b36SAndroid Build Coastguard Worker } 127*333d2b36SAndroid Build Coastguard Worker }) 128*333d2b36SAndroid Build Coastguard Worker // We only need to set the provider if we have aconfig files. 129*333d2b36SAndroid Build Coastguard Worker if len(mergedAconfigFiles) > 0 { 130*333d2b36SAndroid Build Coastguard Worker for _, container := range SortedKeys(mergedAconfigFiles) { 131*333d2b36SAndroid Build Coastguard Worker aconfigFiles := mergedAconfigFiles[container] 132*333d2b36SAndroid Build Coastguard Worker mergedAconfigFiles[container] = mergeAconfigFiles(ctx, container, aconfigFiles, true) 133*333d2b36SAndroid Build Coastguard Worker } 134*333d2b36SAndroid Build Coastguard Worker 135*333d2b36SAndroid Build Coastguard Worker SetProvider(ctx, AconfigPropagatingProviderKey, aconfigPropagatingDeclarationsInfo{ 136*333d2b36SAndroid Build Coastguard Worker AconfigFiles: mergedAconfigFiles, 137*333d2b36SAndroid Build Coastguard Worker ModeInfos: mergedModeInfos, 138*333d2b36SAndroid Build Coastguard Worker }) 139*333d2b36SAndroid Build Coastguard Worker ctx.setAconfigPaths(getAconfigFilePaths(ctx.Module().base(), mergedAconfigFiles)) 140*333d2b36SAndroid Build Coastguard Worker } 141*333d2b36SAndroid Build Coastguard Worker} 142*333d2b36SAndroid Build Coastguard Worker 143*333d2b36SAndroid Build Coastguard Workerfunc aconfigUpdateAndroidMkData(ctx fillInEntriesContext, mod Module, data *AndroidMkData) { 144*333d2b36SAndroid Build Coastguard Worker info, ok := OtherModuleProvider(ctx, mod, AconfigPropagatingProviderKey) 145*333d2b36SAndroid Build Coastguard Worker // If there is no aconfigPropagatingProvider, or there are no AconfigFiles, then we are done. 146*333d2b36SAndroid Build Coastguard Worker if !ok || len(info.AconfigFiles) == 0 { 147*333d2b36SAndroid Build Coastguard Worker return 148*333d2b36SAndroid Build Coastguard Worker } 149*333d2b36SAndroid Build Coastguard Worker data.Extra = append(data.Extra, func(w io.Writer, outputFile Path) { 150*333d2b36SAndroid Build Coastguard Worker AndroidMkEmitAssignList(w, "LOCAL_ACONFIG_FILES", getAconfigFilePaths(mod.base(), info.AconfigFiles).Strings()) 151*333d2b36SAndroid Build Coastguard Worker }) 152*333d2b36SAndroid Build Coastguard Worker // If there is a Custom writer, it needs to support this provider. 153*333d2b36SAndroid Build Coastguard Worker if data.Custom != nil { 154*333d2b36SAndroid Build Coastguard Worker switch reflect.TypeOf(mod).String() { 155*333d2b36SAndroid Build Coastguard Worker case "*aidl.aidlApi": // writes non-custom before adding .phony 156*333d2b36SAndroid Build Coastguard Worker case "*android_sdk.sdkRepoHost": // doesn't go through base_rules 157*333d2b36SAndroid Build Coastguard Worker case "*apex.apexBundle": // aconfig_file properties written 158*333d2b36SAndroid Build Coastguard Worker case "*bpf.bpf": // properties written (both for module and objs) 159*333d2b36SAndroid Build Coastguard Worker case "*genrule.Module": // writes non-custom before adding .phony 160*333d2b36SAndroid Build Coastguard Worker case "*java.SystemModules": // doesn't go through base_rules 161*333d2b36SAndroid Build Coastguard Worker case "*phony.phony": // properties written 162*333d2b36SAndroid Build Coastguard Worker case "*phony.PhonyRule": // writes phony deps and acts like `.PHONY` 163*333d2b36SAndroid Build Coastguard Worker case "*sysprop.syspropLibrary": // properties written 164*333d2b36SAndroid Build Coastguard Worker default: 165*333d2b36SAndroid Build Coastguard Worker panic(fmt.Errorf("custom make rules do not handle aconfig files for %q (%q) module %q", ctx.ModuleType(mod), reflect.TypeOf(mod), mod)) 166*333d2b36SAndroid Build Coastguard Worker } 167*333d2b36SAndroid Build Coastguard Worker } 168*333d2b36SAndroid Build Coastguard Worker} 169*333d2b36SAndroid Build Coastguard Worker 170*333d2b36SAndroid Build Coastguard Workerfunc aconfigUpdateAndroidMkEntries(ctx fillInEntriesContext, mod Module, entries *[]AndroidMkEntries) { 171*333d2b36SAndroid Build Coastguard Worker // If there are no entries, then we can ignore this module, even if it has aconfig files. 172*333d2b36SAndroid Build Coastguard Worker if len(*entries) == 0 { 173*333d2b36SAndroid Build Coastguard Worker return 174*333d2b36SAndroid Build Coastguard Worker } 175*333d2b36SAndroid Build Coastguard Worker info, ok := OtherModuleProvider(ctx, mod, AconfigPropagatingProviderKey) 176*333d2b36SAndroid Build Coastguard Worker if !ok || len(info.AconfigFiles) == 0 { 177*333d2b36SAndroid Build Coastguard Worker return 178*333d2b36SAndroid Build Coastguard Worker } 179*333d2b36SAndroid Build Coastguard Worker // All of the files in the module potentially depend on the aconfig flag values. 180*333d2b36SAndroid Build Coastguard Worker for idx, _ := range *entries { 181*333d2b36SAndroid Build Coastguard Worker (*entries)[idx].ExtraEntries = append((*entries)[idx].ExtraEntries, 182*333d2b36SAndroid Build Coastguard Worker func(ctx AndroidMkExtraEntriesContext, entries *AndroidMkEntries) { 183*333d2b36SAndroid Build Coastguard Worker entries.AddPaths("LOCAL_ACONFIG_FILES", getAconfigFilePaths(mod.base(), info.AconfigFiles)) 184*333d2b36SAndroid Build Coastguard Worker }, 185*333d2b36SAndroid Build Coastguard Worker ) 186*333d2b36SAndroid Build Coastguard Worker 187*333d2b36SAndroid Build Coastguard Worker } 188*333d2b36SAndroid Build Coastguard Worker} 189*333d2b36SAndroid Build Coastguard Worker 190*333d2b36SAndroid Build Coastguard Workerfunc aconfigUpdateAndroidMkInfos(ctx fillInEntriesContext, mod Module, infos *AndroidMkProviderInfo) { 191*333d2b36SAndroid Build Coastguard Worker info, ok := OtherModuleProvider(ctx, mod, AconfigPropagatingProviderKey) 192*333d2b36SAndroid Build Coastguard Worker if !ok || len(info.AconfigFiles) == 0 { 193*333d2b36SAndroid Build Coastguard Worker return 194*333d2b36SAndroid Build Coastguard Worker } 195*333d2b36SAndroid Build Coastguard Worker // All of the files in the module potentially depend on the aconfig flag values. 196*333d2b36SAndroid Build Coastguard Worker infos.PrimaryInfo.AddPaths("LOCAL_ACONFIG_FILES", getAconfigFilePaths(mod.base(), info.AconfigFiles)) 197*333d2b36SAndroid Build Coastguard Worker if len(infos.ExtraInfo) > 0 { 198*333d2b36SAndroid Build Coastguard Worker for _, ei := range (*infos).ExtraInfo { 199*333d2b36SAndroid Build Coastguard Worker ei.AddPaths("LOCAL_ACONFIG_FILES", getAconfigFilePaths(mod.base(), info.AconfigFiles)) 200*333d2b36SAndroid Build Coastguard Worker } 201*333d2b36SAndroid Build Coastguard Worker } 202*333d2b36SAndroid Build Coastguard Worker} 203*333d2b36SAndroid Build Coastguard Worker 204*333d2b36SAndroid Build Coastguard Workerfunc mergeAconfigFiles(ctx ModuleContext, container string, inputs Paths, generateRule bool) Paths { 205*333d2b36SAndroid Build Coastguard Worker inputs = SortedUniquePaths(inputs) 206*333d2b36SAndroid Build Coastguard Worker if len(inputs) == 1 { 207*333d2b36SAndroid Build Coastguard Worker return Paths{inputs[0]} 208*333d2b36SAndroid Build Coastguard Worker } 209*333d2b36SAndroid Build Coastguard Worker 210*333d2b36SAndroid Build Coastguard Worker output := PathForModuleOut(ctx, container, "aconfig_merged.pb") 211*333d2b36SAndroid Build Coastguard Worker 212*333d2b36SAndroid Build Coastguard Worker if generateRule { 213*333d2b36SAndroid Build Coastguard Worker ctx.Build(pctx, BuildParams{ 214*333d2b36SAndroid Build Coastguard Worker Rule: mergeAconfigFilesRule, 215*333d2b36SAndroid Build Coastguard Worker Description: "merge aconfig files", 216*333d2b36SAndroid Build Coastguard Worker Inputs: inputs, 217*333d2b36SAndroid Build Coastguard Worker Output: output, 218*333d2b36SAndroid Build Coastguard Worker Args: map[string]string{ 219*333d2b36SAndroid Build Coastguard Worker "flags": JoinWithPrefix(inputs.Strings(), "--cache "), 220*333d2b36SAndroid Build Coastguard Worker }, 221*333d2b36SAndroid Build Coastguard Worker }) 222*333d2b36SAndroid Build Coastguard Worker } 223*333d2b36SAndroid Build Coastguard Worker 224*333d2b36SAndroid Build Coastguard Worker return Paths{output} 225*333d2b36SAndroid Build Coastguard Worker} 226*333d2b36SAndroid Build Coastguard Worker 227*333d2b36SAndroid Build Coastguard Workerfunc getAconfigFilePaths(m *ModuleBase, aconfigFiles map[string]Paths) (paths Paths) { 228*333d2b36SAndroid Build Coastguard Worker // TODO(b/311155208): The default container here should be system. 229*333d2b36SAndroid Build Coastguard Worker container := "system" 230*333d2b36SAndroid Build Coastguard Worker 231*333d2b36SAndroid Build Coastguard Worker if m.SocSpecific() { 232*333d2b36SAndroid Build Coastguard Worker container = "vendor" 233*333d2b36SAndroid Build Coastguard Worker } else if m.ProductSpecific() { 234*333d2b36SAndroid Build Coastguard Worker container = "product" 235*333d2b36SAndroid Build Coastguard Worker } else if m.SystemExtSpecific() { 236*333d2b36SAndroid Build Coastguard Worker // system_ext and system partitions should be treated as one container 237*333d2b36SAndroid Build Coastguard Worker container = "system" 238*333d2b36SAndroid Build Coastguard Worker } 239*333d2b36SAndroid Build Coastguard Worker 240*333d2b36SAndroid Build Coastguard Worker paths = append(paths, aconfigFiles[container]...) 241*333d2b36SAndroid Build Coastguard Worker if container == "system" { 242*333d2b36SAndroid Build Coastguard Worker // TODO(b/311155208): Once the default container is system, we can drop this. 243*333d2b36SAndroid Build Coastguard Worker paths = append(paths, aconfigFiles[""]...) 244*333d2b36SAndroid Build Coastguard Worker } 245*333d2b36SAndroid Build Coastguard Worker if container != "system" { 246*333d2b36SAndroid Build Coastguard Worker if len(aconfigFiles[container]) == 0 && len(aconfigFiles[""]) > 0 { 247*333d2b36SAndroid Build Coastguard Worker // TODO(b/308625757): Either we guessed the container wrong, or the flag is misdeclared. 248*333d2b36SAndroid Build Coastguard Worker // For now, just include the system (aka "") container if we get here. 249*333d2b36SAndroid Build Coastguard Worker //fmt.Printf("container_mismatch: module=%v container=%v files=%v\n", m, container, aconfigFiles) 250*333d2b36SAndroid Build Coastguard Worker } 251*333d2b36SAndroid Build Coastguard Worker paths = append(paths, aconfigFiles[""]...) 252*333d2b36SAndroid Build Coastguard Worker } 253*333d2b36SAndroid Build Coastguard Worker return 254*333d2b36SAndroid Build Coastguard Worker} 255