DO NOT MERGE - Merge RQ3A.210605.005

Bug: 190855093
Merged-In: Ie1f9147e02f79062d1a17dca5f61ff518a2ae5a6
Change-Id: I34d36eeeef40d372c0585b90685a2cee7e37a1a8
diff --git a/android/arch.go b/android/arch.go
index 1fbba19..340f136 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -1572,20 +1572,20 @@
 // with Neon will break those users.
 func getNdkAbisConfig() []archConfig {
 	return []archConfig{
-		{"arm", "armv7-a", "", []string{"armeabi-v7a"}},
 		{"arm64", "armv8-a-branchprot", "", []string{"arm64-v8a"}},
-		{"x86", "", "", []string{"x86"}},
+		{"arm", "armv7-a", "", []string{"armeabi-v7a"}},
 		{"x86_64", "", "", []string{"x86_64"}},
+		{"x86", "", "", []string{"x86"}},
 	}
 }
 
 // getAmlAbisConfig returns a list of archConfigs for the ABIs supported by mainline modules.
 func getAmlAbisConfig() []archConfig {
 	return []archConfig{
-		{"arm", "armv7-a-neon", "", []string{"armeabi-v7a"}},
 		{"arm64", "armv8-a", "", []string{"arm64-v8a"}},
-		{"x86", "", "", []string{"x86"}},
+		{"arm", "armv7-a-neon", "", []string{"armeabi-v7a"}},
 		{"x86_64", "", "", []string{"x86_64"}},
+		{"x86", "", "", []string{"x86"}},
 	}
 }
 
diff --git a/android/neverallow.go b/android/neverallow.go
index 41b399a..19b58a7 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -55,6 +55,7 @@
 	AddNeverAllowRules(createCcSdkVariantRules()...)
 	AddNeverAllowRules(createUncompressDexRules()...)
 	AddNeverAllowRules(createMakefileGoalRules()...)
+	AddNeverAllowRules(createInitFirstStageRules()...)
 }
 
 // Add a NeverAllow rule to the set of rules to apply.
@@ -216,6 +217,15 @@
 	}
 }
 
