blob: 096b1321e2dcacfe55c882ba15efa62893efc161 [file] [log] [blame]
Jihoon Kangadd2bb22024-11-05 22:29:34 +00001// Copyright (C) 2024 The Android Open Source Project
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 fsgen
16
17import (
18 "android/soong/android"
19 "fmt"
20 "slices"
21 "sync"
22
23 "github.com/google/blueprint/proptools"
24)
25
26func RegisterCollectFileSystemDepsMutators(ctx android.RegisterMutatorsContext) {
27 ctx.BottomUp("fs_collect_deps", collectDepsMutator).MutatesGlobalState()
28 ctx.BottomUp("fs_set_deps", setDepsMutator)
29}
30
31var fsGenStateOnceKey = android.NewOnceKey("FsGenState")
32var fsGenRemoveOverridesOnceKey = android.NewOnceKey("FsGenRemoveOverrides")
33
34// Map of partition module name to its partition that may be generated by Soong.
35// Note that it is not guaranteed that all modules returned by this function are successfully
36// created.
37func getAllSoongGeneratedPartitionNames(config android.Config, partitions []string) map[string]string {
38 ret := map[string]string{}
39 for _, partition := range partitions {
40 ret[generatedModuleNameForPartition(config, partition)] = partition
41 }
42 return ret
43}
44
45type depCandidateProps struct {
46 Namespace string
47 Multilib string
48 Arch []android.ArchType
49}
50
51// Map of module name to depCandidateProps
52type multilibDeps map[string]*depCandidateProps
53
54// Information necessary to generate the filesystem modules, including details about their
55// dependencies
56type FsGenState struct {
57 // List of modules in `PRODUCT_PACKAGES` and `PRODUCT_PACKAGES_DEBUG`
58 depCandidates []string
59 // Map of names of partition to the information of modules to be added as deps
60 fsDeps map[string]*multilibDeps
61 // List of name of partitions to be generated by the filesystem_creator module
62 soongGeneratedPartitions []string
63 // Mutex to protect the fsDeps
64 fsDepsMutex sync.Mutex
65 // Map of _all_ soong module names to their corresponding installation properties
66 moduleToInstallationProps map[string]installationProperties
67}
68
69type installationProperties struct {
70 Required []string
71 Overrides []string
72}
73
74func defaultDepCandidateProps(config android.Config) *depCandidateProps {
75 return &depCandidateProps{
76 Namespace: ".",
77 Arch: []android.ArchType{config.BuildArch},
78 }
79}
80
81func generatedPartitions(ctx android.LoadHookContext) []string {
82 generatedPartitions := []string{"system"}
83 if ctx.DeviceConfig().SystemExtPath() == "system_ext" {
84 generatedPartitions = append(generatedPartitions, "system_ext")
85 }
86 if ctx.DeviceConfig().BuildingVendorImage() && ctx.DeviceConfig().VendorPath() == "vendor" {
87 generatedPartitions = append(generatedPartitions, "vendor")
88 }
89 if ctx.DeviceConfig().BuildingProductImage() && ctx.DeviceConfig().ProductPath() == "product" {
90 generatedPartitions = append(generatedPartitions, "product")
91 }
92 if ctx.DeviceConfig().BuildingOdmImage() && ctx.DeviceConfig().OdmPath() == "odm" {
93 generatedPartitions = append(generatedPartitions, "odm")
94 }
95 if ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BuildingSystemDlkmImage {
96 generatedPartitions = append(generatedPartitions, "system_dlkm")
97 }
98 return generatedPartitions
99}
100
101func createFsGenState(ctx android.LoadHookContext, generatedPrebuiltEtcModuleNames []string) *FsGenState {
102 return ctx.Config().Once(fsGenStateOnceKey, func() interface{} {
103 partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
104 candidates := android.FirstUniqueStrings(android.Concat(partitionVars.ProductPackages, partitionVars.ProductPackagesDebug))
105 candidates = android.Concat(candidates, generatedPrebuiltEtcModuleNames)
106
107 return &FsGenState{
108 depCandidates: candidates,
109 fsDeps: map[string]*multilibDeps{
110 // These additional deps are added according to the cuttlefish system image bp.
111 "system": {
112 "com.android.apex.cts.shim.v1_prebuilt": defaultDepCandidateProps(ctx.Config()),
113 "dex_bootjars": defaultDepCandidateProps(ctx.Config()),
114 "framework_compatibility_matrix.device.xml": defaultDepCandidateProps(ctx.Config()),
115 "init.environ.rc-soong": defaultDepCandidateProps(ctx.Config()),
116 "libclang_rt.asan": defaultDepCandidateProps(ctx.Config()),
117 "libcompiler_rt": defaultDepCandidateProps(ctx.Config()),
118 "libdmabufheap": defaultDepCandidateProps(ctx.Config()),
119 "libgsi": defaultDepCandidateProps(ctx.Config()),
120 "llndk.libraries.txt": defaultDepCandidateProps(ctx.Config()),
121 "logpersist.start": defaultDepCandidateProps(ctx.Config()),
122 "update_engine_sideload": defaultDepCandidateProps(ctx.Config()),
123 },
124 "vendor": {
125 "fs_config_files_vendor": defaultDepCandidateProps(ctx.Config()),
126 "fs_config_dirs_vendor": defaultDepCandidateProps(ctx.Config()),
127 generatedModuleName(ctx.Config(), "vendor-build.prop"): defaultDepCandidateProps(ctx.Config()),
128 },
129 "odm": {
130 // fs_config_* files are automatically installed for all products with odm partitions.
131 // https://cs.android.com/android/_/android/platform/build/+/e4849e87ab660b59a6501b3928693db065ee873b:tools/fs_config/Android.mk;l=34;drc=8d6481b92c4b4e9b9f31a61545b6862090fcc14b;bpv=1;bpt=0
132 "fs_config_files_odm": defaultDepCandidateProps(ctx.Config()),
133 "fs_config_dirs_odm": defaultDepCandidateProps(ctx.Config()),
134 },
135 "product": {},
136 "system_ext": {
137 // VNDK apexes are automatically included.
138 // This hardcoded list will need to be updated if `PRODUCT_EXTRA_VNDK_VERSIONS` is updated.
139 // https://cs.android.com/android/_/android/platform/build/+/adba533072b00c53ac0f198c550a3cbd7a00e4cd:core/main.mk;l=984;bpv=1;bpt=0;drc=174db7b179592cf07cbfd2adb0119486fda911e7
140 "com.android.vndk.v30": defaultDepCandidateProps(ctx.Config()),
141 "com.android.vndk.v31": defaultDepCandidateProps(ctx.Config()),
142 "com.android.vndk.v32": defaultDepCandidateProps(ctx.Config()),
143 "com.android.vndk.v33": defaultDepCandidateProps(ctx.Config()),
144 "com.android.vndk.v34": defaultDepCandidateProps(ctx.Config()),
145 },
146 "system_dlkm": {},
147 },
148 soongGeneratedPartitions: generatedPartitions(ctx),
149 fsDepsMutex: sync.Mutex{},
150 moduleToInstallationProps: map[string]installationProperties{},
151 }
152 }).(*FsGenState)
153}
154
155func checkDepModuleInMultipleNamespaces(mctx android.BottomUpMutatorContext, foundDeps multilibDeps, module string, partitionName string) {
156 otherNamespace := mctx.Namespace().Path
157 if val, found := foundDeps[module]; found && otherNamespace != "." && !android.InList(val.Namespace, []string{".", otherNamespace}) {
158 mctx.ModuleErrorf("found in multiple namespaces(%s and %s) when including in %s partition", val.Namespace, otherNamespace, partitionName)
159 }
160}
161
162func appendDepIfAppropriate(mctx android.BottomUpMutatorContext, deps *multilibDeps, installPartition string) {
163 checkDepModuleInMultipleNamespaces(mctx, *deps, mctx.Module().Name(), installPartition)
164 if _, ok := (*deps)[mctx.Module().Name()]; ok {
165 // Prefer the namespace-specific module over the platform module
166 if mctx.Namespace().Path != "." {
167 (*deps)[mctx.Module().Name()].Namespace = mctx.Namespace().Path
168 }
169 (*deps)[mctx.Module().Name()].Arch = append((*deps)[mctx.Module().Name()].Arch, mctx.Module().Target().Arch.ArchType)
170 } else {
171 multilib, _ := mctx.Module().DecodeMultilib(mctx)
172 (*deps)[mctx.Module().Name()] = &depCandidateProps{
173 Namespace: mctx.Namespace().Path,
174 Multilib: multilib,
175 Arch: []android.ArchType{mctx.Module().Target().Arch.ArchType},
176 }
177 }
178}
179
180func collectDepsMutator(mctx android.BottomUpMutatorContext) {
181 fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
182
183 m := mctx.Module()
184 if m.Target().Os.Class == android.Device && slices.Contains(fsGenState.depCandidates, m.Name()) {
185 installPartition := m.PartitionTag(mctx.DeviceConfig())
186 fsGenState.fsDepsMutex.Lock()
187 // Only add the module as dependency when:
188 // - its enabled
189 // - its namespace is included in PRODUCT_SOONG_NAMESPACES
190 if m.Enabled(mctx) && m.ExportedToMake() {
191 appendDepIfAppropriate(mctx, fsGenState.fsDeps[installPartition], installPartition)
192 }
193 fsGenState.fsDepsMutex.Unlock()
194 }
195 // store the map of module to (required,overrides) even if the module is not in PRODUCT_PACKAGES.
196 // the module might be installed transitively.
197 if m.Target().Os.Class == android.Device && m.Enabled(mctx) && m.ExportedToMake() {
198 fsGenState.fsDepsMutex.Lock()
199 fsGenState.moduleToInstallationProps[m.Name()] = installationProperties{
200 Required: m.RequiredModuleNames(mctx),
201 Overrides: m.Overrides(),
202 }
203 fsGenState.fsDepsMutex.Unlock()
204 }
205}
206
207type depsStruct struct {
208 Deps []string
209}
210
211type multilibDepsStruct struct {
212 Common depsStruct
213 Lib32 depsStruct
214 Lib64 depsStruct
215 Both depsStruct
216 Prefer32 depsStruct
217}
218
219type packagingPropsStruct struct {
220 High_priority_deps []string
221 Deps []string
222 Multilib multilibDepsStruct
223}
224
225func fullyQualifiedModuleName(moduleName, namespace string) string {
226 if namespace == "." {
227 return moduleName
228 }
229 return fmt.Sprintf("//%s:%s", namespace, moduleName)
230}
231
232func getBitness(archTypes []android.ArchType) (ret []string) {
233 for _, archType := range archTypes {
234 if archType.Multilib == "" {
235 ret = append(ret, android.COMMON_VARIANT)
236 } else {
237 ret = append(ret, archType.Bitness())
238 }
239 }
240 return ret
241}
242
243func setDepsMutator(mctx android.BottomUpMutatorContext) {
244 removeOverriddenDeps(mctx)
245 fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
246 fsDeps := fsGenState.fsDeps
247 soongGeneratedPartitionMap := getAllSoongGeneratedPartitionNames(mctx.Config(), fsGenState.soongGeneratedPartitions)
248 m := mctx.Module()
249 if partition, ok := soongGeneratedPartitionMap[m.Name()]; ok {
250 depsStruct := generateDepStruct(*fsDeps[partition])
251 if err := proptools.AppendMatchingProperties(m.GetProperties(), depsStruct, nil); err != nil {
252 mctx.ModuleErrorf(err.Error())
253 }
254 }
255}
256
257// removeOverriddenDeps collects PRODUCT_PACKAGES and (transitive) required deps.
258// it then removes any modules which appear in `overrides` of the above list.
259func removeOverriddenDeps(mctx android.BottomUpMutatorContext) {
260 mctx.Config().Once(fsGenRemoveOverridesOnceKey, func() interface{} {
261 fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
262 fsDeps := fsGenState.fsDeps
263 overridden := map[string]bool{}
264 allDeps := []string{}
265
266 // Step 1: Initialization: Append PRODUCT_PACKAGES to the queue
267 for _, fsDep := range fsDeps {
268 for depName, _ := range *fsDep {
269 allDeps = append(allDeps, depName)
270 }
271 }
272
273 // Step 2: Process the queue, and add required modules to the queue.
274 i := 0
275 for {
276 if i == len(allDeps) {
277 break
278 }
279 depName := allDeps[i]
280 for _, overrides := range fsGenState.moduleToInstallationProps[depName].Overrides {
281 overridden[overrides] = true
282 }
283 // add required dep to the queue.
284 allDeps = append(allDeps, fsGenState.moduleToInstallationProps[depName].Required...)
285 i += 1
286 }
287
288 // Step 3: Delete all the overridden modules.
289 for overridden, _ := range overridden {
290 for partition, _ := range fsDeps {
291 delete(*fsDeps[partition], overridden)
292 }
293 }
294 return nil
295 })
296}
297
298var HighPriorityDeps = []string{}
299
300func generateDepStruct(deps map[string]*depCandidateProps) *packagingPropsStruct {
301 depsStruct := packagingPropsStruct{}
302 for depName, depProps := range deps {
303 bitness := getBitness(depProps.Arch)
304 fullyQualifiedDepName := fullyQualifiedModuleName(depName, depProps.Namespace)
305 if android.InList(depName, HighPriorityDeps) {
306 depsStruct.High_priority_deps = append(depsStruct.High_priority_deps, fullyQualifiedDepName)
307 } else if android.InList("32", bitness) && android.InList("64", bitness) {
308 // If both 32 and 64 bit variants are enabled for this module
309 switch depProps.Multilib {
310 case string(android.MultilibBoth):
311 depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName)
312 case string(android.MultilibCommon), string(android.MultilibFirst):
313 depsStruct.Deps = append(depsStruct.Deps, fullyQualifiedDepName)
314 case "32":
315 depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName)
316 case "64", "darwin_universal":
317 depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName)
318 case "prefer32", "first_prefer32":
319 depsStruct.Multilib.Prefer32.Deps = append(depsStruct.Multilib.Prefer32.Deps, fullyQualifiedDepName)
320 default:
321 depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName)
322 }
323 } else if android.InList("64", bitness) {
324 // If only 64 bit variant is enabled
325 depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName)
326 } else if android.InList("32", bitness) {
327 // If only 32 bit variant is enabled
328 depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName)
329 } else {
330 // If only common variant is enabled
331 depsStruct.Multilib.Common.Deps = append(depsStruct.Multilib.Common.Deps, fullyQualifiedDepName)
332 }
333 }
334 depsStruct.Deps = android.SortedUniqueStrings(depsStruct.Deps)
335 depsStruct.Multilib.Lib32.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Lib32.Deps)
336 depsStruct.Multilib.Lib64.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Lib64.Deps)
337 depsStruct.Multilib.Prefer32.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Prefer32.Deps)
338 depsStruct.Multilib.Both.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Both.Deps)
339 depsStruct.Multilib.Common.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Common.Deps)
340
341 return &depsStruct
342}