1// 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 "fmt" 19 "slices" 20 "strings" 21 "sync" 22 23 "android/soong/android" 24 25 "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 // Information about the main soong-generated partitions 64 soongGeneratedPartitions allGeneratedPartitionData 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 // List of prebuilt_* modules that are autogenerated. 70 generatedPrebuiltEtcModuleNames []string 71 // Mapping from a path to an avb key to the name of a filegroup module that contains it 72 avbKeyFilegroups map[string]string 73} 74 75type installationProperties struct { 76 Required []string 77 Overrides []string 78} 79 80func defaultDepCandidateProps(config android.Config) *depCandidateProps { 81 return &depCandidateProps{ 82 Namespace: ".", 83 Arch: []android.ArchType{config.BuildArch}, 84 } 85} 86 87func createFsGenState(ctx android.LoadHookContext, generatedPrebuiltEtcModuleNames []string, avbpubkeyGenerated bool) *FsGenState { 88 return ctx.Config().Once(fsGenStateOnceKey, func() interface{} { 89 partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse 90 candidates := android.FirstUniqueStrings(android.Concat(partitionVars.ProductPackages, partitionVars.ProductPackagesDebug)) 91 candidates = android.Concat(candidates, generatedPrebuiltEtcModuleNames) 92 93 fsGenState := FsGenState{ 94 depCandidates: candidates, 95 fsDeps: map[string]*multilibDeps{ 96 // These additional deps are added according to the cuttlefish system image bp. 97 "system": { 98 // keep-sorted start 99 "com.android.apex.cts.shim.v1_prebuilt": defaultDepCandidateProps(ctx.Config()), 100 "dex_bootjars": defaultDepCandidateProps(ctx.Config()), 101 "framework_compatibility_matrix.device.xml": defaultDepCandidateProps(ctx.Config()), 102 "init.environ.rc-soong": defaultDepCandidateProps(ctx.Config()), 103 "libcompiler_rt": defaultDepCandidateProps(ctx.Config()), 104 "libdmabufheap": defaultDepCandidateProps(ctx.Config()), 105 "libgsi": defaultDepCandidateProps(ctx.Config()), 106 "llndk.libraries.txt": defaultDepCandidateProps(ctx.Config()), 107 "logpersist.start": defaultDepCandidateProps(ctx.Config()), 108 "notice_xml_system": defaultDepCandidateProps(ctx.Config()), 109 "update_engine_sideload": defaultDepCandidateProps(ctx.Config()), 110 // keep-sorted end 111 }, 112 "vendor": { 113 "fs_config_files_vendor": defaultDepCandidateProps(ctx.Config()), 114 "fs_config_dirs_vendor": defaultDepCandidateProps(ctx.Config()), 115 "notice_xml_vendor": defaultDepCandidateProps(ctx.Config()), 116 generatedModuleName(ctx.Config(), "vendor-build.prop"): defaultDepCandidateProps(ctx.Config()), 117 }, 118 "odm": { 119 // fs_config_* files are automatically installed for all products with odm partitions. 120 // https://cs.android.com/android/_/android/platform/build/+/e4849e87ab660b59a6501b3928693db065ee873b:tools/fs_config/Android.mk;l=34;drc=8d6481b92c4b4e9b9f31a61545b6862090fcc14b;bpv=1;bpt=0 121 "fs_config_files_odm": defaultDepCandidateProps(ctx.Config()), 122 "fs_config_dirs_odm": defaultDepCandidateProps(ctx.Config()), 123 "notice_xml_odm": defaultDepCandidateProps(ctx.Config()), 124 }, 125 "product": { 126 "notice_xml_product": defaultDepCandidateProps(ctx.Config()), 127 }, 128 "system_ext": { 129 // VNDK apexes are automatically included. 130 // This hardcoded list will need to be updated if `PRODUCT_EXTRA_VNDK_VERSIONS` is updated. 131 // https://cs.android.com/android/_/android/platform/build/+/adba533072b00c53ac0f198c550a3cbd7a00e4cd:core/main.mk;l=984;bpv=1;bpt=0;drc=174db7b179592cf07cbfd2adb0119486fda911e7 132 "com.android.vndk.v30": defaultDepCandidateProps(ctx.Config()), 133 "com.android.vndk.v31": defaultDepCandidateProps(ctx.Config()), 134 "com.android.vndk.v32": defaultDepCandidateProps(ctx.Config()), 135 "com.android.vndk.v33": defaultDepCandidateProps(ctx.Config()), 136 "com.android.vndk.v34": defaultDepCandidateProps(ctx.Config()), 137 "notice_xml_system_ext": defaultDepCandidateProps(ctx.Config()), 138 }, 139 "userdata": {}, 140 "system_dlkm": { 141 // these are phony required deps of the phony fs_config_dirs_nonsystem 142 "fs_config_dirs_system_dlkm": defaultDepCandidateProps(ctx.Config()), 143 "fs_config_files_system_dlkm": defaultDepCandidateProps(ctx.Config()), 144 "notice_xml_system_dlkm": defaultDepCandidateProps(ctx.Config()), 145 // build props are automatically added to `ALL_DEFAULT_INSTALLED_MODULES` 146 "system_dlkm-build.prop": defaultDepCandidateProps(ctx.Config()), 147 }, 148 "vendor_dlkm": { 149 "fs_config_dirs_vendor_dlkm": defaultDepCandidateProps(ctx.Config()), 150 "fs_config_files_vendor_dlkm": defaultDepCandidateProps(ctx.Config()), 151 "notice_xml_vendor_dlkm": defaultDepCandidateProps(ctx.Config()), 152 "vendor_dlkm-build.prop": defaultDepCandidateProps(ctx.Config()), 153 }, 154 "odm_dlkm": { 155 "fs_config_dirs_odm_dlkm": defaultDepCandidateProps(ctx.Config()), 156 "fs_config_files_odm_dlkm": defaultDepCandidateProps(ctx.Config()), 157 "notice_xml_odm_dlkm": defaultDepCandidateProps(ctx.Config()), 158 "odm_dlkm-build.prop": defaultDepCandidateProps(ctx.Config()), 159 }, 160 "ramdisk": {}, 161 "vendor_ramdisk": {}, 162 "recovery": { 163 "sepolicy.recovery": defaultDepCandidateProps(ctx.Config()), 164 "plat_file_contexts.recovery": defaultDepCandidateProps(ctx.Config()), 165 "plat_service_contexts.recovery": defaultDepCandidateProps(ctx.Config()), 166 "plat_property_contexts.recovery": defaultDepCandidateProps(ctx.Config()), 167 "system_ext_file_contexts.recovery": defaultDepCandidateProps(ctx.Config()), 168 "system_ext_service_contexts.recovery": defaultDepCandidateProps(ctx.Config()), 169 "system_ext_property_contexts.recovery": defaultDepCandidateProps(ctx.Config()), 170 "vendor_file_contexts.recovery": defaultDepCandidateProps(ctx.Config()), 171 "vendor_service_contexts.recovery": defaultDepCandidateProps(ctx.Config()), 172 "vendor_property_contexts.recovery": defaultDepCandidateProps(ctx.Config()), 173 "odm_file_contexts.recovery": defaultDepCandidateProps(ctx.Config()), 174 "odm_property_contexts.recovery": defaultDepCandidateProps(ctx.Config()), 175 "product_file_contexts.recovery": defaultDepCandidateProps(ctx.Config()), 176 "product_service_contexts.recovery": defaultDepCandidateProps(ctx.Config()), 177 "product_property_contexts.recovery": defaultDepCandidateProps(ctx.Config()), 178 }, 179 }, 180 fsDepsMutex: sync.Mutex{}, 181 moduleToInstallationProps: map[string]installationProperties{}, 182 generatedPrebuiltEtcModuleNames: generatedPrebuiltEtcModuleNames, 183 avbKeyFilegroups: map[string]string{}, 184 } 185 186 if avbpubkeyGenerated { 187 (*fsGenState.fsDeps["product"])["system_other_avbpubkey"] = defaultDepCandidateProps(ctx.Config()) 188 } 189 190 if len(ctx.Config().DeviceManifestFiles()) > 0 { 191 (*fsGenState.fsDeps["vendor"])["vendor_manifest.xml"] = defaultDepCandidateProps(ctx.Config()) 192 } 193 194 // Add common resources `prebuilt_res` module as dep of recovery partition 195 (*fsGenState.fsDeps["recovery"])[fmt.Sprintf("recovery-resources-common-%s", getDpi(ctx))] = defaultDepCandidateProps(ctx.Config()) 196 (*fsGenState.fsDeps["recovery"])[getRecoveryFontModuleName(ctx)] = defaultDepCandidateProps(ctx.Config()) 197 (*fsGenState.fsDeps["recovery"])[createRecoveryBuildProp(ctx)] = defaultDepCandidateProps(ctx.Config()) 198 199 return &fsGenState 200 }).(*FsGenState) 201} 202 203func checkDepModuleInMultipleNamespaces(mctx android.BottomUpMutatorContext, foundDeps multilibDeps, module string, partitionName string) { 204 otherNamespace := mctx.Namespace().Path 205 if val, found := foundDeps[module]; found && otherNamespace != "." && !android.InList(val.Namespace, []string{".", otherNamespace}) { 206 mctx.ModuleErrorf("found in multiple namespaces(%s and %s) when including in %s partition", val.Namespace, otherNamespace, partitionName) 207 } 208} 209 210func appendDepIfAppropriate(mctx android.BottomUpMutatorContext, deps *multilibDeps, installPartition string) { 211 moduleName := mctx.ModuleName() 212 checkDepModuleInMultipleNamespaces(mctx, *deps, moduleName, installPartition) 213 if _, ok := (*deps)[moduleName]; ok { 214 // Prefer the namespace-specific module over the platform module 215 if mctx.Namespace().Path != "." { 216 (*deps)[moduleName].Namespace = mctx.Namespace().Path 217 } 218 (*deps)[moduleName].Arch = append((*deps)[moduleName].Arch, mctx.Module().Target().Arch.ArchType) 219 } else { 220 multilib, _ := mctx.Module().DecodeMultilib(mctx) 221 (*deps)[moduleName] = &depCandidateProps{ 222 Namespace: mctx.Namespace().Path, 223 Multilib: multilib, 224 Arch: []android.ArchType{mctx.Module().Target().Arch.ArchType}, 225 } 226 } 227} 228 229func collectDepsMutator(mctx android.BottomUpMutatorContext) { 230 m := mctx.Module() 231 if m.Target().Os.Class != android.Device { 232 return 233 } 234 fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState) 235 236 fsGenState.fsDepsMutex.Lock() 237 defer fsGenState.fsDepsMutex.Unlock() 238 239 if slices.Contains(fsGenState.depCandidates, mctx.ModuleName()) { 240 installPartition := m.PartitionTag(mctx.DeviceConfig()) 241 // Only add the module as dependency when: 242 // - its enabled 243 // - its namespace is included in PRODUCT_SOONG_NAMESPACES 244 if m.Enabled(mctx) && m.ExportedToMake() { 245 appendDepIfAppropriate(mctx, fsGenState.fsDeps[installPartition], installPartition) 246 } 247 } 248 // store the map of module to (required,overrides) even if the module is not in PRODUCT_PACKAGES. 249 // the module might be installed transitively. 250 if m.Enabled(mctx) && m.ExportedToMake() { 251 fsGenState.moduleToInstallationProps[m.Name()] = installationProperties{ 252 Required: m.RequiredModuleNames(mctx), 253 Overrides: m.Overrides(), 254 } 255 } 256} 257 258type depsStruct struct { 259 Deps []string 260} 261 262type multilibDepsStruct struct { 263 Common depsStruct 264 Lib32 depsStruct 265 Lib64 depsStruct 266 Both depsStruct 267 Prefer32 depsStruct 268} 269 270type packagingPropsStruct struct { 271 High_priority_deps []string 272 Deps []string 273 Multilib multilibDepsStruct 274} 275 276func fullyQualifiedModuleName(moduleName, namespace string) string { 277 if namespace == "." { 278 return moduleName 279 } 280 return fmt.Sprintf("//%s:%s", namespace, moduleName) 281} 282 283func getBitness(archTypes []android.ArchType) (ret []string) { 284 for _, archType := range archTypes { 285 if archType.Multilib == "" { 286 ret = append(ret, android.COMMON_VARIANT) 287 } else { 288 ret = append(ret, archType.Bitness()) 289 } 290 } 291 return ret 292} 293 294func setDepsMutator(mctx android.BottomUpMutatorContext) { 295 removeOverriddenDeps(mctx) 296 fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState) 297 fsDeps := fsGenState.fsDeps 298 m := mctx.Module() 299 if partition := fsGenState.soongGeneratedPartitions.typeForName(m.Name()); partition != "" { 300 if fsGenState.soongGeneratedPartitions.isHandwritten(m.Name()) { 301 // Handwritten image, don't modify it 302 return 303 } 304 depsStruct := generateDepStruct(*fsDeps[partition], fsGenState.generatedPrebuiltEtcModuleNames) 305 if err := proptools.AppendMatchingProperties(m.GetProperties(), depsStruct, nil); err != nil { 306 mctx.ModuleErrorf(err.Error()) 307 } 308 } 309} 310 311// removeOverriddenDeps collects PRODUCT_PACKAGES and (transitive) required deps. 312// it then removes any modules which appear in `overrides` of the above list. 313func removeOverriddenDeps(mctx android.BottomUpMutatorContext) { 314 mctx.Config().Once(fsGenRemoveOverridesOnceKey, func() interface{} { 315 fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState) 316 fsDeps := fsGenState.fsDeps 317 overridden := map[string]bool{} 318 allDeps := []string{} 319 320 // Step 1: Initialization: Append PRODUCT_PACKAGES to the queue 321 for _, fsDep := range fsDeps { 322 for depName, _ := range *fsDep { 323 allDeps = append(allDeps, depName) 324 } 325 } 326 327 // Step 2: Process the queue, and add required modules to the queue. 328 i := 0 329 for { 330 if i == len(allDeps) { 331 break 332 } 333 depName := allDeps[i] 334 for _, overrides := range fsGenState.moduleToInstallationProps[depName].Overrides { 335 overridden[overrides] = true 336 } 337 // add required dep to the queue. 338 allDeps = append(allDeps, fsGenState.moduleToInstallationProps[depName].Required...) 339 i += 1 340 } 341 342 // Step 3: Delete all the overridden modules. 343 for overridden, _ := range overridden { 344 for partition, _ := range fsDeps { 345 delete(*fsDeps[partition], overridden) 346 } 347 } 348 return nil 349 }) 350} 351 352var HighPriorityDeps = []string{} 353 354func isHighPriorityDep(depName string) bool { 355 for _, highPriorityDeps := range HighPriorityDeps { 356 if strings.HasPrefix(depName, highPriorityDeps) { 357 return true 358 } 359 } 360 return false 361} 362 363func generateDepStruct(deps map[string]*depCandidateProps, highPriorityDeps []string) *packagingPropsStruct { 364 depsStruct := packagingPropsStruct{} 365 for depName, depProps := range deps { 366 bitness := getBitness(depProps.Arch) 367 fullyQualifiedDepName := fullyQualifiedModuleName(depName, depProps.Namespace) 368 if android.InList(depName, highPriorityDeps) { 369 depsStruct.High_priority_deps = append(depsStruct.High_priority_deps, fullyQualifiedDepName) 370 } else if android.InList("32", bitness) && android.InList("64", bitness) { 371 // If both 32 and 64 bit variants are enabled for this module 372 switch depProps.Multilib { 373 case string(android.MultilibBoth): 374 depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName) 375 case string(android.MultilibCommon), string(android.MultilibFirst): 376 depsStruct.Deps = append(depsStruct.Deps, fullyQualifiedDepName) 377 case "32": 378 depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName) 379 case "64", "darwin_universal": 380 depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName) 381 case "prefer32", "first_prefer32": 382 depsStruct.Multilib.Prefer32.Deps = append(depsStruct.Multilib.Prefer32.Deps, fullyQualifiedDepName) 383 default: 384 depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName) 385 } 386 } else if android.InList("64", bitness) { 387 // If only 64 bit variant is enabled 388 depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName) 389 } else if android.InList("32", bitness) { 390 // If only 32 bit variant is enabled 391 depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName) 392 } else { 393 // If only common variant is enabled 394 depsStruct.Multilib.Common.Deps = append(depsStruct.Multilib.Common.Deps, fullyQualifiedDepName) 395 } 396 } 397 depsStruct.Deps = android.SortedUniqueStrings(depsStruct.Deps) 398 depsStruct.Multilib.Lib32.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Lib32.Deps) 399 depsStruct.Multilib.Lib64.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Lib64.Deps) 400 depsStruct.Multilib.Prefer32.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Prefer32.Deps) 401 depsStruct.Multilib.Both.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Both.Deps) 402 depsStruct.Multilib.Common.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Common.Deps) 403 depsStruct.High_priority_deps = android.SortedUniqueStrings(depsStruct.High_priority_deps) 404 405 return &depsStruct 406} 407