blob: ee9891df1a06f865568bce55d73b331820fc6253 [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
Yu Liu67a28422024-03-05 00:36:31 +000046type ModeInfo struct {
47 Container string
48 Mode string
49}
50type CodegenInfo struct {
51 // AconfigDeclarations is the name of the aconfig_declarations modules that
52 // the codegen module is associated with
53 AconfigDeclarations []string
54
55 // Paths to the cache files of the associated aconfig_declaration modules
56 IntermediateCacheOutputPaths Paths
57
58 // Paths to the srcjar files generated from the java_aconfig_library modules
59 Srcjars Paths
60
61 ModeInfos map[string]ModeInfo
62}
63
64var CodegenInfoProvider = blueprint.NewProvider[CodegenInfo]()
65
66func propagateModeInfos(ctx ModuleContext, module Module, to, from map[string]ModeInfo) {
67 if len(from) > 0 {
68 depTag := ctx.OtherModuleDependencyTag(module)
69 if tag, ok := depTag.(PropagateAconfigValidationDependencyTag); ok && tag.PropagateAconfigValidation() {
70 maps.Copy(to, from)
71 }
72 }
73}
74
LaMont Jonesb5099382024-01-10 23:42:36 +000075type aconfigPropagatingDeclarationsInfo struct {
76 AconfigFiles map[string]Paths
Yu Liu67a28422024-03-05 00:36:31 +000077 ModeInfos map[string]ModeInfo
LaMont Jonesb5099382024-01-10 23:42:36 +000078}
79
Justin Yun40182b62024-05-07 10:22:19 +090080var AconfigPropagatingProviderKey = blueprint.NewProvider[aconfigPropagatingDeclarationsInfo]()
LaMont Jonesb5099382024-01-10 23:42:36 +000081
Yu Liu67a28422024-03-05 00:36:31 +000082func VerifyAconfigBuildMode(ctx ModuleContext, container string, module blueprint.Module, asError bool) {
Justin Yun40182b62024-05-07 10:22:19 +090083 if dep, ok := OtherModuleProvider(ctx, module, AconfigPropagatingProviderKey); ok {
Yu Liu67a28422024-03-05 00:36:31 +000084 for k, v := range dep.ModeInfos {
85 msg := fmt.Sprintf("%s/%s depends on %s/%s/%s across containers\n",
86 module.Name(), container, k, v.Container, v.Mode)
87 if v.Container != container && v.Mode != "exported" && v.Mode != "force-read-only" {
88 if asError {
89 ctx.ModuleErrorf(msg)
90 } else {
91 fmt.Printf("WARNING: " + msg)
92 }
93 } else {
94 if !asError {
95 fmt.Printf("PASSED: " + msg)
96 }
97 }
98 }
99 }
100}
101
LaMont Jonesb5099382024-01-10 23:42:36 +0000102func aconfigUpdateAndroidBuildActions(ctx ModuleContext) {
103 mergedAconfigFiles := make(map[string]Paths)
Yu Liu67a28422024-03-05 00:36:31 +0000104 mergedModeInfos := make(map[string]ModeInfo)
105
LaMont Jonesb5099382024-01-10 23:42:36 +0000106 ctx.VisitDirectDepsIgnoreBlueprint(func(module Module) {
Yu Liu67a28422024-03-05 00:36:31 +0000107 if aconfig_dep, ok := OtherModuleProvider(ctx, module, CodegenInfoProvider); ok && len(aconfig_dep.ModeInfos) > 0 {
108 maps.Copy(mergedModeInfos, aconfig_dep.ModeInfos)
109 }
110
LaMont Jonesb5099382024-01-10 23:42:36 +0000111 // If any of our dependencies have aconfig declarations (directly or propagated), then merge those and provide them.
112 if dep, ok := OtherModuleProvider(ctx, module, AconfigDeclarationsProviderKey); ok {
113 mergedAconfigFiles[dep.Container] = append(mergedAconfigFiles[dep.Container], dep.IntermediateCacheOutputPath)
114 }
Justin Yun40182b62024-05-07 10:22:19 +0900115 if dep, ok := OtherModuleProvider(ctx, module, AconfigPropagatingProviderKey); ok {
LaMont Jonesb5099382024-01-10 23:42:36 +0000116 for container, v := range dep.AconfigFiles {
117 mergedAconfigFiles[container] = append(mergedAconfigFiles[container], v...)
118 }
Yu Liu67a28422024-03-05 00:36:31 +0000119 propagateModeInfos(ctx, module, mergedModeInfos, dep.ModeInfos)
LaMont Jonesb5099382024-01-10 23:42:36 +0000120 }
LaMont Jonesb5099382024-01-10 23:42:36 +0000121 })
122 // We only need to set the provider if we have aconfig files.
123 if len(mergedAconfigFiles) > 0 {
Spandan Das87f5ee42024-03-28 21:22:37 +0000124 for _, container := range SortedKeys(mergedAconfigFiles) {
125 aconfigFiles := mergedAconfigFiles[container]
LaMont Jonesb5099382024-01-10 23:42:36 +0000126 mergedAconfigFiles[container] = mergeAconfigFiles(ctx, container, aconfigFiles, true)
127 }
128
Justin Yun40182b62024-05-07 10:22:19 +0900129 SetProvider(ctx, AconfigPropagatingProviderKey, aconfigPropagatingDeclarationsInfo{
LaMont Jonesb5099382024-01-10 23:42:36 +0000130 AconfigFiles: mergedAconfigFiles,
Yu Liu67a28422024-03-05 00:36:31 +0000131 ModeInfos: mergedModeInfos,
LaMont Jonesb5099382024-01-10 23:42:36 +0000132 })
Justin Yun74f3f302024-05-07 14:32:14 +0900133 ctx.Module().base().aconfigFilePaths = getAconfigFilePaths(ctx.Module().base(), mergedAconfigFiles)
LaMont Jonesb5099382024-01-10 23:42:36 +0000134 }
135}
136
137func aconfigUpdateAndroidMkData(ctx fillInEntriesContext, mod Module, data *AndroidMkData) {
Justin Yun40182b62024-05-07 10:22:19 +0900138 info, ok := SingletonModuleProvider(ctx, mod, AconfigPropagatingProviderKey)
LaMont Jonesb5099382024-01-10 23:42:36 +0000139 // If there is no aconfigPropagatingProvider, or there are no AconfigFiles, then we are done.
140 if !ok || len(info.AconfigFiles) == 0 {
141 return
142 }
143 data.Extra = append(data.Extra, func(w io.Writer, outputFile Path) {
144 AndroidMkEmitAssignList(w, "LOCAL_ACONFIG_FILES", getAconfigFilePaths(mod.base(), info.AconfigFiles).Strings())
145 })
146 // If there is a Custom writer, it needs to support this provider.
147 if data.Custom != nil {
148 switch reflect.TypeOf(mod).String() {
149 case "*aidl.aidlApi": // writes non-custom before adding .phony
150 case "*android_sdk.sdkRepoHost": // doesn't go through base_rules
151 case "*apex.apexBundle": // aconfig_file properties written
152 case "*bpf.bpf": // properties written (both for module and objs)
153 case "*genrule.Module": // writes non-custom before adding .phony
154 case "*java.SystemModules": // doesn't go through base_rules
155 case "*phony.phony": // properties written
156 case "*phony.PhonyRule": // writes phony deps and acts like `.PHONY`
157 case "*sysprop.syspropLibrary": // properties written
158 default:
159 panic(fmt.Errorf("custom make rules do not handle aconfig files for %q (%q) module %q", ctx.ModuleType(mod), reflect.TypeOf(mod), mod))
160 }
161 }
162}
163
164func aconfigUpdateAndroidMkEntries(ctx fillInEntriesContext, mod Module, entries *[]AndroidMkEntries) {
165 // If there are no entries, then we can ignore this module, even if it has aconfig files.
166 if len(*entries) == 0 {
167 return
168 }
Justin Yun40182b62024-05-07 10:22:19 +0900169 info, ok := SingletonModuleProvider(ctx, mod, AconfigPropagatingProviderKey)
LaMont Jonesb5099382024-01-10 23:42:36 +0000170 if !ok || len(info.AconfigFiles) == 0 {
171 return
172 }
173 // All of the files in the module potentially depend on the aconfig flag values.
174 for idx, _ := range *entries {
175 (*entries)[idx].ExtraEntries = append((*entries)[idx].ExtraEntries,
176 func(ctx AndroidMkExtraEntriesContext, entries *AndroidMkEntries) {
Justin Yun40182b62024-05-07 10:22:19 +0900177 entries.AddPaths("LOCAL_ACONFIG_FILES", getAconfigFilePaths(mod.base(), info.AconfigFiles))
LaMont Jonesb5099382024-01-10 23:42:36 +0000178 },
179 )
180
181 }
182}
183
184func mergeAconfigFiles(ctx ModuleContext, container string, inputs Paths, generateRule bool) Paths {
Spandan Das4d4edfb2024-02-05 19:27:06 +0000185 inputs = SortedUniquePaths(inputs)
LaMont Jonesaa005ae2023-12-19 19:01:57 +0000186 if len(inputs) == 1 {
187 return Paths{inputs[0]}
188 }
189
Yu Liuedeadbf2024-01-10 23:07:35 +0000190 output := PathForModuleOut(ctx, container, "aconfig_merged.pb")
LaMont Jonesaa005ae2023-12-19 19:01:57 +0000191
LaMont Jonesb5099382024-01-10 23:42:36 +0000192 if generateRule {
193 ctx.Build(pctx, BuildParams{
194 Rule: mergeAconfigFilesRule,
195 Description: "merge aconfig files",
196 Inputs: inputs,
197 Output: output,
198 Args: map[string]string{
199 "flags": JoinWithPrefix(inputs.Strings(), "--cache "),
200 },
201 })
202 }
LaMont Jonesaa005ae2023-12-19 19:01:57 +0000203
204 return Paths{output}
205}
LaMont Jonesacae2d72024-01-09 22:53:52 +0000206
LaMont Jonesb5099382024-01-10 23:42:36 +0000207func getAconfigFilePaths(m *ModuleBase, aconfigFiles map[string]Paths) (paths Paths) {
LaMont Jonesacae2d72024-01-09 22:53:52 +0000208 // TODO(b/311155208): The default container here should be system.
LaMont Jonesb5099382024-01-10 23:42:36 +0000209 container := "system"
LaMont Jonesacae2d72024-01-09 22:53:52 +0000210
211 if m.SocSpecific() {
212 container = "vendor"
213 } else if m.ProductSpecific() {
214 container = "product"
215 } else if m.SystemExtSpecific() {
216 container = "system_ext"
217 }
218
LaMont Jonesb5099382024-01-10 23:42:36 +0000219 paths = append(paths, aconfigFiles[container]...)
220 if container == "system" {
221 // TODO(b/311155208): Once the default container is system, we can drop this.
222 paths = append(paths, aconfigFiles[""]...)
223 }
224 if container != "system" {
225 if len(aconfigFiles[container]) == 0 && len(aconfigFiles[""]) > 0 {
226 // TODO(b/308625757): Either we guessed the container wrong, or the flag is misdeclared.
227 // For now, just include the system (aka "") container if we get here.
228 //fmt.Printf("container_mismatch: module=%v container=%v files=%v\n", m, container, aconfigFiles)
229 }
230 paths = append(paths, aconfigFiles[""]...)
231 }
232 return
LaMont Jonesacae2d72024-01-09 22:53:52 +0000233}