Merge changes Ie274263a,I45993324

* changes:
  Adds droidstubs support to sdk module
  Simplify building an SDK snapshot from the command line
diff --git a/android/makevars.go b/android/makevars.go
index c011ea6..38a028c 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -80,6 +80,12 @@
 	// Eval().
 	StrictRaw(name, value string)
 	CheckRaw(name, value string)
+
+	// GlobWithDeps returns a list of files that match the specified pattern but do not match any
+	// of the patterns in excludes.  It also adds efficient dependencies to rerun the primary
+	// builder whenever a file matching the pattern as added or removed, without rerunning if a
+	// file that does not match the pattern is added to a searched directory.
+	GlobWithDeps(pattern string, excludes []string) ([]string, error)
 }
 
 var _ PathContext = MakeVarsContext(nil)
diff --git a/android/module.go b/android/module.go
index fa6388c..891babc 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1771,7 +1771,7 @@
 }
 
 // A module that implements OutputFileProducer can be referenced from any property that is tagged with `android:"path"`
-// using the ":module" syntax or ":module{.tag}" syntax and provides a list of otuput files to be used as if they were
+// using the ":module" syntax or ":module{.tag}" syntax and provides a list of output files to be used as if they were
 // listed in the property.
 type OutputFileProducer interface {
 	OutputFiles(tag string) (Paths, error)
diff --git a/apex/apex.go b/apex/apex.go
index 4dfbdb4..d7f6d53 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"path"
 	"path/filepath"
 	"sort"
 	"strings"
@@ -118,16 +119,11 @@
 func apexMutator(mctx android.BottomUpMutatorContext) {
 	if am, ok := mctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() {
 		am.CreateApexVariations(mctx)
-	} else if a, ok := mctx.Module().(*apexBundle); ok {
+	} else if _, ok := mctx.Module().(*apexBundle); ok {
 		// apex bundle itself is mutated so that it and its modules have same
 		// apex variant.
 		apexBundleName := mctx.ModuleName()
 		mctx.CreateVariations(apexBundleName)
-
-		// collects APEX list
-		if mctx.Device() && a.installable() {
-			addApexFileContextsInfos(mctx, a)
-		}
 	} else if o, ok := mctx.Module().(*OverrideApex); ok {
 		apexBundleName := o.GetOverriddenModuleName()
 		if apexBundleName == "" {
@@ -150,14 +146,11 @@
 	}).(*[]string)
 }
 
-func addApexFileContextsInfos(ctx android.BaseModuleContext, a *apexBundle) {
-	apexName := proptools.StringDefault(a.properties.Apex_name, ctx.ModuleName())
-	fileContextsName := proptools.StringDefault(a.properties.File_contexts, ctx.ModuleName())
-
+func addFlattenedFileContextsInfos(ctx android.BaseModuleContext, fileContextsInfo string) {
 	apexFileContextsInfosMutex.Lock()
 	defer apexFileContextsInfosMutex.Unlock()
 	apexFileContextsInfos := apexFileContextsInfos(ctx.Config())
-	*apexFileContextsInfos = append(*apexFileContextsInfos, apexName+":"+fileContextsName)
+	*apexFileContextsInfos = append(*apexFileContextsInfos, fileContextsInfo)
 }
 
 func apexFlattenedMutator(mctx android.BottomUpMutatorContext) {
@@ -272,10 +265,9 @@
 	Apex_name *string
 
 	// Determines the file contexts file for setting security context to each file in this APEX bundle.
-	// Specifically, when this is set to <value>, /system/sepolicy/apex/<value>_file_contexts file is
-	// used.
-	// Default: <name_of_this_module>
-	File_contexts *string
+	// For platform APEXes, this should points to a file under /system/sepolicy
+	// Default: /system/sepolicy/apex/<module_name>_file_contexts.
+	File_contexts *string `android:"path"`
 
 	// List of native shared libs that are embedded inside this APEX bundle
 	Native_shared_libs []string
@@ -481,6 +473,8 @@
 	container_certificate_file android.Path
 	container_private_key_file android.Path
 
+	fileContexts android.Path
+
 	// list of files to be included in this apex
 	filesInfo []apexFile
 
@@ -1168,12 +1162,29 @@
 	// prepend the name of this APEX to the module names. These names will be the names of
 	// modules that will be defined if the APEX is flattened.
 	for i := range filesInfo {
-		filesInfo[i].moduleName = filesInfo[i].moduleName + "." + ctx.ModuleName() + a.suffix
+		filesInfo[i].moduleName = filesInfo[i].moduleName + "." + a.Name() + a.suffix
 	}
 
 	a.installDir = android.PathForModuleInstall(ctx, "apex")
 	a.filesInfo = filesInfo
 
+	if a.properties.ApexType != zipApex {
+		if a.properties.File_contexts == nil {
+			a.fileContexts = android.PathForSource(ctx, "system/sepolicy/apex", ctx.ModuleName()+"-file_contexts")
+		} else {
+			a.fileContexts = android.PathForModuleSrc(ctx, *a.properties.File_contexts)
+			if a.Platform() {
+				if matched, err := path.Match("system/sepolicy/**/*", a.fileContexts.String()); err != nil || !matched {
+					ctx.PropertyErrorf("file_contexts", "should be under system/sepolicy, but %q", a.fileContexts)
+				}
+			}
+		}
+		if !android.ExistentPathForSource(ctx, a.fileContexts.String()).Valid() {
+			ctx.PropertyErrorf("file_contexts", "cannot find file_contexts file: %q", a.fileContexts)
+			return
+		}
+	}
+
 	// prepare apex_manifest.json
 	a.buildManifest(ctx, provideNativeLibs, requireNativeLibs)
 
@@ -1184,7 +1195,7 @@
 		a.buildUnflattenedApex(ctx)
 	}
 
-	apexName := proptools.StringDefault(a.properties.Apex_name, ctx.ModuleName())
+	apexName := proptools.StringDefault(a.properties.Apex_name, a.Name())
 	a.compatSymlinks = makeCompatSymlinks(apexName, ctx)
 }
 
diff --git a/apex/apex_test.go b/apex/apex_test.go
index f4b8e35..4d7777d 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -263,50 +263,57 @@
 			symbol_file: "",
 			native_bridge_supported: true,
 		}
