Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/build/build/soong/fsgen/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 21 kB image not shown  

Quelle  prebuilt_etc_modules_gen.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 (
 "android/soong/android"
 "android/soong/etc"
 "android/soong/filesystem"
 "fmt"
 "path/filepath"
 "slices"
 "strings"

 "github.com/google/blueprint/proptools"
)

type srcBaseFileInstallBaseFileTuple struct {
 srcBaseFile     string
 installBaseFile string
 destOwner       string
}

// prebuilt src files grouped by the install partitions.
// Each groups are a mapping of the relative install path to the name of the files
type prebuiltSrcGroupByInstallPartition struct {
 system         map[string][]srcBaseFileInstallBaseFileTuple
 system_ext     map[string][]srcBaseFileInstallBaseFileTuple
 product        map[string][]srcBaseFileInstallBaseFileTuple
 vendor         map[string][]srcBaseFileInstallBaseFileTuple
 recovery       map[string][]srcBaseFileInstallBaseFileTuple
 vendor_dlkm    map[string][]srcBaseFileInstallBaseFileTuple
 vendor_ramdisk map[string][]srcBaseFileInstallBaseFileTuple
}

func newPrebuiltSrcGroupByInstallPartition() *prebuiltSrcGroupByInstallPartition {
 return &prebuiltSrcGroupByInstallPartition{
  system:         map[string][]srcBaseFileInstallBaseFileTuple{},
  system_ext:     map[string][]srcBaseFileInstallBaseFileTuple{},
  product:        map[string][]srcBaseFileInstallBaseFileTuple{},
  vendor:         map[string][]srcBaseFileInstallBaseFileTuple{},
  recovery:       map[string][]srcBaseFileInstallBaseFileTuple{},
  vendor_dlkm:    map[string][]srcBaseFileInstallBaseFileTuple{},
  vendor_ramdisk: map[string][]srcBaseFileInstallBaseFileTuple{},
 }
}

func isSubdirectory(parent, child string) bool {
 rel, err := filepath.Rel(parent, child)
 if err != nil {
  return false
 }
 return !strings.HasPrefix(rel, "..")
}

func appendIfCorrectInstallPartition(partitionToInstallPathList []partitionToInstallPath, destPath, srcPath, destOwner string, srcGroup *prebuiltSrcGroupByInstallPartition) {
 for _, part := range partitionToInstallPathList {
  partition := part.name
  installPath := part.installPath

  if isSubdirectory(installPath, destPath) {
   installDir := filepath.Dir(destPath)
   var srcMap map[string][]srcBaseFileInstallBaseFileTuple
   switch partition {
   case "system":
    srcMap = srcGroup.system
   case "system_ext":
    srcMap = srcGroup.system_ext
   case "product":
    srcMap = srcGroup.product
   case "vendor":
    srcMap = srcGroup.vendor
   case "recovery":
    srcMap = srcGroup.recovery
   case "vendor_dlkm":
    srcMap = srcGroup.vendor_dlkm
   case "vendor_ramdisk":
    srcMap = srcGroup.vendor_ramdisk
   }
   if srcMap != nil {
    srcMap[installDir] = append(srcMap[installDir], srcBaseFileInstallBaseFileTuple{
     srcBaseFile:     filepath.Base(srcPath),
     installBaseFile: filepath.Base(destPath),
     destOwner:       destOwner,
    })
   }
   return
  }
 }
}

// CopyFileTarget holds the destination path and the owner of the copied file.
type DestInfo struct {
 DestPath string
 Owner    string
}