+func createInitFirstStageRules() []Rule {
+	return []Rule{
+		NeverAllow().
+			Without("name", "init_first_stage").
+			With("install_in_root", "true").
+			Because("install_in_root is only for init_first_stage."),
+	}
+}
+
 func neverallowMutator(ctx BottomUpMutatorContext) {
 	m, ok := ctx.Module().(Module)
 	if !ok {
diff --git a/apex/Android.bp b/apex/Android.bp
index 14c8771..6269757 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -31,6 +31,7 @@
     testSrcs: [
         "apex_test.go",
         "bootclasspath_fragment_test.go",
+        "classpath_element_test.go",
         "platform_bootclasspath_test.go",
         "systemserver_classpath_fragment_test.go",
         "vndk_test.go",
diff --git a/apex/classpath_element_test.go b/apex/classpath_element_test.go
new file mode 100644
index 0000000..0193127
--- /dev/null
+++ b/apex/classpath_element_test.go
@@ -0,0 +1,317 @@
+// 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 (
+	"reflect"
+	"testing"
+
+	"android/soong/android"
+	"android/soong/java"
+	"github.com/google/blueprint"
+)
+
+// Contains tests for java.CreateClasspathElements logic from java/classpath_element.go that
+// requires apexes.
+
+// testClasspathElementContext is a ClasspathElementContext suitable for use in tests.
+type testClasspathElementContext struct {
+	testContext *android.TestContext
+	module      android.Module
+	errs        []error
+}
+
+func (t *testClasspathElementContext) OtherModuleHasProvider(module blueprint.Module, provider blueprint.ProviderKey) bool {
+	return t.testContext.ModuleHasProvider(module, provider)
+}
+
+func (t *testClasspathElementContext) OtherModuleProvider(module blueprint.Module, provider blueprint.ProviderKey) interface{} {
+	return t.testContext.ModuleProvider(module, provider)
+}
+
+func (t *testClasspathElementContext) ModuleErrorf(fmt string, args ...interface{}) {
+	t.errs = append(t.errs, t.testContext.ModuleErrorf(t.module, fmt, args...))
+}
+
+var _ java.ClasspathElementContext = (*testClasspathElementContext)(nil)
+
+func TestCreateClasspathElements(t *testing.T) {
+	preparer := android.GroupFixturePreparers(
+		prepareForTestWithPlatformBootclasspath,
+		prepareForTestWithArtApex,
+		prepareForTestWithMyapex,
+		// For otherapex.
+		android.FixtureMergeMockFs(android.MockFS{
+			"system/sepolicy/apex/otherapex-file_contexts": nil,
+		}),
+		java.PrepareForTestWithJavaSdkLibraryFiles,
+		java.FixtureWithLastReleaseApis("foo", "othersdklibrary"),
+		android.FixtureWithRootAndroidBp(`
+		apex {
+			name: "com.android.art",
+			key: "com.android.art.key",
+ 			bootclasspath_fragments: [
+				"art-bootclasspath-fragment",
+			],
+			java_libs: [
+				"othersdklibrary",
+			],
+			updatable: false,
+		}
+
+		apex_key {
+			name: "com.android.art.key",
+			public_key: "com.android.art.avbpubkey",
+			private_key: "com.android.art.pem",
+		}
+
+		bootclasspath_fragment {
+			name: "art-bootclasspath-fragment",
+			apex_available: [
+				"com.android.art",
+			],
+			contents: [
+				"baz",
+				"quuz",
+			],
+		}
+
+		java_library {
+			name: "baz",
+			apex_available: [
+				"com.android.art",
+			],
+			srcs: ["b.java"],
+			installable: true,
+		}
+
+		java_library {
+			name: "quuz",
+			apex_available: [
+				"com.android.art",
+			],
+			srcs: ["b.java"],
+			installable: true,
+		}
+
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+ 			bootclasspath_fragments: [
+				"mybootclasspath-fragment",
+			],
+			java_libs: [
+				"othersdklibrary",
+			],
+			updatable: false,
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		bootclasspath_fragment {
+			name: "mybootclasspath-fragment",
+			apex_available: [
+				"myapex",
+			],
+			contents: [
+				"bar",
+			],
+		}
+
+		java_library {
+			name: "bar",
+			srcs: ["b.java"],
+			installable: true,
+			apex_available: ["myapex"],
+			permitted_packages: ["bar"],
+		}
+
+		java_sdk_library {
+			name: "foo",
+			srcs: ["b.java"],
+		}
+
+		java_sdk_library {
+			name: "othersdklibrary",
+			srcs: ["b.java"],
+			shared_library: false,
+			apex_available: [
+				"com.android.art",
+				"myapex",
+			],
+		}
+
+		bootclasspath_fragment {
+			name: "non-apex-fragment",
+			contents: ["othersdklibrary"],
+		}
+
+		apex {
+			name: "otherapex",
+			key: "otherapex.key",
+			java_libs: [
+				"otherapexlibrary",
+			],
+			updatable: false,
+		}
+
+		apex_key {
+			name: "otherapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		java_library {
+			name: "otherapexlibrary",
+			srcs: ["b.java"],
+			installable: true,
+			apex_available: ["otherapex"],
+			permitted_packages: ["otherapexlibrary"],
+		}
+
+		platform_bootclasspath {
+			name: "myplatform-bootclasspath",
+
+			fragments: [
+				{
+					apex: "com.android.art",
+					module: "art-bootclasspath-fragment",
+				},
+			],
+		}
+	`),
+	)
+
+	result := preparer.RunTest(t)
+
+	artFragment := result.Module("art-bootclasspath-fragment", "android_common_apex10000")
+	artBaz := result.Module("baz", "android_common_apex10000")
+	artQuuz := result.Module("quuz", "android_common_apex10000")
+
+	myFragment := result.Module("mybootclasspath-fragment", "android_common_apex10000")
+	myBar := result.Module("bar", "android_common_apex10000")
+
+	nonApexFragment := result.Module("non-apex-fragment", "android_common")
+	other := result.Module("othersdklibrary", "android_common_apex10000")
+
+	otherApexLibrary := result.Module("otherapexlibrary", "android_common_apex10000")
+
+	platformFoo := result.Module("quuz", "android_common")
+
+	bootclasspath := result.Module("myplatform-bootclasspath", "android_common")
+
+	// Use a custom assertion method instead of AssertDeepEquals as the latter formats the output
+	// using %#v which results in meaningless output as ClasspathElements are pointers.
+	assertElementsEquals := func(t *testing.T, message string, expected, actual java.ClasspathElements) {
+		if !reflect.DeepEqual(expected, actual) {
+			t.Errorf("%s: expected:\n  %s\n got:\n  %s", message, expected, actual)
+		}
+	}
+
+	expectFragmentElement := func(module android.Module, contents ...android.Module) java.ClasspathElement {
+		return &java.ClasspathFragmentElement{module, contents}
+	}
+	expectLibraryElement := func(module android.Module) java.ClasspathElement {
+		return &java.ClasspathLibraryElement{module}
+	}
+
+	newCtx := func() *testClasspathElementContext {
+		return &testClasspathElementContext{testContext: result.TestContext, module: bootclasspath}
+	}
+
+	// Verify that CreateClasspathElements works when given valid input.
+	t.Run("art:baz, art:quuz, my:bar, foo", func(t *testing.T) {
+		ctx := newCtx()
+		elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, artQuuz, myBar, platformFoo}, []android.Module{artFragment, myFragment})
+		expectedElements := java.ClasspathElements{
+			expectFragmentElement(artFragment, artBaz, artQuuz),
+			expectFragmentElement(myFragment, myBar),
+			expectLibraryElement(platformFoo),
+		}
+		assertElementsEquals(t, "elements", expectedElements, elements)
+	})
+
+	// Verify that CreateClasspathElements detects when a fragment does not have an associated apex.
+	t.Run("non apex fragment", func(t *testing.T) {
+		ctx := newCtx()
+		elements := java.CreateClasspathElements(ctx, []android.Module{}, []android.Module{nonApexFragment})
+		android.FailIfNoMatchingErrors(t, "fragment non-apex-fragment{.*} is not part of an apex", ctx.errs)
+		expectedElements := java.ClasspathElements{}
+		assertElementsEquals(t, "elements", expectedElements, elements)
+	})
+
+	// Verify that CreateClasspathElements detects when an apex has multiple fragments.
+	t.Run("multiple fragments for same apex", func(t *testing.T) {
+		ctx := newCtx()
+		elements := java.CreateClasspathElements(ctx, []android.Module{}, []android.Module{artFragment, artFragment})
+		android.FailIfNoMatchingErrors(t, "apex com.android.art has multiple fragments, art-bootclasspath-fragment{.*} and art-bootclasspath-fragment{.*}", ctx.errs)
+		expectedElements := java.ClasspathElements{}
+		assertElementsEquals(t, "elements", expectedElements, elements)
+	})
+
+	// Verify that CreateClasspathElements detects when a library is in multiple fragments.
+	t.Run("library from multiple fragments", func(t *testing.T) {
+		ctx := newCtx()
+		elements := java.CreateClasspathElements(ctx, []android.Module{other}, []android.Module{artFragment, myFragment})
+		android.FailIfNoMatchingErrors(t, "library othersdklibrary{.*} is in two separate fragments, art-bootclasspath-fragment{.*} and mybootclasspath-fragment{.*}", ctx.errs)
+		expectedElements := java.ClasspathElements{}
+		assertElementsEquals(t, "elements", expectedElements, elements)
+	})
+
+	// Verify that CreateClasspathElements detects when a fragment's contents are not contiguous and
+	// are separated by a library from another fragment.
+	t.Run("discontiguous separated by fragment", func(t *testing.T) {
+		ctx := newCtx()
+		elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, myBar, artQuuz, platformFoo}, []android.Module{artFragment, myFragment})
+		expectedElements := java.ClasspathElements{
+			expectFragmentElement(artFragment, artBaz, artQuuz),
+			expectFragmentElement(myFragment, myBar),
+			expectLibraryElement(platformFoo),
+		}
+		assertElementsEquals(t, "elements", expectedElements, elements)
+		android.FailIfNoMatchingErrors(t, "libraries from the same fragment must be contiguous, however baz{.*} and quuz{os:android,arch:common,apex:apex10000} from fragment art-bootclasspath-fragment{.*} are separated by libraries from fragment mybootclasspath-fragment{.*} like bar{.*}", ctx.errs)
+	})
+
+	// Verify that CreateClasspathElements detects when a fragment's contents are not contiguous and
+	// are separated by a standalone library.
+	t.Run("discontiguous separated by library", func(t *testing.T) {
+		ctx := newCtx()
+		elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, platformFoo, artQuuz, myBar}, []android.Module{artFragment, myFragment})
+		expectedElements := java.ClasspathElements{
+			expectFragmentElement(artFragment, artBaz, artQuuz),
+			expectLibraryElement(platformFoo),
+			expectFragmentElement(myFragment, myBar),
+		}
+		assertElementsEquals(t, "elements", expectedElements, elements)
+		android.FailIfNoMatchingErrors(t, "libraries from the same fragment must be contiguous, however baz{.*} and quuz{os:android,arch:common,apex:apex10000} from fragment art-bootclasspath-fragment{.*} are separated by library quuz{.*}", ctx.errs)
+	})
+
+	// Verify that CreateClasspathElements detects when there a library on the classpath that
+	// indicates it is from an apex the supplied fragments list does not contain a fragment for that
+	// apex.
+	t.Run("no fragment for apex", func(t *testing.T) {
+		ctx := newCtx()
+		elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, otherApexLibrary}, []android.Module{artFragment})
+		expectedElements := java.ClasspathElements{
+			expectFragmentElement(artFragment, artBaz),
+		}
+		assertElementsEquals(t, "elements", expectedElements, elements)
+		android.FailIfNoMatchingErrors(t, `library otherapexlibrary{.*} is from apexes \[otherapex\] which have no corresponding fragment in \[art-bootclasspath-fragment{.*}\]`, ctx.errs)
+	})
+}
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index ba7482c..aaa3a22 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -217,52 +217,57 @@
 	// apex specific variants of the exported java modules available for use from within make.
 	apexName := p.BaseModuleName()
 	for _, fi := range p.apexFilesForAndroidMk {
-		moduleName := fi.androidMkModuleName + "." + apexName
-		entries := android.AndroidMkEntries{
-			Class:        fi.class.nameInMake(),
-			OverrideName: moduleName,
-			OutputFile:   android.OptionalPathForPath(fi.builtFile),
-			Include:      "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
-			ExtraEntries: []android.AndroidMkExtraEntriesFunc{
-				func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
-					entries.SetString("LOCAL_MODULE_PATH", p.installDir.ToMakePath().String())
-
-					// soong_java_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .jar  Therefore
-					// we need to remove the suffix from LOCAL_MODULE_STEM, otherwise
-					// we will have foo.jar.jar
-					entries.SetString("LOCAL_MODULE_STEM", strings.TrimSuffix(fi.stem(), ".jar"))
-					var classesJar android.Path
-					var headerJar android.Path
-					if javaModule, ok := fi.module.(java.ApexDependency); ok {
-						classesJar = javaModule.ImplementationAndResourcesJars()[0]
-						headerJar = javaModule.HeaderJars()[0]
-					} else {
-						classesJar = fi.builtFile
-						headerJar = fi.builtFile
-					}
-					entries.SetString("LOCAL_SOONG_CLASSES_JAR", classesJar.String())
-					entries.SetString("LOCAL_SOONG_HEADER_JAR", headerJar.String())
-					entries.SetString("LOCAL_SOONG_DEX_JAR", fi.builtFile.String())
-					entries.SetString("LOCAL_DEX_PREOPT", "false")
-				},
-			},
-			ExtraFooters: []android.AndroidMkExtraFootersFunc{
-				func(w io.Writer, name, prefix, moduleDir string) {
-					// m <module_name> will build <module_name>.<apex_name> as well.
-					if fi.androidMkModuleName != moduleName {
-						fmt.Fprintf(w, ".PHONY: %s\n", fi.androidMkModuleName)
-						fmt.Fprintf(w, "%s: %s\n", fi.androidMkModuleName, moduleName)
-					}
-				},
-			},
-		}
-
+		entries := p.createEntriesForApexFile(fi, apexName)
 		entriesList = append(entriesList, entries)
 	}
 
 	return entriesList
 }
 
