a4a83b0ef9
This reworks CL https://r.android.com/1180134 as follows: 1) Do not reorder the list of system server jars passed from Make to Soong via the product variable PRODUCT_SYSTEM_SERVER_JARS. This means that for some products the order of jars on the system server classpath may be non-optimal: a jar X that depends on Y may be dexpreopted before Y, so that all references to the classes and methods from Y wil be unresolved. Unfortunately for such products, fixing the order is not a simple matter of rearranging their PRODUCT_SYSTEM_SERVER_JARS, because the conflicts may arise when the product-specific variable gets merged with the common variable. 2) As a consequence of 1), do not add artificial dependencies between system server jars: this is now impossible, as it would create circular dependencies for those products that have non-optimal order of jars. 3) Copy dex files for system server jars to a predefined build location. This is necessary because at the time when Soong generates class loader context for k-th jar, it needs to know the paths to jars 1 .. (k-1), and it might have not processed those jars yet (so Soong can't query the paths from the modules). This approach is similar to the way Soong handles bootclasspath jars. 4) Do not exclude from dexpreopting system server jars that are not Soong modules (those that are Make modules). The previous CL excluded them because Make modules do not have ModuleContext. But it turns out that ModuleContext is not necessary, as all the information is passed via the dexpreopt config. Test: aosp_walleye-userdebug boots and there are no messages in the logcat regarding class loader context mismatch: $ adb logcat | grep 'mismatch' # empty 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 2>/dev/null | grep '^classpath' classpath = PCL[] $ oatdump --oat-file=out/target/product/walleye/system/framework/oat/arm64/services.odex 2>/dev/null | grep '^classpath' classpath = PCL[/system/framework/com.android.location.provider.jar*1989208671] $ oatdump --oat-file=out/target/product/walleye/system/framework/oat/arm64/ethernet-service.odex 2>/dev/null | grep '^classpath' classpath = PCL[/system/framework/com.android.location.provider.jar*1989208671:/system/framework/services.jar*4040443083:/system/framework/services.jar!classes2.dex*2210087472] 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 -io 'system_server: .*load.*/system/framework.*' system_server: Loading /system/framework/oat/arm64/com.android.location.provider.odex with executable: 0 system_server: Successfully loaded /system/framework/oat/arm64/com.android.location.provider.odex with executable: 0 system_server: Loading /system/framework/oat/arm64/services.odex with executable: 0 system_server: Successfully loaded /system/framework/oat/arm64/services.odex with executable: 0 system_server: Loading /system/framework/oat/arm64/ethernet-service.odex with executable: 0 system_server: Successfully loaded /system/framework/oat/arm64/ethernet-service.odex with executable: 0 system_server: Loading /system/framework/oat/arm64/wifi-service.odex with executable: 0 system_server: Successfully loaded /system/framework/oat/arm64/wifi-service.odex with executable: 0 system_server: Loading /system/framework/oat/arm64/com.android.location.provider.odex with executable: 1 system_server: Successfully loaded /system/framework/oat/arm64/com.android.location.provider.odex with executable: 1 system_server: Loading /system/framework/oat/arm64/services.odex with executable: 1 system_server: Successfully loaded /system/framework/oat/arm64/services.odex with executable: 1 system_server: Loading /system/framework/oat/arm64/ethernet-service.odex with executable: 1 system_server: Successfully loaded /system/framework/oat/arm64/ethernet-service.odex with executable: 1 system_server: Loading /system/framework/oat/arm64/wifi-service.odex with executable: 1 system_server: Successfully loaded /system/framework/oat/arm64/wifi-service.odex with executable: 1 system_server: Loading /system/framework/oat/arm64/com.android.location.provider.odex with executable: 1 system_server: Successfully loaded /system/framework/oat/arm64/com.android.location.provider.odex with executable: 1 Bug: 141785760 Bug: 140451054 Bug: 148944771 Bug: 147017252 Change-Id: I33c4087f8bfacd0ecb89877aa150b75360d06710
221 lines
8 KiB
Go
221 lines
8 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 (
|
|
"fmt"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"android/soong/android"
|
|
"android/soong/dexpreopt"
|
|
)
|
|
|
|
// 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 := dexpreopt.GetGlobalConfig(ctx)
|
|
var systemServerClasspathLocations []string
|
|
nonUpdatable := dexpreopt.NonUpdatableSystemServerJars(ctx, global)
|
|
// 1) Non-updatable jars.
|
|
for _, m := range nonUpdatable {
|
|
systemServerClasspathLocations = append(systemServerClasspathLocations,
|
|
filepath.Join("/system/framework", m+".jar"))
|
|
}
|
|
// 2) The jars that are from an updatable apex.
|
|
for _, m := range global.UpdatableSystemServerJars {
|
|
systemServerClasspathLocations = append(systemServerClasspathLocations,
|
|
dexpreopt.GetJarLocationFromApexJarPair(m))
|
|
}
|
|
if len(systemServerClasspathLocations) != len(global.SystemServerJars)+len(global.UpdatableSystemServerJars) {
|
|
panic(fmt.Errorf("Wrong number of system server jars, got %d, expected %d",
|
|
len(systemServerClasspathLocations),
|
|
len(global.SystemServerJars)+len(global.UpdatableSystemServerJars)))
|
|
}
|
|
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 := dexpreopt.GetGlobalConfig(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 := dexpreopt.GetGlobalConfig(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, ":"))
|
|
}
|