blob: e9fd51351883c1cff5073fff7f0e49cd7e1e421d [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 (
Jihoon Kangadd2bb22024-11-05 22:29:34 +000018 "fmt"
19 "slices"
Jihoon Kang3a8759c2024-11-08 19:35:09 +000020 "strings"
Jihoon Kangadd2bb22024-11-05 22:29:34 +000021 "sync"
22
mrziwange5b1bb32024-11-05 15:51:40 -080023 "android/soong/android"
24
Jihoon Kangadd2bb22024-11-05 22:29:34 +000025 "github.com/google/blueprint/proptools"
26)
27
28func RegisterCollectFileSystemDepsMutators(ctx android.RegisterMutatorsContext) {
29 ctx.BottomUp("fs_collect_deps", collectDepsMutator).MutatesGlobalState()
30 ctx.BottomUp("fs_set_deps", setDepsMutator)
31}
32
33var fsGenStateOnceKey = android.NewOnceKey("FsGenState")
34var fsGenRemoveOverridesOnceKey = android.NewOnceKey("FsGenRemoveOverrides")
35
36// Map of partition module name to its partition that may be generated by Soong.
37// Note that it is not guaranteed that all modules returned by this function are successfully
38// created.
39func getAllSoongGeneratedPartitionNames(config android.Config, partitions []string) map[string]string {
40 ret := map[string]string{}
41 for _, partition := range partitions {
42 ret[generatedModuleNameForPartition(config, partition)] = partition
43 }
44 return ret
45}
46
47type depCandidateProps struct {
48 Namespace string
49 Multilib string
50 Arch []android.ArchType
51}
52
53// Map of module name to depCandidateProps
54type multilibDeps map[string]*depCandidateProps
55
56// Information necessary to generate the filesystem modules, including details about their
57// dependencies
58type FsGenState struct {
59 // List of modules in `PRODUCT_PACKAGES` and `PRODUCT_PACKAGES_DEBUG`
60 depCandidates []string
61 // Map of names of partition to the information of modules to be added as deps
62 fsDeps map[string]*multilibDeps
63 // List of name of partitions to be generated by the filesystem_creator module
64 soongGeneratedPartitions []string
65 // Mutex to protect the fsDeps
66 fsDepsMutex sync.Mutex
67 // Map of _all_ soong module names to their corresponding installation properties
68 moduleToInstallationProps map[string]installationProperties
69}
70
71type installationProperties struct {
72 Required []string
73 Overrides []string
74}
75
76func defaultDepCandidateProps(config android.Config) *depCandidateProps {
77 return &depCandidateProps{
78 Namespace: ".",
79 Arch: []android.ArchType{config.BuildArch},
80 }
81}
82
83func generatedPartitions(ctx android.LoadHookContext) []string {
Cole Faust76a6e952024-11-07 16:56:45 -080084 generatedPartitions := []string{"system", "ramdisk"}
Jihoon Kangadd2bb22024-11-05 22:29:34 +000085 if ctx.DeviceConfig().SystemExtPath() == "system_ext" {
86 generatedPartitions = append(generatedPartitions, "system_ext")
87 }
88 if ctx.DeviceConfig().BuildingVendorImage() && ctx.DeviceConfig().VendorPath() == "vendor" {
89 generatedPartitions = append(generatedPartitions, "vendor")
90 }
91 if ctx.DeviceConfig().BuildingProductImage() && ctx.DeviceConfig().ProductPath() == "product" {
92 generatedPartitions = append(generatedPartitions, "product")
93 }
94 if ctx.DeviceConfig().BuildingOdmImage() && ctx.DeviceConfig().OdmPath() == "odm" {
95 generatedPartitions = append(generatedPartitions, "odm")
96 }
mrziwang23ba8762024-11-07 16:21:53 -080097 if ctx.DeviceConfig().BuildingUserdataImage() && ctx.DeviceConfig().UserdataPath() == "data" {
98 generatedPartitions = append(generatedPartitions, "userdata")
99 }
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000100 if ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BuildingSystemDlkmImage {
101 generatedPartitions = append(generatedPartitions, "system_dlkm")
102 }
Spandan Das5b493cd2024-11-07 20:55:56 +0000103 if ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BuildingVendorDlkmImage {
104 generatedPartitions = append(generatedPartitions, "vendor_dlkm")
105 }
106 if ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BuildingOdmDlkmImage {
107 generatedPartitions = append(generatedPartitions, "odm_dlkm")
108 }
109
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000110 return generatedPartitions
111}
112
113func createFsGenState(ctx android.LoadHookContext, generatedPrebuiltEtcModuleNames []string) *FsGenState {
114 return ctx.Config().Once(fsGenStateOnceKey, func() interface{} {
115 partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
116 candidates := android.FirstUniqueStrings(android.Concat(partitionVars.ProductPackages, partitionVars.ProductPackagesDebug))
117 candidates = android.Concat(candidates, generatedPrebuiltEtcModuleNames)
118
119 return &FsGenState{
120 depCandidates: candidates,
121 fsDeps: map[string]*multilibDeps{
122 // These additional deps are added according to the cuttlefish system image bp.
123 "system": {
124 "com.android.apex.cts.shim.v1_prebuilt": defaultDepCandidateProps(ctx.Config()),
125 "dex_bootjars": defaultDepCandidateProps(ctx.Config()),
126 "framework_compatibility_matrix.device.xml": defaultDepCandidateProps(ctx.Config()),
127 "init.environ.rc-soong": defaultDepCandidateProps(ctx.Config()),
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000128 "libcompiler_rt": defaultDepCandidateProps(ctx.Config()),
129 "libdmabufheap": defaultDepCandidateProps(ctx.Config()),
130 "libgsi": defaultDepCandidateProps(ctx.Config()),
131 "llndk.libraries.txt": defaultDepCandidateProps(ctx.Config()),
132 "logpersist.start": defaultDepCandidateProps(ctx.Config()),
133 "update_engine_sideload": defaultDepCandidateProps(ctx.Config()),
134 },
135 "vendor": {
136 "fs_config_files_vendor": defaultDepCandidateProps(ctx.Config()),
137 "fs_config_dirs_vendor": defaultDepCandidateProps(ctx.Config()),
138 generatedModuleName(ctx.Config(), "vendor-build.prop"): defaultDepCandidateProps(ctx.Config()),
139 },
140 "odm": {
141 // fs_config_* files are automatically installed for all products with odm partitions.
142 // https://cs.android.com/android/_/android/platform/build/+/e4849e87ab660b59a6501b3928693db065ee873b:tools/fs_config/Android.mk;l=34;drc=8d6481b92c4b4e9b9f31a61545b6862090fcc14b;bpv=1;bpt=0
143 "fs_config_files_odm": defaultDepCandidateProps(ctx.Config()),
144 "fs_config_dirs_odm": defaultDepCandidateProps(ctx.Config()),
145 },
146 "product": {},
147 "system_ext": {
148 // VNDK apexes are automatically included.
149 // This hardcoded list will need to be updated if `PRODUCT_EXTRA_VNDK_VERSIONS` is updated.
150 // https://cs.android.com/android/_/android/platform/build/+/adba533072b00c53ac0f198c550a3cbd7a00e4cd:core/main.mk;l=984;bpv=1;bpt=0;drc=174db7b179592cf07cbfd2adb0119486fda911e7
151 "com.android.vndk.v30": defaultDepCandidateProps(ctx.Config()),
152 "com.android.vndk.v31": defaultDepCandidateProps(ctx.Config()),
153 "com.android.vndk.v32": defaultDepCandidateProps(ctx.Config()),
154 "com.android.vndk.v33": defaultDepCandidateProps(ctx.Config()),
155 "com.android.vndk.v34": defaultDepCandidateProps(ctx.Config()),
156 },
Spandan Das912d26b2024-11-06 19:35:17 +0000157 "userdata": {},
158 "system_dlkm": {
159 // these are phony required deps of the phony fs_config_dirs_nonsystem
160 "fs_config_dirs_system_dlkm": defaultDepCandidateProps(ctx.Config()),
161 "fs_config_files_system_dlkm": defaultDepCandidateProps(ctx.Config()),
162 // build props are automatically added to `ALL_DEFAULT_INSTALLED_MODULES`
163 "system_dlkm-build.prop": defaultDepCandidateProps(ctx.Config()),
164 },
Spandan Das5b493cd2024-11-07 20:55:56 +0000165 "vendor_dlkm": {
166 "fs_config_dirs_vendor_dlkm": defaultDepCandidateProps(ctx.Config()),
167 "fs_config_files_vendor_dlkm": defaultDepCandidateProps(ctx.Config()),
168 "vendor_dlkm-build.prop": defaultDepCandidateProps(ctx.Config()),
169 },
170 "odm_dlkm": {
171 "fs_config_dirs_odm_dlkm": defaultDepCandidateProps(ctx.Config()),
172 "fs_config_files_odm_dlkm": defaultDepCandidateProps(ctx.Config()),
173 "odm_dlkm-build.prop": defaultDepCandidateProps(ctx.Config()),
174 },
Cole Faust76a6e952024-11-07 16:56:45 -0800175 "ramdisk": {},
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000176 },
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000177 fsDepsMutex: sync.Mutex{},
178 moduleToInstallationProps: map[string]installationProperties{},
179 }
180 }).(*FsGenState)
181}
182
183func checkDepModuleInMultipleNamespaces(mctx android.BottomUpMutatorContext, foundDeps multilibDeps, module string, partitionName string) {
184 otherNamespace := mctx.Namespace().Path
185 if val, found := foundDeps[module]; found && otherNamespace != "." && !android.InList(val.Namespace, []string{".", otherNamespace}) {
186 mctx.ModuleErrorf("found in multiple namespaces(%s and %s) when including in %s partition", val.Namespace, otherNamespace, partitionName)
187 }
188}
189
190func appendDepIfAppropriate(mctx android.BottomUpMutatorContext, deps *multilibDeps, installPartition string) {
Jihoon Kang81aeb9e2024-11-05 00:22:35 +0000191 moduleName := mctx.ModuleName()
192 checkDepModuleInMultipleNamespaces(mctx, *deps, moduleName, installPartition)
193 if _, ok := (*deps)[moduleName]; ok {
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000194 // Prefer the namespace-specific module over the platform module
195 if mctx.Namespace().Path != "." {
Jihoon Kang81aeb9e2024-11-05 00:22:35 +0000196 (*deps)[moduleName].Namespace = mctx.Namespace().Path
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000197 }
Jihoon Kang81aeb9e2024-11-05 00:22:35 +0000198 (*deps)[moduleName].Arch = append((*deps)[moduleName].Arch, mctx.Module().Target().Arch.ArchType)
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000199 } else {
200 multilib, _ := mctx.Module().DecodeMultilib(mctx)
Jihoon Kang81aeb9e2024-11-05 00:22:35 +0000201 (*deps)[moduleName] = &depCandidateProps{
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000202 Namespace: mctx.Namespace().Path,
203 Multilib: multilib,
204 Arch: []android.ArchType{mctx.Module().Target().Arch.ArchType},
205 }
206 }
207}
208
209func collectDepsMutator(mctx android.BottomUpMutatorContext) {
Cole Faust76a6e952024-11-07 16:56:45 -0800210 m := mctx.Module()
211 if m.Target().Os.Class != android.Device {
212 return
213 }
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000214 fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
215
Cole Faust76a6e952024-11-07 16:56:45 -0800216 fsGenState.fsDepsMutex.Lock()
217 defer fsGenState.fsDepsMutex.Unlock()
218
219 if slices.Contains(fsGenState.depCandidates, mctx.ModuleName()) {
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000220 installPartition := m.PartitionTag(mctx.DeviceConfig())
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000221 // Only add the module as dependency when:
222 // - its enabled
223 // - its namespace is included in PRODUCT_SOONG_NAMESPACES
224 if m.Enabled(mctx) && m.ExportedToMake() {
225 appendDepIfAppropriate(mctx, fsGenState.fsDeps[installPartition], installPartition)
226 }
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000227 }
228 // store the map of module to (required,overrides) even if the module is not in PRODUCT_PACKAGES.
229 // the module might be installed transitively.
Cole Faust76a6e952024-11-07 16:56:45 -0800230 if m.Enabled(mctx) && m.ExportedToMake() {
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000231 fsGenState.moduleToInstallationProps[m.Name()] = installationProperties{
232 Required: m.RequiredModuleNames(mctx),
233 Overrides: m.Overrides(),
234 }
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000235 }
236}
237
238type depsStruct struct {
239 Deps []string
240}
241
242type multilibDepsStruct struct {
243 Common depsStruct
244 Lib32 depsStruct
245 Lib64 depsStruct
246 Both depsStruct
247 Prefer32 depsStruct
248}
249
250type packagingPropsStruct struct {
251 High_priority_deps []string
252 Deps []string
253 Multilib multilibDepsStruct
254}
255
256func fullyQualifiedModuleName(moduleName, namespace string) string {
257 if namespace == "." {
258 return moduleName
259 }
260 return fmt.Sprintf("//%s:%s", namespace, moduleName)
261}
262
263func getBitness(archTypes []android.ArchType) (ret []string) {
264 for _, archType := range archTypes {
265 if archType.Multilib == "" {
266 ret = append(ret, android.COMMON_VARIANT)
267 } else {
268 ret = append(ret, archType.Bitness())
269 }
270 }
271 return ret
272}
273
274func setDepsMutator(mctx android.BottomUpMutatorContext) {
275 removeOverriddenDeps(mctx)
276 fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
277 fsDeps := fsGenState.fsDeps
278 soongGeneratedPartitionMap := getAllSoongGeneratedPartitionNames(mctx.Config(), fsGenState.soongGeneratedPartitions)
279 m := mctx.Module()
280 if partition, ok := soongGeneratedPartitionMap[m.Name()]; ok {
281 depsStruct := generateDepStruct(*fsDeps[partition])
282 if err := proptools.AppendMatchingProperties(m.GetProperties(), depsStruct, nil); err != nil {
283 mctx.ModuleErrorf(err.Error())
284 }
285 }
286}
287
288// removeOverriddenDeps collects PRODUCT_PACKAGES and (transitive) required deps.
289// it then removes any modules which appear in `overrides` of the above list.
290func removeOverriddenDeps(mctx android.BottomUpMutatorContext) {
291 mctx.Config().Once(fsGenRemoveOverridesOnceKey, func() interface{} {
292 fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
293 fsDeps := fsGenState.fsDeps
294 overridden := map[string]bool{}
295 allDeps := []string{}
296
297 // Step 1: Initialization: Append PRODUCT_PACKAGES to the queue
298 for _, fsDep := range fsDeps {
299 for depName, _ := range *fsDep {
300 allDeps = append(allDeps, depName)
301 }
302 }
303
304 // Step 2: Process the queue, and add required modules to the queue.
305 i := 0
306 for {
307 if i == len(allDeps) {
308 break
309 }
310 depName := allDeps[i]
311 for _, overrides := range fsGenState.moduleToInstallationProps[depName].Overrides {
312 overridden[overrides] = true
313 }
314 // add required dep to the queue.
315 allDeps = append(allDeps, fsGenState.moduleToInstallationProps[depName].Required...)
316 i += 1
317 }
318
319 // Step 3: Delete all the overridden modules.
320 for overridden, _ := range overridden {
321 for partition, _ := range fsDeps {
322 delete(*fsDeps[partition], overridden)
323 }
324 }
325 return nil
326 })
327}
328
329var HighPriorityDeps = []string{}
330
Jihoon Kang3a8759c2024-11-08 19:35:09 +0000331func isHighPriorityDep(depName string) bool {
332 for _, highPriorityDeps := range HighPriorityDeps {
333 if strings.HasPrefix(depName, highPriorityDeps) {
334 return true
335 }
336 }
337 return false
338}
339
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000340func generateDepStruct(deps map[string]*depCandidateProps) *packagingPropsStruct {
341 depsStruct := packagingPropsStruct{}
342 for depName, depProps := range deps {
343 bitness := getBitness(depProps.Arch)
344 fullyQualifiedDepName := fullyQualifiedModuleName(depName, depProps.Namespace)
Jihoon Kang3a8759c2024-11-08 19:35:09 +0000345 if isHighPriorityDep(depName) {
Jihoon Kangadd2bb22024-11-05 22:29:34 +0000346 depsStruct.High_priority_deps = append(depsStruct.High_priority_deps, fullyQualifiedDepName)
347 } else if android.InList("32", bitness) && android.InList("64", bitness) {
348 // If both 32 and 64 bit variants are enabled for this module
349 switch depProps.Multilib {
350 case string(android.MultilibBoth):
351 depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName)
352 case string(android.MultilibCommon), string(android.MultilibFirst):
353 depsStruct.Deps = append(depsStruct.Deps, fullyQualifiedDepName)
354 case "32":
355 depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName)
356 case "64", "darwin_universal":
357 depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName)
358 case "prefer32", "first_prefer32":
359 depsStruct.Multilib.Prefer32.Deps = append(depsStruct.Multilib.Prefer32.Deps, fullyQualifiedDepName)
360 default:
361 depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName)
362 }
363 } else if android.InList("64", bitness) {
364 // If only 64 bit variant is enabled
365 depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName)
366 } else if android.InList("32", bitness) {
367 // If only 32 bit variant is enabled
368 depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName)
369 } else {
370 // If only common variant is enabled
371 depsStruct.Multilib.Common.Deps = append(depsStruct.Multilib.Common.Deps, fullyQualifiedDepName)
372 }
373 }
374 depsStruct.Deps = android.SortedUniqueStrings(depsStruct.Deps)
375 depsStruct.Multilib.Lib32.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Lib32.Deps)
376 depsStruct.Multilib.Lib64.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Lib64.Deps)
377 depsStruct.Multilib.Prefer32.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Prefer32.Deps)
378 depsStruct.Multilib.Both.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Both.Deps)
379 depsStruct.Multilib.Common.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Common.Deps)
380
381 return &depsStruct
382}