Merge changes I8e8e8b01,Ifb1f54d5,I9986e64f

* changes:
  Add systemserverclasspath_fragments property to apex.
  Add "contents" property to systemserverclasspath_fragment.
  Move classpaths.proto related info into a separate provider.
diff --git a/apex/Android.bp b/apex/Android.bp
index e234181..14c8771 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -32,6 +32,7 @@
         "apex_test.go",
         "bootclasspath_fragment_test.go",
         "platform_bootclasspath_test.go",
+        "systemserver_classpath_fragment_test.go",
         "vndk_test.go",
     ],
     pluginFor: ["soong_build"],
diff --git a/apex/apex.go b/apex/apex.go
index a8fbf22..7b2e19d 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -102,6 +102,9 @@
 	// List of bootclasspath fragments that are embedded inside this APEX bundle.
 	Bootclasspath_fragments []string
 
+	// List of systemserverclasspath fragments that are embedded inside this APEX bundle.
+	Systemserverclasspath_fragments []string
+
 	// List of java libraries that are embedded inside this APEX bundle.
 	Java_libs []string
 
@@ -575,6 +578,7 @@
 	executableTag   = dependencyTag{name: "executable", payload: true}
 	fsTag           = dependencyTag{name: "filesystem", payload: true}
 	bcpfTag         = dependencyTag{name: "bootclasspathFragment", payload: true, sourceOnly: true}
+	sscpfTag        = dependencyTag{name: "systemserverclasspathFragment", payload: true, sourceOnly: true}
 	compatConfigTag = dependencyTag{name: "compatConfig", payload: true, sourceOnly: true}
 	javaLibTag      = dependencyTag{name: "javaLib", payload: true}
 	jniLibTag       = dependencyTag{name: "jniLib", payload: true}
@@ -755,6 +759,7 @@
 	// Common-arch dependencies come next
 	commonVariation := ctx.Config().AndroidCommonTarget.Variations()
 	ctx.AddFarVariationDependencies(commonVariation, bcpfTag, a.properties.Bootclasspath_fragments...)
+	ctx.AddFarVariationDependencies(commonVariation, sscpfTag, a.properties.Systemserverclasspath_fragments...)
 	ctx.AddFarVariationDependencies(commonVariation, javaLibTag, a.properties.Java_libs...)
 	ctx.AddFarVariationDependencies(commonVariation, bpfTag, a.properties.Bpfs...)
 	ctx.AddFarVariationDependencies(commonVariation, fsTag, a.properties.Filesystems...)
@@ -1715,6 +1720,15 @@
 					filesInfo = append(filesInfo, filesToAdd...)
 					return true
 				}
+			case sscpfTag:
+				{
+					if _, ok := child.(*java.SystemServerClasspathModule); !ok {
+						ctx.PropertyErrorf("systemserverclasspath_fragments", "%q is not a systemserverclasspath_fragment module", depName)
+						return false
+					}
+					filesInfo = append(filesInfo, apexClasspathFragmentProtoFile(ctx, child))
+					return true
+				}
 			case javaLibTag:
 				switch child.(type) {
 				case *java.Library, *java.SdkLibrary, *java.DexImport, *java.SdkLibraryImport, *java.Import:
@@ -1941,7 +1955,16 @@
 					default:
 						ctx.PropertyErrorf("bootclasspath_fragments", "bootclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child))
 					}
-
+				} else if java.IsSystemServerClasspathFragmentContentDepTag(depTag) {
+					// Add the contents of the systemserverclasspath fragment to the apex.
+					switch child.(type) {
+					case *java.Library, *java.SdkLibrary:
+						af := apexFileForJavaModule(ctx, child.(javaModule))
+						filesInfo = append(filesInfo, af)
+						return true // track transitive dependencies
+					default:
+						ctx.PropertyErrorf("systemserverclasspath_fragments", "systemserverclasspath_fragment content %q of type %q is not supported", depName, ctx.OtherModuleType(child))
+					}
 				} else if _, ok := depTag.(android.CopyDirectlyInAnyApexTag); ok {
 					// nothing
 				} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
@@ -2106,13 +2129,19 @@
 	}
 
 	// Add classpaths.proto config.
-	classpathProtoOutput := bootclasspathFragmentInfo.ClasspathFragmentProtoOutput
-	classpathProto := newApexFile(ctx, classpathProtoOutput, classpathProtoOutput.Base(), bootclasspathFragmentInfo.ClasspathFragmentProtoInstallDir.Rel(), etc, nil)
-	filesToAdd = append(filesToAdd, classpathProto)
+	filesToAdd = append(filesToAdd, apexClasspathFragmentProtoFile(ctx, module))
 
 	return filesToAdd
 }
 
