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

Quelle  path.go   Sprache: unbekannt

 
Spracherkennung für: .go vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

// Copyright 2018 Google Inc. All rights reserved.
//
// 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 build

import (
 "fmt"
 "os"
 "os/exec"
 "path/filepath"
 "strings"

 "github.com/google/blueprint/microfactory"

 "android/soong/ui/build/paths"
 "android/soong/ui/metrics"
)

// parsePathDir returns the list of filenames of readable files in a directory.
// This does not recurse into subdirectories, and does not contain subdirectory
// names in the list.
func parsePathDir(dir string) []string {
 f, err := os.Open(dir)
 if err != nil {
  return nil
 }
 defer f.Close()

 if s, err := f.Stat(); err != nil || !s.IsDir() {
  return nil
 }

 infos, err := f.Readdir(-1)
 if err != nil {
  return nil
 }

 ret := make([]string, 0, len(infos))
 for _, info := range infos {
  if m := info.Mode(); !m.IsDir() && m&0111 != 0 {
   ret = append(ret, info.Name())
  }
 }
 return ret
}

// SetupLitePath is the "lite" version of SetupPath used for dumpvars, or other
// places that does not need the full logging capabilities of path_interposer,
// wants the minimal performance overhead, and still get the benefits of $PATH
// hermeticity.
func SetupLitePath(ctx Context, config Config, tmpDir string) {
 // Don't replace the path twice.
 if config.pathReplaced {
  return
 }

 e := ctx.BeginTrace(metrics.RunSetupTool, "litepath")
 defer e.End()

 origPath, _ := config.Environment().Get("PATH")

 // If tmpDir is empty, the default TMPDIR is used from config.
 if tmpDir == "" {
  tmpDir, _ = config.Environment().Get("TMPDIR")
 }
 myPath := filepath.Join(tmpDir, "path")
 ensureEmptyDirectoriesExist(ctx, myPath)

 os.Setenv("PATH", origPath)
 // Iterate over the ACL configuration of host tools for this build.
 for name, pathConfig := range paths.Configuration {
  if !pathConfig.Symlink {
   // Excludes 'Forbidden' and 'LinuxOnlyPrebuilt' PathConfigs.
   continue
  }

  origExec, err := exec.LookPath(name)
  if err != nil {
   continue
  }
  origExec, err = filepath.Abs(origExec)
  if err != nil {
   continue
  }

  // Symlink allowed host tools into a directory for hermeticity.
  err = os.Symlink(origExec, filepath.Join(myPath, name))
  if err != nil {
   ctx.Fatalln("Failed to create symlink:", err)
  }
 }

 myPath, _ = filepath.Abs(myPath)

 // Set up the checked-in prebuilts path directory for the current host OS.
 prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + config.PrebuiltOS())
 myPath = prebuiltsPath + string(os.PathListSeparator) + myPath

 // Set $PATH to be the directories containing the host tool symlinks, and
 // the prebuilts directory for the current host OS.
 config.Environment().Set("PATH", myPath)
 config.pathReplaced = true
}

