Merge "Revert^4 "Package dexpreopt artifacts for libcore jars in the ART apex.""
diff --git a/apex/apex.go b/apex/apex.go
index 477f917..f03a8f9 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -652,6 +652,7 @@
 
 	testApex        bool
 	vndkApex        bool
+	artApex         bool
 	primaryApexType bool
 
 	// intermediate path for apex_manifest.json
@@ -1261,6 +1262,19 @@
 		return false
 	})
 
+	// Specific to the ART apex: dexpreopt artifacts for libcore Java libraries.
+	// Build rules are generated by the dexpreopt singleton, and here we access build artifacts
+	// via the global boot image config.
+	if a.artApex {
+		for arch, files := range java.DexpreoptedArtApexJars(ctx) {
+			dirInApex := filepath.Join("javalib", arch.String())
+			for _, f := range files {
+				localModule := "javalib_" + arch.String() + "_" + filepath.Base(f.String())
+				filesInfo = append(filesInfo, apexFile{f, localModule, dirInApex, etc, nil, nil})
+			}
+		}
+	}
+
 	if a.private_key_file == nil {
 		ctx.PropertyErrorf("key", "private_key for %q could not be found", String(a.properties.Key))
 		return
@@ -1875,9 +1889,10 @@
 	return module
 }
 