+
+		filegroup {
+			name: "myapex-file_contexts",
+			srcs: [
+				"system/sepolicy/apex/myapex-file_contexts",
+			],
+		}
 	`
 	bp = bp + java.GatherRequiredDepsForTest()
 
 	fs := map[string][]byte{
-		"Android.bp":                                []byte(bp),
-		"a.java":                                    nil,
-		"PrebuiltAppFoo.apk":                        nil,
-		"PrebuiltAppFooPriv.apk":                    nil,
-		"build/make/target/product/security":        nil,
-		"apex_manifest.json":                        nil,
-		"AndroidManifest.xml":                       nil,
-		"system/sepolicy/apex/myapex-file_contexts": nil,
-		"system/sepolicy/apex/myapex_keytest-file_contexts": nil,
-		"system/sepolicy/apex/otherapex-file_contexts":      nil,
-		"system/sepolicy/apex/commonapex-file_contexts":     nil,
-		"mylib.cpp":                                  nil,
-		"mylib_common.cpp":                           nil,
-		"mytest.cpp":                                 nil,
-		"mytest1.cpp":                                nil,
-		"mytest2.cpp":                                nil,
-		"mytest3.cpp":                                nil,
-		"myprebuilt":                                 nil,
-		"my_include":                                 nil,
-		"foo/bar/MyClass.java":                       nil,
-		"prebuilt.jar":                               nil,
-		"vendor/foo/devkeys/test.x509.pem":           nil,
-		"vendor/foo/devkeys/test.pk8":                nil,
-		"testkey.x509.pem":                           nil,
-		"testkey.pk8":                                nil,
-		"testkey.override.x509.pem":                  nil,
-		"testkey.override.pk8":                       nil,
-		"vendor/foo/devkeys/testkey.avbpubkey":       nil,
-		"vendor/foo/devkeys/testkey.pem":             nil,
-		"NOTICE":                                     nil,
-		"custom_notice":                              nil,
-		"testkey2.avbpubkey":                         nil,
-		"testkey2.pem":                               nil,
-		"myapex-arm64.apex":                          nil,
-		"myapex-arm.apex":                            nil,
-		"frameworks/base/api/current.txt":            nil,
-		"framework/aidl/a.aidl":                      nil,
-		"build/make/core/proguard.flags":             nil,
-		"build/make/core/proguard_basic_keeps.flags": nil,
-		"dummy.txt":                                  nil,
+		"Android.bp":                                          []byte(bp),
+		"a.java":                                              nil,
+		"PrebuiltAppFoo.apk":                                  nil,
+		"PrebuiltAppFooPriv.apk":                              nil,
+		"build/make/target/product/security":                  nil,
+		"apex_manifest.json":                                  nil,
+		"AndroidManifest.xml":                                 nil,
+		"system/sepolicy/apex/myapex-file_contexts":           nil,
+		"system/sepolicy/apex/otherapex-file_contexts":        nil,
+		"system/sepolicy/apex/commonapex-file_contexts":       nil,
+		"system/sepolicy/apex/com.android.vndk-file_contexts": nil,
+		"mylib.cpp":                                           nil,
+		"mylib_common.cpp":                                    nil,
+		"mytest.cpp":                                          nil,
+		"mytest1.cpp":                                         nil,
+		"mytest2.cpp":                                         nil,
+		"mytest3.cpp":                                         nil,
+		"myprebuilt":                                          nil,
+		"my_include":                                          nil,
+		"foo/bar/MyClass.java":                                nil,
+		"prebuilt.jar":                                        nil,
+		"vendor/foo/devkeys/test.x509.pem":                    nil,
+		"vendor/foo/devkeys/test.pk8":                         nil,
+		"testkey.x509.pem":                                    nil,
+		"testkey.pk8":                                         nil,
+		"testkey.override.x509.pem":                           nil,
+		"testkey.override.pk8":                                nil,
+		"vendor/foo/devkeys/testkey.avbpubkey":                nil,
+		"vendor/foo/devkeys/testkey.pem":                      nil,
+		"NOTICE":                                              nil,
+		"custom_notice":                                       nil,
+		"testkey2.avbpubkey":                                  nil,
+		"testkey2.pem":                                        nil,
+		"myapex-arm64.apex":                                   nil,
+		"myapex-arm.apex":                                     nil,
+		"frameworks/base/api/current.txt":                     nil,
+		"framework/aidl/a.aidl":                               nil,
+		"build/make/core/proguard.flags":                      nil,
+		"build/make/core/proguard_basic_keeps.flags":          nil,
+		"dummy.txt":                                           nil,
 	}
 
 	for _, handler := range handlers {
@@ -1201,6 +1208,7 @@
 			key: "myapex.key",
 			certificate: ":myapex.certificate",
 			native_shared_libs: ["mylib"],
+			file_contexts: ":myapex-file_contexts",
 		}
 
 		cc_library {
@@ -1411,7 +1419,6 @@
 		apex_vndk {
 			name: "myapex",
 			key: "myapex.key",
-			file_contexts: "myapex",
 		}
 
 		apex_key {
@@ -1462,7 +1469,6 @@
 		apex_vndk {
 			name: "myapex",
 			key: "myapex.key",
-			file_contexts: "myapex",
 		}
 
 		apex_key {
@@ -1541,7 +1547,7 @@
 		apex_vndk {
 			name: "myapex_v27",
 			key: "myapex.key",
-			file_contexts: "myapex",
+			file_contexts: ":myapex-file_contexts",
 			vndk_version: "27",
 		}
 
@@ -1606,13 +1612,13 @@
 		apex_vndk {
 			name: "myapex_v27",
 			key: "myapex.key",
-			file_contexts: "myapex",
+			file_contexts: ":myapex-file_contexts",
 			vndk_version: "27",
 		}
 		apex_vndk {
 			name: "myapex_v27_other",
 			key: "myapex.key",
-			file_contexts: "myapex",
+			file_contexts: ":myapex-file_contexts",
 			vndk_version: "27",
 		}
 
@@ -1652,12 +1658,12 @@
 		apex_vndk {
 			name: "myapex",
 			key: "myapex.key",
-			file_contexts: "myapex",
+			file_contexts: ":myapex-file_contexts",
 		}
 		apex_vndk {
 			name: "myapex_v28",
 			key: "myapex.key",
-			file_contexts: "myapex",
+			file_contexts: ":myapex-file_contexts",
 			vndk_version: "28",
 		}
 		apex_key {
@@ -1683,7 +1689,7 @@
 		apex_vndk {
 			name: "myapex",
 			key: "myapex.key",
-			file_contexts: "myapex",
+			file_contexts: ":myapex-file_contexts",
 		}
 
 		apex_key {
@@ -1726,7 +1732,7 @@
 		apex_vndk {
 			name: "myapex",
 			key: "myapex.key",
-			file_contexts: "myapex",
+			file_contexts: ":myapex-file_contexts",
 			native_bridge_supported: true,
 		}
 
@@ -1756,7 +1762,7 @@
 		apex_vndk {
 			name: "myapex_v27",
 			key: "myapex.key",
-			file_contexts: "myapex",
+			file_contexts: ":myapex-file_contexts",
 			vndk_version: "27",
 		}
 
@@ -1822,7 +1828,7 @@
 			key: "myapex.key",
 			native_shared_libs: ["lib_nodep"],
 			compile_multilib: "both",
-			file_contexts: "myapex",
+			file_contexts: ":myapex-file_contexts",
 		}
 
 		apex {
@@ -1830,7 +1836,7 @@
 			key: "myapex.key",
 			native_shared_libs: ["lib_dep"],
 			compile_multilib: "both",
-			file_contexts: "myapex",
+			file_contexts: ":myapex-file_contexts",
 		}
 
 		apex {
@@ -1838,7 +1844,7 @@
 			key: "myapex.key",
 			native_shared_libs: ["libfoo"],
 			compile_multilib: "both",
-			file_contexts: "myapex",
+			file_contexts: ":myapex-file_contexts",
 		}
 
 		apex {
@@ -1846,7 +1852,7 @@
 			key: "myapex.key",
 			native_shared_libs: ["lib_dep", "libfoo"],
 			compile_multilib: "both",
-			file_contexts: "myapex",
+			file_contexts: ":myapex-file_contexts",
 		}
 
 		apex_key {
@@ -2145,6 +2151,7 @@
 			key: "myapex.key",
 			native_shared_libs: ["mylib"],
 			product_specific: true,
+			file_contexts: "myapex_file_contexts",
 		}
 
 		apex_key {
@@ -2160,7 +2167,9 @@
 			system_shared_libs: [],
 			stl: "none",
 		}
-	`)
+	`, withFiles(map[string][]byte{
+		"myapex_file_contexts": nil,
+	}))
 
 	apex := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
 	expected := buildDir + "/target/product/test_device/product/apex"
@@ -2170,6 +2179,112 @@
 	}
 }
 
+func TestFileContexts(t *testing.T) {
+	ctx, _ := testApex(t, `
+	apex {
+		name: "myapex",
+		key: "myapex.key",
+	}
+
+	apex_key {
+		name: "myapex.key",
+		public_key: "testkey.avbpubkey",
+		private_key: "testkey.pem",
+	}
+	`)
+	module := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	apexRule := module.Rule("apexRule")
+	actual := apexRule.Args["file_contexts"]
+	expected := "system/sepolicy/apex/myapex-file_contexts"
+	if actual != expected {
+		t.Errorf("wrong file_contexts. expected %q. actual %q", expected, actual)
+	}
+
+	testApexError(t, `"myapex" .*: file_contexts: should be under system/sepolicy`, `
+	apex {
+		name: "myapex",
+		key: "myapex.key",
+		file_contexts: "my_own_file_contexts",
+	}
+
+	apex_key {
+		name: "myapex.key",
+		public_key: "testkey.avbpubkey",
+		private_key: "testkey.pem",
+	}
+	`, withFiles(map[string][]byte{
+		"my_own_file_contexts": nil,
+	}))
+
+	testApexError(t, `"myapex" .*: file_contexts: cannot find`, `
+	apex {
+		name: "myapex",
+		key: "myapex.key",
+		product_specific: true,
+		file_contexts: "product_specific_file_contexts",
+	}
+
+	apex_key {
+		name: "myapex.key",
+		public_key: "testkey.avbpubkey",
+		private_key: "testkey.pem",
+	}
+	`)
+
+	ctx, _ = testApex(t, `
+	apex {
+		name: "myapex",
+		key: "myapex.key",
+		product_specific: true,
+		file_contexts: "product_specific_file_contexts",
+	}
+
+	apex_key {
+		name: "myapex.key",
+		public_key: "testkey.avbpubkey",
+		private_key: "testkey.pem",
+	}
+	`, withFiles(map[string][]byte{
+		"product_specific_file_contexts": nil,
+	}))
+	module = ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	apexRule = module.Rule("apexRule")
+	actual = apexRule.Args["file_contexts"]
+	expected = "product_specific_file_contexts"
+	if actual != expected {
+		t.Errorf("wrong file_contexts. expected %q. actual %q", expected, actual)
+	}
+
+	ctx, _ = testApex(t, `
+	apex {
+		name: "myapex",
+		key: "myapex.key",
+		product_specific: true,
+		file_contexts: ":my-file-contexts",
+	}
+
+	apex_key {
+		name: "myapex.key",
+		public_key: "testkey.avbpubkey",
+		private_key: "testkey.pem",
+	}
+
+	filegroup {
+		name: "my-file-contexts",
+		srcs: ["product_specific_file_contexts"],
+	}
+	`, withFiles(map[string][]byte{
+		"product_specific_file_contexts": nil,
+	}))
+	module = ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	apexRule = module.Rule("apexRule")
+	actual = apexRule.Args["file_contexts"]
+	expected = "product_specific_file_contexts"
+	if actual != expected {
+		t.Errorf("wrong file_contexts. expected %q. actual %q", expected, actual)
+	}
+}
+
 func TestApexKeyFromOtherModule(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex_key {
@@ -2819,7 +2934,7 @@
 }
 
 func TestOverrideApex(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx, config := testApex(t, `
 		apex {
 			name: "myapex",
 			key: "myapex.key",
@@ -2859,6 +2974,23 @@
 
 	ensureNotContains(t, copyCmds, "image.apex/app/app/app.apk")
 	ensureContains(t, copyCmds, "image.apex/app/app/override_app.apk")
+
+	apexBundle := module.Module().(*apexBundle)
+	name := apexBundle.Name()
+	if name != "override_myapex" {
+		t.Errorf("name should be \"override_myapex\", but was %q", name)
+	}
+
+	data := android.AndroidMkDataForTest(t, config, "", apexBundle)
+	var builder strings.Builder
+	data.Custom(&builder, name, "TARGET_", "", data)
+	androidMk := builder.String()
+	ensureContains(t, androidMk, "LOCAL_MODULE := app.override_myapex")
+	ensureContains(t, androidMk, "LOCAL_MODULE := apex_manifest.pb.override_myapex")
+	ensureContains(t, androidMk, "LOCAL_MODULE_STEM := override_myapex.apex")
+	ensureNotContains(t, androidMk, "LOCAL_MODULE := app.myapex")
+	ensureNotContains(t, androidMk, "LOCAL_MODULE := apex_manifest.pb.myapex")
+	ensureNotContains(t, androidMk, "LOCAL_MODULE_STEM := myapex.apex")
 }
 
 func TestMain(m *testing.M) {
diff --git a/apex/builder.go b/apex/builder.go
index b29bc2c..70f3e1a 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -244,7 +244,7 @@
 
 	apexType := a.properties.ApexType
 	suffix := apexType.suffix()
-	unsignedOutputFile := android.PathForModuleOut(ctx, ctx.ModuleName()+suffix+".unsigned")
+	unsignedOutputFile := android.PathForModuleOut(ctx, a.Name()+suffix+".unsigned")
 
 	filesToCopy := []android.Path{}
 	for _, f := range a.filesInfo {
@@ -253,7 +253,7 @@
 
 	copyCommands := []string{}
 	emitCommands := []string{}
-	imageContentFile := android.PathForModuleOut(ctx, ctx.ModuleName()+"-content.txt")
+	imageContentFile := android.PathForModuleOut(ctx, a.Name()+"-content.txt")
 	emitCommands = append(emitCommands, "echo ./apex_manifest.json >> "+imageContentFile.String())
 	for i, src := range filesToCopy {
 		dest := filepath.Join(a.filesInfo[i].installDir, src.Base())
@@ -284,7 +284,7 @@
 		implicitInputs = append(implicitInputs, imageContentFile)
 		whitelistedFilesFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.Whitelisted_files))
 
-		phonyOutput := android.PathForModuleOut(ctx, ctx.ModuleName()+"-diff-phony-output")
+		phonyOutput := android.PathForModuleOut(ctx, a.Name()+"-diff-phony-output")
 		ctx.Build(pctx, android.BuildParams{
 			Rule:        diffApexContentRule,
 			Implicits:   implicitInputs,
@@ -293,7 +293,7 @@
 			Args: map[string]string{
 				"whitelisted_files_file": whitelistedFilesFile.String(),
 				"image_content_file":     imageContentFile.String(),
-				"apex_module_name":       ctx.ModuleName(),
+				"apex_module_name":       a.Name(),
 			},
 		})
 
@@ -340,22 +340,13 @@
 			},
 		})
 
