Quelle fsgen_mutators.go
Sprache: unbekannt
|
|
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]
// Copyright (C) 2024 The Android Open Source Project
//
// Licensed under the Apache License, Version 2. 0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2. 0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package fsgen
import (
"container/list"
"fmt"
"slices"
"strings"
"sync"
"android/soong/android"
"android/soong/cc"
"android/soong/rust"
"github.com/google/blueprint/proptools"
)
func RegisterCollectFileSystemDepsMutators(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("fs_recovery_fstab", setRecoveryFstabSrcs).MutatesGlobalState()
ctx.BottomUp("fs_collect_deps", collectDepsMutator).MutatesGlobalState()
ctx.BottomUp("fs_remove_deps", removeDepsMutator).MutatesGlobalState()
ctx.BottomUp("fs_cross_partition_required_deps", crossPartitionRequiredMutator).M utatesGlobalState()
ctx.BottomUp("fs_set_deps", setDepsMutator)
}
var fsGenStateOnceKey = android.NewOnceKey("FsGenState")
var fsGenRemoveOverridesOnceKey = android.NewOnceKey("FsGenRemoveOverrides")
var fsGenCrossPartitionRequiredDepsOnceKey = android.NewOnceKey("FsGenCrossPartitionRequiredDeps")
// Map of partition module name to its partition that may be generated by Soong.
// Note that it is not guaranteed that all modules returned by this function are successfully
// created.
func getAllSoongGeneratedPartitionNames(config android.Config, partitions []string) map[string]string {
ret := map[string]string{}
for _, partition := range partitions {
ret[generatedModuleNameForPartition(config, partition)] = partition
}
return ret
}
type depCandidateProps struct {
Namespace string
Multilib string
Arch []android.ArchType
NativeBridgeSupport map[android.NativeBridgeSupport]bool
}
// Map of module name to depCandidateProps
type multilibDeps map[string]*depCandidateProps
func (m *multilibDeps) SortedFullyQualifiedNames() []string {
ret := make([]string, len(*m))
i := 0
for moduleName, props := range *m {
ret[i] = fullyQualifiedModuleName(moduleName, props.Namespace)
i += 1
}
return android.SortedUniqueStrings(ret)
}
type moduleToInstallationProps struct {
// Map of _all_ soong module fully qualified names to their corresponding installation properties
// Should not be accessed directly to add entries; Use AddToMap instead.
moduleToPropsMap map[string]installationProperties
// TODO (b/420968370): Remove this after we enforce that all namespaces are valid.
baseModuleNameToPropsMap map[string][]installationProperties
}
func (m *moduleToInstallationProps) AddToMap(ctx android.BottomUpMutatorContext, prop *installationProperties) {
m.moduleToPropsMap[fullyQualifiedModuleName(ctx.ModuleName(), ctx.Namespace().Path)] = *prop
m.baseModuleNameToPropsMap[ctx.ModuleName()] = append(m.baseModuleNameToPropsMap[ctx.ModuleName()], *prop)
}
func (m *moduleToInstallationProps) Get(ctx android.BottomUpMutatorContext) (installationProperties, bool) {
return m.GetFromFullyQualifiedModuleName(fullyQualifiedModuleName(ctx.ModuleName(), ctx.Namespace().Path))
}
func (m *moduleToInstallationProps) GetFromFullyQualifiedModuleName(fullyQualifiedModuleName string) (installationProperties, bool) {
prop, ok := m.moduleToPropsMap[fullyQualifiedModuleName]
if ok {
return prop, ok
}
return installationProperties{}, ok
}
func (m *moduleToInstallationProps) GetFromModuleName(name string) (string, installationProperties, bool) {
if len(name) == 0 {
return "", installationProperties{}, false
}
// If the name has a fully qualified module name format, get it from the fully qualified module name
if strings.HasPrefix("//", name) {
prop, ok := m.GetFromFullyQualifiedModuleName(name)
return name, prop, ok
}
// Input name is not in fully qualified name format, but the module may be in a namespace
if props, ok := m.baseModuleNameToPropsMap[name]; ok {
for _, prop := range props {
fullyQualifiedName := fullyQualifiedModuleName(name, prop.Namespace)
if discoveredProp, ok := m.GetFromFullyQualifiedModuleName(fullyQualifiedName); ok {
return fullyQualifiedName, discoveredProp, ok
}
}
}
return "", installationProperties{}, false
}
func (m *moduleToInstallationProps) ModuleNameToFullyQualifiedModuleName(name string) string {
if fullyQualifiedName, _, ok := m.GetFromModuleName(name); ok {
return fullyQualifiedName
}
return name
}
func (m *moduleToInstallationProps) SortedKeys() []string {
return android.SortedKeys(m.moduleToPropsMap)
}
// Information necessary to generate the filesystem modules, including details about their
// dependencies
type FsGenState struct {
// List of modules in `PRODUCT_PACKAGES` and `PRODUCT_PACKAGES_DEBUG`
depCandidatesMap map[string]bool
// Map of names of partition to the information of modules to be added as deps
fsDeps map[string]*multilibDeps
// Information about the main soong-generated partitions
soongGeneratedPartitions allGeneratedPartitionData
// Mutex to protect the fsDeps
fsDepsMutex sync.Mutex
moduleToInstallationProps moduleToInstallationProps
// List of prebuilt_* modules that are autogenerated.
generatedPrebuiltEtcModuleNames []string
// Mapping from a path to an avb key to the name of a filegroup module that contains it
avbKeyFilegroups map[string]string
// Name of all native bridge modules
nativeBridgeModules map[string]bool
// Name of the generated recovery fstab module name
recoveryFstabModuleName string
// Mapping of the partition type to the list of overridden modules that will be listed as
// `Overridden_modules` in the generated filesystem modules
overriddenModuleNames map[string][]string
}
type installationProperties struct {
Required []string // Modules that should be installed alongside
RequiredBy []string // List of modules (or PRODUCT_PACKAGES) that require this module to be installed
Overrides []string
CcAndRustSharedLibs []string
Partition string
Namespace string
ArchType android.ArchType
}
func defaultDepCandidateProps(config android.Config) *depCandidateProps {
return &depCandidateProps{
Namespace: ".",
Arch: []android.ArchType{config.DevicePrimaryArchType()},
NativeBridgeSupport: map[android.NativeBridgeSupport]bool{android.NativeBridgeDisabled: true},
}
}
type DeviceConfigContext interface {
Config() android.Config
DeviceConfig() android.DeviceConfig
}
func productInstalledModules(ctx DeviceConfigContext, makefile string) []string {
productPkg := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.ProductPackagesSet[makefile]
allInstalledModules := productPkg.ProductPackages
if ctx.Config().Debuggable() {
allInstalledModules = append(allInstalledModules, productPkg.ProductPackagesDebug...)
if ctx.Config().Eng() {
allInstalledModules = append(allInstalledModules, productPkg.ProductPackagesEng...)
}
if android.InList("address", ctx.Config().SanitizeDevice()) {
allInstalledModules = append(allInstalledModules, productPkg.ProductPackagesDebugAsan...)
}
if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") {
allInstalledModules = append(allInstalledModules, productPkg.ProductPackagesDebugJavaCoverage...)
}
}
if android.InList("arm64", []string{ctx.DeviceConfig().DeviceArch(), ctx.DeviceConfig().DeviceSecondaryArch()}) {
allInstalledModules = append(allInstalledModules, productPkg.ProductPackagesArm64...)
}
if android.UncheckedFinalApiLevel(29).GreaterThanOrEqualTo(ctx.DeviceConfig().ShippingApiLevel()) {
allInstalledModules = append(allInstalledModules, productPkg.ProductPackagesShippingApiLevel29...)
}
if android.UncheckedFinalApiLevel(33).GreaterThanOrEqualTo(ctx.DeviceConfig().ShippingApiLevel()) {
allInstalledModules = append(allInstalledModules, productPkg.ProductPackagesShippingApiLevel33...)
}
if android.UncheckedFinalApiLevel(34).GreaterThanOrEqualTo(ctx.DeviceConfig().ShippingApiLevel()) {
allInstalledModules = append(allInstalledModules, productPkg.ProductPackagesShippingApiLevel34...)
}
return allInstalledModules
}
func createFsGenState(ctx android.LoadHookContext, generatedPrebuiltEtcModuleNames []string, avbpubkeyGenerated bool) *FsGenState {
return ctx.Config().Once(fsGenStateOnceKey, func() interface{} {
allInstalledModules := slices.Concat(
productInstalledModules(ctx, "all"),
generatedPrebuiltEtcModuleNames,
)
candidatesMap := map[string]bool{}
for _, candidate := range allInstalledModules {
candidatesMap[candidate] = true
}
fsGenState := FsGenState{
depCandidatesMap: candidatesMap,
fsDeps: map[string]*multilibDeps{
// These additional deps are added according to the cuttlefish system image bp.
"system": {
// keep-sorted start
"com.android.apex.cts.shim.v1_prebuilt": defaultDepCandidateProps(ctx.Config()),
"dex_bootjars": defaultDepCandidateProps(ctx.Config()),
"framework_compatibility_matrix.device.xml": defaultDepCandidateProps(ctx.Config()),
"init.environ.rc-soong": defaultDepCandidateProps(ctx.Config()),
"libdmabufheap": defaultDepCandidateProps(ctx.Config()),
"libgsi": defaultDepCandidateProps(ctx.Config()),
"llndk.libraries.txt": defaultDepCandidateProps(ctx.Config()),
"logpersist.start": defaultDepCandidateProps(ctx.Config()),
"notice_xml_system": defaultDepCandidateProps(ctx.Config()),
"update_engine_sideload": defaultDepCandidateProps(ctx.Config()),
// keep-sorted end
},
"vendor": {
"fs_config_files_vendor": defaultDepCandidateProps(ctx.Config()),
"fs_config_dirs_vendor": defaultDepCandidateProps(ctx.Config()),
"notice_xml_vendor": defaultDepCandidateProps(ctx.Config()),
generatedModuleName(ctx.Config(), "vendor-build.prop"): defaultDepCandidateProps(ctx.Config()),
},
"odm": {
// fs_config_* files are automatically installed for all products with odm partitions.
// https://cs.android.com/android/_/android/platform/build/+/e4849e87ab660b59a6501b3928693db065ee873b:tools/fs_config/Android.mk;l=34;drc=8d6481b92c4b4e9b9f31a61545b6862090fcc14b;bpv=1;bpt=0
"fs_config_files_odm": defaultDepCandidateProps(ctx.Config()),
"fs_config_dirs_odm": defaultDepCandidateProps(ctx.Config()),
"notice_xml_odm": defaultDepCandidateProps(ctx.Config()),
},
"product": {
"notice_xml_product": defaultDepCandidateProps(ctx.Config()),
},
"system_ext": {
"notice_xml_system_ext": defaultDepCandidateProps(ctx.Config()),
},
"userdata": {},
"system_dlkm": {
// these are phony required deps of the phony fs_config_dirs_nonsystem
"fs_config_dirs_system_dlkm": defaultDepCandidateProps(ctx.Config()),
"fs_config_files_system_dlkm": defaultDepCandidateProps(ctx.Config()),
"notice_xml_system_dlkm": defaultDepCandidateProps(ctx.Config()),
},
"vendor_dlkm": {
"fs_config_dirs_vendor_dlkm": defaultDepCandidateProps(ctx.Config()),
"fs_config_files_vendor_dlkm": defaultDepCandidateProps(ctx.Config()),
"notice_xml_vendor_dlkm": defaultDepCandidateProps(ctx.Config()),
"vendor_dlkm-build.prop": defaultDepCandidateProps(ctx.Config()),
},
"odm_dlkm": {
"fs_config_dirs_odm_dlkm": defaultDepCandidateProps(ctx.Config()),
"fs_config_files_odm_dlkm": defaultDepCandidateProps(ctx.Config()),
"notice_xml_odm_dlkm": defaultDepCandidateProps(ctx.Config()),
},
"ramdisk": {},
"vendor_ramdisk": {},
"vendor_ramdisk-debug": {},
"vendor_ramdisk_fragment_dlkm": {},
"vendor_ramdisk-test-harness": {},
"vendor_kernel_ramdisk": {},
"recovery": {
"sepolicy.recovery": defaultDepCandidateProps(ctx.Config()),
"plat_file_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
"plat_service_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
"plat_property_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
"system_ext_file_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
"system_ext_service_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
"system_ext_property_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
"vendor_file_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
"vendor_service_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
"vendor_property_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
"odm_file_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
"odm_property_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
"product_file_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
"product_service_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
"product_property_contexts.recovery": defaultDepCandidateProps(ctx.Config()),
},
"debug_ramdisk": {
"force_debuggable": defaultDepCandidateProps(ctx.Config()),
}, // TODO: move this to PRODUCT_PACKAGES
"test_harness_ramdisk": {
"adb_debug.test_harness.prop": defaultDepCandidateProps(ctx.Config()),
}, // TODO: move this to PRODUCT_PACKAGES
},
fsDepsMutex: sync.Mutex{},
moduleToInstallationProps: moduleToInstallationProps{
moduleToPropsMap: map[string]installationProperties{},
baseModuleNameToPropsMap: map[string][]installationProperties{},
},
generatedPrebuiltEtcModuleNames: generatedPrebuiltEtcModuleNames,
avbKeyFilegroups: map[string]string{},
nativeBridgeModules: map[string]bool{},
overriddenModuleNames: map[string][]string{},
}
if avbpubkeyGenerated {
(*fsGenState.fsDeps["product"])["system_other_avbpubkey"] = defaultDepCandidateProps(ctx.Config())
}
if len(ctx.Config().DeviceManifestFiles()) > 0 {
(*fsGenState.fsDeps["vendor"])["vendor_manifest.xml"] = defaultDepCandidateProps(ctx.Config())
}
// Add common resources `prebuilt_res` module as dep of recovery partition
(*fsGenState.fsDeps["recovery"])[fmt.Sprintf("recovery-resources-common-%s", getDpi(ctx))] = defaultDepCandidateProps(ctx.Config())
(*fsGenState.fsDeps["recovery"])[getRecoveryFontModuleName(ctx)] = defaultDepCandidateProps(ctx.Config())
(*fsGenState.fsDeps["recovery"])[createRecoveryBuildProp(ctx)] = defaultDepCandidateProps(ctx.Config())
if name, _ := getRecoveryBackgroundPicturesGeneratorModuleName(ctx); name != "" {
(*fsGenState.fsDeps["recovery"])[name] = defaultDepCandidateProps(ctx.Config())
}
if name := createTargetRecoveryWipeModuleName(ctx); name != "" {
(*fsGenState.fsDeps["recovery"])[name] = defaultDepCandidateProps(ctx.Config())
}
if name := handleRecoveryFstab(ctx); name != "" {
(*fsGenState.fsDeps["recovery"])[name] = defaultDepCandidateProps(ctx.Config())
fsGenState.recoveryFstabModuleName = name
}
// VNDK APEXes are deprecated and are not supported and disabled for riscv64 arch.
// Adding these modules as deps of the auto generated riscv64 arch filesystem modules
// leads to execution time build error, thus do not add them as deps when building
// riscv64 arch product.
if ctx.Config().DevicePrimaryArchType() != android.Riscv64 {
for _, vndkVersion := range ctx.DeviceConfig().ExtraVndkVersions() {
(*fsGenState.fsDeps["system_ext"])["com.android.vndk.v"+vndkVersion] = defaultDepCandidateProps(ctx.Config())
}
}
if ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BuildingSystemDlkmImage {
(*fsGenState.fsDeps["system_dlkm"])["system_dlkm-build.prop"] = defaultDepCandidateProps(ctx.Config())
} else {
// system_dlkm build.prop is installed in system partition if system_dlkm.img is not available
(*fsGenState.fsDeps["system"])["system_dlkm-build.prop"] = defaultDepCandidateProps(ctx.Config())
}
if ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BuildingOdmDlkmImage {
(*fsGenState.fsDeps["odm_dlkm"])["odm_dlkm-build.prop"] = defaultDepCandidateProps(ctx.Config())
} else {
// odm_dlkm build.prop is installed in vendor partition if odm_dlkm.img is not available
(*fsGenState.fsDeps["vendor"])["odm_dlkm-build.prop"] = defaultDepCandidateProps(ctx.Config())
}
dtbo, dtbo16k := createPrebuiltDtboImages(ctx)
if bootOtas := createBootOtas16kModules(ctx, dtbo, dtbo16k); bootOtas != "" &&
ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.Board16kOtaMoveVendor {
(*fsGenState.fsDeps["vendor"])[bootOtas] = defaultDepCandidateProps(ctx.Config())
}
return &fsGenState
}).(*FsGenState)
}
func checkDepModuleInMultipleNamespaces(mctx android.BottomUpMutatorContext, foundDeps multilibDeps, module string, partitionName string) {
otherNamespace := mctx.Namespace().Path
if val, found := foundDeps[module]; found && otherNamespace != "." && !android.InList(val.Namespace, []string{".", otherNamespace}) {
mctx.ModuleErrorf("found in multiple namespaces(%s and %s) when including in %s partition", val.Namespace, otherNamespace, partitionName)
}
}
func appendDepIfAppropriate(mctx android.BottomUpMutatorContext, deps *multilibDeps, installPartition string, nbs android.NativeBridgeSupport, moduleName string) {
checkDepModuleInMultipleNamespaces(mctx, *deps, moduleName, installPartition)
arch := mctx.Module().Target().Arch.ArchType
if android.InList(installPartition, []string{
"recovery",
"ramdisk",
"vendor_ramdisk",
"debug_ramdisk",
}) {
// Only the primary arch is supported for these partitions.
// https://cs.android.com/android/_/android/platform/build/soong/+/d046c2afef086a35d24222b09f4d2c4914e8a2a5:android/arch.go;l=618-621;drc=92ac46d1fe04a94d94025554bcecc5f8cb2416ae;bpv=1;bpt=0
arch = mctx.Config().DevicePrimaryArchType()
}
if _, ok := (*deps)[moduleName]; ok {
// Prefer the namespace-specific module over the platform module
if mctx.Namespace().Path != "." {
(*deps)[moduleName].Namespace = mctx.Namespace().Path
}
(*deps)[moduleName].Arch = append((*deps)[moduleName].Arch, arch)
(*deps)[moduleName].NativeBridgeSupport[nbs] = true
} else {
multilib, _ := mctx.Module().DecodeMultilib(mctx)
(*deps)[moduleName] = &depCandidateProps{
Namespace: mctx.Namespace().Path,
Arch: []android.ArchType{arch},
Multilib: multilib,
NativeBridgeSupport: map[android.NativeBridgeSupport]bool{nbs: true},
}
}
}
func isEligibleForFsDeps(mctx android.BottomUpMutatorContext) bool {
m := mctx.Module()
// Only add the module as dependency when:
// - it is enabled
// - its namespace is included in PRODUCT_SOONG_NAMESPACES
// - it is not hidden from make
// - it is a preferred variant in a source/prebuilt pair
return m.Enabled(mctx) && m.ExportedToMake() && !m.IsHideFromMake() && android.IsModulePreferred(m)
}
func collectDepsMutator(mctx android.BottomUpMutatorContext) {
if !shouldEnableFilesystemCreator(mctx) {
return
}
m := mctx.Module()
if m.Target().Os.Class != android.Device {
return
}
fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
fsGenState.fsDepsMutex.Lock()
defer fsGenState.fsDepsMutex.Unlock()
moduleName := mctx.ModuleName()
if p, ok := m.(android.PrebuiltInterface); ok && p.Prebuilt() != nil {
if mm, ok := m.(interface{ BaseModuleName() string }); ok {
moduleName = mm.BaseModuleName()
}
}
image, imageOk := mctx.Module().(android.ImageInterface)
if _, ok := fsGenState.depCandidatesMap[moduleName]; ok {
installPartition := m.PartitionTag(mctx.DeviceConfig())
systemPartitionFalsePositive := installPartition == "system" && android.InList(m.ImageVariation().Variation, []string{
// cc/image.go marks some ramdisk and recovery modules as platform.
// https://cs.android.com/android/platform/superproject/main/+/main:build/soong/cc/image.go;l=514-522?q=MakeAsPlatform%20f:build%2Fsoong&ss=android%2Fplatform%2Fsuperproject%2Fmain
// Skip them in fsgen.
android.RamdiskVariation,
android.VendorRamdiskVariation,
android.RecoveryVariation,
})
if isEligibleForFsDeps(mctx) && !systemPartitionFalsePositive {
appendDepIfAppropriate(mctx, fsGenState.fsDeps[installPartition], installPartition, android.NativeBridgeDisabled, mctx.ModuleName())
}
}
if _, ok := fsGenState.depCandidatesMap[mctx.ModuleName()+".native_bridge"]; ok {
installPartition := m.PartitionTag(mctx.DeviceConfig())
// Native bridge is only supported for system partition modules.
// https://cs.android.com/android/_/android/platform/build/soong/+/d046c2afef086a35d24222b09f4d2c4914e8a2a5:android/arch.go;l=604;drc=92ac46d1fe04a94d94025554bcecc5f8cb2416ae;bpv=1;bpt=0
if isEligibleForFsDeps(mctx) && installPartition == "system" {
appendDepIfAppropriate(mctx, fsGenState.fsDeps[installPartition], installPartition, android.NativeBridgeEnabled, mctx.ModuleName())
}
} else if _, ok := fsGenState.depCandidatesMap[mctx.ModuleName()+".bootstrap.native_bridge"]; ok {
installPartition := m.PartitionTag(mctx.DeviceConfig())
// Native bridge is only supported for system partition modules.
// https://cs.android.com/android/_/android/platform/build/soong/+/d046c2afef086a35d24222b09f4d2c4914e8a2a5:android/arch.go;l=604;drc=92ac46d1fe04a94d94025554bcecc5f8cb2416ae;bpv=1;bpt=0
if isEligibleForFsDeps(mctx) && installPartition == "system" {
appendDepIfAppropriate(mctx, fsGenState.fsDeps[installPartition], installPartition, android.NativeBridgeEnabled, mctx.ModuleName())
}
}
if _, ok := fsGenState.depCandidatesMap[mctx.ModuleName()+".vendor_ramdisk"]; ok && imageOk && image.VendorRamdiskVariantNeeded(mctx) {
installPartition := "vendor_ramdisk"
if isEligibleForFsDeps(mctx) {
appendDepIfAppropriate(mctx, fsGenState.fsDeps[installPartition], installPartition, android.NativeBridgeDisabled, mctx.ModuleName())
}
}
if _, ok := fsGenState.depCandidatesMap[mctx.ModuleName()+".recovery"]; ok && imageOk && image.RecoveryVariantNeeded(mctx) {
installPartition := "recovery"
if isEligibleForFsDeps(mctx) {
appendDepIfAppropriate(mctx, fsGenState.fsDeps[installPartition], installPartition, android.NativeBridgeDisabled, mctx.ModuleName())
}
}
// store the map of module to (required,overrides) even if the module is not in PRODUCT_PACKAGES.
// the module might be installed transitively.
if isEligibleForFsDeps(mctx) {
var ccAndRustSharedLibs []string
if rustModule, ok := m.(*rust.Module); ok {
if !rustModule.StdLinkageIsRlibLinkage(mctx.Device()) {
for _, prop := range m.GetProperties() {
if rustCompilerProps, ok := prop.(*rust.BaseCompilerProperties); ok {
ccAndRustSharedLibs = rustCompilerProps.Rustlibs.GetOrDefault(mctx, nil)
}
}
}
}
if _, ok := m.(*cc.Module); ok {
for _, prop := range m.GetProperties() {
if linkerProps, ok := prop.(*cc.BaseLinkerProperties); ok {
deps := cc.CoalesceLibs(mctx, linkerProps, cc.Deps{})
ccAndRustSharedLibs = append(ccAndRustSharedLibs, deps.SharedLibs...)
}
}
}
fsGenState.moduleToInstallationProps.AddToMap(mctx, &installationProperties{
Required: m.RequiredModuleNames(mctx),
CcAndRustSharedLibs: ccAndRustSharedLibs,
Overrides: m.Overrides(),
Partition: m.PartitionTag(mctx.DeviceConfig()),
Namespace: mctx.Namespace().Path,
ArchType: mctx.Target().Arch.ArchType,
})
}
if mctx.Target().NativeBridge == android.NativeBridgeEnabled {
fsGenState.nativeBridgeModules[fullyQualifiedModuleName(mctx.ModuleName(), mctx.Namespace().Path)] = true
}
}
type depsStruct struct {
Deps []string
}
type multilibDepsStruct struct {
Common depsStruct
Lib32 depsStruct
Lib64 depsStruct
Both depsStruct
Prefer32 depsStruct
Native_bridge depsStruct
}
type packagingPropsStruct struct {
Overridden_deps []string
High_priority_deps []string
Deps []string
Multilib multilibDepsStruct
}
func fullyQualifiedModuleName(moduleName, namespace string) string {
if namespace == "." || strings.HasPrefix(moduleName, "//") {
return moduleName
}
return fmt.Sprintf("//%s:%s", namespace, moduleName)
}
func getBitness(archTypes []android.ArchType) (ret []string) {
for _, archType := range archTypes {
if archType.Multilib == "" {
ret = append(ret, android.COMMON_VARIANT)
} else {
ret = append(ret, archType.Bitness())
}
}
return ret
}
func removeDepsMutator(mctx android.BottomUpMutatorContext) {
if !shouldEnableFilesystemCreator(mctx) {
return
}
fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
fsGenState.fsDepsMutex.Lock()
defer fsGenState.fsDepsMutex.Unlock()
updatePartitionsOfOverrideModules(mctx)
}
func crossPartitionRequiredMutator(mctx android.BottomUpMutatorContext) {
if !shouldEnableFilesystemCreator(mctx) {
return
}
fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
fsGenState.fsDepsMutex.Lock()
defer fsGenState.fsDepsMutex.Unlock()
additionalCrossPartitionRequiredDeps := correctCrossPartitionRequiredDeps(mctx.Config())
fullyQualifiedModuleName := fullyQualifiedModuleName(mctx.ModuleName(), mctx.Namespace().Path)
if xPartitionDep, ok := additionalCrossPartitionRequiredDeps[fullyQualifiedModuleName]; ok && mctx.Module().PartitionTag(mctx.DeviceConfig()) == xPartitionDep.partition {
// For shared libraries, add the dependency only if the archType of the dep and parent match.
addXPartitionDep := !xPartitionDep.isSharedLibDep || android.InList(mctx.Target().Arch.ArchType, xPartitionDep.archesOfRequiredSharedLibDep)
if addXPartitionDep {
appendDepIfAppropriate(mctx, fsGenState.fsDeps[xPartitionDep.partition], xPartitionDep.partition, android.NativeBridgeDisabled, mctx.ModuleName())
}
}
}
func setDepsMutator(mctx android.BottomUpMutatorContext) {
if !shouldEnableFilesystemCreator(mctx) {
return
}
removeOverriddenDeps(mctx)
fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
fsDeps := fsGenState.fsDeps
m := mctx.Module()
if partition := fsGenState.soongGeneratedPartitions.typeForName(m.Name()); partition != "" {
if fsGenState.soongGeneratedPartitions.isHandwritten(m.Name()) {
// Handwritten image, don't modify it
return
}
var overriddenDeps []string
if deps, ok := fsGenState.overriddenModuleNames[partition]; ok {
overriddenDeps = deps
}
if partition == "tzsw" {
// tzsw is a prebuilt file, and does not use android_filesystem module type.
return
}
backgroundRecoveryImageGenerator, _ := getRecoveryBackgroundPicturesGeneratorModuleName(mctx)
// backgroundRecoveryImageGenerator generates additional images which takes precedence over images files
// created by other deps of recovery.img.
// Use this in highPriorityDeps
depsStruct := generateDepStruct(*fsDeps[partition], append([]string{backgroundRecoveryImageGenerator}, fsGenState.generatedPrebuiltEtcModuleNames...), overriddenDeps)
if err := proptools.AppendMatchingProperties(m.GetProperties(), depsStruct, nil); err != nil {
mctx.ModuleErrorf(err.Error())
}
}
}
// Adds override apps (override_android_app, override_apex, ...) to the partition of their `base` apps.
func updatePartitionsOfOverrideModules(mctx android.BottomUpMutatorContext) {
if override, ok := mctx.Module().(android.OverrideModule); ok {
fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
fsDeps := fsGenState.fsDeps
overridePartition := mctx.Module().PartitionTag(mctx.DeviceConfig())
if _, ok := (*fsDeps[overridePartition])[mctx.Module().Name()]; !ok {
// The override module is not in PRODUCT_PACKAGES
return
}
base := override.GetOverriddenModuleName()
if strings.HasPrefix(base, "//") { // Has path prefix, which is either the path to the module or the namespace
base = strings.Split(base, ":")[1]
// TODO (b/420968370): Re-enable this after we enforce that all namespaces are valid.
//pathOrNamspace := strings.TrimPrefix(strings.Split(base, ":")[0], "//")
// If the path prefix is not within the exported namespace, it is likely that the
// prefix is the path to the module, not the namespace. In that case, drop the
// prefix as the non-namespace path prefix is not part of the fully qualified module
// name.
//if !android.InList(pathOrNamspace, mctx.Config().ProductVariables().NamespacesToExport) {
// base = strings.Split(base, ":")[1]
//}
}
// TODO (b/420968370): Use fully qualifed name after we enforce that all namespaces are valid.
if baseModuleProps, ok := fsGenState.moduleToInstallationProps.baseModuleNameToPropsMap[base]; ok && isEligibleForFsDeps(mctx) {
basePartitionCandidates := []string{}
for _, ip := range baseModuleProps {
basePartitionCandidates = append(basePartitionCandidates, ip.Partition)
}
basePartitionCandidates = android.SortedUniqueStrings(basePartitionCandidates)
if len(basePartitionCandidates) > 1 {
mctx.ModuleErrorf("Could not determine partition of base module %s. Possible partitions %s\n", base, basePartitionCandidates)
}
partition := basePartitionCandidates[0]
appendDepIfAppropriate(mctx, fsDeps[partition], partition, android.NativeBridgeDisabled, mctx.Module().Name())
}
}
}
type queue struct {
internalQueue *list.List
}
func (q *queue) Pop() string {
ret := q.internalQueue.Front()
if ret == nil {
return ""
}
q.internalQueue.Remove(ret)
return ret.Value.(string)
}
func (q *queue) Add(inputs ...string) {
for _, input := range inputs {
q.internalQueue.PushBack(input)
}
}
func (q *queue) Len() int {
return q.internalQueue.Len()
}
// removeOverriddenDeps collects PRODUCT_PACKAGES and (transitive) required deps.
// it then removes any modules which appear in `overrides` of the above list.
// Returns the list of names of the overridden modules. These are passed as `Overridden_modules`
// when generating the filesystem modules.
func removeOverriddenDeps(mctx android.BottomUpMutatorContext) {
mctx.Config().Once(fsGenRemoveOverridesOnceKey, func() interface{} {
fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState)
fsDeps := fsGenState.fsDeps
overridden := map[string]bool{}
allDeps := []string{}
// Step 1: Initialization: Append PRODUCT_PACKAGES to the queue
for _, fsDep := range fsDeps {
for depName, moduleInfo := range *fsDep {
fullyQualifiedDepName := depName
// If depName is not fully qualified and the dep specifies namespace, append the
// namespace for correct lookup in Step 2.
if !strings.HasPrefix(depName, "//") && !android.InList(moduleInfo.Namespace, []string{"", "."}) {
fullyQualifiedDepName = fmt.Sprintf("//%s:%s", moduleInfo.Namespace, fullyQualifiedDepName)
}
allDeps = append(allDeps, fullyQualifiedDepName)
}
}
// Record all modules' required rdeps (i.e. modules that set the module as a required
// dependency) and whether if the module is installed as a top level module.
moduleToRequiredRdepsMap := map[string][]string{}
for _, productPackagesEntry := range productInstalledModules(mctx, "all") {
if moduleName, _, ok := fsGenState.moduleToInstallationProps.GetFromModuleName(productPackagesEntry); ok {
moduleToRequiredRdepsMap[moduleName] = append(moduleToRequiredRdepsMap[moduleName], "PRODUCT_PACKAGES")
}
}
// Step 2: Process the queue, and add required modules to the queue.
i := 0
for {
if i == len(allDeps) {
break
}
depName := allDeps[i]
props, _ := fsGenState.moduleToInstallationProps.GetFromFullyQualifiedModuleName(depName)
for _, overrides := range props.Overrides {
if _, ok := fsGenState.nativeBridgeModules[depName]; ok {
// Do not remove automatically remove overrides of native bridge modules
// Some native_bridge_supported modules override the native_bridge variant
// of another module, but not the "main" variant.
// Determining this in fsgen requires additional information. Defer this to
// android_filesystem.
continue
}
overridden[overrides] = true
}
for _, requiredModule := range props.Required {
if requiredModuleName, _, ok := fsGenState.moduleToInstallationProps.GetFromModuleName(requiredModule); ok {
moduleToRequiredRdepsMap[requiredModuleName] = append(moduleToRequiredRdepsMap[requiredModuleName], depName)
}
}
// add required dep to the queue.
allDeps = append(allDeps, props.Required...)
i += 1
}
fullyQualifiedOverriddenModuleNames := map[string]installationProperties{}
for overridden := range overridden {
if fullyQualifiedModuleName, props, ok := fsGenState.moduleToInstallationProps.GetFromModuleName(overridden); ok {
fullyQualifiedOverriddenModuleNames[fullyQualifiedModuleName] = props
}
}
removeModuleFromFsDeps := func(moduleName string) {
for partition := range fsDeps {
delete(*fsDeps[partition], moduleName)
}
}
// isOverriddenModule returns true if the module itself is overridden by another module,
// or is transitively overridden as all of its required reverse dependencies are overridden.
// The module is not overridden if it is listed in PRODUCT_PACKAGES, even all of its
// required reverse dependencies are overridden
isOverriddenModule := func(moduleName string) bool {
// check if the module itself is overridden
if _, ok := fullyQualifiedOverriddenModuleNames[moduleName]; ok {
return true
}
// check if all of its required reverse dependencies are overridden
rdeps, ok := moduleToRequiredRdepsMap[moduleName]
if !ok {
return false
}
for _, rdep := range rdeps {
// The module cannot be transitively overridden if it is listed in PRODUCT_PACKAGES
if rdep == "PRODUCT_PACKAGES" {
return false
} else if _, ok := fullyQualifiedOverriddenModuleNames[rdep]; !ok {
return false
}
}
return true
}
// Step 3: Delete all the overridden modules and its required deps.
// The module is removed only if all of its required rdeps are overridden.
// e.g. if the module is referenced by multiple modules as a required dependency
// and if any of the rdep modules are not overridden, the module should be installed.
for _, overridden := range android.SortedKeys(fullyQualifiedOverriddenModuleNames) {
requiredQueue := queue{internalQueue: list.New()}
requiredQueue.Add(overridden)
// Iterate over overridden module and its rdeps until the queue is empty.
// Rdeps are added to the queue if the module is overridden
for requiredQueue.Len() > 0 {
requiredModule := requiredQueue.Pop()
if isOverriddenModule(requiredModule) {
removeModuleFromFsDeps(requiredModule)
requiredModuleProp, _ := fsGenState.moduleToInstallationProps.GetFromFullyQualifiedModuleName(requiredModule)
for _, requiredDep := range requiredModuleProp.Required {
if fullyQualifiedRequiredDepName, _, ok := fsGenState.moduleToInstallationProps.GetFromModuleName(requiredDep); ok {
requiredQueue.Add(fullyQualifiedRequiredDepName)
}
}
}
}
}
filteredOverriddenDepsMap := make(map[string][]string)
for _, overriddenDep := range android.SortedKeys(fullyQualifiedOverriddenModuleNames) {
prop := fullyQualifiedOverriddenModuleNames[overriddenDep]
filteredOverriddenDepsMap[prop.Partition] = append(filteredOverriddenDepsMap[prop.Partition], overriddenDep)
}
fsGenState.overriddenModuleNames = filteredOverriddenDepsMap
return nil
})
}
type directDepWithParentPartition struct {
// name of the install partition of the parent module
parentPartition string
parentArchType android.ArchType
// fully qualified module name of the "required" direct dep
directDepName string
// whether this is a rustlib or native shared lib dependency
isSharedLibDep bool
}
type crossPartitionRequiredDep struct {
partition string
isSharedLibDep bool
// Arches of the binary that requested the cross partition dependency.
archesOfRequiredSharedLibDep []android.ArchType
}
// This function is run only once to compute the list of transitive "required" dependencies
// where the install partition differs from that of the direct reverse dependency (i.e. parent
// module). Note that this is done via a graph walk from the top level deps of the autogenerated
// filesystem modules. Thus, the module will not be included in the returning map even when the
// install partition differs from that of the parent module if the module is not installed
// for the target product.
// The return value is a mapping of fully qualified module name to their install partition and arch types.
func correctCrossPartitionRequiredDeps(config android.Config) map[string]crossPartitionRequiredDep {
return config.Once(fsGenCrossPartitionRequiredDepsOnceKey, func() interface{} {
fsGenState := config.Get(fsGenStateOnceKey).(*FsGenState)
fsDeps := fsGenState.fsDeps
moduleToInstallationProps := fsGenState.moduleToInstallationProps
// Mapping of fully qualified module name to its list of install partition
// Given that a single module cannot be listed as deps of multiple filesystem modules,
// the key is a single string value instead of a list of strings
ret := make(map[string]crossPartitionRequiredDep)
// Add the pair of:
// 1. install partition of the top level dep module
// 2. fully qualified module name of the direct dep of the top level dep module
// to the stack to perform dfs.
moduleNamesStack := []directDepWithParentPartition{}
for _, partition := range android.SortedKeys(fsDeps) {
for _, topLevelModule := range fsDeps[partition].SortedFullyQualifiedNames() {
if props, ok := moduleToInstallationProps.GetFromFullyQualifiedModuleName(topLevelModule); ok {
for _, requiredModule := range props.Required {
moduleNamesStack = append(moduleNamesStack, directDepWithParentPartition{
parentPartition: partition,
parentArchType: props.ArchType,
directDepName: fullyQualifiedModuleName(requiredModule, props.Namespace),
})
}
// system_ext-specific image variation is not created, thus system_ext
// rust or cc module will link against system rustlibs or shared libs.
// Since cross-partition installation is not supported in filesystem modules,
// system rustlibs or shared libs of system_ext_specific modules should be
// separately added as deps of the system image.
if partition == "system_ext" {
for _, sharedLibModule := range props.CcAndRustSharedLibs {
moduleNamesStack = append(moduleNamesStack, directDepWithParentPartition{
parentPartition: partition,
parentArchType: props.ArchType,
directDepName: fullyQualifiedModuleName(sharedLibModule, props.Namespace),
isSharedLibDep: true,
})
}
}
}
}
}
// map of fully qualified module names to store the names of modules that have been
// visited during the traversal
traversalMap := map[string]bool{}
// Iterate through the stack and find modules where the partition does not match that of
// the parent module
for len(moduleNamesStack) > 0 {
// Pop the last element from the stack
visitingModule := moduleNamesStack[len(moduleNamesStack)-1]
moduleNamesStack = moduleNamesStack[:len(moduleNamesStack)-1]
// Add the fully qualified module name to the returning map with its install
// partition if it does not match that of its parent.
// If the module has already been visited, it means its required direct deps has
// already been visited. Thus do not add the required deps to the stack.
// If it's the first time visiting the module, add the required deps to the stack and
// mark the module visited.
if moduleProps, ok := moduleToInstallationProps.GetFromFullyQualifiedModuleName(visitingModule.directDepName); ok {
if moduleProps.Partition != visitingModule.parentPartition {
if !visitingModule.isSharedLibDep || moduleProps.Partition == "system" {
if entry, exists := ret[visitingModule.directDepName]; exists {
archesOfRequiredSharedLibDep := append(entry.archesOfRequiredSharedLibDep, visitingModule.parentArchType)
entry.archesOfRequiredSharedLibDep = archesOfRequiredSharedLibDep
} else {
ret[visitingModule.directDepName] = crossPartitionRequiredDep{
partition: moduleProps.Partition,
isSharedLibDep: visitingModule.isSharedLibDep,
archesOfRequiredSharedLibDep: []android.ArchType{visitingModule.parentArchType},
}
}
}
}
if _, ok := traversalMap[visitingModule.directDepName]; !ok {
traversalMap[visitingModule.directDepName] = true
for _, requiredModule := range moduleProps.Required {
moduleNamesStack = append(moduleNamesStack, directDepWithParentPartition{
parentPartition: moduleProps.Partition,
directDepName: requiredModule,
})
}
if moduleProps.Partition == "system_ext" {
for _, rustLibModule := range moduleProps.CcAndRustSharedLibs {
moduleNamesStack = append(moduleNamesStack, directDepWithParentPartition{
parentPartition: moduleProps.Partition,
directDepName: rustLibModule,
isSharedLibDep: true,
})
}
}
}
}
}
return ret
}).(map[string]crossPartitionRequiredDep)
}
var HighPriorityDeps = []string{}
func isHighPriorityDep(depName string) bool {
for _, highPriorityDeps := range HighPriorityDeps {
if strings.HasPrefix(depName, highPriorityDeps) {
return true
}
}
return false
}
func generateDepStruct(deps map[string]*depCandidateProps, highPriorityDeps []string, overriddenDeps []string) *packagingPropsStruct {
depsStruct := packagingPropsStruct{}
for depName, depProps := range deps {
if _, ok := depProps.NativeBridgeSupport[android.NativeBridgeDisabled]; !ok {
// Only the native bridge variant of this dep should be added.
// This will be done separately.
continue
}
bitness := getBitness(depProps.Arch)
fullyQualifiedDepName := fullyQualifiedModuleName(depName, depProps.Namespace)
if android.InList(depName, highPriorityDeps) {
depsStruct.High_priority_deps = append(depsStruct.High_priority_deps, fullyQualifiedDepName)
} else if android.InList("32", bitness) && android.InList("64", bitness) {
// If both 32 and 64 bit variants are enabled for this module
switch depProps.Multilib {
case string(android.MultilibBoth):
depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName)
case string(android.MultilibCommon), string(android.MultilibFirst):
depsStruct.Deps = append(depsStruct.Deps, fullyQualifiedDepName)
case "32":
depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName)
case "64", "darwin_universal":
depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName)
case "prefer32", "first_prefer32":
depsStruct.Multilib.Prefer32.Deps = append(depsStruct.Multilib.Prefer32.Deps, fullyQualifiedDepName)
default:
depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName)
}
} else if android.InList("64", bitness) {
// If only 64 bit variant is enabled
depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName)
} else if android.InList("32", bitness) {
// If only 32 bit variant is enabled
depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName)
} else {
// If only common variant is enabled
depsStruct.Multilib.Common.Deps = append(depsStruct.Multilib.Common.Deps, fullyQualifiedDepName)
}
}
// Add the native bridge deps
var nativeBridgeDeps []string
for depName, depProps := range deps {
if _, ok := depProps.NativeBridgeSupport[android.NativeBridgeEnabled]; !ok {
continue
}
if depProps.Namespace != "." { // Add the fully qualified name
nativeBridgeDeps = append(nativeBridgeDeps, "//"+depProps.Namespace+":"+depName)
} else {
nativeBridgeDeps = append(nativeBridgeDeps, depName)
}
}
depsStruct.Deps = android.SortedUniqueStrings(depsStruct.Deps)
depsStruct.Multilib.Lib32.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Lib32.Deps)
depsStruct.Multilib.Lib64.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Lib64.Deps)
depsStruct.Multilib.Prefer32.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Prefer32.Deps)
depsStruct.Multilib.Both.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Both.Deps)
depsStruct.Multilib.Common.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Common.Deps)
depsStruct.Multilib.Native_bridge.Deps = android.SortedUniqueStrings(nativeBridgeDeps)
depsStruct.High_priority_deps = android.SortedUniqueStrings(depsStruct.High_priority_deps)
depsStruct.Overridden_deps = android.SortedUniqueStrings(overriddenDeps)
return &depsStruct
}
[Dauer der Verarbeitung: 0.33 Sekunden, vorverarbeitet 2026-06-28]
|
2026-07-09
|