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