-		fcName := proptools.StringDefault(a.properties.File_contexts, ctx.ModuleName())
-		fileContextsPath := "system/sepolicy/apex/" + fcName + "-file_contexts"
-		fileContextsOptionalPath := android.ExistentPathForSource(ctx, fileContextsPath)
-		if !fileContextsOptionalPath.Valid() {
-			ctx.ModuleErrorf("Cannot find file_contexts file: %q", fileContextsPath)
-			return
-		}
-		fileContexts := fileContextsOptionalPath.Path()
-
 		optFlags := []string{}
 
 		// Additional implicit inputs.
-		implicitInputs = append(implicitInputs, cannedFsConfig, fileContexts, a.private_key_file, a.public_key_file)
+		implicitInputs = append(implicitInputs, cannedFsConfig, a.fileContexts, a.private_key_file, a.public_key_file)
 		optFlags = append(optFlags, "--pubkey "+a.public_key_file.String())
 
-		manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(ctx.ModuleName())
+		manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(a.Name())
 		if overridden {
 			optFlags = append(optFlags, "--override_apk_package_name "+manifestPackageName)
 		}
@@ -377,7 +368,7 @@
 		}
 		optFlags = append(optFlags, "--target_sdk_version "+targetSdkVersion)
 
-		noticeFile := a.buildNoticeFile(ctx, ctx.ModuleName()+suffix)
+		noticeFile := a.buildNoticeFile(ctx, a.Name()+suffix)
 		if noticeFile.Valid() {
 			// If there's a NOTICE file, embed it as an asset file in the APEX.
 			implicitInputs = append(implicitInputs, noticeFile.Path())
@@ -409,15 +400,15 @@
 				"manifest_json_full": a.manifestJsonFullOut.String(),
 				"manifest_json":      a.manifestJsonOut.String(),
 				"manifest":           a.manifestPbOut.String(),
-				"file_contexts":      fileContexts.String(),
+				"file_contexts":      a.fileContexts.String(),
 				"canned_fs_config":   cannedFsConfig.String(),
 				"key":                a.private_key_file.String(),
 				"opt_flags":          strings.Join(optFlags, " "),
 			},
 		})
 