+// createEntriesForApexFile creates an AndroidMkEntries for the supplied apexFile
+func (p *prebuiltCommon) createEntriesForApexFile(fi apexFile, apexName string) android.AndroidMkEntries {
+	moduleName := fi.androidMkModuleName + "." + apexName
+	entries := android.AndroidMkEntries{
+		Class:        fi.class.nameInMake(),
+		OverrideName: moduleName,
+		OutputFile:   android.OptionalPathForPath(fi.builtFile),
+		Include:      "$(BUILD_SYSTEM)/soong_java_prebuilt.mk",
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+				entries.SetString("LOCAL_MODULE_PATH", p.installDir.ToMakePath().String())
+
+				// soong_java_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .jar  Therefore
+				// we need to remove the suffix from LOCAL_MODULE_STEM, otherwise
+				// we will have foo.jar.jar
+				entries.SetString("LOCAL_MODULE_STEM", strings.TrimSuffix(fi.stem(), ".jar"))
+				var classesJar android.Path
+				var headerJar android.Path
+				if javaModule, ok := fi.module.(java.ApexDependency); ok {
+					classesJar = javaModule.ImplementationAndResourcesJars()[0]
+					headerJar = javaModule.HeaderJars()[0]
+				} else {
+					classesJar = fi.builtFile
+					headerJar = fi.builtFile
+				}
+				entries.SetString("LOCAL_SOONG_CLASSES_JAR", classesJar.String())
+				entries.SetString("LOCAL_SOONG_HEADER_JAR", headerJar.String())
+				entries.SetString("LOCAL_SOONG_DEX_JAR", fi.builtFile.String())
+				entries.SetString("LOCAL_DEX_PREOPT", "false")
+			},
+		},
+		ExtraFooters: []android.AndroidMkExtraFootersFunc{
+			func(w io.Writer, name, prefix, moduleDir string) {
+				// m <module_name> will build <module_name>.<apex_name> as well.
+				if fi.androidMkModuleName != moduleName {
+					fmt.Fprintf(w, ".PHONY: %s\n", fi.androidMkModuleName)
+					fmt.Fprintf(w, "%s: %s\n", fi.androidMkModuleName, moduleName)
+				}
+			},
+		},
+	}
+	return entries
+}
+
 // prebuiltApexModuleCreator defines the methods that need to be implemented by prebuilt_apex and
 // apex_set in order to create the modules needed to provide access to the prebuilt .apex file.
 type prebuiltApexModuleCreator interface {
diff --git a/cc/cc.go b/cc/cc.go
index 49e218e..0c9f945 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -585,6 +585,7 @@
 	hostToolPath() android.OptionalPath
 	relativeInstallPath() string
 	makeUninstallable(mod *Module)
+	installInRoot() bool
 }
 
 // bazelHandler is the interface for a helper object related to deferring to Bazel for
