blob: 205b855900b9a13944b6dd849add2a6a61575faa [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
LaMont Jones21d04d92024-06-11 11:28:54 -070046type AconfigReleaseDeclarationsProviderData map[string]AconfigDeclarationsProviderData
47
48var AconfigReleaseDeclarationsProviderKey = blueprint.NewProvider[AconfigReleaseDeclarationsProviderData]()
49
Yu Liu67a28422024-03-05 00:36:31 +000050type ModeInfo struct {
51 Container string
52 Mode string
53}
54type CodegenInfo struct {
55 // AconfigDeclarations is the name of the aconfig_declarations modules that
56 // the codegen module is associated with
57 AconfigDeclarations []string
58
59 // Paths to the cache files of the associated aconfig_declaration modules
60 IntermediateCacheOutputPaths Paths
61
62 // Paths to the srcjar files generated from the java_aconfig_library modules
63 Srcjars Paths
64
65 ModeInfos map[string]ModeInfo
66}
67
68var CodegenInfoProvider = blueprint.NewProvider[CodegenInfo]()
69
70func propagateModeInfos(ctx ModuleContext, module Module, to, from map[string]ModeInfo) {
71 if len(from) > 0 {
72 depTag := ctx.OtherModuleDependencyTag(module)
73 if tag, ok := depTag.(PropagateAconfigValidationDependencyTag); ok && tag.PropagateAconfigValidation() {
74 maps.Copy(to, from)
75 }
76 }
77}
78
LaMont Jonesb5099382024-01-10 23:42:36 +000079type aconfigPropagatingDeclarationsInfo struct {
80 AconfigFiles map[string]Paths
Yu Liu67a28422024-03-05 00:36:31 +000081 ModeInfos map[string]ModeInfo
LaMont Jonesb5099382024-01-10 23:42:36 +000082}
83
Justin Yun40182b62024-05-07 10:22:19 +090084var AconfigPropagatingProviderKey = blueprint.NewProvider[aconfigPropagatingDeclarationsInfo]()
LaMont Jonesb5099382024-01-10 23:42:36 +000085
Yu Liu67a28422024-03-05 00:36:31 +000086func VerifyAconfigBuildMode(ctx ModuleContext, container string, module blueprint.Module, asError bool) {
Justin Yun40182b62024-05-07 10:22:19 +090087 if dep, ok := OtherModuleProvider(ctx, module, AconfigPropagatingProviderKey); ok {
Yu Liu67a28422024-03-05 00:36:31 +000088 for k, v := range dep.ModeInfos {
89 msg := fmt.Sprintf("%s/%s depends on %s/%s/%s across containers\n",
90 module.Name(), container, k, v.Container, v.Mode)
91 if v.Container != container && v.Mode != "exported" && v.Mode != "force-read-only" {
92 if asError {
93 ctx.ModuleErrorf(msg)
94 } else {
Justin Yunf5ed2be2024-12-18 17:50:43 +090095 fmt.Print("WARNING: " + msg)
Yu Liu67a28422024-03-05 00:36:31 +000096 }
97 } else {
98 if !asError {
Justin Yunf5ed2be2024-12-18 17:50:43 +090099 fmt.Print("PASSED: " + msg)
Yu Liu67a28422024-03-05 00:36:31 +0000100 }
101 }
102 }
103 }
104}
105
LaMont Jonesb5099382024-01-10 23:42:36 +0000106func aconfigUpdateAndroidBuildActions(ctx ModuleContext) {
107 mergedAconfigFiles := make(map[string]Paths)
Yu Liu67a28422024-03-05 00:36:31 +0000108 mergedModeInfos := make(map[string]ModeInfo)
109
Yu Liuac483e02024-11-11 22:29:30 +0000110 ctx.VisitDirectDepsProxy(func(module ModuleProxy) {
Yu Liu67a28422024-03-05 00:36:31 +0000111 if aconfig_dep, ok := OtherModuleProvider(ctx, module, CodegenInfoProvider); ok && len(aconfig_dep.ModeInfos) > 0 {
112 maps.Copy(mergedModeInfos, aconfig_dep.ModeInfos)
113 }
114
LaMont Jonesb5099382024-01-10 23:42:36 +0000115 // If any of our dependencies have aconfig declarations (directly or propagated), then merge those and provide them.
116 if dep, ok := OtherModuleProvider(ctx, module, AconfigDeclarationsProviderKey); ok {
117 mergedAconfigFiles[dep.Container] = append(mergedAconfigFiles[dep.Container], dep.IntermediateCacheOutputPath)
118 }
LaMont Jones21d04d92024-06-11 11:28:54 -0700119 // If we were generating on-device artifacts for other release configs, we would need to add code here to propagate
120 // those artifacts as well. See also b/298444886.
Justin Yun40182b62024-05-07 10:22:19 +0900121 if dep, ok := OtherModuleProvider(ctx, module, AconfigPropagatingProviderKey); ok {
LaMont Jonesb5099382024-01-10 23:42:36 +0000122 for container, v := range dep.AconfigFiles {
123 mergedAconfigFiles[container] = append(mergedAconfigFiles[container], v...)
124 }
Yu Liu67a28422024-03-05 00:36:31 +0000125 propagateModeInfos(ctx, module, mergedModeInfos, dep.ModeInfos)
LaMont Jonesb5099382024-01-10 23:42:36 +0000126 }
LaMont Jonesb5099382024-01-10 23:42:36 +0000127 })
128 // We only need to set the provider if we have aconfig files.
129 if len(mergedAconfigFiles) > 0 {
Spandan Das87f5ee42024-03-28 21:22:37 +0000130 for _, container := range SortedKeys(mergedAconfigFiles) {
131 aconfigFiles := mergedAconfigFiles[container]
LaMont Jonesb5099382024-01-10 23:42:36 +0000132 mergedAconfigFiles[container] = mergeAconfigFiles(ctx, container, aconfigFiles, true)
133 }
134
Justin Yun40182b62024-05-07 10:22:19 +0900135 SetProvider(ctx, AconfigPropagatingProviderKey, aconfigPropagatingDeclarationsInfo{
LaMont Jonesb5099382024-01-10 23:42:36 +0000136 AconfigFiles: mergedAconfigFiles,
Yu Liu67a28422024-03-05 00:36:31 +0000137 ModeInfos: mergedModeInfos,
LaMont Jonesb5099382024-01-10 23:42:36 +0000138 })
Yu Liu64371e02025-02-19 23:44:48 +0000139 ctx.setAconfigPaths(getAconfigFilePaths(getContainer(ctx.Module()), mergedAconfigFiles))
LaMont Jonesb5099382024-01-10 23:42:36 +0000140 }
141}
142
143func aconfigUpdateAndroidMkData(ctx fillInEntriesContext, mod Module, data *AndroidMkData) {
Yu Liu663e4502024-08-12 18:23:59 +0000144 info, ok := OtherModuleProvider(ctx, mod, AconfigPropagatingProviderKey)
LaMont Jonesb5099382024-01-10 23:42:36 +0000145 // If there is no aconfigPropagatingProvider, or there are no AconfigFiles, then we are done.
146 if !ok || len(info.AconfigFiles) == 0 {
147 return
148 }
149 data.Extra = append(data.Extra, func(w io.Writer, outputFile Path) {
Yu Liu64371e02025-02-19 23:44:48 +0000150 AndroidMkEmitAssignList(w, "LOCAL_ACONFIG_FILES", getAconfigFilePaths(
151 getContainerUsingProviders(ctx, mod), info.AconfigFiles).Strings())
LaMont Jonesb5099382024-01-10 23:42:36 +0000152 })
153 // If there is a Custom writer, it needs to support this provider.
154 if data.Custom != nil {
155 switch reflect.TypeOf(mod).String() {
156 case "*aidl.aidlApi": // writes non-custom before adding .phony
157 case "*android_sdk.sdkRepoHost": // doesn't go through base_rules
158 case "*apex.apexBundle": // aconfig_file properties written
159 case "*bpf.bpf": // properties written (both for module and objs)
160 case "*genrule.Module": // writes non-custom before adding .phony
161 case "*java.SystemModules": // doesn't go through base_rules
162 case "*phony.phony": // properties written
163 case "*phony.PhonyRule": // writes phony deps and acts like `.PHONY`
164 case "*sysprop.syspropLibrary": // properties written
165 default:
166 panic(fmt.Errorf("custom make rules do not handle aconfig files for %q (%q) module %q", ctx.ModuleType(mod), reflect.TypeOf(mod), mod))
167 }
168 }
169}
170
171func aconfigUpdateAndroidMkEntries(ctx fillInEntriesContext, mod Module, entries *[]AndroidMkEntries) {
172 // If there are no entries, then we can ignore this module, even if it has aconfig files.
173 if len(*entries) == 0 {
174 return
175 }
Yu Liu663e4502024-08-12 18:23:59 +0000176 info, ok := OtherModuleProvider(ctx, mod, AconfigPropagatingProviderKey)
LaMont Jonesb5099382024-01-10 23:42:36 +0000177 if !ok || len(info.AconfigFiles) == 0 {
178 return
179 }
180 // All of the files in the module potentially depend on the aconfig flag values.
181 for idx, _ := range *entries {
182 (*entries)[idx].ExtraEntries = append((*entries)[idx].ExtraEntries,
Yu Liu64371e02025-02-19 23:44:48 +0000183 func(_ AndroidMkExtraEntriesContext, entries *AndroidMkEntries) {
184 entries.AddPaths("LOCAL_ACONFIG_FILES", getAconfigFilePaths(
185 getContainerUsingProviders(ctx, mod), info.AconfigFiles))
LaMont Jonesb5099382024-01-10 23:42:36 +0000186 },
187 )
188
189 }
190}
191
Yu Liu64371e02025-02-19 23:44:48 +0000192// TODO(b/397766191): Change the signature to take ModuleProxy
193// Please only access the module's internal data through providers.
mrziwang18420972024-09-03 15:12:51 -0700194func aconfigUpdateAndroidMkInfos(ctx fillInEntriesContext, mod Module, infos *AndroidMkProviderInfo) {
195 info, ok := OtherModuleProvider(ctx, mod, AconfigPropagatingProviderKey)
196 if !ok || len(info.AconfigFiles) == 0 {
197 return
198 }
199 // All of the files in the module potentially depend on the aconfig flag values.
Yu Liu64371e02025-02-19 23:44:48 +0000200 infos.PrimaryInfo.AddPaths("LOCAL_ACONFIG_FILES", getAconfigFilePaths(
201 getContainerUsingProviders(ctx, mod), info.AconfigFiles))
mrziwang18420972024-09-03 15:12:51 -0700202 if len(infos.ExtraInfo) > 0 {
203 for _, ei := range (*infos).ExtraInfo {
Yu Liu64371e02025-02-19 23:44:48 +0000204 ei.AddPaths("LOCAL_ACONFIG_FILES", getAconfigFilePaths(
205 getContainerUsingProviders(ctx, mod), info.AconfigFiles))
mrziwang18420972024-09-03 15:12:51 -0700206 }
207 }
208}
209
LaMont Jonesb5099382024-01-10 23:42:36 +0000210func mergeAconfigFiles(ctx ModuleContext, container string, inputs Paths, generateRule bool) Paths {
Spandan Das4d4edfb2024-02-05 19:27:06 +0000211 inputs = SortedUniquePaths(inputs)
LaMont Jonesaa005ae2023-12-19 19:01:57 +0000212 if len(inputs) == 1 {
213 return Paths{inputs[0]}
214 }
215
Yu Liuedeadbf2024-01-10 23:07:35 +0000216 output := PathForModuleOut(ctx, container, "aconfig_merged.pb")
LaMont Jonesaa005ae2023-12-19 19:01:57 +0000217
LaMont Jonesb5099382024-01-10 23:42:36 +0000218 if generateRule {
219 ctx.Build(pctx, BuildParams{
220 Rule: mergeAconfigFilesRule,
221 Description: "merge aconfig files",
222 Inputs: inputs,
223 Output: output,
224 Args: map[string]string{
225 "flags": JoinWithPrefix(inputs.Strings(), "--cache "),
226 },
227 })
228 }
LaMont Jonesaa005ae2023-12-19 19:01:57 +0000229
230 return Paths{output}
231}
LaMont Jonesacae2d72024-01-09 22:53:52 +0000232
Yu Liu64371e02025-02-19 23:44:48 +0000233func getContainer(m Module) string {
LaMont Jonesb5099382024-01-10 23:42:36 +0000234 container := "system"
Yu Liu64371e02025-02-19 23:44:48 +0000235 base := m.base()
236 if base.SocSpecific() {
LaMont Jonesacae2d72024-01-09 22:53:52 +0000237 container = "vendor"
Yu Liu64371e02025-02-19 23:44:48 +0000238 } else if base.ProductSpecific() {
LaMont Jonesacae2d72024-01-09 22:53:52 +0000239 container = "product"
Yu Liu64371e02025-02-19 23:44:48 +0000240 } else if base.SystemExtSpecific() {
Dennis Shen01efb832024-09-12 22:05:08 +0000241 // system_ext and system partitions should be treated as one container
242 container = "system"
LaMont Jonesacae2d72024-01-09 22:53:52 +0000243 }
244
Yu Liu64371e02025-02-19 23:44:48 +0000245 return container
246}
247
248// TODO(b/397766191): Change the signature to take ModuleProxy
249// Please only access the module's internal data through providers.
250func getContainerUsingProviders(ctx OtherModuleProviderContext, m Module) string {
251 container := "system"
252 commonInfo, _ := OtherModuleProvider(ctx, m, CommonModuleInfoKey)
253 if commonInfo.Vendor || commonInfo.Proprietary || commonInfo.SocSpecific {
254 container = "vendor"
255 } else if commonInfo.ProductSpecific {
256 container = "product"
257 } else if commonInfo.SystemExtSpecific {
258 // system_ext and system partitions should be treated as one container
259 container = "system"
260 }
261
262 return container
263}
264
265func getAconfigFilePaths(container string, aconfigFiles map[string]Paths) (paths Paths) {
LaMont Jonesb5099382024-01-10 23:42:36 +0000266 paths = append(paths, aconfigFiles[container]...)
LaMont Jonesd4a6cc62024-06-28 14:30:59 +0000267 if container == "system" {
268 // TODO(b/311155208): Once the default container is system, we can drop this.
269 paths = append(paths, aconfigFiles[""]...)
270 }
271 if container != "system" {
272 if len(aconfigFiles[container]) == 0 && len(aconfigFiles[""]) > 0 {
273 // TODO(b/308625757): Either we guessed the container wrong, or the flag is misdeclared.
274 // For now, just include the system (aka "") container if we get here.
275 //fmt.Printf("container_mismatch: module=%v container=%v files=%v\n", m, container, aconfigFiles)
276 }
277 paths = append(paths, aconfigFiles[""]...)
278 }
LaMont Jonesb5099382024-01-10 23:42:36 +0000279 return
LaMont Jonesacae2d72024-01-09 22:53:52 +0000280}