-		apexProtoFile := android.PathForModuleOut(ctx, ctx.ModuleName()+".pb"+suffix)
-		bundleModuleFile := android.PathForModuleOut(ctx, ctx.ModuleName()+suffix+"-base.zip")
+		apexProtoFile := android.PathForModuleOut(ctx, a.Name()+".pb"+suffix)
+		bundleModuleFile := android.PathForModuleOut(ctx, a.Name()+suffix+"-base.zip")
 		a.bundleModuleFile = bundleModuleFile
 
 		ctx.Build(pctx, android.BuildParams{
@@ -452,7 +443,7 @@
 		})
 	}
 
-	a.outputFile = android.PathForModuleOut(ctx, ctx.ModuleName()+suffix)
+	a.outputFile = android.PathForModuleOut(ctx, a.Name()+suffix)
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        java.Signapk,
 		Description: "signapk",
@@ -470,7 +461,7 @@
 
 	// Install to $OUT/soong/{target,host}/.../apex
 	if a.installable() {
-		ctx.InstallFile(a.installDir, ctx.ModuleName()+suffix, a.outputFile)
+		ctx.InstallFile(a.installDir, a.Name()+suffix, a.outputFile)
 	}
 	a.buildFilesInfo(ctx)
 }
@@ -485,6 +476,11 @@
 	apexName := proptools.StringDefault(a.properties.Apex_name, ctx.ModuleName())
 	a.outputFile = android.PathForModuleInstall(&factx, "apex", apexName)
 
