diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go index 6cb987385..7dd01e235 100644 --- a/dexpreopt/dexpreopt.go +++ b/dexpreopt/dexpreopt.go @@ -41,21 +41,12 @@ import ( "android/soong/android" - "github.com/google/blueprint" "github.com/google/blueprint/pathtools" ) const SystemPartition = "/system/" const SystemOtherPartition = "/system_other/" -type dependencyTag struct { - blueprint.BaseDependencyTag - name string -} - -var SystemServerDepTag = dependencyTag{name: "system-server-dep"} -var SystemServerForcedDepTag = dependencyTag{name: "system-server-forced-dep"} - // GenerateDexpreoptRule generates a set of commands that will preopt a module based on a GlobalConfig and a // ModuleConfig. The produced files and their install locations will be available through rule.Installs(). func GenerateDexpreoptRule(ctx android.PathContext, globalSoong *GlobalSoongConfig, @@ -116,13 +107,6 @@ func dexpreoptDisabled(ctx android.PathContext, global *GlobalConfig, module *Mo } } - // Don't preopt system server jars that are not Soong modules. - if android.InList(module.Name, NonUpdatableSystemServerJars(ctx, global)) { - if _, ok := ctx.(android.ModuleContext); !ok { - return true - } - } - // If OnlyPreoptBootImageAndSystemServer=true and module is not in boot class path skip // Also preopt system server jars since selinux prevents system server from loading anything from // /data. If we don't do this they will need to be extracted which is not favorable for RAM usage @@ -239,6 +223,8 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g invocationPath := odexPath.ReplaceExtension(ctx, "invocation") + systemServerJars := NonUpdatableSystemServerJars(ctx, global) + // The class loader context using paths in the build var classLoaderContextHost android.Paths @@ -253,8 +239,8 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g var conditionalClassLoaderContextHost29 android.Paths var conditionalClassLoaderContextTarget29 []string - var classLoaderContextHostString, classLoaderContextDeviceString string - var classLoaderDeps android.Paths + // A flag indicating if the '&' class loader context is used. + unknownClassLoaderContext := false if module.EnforceUsesLibraries { usesLibs := append(copyOf(module.UsesLibraries), module.PresentOptionalUsesLibraries...) @@ -298,49 +284,38 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g pathForLibrary(module, hidlBase)) conditionalClassLoaderContextTarget29 = append(conditionalClassLoaderContextTarget29, filepath.Join("/system/framework", hidlBase+".jar")) - - classLoaderContextHostString = strings.Join(classLoaderContextHost.Strings(), ":") - } else if android.InList(module.Name, NonUpdatableSystemServerJars(ctx, global)) { - // We expect that all dexpreopted system server jars are Soong modules. - mctx, isModule := ctx.(android.ModuleContext) - if !isModule { - panic("Cannot dexpreopt system server jar that is not a soong module.") + } else if jarIndex := android.IndexList(module.Name, systemServerJars); jarIndex >= 0 { + // System server jars should be dexpreopted together: class loader context of each jar + // should include all preceding jars on the system server classpath. + for _, otherJar := range systemServerJars[:jarIndex] { + classLoaderContextHost = append(classLoaderContextHost, SystemServerDexJarHostPath(ctx, otherJar)) + classLoaderContextTarget = append(classLoaderContextTarget, "/system/framework/"+otherJar+".jar") } - // System server jars should be dexpreopted together: class loader context of each jar - // should include preceding jars (which can be found as dependencies of the current jar - // with a special tag). - var jarsOnHost android.Paths - var jarsOnDevice []string - mctx.VisitDirectDepsWithTag(SystemServerDepTag, func(dep android.Module) { - depName := mctx.OtherModuleName(dep) - if jar, ok := dep.(interface{ DexJar() android.Path }); ok { - jarsOnHost = append(jarsOnHost, jar.DexJar()) - jarsOnDevice = append(jarsOnDevice, "/system/framework/"+depName+".jar") - } else { - mctx.ModuleErrorf("module \"%s\" is not a jar", depName) - } - }) - classLoaderContextHostString = strings.Join(jarsOnHost.Strings(), ":") - classLoaderContextDeviceString = strings.Join(jarsOnDevice, ":") - classLoaderDeps = jarsOnHost + // Copy the system server jar to a predefined location where dex2oat will find it. + dexPathHost := SystemServerDexJarHostPath(ctx, module.Name) + rule.Command().Text("mkdir -p").Flag(filepath.Dir(dexPathHost.String())) + rule.Command().Text("cp -f").Input(module.DexPath).Output(dexPathHost) } else { // Pass special class loader context to skip the classpath and collision check. // This will get removed once LOCAL_USES_LIBRARIES is enforced. // Right now LOCAL_USES_LIBRARIES is opt in, for the case where it's not specified we still default // to the &. - classLoaderContextHostString = `\&` + unknownClassLoaderContext = true } rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath.String())) rule.Command().FlagWithOutput("rm -f ", odexPath) // Set values in the environment of the rule. These may be modified by construct_context.sh. - if classLoaderContextHostString == `\&` { - rule.Command().Text(`class_loader_context_arg=--class-loader-context=\&`) - rule.Command().Text(`stored_class_loader_context_arg=""`) + if unknownClassLoaderContext { + rule.Command(). + Text(`class_loader_context_arg=--class-loader-context=\&`). + Text(`stored_class_loader_context_arg=""`) } else { - rule.Command().Text("class_loader_context_arg=--class-loader-context=PCL[" + classLoaderContextHostString + "]") - rule.Command().Text("stored_class_loader_context_arg=--stored-class-loader-context=PCL[" + classLoaderContextDeviceString + "]") + rule.Command(). + Text("class_loader_context_arg=--class-loader-context=PCL[" + strings.Join(classLoaderContextHost.Strings(), ":") + "]"). + Implicits(classLoaderContextHost). + Text("stored_class_loader_context_arg=--stored-class-loader-context=PCL[" + strings.Join(classLoaderContextTarget, ":") + "]") } if module.EnforceUsesLibraries { @@ -395,7 +370,7 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", module.PreoptBootClassPathDexFiles, ":"). Flag("--runtime-arg").FlagWithList("-Xbootclasspath-locations:", module.PreoptBootClassPathDexLocations, ":"). Flag("${class_loader_context_arg}"). - Flag("${stored_class_loader_context_arg}").Implicits(classLoaderDeps). + Flag("${stored_class_loader_context_arg}"). FlagWithArg("--boot-image=", strings.Join(module.DexPreoptImageLocations, ":")).Implicits(module.DexPreoptImagesDeps[archIdx].Paths()). FlagWithInput("--dex-file=", module.DexPath). FlagWithArg("--dex-location=", dexLocationArg). @@ -609,6 +584,14 @@ func NonUpdatableSystemServerJars(ctx android.PathContext, global *GlobalConfig) }).([]string) } +// A predefined location for the system server dex jars. This is needed in order to generate +// class loader context for dex2oat, as the path to the jar in the Soong module may be unknown +// at that time (Soong processes the jars in dependency order, which may be different from the +// the system server classpath order). +func SystemServerDexJarHostPath(ctx android.PathContext, jar string) android.OutputPath { + return android.PathForOutput(ctx, ctx.Config().DeviceName(), "system_server_dexjars", jar+".jar") +} + func contains(l []string, s string) bool { for _, e := range l { if e == s { diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go index d77d3e144..ffce2a9ff 100644 --- a/java/dexpreopt_config.go +++ b/java/dexpreopt_config.go @@ -30,9 +30,9 @@ func systemServerClasspath(ctx android.MakeVarsContext) []string { return ctx.Config().OnceStringSlice(systemServerClasspathKey, func() []string { global := dexpreopt.GetGlobalConfig(ctx) var systemServerClasspathLocations []string - var dexpreoptJars = *DexpreoptedSystemServerJars(ctx.Config()) - // 1) The jars that are dexpreopted. - for _, m := range dexpreoptJars { + nonUpdatable := dexpreopt.NonUpdatableSystemServerJars(ctx, global) + // 1) Non-updatable jars. + for _, m := range nonUpdatable { systemServerClasspathLocations = append(systemServerClasspathLocations, filepath.Join("/system/framework", m+".jar")) } @@ -41,13 +41,6 @@ func systemServerClasspath(ctx android.MakeVarsContext) []string { systemServerClasspathLocations = append(systemServerClasspathLocations, dexpreopt.GetJarLocationFromApexJarPair(m)) } - // 3) The jars from make (which are not updatable, not preopted). - for _, m := range dexpreopt.NonUpdatableSystemServerJars(ctx, global) { - if !android.InList(m, dexpreoptJars) { - systemServerClasspathLocations = append(systemServerClasspathLocations, - filepath.Join("/system/framework", m+".jar")) - } - } if len(systemServerClasspathLocations) != len(global.SystemServerJars)+len(global.UpdatableSystemServerJars) { panic(fmt.Errorf("Wrong number of system server jars, got %d, expected %d", len(systemServerClasspathLocations), diff --git a/java/java.go b/java/java.go index 59a1e05c8..22d14ecfe 100644 --- a/java/java.go +++ b/java/java.go @@ -23,14 +23,12 @@ import ( "path/filepath" "strconv" "strings" - "sync" "github.com/google/blueprint" "github.com/google/blueprint/pathtools" "github.com/google/blueprint/proptools" "android/soong/android" - "android/soong/dexpreopt" "android/soong/java/config" "android/soong/tradefed" ) @@ -60,8 +58,6 @@ func init() { PropertyName: "java_tests", }, }) - - android.PostDepsMutators(RegisterPostDepsMutators) } func RegisterJavaBuildComponents(ctx android.RegistrationContext) { @@ -90,44 +86,6 @@ func RegisterJavaBuildComponents(ctx android.RegistrationContext) { ctx.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory) } -func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) { - ctx.BottomUp("ordered_system_server_jars", systemServerJarsDepsMutator) -} - -var ( - dexpreoptedSystemServerJarsKey = android.NewOnceKey("dexpreoptedSystemServerJars") - dexpreoptedSystemServerJarsLock sync.Mutex -) - -func DexpreoptedSystemServerJars(config android.Config) *[]string { - return config.Once(dexpreoptedSystemServerJarsKey, func() interface{} { - return &[]string{} - }).(*[]string) -} - -// A PostDepsMutator pass that enforces total order on non-updatable system server jars. A total -// order is neededed because such jars must be dexpreopted together (each jar on the list must have -// all preceding jars in its class loader context). The total order must be compatible with the -// partial order imposed by genuine dependencies between system server jars (which is not always -// respected by the PRODUCT_SYSTEM_SERVER_JARS variable). -// -// An earlier mutator pass creates genuine dependencies, and this pass traverses the jars in that -// order (which is partial and non-deterministic). This pass adds additional dependencies between -// jars, making the order total and deterministic. It also constructs a global ordered list. -func systemServerJarsDepsMutator(ctx android.BottomUpMutatorContext) { - jars := dexpreopt.NonUpdatableSystemServerJars(ctx, dexpreopt.GetGlobalConfig(ctx)) - name := ctx.ModuleName() - if android.InList(name, jars) { - dexpreoptedSystemServerJarsLock.Lock() - defer dexpreoptedSystemServerJarsLock.Unlock() - jars := DexpreoptedSystemServerJars(ctx.Config()) - for _, dep := range *jars { - ctx.AddDependency(ctx.Module(), dexpreopt.SystemServerDepTag, dep) - } - *jars = append(*jars, name) - } -} - func (j *Module) checkSdkVersion(ctx android.ModuleContext) { if j.SocSpecific() || j.DeviceSpecific() || (j.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) { @@ -711,11 +669,6 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) { } else if j.shouldInstrumentStatic(ctx) { ctx.AddVariationDependencies(nil, staticLibTag, "jacocoagent") } - - // services depend on com.android.location.provider, but dependency in not registered in a Blueprint file - if ctx.ModuleName() == "services" { - ctx.AddDependency(ctx.Module(), dexpreopt.SystemServerForcedDepTag, "com.android.location.provider") - } } func hasSrcExt(srcs []string, ext string) bool {