ae2694b30d
External applications such as metrics uploader depends on the TMPDIR. DumpMakeVars is changing the TMPDIR environment variable value. Once the work is done, TMPDIR directory is deleted. Additional flow of the tool or external applications can panic since TMPDIR directory does not exist. Since this is an isolated case, pass the TMPDIR directory to the command of dumping the makefile variables. Bug: b/140638454 Test: * Ran lunch command with ANDROID_ENABLE_METRICS_UPLOAD set and metrics_uploader did not crash. * m nothing Change-Id: Ib78a3f8cfb5da48f65bd9bce1511e9abdf3d9cca
210 lines
5.6 KiB
Go
210 lines
5.6 KiB
Go
// 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"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"github.com/google/blueprint/microfactory"
|
|
|
|
"android/soong/ui/build/paths"
|
|
"android/soong/ui/metrics"
|
|
)
|
|
|
|
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
|
|
}
|
|
|
|
// A "lite" version of SetupPath used for dumpvars, or other places that need
|
|
// minimal overhead (but at the expense of logging). If tmpDir is empty, the
|
|
// default TMPDIR is used from config.
|
|
func SetupLitePath(ctx Context, config Config, tmpDir string) {
|
|
if config.pathReplaced {
|
|
return
|
|
}
|
|
|
|
ctx.BeginTrace(metrics.RunSetupTool, "litepath")
|
|
defer ctx.EndTrace()
|
|
|
|
origPath, _ := config.Environment().Get("PATH")
|
|
|
|
if tmpDir == "" {
|
|
tmpDir, _ = config.Environment().Get("TMPDIR")
|
|
}
|
|
myPath := filepath.Join(tmpDir, "path")
|
|
ensureEmptyDirectoriesExist(ctx, myPath)
|
|
|
|
os.Setenv("PATH", origPath)
|
|
for name, pathConfig := range paths.Configuration {
|
|
if !pathConfig.Symlink {
|
|
continue
|
|
}
|
|
|
|
origExec, err := exec.LookPath(name)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
origExec, err = filepath.Abs(origExec)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
|
|
err = os.Symlink(origExec, filepath.Join(myPath, name))
|
|
if err != nil {
|
|
ctx.Fatalln("Failed to create symlink:", err)
|
|
}
|
|
}
|
|
|
|
myPath, _ = filepath.Abs(myPath)
|
|
|
|
prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
|
|
myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
|
|
|
|
config.Environment().Set("PATH", myPath)
|
|
config.pathReplaced = true
|
|
}
|
|
|
|
func SetupPath(ctx Context, config Config) {
|
|
if config.pathReplaced {
|
|
return
|
|
}
|
|
|
|
ctx.BeginTrace(metrics.RunSetupTool, "path")
|
|
defer ctx.EndTrace()
|
|
|
|
origPath, _ := config.Environment().Get("PATH")
|
|
myPath := filepath.Join(config.OutDir(), ".path")
|
|
interposer := myPath + "_interposer"
|
|
|
|
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)
|
|
}
|
|
|
|
if err := ioutil.WriteFile(interposer+"_origpath", []byte(origPath), 0777); err != nil {
|
|
ctx.Fatalln("Failed to write original path:", err)
|
|
}
|
|
|
|
entries, err := paths.LogListener(ctx.Context, interposer+"_log")
|
|
if err != nil {
|
|
ctx.Fatalln("Failed to listen for path logs:", err)
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|
|
procPrints := []string{
|
|
"See https://android.googlesource.com/platform/build/+/master/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))
|
|
}
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
|
|
ensureEmptyDirectoriesExist(ctx, myPath)
|
|
|
|
var execs []string
|
|
for _, pathEntry := range filepath.SplitList(origPath) {
|
|
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.")
|
|
}
|
|
|
|
for _, name := range execs {
|
|
if !paths.GetConfig(name).Symlink {
|
|
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)
|
|
}
|
|
}
|
|
|
|
myPath, _ = filepath.Abs(myPath)
|
|
|
|
// We put some prebuilts in $PATH, since it's infeasible to add dependencies for all of
|
|
// them.
|
|
prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
|
|
myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
|
|
|
|
config.Environment().Set("PATH", myPath)
|
|
config.pathReplaced = true
|
|
}
|