| // 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 |
| } |