diff --git a/android/paths.go b/android/paths.go index 8dbb08644..1a37a34f0 100644 --- a/android/paths.go +++ b/android/paths.go @@ -247,6 +247,33 @@ func PathsForModuleSrcExcludes(ctx ModuleContext, paths, excludes []string) Path return ret } +// OutputPaths is a slice of OutputPath objects, with helpers to operate on the collection. +type OutputPaths []OutputPath + +// Paths returns the OutputPaths as a Paths +func (p OutputPaths) Paths() Paths { + if p == nil { + return nil + } + ret := make(Paths, len(p)) + for i, path := range p { + ret[i] = path + } + return ret +} + +// Strings returns the string forms of the writable paths. +func (p OutputPaths) Strings() []string { + if p == nil { + return nil + } + ret := make([]string, len(p)) + for i, path := range p { + ret[i] = path.String() + } + return ret +} + // PathsAndMissingDepsForModuleSrcExcludes returns Paths rooted from the module's local source directory, excluding // paths listed in the excludes arguments, and a list of missing dependencies. It expands globs, references to // SourceFileProducer modules using the ":name" syntax, and references to OutputFileProducer modules using the diff --git a/dexpreopt/config.go b/dexpreopt/config.go index 35c2b44ae..83e367371 100644 --- a/dexpreopt/config.go +++ b/dexpreopt/config.go @@ -41,7 +41,7 @@ type GlobalConfig struct { BootJars []string // modules for jars that form the boot class path UpdatableBootJars []string // jars within apex that form the boot class path - ArtApexJars []string // modules for jars that are in the ART APEX + ArtApexJars []string // modules for jars that are in the ART APEX SystemServerJars []string // jars that form the system server SystemServerApps []string // apps that are loaded into system server @@ -117,9 +117,10 @@ type ModuleConfig struct { UsesLibraries []string LibraryPaths map[string]android.Path - Archs []android.ArchType - DexPreoptImages []android.Path - DexPreoptImagesDeps []android.Paths + Archs []android.ArchType + DexPreoptImages []android.Path + DexPreoptImagesDeps []android.OutputPaths + DexPreoptImageLocations []string PreoptBootClassPathDexFiles android.Paths // file paths of boot class path files PreoptBootClassPathDexLocations []string // virtual locations of boot class path files @@ -225,6 +226,7 @@ func LoadModuleConfig(ctx android.PathContext, path string) (ModuleConfig, error ProfileClassListing string LibraryPaths map[string]string DexPreoptImages []string + DexPreoptImageLocations []string PreoptBootClassPathDexFiles []string } @@ -242,10 +244,11 @@ func LoadModuleConfig(ctx android.PathContext, path string) (ModuleConfig, error config.ModuleConfig.ProfileClassListing = android.OptionalPathForPath(constructPath(ctx, config.ProfileClassListing)) config.ModuleConfig.LibraryPaths = constructPathMap(ctx, config.LibraryPaths) config.ModuleConfig.DexPreoptImages = constructPaths(ctx, config.DexPreoptImages) + config.ModuleConfig.DexPreoptImageLocations = config.DexPreoptImageLocations config.ModuleConfig.PreoptBootClassPathDexFiles = constructPaths(ctx, config.PreoptBootClassPathDexFiles) // This needs to exist, but dependencies are already handled in Make, so we don't need to pass them through JSON. - config.ModuleConfig.DexPreoptImagesDeps = make([]android.Paths, len(config.ModuleConfig.DexPreoptImages)) + config.ModuleConfig.DexPreoptImagesDeps = make([]android.OutputPaths, len(config.ModuleConfig.DexPreoptImages)) return config.ModuleConfig, nil } diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go index f3bf2ff80..40986c344 100644 --- a/dexpreopt/dexpreopt.go +++ b/dexpreopt/dexpreopt.go @@ -86,10 +86,8 @@ func GenerateDexpreoptRule(ctx android.PathContext, generateDM := shouldGenerateDM(module, global) - for i, arch := range module.Archs { - image := module.DexPreoptImages[i] - imageDeps := module.DexPreoptImagesDeps[i] - dexpreoptCommand(ctx, global, module, rule, arch, profile, image, imageDeps, appImage, generateDM) + for archIdx, _ := range module.Archs { + dexpreoptCommand(ctx, global, module, rule, archIdx, profile, appImage, generateDM) } } } @@ -193,7 +191,9 @@ func bootProfileCommand(ctx android.PathContext, global GlobalConfig, module Mod } func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module ModuleConfig, rule *android.RuleBuilder, - arch android.ArchType, profile, bootImage android.Path, bootImageDeps android.Paths, appImage, generateDM bool) { + archIdx int, profile android.WritablePath, appImage bool, generateDM bool) { + + arch := module.Archs[archIdx] // HACK: make soname in Soong-generated .odex files match Make. base := filepath.Base(module.DexLocation) @@ -222,13 +222,6 @@ func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module Modul invocationPath := odexPath.ReplaceExtension(ctx, "invocation") - // bootImage is .../dex_bootjars/system/framework/arm64/boot.art, but dex2oat wants - // .../dex_bootjars/system/framework/boot.art on the command line - var bootImageLocation string - if bootImage != nil { - bootImageLocation = PathToLocation(bootImage, arch) - } - // The class loader context using paths in the build var classLoaderContextHost android.Paths @@ -356,7 +349,7 @@ func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module Modul Flag("--runtime-arg").FlagWithList("-Xbootclasspath-locations:", module.PreoptBootClassPathDexLocations, ":"). Flag("${class_loader_context_arg}"). Flag("${stored_class_loader_context_arg}"). - FlagWithArg("--boot-image=", bootImageLocation).Implicits(bootImageDeps). + FlagWithArg("--boot-image=", strings.Join(module.DexPreoptImageLocations, ":")).Implicits(module.DexPreoptImagesDeps[archIdx].Paths()). FlagWithInput("--dex-file=", module.DexPath). FlagWithArg("--dex-location=", dexLocationArg). FlagWithOutput("--oat-file=", odexPath).ImplicitOutput(vdexPath). @@ -555,9 +548,9 @@ func SplitApexJarPair(apexJarValue string) (string, string) { } // Expected format for apexJarValue = : -func GetJarLocationFromApexJarPair(apexJarValue string) (string) { +func GetJarLocationFromApexJarPair(apexJarValue string) string { apex, jar := SplitApexJarPair(apexJarValue) - return filepath.Join("/apex", apex, "javalib", jar + ".jar") + return filepath.Join("/apex", apex, "javalib", jar+".jar") } func contains(l []string, s string) bool { diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go index 6f8120ee2..254be0aa1 100644 --- a/dexpreopt/dexpreopt_test.go +++ b/dexpreopt/dexpreopt_test.go @@ -49,7 +49,8 @@ func testModuleConfig(ctx android.PathContext, name, partition string) ModuleCon LibraryPaths: nil, Archs: []android.ArchType{android.Arm}, DexPreoptImages: android.Paths{android.PathForTesting("system/framework/arm/boot.art")}, - DexPreoptImagesDeps: []android.Paths{android.Paths{}}, + DexPreoptImagesDeps: []android.OutputPaths{android.OutputPaths{}}, + DexPreoptImageLocations: []string{}, PreoptBootClassPathDexFiles: nil, PreoptBootClassPathDexLocations: nil, PreoptExtractedApk: false, diff --git a/java/dexpreopt.go b/java/dexpreopt.go index 2b1c9941e..479dec60b 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -124,7 +124,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo } var images android.Paths - var imagesDeps []android.Paths + var imagesDeps []android.OutputPaths for _, arch := range archs { images = append(images, bootImage.images[arch]) imagesDeps = append(imagesDeps, bootImage.imagesDeps[arch]) @@ -169,15 +169,16 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Mo UsesLibraries: d.usesLibs, LibraryPaths: d.libraryPaths, - Archs: archs, - DexPreoptImages: images, - DexPreoptImagesDeps: imagesDeps, + Archs: archs, + DexPreoptImages: images, + DexPreoptImagesDeps: imagesDeps, + DexPreoptImageLocations: bootImage.imageLocations, // We use the dex paths and dex locations of the default boot image, as it // contains the full dexpreopt boot classpath. Other images may just contain a subset of // the dexpreopt boot classpath. - PreoptBootClassPathDexFiles: defaultBootImage.dexPaths.Paths(), - PreoptBootClassPathDexLocations: defaultBootImage.dexLocations, + PreoptBootClassPathDexFiles: defaultBootImage.dexPathsDeps.Paths(), + PreoptBootClassPathDexLocations: defaultBootImage.dexLocationsDeps, PreoptExtractedApk: false, diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index a29665e54..5e72cee7c 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -22,7 +22,6 @@ import ( "android/soong/android" "android/soong/dexpreopt" - "github.com/google/blueprint/pathtools" "github.com/google/blueprint/proptools" ) @@ -50,38 +49,77 @@ func init() { // will then reconstruct the real path, so the rules must have a dependency on the real path. type bootImageConfig struct { - name string - stem string - modules []string - dexLocations []string - dexPaths android.WritablePaths - dir android.OutputPath - symbolsDir android.OutputPath - targets []android.Target - images map[android.ArchType]android.OutputPath - imagesDeps map[android.ArchType]android.Paths - zip android.WritablePath + // Whether this image is an extension. + extension bool + + // Image name (used in directory names and ninja rule names). + name string + + // Basename of the image: the resulting filenames are [-].{art,oat,vdex}. + stem string + + // Output directory for the image files. + dir android.OutputPath + + // Output directory for the image files with debug symbols. + symbolsDir android.OutputPath + + // Subdirectory where the image files are installed. + installSubdir string + + // Targets for which the image is generated. + targets []android.Target + + // The names of jars that constitute this image. + modules []string + + // The "locations" of jars. + dexLocations []string // for this image + dexLocationsDeps []string // for the dependency images and in this image + + // File paths to jars. + dexPaths android.WritablePaths // for this image + dexPathsDeps android.WritablePaths // for the dependency images and in this image + + // The "locations" of the dependency images and in this image. + imageLocations []string + + // Paths to image files (grouped by target). + images map[android.ArchType]android.OutputPath // first image file + imagesDeps map[android.ArchType]android.OutputPaths // all files + + // File path to a zip archive with all image files (or nil, if not needed). + zip android.WritablePath } -func (image bootImageConfig) moduleFiles(ctx android.PathContext, dir android.OutputPath, exts ...string) []android.OutputPath { - ret := make([]android.OutputPath, 0, len(image.modules)*len(exts)) - - // dex preopt on the bootclasspath produces multiple files. The first dex file - // is converted into to 'name'.art (to match the legacy assumption that 'name'.art +func (image bootImageConfig) moduleName(idx int) string { + // Dexpreopt on the boot class path produces multiple files. The first dex file + // is converted into 'name'.art (to match the legacy assumption that 'name'.art // exists), and the rest are converted to 'name'-.art. - // In addition, each .art file has an associated .oat and .vdex file, and an - // unstripped .oat file - for i, m := range image.modules { - name := image.stem - if i != 0 { - name += "-" + stemOf(m) - } + m := image.modules[idx] + name := image.stem + if idx != 0 || image.extension { + name += "-" + stemOf(m) + } + return name +} +func (image bootImageConfig) firstModuleNameOrStem() string { + if len(image.modules) > 0 { + return image.moduleName(0) + } else { + return image.stem + } +} + +func (image bootImageConfig) moduleFiles(ctx android.PathContext, dir android.OutputPath, exts ...string) android.OutputPaths { + ret := make(android.OutputPaths, 0, len(image.modules)*len(exts)) + for i := range image.modules { + name := image.moduleName(i) for _, ext := range exts { ret = append(ret, dir.Join(ctx, name+ext)) } } - return ret } @@ -140,12 +178,6 @@ func skipDexpreoptBootJars(ctx android.PathContext) bool { return false } -func skipDexpreoptArtBootJars(ctx android.BuilderContext) bool { - // with EMMA_INSTRUMENT_FRAMEWORK=true ART boot class path libraries have dependencies on framework, - // therefore dexpreopt ART libraries cannot be dexpreopted in isolation => no ART boot image - return ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") -} - type dexpreoptBootJars struct { defaultBootImage *bootImage otherImages []*bootImage @@ -154,8 +186,8 @@ type dexpreoptBootJars struct { } // Accessor function for the apex package. Returns nil if dexpreopt is disabled. -func DexpreoptedArtApexJars(ctx android.BuilderContext) map[android.ArchType]android.Paths { - if skipDexpreoptBootJars(ctx) || skipDexpreoptArtBootJars(ctx) { +func DexpreoptedArtApexJars(ctx android.BuilderContext) map[android.ArchType]android.OutputPaths { + if skipDexpreoptBootJars(ctx) { return nil } return artBootImageConfig(ctx).imagesDeps @@ -184,10 +216,8 @@ func (d *dexpreoptBootJars) GenerateBuildActions(ctx android.SingletonContext) { // Always create the default boot image first, to get a unique profile rule for all images. d.defaultBootImage = buildBootImage(ctx, defaultBootImageConfig(ctx)) - if !skipDexpreoptArtBootJars(ctx) { - // Create boot image for the ART apex (build artifacts are accessed via the global boot image config). - buildBootImage(ctx, artBootImageConfig(ctx)) - } + // Create boot image for the ART apex (build artifacts are accessed via the global boot image config). + buildBootImage(ctx, artBootImageConfig(ctx)) if global.GenerateApexImage { // Create boot images for the JIT-zygote experiment. d.otherImages = append(d.otherImages, buildBootImage(ctx, apexBootImageConfig(ctx))) @@ -201,7 +231,6 @@ func buildBootImage(ctx android.SingletonContext, config bootImageConfig) *bootI image := newBootImage(ctx, config) bootDexJars := make(android.Paths, len(image.modules)) - ctx.VisitAllModules(func(module android.Module) { // Collect dex jar paths for the modules listed above. if j, ok := module.(interface{ DexJar() android.Path }); ok { @@ -265,11 +294,12 @@ func buildBootImageRuleForArch(ctx android.SingletonContext, image *bootImage, global := dexpreoptGlobalConfig(ctx) - symbolsDir := image.symbolsDir.Join(ctx, "system/framework", arch.String()) + symbolsDir := image.symbolsDir.Join(ctx, image.installSubdir, arch.String()) symbolsFile := symbolsDir.Join(ctx, image.stem+".oat") - outputDir := image.dir.Join(ctx, "system/framework", arch.String()) - outputPath := image.images[arch] - oatLocation := pathtools.ReplaceExtension(dexpreopt.PathToLocation(outputPath, arch), "oat") + outputDir := image.dir.Join(ctx, image.installSubdir, arch.String()) + outputPath := outputDir.Join(ctx, image.stem+".oat") + oatLocation := dexpreopt.PathToLocation(outputPath, arch) + imagePath := outputPath.ReplaceExtension(ctx, "art") rule := android.NewRuleBuilder() rule.MissingDeps(missingDeps) @@ -312,18 +342,27 @@ func buildBootImageRuleForArch(ctx android.SingletonContext, image *bootImage, cmd.FlagWithInput("--dirty-image-objects=", global.DirtyImageObjects.Path()) } + if image.extension { + artImage := artBootImageConfig(ctx).images[arch] + cmd. + Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", image.dexPathsDeps.Paths(), ":"). + Flag("--runtime-arg").FlagWithList("-Xbootclasspath-locations:", image.dexLocationsDeps, ":"). + FlagWithArg("--boot-image=", dexpreopt.PathToLocation(artImage, arch)).Implicit(artImage) + } else { + cmd.FlagWithArg("--base=", ctx.Config().LibartImgDeviceBaseAddress()) + } + cmd. FlagForEachInput("--dex-file=", image.dexPaths.Paths()). FlagForEachArg("--dex-location=", image.dexLocations). Flag("--generate-debug-info"). Flag("--generate-build-id"). Flag("--image-format=lz4hc"). - FlagWithOutput("--oat-symbols=", symbolsFile). + FlagWithArg("--oat-symbols=", symbolsFile.String()). Flag("--strip"). - FlagWithOutput("--oat-file=", outputPath.ReplaceExtension(ctx, "oat")). + FlagWithArg("--oat-file=", outputPath.String()). FlagWithArg("--oat-location=", oatLocation). - FlagWithOutput("--image=", outputPath). - FlagWithArg("--base=", ctx.Config().LibartImgDeviceBaseAddress()). + FlagWithArg("--image=", imagePath.String()). FlagWithArg("--instruction-set=", arch.String()). FlagWithArg("--instruction-set-variant=", global.CpuVariant[arch]). FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch]). @@ -341,8 +380,8 @@ func buildBootImageRuleForArch(ctx android.SingletonContext, image *bootImage, cmd.Textf(`|| ( echo %s ; false )`, proptools.ShellEscape(failureMessage)) - installDir := filepath.Join("/system/framework", arch.String()) - vdexInstallDir := filepath.Join("/system/framework") + installDir := filepath.Join("/", image.installSubdir, arch.String()) + vdexInstallDir := filepath.Join("/", image.installSubdir) var vdexInstalls android.RuleBuilderInstalls var unstrippedInstalls android.RuleBuilderInstalls @@ -425,8 +464,8 @@ func bootImageProfileRule(ctx android.SingletonContext, image *bootImage, missin Text(`ANDROID_LOG_TAGS="*:e"`). Tool(tools.Profman). FlagWithInput("--create-profile-from=", bootImageProfile). - FlagForEachInput("--apk=", image.dexPaths.Paths()). - FlagForEachArg("--dex-location=", image.dexLocations). + FlagForEachInput("--apk=", image.dexPathsDeps.Paths()). + FlagForEachArg("--dex-location=", image.dexLocationsDeps). FlagWithOutput("--reference-profile-file=", profile) rule.Install(profile, "/system/etc/boot-image.prof") @@ -477,8 +516,8 @@ func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImage, mi Tool(tools.Profman). Flag("--generate-boot-profile"). FlagWithInput("--create-profile-from=", bootFrameworkProfile). - FlagForEachInput("--apk=", image.dexPaths.Paths()). - FlagForEachArg("--dex-location=", image.dexLocations). + FlagForEachInput("--apk=", image.dexPathsDeps.Paths()). + FlagForEachArg("--dex-location=", image.dexLocationsDeps). FlagWithOutput("--reference-profile-file=", profile) rule.Install(profile, "/system/etc/boot-image.bprof") @@ -506,8 +545,8 @@ func dumpOatRules(ctx android.SingletonContext, image *bootImage) { rule.Command(). // TODO: for now, use the debug version for better error reporting BuiltTool(ctx, "oatdumpd"). - FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPaths.Paths(), ":"). - FlagWithList("--runtime-arg -Xbootclasspath-locations:", image.dexLocations, ":"). + FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPathsDeps.Paths(), ":"). + FlagWithList("--runtime-arg -Xbootclasspath-locations:", image.dexLocationsDeps, ":"). FlagWithArg("--image=", dexpreopt.PathToLocation(image.images[arch], arch)).Implicit(image.images[arch]). FlagWithOutput("--output=", output). FlagWithArg("--instruction-set=", arch.String()) @@ -556,8 +595,9 @@ func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) { image := d.defaultBootImage if image != nil { ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", image.profileInstalls.String()) - ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(image.dexPaths.Strings(), " ")) - ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(image.dexLocations, " ")) + ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(image.dexPathsDeps.Strings(), " ")) + ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(image.dexLocationsDeps, " ")) + ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS", strings.Join(image.imageLocations, ":")) ctx.Strict("DEXPREOPT_IMAGE_ZIP_"+image.name, image.zip.String()) var imageNames []string diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go index 29a5abe7f..87d5e30f8 100644 --- a/java/dexpreopt_bootjars_test.go +++ b/java/dexpreopt_bootjars_test.go @@ -48,7 +48,7 @@ func TestDexpreoptBootJars(t *testing.T) { pathCtx := android.PathContextForTesting(config, nil) dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx) - dexpreoptConfig.ArtApexJars = []string{"foo", "bar", "baz"} + dexpreoptConfig.BootJars = []string{"foo", "bar", "baz"} setDexpreoptTestGlobalConfig(config, dexpreoptConfig) ctx := testContext(bp, nil) @@ -59,9 +59,10 @@ func TestDexpreoptBootJars(t *testing.T) { dexpreoptBootJars := ctx.SingletonForTests("dex_bootjars") - bootArt := dexpreoptBootJars.Output("boot.art") + bootArt := dexpreoptBootJars.Output("boot-foo.art") expectedInputs := []string{ + "dex_artjars/apex/com.android.art/javalib/arm64/boot.art", "dex_bootjars_input/foo.jar", "dex_bootjars_input/bar.jar", "dex_bootjars_input/baz.jar", @@ -82,19 +83,19 @@ func TestDexpreoptBootJars(t *testing.T) { expectedOutputs := []string{ "dex_bootjars/system/framework/arm64/boot.invocation", - "dex_bootjars/system/framework/arm64/boot.art", + "dex_bootjars/system/framework/arm64/boot-foo.art", "dex_bootjars/system/framework/arm64/boot-bar.art", "dex_bootjars/system/framework/arm64/boot-baz.art", - "dex_bootjars/system/framework/arm64/boot.oat", + "dex_bootjars/system/framework/arm64/boot-foo.oat", "dex_bootjars/system/framework/arm64/boot-bar.oat", "dex_bootjars/system/framework/arm64/boot-baz.oat", - "dex_bootjars/system/framework/arm64/boot.vdex", + "dex_bootjars/system/framework/arm64/boot-foo.vdex", "dex_bootjars/system/framework/arm64/boot-bar.vdex", "dex_bootjars/system/framework/arm64/boot-baz.vdex", - "dex_bootjars_unstripped/system/framework/arm64/boot.oat", + "dex_bootjars_unstripped/system/framework/arm64/boot-foo.oat", "dex_bootjars_unstripped/system/framework/arm64/boot-bar.oat", "dex_bootjars_unstripped/system/framework/arm64/boot-baz.oat", } diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go index 4dd7cfe80..57a770e1c 100644 --- a/java/dexpreopt_config.go +++ b/java/dexpreopt_config.go @@ -119,118 +119,147 @@ func getJarsFromApexJarPairs(apexJarPairs []string) []string { return modules } -// Construct a variant of the global config for dexpreopted bootclasspath jars. The variants differ -// in the list of input jars (libcore, framework, or both), in the naming scheme for the dexpreopt -// files (ART recognizes "apex" names as special), and whether to include a zip archive. -// -// 'name' is a string unique for each profile (used in directory names and ninja rule names) -// 'stem' is the basename of the image: the resulting filenames are [-].{art,oat,vdex}. -func getBootImageConfig(ctx android.PathContext, key android.OnceKey, name string, stem string, - needZip bool, artApexJarsOnly bool) bootImageConfig { +var ( + bootImageConfigKey = android.NewOnceKey("bootImageConfig") + artBootImageName = "art" + frameworkBootImageName = "boot" + apexBootImageName = "apex" +) + +// Construct the global boot image configs. +func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig { + return ctx.Config().Once(bootImageConfigKey, func() interface{} { - return ctx.Config().Once(key, func() interface{} { global := dexpreoptGlobalConfig(ctx) + targets := dexpreoptTargets(ctx) + deviceDir := android.PathForOutput(ctx, ctx.Config().DeviceName()) artModules := global.ArtApexJars - imageModules := artModules + // In coverage builds ART boot class path jars are instrumented and have additional dependencies. + if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") { + artModules = append(artModules, "jacocoagent") + } + frameworkModules := android.RemoveListFromList(global.BootJars, + concat(artModules, getJarsFromApexJarPairs(global.UpdatableBootJars))) - var bootLocations []string + artSubdir := "apex/com.android.art/javalib" + frameworkSubdir := "system/framework" + var artLocations, frameworkLocations []string for _, m := range artModules { - bootLocations = append(bootLocations, - filepath.Join("/apex/com.android.art/javalib", stemOf(m)+".jar")) + artLocations = append(artLocations, filepath.Join("/"+artSubdir, stemOf(m)+".jar")) + } + for _, m := range frameworkModules { + frameworkLocations = append(frameworkLocations, filepath.Join("/"+frameworkSubdir, stemOf(m)+".jar")) } - if !artApexJarsOnly { - nonFrameworkModules := concat(artModules, getJarsFromApexJarPairs(global.UpdatableBootJars)) - frameworkModules := android.RemoveListFromList(global.BootJars, nonFrameworkModules) - imageModules = concat(imageModules, frameworkModules) + // 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, + } - for _, m := range frameworkModules { - bootLocations = append(bootLocations, - filepath.Join("/system/framework", stemOf(m)+".jar")) + // 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...), + } + + // Apex config for the boot image used in the JIT-zygote experiment. + // It includes both the Core libraries and framework. + apexCfg := bootImageConfig{ + extension: false, + name: apexBootImageName, + stem: "apex", + installSubdir: frameworkSubdir, + modules: concat(artModules, frameworkModules), + dexLocations: concat(artLocations, frameworkLocations), + dexLocationsDeps: concat(artLocations, frameworkLocations), + } + + configs := map[string]*bootImageConfig{ + artBootImageName: &artCfg, + frameworkBootImageName: &frameworkCfg, + apexBootImageName: &apexCfg, + } + + // 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 .art for primary image and -<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") } } - // 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 - var bootDexPaths android.WritablePaths - for _, m := range imageModules { - bootDexPaths = append(bootDexPaths, - android.PathForOutput(ctx, ctx.Config().DeviceName(), "dex_"+name+"jars_input", m+".jar")) - } + // specific to the framework config + frameworkCfg.dexPathsDeps = append(artCfg.dexPathsDeps, frameworkCfg.dexPathsDeps...) + frameworkCfg.imageLocations = append(artCfg.imageLocations, frameworkCfg.imageLocations...) + frameworkCfg.zip = frameworkCfg.dir.Join(ctx, frameworkCfg.stem+".zip") - dir := android.PathForOutput(ctx, ctx.Config().DeviceName(), "dex_"+name+"jars") - symbolsDir := android.PathForOutput(ctx, ctx.Config().DeviceName(), "dex_"+name+"jars_unstripped") - - var zip android.WritablePath - if needZip { - zip = dir.Join(ctx, stem+".zip") - } - - targets := dexpreoptTargets(ctx) - - imageConfig := bootImageConfig{ - name: name, - stem: stem, - modules: imageModules, - dexLocations: bootLocations, - dexPaths: bootDexPaths, - dir: dir, - symbolsDir: symbolsDir, - targets: targets, - images: make(map[android.ArchType]android.OutputPath), - imagesDeps: make(map[android.ArchType]android.Paths), - zip: zip, - } - - for _, target := range targets { - imageDir := dir.Join(ctx, "system/framework", target.Arch.ArchType.String()) - imageConfig.images[target.Arch.ArchType] = imageDir.Join(ctx, stem+".art") - - imagesDeps := make([]android.Path, 0, len(imageConfig.modules)*3) - for _, dep := range imageConfig.moduleFiles(ctx, imageDir, ".art", ".oat", ".vdex") { - imagesDeps = append(imagesDeps, dep) - } - imageConfig.imagesDeps[target.Arch.ArchType] = imagesDeps - } - - return imageConfig - }).(bootImageConfig) + return configs + }).(map[string]*bootImageConfig) } -// Default config is the one that goes in the system image. It includes both libcore and framework. -var defaultBootImageConfigKey = android.NewOnceKey("defaultBootImageConfig") - -func defaultBootImageConfig(ctx android.PathContext) bootImageConfig { - return getBootImageConfig(ctx, defaultBootImageConfigKey, "boot", "boot", true, false) -} - -// Apex config is used for the JIT-zygote experiment. It includes both libcore and framework, but AOT-compiles only libcore. -var apexBootImageConfigKey = android.NewOnceKey("apexBootImageConfig") - -func apexBootImageConfig(ctx android.PathContext) bootImageConfig { - return getBootImageConfig(ctx, apexBootImageConfigKey, "apex", "apex", false, false) -} - -// ART config is the one used for the ART apex. It includes only libcore. -var artBootImageConfigKey = android.NewOnceKey("artBootImageConfig") - func artBootImageConfig(ctx android.PathContext) bootImageConfig { - return getBootImageConfig(ctx, artBootImageConfigKey, "art", "boot", false, true) + return *genBootImageConfigs(ctx)[artBootImageName] +} + +func defaultBootImageConfig(ctx android.PathContext) bootImageConfig { + return *genBootImageConfigs(ctx)[frameworkBootImageName] +} + +func apexBootImageConfig(ctx android.PathContext) bootImageConfig { + return *genBootImageConfigs(ctx)[apexBootImageName] } 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.dexLocations), updatableBootclasspath...) + + bootclasspath := append(copyOf(image.dexLocationsDeps), updatableBootclasspath...) return bootclasspath }) } @@ -245,7 +274,7 @@ func init() { func dexpreoptConfigMakevars(ctx android.MakeVarsContext) { ctx.Strict("PRODUCT_BOOTCLASSPATH", strings.Join(defaultBootclasspath(ctx), ":")) - ctx.Strict("PRODUCT_DEX2OAT_BOOTCLASSPATH", strings.Join(defaultBootImageConfig(ctx).dexLocations, ":")) + 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, ":"))