Reland: Get the dex2oat host tool path from module dependency on the
binary module. This uses the Once cache for GlobalSoongConfig to propagate the dex2oat path from a module dependency to the singletons (both the one that writes out dexpreopt_soong.config and the one that creates the dexpreopted boot images). Unless dexpreopting is disabled altogether through DisablePreopt in dexpreopt.config, that means: - We must ensure at least one module registers a dex2oat tool dependency and resolves a GlobalSoongConfig using it, or else the singletons fail. That means we litter dex2oat dependencies in java modules even when they won't get dexpreopted and hence don't really need them. - We still assume there's at least one java_library or android_app in the build. This relands https://r.android.com/1205730 without changes - the necessary fixes are in the child CLs. Bug: 145934348 Test: m (check that out/soong/dexpreopt_soong.config points to dex2oatd64) Test: env USE_DEX2OAT_DEBUG=false m (check that out/soong/dexpreopt_soong.config points to dex2oat64) Test: env OUT_DIR=out-tools prebuilts/build-tools/build-prebuilts.sh on the aosp-build-tools branch Change-Id: I66661711b317d1e4ec434861982919bdde19b575
This commit is contained in:
@@ -4,6 +4,7 @@ bootstrap_go_package {
|
||||
srcs: [
|
||||
"config.go",
|
||||
"dexpreopt.go",
|
||||
"testing.go",
|
||||
],
|
||||
testSrcs: [
|
||||
"dexpreopt_test.go",
|
||||
|
@@ -16,8 +16,11 @@ package dexpreopt
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/google/blueprint"
|
||||
|
||||
"android/soong/android"
|
||||
)
|
||||
|
||||
@@ -297,6 +300,71 @@ func ParseModuleConfig(ctx android.PathContext, data []byte) (ModuleConfig, erro
|
||||
return config.ModuleConfig, nil
|
||||
}
|
||||
|
||||
// dex2oatModuleName returns the name of the module to use for the dex2oat host
|
||||
// tool. It should be a binary module with public visibility that is compiled
|
||||
// and installed for host.
|
||||
func dex2oatModuleName(config android.Config) string {
|
||||
// Default to the debug variant of dex2oat to help find bugs.
|
||||
// Set USE_DEX2OAT_DEBUG to false for only building non-debug versions.
|
||||
if config.Getenv("USE_DEX2OAT_DEBUG") == "false" {
|
||||
return "dex2oat"
|
||||
} else {
|
||||
return "dex2oatd"
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
dex2oatBin := dex2oatModuleName(ctx.Config())
|
||||
v := ctx.Config().BuildOSTarget.Variations()
|
||||
ctx.AddFarVariationDependencies(v, dex2oatDepTag, dex2oatBin)
|
||||
}
|
||||
|
||||
func dex2oatPathFromDep(ctx android.ModuleContext) android.Path {
|
||||
dex2oatBin := dex2oatModuleName(ctx.Config())
|
||||
|
||||
dex2oatModule := ctx.GetDirectDepWithTag(dex2oatBin, dex2oatDepTag)
|
||||
if dex2oatModule == nil {
|
||||
// If this happens there's probably a missing call to AddToolDeps in DepsMutator.
|
||||
panic(fmt.Sprintf("Failed to lookup %s dependency", dex2oatBin))
|
||||
}
|
||||
|
||||
dex2oatPath := dex2oatModule.(android.HostToolProvider).HostToolPath()
|
||||
if !dex2oatPath.Valid() {
|
||||
panic(fmt.Sprintf("Failed to find host tool path in %s", dex2oatModule))
|
||||
}
|
||||
|
||||
return dex2oatPath.Path()
|
||||
}
|
||||
|
||||
// createGlobalSoongConfig creates a GlobalSoongConfig from the current context.
|
||||
// Should not be used in dexpreopt_gen.
|
||||
func createGlobalSoongConfig(ctx android.ModuleContext) GlobalSoongConfig {
|
||||
@@ -307,18 +375,9 @@ func createGlobalSoongConfig(ctx android.ModuleContext) GlobalSoongConfig {
|
||||
panic("This should not be called from tests. Please call GlobalSoongConfigForTests somewhere in the test setup.")
|
||||
}
|
||||
|
||||
// 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),
|
||||
Dex2oat: dex2oatPathFromDep(ctx),
|
||||
Aapt: ctx.Config().HostToolPath(ctx, "aapt"),
|
||||
SoongZip: ctx.Config().HostToolPath(ctx, "soong_zip"),
|
||||
Zip2zip: ctx.Config().HostToolPath(ctx, "zip2zip"),
|
||||
@@ -327,6 +386,16 @@ func createGlobalSoongConfig(ctx android.ModuleContext) GlobalSoongConfig {
|
||||
}
|
||||
}
|
||||
|
||||
// The main reason for this Once cache for GlobalSoongConfig is to make the
|
||||
// dex2oat path available to singletons. In ordinary modules we get it through a
|
||||
// dex2oatDepTag dependency, but in singletons there's no simple way to do the
|
||||
// same thing and ensure the right variant is selected, hence this cache to make
|
||||
// the resolved path available to singletons. This means we depend on there
|
||||
// being at least one ordinary module with a dex2oatDepTag dependency.
|
||||
//
|
||||
// TODO(b/147613152): Implement a way to deal with dependencies from singletons,
|
||||
// and then possibly remove this cache altogether (but the use in
|
||||
// GlobalSoongConfigForTests also needs to be rethought).
|
||||
var globalSoongConfigOnceKey = android.NewOnceKey("DexpreoptGlobalSoongConfig")
|
||||
|
||||
// GetGlobalSoongConfig creates a GlobalSoongConfig the first time it's called,
|
||||
@@ -335,6 +404,14 @@ func GetGlobalSoongConfig(ctx android.ModuleContext) GlobalSoongConfig {
|
||||
globalSoong := ctx.Config().Once(globalSoongConfigOnceKey, func() interface{} {
|
||||
return createGlobalSoongConfig(ctx)
|
||||
}).(GlobalSoongConfig)
|
||||
|
||||
// Always resolve the tool path from the dependency, to ensure that every
|
||||
// module has the dependency added properly.
|
||||
myDex2oat := dex2oatPathFromDep(ctx)
|
||||
if myDex2oat != globalSoong.Dex2oat {
|
||||
panic(fmt.Sprintf("Inconsistent dex2oat path in cached config: expected %s, got %s", globalSoong.Dex2oat, myDex2oat))
|
||||
}
|
||||
|
||||
return globalSoong
|
||||
}
|
||||
|
||||
@@ -382,6 +459,10 @@ func ParseGlobalSoongConfig(ctx android.PathContext, data []byte) (GlobalSoongCo
|
||||
}
|
||||
|
||||
func (s *globalSoongConfigSingleton) GenerateBuildActions(ctx android.SingletonContext) {
|
||||
if GetGlobalConfig(ctx).DisablePreopt {
|
||||
return
|
||||
}
|
||||
|
||||
config := GetCachedGlobalSoongConfig(ctx)
|
||||
jc := globalJsonSoongConfig{
|
||||
Profman: config.Profman.String(),
|
||||
@@ -409,6 +490,10 @@ func (s *globalSoongConfigSingleton) GenerateBuildActions(ctx android.SingletonC
|
||||
}
|
||||
|
||||
func (s *globalSoongConfigSingleton) MakeVars(ctx android.MakeVarsContext) {
|
||||
if GetGlobalConfig(ctx).DisablePreopt {
|
||||
return
|
||||
}
|
||||
|
||||
config := GetCachedGlobalSoongConfig(ctx)
|
||||
|
||||
ctx.Strict("DEX2OAT", config.Dex2oat.String())
|
||||
|
47
dexpreopt/testing.go
Normal file
47
dexpreopt/testing.go
Normal file
@@ -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 dexpreopt
|
||||
|
||||
import (
|
||||
"android/soong/android"
|
||||
)
|
||||
|
||||
type dummyToolBinary struct {
|
||||
android.ModuleBase
|
||||
}
|
||||
|
||||
func (m *dummyToolBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) {}
|
||||
|
||||
func (m *dummyToolBinary) HostToolPath() android.OptionalPath {
|
||||
return android.OptionalPathForPath(android.PathForTesting("dex2oat"))
|
||||
}
|
||||
|
||||
func dummyToolBinaryFactory() android.Module {
|
||||
module := &dummyToolBinary{}
|
||||
android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
|
||||
return module
|
||||
}
|
||||
|
||||
func RegisterToolModulesForTest(ctx *android.TestContext) {
|
||||
ctx.RegisterModuleType("dummy_tool_binary", dummyToolBinaryFactory)
|
||||
}
|
||||
|
||||
func BpToolModulesForTest() string {
|
||||
return `
|
||||
dummy_tool_binary {
|
||||
name: "dex2oatd",
|
||||
}
|
||||
`
|
||||
}
|
@@ -27,6 +27,7 @@ import (
|
||||
|
||||
"android/soong/android"
|
||||
"android/soong/cc"
|
||||
"android/soong/dexpreopt"
|
||||
"android/soong/tradefed"
|
||||
)
|
||||
|
||||
@@ -875,6 +876,7 @@ type AndroidAppImport struct {
|
||||
android.ModuleBase
|
||||
android.DefaultableModuleBase
|
||||
prebuilt android.Prebuilt
|
||||
dexpreopt.DexPreoptModule
|
||||
|
||||
properties AndroidAppImportProperties
|
||||
dpiVariants interface{}
|
||||
|
15
java/java.go
15
java/java.go
@@ -76,6 +76,8 @@ func RegisterJavaBuildComponents(ctx android.RegistrationContext) {
|
||||
ctx.RegisterModuleType("java_host_for_device", HostForDeviceFactory)
|
||||
ctx.RegisterModuleType("dex_import", DexImportFactory)
|
||||
|
||||
ctx.FinalDepsMutators(dexpreopt.RegisterToolDepsMutator)
|
||||
|
||||
ctx.RegisterSingletonType("logtags", LogtagsSingleton)
|
||||
ctx.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory)
|
||||
}
|
||||
@@ -369,6 +371,7 @@ type Module struct {
|
||||
android.DefaultableModuleBase
|
||||
android.ApexModuleBase
|
||||
android.SdkBase
|
||||
dexpreopt.DexPreoptModule
|
||||
|
||||
properties CompilerProperties
|
||||
protoProperties android.ProtoProperties
|
||||
@@ -1574,6 +1577,16 @@ 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)
|
||||
@@ -2340,6 +2353,7 @@ type Import struct {
|
||||
android.ApexModuleBase
|
||||
prebuilt android.Prebuilt
|
||||
android.SdkBase
|
||||
dexpreopt.DexPreoptModule
|
||||
|
||||
properties ImportProperties
|
||||
|
||||
@@ -2550,6 +2564,7 @@ type DexImport struct {
|
||||
android.DefaultableModuleBase
|
||||
android.ApexModuleBase
|
||||
prebuilt android.Prebuilt
|
||||
dexpreopt.DexPreoptModule
|
||||
|
||||
properties DexImportProperties
|
||||
|
||||
|
@@ -57,6 +57,8 @@ func TestMain(m *testing.M) {
|
||||
}
|
||||
|
||||
func testConfig(env map[string]string, bp string, fs map[string][]byte) android.Config {
|
||||
bp += dexpreopt.BpToolModulesForTest()
|
||||
|
||||
config := TestConfig(buildDir, env, bp, fs)
|
||||
|
||||
// Set up the global Once cache used for dexpreopt.GlobalSoongConfig, so that
|
||||
@@ -92,6 +94,8 @@ func testContext() *android.TestContext {
|
||||
cc.RegisterRequiredBuildComponentsForTest(ctx)
|
||||
ctx.RegisterModuleType("ndk_prebuilt_shared_stl", cc.NdkPrebuiltSharedStlFactory)
|
||||
|
||||
dexpreopt.RegisterToolModulesForTest(ctx)
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user