// SetupPath uses the path_interposer to intercept calls to $PATH binaries, and
// communicates with the interposer to validate allowed $PATH binaries at
// runtime, using logs as a medium.
//
// This results in hermetic directories in $PATH containing only allowed host
// tools for the build, and replaces $PATH to contain *only* these directories,
// and enables an incremental restriction of tools allowed in the $PATH without
// breaking existing use cases.
func SetupPath(ctx Context, config Config) {
 // Don't replace $PATH twice.
 if config.pathReplaced {
  return
 }

 e := ctx.BeginTrace(metrics.RunSetupTool, "path")
 defer e.End()

 origPath, _ := config.Environment().Get("PATH")
 // The directory containing symlinks from binaries in $PATH to the interposer.
 myPath := filepath.Join(config.OutDir(), ".path")
 interposer := myPath + "_interposer"

 // Bootstrap the path_interposer Go binary with microfactory.
 var cfg microfactory.Config
 cfg.Map("android/soong", "build/soong")
 cfg.TrimPath, _ = filepath.Abs(".")
 if _, err := microfactory.Build(&cfg, interposer, "android/soong/cmd/path_interposer"); err != nil {
  ctx.Fatalln("Failed to build path interposer:", err)
 }

 // envsetup.sh can keep prepending paths across consecutive runs, causing
 // origPath to change slightly. Deduplicate the path list before checking.
 var cleanPath []string
 seenPath := make(map[string]bool)
 for _, p := range filepath.SplitList(origPath) {
  if p != "" && !seenPath[p] {
   seenPath[p] = true
   cleanPath = append(cleanPath, p)
  }
 }
 cleanOrigPath := strings.Join(cleanPath, string(os.PathListSeparator))

 // Save the original $PATH in a file if it has changed.
 writeValueIfChanged(ctx, interposer+"_origpath", cleanOrigPath)

 // Communication with the path interposer works over log entries. Set up the
 // listener channel for the log entries here.
 entries, err := paths.LogListener(ctx.Context, interposer+"_log")
 if err != nil {
  ctx.Fatalln("Failed to listen for path logs:", err)
 }

 // Loop over all log entry listener channels to validate usage of only
 // allowed PATH tools at runtime.
 go func() {
  for log := range entries {
   curPid := os.Getpid()
   for i, proc := range log.Parents {
    if proc.Pid == curPid {
     log.Parents = log.Parents[i:]
     break
    }
   }
   // Compute the error message along with the process tree, including
   // parents, for this log line.
   procPrints := []string{
    "See https://android.googlesource.com/platform/build/+/main/Changes.md#PATH_Tools for more information.",
   }
   if len(log.Parents) > 0 {
    procPrints = append(procPrints, "Process tree:")
    for i, proc := range log.Parents {
     procPrints = append(procPrints, fmt.Sprintf("%s→ %s", strings.Repeat(" ", i), proc.Command))
    }
   }

   // Validate usage against disallowed or missing PATH tools.
   config := paths.GetConfig(log.Basename)
   if config.Error {
    ctx.Printf("Disallowed PATH tool %q used: %#v", log.Basename, log.Args)
    for _, line := range procPrints {
     ctx.Println(line)
    }
   } else {
    ctx.Verbosef("Unknown PATH tool %q used: %#v", log.Basename, log.Args)
    for _, line := range procPrints {
     ctx.Verboseln(line)
    }
   }
  }
 }()

 // Create the .path directory.
 // Do not wipe out the entire .path directory; only ensure that the directory exists.
 ensureDirectoriesExist(ctx, myPath)

 // Compute the full list of binaries available in the original $PATH.
 var execs []string
 for _, pathEntry := range filepath.SplitList(cleanOrigPath) {
  if pathEntry == "" {
   // Ignore the current directory
   continue
  }
  // TODO(dwillemsen): remove path entries under TOP? or anything
  // that looks like an android source dir? They won't exist on
  // the build servers, since they're added by envsetup.sh.
  // (Except for the JDK, which is configured in ui/build/config.go)

  execs = append(execs, parsePathDir(pathEntry)...)
 }

 if config.Environment().IsEnvTrue("TEMPORARY_DISABLE_PATH_RESTRICTIONS") {
  ctx.Fatalln("TEMPORARY_DISABLE_PATH_RESTRICTIONS was a temporary migration method, and is now obsolete.")
 }

 // Create symlinks from the path_interposer binary to all binaries for each
 // directory in the original $PATH. This ensures that during the build,
 // every call to a binary that's expected to be in the $PATH will be
 // intercepted by the path_interposer binary, and validated with the
 // LogEntry listener above at build time.
 for _, name := range execs {
  if !paths.GetConfig(name).Symlink {
   // Ignore host tools that shouldn't be symlinked.
   continue
  }

  // check if a file already exists and skip if it does
  if _, err := os.Lstat(filepath.Join(myPath, name)); err == nil {
   continue
  }

  err := os.Symlink("../.path_interposer", filepath.Join(myPath, name))
  // Intentionally ignore existing files -- that means that we
  // just created it, and the first one should win.
  if err != nil && !os.IsExist(err) {
   ctx.Fatalln("Failed to create symlink:", err)
  }
 }

 myPathWithSrc := myPath
 // Should be appended with /src if OutDir is not absolute.
 if !filepath.IsAbs(myPath) {
  myPathWithSrc = filepath.Join("/src", myPath)
 }
 myPath, _ = filepath.Abs(myPath)

 // We put some prebuilts in $PATH, since it's infeasible to add dependencies
 // for all of them.
 prebuiltsPathRel := "prebuilts/build-tools/path/" + config.PrebuiltOS()
 prebuiltsPath, _ := filepath.Abs(prebuiltsPathRel)
 myPath = prebuiltsPath + string(os.PathListSeparator) + myPath

 // Add /src/$OUT_DIR/.path to PATH for action sandboxed build.
 if config.IsActionSandboxedBuild() {
  myPath = myPath + string(os.PathListSeparator) + myPathWithSrc
  prebuiltsPathRel = filepath.Join("/src", prebuiltsPathRel)
  myPath = myPath + string(os.PathListSeparator) + prebuiltsPathRel
 }

 // Replace the $PATH variable with the path_interposer symlinks, and
 // checked-in prebuilts.
 config.Environment().Set("PATH", myPath)
 config.pathReplaced = true
}

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