// Create a map of source files to the list of destination files from PRODUCT_COPY_FILES entries.
// Note that the value of the map is a list of string, given that a single source file can be
// copied to multiple files.
// This function also checks the existence of the source files, and validates that there is no
// multiple source files copying to the same dest file.
func uniqueExistingProductCopyFileMap(ctx android.LoadHookContext) map[string][]DestInfo {
 seen := make(map[string]bool)
 filtered := make(map[string][]DestInfo)

 for _, copyFilePair := range ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.ProductCopyFiles {
  // PRODUCT_COPY_FILES format: 'src:dest:owner'.
  // Ensure we have at least 'src:dest'. The 'owner' is optional or defaults.
  srcDestList := strings.Split(copyFilePair, ":")
  if len(srcDestList) < 2 {
   ctx.ModuleErrorf("PRODUCT_COPY_FILES must follow the format \"src:dest\", got: %s", copyFilePair)
  }
  src, dest := srcDestList[0], srcDestList[1]
  owner := ""
  if len(srcDestList) >= 3 {
   owner = srcDestList[2]
  }

  // Some downstream branches use absolute path as entries in PRODUCT_COPY_FILES.
  // Convert them to relative path from top and check if they do not escape the tree root.
  relSrc := android.ToRelativeSourcePath(ctx, src)

  if _, ok := seen[dest]; !ok {
   if optionalPath := android.ExistentPathForSource(ctx, relSrc); optionalPath.Valid() {
    seen[dest] = true
    target := DestInfo{
     DestPath: dest,
     Owner:    owner, // Include the parsed owner
    }
    filtered[relSrc] = append(filtered[relSrc], target)
   }
  }
 }

 return filtered
}

type partitionToInstallPath struct {
 name        string
 installPath string
}

func getPartitionToInstallPathList(ctx android.LoadHookContext) []partitionToInstallPath {
 // System is intentionally added at the last to consider the scenarios where
 // non-system partitions are installed as part of the system partition
 partitionToInstallPathList := []partitionToInstallPath{
  {name: "recovery", installPath: "recovery/root"},
  {name: "vendor", installPath: ctx.DeviceConfig().VendorPath()},
  {name: "vendor_dlkm", installPath: ctx.DeviceConfig().VendorDlkmPath()},
  {name: "vendor_ramdisk", installPath: "vendor_ramdisk"},
  {name: "product", installPath: ctx.DeviceConfig().ProductPath()},
  {name: "system_ext", installPath: ctx.DeviceConfig().SystemExtPath()},
  {name: "system", installPath: "system"},
  {name: "system", installPath: "root"},
 }

 return partitionToInstallPathList
}

func processProductCopyFiles(ctx android.LoadHookContext) map[string]*prebuiltSrcGroupByInstallPartition {
 // Filter out duplicate dest entries and non existing src entries
 productCopyFileMap := uniqueExistingProductCopyFileMap(ctx)

 groupedSources := map[string]*prebuiltSrcGroupByInstallPartition{}
 for _, src := range android.SortedKeys(productCopyFileMap) {
  destInfos := productCopyFileMap[src]
  srcFileDir := filepath.Dir(src)
  if _, ok := groupedSources[srcFileDir]; !ok {
   groupedSources[srcFileDir] = newPrebuiltSrcGroupByInstallPartition()
  }
  for _, dest := range destInfos {
   appendIfCorrectInstallPartition(getPartitionToInstallPathList(ctx), dest.DestPath, filepath.Base(src), dest.Owner, groupedSources[srcFileDir])
  }
 }

 return groupedSources
}

type prebuiltModuleProperties struct {
 Name *string

 From_product_copy_files *bool

 Soc_specific                              *bool
 Product_specific                          *bool
 System_ext_specific                       *bool
 Vendor_dlkm_specific                      *bool
 Recovery                                  *bool
 Ramdisk                                   *bool
 Vendor_ramdisk                            *bool
 Install_in_root                           *bool
 Install_path_skip_first_stage_ramdisk_dir *bool

 Srcs []string

 No_full_install *bool

 NamespaceExportedToMake bool

 Visibility []string

 Owner *string
}

// Split relative_install_path to a separate struct, because it is not supported for every
// modules listed in [etcInstallPathToFactoryMap]
type prebuiltSubdirProperties struct {
 // If the base file name of the src and dst all match, dsts property does not need to be
 // set, and only relative_install_path can be set.
 Relative_install_path *string
}