@@ -1309,6 +1310,10 @@
 		Bool(c.sanitize.Properties.Sanitize.Config.Cfi_assembly_support)
 }
 
+func (c *Module) InstallInRoot() bool {
+	return c.installer != nil && c.installer.installInRoot()
+}
+
 type baseModuleContext struct {
 	android.BaseModuleContext
 	moduleContextImpl
diff --git a/cc/installer.go b/cc/installer.go
index e551c63..f95b493 100644
--- a/cc/installer.go
+++ b/cc/installer.go
@@ -25,6 +25,10 @@
 type InstallerProperties struct {
 	// install to a subdirectory of the default install path for the module
 	Relative_install_path *string `android:"arch_variant"`
+
+	// Install output directly in {partition}/, not in any subdir.  This is only intended for use by
+	// init_first_stage.
+	Install_in_root *bool `android:"arch_variant"`
 }
 
 type installLocation int
@@ -66,6 +70,11 @@
 	if ctx.toolchain().Is64Bit() && installer.dir64 != "" {
 		dir = installer.dir64
 	}
+
+	if installer.installInRoot() {
+		dir = ""
+	}
+
 	if ctx.Target().NativeBridge == android.NativeBridgeEnabled {
 		dir = filepath.Join(dir, ctx.Target().NativeBridgeRelativePath)
 	} else if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
@@ -110,3 +119,7 @@
 func (installer *baseInstaller) makeUninstallable(mod *Module) {
 	mod.ModuleBase.MakeUninstallable()
 }
+
+func (installer *baseInstaller) installInRoot() bool {
+	return Bool(installer.Properties.Install_in_root)
+}
diff --git a/cc/pgo.go b/cc/pgo.go
index 95c9c2e..e78549e 100644
--- a/cc/pgo.go
+++ b/cc/pgo.go
@@ -56,7 +56,7 @@
 type PgoProperties struct {
 	Pgo struct {
 		Instrumentation    *bool
-		Sampling           *bool
+		Sampling           *bool   `android:"arch_variant"`
 		Profile_file       *string `android:"arch_variant"`
 		Benchmarks         []string
 		Enable_profile_use *bool `android:"arch_variant"`
diff --git a/java/Android.bp b/java/Android.bp
index 680f3a1..5952602 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -33,6 +33,7 @@
         "bootclasspath.go",
         "bootclasspath_fragment.go",
         "builder.go",
+        "classpath_element.go",
         "classpath_fragment.go",
         "device_host_converter.go",
         "dex.go",
diff --git a/java/app.go b/java/app.go
index 81fa5f3..fc1ace0 100755
--- a/java/app.go
+++ b/java/app.go
@@ -925,6 +925,8 @@
 		&module.appProperties,
 		&module.overridableAppProperties)
 
+	module.usesLibrary.enforce = true
+
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
 	android.InitOverridableModule(module, &module.appProperties.Overrides)
@@ -1195,6 +1197,9 @@
 // with knowledge of their shared libraries.
 type usesLibrary struct {
 	usesLibraryProperties UsesLibraryProperties
+
+	// Whether to enforce verify_uses_library check.
+	enforce bool
 }
 
 func (u *usesLibrary) addLib(lib string, optional bool) {
@@ -1279,7 +1284,7 @@
 func (u *usesLibrary) enforceUsesLibraries() bool {
 	defaultEnforceUsesLibs := len(u.usesLibraryProperties.Uses_libs) > 0 ||
 		len(u.usesLibraryProperties.Optional_uses_libs) > 0
-	return BoolDefault(u.usesLibraryProperties.Enforce_uses_libs, defaultEnforceUsesLibs)
+	return BoolDefault(u.usesLibraryProperties.Enforce_uses_libs, u.enforce || defaultEnforceUsesLibs)
 }
 
 // Freeze the value of `enforce_uses_libs` based on the current values of `uses_libs` and `optional_uses_libs`.
diff --git a/java/app_import.go b/java/app_import.go
index 75b3292..6fe6204 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -470,6 +470,8 @@
 	android.InitDefaultableModule(module)
 	android.InitSingleSourcePrebuiltModule(module, &module.properties, "Apk")
 
+	module.usesLibrary.enforce = true
+
 	return module
 }
 
diff --git a/java/app_import_test.go b/java/app_import_test.go
index fc82e5b..024a3df 100644
--- a/java/app_import_test.go
+++ b/java/app_import_test.go
@@ -222,31 +222,31 @@
 			name:                "no preferred",
 			aaptPreferredConfig: nil,
 			aaptPrebuiltDPI:     []string{},
-			expected:            "prebuilts/apk/app.apk",
+			expected:            "verify_uses_libraries/apk/app.apk",
 		},
 		{
 			name:                "AAPTPreferredConfig matches",
 			aaptPreferredConfig: proptools.StringPtr("xhdpi"),
 			aaptPrebuiltDPI:     []string{"xxhdpi", "ldpi"},
-			expected:            "prebuilts/apk/app_xhdpi.apk",
+			expected:            "verify_uses_libraries/apk/app_xhdpi.apk",
 		},
 		{
 			name:                "AAPTPrebuiltDPI matches",
 			aaptPreferredConfig: proptools.StringPtr("mdpi"),
 			aaptPrebuiltDPI:     []string{"xxhdpi", "xhdpi"},
-			expected:            "prebuilts/apk/app_xxhdpi.apk",
+			expected:            "verify_uses_libraries/apk/app_xxhdpi.apk",
 		},
 		{
 			name:                "non-first AAPTPrebuiltDPI matches",
 			aaptPreferredConfig: proptools.StringPtr("mdpi"),
 			aaptPrebuiltDPI:     []string{"ldpi", "xhdpi"},
-			expected:            "prebuilts/apk/app_xhdpi.apk",
+			expected:            "verify_uses_libraries/apk/app_xhdpi.apk",
 		},
 		{
 			name:                "no matches",
 			aaptPreferredConfig: proptools.StringPtr("mdpi"),
 			aaptPrebuiltDPI:     []string{"ldpi", "xxxhdpi"},
-			expected:            "prebuilts/apk/app.apk",
+			expected:            "verify_uses_libraries/apk/app.apk",
 		},
 	}
 
