xref: /aosp_15_r20/build/soong/android/aconfig_providers.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
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