Generate empty classpaths.proto for bootclasspath_fragment.go.

- Adds all required details for bootclasspath_fragment to implement
  classpath_fragment.
- Keeps the actual boot jars in platform-bootclasspath to begin with.
- Makes sure to put the file in apex/etc/classpath on device. Note that
  for platform versions of classpath fragment AndroidMkEntries perform
  the installation, while for APEXes it must be plumbed via apex.go.

Bug: 180105615
Test: m && launch_cvd; atest CtsClasspathsTestCases
Change-Id: I6101ebdf5b8bcbe95c0b7ce21f3f67a2685aef50
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 6270b5b..bed629d 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -109,6 +109,8 @@
 	android.ModuleBase
 	android.ApexModuleBase
 	android.SdkBase
+	ClasspathFragmentBase
+
 	properties bootclasspathFragmentProperties
 }
 
@@ -117,6 +119,7 @@
 	m.AddProperties(&m.properties)
 	android.InitApexModule(m)
 	android.InitSdkAwareModule(m)
+	initClasspathFragment(m, BOOTCLASSPATH)
 	android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibCommon)
 
 	android.AddLoadHook(m, func(ctx android.LoadHookContext) {
@@ -242,6 +245,22 @@
 // BootclasspathFragmentApexContentInfo contains the bootclasspath_fragments contributions to the
 // apex contents.
 type BootclasspathFragmentApexContentInfo struct {
+	// ClasspathFragmentProtoOutput is an output path for the generated classpaths.proto config of this module.
+	//
+	// The file should be copied to a relevant place on device, see ClasspathFragmentProtoInstallDir
+	// for more details.
+	ClasspathFragmentProtoOutput android.OutputPath
+
+	// ClasspathFragmentProtoInstallDir contains information about on device location for the generated classpaths.proto file.
+	//
+	// The path encodes expected sub-location within partitions, i.e. etc/classpaths/<proto-file>,
+	// for ClasspathFragmentProtoOutput. To get sub-location, instead of the full output / make path
+	// use android.InstallPath#Rel().
+	//
+	// This is only relevant for APEX modules as they perform their own installation; while regular
+	// system files are installed via ClasspathFragmentBase#androidMkEntries().
+	ClasspathFragmentProtoInstallDir android.InstallPath
+
 	// The image config, internal to this module (and the dex_bootjars singleton).
 	//
 	// Will be nil if the BootclasspathFragmentApexContentInfo has not been provided for a specific module. That can occur
@@ -339,30 +358,47 @@
 		b.bootclasspathImageNameContentsConsistencyCheck(ctx)
 	}
 
+	// Generate classpaths.proto config
+	b.generateClasspathProtoBuildActions(ctx)
+
 	// Perform hidden API processing.
 	b.generateHiddenAPIBuildActions(ctx)
 
-	// Nothing to do if skipping the dexpreopt of boot image jars.
-	if SkipDexpreoptBootJars(ctx) {
-		return
-	}
-
-	// Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars
-	// GenerateSingletonBuildActions method as it cannot create it for itself.
-	dexpreopt.GetGlobalSoongConfig(ctx)
-
-	imageConfig := b.getImageConfig(ctx)
-	if imageConfig == nil {
-		return
-	}
-
 	// Construct the boot image info from the config.
-	info := BootclasspathFragmentApexContentInfo{imageConfig: imageConfig}
+	info := BootclasspathFragmentApexContentInfo{
+		ClasspathFragmentProtoInstallDir: b.classpathFragmentBase().installDirPath,
+		ClasspathFragmentProtoOutput:     b.classpathFragmentBase().outputFilepath,
+		imageConfig:                      nil,
+	}
+
+	if !SkipDexpreoptBootJars(ctx) {
+		// Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars
+		// GenerateSingletonBuildActions method as it cannot create it for itself.
+		dexpreopt.GetGlobalSoongConfig(ctx)
+		info.imageConfig = b.getImageConfig(ctx)
+	}
 
 	// Make it available for other modules.
 	ctx.SetProvider(BootclasspathFragmentApexContentInfoProvider, info)
 }
 
+// generateClasspathProtoBuildActions generates all required build actions for classpath.proto config
+func (b *BootclasspathFragmentModule) generateClasspathProtoBuildActions(ctx android.ModuleContext) {
+	var classpathJars []classpathJar
+	if "art" == proptools.String(b.properties.Image_name) {
+		// ART and platform boot jars must have a corresponding entry in DEX2OATBOOTCLASSPATH
+		classpathJars = configuredJarListToClasspathJars(ctx, b.ClasspathFragmentToConfiguredJarList(ctx), BOOTCLASSPATH, DEX2OATBOOTCLASSPATH)
+	} else {
+		classpathJars = configuredJarListToClasspathJars(ctx, b.ClasspathFragmentToConfiguredJarList(ctx), b.classpathType)
+	}
+	b.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, classpathJars)
+}
+
+func (b *BootclasspathFragmentModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList {
+	// TODO(satayev): populate with actual content
+	return android.EmptyConfiguredJarList()
+}
+
 func (b *BootclasspathFragmentModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig {
 	// Get a map of the image configs that are supported.
 	imageConfigs := genBootImageConfigs(ctx)