@@ -266,7 +266,7 @@
 		if len(matches) != 2 {
 			t.Errorf("failed to extract the src apk path from %q", jniRuleCommand)
 		}
-		if test.expected != matches[1] {
+		if strings.HasSuffix(matches[1], test.expected) {
 			t.Errorf("wrong src apk, expected: %q got: %q", test.expected, matches[1])
 		}
 	}
@@ -342,7 +342,7 @@
 					},
 				}
 			`,
-			expected: "prebuilts/apk/app_arm64.apk",
+			expected: "verify_uses_libraries/apk/app_arm64.apk",
 		},
 		{
 			name: "no matching arch",
@@ -361,7 +361,7 @@
 					},
 				}
 			`,
-			expected: "prebuilts/apk/app.apk",
+			expected: "verify_uses_libraries/apk/app.apk",
 		},
 		{
 			name: "no matching arch without default",
@@ -399,7 +399,7 @@
 		if len(matches) != 2 {
 			t.Errorf("failed to extract the src apk path from %q", jniRuleCommand)
 		}
-		if test.expected != matches[1] {
+		if strings.HasSuffix(matches[1], test.expected) {
 			t.Errorf("wrong src apk, expected: %q got: %q", test.expected, matches[1])
 		}
 	}
diff --git a/java/classpath_element.go b/java/classpath_element.go
new file mode 100644
index 0000000..753e7f8
--- /dev/null
+++ b/java/classpath_element.go
@@ -0,0 +1,229 @@
+/*
+ * 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 java
+
+import (
+	"fmt"
+	"strings"
+
+	"android/soong/android"
+	"github.com/google/blueprint"
+)
+
+// Supports constructing a list of ClasspathElement from a set of fragments and modules.
+
+// ClasspathElement represents a component that contributes to a classpath. That can be
+// either a java module or a classpath fragment module.
+type ClasspathElement interface {
+	Module() android.Module
+	String() string
+}
+
+type ClasspathElements []ClasspathElement
+
+// ClasspathFragmentElement is a ClasspathElement that encapsulates a classpath fragment module.
+type ClasspathFragmentElement struct {
+	Fragment android.Module
+	Contents []android.Module
+}
+
+func (b *ClasspathFragmentElement) Module() android.Module {
+	return b.Fragment
+}
+
+func (b *ClasspathFragmentElement) String() string {
+	contents := []string{}
+	for _, module := range b.Contents {
+		contents = append(contents, module.String())
+	}
+	return fmt.Sprintf("fragment(%s, %s)", b.Fragment, strings.Join(contents, ", "))
+}
+
+var _ ClasspathElement = (*ClasspathFragmentElement)(nil)
+
+// ClasspathLibraryElement is a ClasspathElement that encapsulates a java library.
+type ClasspathLibraryElement struct {
+	Library android.Module
+}
+
+func (b *ClasspathLibraryElement) Module() android.Module {
+	return b.Library
+}
+
+func (b *ClasspathLibraryElement) String() string {
+	return fmt.Sprintf("library{%s}", b.Library)
+}
+
+var _ ClasspathElement = (*ClasspathLibraryElement)(nil)
+
+// ClasspathElementContext defines the context methods needed by CreateClasspathElements
+type ClasspathElementContext interface {
+	OtherModuleHasProvider(m blueprint.Module, provider blueprint.ProviderKey) bool
+	OtherModuleProvider(m blueprint.Module, provider blueprint.ProviderKey) interface{}
+	ModuleErrorf(fmt string, args ...interface{})
+}
+
+// CreateClasspathElements creates a list of ClasspathElement objects from a list of libraries and
+// a list of fragments.
+//
+// The libraries parameter contains the set of libraries from which the classpath is constructed.
+// The fragments parameter contains the classpath fragment modules whose contents are libraries that
+// are part of the classpath. Each library in the libraries parameter may be part of a fragment. The
+// determination as to which libraries belong to fragments and which do not is based on the apex to
+// which they belong, if any.
+//
+// Every fragment in the fragments list must be part of one or more apexes and each apex is assumed
+// to contain only a single fragment from the fragments list. A library in the libraries parameter
+// that is part of an apex must be provided by a classpath fragment in the corresponding apex.
+//
+// This will return a ClasspathElements list that contains a ClasspathElement for each standalone
+// library and each fragment. The order of the elements in the list is such that if the list was
+// flattened into a list of library modules that it would result in the same list or modules as the
+// input libraries. Flattening the list can be done by replacing each ClasspathFragmentElement in
+// the list with its Contents field.
+//
+// Requirements/Assumptions:
+// * A fragment can be associated with more than one apex but each apex must only be associated with
+//   a single fragment from the fragments list.
+// * All of a fragment's contents must appear as a contiguous block in the same order in the
+//   libraries list.
+// * Each library must only appear in a single fragment.
+//
+// The apex is used to identify which libraries belong to which fragment. First a mapping is created
+// from apex to fragment. Then the libraries are iterated over and any library in an apex is
+// associated with an element for the fragment to which it belongs. Otherwise, the libraries are
+// standalone and have their own element.
+//
+// e.g. Given the following input:
+//     libraries: com.android.art:core-oj, com.android.art:core-libart, framework, ext
+//     fragments: com.android.art:art-bootclasspath-fragment
+//
+// Then this will return:
+//     ClasspathFragmentElement(art-bootclasspath-fragment, [core-oj, core-libart]),
+//     ClasspathLibraryElement(framework),
+//     ClasspathLibraryElement(ext),
+func CreateClasspathElements(ctx ClasspathElementContext, libraries []android.Module, fragments []android.Module) ClasspathElements {
+	// Create a map from apex name to the fragment module. This makes it easy to find the fragment
+	// associated with a particular apex.
+	apexToFragment := map[string]android.Module{}
+	for _, fragment := range fragments {
+		if !ctx.OtherModuleHasProvider(fragment, android.ApexInfoProvider) {
+			ctx.ModuleErrorf("fragment %s is not part of an apex", fragment)
+			continue
+		}
+
+		apexInfo := ctx.OtherModuleProvider(fragment, android.ApexInfoProvider).(android.ApexInfo)
+		for _, apex := range apexInfo.InApexVariants {
+			if existing, ok := apexToFragment[apex]; ok {
+				ctx.ModuleErrorf("apex %s has multiple fragments, %s and %s", apex, fragment, existing)
+				continue
+			}
+			apexToFragment[apex] = fragment
+		}
+	}
+
+	fragmentToElement := map[android.Module]*ClasspathFragmentElement{}
+	elements := []ClasspathElement{}
+	var currentElement ClasspathElement
+
+skipLibrary:
+	// Iterate over the libraries to construct the ClasspathElements list.
+	for _, library := range libraries {
+		var element ClasspathElement
+		if ctx.OtherModuleHasProvider(library, android.ApexInfoProvider) {
+			apexInfo := ctx.OtherModuleProvider(library, android.ApexInfoProvider).(android.ApexInfo)
+
+			var fragment android.Module
+
+			// Make sure that the library is in only one fragment of the classpath.
+			for _, apex := range apexInfo.InApexVariants {
+				if f, ok := apexToFragment[apex]; ok {
+					if fragment == nil {
+						// This is the first fragment so just save it away.
+						fragment = f
+					} else if f != fragment {
+						// This apex variant of the library is in a different fragment.
+						ctx.ModuleErrorf("library %s is in two separate fragments, %s and %s", library, fragment, f)
+						// Skip over this library entirely as otherwise the resulting classpath elements would
+						// be invalid.
+						continue skipLibrary
+					}
+				} else {
+					// There is no fragment associated with the library's apex.
+				}
+			}
+
+			if fragment == nil {
+				ctx.ModuleErrorf("library %s is from apexes %s which have no corresponding fragment in %s",
+					library, apexInfo.InApexVariants, fragments)
+				// Skip over this library entirely as otherwise the resulting classpath elements would
+				// be invalid.
+				continue skipLibrary
+			} else if existingFragmentElement, ok := fragmentToElement[fragment]; ok {
+				// This library is in a fragment element that has already been added.
+
+				// If the existing fragment element is still the current element then this library is
+				// contiguous with other libraries in that fragment so there is nothing more to do.
+				// Otherwise this library is not contiguous with other libraries in the same fragment which
+				// is an error.
+				if existingFragmentElement != currentElement {
+					separator := ""
+					if fragmentElement, ok := currentElement.(*ClasspathFragmentElement); ok {
+						separator = fmt.Sprintf("libraries from fragment %s like %s", fragmentElement.Fragment, fragmentElement.Contents[0])
+					} else {
+						libraryElement := currentElement.(*ClasspathLibraryElement)
+						separator = fmt.Sprintf("library %s", libraryElement.Library)
+					}
+
+					// Get the library that precedes this library in the fragment. That is the last library as
+					// this library has not yet been added.
+					precedingLibraryInFragment := existingFragmentElement.Contents[len(existingFragmentElement.Contents)-1]
+					ctx.ModuleErrorf("libraries from the same fragment must be contiguous, however %s and %s from fragment %s are separated by %s",
+						precedingLibraryInFragment, library, fragment, separator)
+				}
+
+				// Add this library to the fragment element's contents.
+				existingFragmentElement.Contents = append(existingFragmentElement.Contents, library)
+			} else {
+				// This is the first library in this fragment so add a new element for the fragment,
+				// including the library.
+				fragmentElement := &ClasspathFragmentElement{
+					Fragment: fragment,
+					Contents: []android.Module{library},
+				}
+
+				// Store it away so we can detect when attempting to create another element for the same
+				// fragment.
+				fragmentToElement[fragment] = fragmentElement
+				element = fragmentElement
+			}
+		} else {
+			// The library is from the platform so just add an element for it.
+			element = &ClasspathLibraryElement{Library: library}
+		}
+
+		// If no element was created then it means that the library has been added to an existing
+		// fragment element so the list of elements and current element are unaffected.
+		if element != nil {
+			// Add the element to the list and make it the current element for the next iteration.
+			elements = append(elements, element)
+			currentElement = element
+		}
+	}
+
+	return elements
+}
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index f1c2d0d..a29d4c3 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -145,6 +145,9 @@
 	// If set to true, allow this module to be dexed and installed on devices.
 	Installable *bool
 
+	// Make this module available when building for ramdisk
+	Ramdisk_available *bool
+
 	// Make this module available when building for recovery
 	Recovery_available *bool
 
@@ -396,6 +399,7 @@
 	Recovery_available *bool
 	Vendor_available   *bool
 	Product_available  *bool
+	Ramdisk_available  *bool
 	Host_supported     *bool
 	Apex_available     []string
 	Min_sdk_version    *string
@@ -475,6 +479,7 @@
 	ccProps.Recovery_available = m.properties.Recovery_available
 	ccProps.Vendor_available = m.properties.Vendor_available
 	ccProps.Product_available = m.properties.Product_available
+	ccProps.Ramdisk_available = m.properties.Ramdisk_available
 	ccProps.Host_supported = m.properties.Host_supported
 	ccProps.Apex_available = m.ApexProperties.Apex_available
 	ccProps.Min_sdk_version = m.properties.Cpp.Min_sdk_version