// Split install_in_root to a separate struct as it is part of rootProperties instead of
// properties
type prebuiltInstallInRootProperties struct {
 Install_in_root *bool
}

var (
 etcInstallPathToFactoryList = map[string]android.ModuleFactory{
  "":                    etc.PrebuiltRootFactory,
  "avb":                 etc.PrebuiltAvbFactory,
  "bin":                 etc.PrebuiltBinaryFactory,
  "bt_firmware":         etc.PrebuiltBtFirmwareFactory,
  "cacerts":             etc.PrebuiltEtcCaCertsFactory,
  "dsp":                 etc.PrebuiltDSPFactory,
  "etc":                 etc.PrebuiltEtcFactory,
  "etc/dsp":             etc.PrebuiltDSPFactory,
  "etc/firmware":        etc.PrebuiltFirmwareFactory,
  "firmware":            etc.PrebuiltFirmwareFactory,
  "gpu":                 etc.PrebuiltGPUFactory,
  "first_stage_ramdisk": etc.PrebuiltFirstStageRamdiskFactory,
  "fonts":               etc.PrebuiltFontFactory,
  "framework":           etc.PrebuiltFrameworkFactory,
  "lib":                 etc.PrebuiltLibFactory,
  "lib64":               etc.PrebuiltRenderScriptBitcodeFactory,
  "lib/rfsa":            etc.PrebuiltRFSAFactory,
  "media":               etc.PrebuiltMediaFactory,
  "odm":                 etc.PrebuiltOdmFactory,
  "optee":               etc.PrebuiltOpteeFactory,
  "overlay":             etc.PrebuiltOverlayFactory,
  "priv-app":            etc.PrebuiltPrivAppFactory,
  "radio":               etc.PrebuiltRadioFactory,
  "sbin":                etc.PrebuiltSbinFactory,
  "system":              etc.PrebuiltSystemFactory,
  "res":                 etc.PrebuiltResFactory,
  "rfs":                 etc.PrebuiltRfsFactory,
  "tee":                 etc.PrebuiltTeeFactory,
  "tts":                 etc.PrebuiltVoicepackFactory,
  "tvconfig":            etc.PrebuiltTvConfigFactory,
  "tvservice":           etc.PrebuiltTvServiceFactory,
  "usr/share":           etc.PrebuiltUserShareFactory,
  "usr/hyphen-data":     etc.PrebuiltUserHyphenDataFactory,
  "usr/keylayout":       etc.PrebuiltUserKeyLayoutFactory,
  "usr/keychars":        etc.PrebuiltUserKeyCharsFactory,
  "usr/srec":            etc.PrebuiltUserSrecFactory,
  "usr/idc":             etc.PrebuiltUserIdcFactory,
  "vendor":              etc.PrebuiltVendorFactory,
  "vendor_dlkm":         etc.PrebuiltVendorDlkmFactory,
  "vendor_overlay":      etc.PrebuiltVendorOverlayFactory,
  "wallpaper":           etc.PrebuiltWallpaperFactory,
  "wlc_upt":             etc.PrebuiltWlcUptFactory,
 }
)

func generatedPrebuiltEtcModuleName(partition, srcDir, destDir string, count int) string {
 // generated module name follows the pattern:
 // <install partition>-<src file path>-<relative install path from partition root>-<number>
 // Note that all path separators are replaced with "_" in the name
 moduleName := partition
 if !android.InList(srcDir, []string{"", "."}) {
  moduleName += fmt.Sprintf("-%s", strings.ReplaceAll(srcDir, string(filepath.Separator), "_"))
 }
 if !android.InList(destDir, []string{"", "."}) {
  moduleName += fmt.Sprintf("-%s", strings.ReplaceAll(destDir, string(filepath.Separator), "_"))
 }
 moduleName += fmt.Sprintf("-%d", count)

 return moduleName
}

