diff --git a/dexpreopt/config.go b/dexpreopt/config.go index 3ab341438..98850e51a 100644 --- a/dexpreopt/config.go +++ b/dexpreopt/config.go @@ -317,32 +317,11 @@ var dex2oatDepTag = struct { blueprint.BaseDependencyTag }{} -type DexPreoptModule interface { - dexPreoptModuleSignature() // Not called - only for type detection. -} - -// RegisterToolDepsMutator registers a mutator that adds the necessary -// dependencies to binary modules for tools that are required later when -// Get(Cached)GlobalSoongConfig is called. It should be passed to -// android.RegistrationContext.FinalDepsMutators, and module types that need -// dependencies also need to embed DexPreoptModule. -func RegisterToolDepsMutator(ctx android.RegisterMutatorsContext) { - ctx.BottomUp("dexpreopt_tool_deps", toolDepsMutator).Parallel() -} - -func toolDepsMutator(ctx android.BottomUpMutatorContext) { - if GetGlobalConfig(ctx).DisablePreopt { - // Only register dependencies if dexpreopting is enabled. Necessary to avoid - // them in non-platform builds where dex2oat etc isn't available. - // - // It would be nice to not register this mutator at all then, but - // RegisterMutatorsContext available at registration doesn't have the state - // necessary to pass as PathContext to constructPath etc. - return - } - if _, ok := ctx.Module().(DexPreoptModule); !ok { - return - } +// RegisterToolDeps adds the necessary dependencies to binary modules for tools +// that are required later when Get(Cached)GlobalSoongConfig is called. It +// should be called from a mutator that's registered with +// android.RegistrationContext.FinalDepsMutators. +func RegisterToolDeps(ctx android.BottomUpMutatorContext) { dex2oatBin := dex2oatModuleName(ctx.Config()) v := ctx.Config().BuildOSTarget.Variations() ctx.AddFarVariationDependencies(v, dex2oatDepTag, dex2oatBin) @@ -418,10 +397,13 @@ func GetGlobalSoongConfig(ctx android.ModuleContext) *GlobalSoongConfig { // GetCachedGlobalSoongConfig returns a cached GlobalSoongConfig created by an // earlier GetGlobalSoongConfig call. This function works with any context // compatible with a basic PathContext, since it doesn't try to create a -// GlobalSoongConfig (which requires a full ModuleContext). It will panic if -// called before the first GetGlobalSoongConfig call. +// GlobalSoongConfig with the proper paths (which requires a full +// ModuleContext). If there has been no prior call to GetGlobalSoongConfig, nil +// is returned. func GetCachedGlobalSoongConfig(ctx android.PathContext) *GlobalSoongConfig { - return ctx.Config().Get(globalSoongConfigOnceKey).(*GlobalSoongConfig) + return ctx.Config().Once(globalSoongConfigOnceKey, func() interface{} { + return (*GlobalSoongConfig)(nil) + }).(*GlobalSoongConfig) } type globalJsonSoongConfig struct { @@ -464,6 +446,12 @@ func (s *globalSoongConfigSingleton) GenerateBuildActions(ctx android.SingletonC } config := GetCachedGlobalSoongConfig(ctx) + if config == nil { + // No module has enabled dexpreopting, so we assume there will be no calls + // to dexpreopt_gen. + return + } + jc := globalJsonSoongConfig{ Profman: config.Profman.String(), Dex2oat: config.Dex2oat.String(), @@ -495,6 +483,9 @@ func (s *globalSoongConfigSingleton) MakeVars(ctx android.MakeVarsContext) { } config := GetCachedGlobalSoongConfig(ctx) + if config == nil { + return + } ctx.Strict("DEX2OAT", config.Dex2oat.String()) ctx.Strict("DEXPREOPT_GEN_DEPS", strings.Join([]string{ diff --git a/java/app.go b/java/app.go index f55fc45a1..02f3e7fc0 100755 --- a/java/app.go +++ b/java/app.go @@ -27,7 +27,6 @@ import ( "android/soong/android" "android/soong/cc" - "android/soong/dexpreopt" "android/soong/tradefed" ) @@ -143,6 +142,10 @@ type AndroidApp struct { noticeOutputs android.NoticeOutputs } +func (a *AndroidApp) IsInstallable() bool { + return Bool(a.properties.Installable) +} + func (a *AndroidApp) ExportedProguardFlagFiles() android.Paths { return nil } @@ -339,7 +342,6 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path { installDir = filepath.Join("app", a.installApkName) } a.dexpreopter.installPath = android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk") - a.dexpreopter.isInstallable = Bool(a.properties.Installable) a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx) a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries() @@ -876,7 +878,6 @@ type AndroidAppImport struct { android.ModuleBase android.DefaultableModuleBase prebuilt android.Prebuilt - dexpreopt.DexPreoptModule properties AndroidAppImportProperties dpiVariants interface{} @@ -924,6 +925,10 @@ type AndroidAppImportProperties struct { Filename *string } +func (a *AndroidAppImport) IsInstallable() bool { + return true +} + // Updates properties with variant-specific values. func (a *AndroidAppImport) processVariants(ctx android.LoadHookContext) { config := ctx.Config() @@ -1066,7 +1071,6 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext } a.dexpreopter.installPath = installDir.Join(ctx, a.BaseModuleName()+".apk") - a.dexpreopter.isInstallable = true a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned) a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx) diff --git a/java/dexpreopt.go b/java/dexpreopt.go index 2b87cf797..4313964aa 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -19,6 +19,11 @@ import ( "android/soong/dexpreopt" ) +type dexpreopterInterface interface { + IsInstallable() bool // Structs that embed dexpreopter must implement this. + dexpreoptDisabled(ctx android.BaseModuleContext) bool +} + type dexpreopter struct { dexpreoptProperties DexpreoptProperties @@ -26,7 +31,6 @@ type dexpreopter struct { uncompressedDex bool isSDKLibrary bool isTest bool - isInstallable bool isPresignedPrebuilt bool manifestFile android.Path @@ -58,7 +62,7 @@ type DexpreoptProperties struct { } } -func (d *dexpreopter) dexpreoptDisabled(ctx android.ModuleContext) bool { +func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool { global := dexpreopt.GetGlobalConfig(ctx) if global.DisablePreopt { @@ -81,7 +85,11 @@ func (d *dexpreopter) dexpreoptDisabled(ctx android.ModuleContext) bool { return true } - if !d.isInstallable { + if !ctx.Module().(dexpreopterInterface).IsInstallable() { + return true + } + + if ctx.Host() { return true } @@ -95,12 +103,23 @@ func (d *dexpreopter) dexpreoptDisabled(ctx android.ModuleContext) bool { return false } +func dexpreoptToolDepsMutator(ctx android.BottomUpMutatorContext) { + if d, ok := ctx.Module().(dexpreopterInterface); !ok || d.dexpreoptDisabled(ctx) { + return + } + dexpreopt.RegisterToolDeps(ctx) +} + func odexOnSystemOther(ctx android.ModuleContext, installPath android.InstallPath) bool { return dexpreopt.OdexOnSystemOtherByName(ctx.ModuleName(), android.InstallPathToOnDevicePath(ctx, installPath), dexpreopt.GetGlobalConfig(ctx)) } func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.ModuleOutPath) android.ModuleOutPath { - if d.dexpreoptDisabled(ctx) { + // TODO(b/148690468): The check on d.installPath is to bail out in cases where + // the dexpreopter struct hasn't been fully initialized before we're called, + // e.g. in aar.go. This keeps the behaviour that dexpreopting is effectively + // disabled, even if installable is true. + if d.dexpreoptDisabled(ctx) || d.installPath.Base() == "." { return dexJarFile } diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 2a2e6dae5..655a47644 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -205,6 +205,10 @@ func (d *dexpreoptBootJars) GenerateBuildActions(ctx android.SingletonContext) { if skipDexpreoptBootJars(ctx) { return } + if dexpreopt.GetCachedGlobalSoongConfig(ctx) == nil { + // No module has enabled dexpreopting, so we assume there will be no boot image to make. + return + } d.dexpreoptConfigForMake = android.PathForOutput(ctx, ctx.Config().DeviceName(), "dexpreopt.config") writeGlobalConfigForMake(ctx, d.dexpreoptConfigForMake) diff --git a/java/java.go b/java/java.go index 2e53654cc..ceedd8971 100644 --- a/java/java.go +++ b/java/java.go @@ -76,7 +76,9 @@ func RegisterJavaBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("java_host_for_device", HostForDeviceFactory) ctx.RegisterModuleType("dex_import", DexImportFactory) - ctx.FinalDepsMutators(dexpreopt.RegisterToolDepsMutator) + ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("dexpreopt_tool_deps", dexpreoptToolDepsMutator).Parallel() + }) ctx.RegisterSingletonType("logtags", LogtagsSingleton) ctx.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory) @@ -371,7 +373,6 @@ type Module struct { android.DefaultableModuleBase android.ApexModuleBase android.SdkBase - dexpreopt.DexPreoptModule properties CompilerProperties protoProperties android.ProtoProperties @@ -1577,16 +1578,6 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { } } else { outputFile = implementationAndResourcesJar - - // dexpreopt.GetGlobalSoongConfig needs to be called at least once even if - // no module actually is dexpreopted, to ensure there's a cached - // GlobalSoongConfig for the dexpreopt singletons, which will run - // regardless. - // TODO(b/147613152): Remove when the singletons no longer rely on the - // cached GlobalSoongConfig. - if !dexpreopt.GetGlobalConfig(ctx).DisablePreopt { - _ = dexpreopt.GetGlobalSoongConfig(ctx) - } } ctx.CheckbuildFile(outputFile) @@ -1794,6 +1785,10 @@ func (j *Module) JacocoReportClassesFile() android.Path { return j.jacocoReportClassesFile } +func (j *Module) IsInstallable() bool { + return Bool(j.properties.Installable) +} + // // Java libraries (.jar file) // @@ -1831,7 +1826,6 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.checkSdkVersion(ctx) j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar") j.dexpreopter.isSDKLibrary = j.deviceProperties.IsSDKLibrary - j.dexpreopter.isInstallable = Bool(j.properties.Installable) j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter) j.deviceProperties.UncompressDex = j.dexpreopter.uncompressedDex j.compile(ctx, nil) @@ -2353,7 +2347,6 @@ type Import struct { android.ApexModuleBase prebuilt android.Prebuilt android.SdkBase - dexpreopt.DexPreoptModule properties ImportProperties @@ -2564,7 +2557,6 @@ type DexImport struct { android.DefaultableModuleBase android.ApexModuleBase prebuilt android.Prebuilt - dexpreopt.DexPreoptModule properties DexImportProperties @@ -2590,13 +2582,16 @@ func (j *DexImport) Stem() string { return proptools.StringDefault(j.properties.Stem, j.ModuleBase.Name()) } +func (j *DexImport) IsInstallable() bool { + return true +} + func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { if len(j.properties.Jars) != 1 { ctx.PropertyErrorf("jars", "exactly one jar must be provided") } j.dexpreopter.installPath = android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar") - j.dexpreopter.isInstallable = true j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, &j.dexpreopter) inputJar := ctx.ExpandSource(j.properties.Jars[0], "jars")