+// apexClasspathFragmentProtoFile returns apexFile structure defining the classpath.proto config that
+// the module contributes to the apex.
+func apexClasspathFragmentProtoFile(ctx android.ModuleContext, module blueprint.Module) apexFile {
+	fragmentInfo := ctx.OtherModuleProvider(module, java.ClasspathFragmentProtoContentInfoProvider).(java.ClasspathFragmentProtoContentInfo)
+	classpathProtoOutput := fragmentInfo.ClasspathFragmentProtoOutput
+	return newApexFile(ctx, classpathProtoOutput, classpathProtoOutput.Base(), fragmentInfo.ClasspathFragmentProtoInstallDir.Rel(), etc, nil)
+}
+
 // apexFileForBootclasspathFragmentContentModule creates an apexFile for a bootclasspath_fragment
 // content module, i.e. a library that is part of the bootclasspath.
 func apexFileForBootclasspathFragmentContentModule(ctx android.ModuleContext, fragmentModule blueprint.Module, javaModule javaModule) apexFile {
diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go
new file mode 100644
index 0000000..e1a101a
--- /dev/null
+++ b/apex/systemserver_classpath_fragment_test.go
@@ -0,0 +1,78 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// 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 apex
+
+import (
+	"testing"
+
+	"android/soong/android"
+	"android/soong/java"
+)
+
+var prepareForTestWithSystemserverclasspathFragment = android.GroupFixturePreparers(
+	java.PrepareForTestWithDexpreopt,
+	PrepareForTestWithApexBuildComponents,
+)
+
+func TestSystemserverclasspathFragmentContents(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForTestWithSystemserverclasspathFragment,
+		prepareForTestWithMyapex,
+	).RunTestWithBp(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			systemserverclasspath_fragments: [
+				"mysystemserverclasspathfragment",
+			],
+			updatable: false,
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		java_library {
+			name: "foo",
+			srcs: ["b.java"],
+			installable: true,
+			apex_available: [
+				"myapex",
+			],
+		}
+
+		systemserverclasspath_fragment {
+			name: "mysystemserverclasspathfragment",
+			contents: [
+				"foo",
+			],
+			apex_available: [
+				"myapex",
+			],
+		}
+	`)
+
+	ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
+		"etc/classpaths/mysystemserverclasspathfragment.pb",
+		"javalib/foo.jar",
+	})
+
+	java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex_image", []string{
+		`myapex.key`,
+		`mysystemserverclasspathfragment`,
+	})
+}
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index b6b877b..5d8a8e5 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -268,22 +268,6 @@
 // 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
@@ -396,25 +380,19 @@
 	// Perform hidden API processing.
 	b.generateHiddenAPIBuildActions(ctx, contents)
 
-	// Construct the boot image info from the config.
-	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)
 
 		// Only generate the boot image if the configuration does not skip it.
 		b.generateBootImageBuildActions(ctx, contents)
-	}
 
-	// Make it available for other modules.
-	ctx.SetProvider(BootclasspathFragmentApexContentInfoProvider, info)
+		// Make the boot image info available for other modules
+		ctx.SetProvider(BootclasspathFragmentApexContentInfoProvider, BootclasspathFragmentApexContentInfo{
+			imageConfig: b.getImageConfig(ctx),
+		})
+	}
 }
 
 // generateClasspathProtoBuildActions generates all required build actions for classpath.proto config
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index 7422fa2..7408090 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -18,6 +18,7 @@
 
 import (
 	"fmt"
+	"github.com/google/blueprint"
 	"strings"
 
 	"android/soong/android"
@@ -120,6 +121,12 @@
 		FlagWithOutput("--output=", c.outputFilepath)
 
 	rule.Build("classpath_fragment", "Compiling "+c.outputFilepath.String())
+
+	classpathProtoInfo := ClasspathFragmentProtoContentInfo{
+		ClasspathFragmentProtoInstallDir: c.installDirPath,
+		ClasspathFragmentProtoOutput:     c.outputFilepath,
+	}
+	ctx.SetProvider(ClasspathFragmentProtoContentInfoProvider, classpathProtoInfo)
 }
 
 func writeClasspathsJson(ctx android.ModuleContext, output android.WritablePath, jars []classpathJar) {
@@ -157,3 +164,23 @@
 		},
 	}}
 }
+
+var ClasspathFragmentProtoContentInfoProvider = blueprint.NewProvider(ClasspathFragmentProtoContentInfo{})
+
+type ClasspathFragmentProtoContentInfo 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
+}
diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go
index cc5ff96..a505c6d 100644
--- a/java/systemserver_classpath_fragment.go
+++ b/java/systemserver_classpath_fragment.go
@@ -17,6 +17,7 @@
 import (
 	"android/soong/android"
 	"android/soong/dexpreopt"
+	"github.com/google/blueprint"
 )
 
 func init() {
@@ -66,24 +67,63 @@
 	}).(android.ConfiguredJarList)
 }
 
-type systemServerClasspathModule struct {
+type SystemServerClasspathModule struct {
 	android.ModuleBase
+	android.ApexModuleBase
 
 	ClasspathFragmentBase
+
+	properties systemServerClasspathFragmentProperties
+}
+
+func (s *SystemServerClasspathModule) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
+	return nil
+}
+
+type systemServerClasspathFragmentProperties struct {
+	// The contents of this systemserverclasspath_fragment, could be either java_library, or java_sdk_library.
+	//
+	// The order of this list matters as it is the order that is used in the SYSTEMSERVERCLASSPATH.
+	Contents []string
 }
 
 func systemServerClasspathFactory() android.Module {
-	m := &systemServerClasspathModule{}
+	m := &SystemServerClasspathModule{}
+	m.AddProperties(&m.properties)
+	android.InitApexModule(m)
 	initClasspathFragment(m, SYSTEMSERVERCLASSPATH)
 	android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
 	return m
 }
 
-func (s *systemServerClasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+func (s *SystemServerClasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	if len(s.properties.Contents) == 0 {
+		ctx.PropertyErrorf("contents", "empty contents are not allowed")
+	}
+
 	s.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJarListToClasspathJars(ctx, s.ClasspathFragmentToConfiguredJarList(ctx)))
 }
 
-func (s *systemServerClasspathModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList {
+func (s *SystemServerClasspathModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList {
 	// TODO(satayev): populate with actual content
 	return android.EmptyConfiguredJarList()
 }
+
+type systemServerClasspathFragmentContentDependencyTag struct {
+	blueprint.BaseDependencyTag
+}
+
+// The tag used for the dependency between the systemserverclasspath_fragment module and its contents.
+var systemServerClasspathFragmentContentDepTag = systemServerClasspathFragmentContentDependencyTag{}
+
+func IsSystemServerClasspathFragmentContentDepTag(tag blueprint.DependencyTag) bool {
+	return tag == systemServerClasspathFragmentContentDepTag
+}
+
+func (s *SystemServerClasspathModule) ComponentDepsMutator(ctx android.BottomUpMutatorContext) {
+	module := ctx.Module()
+
+	for _, name := range s.properties.Contents {
+		ctx.AddDependency(module, systemServerClasspathFragmentContentDepTag, name)
+	}
+}
diff --git a/java/systemserver_classpath_fragment_test.go b/java/systemserver_classpath_fragment_test.go
index 6126d5e..5272f27 100644
--- a/java/systemserver_classpath_fragment_test.go
+++ b/java/systemserver_classpath_fragment_test.go
@@ -20,13 +20,13 @@
 	"android/soong/android"
 )
 
-var prepareForTestWithSystemserverClasspath = android.GroupFixturePreparers(
+var prepareForTestWithSystemServerClasspath = android.GroupFixturePreparers(
 	PrepareForTestWithJavaDefaultModules,
 )
 
-func TestSystemserverClasspathVariant(t *testing.T) {
+func TestPlatformSystemserverClasspathVariant(t *testing.T) {
 	result := android.GroupFixturePreparers(
-		prepareForTestWithSystemserverClasspath,
+		prepareForTestWithSystemServerClasspath,
 		android.FixtureWithRootAndroidBp(`
 			platform_systemserverclasspath {
 				name: "platform-systemserverclasspath",
@@ -38,9 +38,9 @@
 	android.AssertIntEquals(t, "expect 1 variant", 1, len(variants))
 }
 
-func TestSystemserverClasspath_ClasspathFragmentPaths(t *testing.T) {
+func TestPlatformSystemserverClasspath_ClasspathFragmentPaths(t *testing.T) {
 	result := android.GroupFixturePreparers(
-		prepareForTestWithSystemserverClasspath,
+		prepareForTestWithSystemServerClasspath,
 		android.FixtureWithRootAndroidBp(`
 			platform_systemserverclasspath {
 				name: "platform-systemserverclasspath",
@@ -53,9 +53,9 @@
 	android.AssertPathRelativeToTopEquals(t, "install filepath", "out/soong/target/product/test_device/system/etc/classpaths", p.ClasspathFragmentBase.installDirPath)
 }
 
-func TestSystemserverClasspathModule_AndroidMkEntries(t *testing.T) {
+func TestPlatformSystemserverClasspathModule_AndroidMkEntries(t *testing.T) {
 	preparer := android.GroupFixturePreparers(
-		prepareForTestWithSystemserverClasspath,
+		prepareForTestWithSystemServerClasspath,
 		android.FixtureWithRootAndroidBp(`
 			platform_systemserverclasspath {
 				name: "platform-systemserverclasspath",
@@ -95,3 +95,14 @@
 		}
 	})
 }
+
+func TestSystemserverclasspathFragmentWithoutContents(t *testing.T) {
+	prepareForTestWithSystemServerClasspath.
+		ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(
+			`\Qempty contents are not allowed\E`)).
+		RunTestWithBp(t, `
+			systemserverclasspath_fragment {
+				name: "systemserverclasspath-fragment",
+			}
+		`)
+}