func groupDestFilesBySrc(destFiles []srcBaseFileInstallBaseFileTuple) (ret map[string][]srcBaseFileInstallBaseFileTuple, maxLen int) {
 ret = map[string][]srcBaseFileInstallBaseFileTuple{}
 maxLen = 0
 for _, tuple := range destFiles {
  if _, ok := ret[tuple.srcBaseFile]; !ok {
   ret[tuple.srcBaseFile] = []srcBaseFileInstallBaseFileTuple{}
  }
  ret[tuple.srcBaseFile] = append(ret[tuple.srcBaseFile], tuple)
  maxLen = max(maxLen, len(ret[tuple.srcBaseFile]))
 }
 return ret, maxLen
}

func prebuiltEtcModuleProps(ctx android.LoadHookContext, moduleName, partition, destDir, destOwner string) prebuiltModuleProperties {
 moduleProps := prebuiltModuleProperties{}
 moduleProps.Name = proptools.StringPtr(moduleName)

 // Set partition specific properties
 switch partition {
 case "system_ext":
  moduleProps.System_ext_specific = proptools.BoolPtr(true)
 case "product":
  moduleProps.Product_specific = proptools.BoolPtr(true)
 case "vendor":
  moduleProps.Soc_specific = proptools.BoolPtr(true)
 case "vendor_dlkm":
  moduleProps.Vendor_dlkm_specific = proptools.BoolPtr(true)
 case "vendor_ramdisk":
  moduleProps.Vendor_ramdisk = proptools.BoolPtr(true)
  // Enforce partition path to be "TARGET_COPY_OUT_VENDOR_RAMDISK" by skipping "first_stage_ramdisk".
  moduleProps.Install_path_skip_first_stage_ramdisk_dir = proptools.BoolPtr(true)
  moduleProps.Install_in_root = proptools.BoolPtr(true)
 case "recovery":
  // To match the logic in modulePartition() in android/paths.go
  if ctx.DeviceConfig().BoardUsesRecoveryAsBoot() && strings.HasPrefix(destDir, "first_stage_ramdisk") {
   moduleProps.Ramdisk = proptools.BoolPtr(true)
  } else {
   moduleProps.Recovery = proptools.BoolPtr(true)
  }
 }

 moduleProps.From_product_copy_files = proptools.BoolPtr(true)
 moduleProps.No_full_install = proptools.BoolPtr(true)
 moduleProps.NamespaceExportedToMake = true
 moduleProps.Visibility = []string{"//visibility:public"}
 moduleProps.Owner = proptools.StringPtr(destOwner)

 return moduleProps
}