+	if a.installable() {
+		installPath := android.PathForModuleInstall(ctx, "apex", apexName)
+		devicePath := android.InstallPathToOnDevicePath(ctx, installPath)
+		addFlattenedFileContextsInfos(ctx, apexName+":"+devicePath+":"+a.fileContexts.String())
+	}
 	a.buildFilesInfo(ctx)
 }
 
@@ -505,8 +501,8 @@
 	if a.installable() {
 		// For flattened APEX, do nothing but make sure that apex_manifest.json and apex_pubkey are also copied along
 		// with other ordinary files.
-		a.filesInfo = append(a.filesInfo, apexFile{a.manifestJsonOut, "apex_manifest.json." + ctx.ModuleName() + a.suffix, ".", etc, nil, nil})
-		a.filesInfo = append(a.filesInfo, apexFile{a.manifestPbOut, "apex_manifest.pb." + ctx.ModuleName() + a.suffix, ".", etc, nil, nil})
+		a.filesInfo = append(a.filesInfo, apexFile{a.manifestJsonOut, "apex_manifest.json." + a.Name() + a.suffix, ".", etc, nil, nil})
+		a.filesInfo = append(a.filesInfo, apexFile{a.manifestPbOut, "apex_manifest.pb." + a.Name() + a.suffix, ".", etc, nil, nil})
 
 		// rename to apex_pubkey
 		copiedPubkey := android.PathForModuleOut(ctx, "apex_pubkey")
@@ -515,10 +511,10 @@
 			Input:  a.public_key_file,
 			Output: copiedPubkey,
 		})