-func ApexBundleFactory(testApex bool) android.Module {
+func ApexBundleFactory(testApex bool, artApex bool) android.Module {
 	bundle := newApexBundle()
 	bundle.testApex = testApex
+	bundle.artApex = artApex
 	return bundle
 }
 
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 74ef667..a29665e 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -51,6 +51,7 @@
 
 type bootImageConfig struct {
 	name         string
+	stem         string
 	modules      []string
 	dexLocations []string
 	dexPaths     android.WritablePaths
@@ -71,7 +72,7 @@
 	// 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.name
+		name := image.stem
 		if i != 0 {
 			name += "-" + stemOf(m)
 		}
@@ -139,6 +140,12 @@
 	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
@@ -146,6 +153,14 @@
 	dexpreoptConfigForMake android.WritablePath
 }
 
+// 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) {
+		return nil
+	}
+	return artBootImageConfig(ctx).imagesDeps
+}
+
 // dexpreoptBoot singleton rules
 func (d *dexpreoptBootJars) GenerateBuildActions(ctx android.SingletonContext) {
 	if skipDexpreoptBootJars(ctx) {
@@ -169,7 +184,12 @@
 
 	// 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))
+	}
 	if global.GenerateApexImage {
+		// Create boot images for the JIT-zygote experiment.
 		d.otherImages = append(d.otherImages, buildBootImage(ctx, apexBootImageConfig(ctx)))
 	}
 
@@ -178,8 +198,6 @@
 
 // buildBootImage takes a bootImageConfig, creates rules to build it, and returns a *bootImage.
 func buildBootImage(ctx android.SingletonContext, config bootImageConfig) *bootImage {
-	global := dexpreoptGlobalConfig(ctx)
-
 	image := newBootImage(ctx, config)
 
 	bootDexJars := make(android.Paths, len(image.modules))
@@ -223,12 +241,9 @@
 	bootFrameworkProfileRule(ctx, image, missingDeps)
 
 	var allFiles android.Paths
-
-	if !global.DisablePreopt {
-		for _, target := range image.targets {
-			files := buildBootImageRuleForArch(ctx, image, target.Arch.ArchType, profile, missingDeps)
-			allFiles = append(allFiles, files.Paths()...)
-		}
+	for _, target := range image.targets {
+		files := buildBootImageRuleForArch(ctx, image, target.Arch.ArchType, profile, missingDeps)
+		allFiles = append(allFiles, files.Paths()...)
 	}
 
 	if image.zip != nil {
@@ -251,7 +266,7 @@
 	global := dexpreoptGlobalConfig(ctx)
 
 	symbolsDir := image.symbolsDir.Join(ctx, "system/framework", arch.String())
-	symbolsFile := symbolsDir.Join(ctx, image.name+".oat")
+	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")
@@ -381,8 +396,9 @@
 	if global.DisableGenerateProfile || ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() {
 		return nil
 	}
-	return ctx.Config().Once(bootImageProfileRuleKey, func() interface{} {
+	profile := ctx.Config().Once(bootImageProfileRuleKey, func() interface{} {
 		tools := global.Tools
+		defaultProfile := "frameworks/base/config/boot-image-profile.txt"
 
 		rule := android.NewRuleBuilder()
 		rule.MissingDeps(missingDeps)
@@ -394,18 +410,13 @@
 			bootImageProfile = combinedBootImageProfile
 		} else if len(global.BootImageProfiles) == 1 {
 			bootImageProfile = global.BootImageProfiles[0]
+		} else if path := android.ExistentPathForSource(ctx, defaultProfile); path.Valid() {
+			bootImageProfile = path.Path()
 		} else {
-			// If not set, use the default.  Some branches like master-art-host don't have frameworks/base, so manually
-			// handle the case that the default is missing.  Those branches won't attempt to build the profile rule,
-			// and if they do they'll get a missing deps error.
-			defaultProfile := "frameworks/base/config/boot-image-profile.txt"
-			path := android.ExistentPathForSource(ctx, defaultProfile)
-			if path.Valid() {
-				bootImageProfile = path.Path()
-			} else {
-				missingDeps = append(missingDeps, defaultProfile)
-				bootImageProfile = android.PathForOutput(ctx, "missing")
-			}
+			// No profile (not even a default one, which is the case on some branches
+			// like master-art-host that don't have frameworks/base).
+			// Return nil and continue without profile.
+			return nil
 		}
 
 		profile := image.dir.Join(ctx, "boot.prof")
@@ -425,7 +436,11 @@
 		image.profileInstalls = rule.Installs()
 
 		return profile
-	}).(android.WritablePath)
+	})
+	if profile == nil {
+		return nil // wrap nil into a typed pointer with value nil
+	}
+	return profile.(android.WritablePath)
 }
 
 var bootImageProfileRuleKey = android.NewOnceKey("bootImageProfileRule")
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index 244bd52..a684ab2 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -62,7 +62,6 @@
 	bootArt := dexpreoptBootJars.Output("boot.art")
 
 	expectedInputs := []string{
-		"dex_bootjars/boot.prof",
 		"dex_bootjars_input/foo.jar",
 		"dex_bootjars_input/bar.jar",
 		"dex_bootjars_input/baz.jar",
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index b3b1317..a6661b3 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -106,15 +106,20 @@
 	return moduleName
 }
 
-func getBootImageConfig(ctx android.PathContext, key android.OnceKey, name string,
-	needZip bool) bootImageConfig {
+// 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 <stem>[-<jar>].{art,oat,vdex}.
+func getBootImageConfig(ctx android.PathContext, key android.OnceKey, name string, stem string,
+	needZip bool, artApexJarsOnly bool) bootImageConfig {
+
 	return ctx.Config().Once(key, func() interface{} {
 		global := dexpreoptGlobalConfig(ctx)
 
 		artModules := global.ArtApexJars
-		nonFrameworkModules := concat(artModules, global.ProductUpdatableBootModules)
-		frameworkModules := android.RemoveListFromList(global.BootJars, nonFrameworkModules)
-		imageModules := concat(artModules, frameworkModules)
+		imageModules := artModules
 
 		var bootLocations []string
 
@@ -123,9 +128,15 @@
 				filepath.Join("/apex/com.android.art/javalib", stemOf(m)+".jar"))
 		}
 
-		for _, m := range frameworkModules {
-			bootLocations = append(bootLocations,
-				filepath.Join("/system/framework", stemOf(m)+".jar"))
+		if !artApexJarsOnly {
+			nonFrameworkModules := concat(artModules, global.ProductUpdatableBootModules)
+			frameworkModules := android.RemoveListFromList(global.BootJars, nonFrameworkModules)
+			imageModules = concat(imageModules, frameworkModules)
+
+			for _, m := range frameworkModules {
+				bootLocations = append(bootLocations,
+					filepath.Join("/system/framework", stemOf(m)+".jar"))
+			}
 		}
 
 		// The path to bootclasspath dex files needs to be known at module GenerateAndroidBuildAction time, before
@@ -143,13 +154,14 @@
 
 		var zip android.WritablePath
 		if needZip {
-			zip = dir.Join(ctx, name+".zip")
+			zip = dir.Join(ctx, stem+".zip")
 		}
 
 		targets := dexpreoptTargets(ctx)
 
 		imageConfig := bootImageConfig{
 			name:         name,
+			stem:         stem,
 			modules:      imageModules,
 			dexLocations: bootLocations,
 			dexPaths:     bootDexPaths,
@@ -163,7 +175,7 @@
 
 		for _, target := range targets {
 			imageDir := dir.Join(ctx, "system/framework", target.Arch.ArchType.String())
-			imageConfig.images[target.Arch.ArchType] = imageDir.Join(ctx, name+".art")
+			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") {
@@ -176,15 +188,25 @@
 	}).(bootImageConfig)
 }
 
+// Default config is the one that goes in the system image. It includes both libcore and framework.
 var defaultBootImageConfigKey = android.NewOnceKey("defaultBootImageConfig")
-var apexBootImageConfigKey = android.NewOnceKey("apexBootImageConfig")
 
 func defaultBootImageConfig(ctx android.PathContext) bootImageConfig {
-	return getBootImageConfig(ctx, defaultBootImageConfigKey, "boot", true)
+	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", false)
+	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)
 }
 
 func defaultBootclasspath(ctx android.PathContext) []string {