func createPrebuiltEtcModulesInDirectory(ctx android.LoadHookContext, partition, srcDir, destDir string, destFiles []srcBaseFileInstallBaseFileTuple) (moduleNames []string) {
 groupedDestFiles, maxLen := groupDestFilesBySrc(destFiles)

 for fileIndex := range maxLen {
  srcTuple := []srcBaseFileInstallBaseFileTuple{}
  for _, srcFile := range android.SortedKeys(groupedDestFiles) {
   groupedDestFile := groupedDestFiles[srcFile]
   if len(groupedDestFile) > fileIndex {
    srcTuple = append(srcTuple, groupedDestFile[fileIndex])
   }
  }

  moduleName := generatedPrebuiltEtcModuleName(partition, srcDir, destDir, fileIndex)

  var firstInstallPath string
  for _, pi := range getPartitionToInstallPathList(ctx) {
   if isSubdirectory(pi.installPath, destDir) {
    destDir, _ = filepath.Rel(pi.installPath, destDir)
    firstInstallPath = pi.installPath
    break
   }
  }

  // Find out the most appropriate module type to generate
  var etcInstallPathKey string
  for _, etcInstallPath := range android.SortedKeys(etcInstallPathToFactoryList) {
   // Do not break when found but iterate until the end to find a module with more
   // specific install path
   if strings.HasPrefix(destDir, etcInstallPath) {
    etcInstallPathKey = etcInstallPath
   }
  }
  moduleFactory := etcInstallPathToFactoryList[etcInstallPathKey]
  relDestDirFromInstallDirBase, _ := filepath.Rel(etcInstallPathKey, destDir)

  // Extract owner data from the first tuple in the current group
  var destOwner string
  if len(srcTuple) > 0 {
   destOwner = srcTuple[0].destOwner // Use the owner from the first file in the group
  }
  moduleProps := prebuiltEtcModuleProps(ctx, moduleName, partition, destDir, destOwner)
  modulePropsPtr := &moduleProps
  propsList := []interface{}{modulePropsPtr}

  allCopyFileNamesUnchanged := true
  var srcBaseFiles, installBaseFiles []string
  for _, tuple := range srcTuple {
   if tuple.srcBaseFile != tuple.installBaseFile {
    allCopyFileNamesUnchanged = false
   }
   srcBaseFiles = append(srcBaseFiles, tuple.srcBaseFile)
   installBaseFiles = append(installBaseFiles, tuple.installBaseFile)
  }

  // Recovery partition-installed modules are installed to `recovery/root/system` by
  // default (See modulePartition() in android/paths.go). If the destination file
  // directory is not `recovery/root/system/...`, it should set install_in_root to true
  // to prevent being installed in `recovery/root/system`.
  if (partition == "recovery" && !strings.HasPrefix(destDir, "system")) ||
   (partition == "system" && firstInstallPath == "root" && destDir == ".") {
   propsList = append(propsList, &prebuiltInstallInRootProperties{
    Install_in_root: proptools.BoolPtr(true),
   })
   // Discard any previously picked module and force it to prebuilt_{root,any} as
   // they are the only modules allowed to specify the `install_in_root` property.
   etcInstallPathKey = ""
   relDestDirFromInstallDirBase = destDir
  }

  // Set appropriate srcs, dsts, and releative_install_path based on
  // the source and install file names
  modulePropsPtr.Srcs = srcBaseFiles

  // prebuilt_root should only be used in very limited cases in prebuilt_etc moddule gen, where:
  // - all source file names are identical to the installed file names, and
  // - all source files are installed in root, not the subdirectories of root
  // prebuilt_root currently does not have a good way to specify the names of the multiple
  // installed files, and prebuilt_root does not allow installing files at a subdirectory
  // of the root.
  // Use prebuilt_any instead of prebuilt_root if either of the conditions are not met as
  // a fallback behavior.
  if etcInstallPathKey == "" {
   if !(allCopyFileNamesUnchanged && android.InList(relDestDirFromInstallDirBase, []string{"", "."})) {
    moduleFactory = etc.PrebuiltAnyFactory
   }
  }

  if allCopyFileNamesUnchanged {
   // Specify relative_install_path if it is not installed in the base directory of the module.
   // In case of prebuilt_{root,any} this is equivalent to the root of the partition.
   if !android.InList(relDestDirFromInstallDirBase, []string{"", "."}) {
    propsList = append(propsList, &prebuiltSubdirProperties{
     Relative_install_path: proptools.StringPtr(relDestDirFromInstallDirBase),
    })
   }
  } else {
   dsts := proptools.NewConfigurable[[]string](nil, nil)
   for _, installBaseFile := range installBaseFiles {
    dsts.AppendSimpleValue([]string{filepath.Join(relDestDirFromInstallDirBase, installBaseFile)})
   }
   propsList = append(propsList, &etc.PrebuiltDstsProperties{
    Dsts: dsts,
   })
  }

  ctx.CreateModuleInDirectory(moduleFactory, srcDir, propsList...)
  moduleNames = append(moduleNames, moduleName)
 }

 return moduleNames
}

func createPrebuiltEtcModulesForPartition(ctx android.LoadHookContext, partition, srcDir string, destDirFilesMap map[string][]srcBaseFileInstallBaseFileTuple) (ret []string) {
 for _, destDir := range android.SortedKeys(destDirFilesMap) {
  ret = append(ret, createPrebuiltEtcModulesInDirectory(ctx, partition, srcDir, destDir, destDirFilesMap[destDir])...)
 }
 return ret
}