-		a.filesInfo = append(a.filesInfo, apexFile{copiedPubkey, "apex_pubkey." + ctx.ModuleName() + a.suffix, ".", etc, nil, nil})
+		a.filesInfo = append(a.filesInfo, apexFile{copiedPubkey, "apex_pubkey." + a.Name() + a.suffix, ".", etc, nil, nil})
 
 		if a.properties.ApexType == flattenedApex {
-			apexName := proptools.StringDefault(a.properties.Apex_name, ctx.ModuleName())
+			apexName := proptools.StringDefault(a.properties.Apex_name, a.Name())
 			for _, fi := range a.filesInfo {
 				dir := filepath.Join("apex", apexName, fi.installDir)
 				target := ctx.InstallFile(android.PathForModuleInstall(ctx, dir), fi.builtFile.Base(), fi.builtFile)
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 476d805..bb89bb4 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -117,45 +117,46 @@
 // incorrectly use the core libraries (sanitizer runtimes, libc, libdl, etc.)
 // from a dependency. This may cause issues when dependencies have explicit
 // sanitizer tags, as we may get a dependency on an unsanitized libc, etc.
-func collectAllSharedDependencies(
-	module android.Module,
-	sharedDeps map[string]android.Path,
-	ctx android.SingletonContext) {
+func collectAllSharedDependencies(ctx android.SingletonContext, module android.Module) android.Paths {
 	var fringe []android.Module
 
+	seen := make(map[android.Module]bool)
+
 	// Enumerate the first level of dependencies, as we discard all non-library
 	// modules in the BFS loop below.
 	ctx.VisitDirectDeps(module, func(dep android.Module) {
-		if isValidSharedDependency(dep, sharedDeps) {
+		if isValidSharedDependency(dep) {
 			fringe = append(fringe, dep)
 		}
 	})
 
+	var sharedLibraries android.Paths
+
 	for i := 0; i < len(fringe); i++ {
 		module := fringe[i]
-		if _, exists := sharedDeps[module.Name()]; exists {
+		if seen[module] {
 			continue
 		}
+		seen[module] = true
 
 		ccModule := module.(*Module)
-		sharedDeps[ccModule.Name()] = ccModule.UnstrippedOutputFile()
+		sharedLibraries = append(sharedLibraries, ccModule.UnstrippedOutputFile())
 		ctx.VisitDirectDeps(module, func(dep android.Module) {
-			if isValidSharedDependency(dep, sharedDeps) {
+			if isValidSharedDependency(dep) && !seen[dep] {
 				fringe = append(fringe, dep)
 			}
 		})
 	}
+
+	return sharedLibraries
 }
 
 // This function takes a module and determines if it is a unique shared library
 // that should be installed in the fuzz target output directories. This function
 // returns true, unless:
-//  - The module already exists in `sharedDeps`, or
 //  - The module is not a shared library, or
 //  - The module is a header, stub, or vendor-linked library.
-func isValidSharedDependency(
-	dependency android.Module,
-	sharedDeps map[string]android.Path) bool {
+func isValidSharedDependency(dependency android.Module) bool {
 	// TODO(b/144090547): We should be parsing these modules using
 	// ModuleDependencyTag instead of the current brute-force checking.
 
@@ -177,10 +178,6 @@
 		}
 	}
 
-	// If this library has already been traversed, we don't need to do any more work.
-	if _, exists := sharedDeps[dependency.Name()]; exists {
-		return false
-	}
 	return true
 }
 
@@ -236,10 +233,16 @@
 	}
 
 	// Grab the list of required shared libraries.
-	sharedLibraries := make(map[string]android.Path)
+	seen := make(map[android.Module]bool)
+	var sharedLibraries android.Paths
 	ctx.WalkDeps(func(child, parent android.Module) bool {
-		if isValidSharedDependency(child, sharedLibraries) {
-			sharedLibraries[child.Name()] = child.(*Module).UnstrippedOutputFile()
+		if seen[child] {
+			return false
+		}
+		seen[child] = true
+
+		if isValidSharedDependency(child) {
+			sharedLibraries = append(sharedLibraries, child.(*Module).UnstrippedOutputFile())
 			return true
 		}
 		return false
@@ -250,8 +253,6 @@
 			sharedLibraryInstallLocation(
 				lib, ctx.Host(), ctx.Arch().ArchType.String()))
 	}
-
-	sort.Strings(fuzz.installedSharedDeps)
 }
 
 func NewFuzz(hod android.HostOrDeviceSupported) *Module {
@@ -305,19 +306,21 @@
 	DestinationPathPrefix string
 }
 
-type archAndLibraryKey struct {
-	ArchDir android.OutputPath
-	Library android.Path
+type archOs struct {
+	hostOrTarget string
+	arch         string
+	dir          string
 }
 
 func (s *fuzzPackager) GenerateBuildActions(ctx android.SingletonContext) {
 	// Map between each architecture + host/device combination, and the files that
 	// need to be packaged (in the tuple of {source file, destination folder in
 	// archive}).
-	archDirs := make(map[android.OutputPath][]fileToZip)
+	archDirs := make(map[archOs][]fileToZip)
 
-	// List of shared library dependencies for each architecture + host/device combo.
-	archSharedLibraryDeps := make(map[archAndLibraryKey]bool)
+	// Map tracking whether each shared library has an install rule to avoid duplicate install rules from
+	// multiple fuzzers that depend on the same shared library.
+	sharedLibraryInstalled := make(map[string]bool)
 
 	// List of individual fuzz targets, so that 'make fuzz' also installs the targets
 	// to the correct output directories as well.
@@ -351,10 +354,10 @@
 
 		archString := ccModule.Arch().ArchType.String()
 		archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString)
+		archOs := archOs{hostOrTarget: hostOrTargetString, arch: archString, dir: archDir.String()}
 
 		// Grab the list of required shared libraries.
-		sharedLibraries := make(map[string]android.Path)
-		collectAllSharedDependencies(module, sharedLibraries, ctx)
+		sharedLibraries := collectAllSharedDependencies(ctx, module)
 
 		var files []fileToZip
 		builder := android.NewRuleBuilder()
@@ -374,16 +377,15 @@
 		for _, library := range sharedLibraries {
 			files = append(files, fileToZip{library, "lib"})
 
-			if _, exists := archSharedLibraryDeps[archAndLibraryKey{archDir, library}]; exists {
-				continue
-			}
-
 			// For each architecture-specific shared library dependency, we need to
 			// install it to the output directory. Setup the install destination here,
 			// which will be used by $(copy-many-files) in the Make backend.
-			archSharedLibraryDeps[archAndLibraryKey{archDir, library}] = true
 			installDestination := sharedLibraryInstallLocation(
 				library, ccModule.Host(), archString)
+			if sharedLibraryInstalled[installDestination] {
+				continue
+			}
+			sharedLibraryInstalled[installDestination] = true
 			// Escape all the variables, as the install destination here will be called
 			// via. $(eval) in Make.
 			installDestination = strings.ReplaceAll(
@@ -421,12 +423,19 @@
 		builder.Build(pctx, ctx, "create-"+fuzzZip.String(),
 			"Package "+module.Name()+" for "+archString+"-"+hostOrTargetString)
 
-		archDirs[archDir] = append(archDirs[archDir], fileToZip{fuzzZip, ""})
+		archDirs[archOs] = append(archDirs[archOs], fileToZip{fuzzZip, ""})
 	})
 
-	for archDir, filesToZip := range archDirs {
-		arch := archDir.Base()
-		hostOrTarget := filepath.Base(filepath.Dir(archDir.String()))
+	var archOsList []archOs
+	for archOs := range archDirs {
+		archOsList = append(archOsList, archOs)
+	}
+	sort.Slice(archOsList, func(i, j int) bool { return archOsList[i].dir < archOsList[j].dir })
+
+	for _, archOs := range archOsList {
+		filesToZip := archDirs[archOs]
+		arch := archOs.arch
+		hostOrTarget := archOs.hostOrTarget
 		builder := android.NewRuleBuilder()
 		outputFile := android.PathForOutput(ctx, "fuzz-"+hostOrTarget+"-"+arch+".zip")
 		s.packages = append(s.packages, outputFile)
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 9215eff..f38d892 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -44,9 +44,10 @@
 	ProductUpdatableBootModules   []string
 	ProductUpdatableBootLocations []string
 
-	SystemServerJars []string // jars that form the system server
-	SystemServerApps []string // apps that are loaded into system server
-	SpeedApps        []string // apps that should be speed optimized
+	SystemServerJars          []string // jars that form the system server
+	SystemServerApps          []string // apps that are loaded into system server
+	UpdatableSystemServerJars []string // jars within apex that are loaded into system server
+	SpeedApps                 []string // apps that should be speed optimized
 
 	PreoptFlags []string // global dex2oat flags that should be used if no module-specific dex2oat flags are specified
 
@@ -285,6 +286,7 @@
 		ProductUpdatableBootLocations:      nil,
 		SystemServerJars:                   nil,
 		SystemServerApps:                   nil,
+		UpdatableSystemServerJars:          nil,
 		SpeedApps:                          nil,
 		PreoptFlags:                        nil,
 		DefaultCompilerFilter:              "",
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index a6661b3..15f11e1 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -15,6 +15,7 @@
 package java
 
 import (
+	"fmt"
 	"path/filepath"
 	"strings"
 
@@ -65,6 +66,16 @@
 var dexpreoptGlobalConfigKey = android.NewOnceKey("DexpreoptGlobalConfig")
 var dexpreoptTestGlobalConfigKey = android.NewOnceKey("TestDexpreoptGlobalConfig")
 
+// Expected format for apexJarValue = <apex name>:<jar name>
+func splitApexJarPair(apexJarValue string) (string, string)  {
+	var apexJarPair []string = strings.SplitN(apexJarValue, ":", 2)
+	if apexJarPair == nil || len(apexJarPair) != 2 {
+		panic(fmt.Errorf("malformed apexJarValue: %q, expected format: <apex>:<jar>",
+			apexJarValue))
+	}
+	return apexJarPair[0], apexJarPair[1]
+}
+
 // systemServerClasspath returns the on-device locations of the modules in the system server classpath.  It is computed
 // once the first time it is called for any ctx.Config(), and returns the same slice for all future calls with the same
 // ctx.Config().
@@ -77,6 +88,11 @@
 			systemServerClasspathLocations = append(systemServerClasspathLocations,
 				filepath.Join("/system/framework", m+".jar"))
 		}
+		for _, m := range global.UpdatableSystemServerJars {
+			apex, jar := splitApexJarPair(m)
+			systemServerClasspathLocations = append(systemServerClasspathLocations,
+				filepath.Join("/apex", apex, "javalib", jar + ".jar"))
+		}
 		return systemServerClasspathLocations
 	})
 }