From 988414c2cf6bfb868df7d402e0bf825d6fd44cc8 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Sat, 11 Jan 2020 01:11:46 +0000 Subject: [PATCH] Sandbox soong_build by changing to root directory This relands I12a0f907753fefd1997ab8b4ea2ac331234093cf along with a fix to blueprint for absolute paths. Store the current working directory and then change to the root directory so that all file accesses must go through helpers in the android package that properly track dependencies. Change-Id: I24ac485677aa102eec1a2521d16820da6ee1ae77 Fixes: 146437378 Test: m checkbuild Test: m OUT_DIR=/tmp/out nothing --- Android.bp | 1 + android/androidmk.go | 8 ++-- android/config.go | 30 ++++++++++++--- android/env.go | 18 ++++++++- android/makevars.go | 11 +++--- android/module.go | 21 ++++++++++- android/package_ctx.go | 5 --- android/paths.go | 25 ++++++++++--- android/paths_test.go | 5 --- android/register.go | 4 +- android/sandbox.go | 47 ++++++++++++++++++++++++ android/singleton.go | 3 -- androidmk/Android.bp | 1 - androidmk/androidmk/android.go | 10 ++++- cc/cmakelists.go | 11 ++---- cc/compdb.go | 22 ++++------- cc/ndk_headers.go | 13 +------ dexpreopt/config.go | 37 ++++--------------- dexpreopt/dexpreopt_gen/dexpreopt_gen.go | 30 ++++++++++++--- env/env.go | 11 ++---- java/dexpreopt_config.go | 7 ++-- java/jdeps.go | 17 ++++----- ui/build/soong.go | 1 + 23 files changed, 208 insertions(+), 130 deletions(-) create mode 100644 android/sandbox.go diff --git a/Android.bp b/Android.bp index 9403b26f8..0382ee2ed 100644 --- a/Android.bp +++ b/Android.bp @@ -69,6 +69,7 @@ bootstrap_go_package { "android/proto.go", "android/register.go", "android/rule_builder.go", + "android/sandbox.go", "android/sdk.go", "android/sh_binary.go", "android/singleton.go", diff --git a/android/androidmk.go b/android/androidmk.go index f3c15e471..dbf3aa884 100644 --- a/android/androidmk.go +++ b/android/androidmk.go @@ -323,7 +323,7 @@ func (c *androidMkSingleton) GenerateBuildActions(ctx SingletonContext) { return } - err := translateAndroidMk(ctx, transMk.String(), androidMkModulesList) + err := translateAndroidMk(ctx, absolutePath(transMk.String()), androidMkModulesList) if err != nil { ctx.Errorf(err.Error()) } @@ -364,8 +364,8 @@ func translateAndroidMk(ctx SingletonContext, mkFile string, mods []blueprint.Mo } // Don't write to the file if it hasn't changed - if _, err := os.Stat(mkFile); !os.IsNotExist(err) { - if data, err := ioutil.ReadFile(mkFile); err == nil { + if _, err := os.Stat(absolutePath(mkFile)); !os.IsNotExist(err) { + if data, err := ioutil.ReadFile(absolutePath(mkFile)); err == nil { matches := buf.Len() == len(data) if matches { @@ -383,7 +383,7 @@ func translateAndroidMk(ctx SingletonContext, mkFile string, mods []blueprint.Mo } } - return ioutil.WriteFile(mkFile, buf.Bytes(), 0666) + return ioutil.WriteFile(absolutePath(mkFile), buf.Bytes(), 0666) } func translateAndroidMkModule(ctx SingletonContext, w io.Writer, mod blueprint.Module) error { diff --git a/android/config.go b/android/config.go index 101f45728..3c49c1a6a 100644 --- a/android/config.go +++ b/android/config.go @@ -135,12 +135,12 @@ type jsonConfigurable interface { } func loadConfig(config *config) error { - err := loadFromConfigFile(&config.FileConfigurableOptions, config.ConfigFileName) + err := loadFromConfigFile(&config.FileConfigurableOptions, absolutePath(config.ConfigFileName)) if err != nil { return err } - return loadFromConfigFile(&config.productVariables, config.ProductVariablesFileName) + return loadFromConfigFile(&config.productVariables, absolutePath(config.ProductVariablesFileName)) } // loads configuration options from a JSON file in the cwd. @@ -204,6 +204,17 @@ func saveToConfigFile(config jsonConfigurable, filename string) error { return nil } +// NullConfig returns a mostly empty Config for use by standalone tools like dexpreopt_gen that +// use the android package. +func NullConfig(buildDir string) Config { + return Config{ + config: &config{ + buildDir: buildDir, + fs: pathtools.OsFs, + }, + } +} + // TestConfig returns a Config object suitable for using for tests func TestConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) Config { envCopy := make(map[string]string) @@ -320,7 +331,7 @@ func NewConfig(srcDir, buildDir string) (Config, error) { buildDir: buildDir, multilibConflicts: make(map[ArchType]bool), - fs: pathtools.OsFs, + fs: pathtools.NewOsFs(absSrcDir), } config.deviceConfig = &deviceConfig{ @@ -350,7 +361,7 @@ func NewConfig(srcDir, buildDir string) (Config, error) { } inMakeFile := filepath.Join(buildDir, ".soong.in_make") - if _, err := os.Stat(inMakeFile); err == nil { + if _, err := os.Stat(absolutePath(inMakeFile)); err == nil { config.inMake = true } @@ -398,6 +409,8 @@ func NewConfig(srcDir, buildDir string) (Config, error) { return Config{config}, nil } +var TestConfigOsFs = map[string][]byte{} + // mockFileSystem replaces all reads with accesses to the provided map of // filenames to contents stored as a byte slice. func (c *config) mockFileSystem(bp string, fs map[string][]byte) { @@ -901,8 +914,13 @@ func (c *config) BootJars() []string { return c.productVariables.BootJars } -func (c *config) DexpreoptGlobalConfig() string { - return String(c.productVariables.DexpreoptGlobalConfig) +func (c *config) DexpreoptGlobalConfig(ctx PathContext) ([]byte, error) { + if c.productVariables.DexpreoptGlobalConfig == nil { + return nil, nil + } + path := absolutePath(*c.productVariables.DexpreoptGlobalConfig) + ctx.AddNinjaFileDeps(path) + return ioutil.ReadFile(path) } func (c *config) FrameworksBaseDirExists(ctx PathContext) bool { diff --git a/android/env.go b/android/env.go index d9f2db2f3..46bd3d6c5 100644 --- a/android/env.go +++ b/android/env.go @@ -52,6 +52,17 @@ func init() { os.Clearenv() } +// getenv checks either os.Getenv or originalEnv so that it works before or after the init() +// function above. It doesn't add any dependencies on the environment variable, so it should +// only be used for values that won't change. For values that might change use ctx.Config().Getenv. +func getenv(key string) string { + if originalEnv == nil { + return os.Getenv(key) + } else { + return originalEnv[key] + } +} + func EnvSingleton() Singleton { return &envSingleton{} } @@ -66,7 +77,12 @@ func (c *envSingleton) GenerateBuildActions(ctx SingletonContext) { return } - err := env.WriteEnvFile(envFile.String(), envDeps) + data, err := env.EnvFileContents(envDeps) + if err != nil { + ctx.Errorf(err.Error()) + } + + err = WriteFileToOutputDir(envFile, data, 0666) if err != nil { ctx.Errorf(err.Error()) } diff --git a/android/makevars.go b/android/makevars.go index 38a028caf..aba4ccec3 100644 --- a/android/makevars.go +++ b/android/makevars.go @@ -23,7 +23,6 @@ import ( "strings" "github.com/google/blueprint" - "github.com/google/blueprint/pathtools" "github.com/google/blueprint/proptools" ) @@ -41,7 +40,6 @@ type MakeVarsContext interface { Config() Config DeviceConfig() DeviceConfig AddNinjaFileDeps(deps ...string) - Fs() pathtools.FileSystem ModuleName(module blueprint.Module) string ModuleDir(module blueprint.Module) string @@ -151,7 +149,8 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) { return } - outFile := PathForOutput(ctx, "make_vars"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String() + outFile := absolutePath(PathForOutput(ctx, + "make_vars"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String()) if ctx.Failed() { return @@ -175,15 +174,15 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) { outBytes := s.writeVars(vars) - if _, err := os.Stat(outFile); err == nil { - if data, err := ioutil.ReadFile(outFile); err == nil { + if _, err := os.Stat(absolutePath(outFile)); err == nil { + if data, err := ioutil.ReadFile(absolutePath(outFile)); err == nil { if bytes.Equal(data, outBytes) { return } } } - if err := ioutil.WriteFile(outFile, outBytes, 0666); err != nil { + if err := ioutil.WriteFile(absolutePath(outFile), outBytes, 0666); err != nil { ctx.Errorf(err.Error()) } } diff --git a/android/module.go b/android/module.go index c99800727..67d1f129e 100644 --- a/android/module.go +++ b/android/module.go @@ -16,13 +16,13 @@ package android import ( "fmt" + "os" "path" "path/filepath" "strings" "text/scanner" "github.com/google/blueprint" - "github.com/google/blueprint/pathtools" "github.com/google/blueprint/proptools" ) @@ -91,7 +91,8 @@ type EarlyModuleContext interface { Glob(globPattern string, excludes []string) Paths GlobFiles(globPattern string, excludes []string) Paths - Fs() pathtools.FileSystem + IsSymlink(path Path) bool + Readlink(path Path) string } // BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns @@ -1172,6 +1173,22 @@ func (e *earlyModuleContext) GlobFiles(globPattern string, excludes []string) Pa return pathsForModuleSrcFromFullPath(e, ret, false) } +func (b *earlyModuleContext) IsSymlink(path Path) bool { + fileInfo, err := b.config.fs.Lstat(path.String()) + if err != nil { + b.ModuleErrorf("os.Lstat(%q) failed: %s", path.String(), err) + } + return fileInfo.Mode()&os.ModeSymlink == os.ModeSymlink +} + +func (b *earlyModuleContext) Readlink(path Path) string { + dest, err := b.config.fs.Readlink(path.String()) + if err != nil { + b.ModuleErrorf("os.Readlink(%q) failed: %s", path.String(), err) + } + return dest +} + func (e *earlyModuleContext) Module() Module { module, _ := e.EarlyModuleContext.Module().(Module) return module diff --git a/android/package_ctx.go b/android/package_ctx.go index d3527fa20..a22891081 100644 --- a/android/package_ctx.go +++ b/android/package_ctx.go @@ -19,7 +19,6 @@ import ( "strings" "github.com/google/blueprint" - "github.com/google/blueprint/pathtools" ) // PackageContext is a wrapper for blueprint.PackageContext that adds @@ -60,10 +59,6 @@ func (e *configErrorWrapper) AddNinjaFileDeps(deps ...string) { e.pctx.AddNinjaFileDeps(deps...) } -func (e *configErrorWrapper) Fs() pathtools.FileSystem { - return nil -} - type PackageVarContext interface { PathContext errorfContext diff --git a/android/paths.go b/android/paths.go index a03fe17e5..02f56d095 100644 --- a/android/paths.go +++ b/android/paths.go @@ -16,6 +16,8 @@ package android import ( "fmt" + "io/ioutil" + "os" "path/filepath" "reflect" "sort" @@ -25,10 +27,11 @@ import ( "github.com/google/blueprint/pathtools" ) +var absSrcDir string + // PathContext is the subset of a (Module|Singleton)Context required by the // Path methods. type PathContext interface { - Fs() pathtools.FileSystem Config() Config AddNinjaFileDeps(deps ...string) } @@ -390,7 +393,7 @@ func expandOneSrcPath(ctx ModuleContext, s string, expandedExcludes []string) (P return PathsWithModuleSrcSubDir(ctx, paths, ""), nil } else { p := pathForModuleSrc(ctx, s) - if exists, _, err := ctx.Fs().Exists(p.String()); err != nil { + if exists, _, err := ctx.Config().fs.Exists(p.String()); err != nil { reportPathErrorf(ctx, "%s: %s", p, err.Error()) } else if !exists { reportPathErrorf(ctx, "module source path %q does not exist", p) @@ -720,7 +723,7 @@ func existsWithDependencies(ctx PathContext, path SourcePath) (exists bool, err var deps []string // We cannot add build statements in this context, so we fall back to // AddNinjaFileDeps - files, deps, err = pathtools.Glob(path.String(), nil, pathtools.FollowSymlinks) + files, deps, err = ctx.Config().fs.Glob(path.String(), nil, pathtools.FollowSymlinks) ctx.AddNinjaFileDeps(deps...) } @@ -752,7 +755,7 @@ func PathForSource(ctx PathContext, pathComponents ...string) SourcePath { if !exists { modCtx.AddMissingDependencies([]string{path.String()}) } - } else if exists, _, err := ctx.Fs().Exists(path.String()); err != nil { + } else if exists, _, err := ctx.Config().fs.Exists(path.String()); err != nil { reportPathErrorf(ctx, "%s: %s", path, err.Error()) } else if !exists { reportPathErrorf(ctx, "source path %q does not exist", path) @@ -1356,7 +1359,6 @@ type testPathContext struct { config Config } -func (x *testPathContext) Fs() pathtools.FileSystem { return x.config.fs } func (x *testPathContext) Config() Config { return x.config } func (x *testPathContext) AddNinjaFileDeps(...string) {} @@ -1402,3 +1404,16 @@ func maybeRelErr(basePath string, targetPath string) (string, bool, error) { } return rel, true, nil } + +// Writes a file to the output directory. Attempting to write directly to the output directory +// will fail due to the sandbox of the soong_build process. +func WriteFileToOutputDir(path WritablePath, data []byte, perm os.FileMode) error { + return ioutil.WriteFile(absolutePath(path.String()), data, perm) +} + +func absolutePath(path string) string { + if filepath.IsAbs(path) { + return path + } + return filepath.Join(absSrcDir, path) +} diff --git a/android/paths_test.go b/android/paths_test.go index ec5e59820..46e3e1fa6 100644 --- a/android/paths_test.go +++ b/android/paths_test.go @@ -21,7 +21,6 @@ import ( "strings" "testing" - "github.com/google/blueprint/pathtools" "github.com/google/blueprint/proptools" ) @@ -207,10 +206,6 @@ type moduleInstallPathContextImpl struct { inRoot bool } -func (moduleInstallPathContextImpl) Fs() pathtools.FileSystem { - return pathtools.MockFs(nil) -} - func (m moduleInstallPathContextImpl) Config() Config { return m.baseModuleContext.config } diff --git a/android/register.go b/android/register.go index b5defecad..b48d3d1bc 100644 --- a/android/register.go +++ b/android/register.go @@ -84,7 +84,9 @@ type Context struct { } func NewContext() *Context { - return &Context{blueprint.NewContext()} + ctx := &Context{blueprint.NewContext()} + ctx.SetSrcDir(absSrcDir) + return ctx } func (ctx *Context) Register() { diff --git a/android/sandbox.go b/android/sandbox.go new file mode 100644 index 000000000..ed022fb87 --- /dev/null +++ b/android/sandbox.go @@ -0,0 +1,47 @@ +// Copyright 2020 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 android + +import ( + "fmt" + "os" +) + +func init() { + // Stash the working directory in a private variable and then change the working directory + // to "/", which will prevent untracked accesses to files by Go Soong plugins. The + // SOONG_SANDBOX_SOONG_BUILD environment variable is set by soong_ui, and is not + // overrideable on the command line. + + orig, err := os.Getwd() + if err != nil { + panic(fmt.Errorf("failed to get working directory: %s", err)) + } + absSrcDir = orig + + if getenv("SOONG_SANDBOX_SOONG_BUILD") == "true" { + err = os.Chdir("/") + if err != nil { + panic(fmt.Errorf("failed to change working directory to '/': %s", err)) + } + } +} + +// DO NOT USE THIS FUNCTION IN NEW CODE. +// Deprecated: This function will be removed as soon as the existing use cases that use it have been +// replaced. +func AbsSrcDirForExistingUseCases() string { + return absSrcDir +} diff --git a/android/singleton.go b/android/singleton.go index 5519ca019..91268ad1c 100644 --- a/android/singleton.go +++ b/android/singleton.go @@ -16,7 +16,6 @@ package android import ( "github.com/google/blueprint" - "github.com/google/blueprint/pathtools" ) // SingletonContext @@ -74,8 +73,6 @@ type SingletonContext interface { // builder whenever a file matching the pattern as added or removed, without rerunning if a // file that does not match the pattern is added to a searched directory. GlobWithDeps(pattern string, excludes []string) ([]string, error) - - Fs() pathtools.FileSystem } type singletonAdaptor struct { diff --git a/androidmk/Android.bp b/androidmk/Android.bp index 41100738c..70fc1f75c 100644 --- a/androidmk/Android.bp +++ b/androidmk/Android.bp @@ -41,7 +41,6 @@ bootstrap_go_package { "androidmk-parser", "blueprint-parser", "bpfix-lib", - "soong-android", ], } diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go index 0082d8b0b..88609849d 100644 --- a/androidmk/androidmk/android.go +++ b/androidmk/androidmk/android.go @@ -15,9 +15,9 @@ package androidmk import ( - "android/soong/android" mkparser "android/soong/androidmk/parser" "fmt" + "sort" "strings" bpparser "github.com/google/blueprint/parser" @@ -350,7 +350,13 @@ func splitAndAssign(ctx variableAssignmentContext, splitFunc listSplitFunc, name return err } - for _, nameClassification := range android.SortedStringKeys(namesByClassification) { + var classifications []string + for classification := range namesByClassification { + classifications = append(classifications, classification) + } + sort.Strings(classifications) + + for _, nameClassification := range classifications { name := namesByClassification[nameClassification] if component, ok := lists[nameClassification]; ok && !emptyList(component) { err = setVariable(ctx.file, ctx.append, ctx.prefix, name, component, true) diff --git a/cc/cmakelists.go b/cc/cmakelists.go index 97d21f444..f7d9081db 100644 --- a/cc/cmakelists.go +++ b/cc/cmakelists.go @@ -76,7 +76,7 @@ func (c *cmakelistsGeneratorSingleton) GenerateBuildActions(ctx android.Singleto // Link all handmade CMakeLists.txt aggregate from // BASE/development/ide/clion to // BASE/out/development/ide/clion. - dir := filepath.Join(getAndroidSrcRootDirectory(ctx), cLionAggregateProjectsDirectory) + dir := filepath.Join(android.AbsSrcDirForExistingUseCases(), cLionAggregateProjectsDirectory) filepath.Walk(dir, linkAggregateCMakeListsFiles) return @@ -147,7 +147,7 @@ func generateCLionProject(compiledModule CompiledInterface, ctx android.Singleto f.WriteString("# Tools > CMake > Change Project Root \n\n") f.WriteString(fmt.Sprintf("cmake_minimum_required(VERSION %s)\n", minimumCMakeVersionSupported)) f.WriteString(fmt.Sprintf("project(%s)\n", ccModule.ModuleBase.Name())) - f.WriteString(fmt.Sprintf("set(ANDROID_ROOT %s)\n\n", getAndroidSrcRootDirectory(ctx))) + f.WriteString(fmt.Sprintf("set(ANDROID_ROOT %s)\n\n", android.AbsSrcDirForExistingUseCases())) pathToCC, _ := evalVariable(ctx, "${config.ClangBin}/") f.WriteString(fmt.Sprintf("set(CMAKE_C_COMPILER \"%s%s\")\n", buildCMakePath(pathToCC), "clang")) @@ -465,7 +465,7 @@ func evalVariable(ctx android.SingletonContext, str string) (string, error) { } func getCMakeListsForModule(module *Module, ctx android.SingletonContext) string { - return filepath.Join(getAndroidSrcRootDirectory(ctx), + return filepath.Join(android.AbsSrcDirForExistingUseCases(), cLionOutputProjectsDirectory, path.Dir(ctx.BlueprintFile(module)), module.ModuleBase.Name()+"-"+ @@ -473,8 +473,3 @@ func getCMakeListsForModule(module *Module, ctx android.SingletonContext) string module.ModuleBase.Os().Name, cMakeListsFilename) } - -func getAndroidSrcRootDirectory(ctx android.SingletonContext) string { - srcPath, _ := filepath.Abs(android.PathForSource(ctx).String()) - return srcPath -} diff --git a/cc/compdb.go b/cc/compdb.go index dff14dbeb..ea124438e 100644 --- a/cc/compdb.go +++ b/cc/compdb.go @@ -79,9 +79,9 @@ func (c *compdbGeneratorSingleton) GenerateBuildActions(ctx android.SingletonCon // Create the output file. dir := android.PathForOutput(ctx, compdbOutputProjectsDirectory) - os.MkdirAll(dir.String(), 0777) + os.MkdirAll(filepath.Join(android.AbsSrcDirForExistingUseCases(), dir.String()), 0777) compDBFile := dir.Join(ctx, compdbFilename) - f, err := os.Create(compDBFile.String()) + f, err := os.Create(filepath.Join(android.AbsSrcDirForExistingUseCases(), compDBFile.String())) if err != nil { log.Fatalf("Could not create file %s: %s", compDBFile, err) } @@ -103,8 +103,8 @@ func (c *compdbGeneratorSingleton) GenerateBuildActions(ctx android.SingletonCon } f.Write(dat) - finalLinkPath := filepath.Join(ctx.Config().Getenv(envVariableCompdbLink), compdbFilename) - if finalLinkPath != "" { + if finalLinkDir := ctx.Config().Getenv(envVariableCompdbLink); finalLinkDir != "" { + finalLinkPath := filepath.Join(finalLinkDir, compdbFilename) os.Remove(finalLinkPath) if err := os.Symlink(compDBFile.String(), finalLinkPath); err != nil { log.Fatalf("Unable to symlink %s to %s: %s", compDBFile, finalLinkPath, err) @@ -174,18 +174,17 @@ func generateCompdbProject(compiledModule CompiledInterface, ctx android.Singlet return } - rootDir := getCompdbAndroidSrcRootDirectory(ctx) - pathToCC, err := ctx.Eval(pctx, rootDir+"/${config.ClangBin}/") + pathToCC, err := ctx.Eval(pctx, "${config.ClangBin}") ccPath := "/bin/false" cxxPath := "/bin/false" if err == nil { - ccPath = pathToCC + "clang" - cxxPath = pathToCC + "clang++" + ccPath = filepath.Join(pathToCC, "clang") + cxxPath = filepath.Join(pathToCC, "clang++") } for _, src := range srcs { if _, ok := builds[src.String()]; !ok { builds[src.String()] = compDbEntry{ - Directory: rootDir, + Directory: android.AbsSrcDirForExistingUseCases(), Arguments: getArguments(src, ctx, ccModule, ccPath, cxxPath), File: src.String(), } @@ -200,8 +199,3 @@ func evalAndSplitVariable(ctx android.SingletonContext, str string) ([]string, e } return []string{""}, err } - -func getCompdbAndroidSrcRootDirectory(ctx android.SingletonContext) string { - srcPath, _ := filepath.Abs(android.PathForSource(ctx).String()) - return srcPath -} diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go index b8423be1f..5744bb285 100644 --- a/cc/ndk_headers.go +++ b/cc/ndk_headers.go @@ -16,7 +16,6 @@ package cc import ( "fmt" - "os" "path/filepath" "strings" @@ -255,16 +254,8 @@ func processHeadersWithVersioner(ctx android.ModuleContext, srcDir, outDir andro depsPath := android.PathForSource(ctx, "bionic/libc/versioner-dependencies") depsGlob := ctx.Glob(filepath.Join(depsPath.String(), "**/*"), nil) for i, path := range depsGlob { - fileInfo, err := os.Lstat(path.String()) - if err != nil { - ctx.ModuleErrorf("os.Lstat(%q) failed: %s", path.String, err) - } - if fileInfo.Mode()&os.ModeSymlink == os.ModeSymlink { - dest, err := os.Readlink(path.String()) - if err != nil { - ctx.ModuleErrorf("os.Readlink(%q) failed: %s", - path.String, err) - } + if ctx.IsSymlink(path) { + dest := ctx.Readlink(path) // Additional .. to account for the symlink itself. depsGlob[i] = android.PathForSource( ctx, filepath.Clean(filepath.Join(path.String(), "..", dest))) diff --git a/dexpreopt/config.go b/dexpreopt/config.go index 0c79ccc73..2a929c536 100644 --- a/dexpreopt/config.go +++ b/dexpreopt/config.go @@ -16,7 +16,6 @@ package dexpreopt import ( "encoding/json" - "io/ioutil" "strings" "android/soong/android" @@ -185,7 +184,7 @@ func constructWritablePath(ctx android.PathContext, path string) android.Writabl // soongConfig argument. LoadGlobalConfig is used directly in Soong and in // dexpreopt_gen called from Make to read the $OUT/dexpreopt.config written by // Make. -func LoadGlobalConfig(ctx android.PathContext, path string, soongConfig GlobalSoongConfig) (GlobalConfig, []byte, error) { +func LoadGlobalConfig(ctx android.PathContext, data []byte, soongConfig GlobalSoongConfig) (GlobalConfig, error) { type GlobalJSONConfig struct { GlobalConfig @@ -196,9 +195,9 @@ func LoadGlobalConfig(ctx android.PathContext, path string, soongConfig GlobalSo } config := GlobalJSONConfig{} - data, err := loadConfig(ctx, path, &config) + err := json.Unmarshal(data, &config) if err != nil { - return config.GlobalConfig, nil, err + return config.GlobalConfig, err } // Construct paths that require a PathContext. @@ -209,13 +208,13 @@ func LoadGlobalConfig(ctx android.PathContext, path string, soongConfig GlobalSo // either CreateGlobalSoongConfig or LoadGlobalSoongConfig). config.GlobalConfig.SoongConfig = soongConfig - return config.GlobalConfig, data, nil + return config.GlobalConfig, nil } // LoadModuleConfig reads a per-module dexpreopt.config file into a ModuleConfig struct. It is not used in Soong, which // receives a ModuleConfig struct directly from java/dexpreopt.go. It is used in dexpreopt_gen called from oMake to // read the module dexpreopt.config written by Make. -func LoadModuleConfig(ctx android.PathContext, path string) (ModuleConfig, error) { +func LoadModuleConfig(ctx android.PathContext, data []byte) (ModuleConfig, error) { type ModuleJSONConfig struct { ModuleConfig @@ -233,7 +232,7 @@ func LoadModuleConfig(ctx android.PathContext, path string) (ModuleConfig, error config := ModuleJSONConfig{} - _, err := loadConfig(ctx, path, &config) + err := json.Unmarshal(data, &config) if err != nil { return config.ModuleConfig, err } @@ -289,10 +288,10 @@ type globalJsonSoongConfig struct { // LoadGlobalSoongConfig reads the dexpreopt_soong.config file into a // GlobalSoongConfig struct. It is only used in dexpreopt_gen. -func LoadGlobalSoongConfig(ctx android.PathContext, path string) (GlobalSoongConfig, error) { +func LoadGlobalSoongConfig(ctx android.PathContext, data []byte) (GlobalSoongConfig, error) { var jc globalJsonSoongConfig - _, err := loadConfig(ctx, path, &jc) + err := json.Unmarshal(data, &jc) if err != nil { return GlobalSoongConfig{}, err } @@ -352,26 +351,6 @@ func (s *globalSoongConfigSingleton) MakeVars(ctx android.MakeVarsContext) { }, " ")) } -func loadConfig(ctx android.PathContext, path string, config interface{}) ([]byte, error) { - r, err := ctx.Fs().Open(path) - if err != nil { - return nil, err - } - defer r.Close() - - data, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - - err = json.Unmarshal(data, config) - if err != nil { - return nil, err - } - - return data, nil -} - func GlobalConfigForTests(ctx android.PathContext) GlobalConfig { return GlobalConfig{ DisablePreopt: false, diff --git a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go index d2faa00de..e2818bb61 100644 --- a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go +++ b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go @@ -18,6 +18,7 @@ import ( "bytes" "flag" "fmt" + "io/ioutil" "os" "path/filepath" "runtime" @@ -41,7 +42,6 @@ type pathContext struct { config android.Config } -func (x *pathContext) Fs() pathtools.FileSystem { return pathtools.OsFs } func (x *pathContext) Config() android.Config { return x.config } func (x *pathContext) AddNinjaFileDeps(...string) {} @@ -76,21 +76,39 @@ func main() { usage("--module configuration file is required") } - ctx := &pathContext{android.TestConfig(*outDir, nil, "", nil)} + ctx := &pathContext{android.NullConfig(*outDir)} - globalSoongConfig, err := dexpreopt.LoadGlobalSoongConfig(ctx, *globalSoongConfigPath) + globalSoongConfigData, err := ioutil.ReadFile(*globalSoongConfigPath) + if err != nil { + fmt.Fprintf(os.Stderr, "error reading global config %q: %s\n", *globalSoongConfigPath, err) + os.Exit(2) + } + + globalSoongConfig, err := dexpreopt.LoadGlobalSoongConfig(ctx, globalSoongConfigData) if err != nil { fmt.Fprintf(os.Stderr, "error loading global config %q: %s\n", *globalSoongConfigPath, err) os.Exit(2) } - globalConfig, _, err := dexpreopt.LoadGlobalConfig(ctx, *globalConfigPath, globalSoongConfig) + globalConfigData, err := ioutil.ReadFile(*globalConfigPath) if err != nil { - fmt.Fprintf(os.Stderr, "error loading global config %q: %s\n", *globalConfigPath, err) + fmt.Fprintf(os.Stderr, "error reading global config %q: %s\n", *globalConfigPath, err) os.Exit(2) } - moduleConfig, err := dexpreopt.LoadModuleConfig(ctx, *moduleConfigPath) + globalConfig, err := dexpreopt.LoadGlobalConfig(ctx, globalConfigData, globalSoongConfig) + if err != nil { + fmt.Fprintf(os.Stderr, "error parse global config %q: %s\n", *globalConfigPath, err) + os.Exit(2) + } + + moduleConfigData, err := ioutil.ReadFile(*moduleConfigPath) + if err != nil { + fmt.Fprintf(os.Stderr, "error reading module config %q: %s\n", *moduleConfigPath, err) + os.Exit(2) + } + + moduleConfig, err := dexpreopt.LoadModuleConfig(ctx, moduleConfigData) if err != nil { fmt.Fprintf(os.Stderr, "error loading module config %q: %s\n", *moduleConfigPath, err) os.Exit(2) diff --git a/env/env.go b/env/env.go index bf58a9914..a98e1f6a8 100644 --- a/env/env.go +++ b/env/env.go @@ -27,7 +27,7 @@ import ( type envFileEntry struct{ Key, Value string } type envFileData []envFileEntry -func WriteEnvFile(filename string, envDeps map[string]string) error { +func EnvFileContents(envDeps map[string]string) ([]byte, error) { contents := make(envFileData, 0, len(envDeps)) for key, value := range envDeps { contents = append(contents, envFileEntry{key, value}) @@ -37,17 +37,12 @@ func WriteEnvFile(filename string, envDeps map[string]string) error { data, err := json.MarshalIndent(contents, "", " ") if err != nil { - return err + return nil, err } data = append(data, '\n') - err = ioutil.WriteFile(filename, data, 0664) - if err != nil { - return err - } - - return nil + return data, nil } func StaleEnvFile(filename string) (bool, error) { diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go index 35748b8d1..f3191e741 100644 --- a/java/dexpreopt_config.go +++ b/java/dexpreopt_config.go @@ -36,10 +36,11 @@ type globalConfigAndRaw struct { func dexpreoptGlobalConfigRaw(ctx android.PathContext) globalConfigAndRaw { return ctx.Config().Once(dexpreoptGlobalConfigKey, func() interface{} { - if f := ctx.Config().DexpreoptGlobalConfig(); f != "" { + if data, err := ctx.Config().DexpreoptGlobalConfig(ctx); err != nil { + panic(err) + } else if data != nil { soongConfig := dexpreopt.CreateGlobalSoongConfig(ctx) - ctx.AddNinjaFileDeps(f) - globalConfig, data, err := dexpreopt.LoadGlobalConfig(ctx, f, soongConfig) + globalConfig, err := dexpreopt.LoadGlobalConfig(ctx, data, soongConfig) if err != nil { panic(err) } diff --git a/java/jdeps.go b/java/jdeps.go index fccc40fa8..49e3de3cc 100644 --- a/java/jdeps.go +++ b/java/jdeps.go @@ -17,7 +17,6 @@ package java import ( "encoding/json" "fmt" - "os" "android/soong/android" ) @@ -92,23 +91,21 @@ func (j *jdepsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonCont moduleInfos[name] = dpInfo }) - jfpath := android.PathForOutput(ctx, jdepsJsonFileName).String() + jfpath := android.PathForOutput(ctx, jdepsJsonFileName) err := createJsonFile(moduleInfos, jfpath) if err != nil { ctx.Errorf(err.Error()) } } -func createJsonFile(moduleInfos map[string]android.IdeInfo, jfpath string) error { - file, err := os.Create(jfpath) - if err != nil { - return fmt.Errorf("Failed to create file: %s, relative: %v", jdepsJsonFileName, err) - } - defer file.Close() +func createJsonFile(moduleInfos map[string]android.IdeInfo, jfpath android.WritablePath) error { buf, err := json.MarshalIndent(moduleInfos, "", "\t") if err != nil { - return fmt.Errorf("Write file failed: %s, relative: %v", jdepsJsonFileName, err) + return fmt.Errorf("JSON marshal of java deps failed: %s", err) + } + err = android.WriteFileToOutputDir(jfpath, buf, 0666) + if err != nil { + return fmt.Errorf("Writing java deps to %s failed: %s", jfpath.String(), err) } - fmt.Fprintf(file, string(buf)) return nil } diff --git a/ui/build/soong.go b/ui/build/soong.go index 338841702..afbc0734b 100644 --- a/ui/build/soong.go +++ b/ui/build/soong.go @@ -119,6 +119,7 @@ func runSoong(ctx Context, config Config) { "-j", strconv.Itoa(config.Parallel()), "--frontend_file", fifo, "-f", filepath.Join(config.SoongOutDir(), file)) + cmd.Environment.Set("SOONG_SANDBOX_SOONG_BUILD", "true") cmd.Sandbox = soongSandbox cmd.RunAndStreamOrFatal() }