// Creates prebuilt_* modules based on the install paths and returns the list of generated
// module names
func createPrebuiltEtcModules(ctx android.LoadHookContext) (ret []string) {
 groupedSources := processProductCopyFiles(ctx)
 for _, srcDir := range android.SortedKeys(groupedSources) {
  groupedSource := groupedSources[srcDir]
  ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "system", srcDir, groupedSource.system)...)
  ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "system_ext", srcDir, groupedSource.system_ext)...)
  ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "product", srcDir, groupedSource.product)...)
  ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "vendor", srcDir, groupedSource.vendor)...)
  ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "recovery", srcDir, groupedSource.recovery)...)
  ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "vendor_dlkm", srcDir, groupedSource.vendor_dlkm)...)
  ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "vendor_ramdisk", srcDir, groupedSource.vendor_ramdisk)...)
 }

 return ret
}

func createAvbpubkeyModule(ctx android.LoadHookContext) bool {
 partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse
 if !(partitionVars.BuildingSystemOtherImage && partitionVars.BoardAvbEnable) {
  // https://cs.android.com/android/platform/superproject/+/android-latest-release:build/make/core/Makefile;l=835;drc=8ab87941b1b9a3fc990cb1986e6245cf0af10a70
  return false
 }

 avbKeyPath := partitionVars.BoardAvbKeyPath
 if avbKeyPath == "" {
  // Use default
  // https://cs.android.com/android/_/android/platform/build/+/045a3d6a3e359633a14853a5a5e1e4f2a11cbdae:core/Makefile;l=4548;bpv=1;bpt=0;drc=a951ebf0198006f7fd38073a05c442d0eb92f97b
  avbKeyPath = "external/avb/test/data/testkey_rsa4096.pem"
 }
 ctx.CreateModuleInDirectory(
  etc.AvbpubkeyModuleFactory,
  ".",
  &struct {
   Name             *string
   Product_specific *bool
   Private_key      *string
   No_full_install  *bool
   Visibility       []string
   Licenses         []string
  }{
   Name:             proptools.StringPtr("system_other_avbpubkey"),
   Product_specific: proptools.BoolPtr(true),
   Private_key:      proptools.StringPtr(avbKeyPath),
   No_full_install:  proptools.BoolPtr(true),
   Visibility:       []string{"//visibility:public"},
   Licenses:         []string{"Android-Apache-2.0"},
  },
 )

 return true
}

func getPrebuiltKernelPath(ctx android.LoadHookContext) string {
 processedProductCopyFilesMap := uniqueExistingProductCopyFileMap(ctx)
 for _, srcPath := range android.SortedKeys(processedProductCopyFilesMap) {
  destPaths := processedProductCopyFilesMap[srcPath]
  for _, destPath := range destPaths {
   if destPath.DestPath == "kernel" {
    return srcPath
   }
  }
 }
 return ""
}

func getstageDeviceFileProps(ctx android.LoadHookContext) []filesystem.StageDeviceFilePairProp {
 stageDeviceFileProps := []filesystem.StageDeviceFilePairProp{}
 processedProductCopyFilesMap := uniqueExistingProductCopyFileMap(ctx)
 for _, src := range android.SortedKeys(processedProductCopyFilesMap) {
  dstInfos := processedProductCopyFilesMap[src]
  for _, dst := range dstInfos {
   // Only collect entries that are installed at the root directory, i.e. entries where
   // the dst does not contain any directories
   if filepath.Base(dst.DestPath) == dst.DestPath {
    stageDeviceFileProps = append(stageDeviceFileProps, filesystem.StageDeviceFilePairProp{
     Src: proptools.StringPtr(src),
     Dst: proptools.StringPtr(dst.DestPath),
    })
   }
  }
 }
 slices.SortFunc(stageDeviceFileProps, func(a, b filesystem.StageDeviceFilePairProp) int {
  return strings.Compare(*a.Src, *b.Src)
 })

 return stageDeviceFileProps
}

[Dauer der Verarbeitung: 0.23 Sekunden, vorverarbeitet 2026-06-28]