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() }