This patch excludes non-Soong system server jars from dexpreopting. System server jars should be dexpreopted together for better performance: each jar should have all preceding system server jars in its class loader context (that is passed to dex2oat and recorded in the resulting .oat file to be used by the loader). This means that we need a total order on system server jars. The default order provided by PRODUCT_SYSTEM_SERVER_JARS is not good, as it does not always respect genuine dependencies between jars (counter- examples are rare, but non-trivial to fix: b/148219586). This patch adds a post deps mutator pass that creates additional dependencies and enforces global order. These are later used to generate precise class loader contexts and system server classpath. Test: Class loader contexts in the oat files for system server jars match expectations: $ oatdump --oat-file=out/target/product/walleye/system/framework/oat/arm64/com.android.location.provider.odex | grep '^classpath' classpath = PCL[] $ oatdump --oat-file=out/target/product/walleye/system/framework/oat/arm64/services.odex | grep '^classpath' classpath = PCL[/system/framework/com.android.location.provider.jar*1919890654] $ oatdump --oat-file=out/target/product/walleye/system/framework/oat/arm64/wifi-service.odex | grep '^classpath' classpath = PCL[/system/framework/com.android.location.provider.jar*1919890654:/system/framework/services.jar*4269704903:/system/framework/services.jar!classes2.dex*134345935] ... Test: The phone boots and logcat has no scary messages related to class loader contexts: $ lunch aosp_walleye-userdebug && m $ adb reboot bootloader && fastboot flashall -w && adb wait-for-device $ adb root $ adb shell stop $ adb logcat -c $ adb shell setprop dalvik.vm.extra-opts -verbose:oat $ adb shell start $ adb logcat | egrep -i 'system_server: .*load.*/system/framework' 02-03 14:14:26.912 5016 5016 I system_server: Loading /system/framework/oat/arm64/com.android.location.provider.odex with executable: 1 02-03 14:14:26.914 5016 5016 I system_server: Successfully loaded /system/framework/oat/arm64/com.android.location.provider.odex with executable: 1 02-03 14:14:26.914 5016 5016 I system_server: Loading /system/framework/oat/arm64/services.odex with executable: 1 02-03 14:14:26.916 5016 5016 I system_server: Successfully loaded /system/framework/oat/arm64/services.odex with executable: 1 02-03 14:14:26.927 5016 5016 I system_server: Loading /system/framework/oat/arm64/wifi-service.odex with executable: 1 02-03 14:14:26.933 5016 5016 I system_server: Successfully loaded /system/framework/oat/arm64/wifi-service.odex with executable: 1 02-03 14:14:26.933 5016 5016 I system_server: Loading /system/framework/oat/arm64/ethernet-service.odex with executable: 1 02-03 14:14:26.934 5016 5016 I system_server: Successfully loaded /system/framework/oat/arm64/ethernet-service.odex with executable: 1 02-03 14:14:26.946 5016 5016 I system_server: Loading /system/framework/oat/arm64/com.android.location.provider.odex with executable: 0 02-03 14:14:26.947 5016 5016 I system_server: Successfully loaded /system/framework/oat/arm64/com.android.location.provider.odex with executable: 0 02-03 14:14:26.947 5016 5016 I system_server: Loading /system/framework/oat/arm64/services.odex with executable: 0 02-03 14:14:26.948 5016 5016 I system_server: Successfully loaded /system/framework/oat/arm64/services.odex with executable: 0 02-03 14:14:26.948 5016 5016 I system_server: Loading /system/framework/oat/arm64/wifi-service.odex with executable: 0 02-03 14:14:26.948 5016 5016 I system_server: Successfully loaded /system/framework/oat/arm64/wifi-service.odex with executable: 0 02-03 14:14:26.949 5016 5016 I system_server: Loading /system/framework/oat/arm64/ethernet-service.odex with executable: 0 02-03 14:14:26.949 5016 5016 I system_server: Successfully loaded /system/framework/oat/arm64/ethernet-service.odex with executable: 0 02-03 14:14:30.480 5016 5016 I system_server: Loading /system/framework/oat/arm64/com.android.location.provider.odex with executable: 1 02-03 14:14:30.481 5016 5016 I system_server: Successfully loaded /system/framework/oat/arm64/com.android.location.provider.odex with executable: 1 Bug: 141785760 Bug: 140451054 Bug: 148944771 Change-Id: Idac678dbd1f5fe0e381ce8e0e3561423f8a31389
258 lines
9.4 KiB
Go
258 lines
9.4 KiB
Go
// Copyright 2019 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 java
|
|
|
|
import (
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"android/soong/android"
|
|
"android/soong/dexpreopt"
|
|
)
|
|
|
|
// dexpreoptGlobalConfig returns the global dexpreopt.config. It is loaded once the first time it is called for any
|
|
// ctx.Config(), and returns the same data for all future calls with the same ctx.Config(). A value can be inserted
|
|
// for tests using setDexpreoptTestGlobalConfig.
|
|
func dexpreoptGlobalConfig(ctx android.PathContext) dexpreopt.GlobalConfig {
|
|
return dexpreoptGlobalConfigRaw(ctx).global
|
|
}
|
|
|
|
type globalConfigAndRaw struct {
|
|
global dexpreopt.GlobalConfig
|
|
data []byte
|
|
}
|
|
|
|
func dexpreoptGlobalConfigRaw(ctx android.PathContext) globalConfigAndRaw {
|
|
return ctx.Config().Once(dexpreoptGlobalConfigKey, func() interface{} {
|
|
if data, err := ctx.Config().DexpreoptGlobalConfig(ctx); err != nil {
|
|
panic(err)
|
|
} else if data != nil {
|
|
soongConfig := dexpreopt.CreateGlobalSoongConfig(ctx)
|
|
globalConfig, err := dexpreopt.LoadGlobalConfig(ctx, data, soongConfig)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return globalConfigAndRaw{globalConfig, data}
|
|
}
|
|
|
|
// No global config filename set, see if there is a test config set
|
|
return ctx.Config().Once(dexpreoptTestGlobalConfigKey, func() interface{} {
|
|
// Nope, return a config with preopting disabled
|
|
return globalConfigAndRaw{dexpreopt.GlobalConfig{
|
|
DisablePreopt: true,
|
|
DisableGenerateProfile: true,
|
|
}, nil}
|
|
})
|
|
}).(globalConfigAndRaw)
|
|
}
|
|
|
|
// setDexpreoptTestGlobalConfig sets a GlobalConfig that future calls to dexpreoptGlobalConfig will return. It must
|
|
// be called before the first call to dexpreoptGlobalConfig for the config.
|
|
func setDexpreoptTestGlobalConfig(config android.Config, globalConfig dexpreopt.GlobalConfig) {
|
|
config.Once(dexpreoptTestGlobalConfigKey, func() interface{} { return globalConfigAndRaw{globalConfig, nil} })
|
|
}
|
|
|
|
var dexpreoptGlobalConfigKey = android.NewOnceKey("DexpreoptGlobalConfig")
|
|
var dexpreoptTestGlobalConfigKey = android.NewOnceKey("TestDexpreoptGlobalConfig")
|
|
|
|
// systemServerClasspath returns the on-device locations of the modules in the system server classpath. It is computed
|
|
// once the first time it is called for any ctx.Config(), and returns the same slice for all future calls with the same
|
|
// ctx.Config().
|
|
func systemServerClasspath(ctx android.MakeVarsContext) []string {
|
|
return ctx.Config().OnceStringSlice(systemServerClasspathKey, func() []string {
|
|
global := dexpreoptGlobalConfig(ctx)
|
|
var systemServerClasspathLocations []string
|
|
for _, m := range *DexpreoptedSystemServerJars(ctx.Config()) {
|
|
systemServerClasspathLocations = append(systemServerClasspathLocations,
|
|
filepath.Join("/system/framework", m+".jar"))
|
|
}
|
|
for _, m := range global.UpdatableSystemServerJars {
|
|
systemServerClasspathLocations = append(systemServerClasspathLocations,
|
|
dexpreopt.GetJarLocationFromApexJarPair(m))
|
|
}
|
|
return systemServerClasspathLocations
|
|
})
|
|
}
|
|
|
|
var systemServerClasspathKey = android.NewOnceKey("systemServerClasspath")
|
|
|
|
// dexpreoptTargets returns the list of targets that are relevant to dexpreopting, which excludes architectures
|
|
// supported through native bridge.
|
|
func dexpreoptTargets(ctx android.PathContext) []android.Target {
|
|
var targets []android.Target
|
|
for _, target := range ctx.Config().Targets[android.Android] {
|
|
if target.NativeBridge == android.NativeBridgeDisabled {
|
|
targets = append(targets, target)
|
|
}
|
|
}
|
|
|
|
return targets
|
|
}
|
|
|
|
func stemOf(moduleName string) string {
|
|
// b/139391334: the stem of framework-minus-apex is framework
|
|
// This is hard coded here until we find a good way to query the stem
|
|
// of a module before any other mutators are run
|
|
if moduleName == "framework-minus-apex" {
|
|
return "framework"
|
|
}
|
|
return moduleName
|
|
}
|
|
|
|
var (
|
|
bootImageConfigKey = android.NewOnceKey("bootImageConfig")
|
|
artBootImageName = "art"
|
|
frameworkBootImageName = "boot"
|
|
)
|
|
|
|
// Construct the global boot image configs.
|
|
func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
|
|
return ctx.Config().Once(bootImageConfigKey, func() interface{} {
|
|
|
|
global := dexpreoptGlobalConfig(ctx)
|
|
targets := dexpreoptTargets(ctx)
|
|
deviceDir := android.PathForOutput(ctx, ctx.Config().DeviceName())
|
|
|
|
artModules := global.ArtApexJars
|
|
// With EMMA_INSTRUMENT_FRAMEWORK=true the Core libraries depend on jacoco.
|
|
if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
|
|
artModules = append(artModules, "jacocoagent")
|
|
}
|
|
frameworkModules := android.RemoveListFromList(global.BootJars,
|
|
concat(artModules, dexpreopt.GetJarsFromApexJarPairs(global.UpdatableBootJars)))
|
|
|
|
artSubdir := "apex/com.android.art/javalib"
|
|
frameworkSubdir := "system/framework"
|
|
|
|
var artLocations, frameworkLocations []string
|
|
for _, m := range artModules {
|
|
artLocations = append(artLocations, filepath.Join("/"+artSubdir, stemOf(m)+".jar"))
|
|
}
|
|
for _, m := range frameworkModules {
|
|
frameworkLocations = append(frameworkLocations, filepath.Join("/"+frameworkSubdir, stemOf(m)+".jar"))
|
|
}
|
|
|
|
// ART config for the primary boot image in the ART apex.
|
|
// It includes the Core Libraries.
|
|
artCfg := bootImageConfig{
|
|
extension: false,
|
|
name: artBootImageName,
|
|
stem: "boot",
|
|
installSubdir: artSubdir,
|
|
modules: artModules,
|
|
dexLocations: artLocations,
|
|
dexLocationsDeps: artLocations,
|
|
}
|
|
|
|
// Framework config for the boot image extension.
|
|
// It includes framework libraries and depends on the ART config.
|
|
frameworkCfg := bootImageConfig{
|
|
extension: true,
|
|
name: frameworkBootImageName,
|
|
stem: "boot",
|
|
installSubdir: frameworkSubdir,
|
|
modules: frameworkModules,
|
|
dexLocations: frameworkLocations,
|
|
dexLocationsDeps: append(artLocations, frameworkLocations...),
|
|
}
|
|
|
|
configs := map[string]*bootImageConfig{
|
|
artBootImageName: &artCfg,
|
|
frameworkBootImageName: &frameworkCfg,
|
|
}
|
|
|
|
// common to all configs
|
|
for _, c := range configs {
|
|
c.targets = targets
|
|
|
|
c.dir = deviceDir.Join(ctx, "dex_"+c.name+"jars")
|
|
c.symbolsDir = deviceDir.Join(ctx, "dex_"+c.name+"jars_unstripped")
|
|
|
|
// expands to <stem>.art for primary image and <stem>-<1st module>.art for extension
|
|
imageName := c.firstModuleNameOrStem() + ".art"
|
|
|
|
c.imageLocations = []string{c.dir.Join(ctx, c.installSubdir, imageName).String()}
|
|
|
|
// The path to bootclasspath dex files needs to be known at module
|
|
// GenerateAndroidBuildAction time, before the bootclasspath modules have been compiled.
|
|
// Set up known paths for them, the singleton rules will copy them there.
|
|
// TODO(b/143682396): use module dependencies instead
|
|
inputDir := deviceDir.Join(ctx, "dex_"+c.name+"jars_input")
|
|
for _, m := range c.modules {
|
|
c.dexPaths = append(c.dexPaths, inputDir.Join(ctx, stemOf(m)+".jar"))
|
|
}
|
|
c.dexPathsDeps = c.dexPaths
|
|
|
|
c.images = make(map[android.ArchType]android.OutputPath)
|
|
c.imagesDeps = make(map[android.ArchType]android.OutputPaths)
|
|
|
|
for _, target := range targets {
|
|
arch := target.Arch.ArchType
|
|
imageDir := c.dir.Join(ctx, c.installSubdir, arch.String())
|
|
c.images[arch] = imageDir.Join(ctx, imageName)
|
|
c.imagesDeps[arch] = c.moduleFiles(ctx, imageDir, ".art", ".oat", ".vdex")
|
|
}
|
|
|
|
c.zip = c.dir.Join(ctx, c.name+".zip")
|
|
}
|
|
|
|
// specific to the framework config
|
|
frameworkCfg.dexPathsDeps = append(artCfg.dexPathsDeps, frameworkCfg.dexPathsDeps...)
|
|
frameworkCfg.primaryImages = artCfg.images
|
|
frameworkCfg.imageLocations = append(artCfg.imageLocations, frameworkCfg.imageLocations...)
|
|
|
|
return configs
|
|
}).(map[string]*bootImageConfig)
|
|
}
|
|
|
|
func artBootImageConfig(ctx android.PathContext) bootImageConfig {
|
|
return *genBootImageConfigs(ctx)[artBootImageName]
|
|
}
|
|
|
|
func defaultBootImageConfig(ctx android.PathContext) bootImageConfig {
|
|
return *genBootImageConfigs(ctx)[frameworkBootImageName]
|
|
}
|
|
|
|
func defaultBootclasspath(ctx android.PathContext) []string {
|
|
return ctx.Config().OnceStringSlice(defaultBootclasspathKey, func() []string {
|
|
global := dexpreoptGlobalConfig(ctx)
|
|
image := defaultBootImageConfig(ctx)
|
|
|
|
updatableBootclasspath := make([]string, len(global.UpdatableBootJars))
|
|
for i, p := range global.UpdatableBootJars {
|
|
updatableBootclasspath[i] = dexpreopt.GetJarLocationFromApexJarPair(p)
|
|
}
|
|
|
|
bootclasspath := append(copyOf(image.dexLocationsDeps), updatableBootclasspath...)
|
|
return bootclasspath
|
|
})
|
|
}
|
|
|
|
var defaultBootclasspathKey = android.NewOnceKey("defaultBootclasspath")
|
|
|
|
var copyOf = android.CopyOf
|
|
|
|
func init() {
|
|
android.RegisterMakeVarsProvider(pctx, dexpreoptConfigMakevars)
|
|
}
|
|
|
|
func dexpreoptConfigMakevars(ctx android.MakeVarsContext) {
|
|
ctx.Strict("PRODUCT_BOOTCLASSPATH", strings.Join(defaultBootclasspath(ctx), ":"))
|
|
ctx.Strict("PRODUCT_DEX2OAT_BOOTCLASSPATH", strings.Join(defaultBootImageConfig(ctx).dexLocationsDeps, ":"))
|
|
ctx.Strict("PRODUCT_SYSTEM_SERVER_CLASSPATH", strings.Join(systemServerClasspath(ctx), ":"))
|
|
|
|
ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules, ":"))
|
|
}
|