blob: 74c1a5eccbe434e2ef39859e64109ed53725781a [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"
20 "reflect"
21
LaMont Jonesaa005ae2023-12-19 19:01:57 +000022 "github.com/google/blueprint"
23)
24
25var (
26 mergeAconfigFilesRule = pctx.AndroidStaticRule("mergeAconfigFilesRule",
27 blueprint.RuleParams{
28 Command: `${aconfig} dump --dedup --format protobuf --out $out $flags`,
29 CommandDeps: []string{"${aconfig}"},
30 }, "flags")
31 _ = pctx.HostBinToolVariable("aconfig", "aconfig")
32)
33
34// Provider published by aconfig_value_set
35type AconfigDeclarationsProviderData struct {
36 Package string
37 Container string
Zi Wang0e5d16c2024-02-08 06:19:34 +000038 Exportable bool
LaMont Jonesaa005ae2023-12-19 19:01:57 +000039 IntermediateCacheOutputPath WritablePath
40 IntermediateDumpOutputPath WritablePath
41}
42
43var AconfigDeclarationsProviderKey = blueprint.NewProvider[AconfigDeclarationsProviderData]()
44
45// This is used to collect the aconfig declarations info on the transitive closure,
46// the data is keyed on the container.
47type AconfigTransitiveDeclarationsInfo struct {
48 AconfigFiles map[string]Paths
49}
50
51var AconfigTransitiveDeclarationsInfoProvider = blueprint.NewProvider[AconfigTransitiveDeclarationsInfo]()
52
LaMont Jonesb5099382024-01-10 23:42:36 +000053// CollectDependencyAconfigFiles is used by some module types to provide finer dependency graphing than
54// we can do in ModuleBase.
LaMont Jonesaa005ae2023-12-19 19:01:57 +000055func CollectDependencyAconfigFiles(ctx ModuleContext, mergedAconfigFiles *map[string]Paths) {
56 if *mergedAconfigFiles == nil {
57 *mergedAconfigFiles = make(map[string]Paths)
58 }
LaMont Jones34314b72024-01-18 18:27:35 +000059 ctx.VisitDirectDepsIgnoreBlueprint(func(module Module) {
LaMont Jonesaa005ae2023-12-19 19:01:57 +000060 if dep, _ := OtherModuleProvider(ctx, module, AconfigDeclarationsProviderKey); dep.IntermediateCacheOutputPath != nil {
61 (*mergedAconfigFiles)[dep.Container] = append((*mergedAconfigFiles)[dep.Container], dep.IntermediateCacheOutputPath)
62 return
63 }
LaMont Jonesb5099382024-01-10 23:42:36 +000064 if dep, ok := OtherModuleProvider(ctx, module, aconfigPropagatingProviderKey); ok {
65 for container, v := range dep.AconfigFiles {
66 (*mergedAconfigFiles)[container] = append((*mergedAconfigFiles)[container], v...)
67 }
68 }
69 // We process these last, so that they determine the final value, eliminating any duplicates that we picked up
70 // from UpdateAndroidBuildActions.
71 if dep, ok := OtherModuleProvider(ctx, module, AconfigTransitiveDeclarationsInfoProvider); ok {
LaMont Jonesaa005ae2023-12-19 19:01:57 +000072 for container, v := range dep.AconfigFiles {
73 (*mergedAconfigFiles)[container] = append((*mergedAconfigFiles)[container], v...)
74 }
75 }
76 })
77
78 for container, aconfigFiles := range *mergedAconfigFiles {
LaMont Jonesb5099382024-01-10 23:42:36 +000079 (*mergedAconfigFiles)[container] = mergeAconfigFiles(ctx, container, aconfigFiles, false)
LaMont Jonesaa005ae2023-12-19 19:01:57 +000080 }
81
82 SetProvider(ctx, AconfigTransitiveDeclarationsInfoProvider, AconfigTransitiveDeclarationsInfo{
83 AconfigFiles: *mergedAconfigFiles,
84 })
85}
86
LaMont Jonesb5099382024-01-10 23:42:36 +000087func SetAconfigFileMkEntries(m *ModuleBase, entries *AndroidMkEntries, aconfigFiles map[string]Paths) {
88 setAconfigFileMkEntries(m, entries, aconfigFiles)
89}
90
91type aconfigPropagatingDeclarationsInfo struct {
92 AconfigFiles map[string]Paths
93}
94
95var aconfigPropagatingProviderKey = blueprint.NewProvider[aconfigPropagatingDeclarationsInfo]()
96
97func aconfigUpdateAndroidBuildActions(ctx ModuleContext) {
98 mergedAconfigFiles := make(map[string]Paths)
99 ctx.VisitDirectDepsIgnoreBlueprint(func(module Module) {
100 // If any of our dependencies have aconfig declarations (directly or propagated), then merge those and provide them.
101 if dep, ok := OtherModuleProvider(ctx, module, AconfigDeclarationsProviderKey); ok {
102 mergedAconfigFiles[dep.Container] = append(mergedAconfigFiles[dep.Container], dep.IntermediateCacheOutputPath)
103 }
104 if dep, ok := OtherModuleProvider(ctx, module, aconfigPropagatingProviderKey); ok {
105 for container, v := range dep.AconfigFiles {
106 mergedAconfigFiles[container] = append(mergedAconfigFiles[container], v...)
107 }
108 }
109 if dep, ok := OtherModuleProvider(ctx, module, AconfigTransitiveDeclarationsInfoProvider); ok {
110 for container, v := range dep.AconfigFiles {
111 mergedAconfigFiles[container] = append(mergedAconfigFiles[container], v...)
112 }
113 }
114 })
115 // We only need to set the provider if we have aconfig files.
116 if len(mergedAconfigFiles) > 0 {
117 for container, aconfigFiles := range mergedAconfigFiles {
118 mergedAconfigFiles[container] = mergeAconfigFiles(ctx, container, aconfigFiles, true)
119 }
120
121 SetProvider(ctx, aconfigPropagatingProviderKey, aconfigPropagatingDeclarationsInfo{
122 AconfigFiles: mergedAconfigFiles,
123 })
124 }
125}
126
127func aconfigUpdateAndroidMkData(ctx fillInEntriesContext, mod Module, data *AndroidMkData) {
128 info, ok := SingletonModuleProvider(ctx, mod, aconfigPropagatingProviderKey)
129 // If there is no aconfigPropagatingProvider, or there are no AconfigFiles, then we are done.
130 if !ok || len(info.AconfigFiles) == 0 {
131 return
132 }
133 data.Extra = append(data.Extra, func(w io.Writer, outputFile Path) {
134 AndroidMkEmitAssignList(w, "LOCAL_ACONFIG_FILES", getAconfigFilePaths(mod.base(), info.AconfigFiles).Strings())
135 })
136 // If there is a Custom writer, it needs to support this provider.
137 if data.Custom != nil {
138 switch reflect.TypeOf(mod).String() {
139 case "*aidl.aidlApi": // writes non-custom before adding .phony
140 case "*android_sdk.sdkRepoHost": // doesn't go through base_rules
141 case "*apex.apexBundle": // aconfig_file properties written
142 case "*bpf.bpf": // properties written (both for module and objs)
143 case "*genrule.Module": // writes non-custom before adding .phony
144 case "*java.SystemModules": // doesn't go through base_rules
145 case "*phony.phony": // properties written
146 case "*phony.PhonyRule": // writes phony deps and acts like `.PHONY`
147 case "*sysprop.syspropLibrary": // properties written
148 default:
149 panic(fmt.Errorf("custom make rules do not handle aconfig files for %q (%q) module %q", ctx.ModuleType(mod), reflect.TypeOf(mod), mod))
150 }
151 }
152}
153
154func aconfigUpdateAndroidMkEntries(ctx fillInEntriesContext, mod Module, entries *[]AndroidMkEntries) {
155 // If there are no entries, then we can ignore this module, even if it has aconfig files.
156 if len(*entries) == 0 {
157 return
158 }
159 info, ok := SingletonModuleProvider(ctx, mod, aconfigPropagatingProviderKey)
160 if !ok || len(info.AconfigFiles) == 0 {
161 return
162 }
163 // All of the files in the module potentially depend on the aconfig flag values.
164 for idx, _ := range *entries {
165 (*entries)[idx].ExtraEntries = append((*entries)[idx].ExtraEntries,
166 func(ctx AndroidMkExtraEntriesContext, entries *AndroidMkEntries) {
167 setAconfigFileMkEntries(mod.base(), entries, info.AconfigFiles)
168 },
169 )
170
171 }
172}
173
174func mergeAconfigFiles(ctx ModuleContext, container string, inputs Paths, generateRule bool) Paths {
Spandan Das4d4edfb2024-02-05 19:27:06 +0000175 inputs = SortedUniquePaths(inputs)
LaMont Jonesaa005ae2023-12-19 19:01:57 +0000176 if len(inputs) == 1 {
177 return Paths{inputs[0]}
178 }
179
Yu Liuedeadbf2024-01-10 23:07:35 +0000180 output := PathForModuleOut(ctx, container, "aconfig_merged.pb")
LaMont Jonesaa005ae2023-12-19 19:01:57 +0000181
LaMont Jonesb5099382024-01-10 23:42:36 +0000182 if generateRule {
183 ctx.Build(pctx, BuildParams{
184 Rule: mergeAconfigFilesRule,
185 Description: "merge aconfig files",
186 Inputs: inputs,
187 Output: output,
188 Args: map[string]string{
189 "flags": JoinWithPrefix(inputs.Strings(), "--cache "),
190 },
191 })
192 }
LaMont Jonesaa005ae2023-12-19 19:01:57 +0000193
194 return Paths{output}
195}
LaMont Jonesacae2d72024-01-09 22:53:52 +0000196
LaMont Jonesb5099382024-01-10 23:42:36 +0000197func setAconfigFileMkEntries(m *ModuleBase, entries *AndroidMkEntries, aconfigFiles map[string]Paths) {
198 entries.AddPaths("LOCAL_ACONFIG_FILES", getAconfigFilePaths(m, aconfigFiles))
199}
200
201func getAconfigFilePaths(m *ModuleBase, aconfigFiles map[string]Paths) (paths Paths) {
LaMont Jonesacae2d72024-01-09 22:53:52 +0000202 // TODO(b/311155208): The default container here should be system.
LaMont Jonesb5099382024-01-10 23:42:36 +0000203 container := "system"
LaMont Jonesacae2d72024-01-09 22:53:52 +0000204
205 if m.SocSpecific() {
206 container = "vendor"
207 } else if m.ProductSpecific() {
208 container = "product"
209 } else if m.SystemExtSpecific() {
210 container = "system_ext"
211 }
212
LaMont Jonesb5099382024-01-10 23:42:36 +0000213 paths = append(paths, aconfigFiles[container]...)
214 if container == "system" {
215 // TODO(b/311155208): Once the default container is system, we can drop this.
216 paths = append(paths, aconfigFiles[""]...)
217 }
218 if container != "system" {
219 if len(aconfigFiles[container]) == 0 && len(aconfigFiles[""]) > 0 {
220 // TODO(b/308625757): Either we guessed the container wrong, or the flag is misdeclared.
221 // For now, just include the system (aka "") container if we get here.
222 //fmt.Printf("container_mismatch: module=%v container=%v files=%v\n", m, container, aconfigFiles)
223 }
224 paths = append(paths, aconfigFiles[""]...)
225 }
226 return
LaMont Jonesacae2d72024-01-09 22:53:52 +0000227}