blob: 50d8576b15cc47086df5a4b9a6bee2718b0bf311 [file]
// 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 (
"fmt"
"slices"
"strings"
"sync"
"android/soong/android"
"github.com/google/blueprint/proptools"
)
func RegisterCollectFileSystemDepsMutators(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("fs_collect_deps", collectDepsMutator).MutatesGlobalState()
ctx.BottomUp("fs_remove_deps", removeDepsMutator).MutatesGlobalState()
ctx.BottomUp("fs_cross_partition_required_deps", crossPartitionRequiredMutator).MutatesGlobalState()
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 names to their corresponding installation properties
// Should not be accessed directly to add entries; Use AddToMap instead.
moduleToPropsMap map[string]installationProperties
}
func (m *moduleToInstallationProps) AddToMap(ctx android.BottomUpMutatorContext, prop *installationProperties) {
m.moduleToPropsMap[fullyQualifiedModuleName(ctx.ModuleName(), ctx.Namespace().Path)] = *prop
}
func (m *moduleToInstallationProps) Get(ctx android.BottomUpMutatorContext) (installationProperties, bool) {
return m.GetFromFullyQualifiedModuleName(fullyQualifiedModuleName(ctx.ModuleName(), ctx.Namespace().Path))
}
func (m *moduleToInstallationProps) GetFromFullyQualifiedModuleName(name string) (installationProperties, bool) {
prop, ok := m.moduleToPropsMap[name]
if ok {
return prop, ok
}
return installationProperties{}, ok
}
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
}
type installationProperties struct {
Required []string
Overrides []string
Partition string
Namespace string
}
func defaultDepCandidateProps(config android.Config) *depCandidateProps {
return &depCandidateProps{
Namespace: ".",
Arch: []android.ArchType{config.DevicePrimaryArchType()},
NativeBridgeSupport: map[android.NativeBridgeSupport]bool{android.NativeBridgeDisabled: true},
}
}
func productInstalledModules(ctx android.LoadHookContext) []string {
partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
allInstalledModules := partitionVars.ProductPackages
if ctx.Config().Debuggable() {
allInstalledModules = append(allInstalledModules, partitionVars.ProductPackagesDebug...)
if ctx.Config().Eng() {
allInstalledModules = append(allInstalledModules, partitionVars.ProductPackagesEng...)
}
if android.InList("address", ctx.Config().SanitizeDevice()) {
allInstalledModules = append(allInstalledModules, partitionVars.ProductPackagesDebugAsan...)
}
if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") {
allInstalledModules = append(allInstalledModules, partitionVars.ProductPackagesDebugJavaCoverage...)
}
}
if android.InList("arm64", []string{ctx.DeviceConfig().DeviceArch(), ctx.DeviceConfig().DeviceSecondaryArch()}) {
allInstalledModules = append(allInstalledModules, partitionVars.ProductPackagesArm64...)
}
if android.UncheckedFinalApiLevel(29).GreaterThanOrEqualTo(ctx.DeviceConfig().ShippingApiLevel()) {
allInstalledModules = append(allInstalledModules, partitionVars.ProductPackagesShippingApiLevel29...)
}
if android.UncheckedFinalApiLevel(33).GreaterThanOrEqualTo(ctx.DeviceConfig().ShippingApiLevel()) {
allInstalledModules = append(allInstalledModules, partitionVars.ProductPackagesShippingApiLevel33...)
}
if android.UncheckedFinalApiLevel(34).GreaterThanOrEqualTo(ctx.DeviceConfig().ShippingApiLevel()) {
allInstalledModules = append(allInstalledModules, partitionVars.ProductPackagesShippingApiLevel34...)
}
return allInstalledModules
}
func createFsGenState(ctx android.LoadHookContext, generatedPrebuiltEtcModuleNames []string) *FsGenState {
return ctx.Config().Once(fsGenStateOnceKey, func() interface{} {
allInstalledModules := slices.Concat(
productInstalledModules(ctx),
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()),
// build props are automatically added to `ALL_DEFAULT_INSTALLED_MODULES`
"system_dlkm-build.prop": 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_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()),
},
},
fsDepsMutex: sync.Mutex{},
moduleToInstallationProps: moduleToInstallationProps{moduleToPropsMap: map[string]installationProperties{}},
generatedPrebuiltEtcModuleNames: generatedPrebuiltEtcModuleNames,
avbKeyFilegroups: map[string]string{},
nativeBridgeModules: map[string]bool{},
}
(*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())
}
// 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.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 != "" {
(*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)
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, mctx.Module().Target().Arch.ArchType)
(*deps)[moduleName].NativeBridgeSupport[nbs] = true
} else {
multilib, _ := mctx.Module().DecodeMultilib(mctx)
(*deps)[moduleName] = &depCandidateProps{
Namespace: mctx.Namespace().Path,
Multilib: multilib,
Arch: []android.ArchType{mctx.Module().Target().Arch.ArchType},
NativeBridgeSupport: map[android.NativeBridgeSupport]bool{nbs: true},
}
}
}
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()
if _, ok := fsGenState.depCandidatesMap[mctx.ModuleName()]; ok {
installPartition := m.PartitionTag(mctx.DeviceConfig())
// Only add the module as dependency when:
// - its enabled
// - its namespace is included in PRODUCT_SOONG_NAMESPACES
if m.Enabled(mctx) && m.ExportedToMake() {
appendDepIfAppropriate(mctx, fsGenState.fsDeps[installPartition], installPartition, android.NativeBridgeDisabled, mctx.ModuleName())
}
}
if _, ok := fsGenState.depCandidatesMap[mctx.ModuleName()+".native_bridge"]; ok {
installPartition := m.PartitionTag(mctx.DeviceConfig())
if m.Enabled(mctx) && m.ExportedToMake() {
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())
if m.Enabled(mctx) && m.ExportedToMake() {
appendDepIfAppropriate(mctx, fsGenState.fsDeps[installPartition], installPartition, android.NativeBridgeEnabled, 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 m.Enabled(mctx) && m.ExportedToMake() {
fsGenState.moduleToInstallationProps.AddToMap(mctx, &installationProperties{
Required: m.RequiredModuleNames(mctx),
Overrides: m.Overrides(),
Partition: m.PartitionTag(mctx.DeviceConfig()),
Namespace: mctx.Namespace().Path,
})
}
if mctx.Target().NativeBridge == android.NativeBridgeEnabled {
fsGenState.nativeBridgeModules[mctx.ModuleName()] = 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 {
High_priority_deps []string
Deps []string
Multilib multilibDepsStruct
}
func fullyQualifiedModuleName(moduleName, namespace string) string {
if namespace == "." {
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 partition, ok := additionalCrossPartitionRequiredDeps[fullyQualifiedModuleName]; ok && mctx.Module().PartitionTag(mctx.DeviceConfig()) == partition {
appendDepIfAppropriate(mctx, fsGenState.fsDeps[partition], 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
}
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...))
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
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]
}
}
if baseModuleProps, ok := fsGenState.moduleToInstallationProps.GetFromFullyQualifiedModuleName(base); ok && mctx.Module().Enabled(mctx) && mctx.Module().ExportedToMake() {
partition := baseModuleProps.Partition
appendDepIfAppropriate(mctx, fsDeps[partition], partition, android.NativeBridgeDisabled, mctx.Module().Name())
}
}
}
// removeOverriddenDeps collects PRODUCT_PACKAGES and (transitive) required deps.
// it then removes any modules which appear in `overrides` of the above list.
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)
}
}
// 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
}
// add required dep to the queue.
allDeps = append(allDeps, props.Required...)
i += 1
}
// Step 3: Delete all the overridden modules.
for overridden, _ := range overridden {
for partition, _ := range fsDeps {
delete(*fsDeps[partition], overridden)
}
}
return nil
})
}
type directDepWithParentPartition struct {
// name of the install partition of the parent module
parentPartition string
// fully qualified module name of the "required" direct dep
directDepName string
}
// 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 names to their install partition.
func correctCrossPartitionRequiredDeps(config android.Config) map[string]string {
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]string)
// 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,
directDepName: fullyQualifiedModuleName(requiredModule, props.Namespace),
})
}
}
}
}
// 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 {
ret[visitingModule.directDepName] = moduleProps.Partition
}
if _, ok := traversalMap[visitingModule.directDepName]; !ok {
traversalMap[visitingModule.directDepName] = true
for _, requiredModule := range moduleProps.Required {
moduleNamesStack = append(moduleNamesStack, directDepWithParentPartition{
parentPartition: moduleProps.Partition,
directDepName: requiredModule,
})
}
}
}
}
return ret
}).(map[string]string)
}
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) *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)
return &depsStruct
}