blob: fcc57e1a4614716f42ea47e732e8779fc21778c6 [file] [log] [blame]
LaMont Jonesaa005ae2023-12-19 19:01:57 +00001// 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 (
LaMont Jonesb5099382024-01-10 23:42:36 +000018 "fmt"
19 "io"
Yu Liu67a28422024-03-05 00:36:31 +000020 "maps"
LaMont Jonesb5099382024-01-10 23:42:36 +000021 "reflect"
22
LaMont Jonesaa005ae2023-12-19 19:01:57 +000023 "github.com/google/blueprint"
24)
25
26var (
27 mergeAconfigFilesRule = pctx.AndroidStaticRule("mergeAconfigFilesRule",
28 blueprint.RuleParams{
29 Command: `${aconfig} dump --dedup --format protobuf --out $out $flags`,
30 CommandDeps: []string{"${aconfig}"},
31 }, "flags")
32 _ = pctx.HostBinToolVariable("aconfig", "aconfig")
33)
34
35// Provider published by aconfig_value_set
36type AconfigDeclarationsProviderData struct {
37 Package string
38 Container string
Zi Wang0e5d16c2024-02-08 06:19:34 +000039 Exportable bool
LaMont Jonesaa005ae2023-12-19 19:01:57 +000040 IntermediateCacheOutputPath WritablePath
41 IntermediateDumpOutputPath WritablePath
42}
43
44var AconfigDeclarationsProviderKey = blueprint.NewProvider[AconfigDeclarationsProviderData]()
45
46// This is used to collect the aconfig declarations info on the transitive closure,
47// the data is keyed on the container.
48type AconfigTransitiveDeclarationsInfo struct {
49 AconfigFiles map[string]Paths
50}
51
52var AconfigTransitiveDeclarationsInfoProvider = blueprint.NewProvider[AconfigTransitiveDeclarationsInfo]()
53
Yu Liu67a28422024-03-05 00:36:31 +000054type ModeInfo struct {
55 Container string
56 Mode string
57}
58type CodegenInfo struct {
59 // AconfigDeclarations is the name of the aconfig_declarations modules that
60 // the codegen module is associated with
61 AconfigDeclarations []string
62
63 // Paths to the cache files of the associated aconfig_declaration modules
64 IntermediateCacheOutputPaths Paths
65
66 // Paths to the srcjar files generated from the java_aconfig_library modules
67 Srcjars Paths
68
69 ModeInfos map[string]ModeInfo
70}
71
72var CodegenInfoProvider = blueprint.NewProvider[CodegenInfo]()
73
74func propagateModeInfos(ctx ModuleContext, module Module, to, from map[string]ModeInfo) {
75 if len(from) > 0 {
76 depTag := ctx.OtherModuleDependencyTag(module)
77 if tag, ok := depTag.(PropagateAconfigValidationDependencyTag); ok && tag.PropagateAconfigValidation() {
78 maps.Copy(to, from)
79 }
80 }
81}
82
LaMont Jonesb5099382024-01-10 23:42:36 +000083// CollectDependencyAconfigFiles is used by some module types to provide finer dependency graphing than
84// we can do in ModuleBase.
LaMont Jonesaa005ae2023-12-19 19:01:57 +000085func CollectDependencyAconfigFiles(ctx ModuleContext, mergedAconfigFiles *map[string]Paths) {
86 if *mergedAconfigFiles == nil {
87 *mergedAconfigFiles = make(map[string]Paths)
88 }
LaMont Jones34314b72024-01-18 18:27:35 +000089 ctx.VisitDirectDepsIgnoreBlueprint(func(module Module) {
LaMont Jonesaa005ae2023-12-19 19:01:57 +000090 if dep, _ := OtherModuleProvider(ctx, module, AconfigDeclarationsProviderKey); dep.IntermediateCacheOutputPath != nil {
91 (*mergedAconfigFiles)[dep.Container] = append((*mergedAconfigFiles)[dep.Container], dep.IntermediateCacheOutputPath)
92 return
93 }
LaMont Jonesb5099382024-01-10 23:42:36 +000094 if dep, ok := OtherModuleProvider(ctx, module, aconfigPropagatingProviderKey); ok {
95 for container, v := range dep.AconfigFiles {
96 (*mergedAconfigFiles)[container] = append((*mergedAconfigFiles)[container], v...)
97 }
98 }
99 // We process these last, so that they determine the final value, eliminating any duplicates that we picked up
100 // from UpdateAndroidBuildActions.
101 if dep, ok := OtherModuleProvider(ctx, module, AconfigTransitiveDeclarationsInfoProvider); ok {
LaMont Jonesaa005ae2023-12-19 19:01:57 +0000102 for container, v := range dep.AconfigFiles {
103 (*mergedAconfigFiles)[container] = append((*mergedAconfigFiles)[container], v...)
104 }
105 }
106 })
107
108 for container, aconfigFiles := range *mergedAconfigFiles {
LaMont Jonesb5099382024-01-10 23:42:36 +0000109 (*mergedAconfigFiles)[container] = mergeAconfigFiles(ctx, container, aconfigFiles, false)
LaMont Jonesaa005ae2023-12-19 19:01:57 +0000110 }
111
112 SetProvider(ctx, AconfigTransitiveDeclarationsInfoProvider, AconfigTransitiveDeclarationsInfo{
113 AconfigFiles: *mergedAconfigFiles,
114 })
115}
116
LaMont Jonesb5099382024-01-10 23:42:36 +0000117func SetAconfigFileMkEntries(m *ModuleBase, entries *AndroidMkEntries, aconfigFiles map[string]Paths) {
118 setAconfigFileMkEntries(m, entries, aconfigFiles)
119}
120
121type aconfigPropagatingDeclarationsInfo struct {
122 AconfigFiles map[string]Paths
Yu Liu67a28422024-03-05 00:36:31 +0000123 ModeInfos map[string]ModeInfo
LaMont Jonesb5099382024-01-10 23:42:36 +0000124}
125
126var aconfigPropagatingProviderKey = blueprint.NewProvider[aconfigPropagatingDeclarationsInfo]()
127
Yu Liu67a28422024-03-05 00:36:31 +0000128func VerifyAconfigBuildMode(ctx ModuleContext, container string, module blueprint.Module, asError bool) {
129 if dep, ok := OtherModuleProvider(ctx, module, aconfigPropagatingProviderKey); ok {
130 for k, v := range dep.ModeInfos {
131 msg := fmt.Sprintf("%s/%s depends on %s/%s/%s across containers\n",
132 module.Name(), container, k, v.Container, v.Mode)
133 if v.Container != container && v.Mode != "exported" && v.Mode != "force-read-only" {
134 if asError {
135 ctx.ModuleErrorf(msg)
136 } else {
137 fmt.Printf("WARNING: " + msg)
138 }
139 } else {
140 if !asError {
141 fmt.Printf("PASSED: " + msg)
142 }
143 }
144 }
145 }
146}
147
LaMont Jonesb5099382024-01-10 23:42:36 +0000148func aconfigUpdateAndroidBuildActions(ctx ModuleContext) {
149 mergedAconfigFiles := make(map[string]Paths)
Yu Liu67a28422024-03-05 00:36:31 +0000150 mergedModeInfos := make(map[string]ModeInfo)
151
LaMont Jonesb5099382024-01-10 23:42:36 +0000152 ctx.VisitDirectDepsIgnoreBlueprint(func(module Module) {
Yu Liu67a28422024-03-05 00:36:31 +0000153 if aconfig_dep, ok := OtherModuleProvider(ctx, module, CodegenInfoProvider); ok && len(aconfig_dep.ModeInfos) > 0 {
154 maps.Copy(mergedModeInfos, aconfig_dep.ModeInfos)
155 }
156
LaMont Jonesb5099382024-01-10 23:42:36 +0000157 // If any of our dependencies have aconfig declarations (directly or propagated), then merge those and provide them.
158 if dep, ok := OtherModuleProvider(ctx, module, AconfigDeclarationsProviderKey); ok {
159 mergedAconfigFiles[dep.Container] = append(mergedAconfigFiles[dep.Container], dep.IntermediateCacheOutputPath)
160 }
161 if dep, ok := OtherModuleProvider(ctx, module, aconfigPropagatingProviderKey); ok {
162 for container, v := range dep.AconfigFiles {
163 mergedAconfigFiles[container] = append(mergedAconfigFiles[container], v...)
164 }
Yu Liu67a28422024-03-05 00:36:31 +0000165 propagateModeInfos(ctx, module, mergedModeInfos, dep.ModeInfos)
LaMont Jonesb5099382024-01-10 23:42:36 +0000166 }
167 if dep, ok := OtherModuleProvider(ctx, module, AconfigTransitiveDeclarationsInfoProvider); ok {
168 for container, v := range dep.AconfigFiles {
169 mergedAconfigFiles[container] = append(mergedAconfigFiles[container], v...)
170 }
171 }
172 })
173 // We only need to set the provider if we have aconfig files.
174 if len(mergedAconfigFiles) > 0 {
175 for container, aconfigFiles := range mergedAconfigFiles {
176 mergedAconfigFiles[container] = mergeAconfigFiles(ctx, container, aconfigFiles, true)
177 }
178
179 SetProvider(ctx, aconfigPropagatingProviderKey, aconfigPropagatingDeclarationsInfo{
180 AconfigFiles: mergedAconfigFiles,
Yu Liu67a28422024-03-05 00:36:31 +0000181 ModeInfos: mergedModeInfos,
LaMont Jonesb5099382024-01-10 23:42:36 +0000182 })
183 }
184}
185
186func aconfigUpdateAndroidMkData(ctx fillInEntriesContext, mod Module, data *AndroidMkData) {
187 info, ok := SingletonModuleProvider(ctx, mod, aconfigPropagatingProviderKey)
188 // If there is no aconfigPropagatingProvider, or there are no AconfigFiles, then we are done.
189 if !ok || len(info.AconfigFiles) == 0 {
190 return
191 }
192 data.Extra = append(data.Extra, func(w io.Writer, outputFile Path) {
193 AndroidMkEmitAssignList(w, "LOCAL_ACONFIG_FILES", getAconfigFilePaths(mod.base(), info.AconfigFiles).Strings())
194 })
195 // If there is a Custom writer, it needs to support this provider.
196 if data.Custom != nil {
197 switch reflect.TypeOf(mod).String() {
198 case "*aidl.aidlApi": // writes non-custom before adding .phony
199 case "*android_sdk.sdkRepoHost": // doesn't go through base_rules
200 case "*apex.apexBundle": // aconfig_file properties written
201 case "*bpf.bpf": // properties written (both for module and objs)
202 case "*genrule.Module": // writes non-custom before adding .phony
203 case "*java.SystemModules": // doesn't go through base_rules
204 case "*phony.phony": // properties written
205 case "*phony.PhonyRule": // writes phony deps and acts like `.PHONY`
206 case "*sysprop.syspropLibrary": // properties written
207 default:
208 panic(fmt.Errorf("custom make rules do not handle aconfig files for %q (%q) module %q", ctx.ModuleType(mod), reflect.TypeOf(mod), mod))
209 }
210 }
211}
212
213func aconfigUpdateAndroidMkEntries(ctx fillInEntriesContext, mod Module, entries *[]AndroidMkEntries) {
214 // If there are no entries, then we can ignore this module, even if it has aconfig files.
215 if len(*entries) == 0 {
216 return
217 }
218 info, ok := SingletonModuleProvider(ctx, mod, aconfigPropagatingProviderKey)
219 if !ok || len(info.AconfigFiles) == 0 {
220 return
221 }
222 // All of the files in the module potentially depend on the aconfig flag values.
223 for idx, _ := range *entries {
224 (*entries)[idx].ExtraEntries = append((*entries)[idx].ExtraEntries,
225 func(ctx AndroidMkExtraEntriesContext, entries *AndroidMkEntries) {
226 setAconfigFileMkEntries(mod.base(), entries, info.AconfigFiles)
227 },
228 )
229
230 }
231}
232
233func mergeAconfigFiles(ctx ModuleContext, container string, inputs Paths, generateRule bool) Paths {
Spandan Das4d4edfb2024-02-05 19:27:06 +0000234 inputs = SortedUniquePaths(inputs)
LaMont Jonesaa005ae2023-12-19 19:01:57 +0000235 if len(inputs) == 1 {
236 return Paths{inputs[0]}
237 }
238
Yu Liuedeadbf2024-01-10 23:07:35 +0000239 output := PathForModuleOut(ctx, container, "aconfig_merged.pb")
LaMont Jonesaa005ae2023-12-19 19:01:57 +0000240
LaMont Jonesb5099382024-01-10 23:42:36 +0000241 if generateRule {
242 ctx.Build(pctx, BuildParams{
243 Rule: mergeAconfigFilesRule,
244 Description: "merge aconfig files",
245 Inputs: inputs,
246 Output: output,
247 Args: map[string]string{
248 "flags": JoinWithPrefix(inputs.Strings(), "--cache "),
249 },
250 })
251 }
LaMont Jonesaa005ae2023-12-19 19:01:57 +0000252
253 return Paths{output}
254}
LaMont Jonesacae2d72024-01-09 22:53:52 +0000255
LaMont Jonesb5099382024-01-10 23:42:36 +0000256func setAconfigFileMkEntries(m *ModuleBase, entries *AndroidMkEntries, aconfigFiles map[string]Paths) {
257 entries.AddPaths("LOCAL_ACONFIG_FILES", getAconfigFilePaths(m, aconfigFiles))
258}
259
260func getAconfigFilePaths(m *ModuleBase, aconfigFiles map[string]Paths) (paths Paths) {
LaMont Jonesacae2d72024-01-09 22:53:52 +0000261 // TODO(b/311155208): The default container here should be system.
LaMont Jonesb5099382024-01-10 23:42:36 +0000262 container := "system"
LaMont Jonesacae2d72024-01-09 22:53:52 +0000263
264 if m.SocSpecific() {
265 container = "vendor"
266 } else if m.ProductSpecific() {
267 container = "product"
268 } else if m.SystemExtSpecific() {
269 container = "system_ext"
270 }
271
LaMont Jonesb5099382024-01-10 23:42:36 +0000272 paths = append(paths, aconfigFiles[container]...)
273 if container == "system" {
274 // TODO(b/311155208): Once the default container is system, we can drop this.
275 paths = append(paths, aconfigFiles[""]...)
276 }
277 if container != "system" {
278 if len(aconfigFiles[container]) == 0 && len(aconfigFiles[""]) > 0 {
279 // TODO(b/308625757): Either we guessed the container wrong, or the flag is misdeclared.
280 // For now, just include the system (aka "") container if we get here.
281 //fmt.Printf("container_mismatch: module=%v container=%v files=%v\n", m, container, aconfigFiles)
282 }
283 paths = append(paths, aconfigFiles[""]...)
284 }
285 return
LaMont Jonesacae2d72024-01-09 22:53:52 +0000286}