diff --git a/dexpreopt/config.go b/dexpreopt/config.go index 83e367371..0c79ccc73 100644 --- a/dexpreopt/config.go +++ b/dexpreopt/config.go @@ -22,7 +22,9 @@ import ( "android/soong/android" ) -// GlobalConfig stores the configuration for dex preopting set by the product +// GlobalConfig stores the configuration for dex preopting. The fields are set +// from product variables via dex_preopt_config.mk, except for SoongConfig +// which come from CreateGlobalSoongConfig. type GlobalConfig struct { DisablePreopt bool // disable preopt for all modules DisablePreoptModules []string // modules with preopt disabled by product-specific config @@ -82,19 +84,19 @@ type GlobalConfig struct { Dex2oatImageXmx string // max heap size for dex2oat for the boot image Dex2oatImageXms string // initial heap size for dex2oat for the boot image - Tools Tools // paths to tools possibly used by the generated commands + SoongConfig GlobalSoongConfig // settings read from dexpreopt_soong.config } -// Tools contains paths to tools possibly used by the generated commands. If you add a new tool here you MUST add it -// to the order-only dependency list in DEXPREOPT_GEN_DEPS. -type Tools struct { - Profman android.Path - Dex2oat android.Path - Aapt android.Path - SoongZip android.Path - Zip2zip android.Path - ManifestCheck android.Path - +// GlobalSoongConfig contains the global config that is generated from Soong, +// stored in dexpreopt_soong.config. +type GlobalSoongConfig struct { + // Paths to tools possibly used by the generated commands. + Profman android.Path + Dex2oat android.Path + Aapt android.Path + SoongZip android.Path + Zip2zip android.Path + ManifestCheck android.Path ConstructContext android.Path } @@ -133,6 +135,17 @@ type ModuleConfig struct { PresignedPrebuilt bool } +type globalSoongConfigSingleton struct{} + +var pctx = android.NewPackageContext("android/soong/dexpreopt") + +func init() { + pctx.Import("android/soong/android") + android.RegisterSingletonType("dexpreopt-soong-config", func() android.Singleton { + return &globalSoongConfigSingleton{} + }) +} + func constructPath(ctx android.PathContext, path string) android.Path { buildDirPrefix := ctx.Config().BuildDir() + "/" if path == "" { @@ -167,9 +180,12 @@ func constructWritablePath(ctx android.PathContext, path string) android.Writabl return constructPath(ctx, path).(android.WritablePath) } -// LoadGlobalConfig reads the global dexpreopt.config file into a GlobalConfig struct. It 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) (GlobalConfig, []byte, error) { +// LoadGlobalConfig reads the global dexpreopt.config file into a GlobalConfig +// struct, except the SoongConfig field which is set from the provided +// 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) { type GlobalJSONConfig struct { GlobalConfig @@ -177,17 +193,6 @@ func LoadGlobalConfig(ctx android.PathContext, path string) (GlobalConfig, []byt // used to construct the real value manually below. DirtyImageObjects string BootImageProfiles []string - - Tools struct { - Profman string - Dex2oat string - Aapt string - SoongZip string - Zip2zip string - ManifestCheck string - - ConstructContext string - } } config := GlobalJSONConfig{} @@ -200,13 +205,9 @@ func LoadGlobalConfig(ctx android.PathContext, path string) (GlobalConfig, []byt config.GlobalConfig.DirtyImageObjects = android.OptionalPathForPath(constructPath(ctx, config.DirtyImageObjects)) config.GlobalConfig.BootImageProfiles = constructPaths(ctx, config.BootImageProfiles) - config.GlobalConfig.Tools.Profman = constructPath(ctx, config.Tools.Profman) - config.GlobalConfig.Tools.Dex2oat = constructPath(ctx, config.Tools.Dex2oat) - config.GlobalConfig.Tools.Aapt = constructPath(ctx, config.Tools.Aapt) - config.GlobalConfig.Tools.SoongZip = constructPath(ctx, config.Tools.SoongZip) - config.GlobalConfig.Tools.Zip2zip = constructPath(ctx, config.Tools.Zip2zip) - config.GlobalConfig.Tools.ManifestCheck = constructPath(ctx, config.Tools.ManifestCheck) - config.GlobalConfig.Tools.ConstructContext = constructPath(ctx, config.Tools.ConstructContext) + // Set this here to force the caller to provide a value for this struct (from + // either CreateGlobalSoongConfig or LoadGlobalSoongConfig). + config.GlobalConfig.SoongConfig = soongConfig return config.GlobalConfig, data, nil } @@ -253,6 +254,104 @@ func LoadModuleConfig(ctx android.PathContext, path string) (ModuleConfig, error return config.ModuleConfig, nil } +// CreateGlobalSoongConfig creates a GlobalSoongConfig from the current context. +// Should not be used in dexpreopt_gen. +func CreateGlobalSoongConfig(ctx android.PathContext) GlobalSoongConfig { + // Default to debug version to help find bugs. + // Set USE_DEX2OAT_DEBUG to false for only building non-debug versions. + var dex2oatBinary string + if ctx.Config().Getenv("USE_DEX2OAT_DEBUG") == "false" { + dex2oatBinary = "dex2oat" + } else { + dex2oatBinary = "dex2oatd" + } + + return GlobalSoongConfig{ + Profman: ctx.Config().HostToolPath(ctx, "profman"), + Dex2oat: ctx.Config().HostToolPath(ctx, dex2oatBinary), + Aapt: ctx.Config().HostToolPath(ctx, "aapt"), + SoongZip: ctx.Config().HostToolPath(ctx, "soong_zip"), + Zip2zip: ctx.Config().HostToolPath(ctx, "zip2zip"), + ManifestCheck: ctx.Config().HostToolPath(ctx, "manifest_check"), + ConstructContext: android.PathForSource(ctx, "build/make/core/construct_context.sh"), + } +} + +type globalJsonSoongConfig struct { + Profman string + Dex2oat string + Aapt string + SoongZip string + Zip2zip string + ManifestCheck string + ConstructContext string +} + +// 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) { + var jc globalJsonSoongConfig + + _, err := loadConfig(ctx, path, &jc) + if err != nil { + return GlobalSoongConfig{}, err + } + + config := GlobalSoongConfig{ + Profman: constructPath(ctx, jc.Profman), + Dex2oat: constructPath(ctx, jc.Dex2oat), + Aapt: constructPath(ctx, jc.Aapt), + SoongZip: constructPath(ctx, jc.SoongZip), + Zip2zip: constructPath(ctx, jc.Zip2zip), + ManifestCheck: constructPath(ctx, jc.ManifestCheck), + ConstructContext: constructPath(ctx, jc.ConstructContext), + } + + return config, nil +} + +func (s *globalSoongConfigSingleton) GenerateBuildActions(ctx android.SingletonContext) { + config := CreateGlobalSoongConfig(ctx) + jc := globalJsonSoongConfig{ + Profman: config.Profman.String(), + Dex2oat: config.Dex2oat.String(), + Aapt: config.Aapt.String(), + SoongZip: config.SoongZip.String(), + Zip2zip: config.Zip2zip.String(), + ManifestCheck: config.ManifestCheck.String(), + ConstructContext: config.ConstructContext.String(), + } + + data, err := json.Marshal(jc) + if err != nil { + ctx.Errorf("failed to JSON marshal GlobalSoongConfig: %v", err) + return + } + + ctx.Build(pctx, android.BuildParams{ + Rule: android.WriteFile, + Output: android.PathForOutput(ctx, "dexpreopt_soong.config"), + Args: map[string]string{ + "content": string(data), + }, + }) +} + +func (s *globalSoongConfigSingleton) MakeVars(ctx android.MakeVarsContext) { + config := CreateGlobalSoongConfig(ctx) + + ctx.Strict("DEX2OAT", config.Dex2oat.String()) + ctx.Strict("DEXPREOPT_GEN_DEPS", strings.Join([]string{ + config.Profman.String(), + config.Dex2oat.String(), + config.Aapt.String(), + config.SoongZip.String(), + config.Zip2zip.String(), + config.ManifestCheck.String(), + config.ConstructContext.String(), + }, " ")) +} + func loadConfig(ctx android.PathContext, path string, config interface{}) ([]byte, error) { r, err := ctx.Fs().Open(path) if err != nil { @@ -312,7 +411,7 @@ func GlobalConfigForTests(ctx android.PathContext) GlobalConfig { BootFlags: "", Dex2oatImageXmx: "", Dex2oatImageXms: "", - Tools: Tools{ + SoongConfig: GlobalSoongConfig{ Profman: android.PathForTesting("profman"), Dex2oat: android.PathForTesting("dex2oat"), Aapt: android.PathForTesting("aapt"), diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go index ee04dfd6d..ac5b691c1 100644 --- a/dexpreopt/dexpreopt.go +++ b/dexpreopt/dexpreopt.go @@ -131,7 +131,7 @@ func profileCommand(ctx android.PathContext, global GlobalConfig, module ModuleC cmd := rule.Command(). Text(`ANDROID_LOG_TAGS="*:e"`). - Tool(global.Tools.Profman) + Tool(global.SoongConfig.Profman) if module.ProfileIsTextListing { // The profile is a test listing of classes (used for framework jars). @@ -170,7 +170,7 @@ func bootProfileCommand(ctx android.PathContext, global GlobalConfig, module Mod cmd := rule.Command(). Text(`ANDROID_LOG_TAGS="*:e"`). - Tool(global.Tools.Profman) + Tool(global.SoongConfig.Profman) // The profile is a test listing of methods. // We need to generate the actual binary profile. @@ -299,14 +299,14 @@ func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module Modul if module.EnforceUsesLibraries { if module.ManifestPath != nil { rule.Command().Text(`target_sdk_version="$(`). - Tool(global.Tools.ManifestCheck). + Tool(global.SoongConfig.ManifestCheck). Flag("--extract-target-sdk-version"). Input(module.ManifestPath). Text(`)"`) } else { // No manifest to extract targetSdkVersion from, hope that DexJar is an APK rule.Command().Text(`target_sdk_version="$(`). - Tool(global.Tools.Aapt). + Tool(global.SoongConfig.Aapt). Flag("dump badging"). Input(module.DexPath). Text(`| grep "targetSdkVersion" | sed -n "s/targetSdkVersion:'\(.*\)'/\1/p"`). @@ -327,7 +327,7 @@ func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module Modul Implicits(conditionalClassLoaderContextHost29) rule.Command().Textf(`conditional_target_libs_29="%s"`, strings.Join(conditionalClassLoaderContextTarget29, " ")) - rule.Command().Text("source").Tool(global.Tools.ConstructContext).Input(module.DexPath) + rule.Command().Text("source").Tool(global.SoongConfig.ConstructContext).Input(module.DexPath) } // Devices that do not have a product partition use a symlink from /product to /system/product. @@ -340,7 +340,7 @@ func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module Modul cmd := rule.Command(). Text(`ANDROID_LOG_TAGS="*:e"`). - Tool(global.Tools.Dex2oat). + Tool(global.SoongConfig.Dex2oat). Flag("--avoid-storing-invocation"). FlagWithOutput("--write-invocation-to=", invocationPath).ImplicitOutput(invocationPath). Flag("--runtime-arg").FlagWithArg("-Xms", global.Dex2oatXms). @@ -409,7 +409,7 @@ func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module Modul dmInstalledPath := pathtools.ReplaceExtension(module.DexLocation, "dm") tmpPath := module.BuildPath.InSameDir(ctx, "primary.vdex") rule.Command().Text("cp -f").Input(vdexPath).Output(tmpPath) - rule.Command().Tool(global.Tools.SoongZip). + rule.Command().Tool(global.SoongConfig.SoongZip). FlagWithArg("-L", "9"). FlagWithOutput("-o", dmPath). Flag("-j"). diff --git a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go index 6f5108010..d2faa00de 100644 --- a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go +++ b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go @@ -30,10 +30,11 @@ import ( ) var ( - dexpreoptScriptPath = flag.String("dexpreopt_script", "", "path to output dexpreopt script") - globalConfigPath = flag.String("global", "", "path to global configuration file") - moduleConfigPath = flag.String("module", "", "path to module configuration file") - outDir = flag.String("out_dir", "", "path to output directory") + dexpreoptScriptPath = flag.String("dexpreopt_script", "", "path to output dexpreopt script") + globalSoongConfigPath = flag.String("global_soong", "", "path to global configuration file for settings originating from Soong") + globalConfigPath = flag.String("global", "", "path to global configuration file") + moduleConfigPath = flag.String("module", "", "path to module configuration file") + outDir = flag.String("out_dir", "", "path to output directory") ) type pathContext struct { @@ -63,17 +64,27 @@ func main() { usage("path to output dexpreopt script is required") } + if *globalSoongConfigPath == "" { + usage("--global_soong configuration file is required") + } + if *globalConfigPath == "" { - usage("path to global configuration file is required") + usage("--global configuration file is required") } if *moduleConfigPath == "" { - usage("path to module configuration file is required") + usage("--module configuration file is required") } ctx := &pathContext{android.TestConfig(*outDir, nil, "", nil)} - globalConfig, _, err := dexpreopt.LoadGlobalConfig(ctx, *globalConfigPath) + globalSoongConfig, err := dexpreopt.LoadGlobalSoongConfig(ctx, *globalSoongConfigPath) + 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) if err != nil { fmt.Fprintf(os.Stderr, "error loading global config %q: %s\n", *globalConfigPath, err) os.Exit(2) @@ -121,7 +132,7 @@ func writeScripts(ctx android.PathContext, global dexpreopt.GlobalConfig, module dexpreoptRule.Command().Text("mkdir -p").Flag(filepath.Dir(installPath.String())) dexpreoptRule.Command().Text("cp -f").Input(install.From).Output(installPath) } - dexpreoptRule.Command().Tool(global.Tools.SoongZip). + dexpreoptRule.Command().Tool(global.SoongConfig.SoongZip). FlagWithArg("-o ", "$2"). FlagWithArg("-C ", installDir.String()). FlagWithArg("-D ", installDir.String()) diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 830825427..11aa27112 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -335,7 +335,7 @@ func buildBootImageRuleForArch(ctx android.SingletonContext, image *bootImage, invocationPath := outputPath.ReplaceExtension(ctx, "invocation") - cmd.Tool(global.Tools.Dex2oat). + cmd.Tool(global.SoongConfig.Dex2oat). Flag("--avoid-storing-invocation"). FlagWithOutput("--write-invocation-to=", invocationPath).ImplicitOutput(invocationPath). Flag("--runtime-arg").FlagWithArg("-Xms", global.Dex2oatImageXms). @@ -444,7 +444,6 @@ func bootImageProfileRule(ctx android.SingletonContext, image *bootImage, missin return nil } profile := ctx.Config().Once(bootImageProfileRuleKey, func() interface{} { - tools := global.Tools defaultProfile := "frameworks/base/config/boot-image-profile.txt" rule := android.NewRuleBuilder() @@ -470,7 +469,7 @@ func bootImageProfileRule(ctx android.SingletonContext, image *bootImage, missin rule.Command(). Text(`ANDROID_LOG_TAGS="*:e"`). - Tool(tools.Profman). + Tool(global.SoongConfig.Profman). FlagWithInput("--create-profile-from=", bootImageProfile). FlagForEachInput("--apk=", image.dexPathsDeps.Paths()). FlagForEachArg("--dex-location=", image.dexLocationsDeps). @@ -499,8 +498,6 @@ func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImage, mi return nil } return ctx.Config().Once(bootFrameworkProfileRuleKey, func() interface{} { - tools := global.Tools - rule := android.NewRuleBuilder() rule.MissingDeps(missingDeps) @@ -521,7 +518,7 @@ func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImage, mi rule.Command(). Text(`ANDROID_LOG_TAGS="*:e"`). - Tool(tools.Profman). + Tool(global.SoongConfig.Profman). Flag("--generate-boot-profile"). FlagWithInput("--create-profile-from=", bootFrameworkProfile). FlagForEachInput("--apk=", image.dexPathsDeps.Paths()). @@ -598,6 +595,7 @@ func writeGlobalConfigForMake(ctx android.SingletonContext, path android.Writabl func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) { if d.dexpreoptConfigForMake != nil { ctx.Strict("DEX_PREOPT_CONFIG_FOR_MAKE", d.dexpreoptConfigForMake.String()) + ctx.Strict("DEX_PREOPT_SOONG_CONFIG_FOR_MAKE", android.PathForOutput(ctx, "dexpreopt_soong.config").String()) } image := d.defaultBootImage diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go index 91e0dfbdd..b3af911fb 100644 --- a/java/dexpreopt_config.go +++ b/java/dexpreopt_config.go @@ -37,8 +37,9 @@ type globalConfigAndRaw struct { func dexpreoptGlobalConfigRaw(ctx android.PathContext) globalConfigAndRaw { return ctx.Config().Once(dexpreoptGlobalConfigKey, func() interface{} { if f := ctx.Config().DexpreoptGlobalConfig(); f != "" { + soongConfig := dexpreopt.CreateGlobalSoongConfig(ctx) ctx.AddNinjaFileDeps(f) - globalConfig, data, err := dexpreopt.LoadGlobalConfig(ctx, f) + globalConfig, data, err := dexpreopt.LoadGlobalConfig(ctx, f, soongConfig) if err != nil { panic(err) }