Merge "Fix duplicate install targets from sdk variants in --skip-make mode."
diff --git a/OWNERS b/OWNERS
index e1db459..adf2b4c 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,4 +1,10 @@
-per-file * = asmundak@google.com,ccross@android.com,dwillemsen@google.com,jungjw@google.com,paulduffin@google.com
+per-file * = asmundak@google.com
+per-file * = ccross@android.com
+per-file * = dwillemsen@google.com
+per-file * = eakammer@google.com
+per-file * = jungjw@google.com
+per-file * = patricearruda@google.com
+per-file * = paulduffin@google.com
 
 per-file ndk_*.go, *gen_stub_libs.py = danalbert@google.com
 per-file clang.go,global.go = srhines@google.com, chh@google.com, pirama@google.com, yikong@google.com
diff --git a/android/arch.go b/android/arch.go
index 08c0256..9a54614 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -810,7 +810,7 @@
 // Valid multilib values include:
 //    "both": compile for all Targets supported by the OsClass (generally x86_64 and x86, or arm64 and arm).
 //    "first": compile for only a single preferred Target supported by the OsClass.  This is generally x86_64 or arm64,
-//        but may be arm for a 32-bit only build or a build with TARGET_PREFER_32_BIT=true set.
+//        but may be arm for a 32-bit only build.
 //    "32": compile for only a single 32-bit Target supported by the OsClass.
 //    "64": compile for only a single 64-bit Target supported by the OsClass.
 //    "common": compile a for a single Target that will work on all Targets suported by the OsClass (for example Java).
@@ -1026,6 +1026,7 @@
 			"Not_windows",
 			"Arm_on_x86",
 			"Arm_on_x86_64",
+			"Native_bridge",
 		}
 		for _, os := range OsTypeList {
 			targets = append(targets, os.Field)
@@ -1413,6 +1414,11 @@
 					prefix := "target.arm_on_x86_64"
 					m.appendProperties(ctx, genProps, targetProp, field, prefix)
 				}
+				if os == Android && m.Target().NativeBridge == NativeBridgeEnabled {
+					field := "Native_bridge"
+					prefix := "target.native_bridge"
+					m.appendProperties(ctx, genProps, targetProp, field, prefix)
+				}
 			}
 		}
 	}
diff --git a/android/arch_test.go b/android/arch_test.go
index b987d56..8525b03 100644
--- a/android/arch_test.go
+++ b/android/arch_test.go
@@ -383,3 +383,88 @@
 		})
 	}
 }
+
+func TestArchMutatorNativeBridge(t *testing.T) {
+	bp := `
+		// This module is only enabled for x86.
+		module {
+			name: "foo",
+		}
+
+		// This module is enabled for x86 and arm (via native bridge).
+		module {
+			name: "bar",
+			native_bridge_supported: true,
+		}
+
+		// This module is enabled for arm (native_bridge) only.
+		module {
+			name: "baz",
+			native_bridge_supported: true,
+			enabled: false,
+			target: {
+				native_bridge: {
+					enabled: true,
+				}
+			}
+		}
+	`
+
+	testCases := []struct {
+		name        string
+		config      func(Config)
+		fooVariants []string
+		barVariants []string
+		bazVariants []string
+	}{
+		{
+			name:        "normal",
+			config:      nil,
+			fooVariants: []string{"android_x86_64_silvermont", "android_x86_silvermont"},
+			barVariants: []string{"android_x86_64_silvermont", "android_native_bridge_arm64_armv8-a", "android_x86_silvermont", "android_native_bridge_arm_armv7-a-neon"},
+			bazVariants: []string{"android_native_bridge_arm64_armv8-a", "android_native_bridge_arm_armv7-a-neon"},
+		},
+	}
+
+	enabledVariants := func(ctx *TestContext, name string) []string {
+		var ret []string
+		variants := ctx.ModuleVariantsForTests(name)
+		for _, variant := range variants {
+			m := ctx.ModuleForTests(name, variant)
+			if m.Module().Enabled() {
+				ret = append(ret, variant)
+			}
+		}
+		return ret
+	}
+
+	for _, tt := range testCases {
+		t.Run(tt.name, func(t *testing.T) {
+			config := TestArchConfigNativeBridge(buildDir, nil, bp, nil)
+
+			ctx := NewTestArchContext()
+			ctx.RegisterModuleType("module", archTestModuleFactory)
+			ctx.Register(config)
+			if tt.config != nil {
+				tt.config(config)
+			}
+
+			_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+			FailIfErrored(t, errs)
+			_, errs = ctx.PrepareBuildActions(config)
+			FailIfErrored(t, errs)
+
+			if g, w := enabledVariants(ctx, "foo"), tt.fooVariants; !reflect.DeepEqual(w, g) {
+				t.Errorf("want foo variants:\n%q\ngot:\n%q\n", w, g)
+			}
+
+			if g, w := enabledVariants(ctx, "bar"), tt.barVariants; !reflect.DeepEqual(w, g) {
+				t.Errorf("want bar variants:\n%q\ngot:\n%q\n", w, g)
+			}
+
+			if g, w := enabledVariants(ctx, "baz"), tt.bazVariants; !reflect.DeepEqual(w, g) {
+				t.Errorf("want qux variants:\n%q\ngot:\n%q\n", w, g)
+			}
+		})
+	}
+}
diff --git a/android/config.go b/android/config.go
index 59118ce..675660e 100644
--- a/android/config.go
+++ b/android/config.go
@@ -732,14 +732,6 @@
 	return Bool(c.productVariables.Eng)
 }
 
-func (c *config) DevicePrefer32BitApps() bool {
-	return Bool(c.productVariables.DevicePrefer32BitApps)
-}
-
-func (c *config) DevicePrefer32BitExecutables() bool {
-	return Bool(c.productVariables.DevicePrefer32BitExecutables)
-}
-
 func (c *config) DevicePrimaryArchType() ArchType {
 	return c.Targets[Android][0].Arch.ArchType
 }
diff --git a/android/variable.go b/android/variable.go
index 3c08405..e025ae0 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -272,10 +272,6 @@
 	CoveragePaths        []string `json:",omitempty"`
 	CoverageExcludePaths []string `json:",omitempty"`
 
-	DevicePrefer32BitApps        *bool `json:",omitempty"`
-	DevicePrefer32BitExecutables *bool `json:",omitempty"`
-	HostPrefer32BitExecutables   *bool `json:",omitempty"`
-
 	SanitizeHost       []string `json:",omitempty"`
 	SanitizeDevice     []string `json:",omitempty"`
 	SanitizeDeviceDiag []string `json:",omitempty"`
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 9321ad2..1b3a4ba 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -81,7 +81,7 @@
 	seenDataOutPaths := make(map[string]bool)
 
 	for _, fi := range a.filesInfo {
-		if cc, ok := fi.module.(*cc.Module); ok && cc.Properties.HideFromMake {
+		if ccMod, ok := fi.module.(*cc.Module); ok && ccMod.Properties.HideFromMake {
 			continue
 		}
 
@@ -178,7 +178,8 @@
 		if fi.jacocoReportClassesFile != nil {
 			fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", fi.jacocoReportClassesFile.String())
 		}
-		if fi.class == javaSharedLib {
+		switch fi.class {
+		case javaSharedLib:
 			javaModule := fi.module.(java.Dependency)
 			// soong_java_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .jar  Therefore
 			// we need to remove the suffix from LOCAL_MODULE_STEM, otherwise
@@ -189,7 +190,7 @@
 			fmt.Fprintln(w, "LOCAL_SOONG_DEX_JAR :=", fi.builtFile.String())
 			fmt.Fprintln(w, "LOCAL_DEX_PREOPT := false")
 			fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_java_prebuilt.mk")
-		} else if fi.class == app {
+		case app:
 			fmt.Fprintln(w, "LOCAL_CERTIFICATE :=", fi.certificate.AndroidMkString())
 			// soong_app_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .apk  Therefore
 			// we need to remove the suffix from LOCAL_MODULE_STEM, otherwise
@@ -199,19 +200,26 @@
 				fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", strings.Join(app.JniCoverageOutputs().Strings(), " "))
 			}
 			fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_app_prebuilt.mk")
-		} else if fi.class == nativeSharedLib || fi.class == nativeExecutable || fi.class == nativeTest {
+		case appSet:
+			as, ok := fi.module.(*java.AndroidAppSet)
+			if !ok {
+				panic(fmt.Sprintf("Expected %s to be AndroidAppSet", fi.module))
+			}
+			fmt.Fprintln(w, "LOCAL_APK_SET_MASTER_FILE :=", as.MasterFile())
+			fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_android_app_set.mk")
+		case nativeSharedLib, nativeExecutable, nativeTest:
 			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.Stem())
-			if cc, ok := fi.module.(*cc.Module); ok {
-				if cc.UnstrippedOutputFile() != nil {
-					fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", cc.UnstrippedOutputFile().String())
+			if ccMod, ok := fi.module.(*cc.Module); ok {
+				if ccMod.UnstrippedOutputFile() != nil {
+					fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", ccMod.UnstrippedOutputFile().String())
 				}
-				cc.AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w)
-				if cc.CoverageOutputFile().Valid() {
-					fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", cc.CoverageOutputFile().String())
+				ccMod.AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w)
+				if ccMod.CoverageOutputFile().Valid() {
+					fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", ccMod.CoverageOutputFile().String())
 				}
 			}
 			fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_cc_prebuilt.mk")
-		} else {
+		default:
 			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.Stem())
 			if fi.builtFile == a.manifestPbOut && apexType == flattenedApex {
 				if a.primaryApexType {
diff --git a/apex/apex.go b/apex/apex.go
index 8fd80fc..d45dd6f 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1115,6 +1115,7 @@
 	javaSharedLib
 	nativeTest
 	app
+	appSet
 )
 
 func (class apexFileClass) NameInMake() string {
@@ -1129,7 +1130,7 @@
 		return "JAVA_LIBRARIES"
 	case nativeTest:
 		return "NATIVE_TESTS"
-	case app:
+	case app, appSet:
 		// b/142537672 Why isn't this APP? We want to have full control over
 		// the paths and file names of the apk file under the flattend APEX.
 		// If this is set to APP, then the paths and file names are modified
@@ -1650,14 +1651,14 @@
 }
 
 type javaDependency interface {
-	DexJar() android.Path
+	DexJarBuildPath() android.Path
 	JacocoReportClassesFile() android.Path
 	Stem() string
 }
 
 func apexFileForJavaLibrary(ctx android.BaseModuleContext, lib javaDependency, module android.Module) apexFile {
 	dirInApex := "javalib"
-	fileToCopy := lib.DexJar()
+	fileToCopy := lib.DexJarBuildPath()
 	af := newApexFile(ctx, fileToCopy, module.Name(), dirInApex, javaSharedLib, module)
 	af.jacocoReportClassesFile = lib.JacocoReportClassesFile()
 	af.stem = lib.Stem() + ".jar"
@@ -1998,6 +1999,15 @@
 					filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap))
 				} else if ap, ok := child.(*java.AndroidTestHelperApp); ok {
 					filesInfo = append(filesInfo, apexFileForAndroidApp(ctx, ap))
+				} else if ap, ok := child.(*java.AndroidAppSet); ok {
+					appDir := "app"
+					if ap.Privileged() {
+						appDir = "priv-app"
+					}
+					af := newApexFile(ctx, ap.OutputFile(), ap.Name(),
+						filepath.Join(appDir, ap.BaseModuleName()), appSet, ap)
+					af.certificate = java.PresignedCertificate
+					filesInfo = append(filesInfo, af)
 				} else {
 					ctx.PropertyErrorf("apps", "%q is not an android_app module", depName)
 				}
@@ -2270,9 +2280,6 @@
 	module.AddProperties(&module.properties)
 	module.AddProperties(&module.targetProperties)
 	module.AddProperties(&module.overridableProperties)
-	module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool {
-		return class == android.Device && ctx.Config().DevicePrefer32BitExecutables()
-	})
 	android.InitAndroidMultiTargetsArchModule(module, android.HostAndDeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
 	android.InitSdkAwareModule(module)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index e45cd00..d6a5d09 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -96,7 +96,7 @@
 // - X86 (secondary)
 // - Arm64 on X86_64 (native bridge)
 // - Arm on X86 (native bridge)
-func withNativeBridgeEnabled(fs map[string][]byte, config android.Config) {
+func withNativeBridgeEnabled(_ map[string][]byte, config android.Config) {
 	config.Targets[android.Android] = []android.Target{
 		{Os: android.Android, Arch: android.Arch{ArchType: android.X86_64, ArchVariant: "silvermont", Abi: []string{"arm64-v8a"}},
 			NativeBridge: android.NativeBridgeDisabled, NativeBridgeHostArchName: "", NativeBridgeRelativePath: ""},
@@ -115,15 +115,15 @@
 	}
 }
 
-func withBinder32bit(fs map[string][]byte, config android.Config) {
+func withBinder32bit(_ map[string][]byte, config android.Config) {
 	config.TestProductVariables.Binder32bit = proptools.BoolPtr(true)
 }
 
-func withUnbundledBuild(fs map[string][]byte, config android.Config) {
+func withUnbundledBuild(_ map[string][]byte, config android.Config) {
 	config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
 }
 
-func testApexContext(t *testing.T, bp string, handlers ...testCustomizer) (*android.TestContext, android.Config) {
+func testApexContext(_ *testing.T, bp string, handlers ...testCustomizer) (*android.TestContext, android.Config) {
 	android.ClearApexDependency()
 
 	bp = bp + `
@@ -187,6 +187,7 @@
 		"baz":                                        nil,
 		"bar/baz":                                    nil,
 		"testdata/baz":                               nil,
+		"AppSet.apks":                                nil,
 	}
 
 	cc.GatherRequiredFilesForTest(fs)
@@ -258,7 +259,7 @@
 }
 
 func tearDown() {
-	os.RemoveAll(buildDir)
+	_ = os.RemoveAll(buildDir)
 }
 
 // ensure that 'result' equals 'expected'
@@ -294,6 +295,17 @@
 	}
 }
 
+func ensureMatches(t *testing.T, result string, expectedRex string) {
+	ok, err := regexp.MatchString(expectedRex, result)
+	if err != nil {
+		t.Fatalf("regexp failure trying to match %s against `%s` expression: %s", result, expectedRex, err)
+		return
+	}
+	if !ok {
+		t.Errorf("%s does not match regular expession %s", result, expectedRex)
+	}
+}
+
 func ensureListContains(t *testing.T, result []string, expected string) {
 	t.Helper()
 	if !android.InList(expected, result) {
@@ -4772,6 +4784,38 @@
 	ensureContains(t, content, `"apex_config":{"apex_embedded_apk_config":[{"package_name":"com.android.foo","path":"app/AppFoo/AppFoo.apk"}]}`)
 }
 
+func TestAppSetBundle(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			apps: ["AppSet"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		android_app_set {
+			name: "AppSet",
+			set: "AppSet.apks",
+		}`)
+	mod := ctx.ModuleForTests("myapex", "android_common_myapex_image")
+	bundleConfigRule := mod.Description("Bundle Config")
+	content := bundleConfigRule.Args["content"]
+	ensureContains(t, content, `"compression":{"uncompressed_glob":["apex_payload.img","apex_manifest.*"]}`)
+	s := mod.Rule("apexRule").Args["copy_commands"]
+	copyCmds := regexp.MustCompile(" *&& *").Split(s, -1)
+	if len(copyCmds) != 3 {
+		t.Fatalf("Expected 3 commands, got %d in:\n%s", len(copyCmds), s)
+	}
+	ensureMatches(t, copyCmds[0], "^rm -rf .*/app/AppSet$")
+	ensureMatches(t, copyCmds[1], "^mkdir -p .*/app/AppSet$")
+	ensureMatches(t, copyCmds[2], "^unzip .*-d .*/app/AppSet .*/AppSet.zip$")
+}
+
 func testNoUpdatableJarsInBootImage(t *testing.T, errmsg string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) {
 	t.Helper()
 
@@ -4931,7 +4975,7 @@
 
 func TestNoUpdatableJarsInBootImage(t *testing.T) {
 
-	var error string
+	var err string
 	var transform func(*dexpreopt.GlobalConfig)
 
 	t.Run("updatable jar from ART apex in the ART boot image => ok", func(t *testing.T) {
@@ -4942,35 +4986,35 @@
 	})
 
 	t.Run("updatable jar from ART apex in the framework boot image => error", func(t *testing.T) {
-		error = "module 'some-art-lib' from updatable apex 'com.android.art.something' is not allowed in the framework boot image"
+		err = "module 'some-art-lib' from updatable apex 'com.android.art.something' is not allowed in the framework boot image"
 		transform = func(config *dexpreopt.GlobalConfig) {
 			config.BootJars = []string{"com.android.art.something:some-art-lib"}
 		}
-		testNoUpdatableJarsInBootImage(t, error, transform)
+		testNoUpdatableJarsInBootImage(t, err, transform)
 	})
 
 	t.Run("updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
-		error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the ART boot image"
+		err = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the ART boot image"
 		transform = func(config *dexpreopt.GlobalConfig) {
 			config.ArtApexJars = []string{"some-updatable-apex:some-updatable-apex-lib"}
 		}
-		testNoUpdatableJarsInBootImage(t, error, transform)
+		testNoUpdatableJarsInBootImage(t, err, transform)
 	})
 
 	t.Run("non-updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
-		error = "module 'some-non-updatable-apex-lib' is not allowed in the ART boot image"
+		err = "module 'some-non-updatable-apex-lib' is not allowed in the ART boot image"
 		transform = func(config *dexpreopt.GlobalConfig) {
 			config.ArtApexJars = []string{"some-non-updatable-apex:some-non-updatable-apex-lib"}
 		}
-		testNoUpdatableJarsInBootImage(t, error, transform)
+		testNoUpdatableJarsInBootImage(t, err, transform)
 	})
 
 	t.Run("updatable jar from some other apex in the framework boot image => error", func(t *testing.T) {
-		error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the framework boot image"
+		err = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the framework boot image"
 		transform = func(config *dexpreopt.GlobalConfig) {
 			config.BootJars = []string{"some-updatable-apex:some-updatable-apex-lib"}
 		}
-		testNoUpdatableJarsInBootImage(t, error, transform)
+		testNoUpdatableJarsInBootImage(t, err, transform)
 	})
 
 	t.Run("non-updatable jar from some other apex in the framework boot image => ok", func(t *testing.T) {
@@ -4981,27 +5025,27 @@
 	})
 
 	t.Run("nonexistent jar in the ART boot image => error", func(t *testing.T) {
-		error = "failed to find a dex jar path for module 'nonexistent'"
+		err = "failed to find a dex jar path for module 'nonexistent'"
 		transform = func(config *dexpreopt.GlobalConfig) {
 			config.ArtApexJars = []string{"platform:nonexistent"}
 		}
-		testNoUpdatableJarsInBootImage(t, error, transform)
+		testNoUpdatableJarsInBootImage(t, err, transform)
 	})
 
 	t.Run("nonexistent jar in the framework boot image => error", func(t *testing.T) {
-		error = "failed to find a dex jar path for module 'nonexistent'"
+		err = "failed to find a dex jar path for module 'nonexistent'"
 		transform = func(config *dexpreopt.GlobalConfig) {
 			config.BootJars = []string{"platform:nonexistent"}
 		}
-		testNoUpdatableJarsInBootImage(t, error, transform)
+		testNoUpdatableJarsInBootImage(t, err, transform)
 	})
 
 	t.Run("platform jar in the ART boot image => error", func(t *testing.T) {
-		error = "module 'some-platform-lib' is not allowed in the ART boot image"
+		err = "module 'some-platform-lib' is not allowed in the ART boot image"
 		transform = func(config *dexpreopt.GlobalConfig) {
 			config.ArtApexJars = []string{"platform:some-platform-lib"}
 		}
-		testNoUpdatableJarsInBootImage(t, error, transform)
+		testNoUpdatableJarsInBootImage(t, err, transform)
 	})
 
 	t.Run("platform jar in the framework boot image => ok", func(t *testing.T) {
diff --git a/apex/builder.go b/apex/builder.go
index 0108d06..17eac1a 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -69,11 +69,14 @@
 	// by default set to (uid/gid/mode) = (1000/1000/0644)
 	// TODO(b/113082813) make this configurable using config.fs syntax
 	generateFsConfig = pctx.StaticRule("generateFsConfig", blueprint.RuleParams{
-		Command: `echo '/ 1000 1000 0755' > ${out} && ` +
-			`echo ${ro_paths} | tr ' ' '\n' | awk '{print "/"$$1 " 1000 1000 0644"}' >> ${out} && ` +
-			`echo ${exec_paths} | tr ' ' '\n' | awk '{print "/"$$1 " 0 2000 0755"}' >> ${out}`,
-		Description: "fs_config ${out}",
-	}, "ro_paths", "exec_paths")
+		Command: `( echo '/ 1000 1000 0755' ` +
+			`&& for i in ${ro_paths}; do echo "/$$i 1000 1000 0644"; done ` +
+			`&& for i in  ${exec_paths}; do echo "/$$i 0 2000 0755"; done ` +
+			`&& ( tr ' ' '\n' <${out}.apklist | for i in ${apk_paths}; do read apk; echo "/$$i 0 2000 0755"; zipinfo -1 $$apk | sed "s:\(.*\):/$$i/\1 1000 1000 0644:"; done ) ) > ${out}`,
+		Description:    "fs_config ${out}",
+		Rspfile:        "$out.apklist",
+		RspfileContent: "$in",
+	}, "ro_paths", "exec_paths", "apk_paths")
 
 	apexManifestRule = pctx.StaticRule("apexManifestRule", blueprint.RuleParams{
 		Command: `rm -f $out && ${jsonmodify} $in ` +
@@ -287,7 +290,7 @@
 	// collect the manifest names and paths of android apps
 	// if their manifest names are overridden
 	for _, fi := range a.filesInfo {
-		if fi.class != app {
+		if fi.class != app && fi.class != appSet {
 			continue
 		}
 		packageName := fi.overriddenPackageName
@@ -337,13 +340,22 @@
 	var copyCommands []string
 	for _, fi := range a.filesInfo {
 		destPath := android.PathForModuleOut(ctx, "image"+suffix, fi.Path()).String()
-		copyCommands = append(copyCommands, "mkdir -p "+filepath.Dir(destPath))
+		destPathDir := filepath.Dir(destPath)
+		if fi.class == appSet {
+			copyCommands = append(copyCommands, "rm -rf "+destPathDir)
+		}
+		copyCommands = append(copyCommands, "mkdir -p "+destPathDir)
 		if a.linkToSystemLib && fi.transitiveDep && fi.AvailableToPlatform() {
 			// TODO(jiyong): pathOnDevice should come from fi.module, not being calculated here
 			pathOnDevice := filepath.Join("/system", fi.Path())
 			copyCommands = append(copyCommands, "ln -sfn "+pathOnDevice+" "+destPath)
 		} else {
-			copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath)
+			if fi.class == appSet {
+				copyCommands = append(copyCommands,
+					fmt.Sprintf("unzip -q -d %s %s", destPathDir, fi.builtFile.String()))
+			} else {
+				copyCommands = append(copyCommands, "cp -f "+fi.builtFile.String()+" "+destPath)
+			}
 			implicitInputs = append(implicitInputs, fi.builtFile)
 		}
 		// create additional symlinks pointing the file inside the APEX
@@ -416,6 +428,8 @@
 		// files and dirs that will be created in APEX
 		var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"}
 		var executablePaths []string // this also includes dirs
+		var extractedAppSetPaths android.Paths
+		var extractedAppSetDirs []string
 		for _, f := range a.filesInfo {
 			pathInApex := f.Path()
 			if f.installDir == "bin" || strings.HasPrefix(f.installDir, "bin/") {
@@ -426,6 +440,9 @@
 				for _, s := range f.symlinks {
 					executablePaths = append(executablePaths, filepath.Join(f.installDir, s))
 				}
+			} else if f.class == appSet {
+				extractedAppSetPaths = append(extractedAppSetPaths, f.builtFile)
+				extractedAppSetDirs = append(extractedAppSetDirs, f.installDir)
 			} else {
 				readOnlyPaths = append(readOnlyPaths, pathInApex)
 			}
@@ -446,9 +463,11 @@
 			Rule:        generateFsConfig,
 			Output:      cannedFsConfig,
 			Description: "generate fs config",
+			Inputs:      extractedAppSetPaths,
 			Args: map[string]string{
 				"ro_paths":   strings.Join(readOnlyPaths, " "),
 				"exec_paths": strings.Join(executablePaths, " "),
+				"apk_paths":  strings.Join(extractedAppSetDirs, " "),
 			},
 		})
 
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 3ce1a89..52480ea 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -548,6 +548,25 @@
 	})
 }
 
+func (c *vendorSnapshotObjectLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
+	entries.Class = "STATIC_LIBRARIES"
+
+	if c.androidMkVendorSuffix {
+		entries.SubName = vendorSuffix
+	} else {
+		entries.SubName = ""
+	}
+
+	entries.ExtraFooters = append(entries.ExtraFooters,
+		func(w io.Writer, name, prefix, moduleDir string, entries *android.AndroidMkEntries) {
+			out := entries.OutputFile.Path()
+			varname := fmt.Sprintf("SOONG_%sOBJECT_%s%s", prefix, name, entries.SubName)
+
+			fmt.Fprintf(w, "\n%s := %s\n", varname, out.String())
+			fmt.Fprintln(w, ".KATI_READONLY: "+varname)
+		})
+}
+
 func (c *ndkPrebuiltStlLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
 	entries.Class = "SHARED_LIBRARIES"
 }
diff --git a/cc/binary.go b/cc/binary.go
index 661264e..251b7f0 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -231,6 +231,10 @@
 	return binary.static()
 }
 
+func (binary *binaryDecorator) binary() bool {
+	return true
+}
+
 func (binary *binaryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags {
 	flags = binary.baseLinker.linkerFlags(ctx, flags)
 
diff --git a/cc/cc.go b/cc/cc.go
index 94512d5..770391a 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -316,6 +316,8 @@
 	static() bool
 	staticBinary() bool
 	header() bool
+	binary() bool
+	object() bool
 	toolchain() config.Toolchain
 	canUseSdk() bool
 	useSdk() bool
@@ -823,15 +825,8 @@
 	}
 
 	c.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool {
-		switch class {
-		case android.Device:
-			return ctx.Config().DevicePrefer32BitExecutables()
-		case android.HostCross:
-			// Windows builds always prefer 32-bit
-			return true
-		default:
-			return false
-		}
+		// Windows builds always prefer 32-bit
+		return class == android.HostCross
 	})
 	android.InitAndroidArchModule(c, c.hod, c.multilib)
 	android.InitApexModule(c)
@@ -1017,14 +1012,8 @@
 }
 
 func (c *Module) isSnapshotPrebuilt() bool {
-	if _, ok := c.linker.(*vndkPrebuiltLibraryDecorator); ok {
-		return true
-	}
-	if _, ok := c.linker.(*vendorSnapshotLibraryDecorator); ok {
-		return true
-	}
-	if _, ok := c.linker.(*vendorSnapshotBinaryDecorator); ok {
-		return true
+	if p, ok := c.linker.(interface{ isSnapshotPrebuilt() bool }); ok {
+		return p.isSnapshotPrebuilt()
 	}
 	return false
 }
@@ -1129,6 +1118,14 @@
 	return ctx.mod.header()
 }
 
+func (ctx *moduleContextImpl) binary() bool {
+	return ctx.mod.binary()
+}
+
+func (ctx *moduleContextImpl) object() bool {
+	return ctx.mod.object()
+}
+
 func (ctx *moduleContextImpl) canUseSdk() bool {
 	return ctx.mod.canUseSdk()
 }
@@ -1925,7 +1922,7 @@
 	if deps.StaticUnwinderIfLegacy {
 		actx.AddVariationDependencies([]blueprint.Variation{
 			{Mutator: "link", Variation: "static"},
-		}, staticUnwinderDepTag, staticUnwinder(actx))
+		}, staticUnwinderDepTag, rewriteSnapshotLibs(staticUnwinder(actx), vendorSnapshotStaticLibs))
 	}
 
 	for _, lib := range deps.LateStaticLibs {
@@ -2006,11 +2003,13 @@
 
 	actx.AddVariationDependencies(nil, objDepTag, deps.ObjFiles...)
 
+	vendorSnapshotObjects := vendorSnapshotObjects(actx.Config())
+
 	if deps.CrtBegin != "" {
-		actx.AddVariationDependencies(nil, CrtBeginDepTag, deps.CrtBegin)
+		actx.AddVariationDependencies(nil, CrtBeginDepTag, rewriteSnapshotLibs(deps.CrtBegin, vendorSnapshotObjects))
 	}
 	if deps.CrtEnd != "" {
-		actx.AddVariationDependencies(nil, CrtEndDepTag, deps.CrtEnd)
+		actx.AddVariationDependencies(nil, CrtEndDepTag, rewriteSnapshotLibs(deps.CrtEnd, vendorSnapshotObjects))
 	}
 	if deps.LinkerFlagsFile != "" {
 		actx.AddDependency(c, linkerFlagsDepTag, deps.LinkerFlagsFile)
@@ -2752,6 +2751,24 @@
 	return false
 }
 
+func (c *Module) binary() bool {
+	if b, ok := c.linker.(interface {
+		binary() bool
+	}); ok {
+		return b.binary()
+	}
+	return false
+}
+
+func (c *Module) object() bool {
+	if o, ok := c.linker.(interface {
+		object() bool
+	}); ok {
+		return o.object()
+	}
+	return false
+}
+
 func (c *Module) getMakeLinkType(actx android.ModuleContext) string {
 	if c.UseVndk() {
 		if lib, ok := c.linker.(*llndkStubDecorator); ok {
@@ -3064,20 +3081,32 @@
 		// This will be available in /system, /vendor and /product
 		// or a /system directory that is available to vendor and product.
 		coreVariantNeeded = true
-		vendorVariants = append(vendorVariants, platformVndkVersion)
-		productVariants = append(productVariants, platformVndkVersion)
-		// VNDK modules must not create BOARD_VNDK_VERSION variant because its
-		// code is PLATFORM_VNDK_VERSION.
-		// On the other hand, vendor_available modules which are not VNDK should
-		// also build BOARD_VNDK_VERSION because it's installed in /vendor.
-		// vendor_available modules are also available to /product.
-		if !m.IsVndk() {
+
+		// We assume that modules under proprietary paths are compatible for
+		// BOARD_VNDK_VERSION. The other modules are regarded as AOSP, or
+		// PLATFORM_VNDK_VERSION.
+		if isVendorProprietaryPath(mctx.ModuleDir()) {
 			vendorVariants = append(vendorVariants, boardVndkVersion)
+		} else {
+			vendorVariants = append(vendorVariants, platformVndkVersion)
+		}
+
+		// vendor_available modules are also available to /product.
+		productVariants = append(productVariants, platformVndkVersion)
+		// VNDK is always PLATFORM_VNDK_VERSION
+		if !m.IsVndk() {
 			productVariants = append(productVariants, productVndkVersion)
 		}
 	} else if vendorSpecific && String(m.Properties.Sdk_version) == "" {
 		// This will be available in /vendor (or /odm) only
-		vendorVariants = append(vendorVariants, boardVndkVersion)
+		// We assume that modules under proprietary paths are compatible for
+		// BOARD_VNDK_VERSION. The other modules are regarded as AOSP, or
+		// PLATFORM_VNDK_VERSION.
+		if isVendorProprietaryPath(mctx.ModuleDir()) {
+			vendorVariants = append(vendorVariants, boardVndkVersion)
+		} else {
+			vendorVariants = append(vendorVariants, platformVndkVersion)
+		}
 	} else {
 		// This is either in /system (or similar: /data), or is a
 		// modules built with the NDK. Modules built with the NDK
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 67eb248..76b4e38 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -258,9 +258,7 @@
 	}
 }
 
-func checkSnapshot(t *testing.T, ctx *android.TestContext, singletonName, moduleName, snapshotFilename, subDir, variant string) {
-	snapshotSingleton := ctx.SingletonForTests(singletonName)
-
+func checkSnapshot(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) {
 	mod, ok := ctx.ModuleForTests(moduleName, variant).Module().(android.OutputFileProducer)
 	if !ok {
 		t.Errorf("%q must have output\n", moduleName)
@@ -273,7 +271,7 @@
 	}
 	snapshotPath := filepath.Join(subDir, snapshotFilename)
 
-	out := snapshotSingleton.Output(snapshotPath)
+	out := singleton.Output(snapshotPath)
 	if out.Input.String() != outputFiles[0].String() {
 		t.Errorf("The input of snapshot %q must be %q, but %q", moduleName, out.Input.String(), outputFiles[0])
 	}
@@ -398,16 +396,18 @@
 	variant := "android_vendor.VER_arm64_armv8-a_shared"
 	variant2nd := "android_vendor.VER_arm_armv7-a-neon_shared"
 
-	checkSnapshot(t, ctx, "vndk-snapshot", "libvndk", "libvndk.so", vndkCoreLibPath, variant)
-	checkSnapshot(t, ctx, "vndk-snapshot", "libvndk", "libvndk.so", vndkCoreLib2ndPath, variant2nd)
-	checkSnapshot(t, ctx, "vndk-snapshot", "libvndk_sp", "libvndk_sp-x.so", vndkSpLibPath, variant)
-	checkSnapshot(t, ctx, "vndk-snapshot", "libvndk_sp", "libvndk_sp-x.so", vndkSpLib2ndPath, variant2nd)
+	snapshotSingleton := ctx.SingletonForTests("vndk-snapshot")
+
+	checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.so", vndkCoreLibPath, variant)
+	checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.so", vndkCoreLib2ndPath, variant2nd)
+	checkSnapshot(t, ctx, snapshotSingleton, "libvndk_sp", "libvndk_sp-x.so", vndkSpLibPath, variant)
+	checkSnapshot(t, ctx, snapshotSingleton, "libvndk_sp", "libvndk_sp-x.so", vndkSpLib2ndPath, variant2nd)
 
 	snapshotConfigsPath := filepath.Join(snapshotVariantPath, "configs")
-	checkSnapshot(t, ctx, "vndk-snapshot", "llndk.libraries.txt", "llndk.libraries.txt", snapshotConfigsPath, "")
-	checkSnapshot(t, ctx, "vndk-snapshot", "vndkcore.libraries.txt", "vndkcore.libraries.txt", snapshotConfigsPath, "")
-	checkSnapshot(t, ctx, "vndk-snapshot", "vndksp.libraries.txt", "vndksp.libraries.txt", snapshotConfigsPath, "")
-	checkSnapshot(t, ctx, "vndk-snapshot", "vndkprivate.libraries.txt", "vndkprivate.libraries.txt", snapshotConfigsPath, "")
+	checkSnapshot(t, ctx, snapshotSingleton, "llndk.libraries.txt", "llndk.libraries.txt", snapshotConfigsPath, "")
+	checkSnapshot(t, ctx, snapshotSingleton, "vndkcore.libraries.txt", "vndkcore.libraries.txt", snapshotConfigsPath, "")
+	checkSnapshot(t, ctx, snapshotSingleton, "vndksp.libraries.txt", "vndksp.libraries.txt", snapshotConfigsPath, "")
+	checkSnapshot(t, ctx, snapshotSingleton, "vndkprivate.libraries.txt", "vndkprivate.libraries.txt", snapshotConfigsPath, "")
 
 	checkVndkOutput(t, ctx, "vndk/vndk.libraries.txt", []string{
 		"LLNDK: libc.so",
@@ -839,6 +839,17 @@
 		vendor_available: true,
 		nocrt: true,
 	}
+
+	toolchain_library {
+		name: "libb",
+		vendor_available: true,
+		src: "libb.a",
+	}
+
+	cc_object {
+		name: "obj",
+		vendor_available: true,
+	}
 `
 	config := TestConfig(buildDir, android.Android, nil, bp, nil)
 	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
@@ -849,6 +860,9 @@
 
 	snapshotDir := "vendor-snapshot"
 	snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
+	snapshotSingleton := ctx.SingletonForTests("vendor-snapshot")
+
+	var jsonFiles []string
 
 	for _, arch := range [][]string{
 		[]string{"arm64", "armv8-a"},
@@ -861,22 +875,51 @@
 		// For shared libraries, only non-VNDK vendor_available modules are captured
 		sharedVariant := fmt.Sprintf("android_vendor.VER_%s_%s_shared", archType, archVariant)
 		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
-		checkSnapshot(t, ctx, "vendor-snapshot", "libvendor", "libvendor.so", sharedDir, sharedVariant)
-		checkSnapshot(t, ctx, "vendor-snapshot", "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant)
+		checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.so", sharedDir, sharedVariant)
+		checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant)
+		jsonFiles = append(jsonFiles,
+			filepath.Join(sharedDir, "libvendor.so.json"),
+			filepath.Join(sharedDir, "libvendor_available.so.json"))
 
 		// For static libraries, all vendor:true and vendor_available modules (including VNDK) are captured.
 		staticVariant := fmt.Sprintf("android_vendor.VER_%s_%s_static", archType, archVariant)
 		staticDir := filepath.Join(snapshotVariantPath, archDir, "static")
-		checkSnapshot(t, ctx, "vendor-snapshot", "libvndk", "libvndk.a", staticDir, staticVariant)
-		checkSnapshot(t, ctx, "vendor-snapshot", "libvendor", "libvendor.a", staticDir, staticVariant)
-		checkSnapshot(t, ctx, "vendor-snapshot", "libvendor_available", "libvendor_available.a", staticDir, staticVariant)
+		checkSnapshot(t, ctx, snapshotSingleton, "libb", "libb.a", staticDir, staticVariant)
+		checkSnapshot(t, ctx, snapshotSingleton, "libvndk", "libvndk.a", staticDir, staticVariant)
+		checkSnapshot(t, ctx, snapshotSingleton, "libvendor", "libvendor.a", staticDir, staticVariant)
+		checkSnapshot(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.a", staticDir, staticVariant)
+		jsonFiles = append(jsonFiles,
+			filepath.Join(staticDir, "libb.a.json"),
+			filepath.Join(staticDir, "libvndk.a.json"),
+			filepath.Join(staticDir, "libvendor.a.json"),
+			filepath.Join(staticDir, "libvendor_available.a.json"))
 
-		// For binary libraries, all vendor:true and vendor_available modules are captured.
+		// For binary executables, all vendor:true and vendor_available modules are captured.
 		if archType == "arm64" {
 			binaryVariant := fmt.Sprintf("android_vendor.VER_%s_%s", archType, archVariant)
 			binaryDir := filepath.Join(snapshotVariantPath, archDir, "binary")
-			checkSnapshot(t, ctx, "vendor-snapshot", "vendor_bin", "vendor_bin", binaryDir, binaryVariant)
-			checkSnapshot(t, ctx, "vendor-snapshot", "vendor_available_bin", "vendor_available_bin", binaryDir, binaryVariant)
+			checkSnapshot(t, ctx, snapshotSingleton, "vendor_bin", "vendor_bin", binaryDir, binaryVariant)
+			checkSnapshot(t, ctx, snapshotSingleton, "vendor_available_bin", "vendor_available_bin", binaryDir, binaryVariant)
+			jsonFiles = append(jsonFiles,
+				filepath.Join(binaryDir, "vendor_bin.json"),
+				filepath.Join(binaryDir, "vendor_available_bin.json"))
+		}
+
+		// For header libraries, all vendor:true and vendor_available modules are captured.
+		headerDir := filepath.Join(snapshotVariantPath, archDir, "header")
+		jsonFiles = append(jsonFiles, filepath.Join(headerDir, "libvendor_headers.json"))
+
+		// For object modules, all vendor:true and vendor_available modules are captured.
+		objectVariant := fmt.Sprintf("android_vendor.VER_%s_%s", archType, archVariant)
+		objectDir := filepath.Join(snapshotVariantPath, archDir, "object")
+		checkSnapshot(t, ctx, snapshotSingleton, "obj", "obj.o", objectDir, objectVariant)
+		jsonFiles = append(jsonFiles, filepath.Join(objectDir, "obj.o.json"))
+	}
+
+	for _, jsonFile := range jsonFiles {
+		// verify all json files exist
+		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
+			t.Errorf("%q expected but not found", jsonFile)
 		}
 	}
 }
diff --git a/cc/compiler.go b/cc/compiler.go
index 681b1ab..e7495da 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -300,8 +300,7 @@
 	if !(ctx.useSdk() || ctx.useVndk()) || ctx.Host() {
 		flags.SystemIncludeFlags = append(flags.SystemIncludeFlags,
 			"${config.CommonGlobalIncludes}",
-			tc.IncludeFlags(),
-			"${config.CommonNativehelperInclude}")
+			tc.IncludeFlags())
 	}
 
 	if ctx.useSdk() {
diff --git a/cc/genrule.go b/cc/genrule.go
index 9331448..66d1784 100644
--- a/cc/genrule.go
+++ b/cc/genrule.go
@@ -79,8 +79,14 @@
 
 	var variants []string
 	if Bool(g.Vendor_available) || ctx.SocSpecific() || ctx.DeviceSpecific() {
-		variants = append(variants, VendorVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion())
-		if vndkVersion := ctx.DeviceConfig().VndkVersion(); vndkVersion != "current" {
+		vndkVersion := ctx.DeviceConfig().VndkVersion()
+		// If vndkVersion is current, we can always use PlatformVndkVersion.
+		// If not, we assume modules under proprietary paths are compatible for
+		// BOARD_VNDK_VERSION. The other modules are regarded as AOSP, that is
+		// PLATFORM_VNDK_VERSION.
+		if vndkVersion == "current" || !isVendorProprietaryPath(ctx.ModuleDir()) {
+			variants = append(variants, VendorVariationPrefix+ctx.DeviceConfig().PlatformVndkVersion())
+		} else {
 			variants = append(variants, VendorVariationPrefix+vndkVersion)
 		}
 	}
diff --git a/cc/object.go b/cc/object.go
index 19decec..15a529e 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -158,3 +158,7 @@
 func (object *objectLinker) coverageOutputFilePath() android.OptionalPath {
 	return android.OptionalPath{}
 }
+
+func (object *objectLinker) object() bool {
+	return true
+}
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index ac990f3..0751f1c 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -291,6 +291,10 @@
 	return nil
 }
 
+func (p *prebuiltObjectLinker) object() bool {
+	return true
+}
+
 func newPrebuiltObject() *Module {
 	module := newObject()
 	prebuilt := &prebuiltObjectLinker{
@@ -349,6 +353,10 @@
 	return nil
 }
 
+func (p *prebuiltBinaryLinker) binary() bool {
+	return true
+}
+
 // cc_prebuilt_binary installs a precompiled executable in srcs property in the
 // device's directory.
 func prebuiltBinaryFactory() android.Module {
diff --git a/cc/testing.go b/cc/testing.go
index be020c5..edbb24d 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -496,6 +496,7 @@
 		"my_include":  nil,
 		"foo.map.txt": nil,
 		"liba.so":     nil,
+		"libb.a":      nil,
 	}
 
 	GatherRequiredFilesForTest(mockFS)
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 5801fc7..ea94544 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -30,6 +30,7 @@
 	vendorSnapshotSharedSuffix = ".vendor_shared."
 	vendorSnapshotStaticSuffix = ".vendor_static."
 	vendorSnapshotBinarySuffix = ".vendor_binary."
+	vendorSnapshotObjectSuffix = ".vendor_object."
 )
 
 var (
@@ -39,6 +40,7 @@
 	vendorSnapshotStaticLibsKey = android.NewOnceKey("vendorSnapshotStaticLibs")
 	vendorSnapshotSharedLibsKey = android.NewOnceKey("vendorSnapshotSharedLibs")
 	vendorSnapshotBinariesKey   = android.NewOnceKey("vendorSnapshotBinaries")
+	vendorSnapshotObjectsKey    = android.NewOnceKey("vendorSnapshotObjects")
 )
 
 // vendor snapshot maps hold names of vendor snapshot modules per arch
@@ -72,6 +74,12 @@
 	}).(*snapshotMap)
 }
 
+func vendorSnapshotObjects(config android.Config) *snapshotMap {
+	return config.Once(vendorSnapshotObjectsKey, func() interface{} {
+		return newSnapshotMap()
+	}).(*snapshotMap)
+}
+
 type vendorSnapshotLibraryProperties struct {
 	// snapshot version.
 	Version string
@@ -185,6 +193,10 @@
 	return false
 }
 
+func (p *vendorSnapshotLibraryDecorator) isSnapshotPrebuilt() bool {
+	return true
+}
+
 func (p *vendorSnapshotLibraryDecorator) install(ctx ModuleContext, file android.Path) {
 	if p.matchesWithDevice(ctx.DeviceConfig()) && (p.shared() || p.static()) {
 		p.baseInstaller.install(ctx, file)
@@ -337,6 +349,10 @@
 	return outputFile
 }
 
+func (p *vendorSnapshotBinaryDecorator) isSnapshotPrebuilt() bool {
+	return true
+}
+
 func VendorSnapshotBinaryFactory() android.Module {
 	module, binary := NewBinary(android.DeviceSupported)
 	binary.baseLinker.Properties.No_libcrt = BoolPtr(true)
@@ -364,12 +380,98 @@
 	return module.Init()
 }
 
+type vendorSnapshotObjectProperties struct {
+	// snapshot version.
+	Version string
+
+	// Target arch name of the snapshot (e.g. 'arm64' for variant 'aosp_arm64_ab')
+	Target_arch string
+
+	// Prebuilt file for each arch.
+	Src *string `android:"arch_variant"`
+}
+
+type vendorSnapshotObjectLinker struct {
+	objectLinker
+	properties            vendorSnapshotObjectProperties
+	androidMkVendorSuffix bool
+}
+
+func (p *vendorSnapshotObjectLinker) Name(name string) string {
+	return name + p.NameSuffix()
+}
+
+func (p *vendorSnapshotObjectLinker) NameSuffix() string {
+	versionSuffix := p.version()
+	if p.arch() != "" {
+		versionSuffix += "." + p.arch()
+	}
+	return vendorSnapshotObjectSuffix + versionSuffix
+}
+
+func (p *vendorSnapshotObjectLinker) version() string {
+	return p.properties.Version
+}
+
+func (p *vendorSnapshotObjectLinker) arch() string {
+	return p.properties.Target_arch
+}
+
+func (p *vendorSnapshotObjectLinker) matchesWithDevice(config android.DeviceConfig) bool {
+	if config.DeviceArch() != p.arch() {
+		return false
+	}
+	if p.properties.Src == nil {
+		return false
+	}
+	return true
+}
+
+func (p *vendorSnapshotObjectLinker) link(ctx ModuleContext,
+	flags Flags, deps PathDeps, objs Objects) android.Path {
+	if !p.matchesWithDevice(ctx.DeviceConfig()) {
+		return nil
+	}
+
+	m := ctx.Module().(*Module)
+	p.androidMkVendorSuffix = vendorSuffixModules(ctx.Config())[m.BaseModuleName()]
+
+	return android.PathForModuleSrc(ctx, *p.properties.Src)
+}
+
+func (p *vendorSnapshotObjectLinker) nativeCoverage() bool {
+	return false
+}
+
+func (p *vendorSnapshotObjectLinker) isSnapshotPrebuilt() bool {
+	return true
+}
+
+func VendorSnapshotObjectFactory() android.Module {
+	module := newObject()
+
+	prebuilt := &vendorSnapshotObjectLinker{
+		objectLinker: objectLinker{
+			baseLinker: NewBaseLinker(nil),
+		},
+	}
+	module.linker = prebuilt
+
+	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+		vendorSnapshotLoadHook(ctx, prebuilt)
+	})
+
+	module.AddProperties(&prebuilt.properties)
+	return module.Init()
+}
+
 func init() {
 	android.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton)
 	android.RegisterModuleType("vendor_snapshot_shared", VendorSnapshotSharedFactory)
 	android.RegisterModuleType("vendor_snapshot_static", VendorSnapshotStaticFactory)
 	android.RegisterModuleType("vendor_snapshot_header", VendorSnapshotHeaderFactory)
 	android.RegisterModuleType("vendor_snapshot_binary", VendorSnapshotBinaryFactory)
+	android.RegisterModuleType("vendor_snapshot_object", VendorSnapshotObjectFactory)
 }
 
 func VendorSnapshotSingleton() android.Singleton {
@@ -429,7 +531,7 @@
 // depend on newer VNDK) So they are captured as vendor snapshot To build older vendor
 // image and newer system image altogether.
 func isVendorSnapshotModule(m *Module, moduleDir string) bool {
-	if !m.Enabled() {
+	if !m.Enabled() || m.Properties.HideFromMake {
 		return false
 	}
 	// skip proprietary modules, but include all VNDK (static)
@@ -443,37 +545,37 @@
 		return false
 	}
 	// the module must be installed in /vendor
-	if !m.installable() || m.isSnapshotPrebuilt() || !m.inVendor() {
-		return false
-	}
-	// exclude test modules
-	if _, ok := m.linker.(interface{ gtest() bool }); ok {
-		return false
-	}
-	// TODO(b/65377115): add full support for sanitizer
-	if m.sanitize != nil && !m.sanitize.isUnsanitizedVariant() {
+	if !m.IsForPlatform() || m.isSnapshotPrebuilt() || !m.inVendor() {
 		return false
 	}
 
 	// Libraries
 	if l, ok := m.linker.(snapshotLibraryInterface); ok {
+		// TODO(b/65377115): add full support for sanitizer
+		if m.sanitize != nil {
+			// cfi, scs and hwasan export both sanitized and unsanitized variants for static and header
+			// Always use unsanitized variants of them.
+			for _, t := range []sanitizerType{cfi, scs, hwasan} {
+				if !l.shared() && m.sanitize.isSanitizerEnabled(t) {
+					return false
+				}
+			}
+		}
 		if l.static() {
-			return proptools.BoolDefault(m.VendorProperties.Vendor_available, true)
+			return m.outputFile.Valid() && proptools.BoolDefault(m.VendorProperties.Vendor_available, true)
 		}
 		if l.shared() {
-			return !m.IsVndk()
+			return m.outputFile.Valid() && !m.IsVndk()
 		}
 		return true
 	}
 
-	// Binaries
-	_, ok := m.linker.(*binaryDecorator)
-	if !ok {
-		if _, ok := m.linker.(*prebuiltBinaryLinker); !ok {
-			return false
-		}
+	// Binaries and Objects
+	if m.binary() || m.object() {
+		return m.outputFile.Valid() && proptools.BoolDefault(m.VendorProperties.Vendor_available, true)
 	}
-	return proptools.BoolDefault(m.VendorProperties.Vendor_available, true)
+
+	return false
 }
 
 func (c *vendorSnapshotSingleton) GenerateBuildActions(ctx android.SingletonContext) {
@@ -496,6 +598,8 @@
 					(header only libraries)
 				binary/
 					(executable binaries)
+				object/
+					(.o object files)
 			arch-{TARGET_2ND_ARCH}-{TARGET_2ND_ARCH_VARIANT}/
 				shared/
 					(.so shared libraries)
@@ -505,6 +609,8 @@
 					(header only libraries)
 				binary/
 					(executable binaries)
+				object/
+					(.o object files)
 			NOTICE_FILES/
 				(notice files, e.g. libbase.txt)
 			configs/
@@ -620,7 +726,7 @@
 			}
 
 			propOut = filepath.Join(snapshotArchDir, targetArch, libType, stem+".json")
-		} else {
+		} else if m.binary() {
 			// binary flags
 			prop.Symlinks = m.Symlinks()
 			prop.SharedLibs = m.Properties.SnapshotSharedLibs
@@ -630,6 +736,17 @@
 			snapshotBinOut := filepath.Join(snapshotArchDir, targetArch, "binary", binPath.Base())
 			ret = append(ret, copyFile(ctx, binPath, snapshotBinOut))
 			propOut = snapshotBinOut + ".json"
+		} else if m.object() {
+			// object files aren't installed to the device, so their names can conflict.
+			// Use module name as stem.
+			objPath := m.outputFile.Path()
+			snapshotObjOut := filepath.Join(snapshotArchDir, targetArch, "object",
+				ctx.ModuleName(m)+filepath.Ext(objPath.Base()))
+			ret = append(ret, copyFile(ctx, objPath, snapshotObjOut))
+			propOut = snapshotObjOut + ".json"
+		} else {
+			ctx.Errorf("unknown module %q in vendor snapshot", m.String())
+			return nil
 		}
 
 		j, err := json.Marshal(prop)
@@ -716,6 +833,7 @@
 var _ snapshotInterface = (*vndkPrebuiltLibraryDecorator)(nil)
 var _ snapshotInterface = (*vendorSnapshotLibraryDecorator)(nil)
 var _ snapshotInterface = (*vendorSnapshotBinaryDecorator)(nil)
+var _ snapshotInterface = (*vendorSnapshotObjectLinker)(nil)
 
 // gathers all snapshot modules for vendor, and disable unnecessary snapshots
 // TODO(b/145966707): remove mutator and utilize android.Prebuilt to override source modules
@@ -731,12 +849,12 @@
 		return
 	}
 
-	snapshot, ok := module.linker.(snapshotInterface)
-	if !ok {
+	if !module.isSnapshotPrebuilt() {
 		return
 	}
 
-	if !snapshot.matchesWithDevice(ctx.DeviceConfig()) {
+	// isSnapshotPrebuilt ensures snapshotInterface
+	if !module.linker.(snapshotInterface).matchesWithDevice(ctx.DeviceConfig()) {
 		// Disable unnecessary snapshot module, but do not disable
 		// vndk_prebuilt_shared because they might be packed into vndk APEX
 		if !module.IsVndk() {
@@ -758,6 +876,8 @@
 		}
 	} else if _, ok := module.linker.(*vendorSnapshotBinaryDecorator); ok {
 		snapshotMap = vendorSnapshotBinaries(ctx.Config())
+	} else if _, ok := module.linker.(*vendorSnapshotObjectLinker); ok {
+		snapshotMap = vendorSnapshotObjects(ctx.Config())
 	} else {
 		return
 	}
@@ -804,6 +924,11 @@
 		return
 	}
 
+	// .. and also filter out llndk library
+	if module.isLlndk(ctx.Config()) {
+		return
+	}
+
 	var snapshotMap *snapshotMap
 
 	if lib, ok := module.linker.(libraryInterface); ok {
@@ -815,10 +940,10 @@
 			// header
 			snapshotMap = vendorSnapshotHeaderLibs(ctx.Config())
 		}
-	} else if _, ok := module.linker.(*binaryDecorator); ok {
+	} else if module.binary() {
 		snapshotMap = vendorSnapshotBinaries(ctx.Config())
-	} else if _, ok := module.linker.(*prebuiltBinaryLinker); ok {
-		snapshotMap = vendorSnapshotBinaries(ctx.Config())
+	} else if module.object() {
+		snapshotMap = vendorSnapshotObjects(ctx.Config())
 	} else {
 		return
 	}
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index 53b5181..5a44c46 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -186,6 +186,10 @@
 	return false
 }
 
+func (p *vndkPrebuiltLibraryDecorator) isSnapshotPrebuilt() bool {
+	return true
+}
+
 func (p *vndkPrebuiltLibraryDecorator) install(ctx ModuleContext, file android.Path) {
 	arches := ctx.DeviceConfig().Arches()
 	if len(arches) == 0 || arches[0].ArchType.String() != p.arch() {
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 0148161..3440f8e 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -100,6 +100,15 @@
 	ConstructContext android.Path
 }
 
+// LibraryPath contains paths to the library DEX jar on host and on device.
+type LibraryPath struct {
+	Host   android.Path
+	Device string
+}
+
+// LibraryPaths is a map from library name to on-host and on-device paths to its DEX jar.
+type LibraryPaths map[string]*LibraryPath
+
 type ModuleConfig struct {
 	Name            string
 	DexLocation     string // dex location on device
@@ -117,7 +126,7 @@
 	EnforceUsesLibraries         bool
 	PresentOptionalUsesLibraries []string
 	UsesLibraries                []string
-	LibraryPaths                 map[string]android.Path
+	LibraryPaths                 LibraryPaths
 
 	Archs                   []android.ArchType
 	DexPreoptImages         []android.Path
@@ -165,14 +174,6 @@
 	return ret
 }
 
-func constructPathMap(ctx android.PathContext, paths map[string]string) map[string]android.Path {
-	ret := map[string]android.Path{}
-	for key, path := range paths {
-		ret[key] = constructPath(ctx, path)
-	}
-	return ret
-}
-
 func constructWritablePath(ctx android.PathContext, path string) android.WritablePath {
 	if path == "" {
 		return nil
@@ -264,6 +265,13 @@
 // from Make to read the module dexpreopt.config written in the Make config
 // stage.
 func ParseModuleConfig(ctx android.PathContext, data []byte) (*ModuleConfig, error) {
+	type jsonLibraryPath struct {
+		Host   string
+		Device string
+	}
+
+	type jsonLibraryPaths map[string]jsonLibraryPath
+
 	type ModuleJSONConfig struct {
 		*ModuleConfig
 
@@ -273,12 +281,24 @@
 		DexPath                     string
 		ManifestPath                string
 		ProfileClassListing         string
-		LibraryPaths                map[string]string
+		LibraryPaths                jsonLibraryPaths
 		DexPreoptImages             []string
 		DexPreoptImageLocations     []string
 		PreoptBootClassPathDexFiles []string
 	}
 
+	// convert JSON map of library paths to LibraryPaths
+	constructLibraryPaths := func(ctx android.PathContext, paths jsonLibraryPaths) LibraryPaths {
+		m := LibraryPaths{}
+		for lib, path := range paths {
+			m[lib] = &LibraryPath{
+				constructPath(ctx, path.Host),
+				path.Device,
+			}
+		}
+		return m
+	}
+
 	config := ModuleJSONConfig{}
 
 	err := json.Unmarshal(data, &config)
@@ -291,7 +311,7 @@
 	config.ModuleConfig.DexPath = constructPath(ctx, config.DexPath)
 	config.ModuleConfig.ManifestPath = constructPath(ctx, config.ManifestPath)
 	config.ModuleConfig.ProfileClassListing = android.OptionalPathForPath(constructPath(ctx, config.ProfileClassListing))
-	config.ModuleConfig.LibraryPaths = constructPathMap(ctx, config.LibraryPaths)
+	config.ModuleConfig.LibraryPaths = constructLibraryPaths(ctx, config.LibraryPaths)
 	config.ModuleConfig.DexPreoptImages = constructPaths(ctx, config.DexPreoptImages)
 	config.ModuleConfig.DexPreoptImageLocations = config.DexPreoptImageLocations
 	config.ModuleConfig.PreoptBootClassPathDexFiles = constructPaths(ctx, config.PreoptBootClassPathDexFiles)
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 8e65ca6..57a9250 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -229,8 +229,9 @@
 func (m classLoaderContextMap) addLibs(sdkVer int, module *ModuleConfig, libs ...string) {
 	clc := m.getValue(sdkVer)
 	for _, lib := range libs {
-		clc.Host = append(clc.Host, pathForLibrary(module, lib))
-		clc.Target = append(clc.Target, filepath.Join("/system/framework", lib+".jar"))
+		p := pathForLibrary(module, lib)
+		clc.Host = append(clc.Host, p.Host)
+		clc.Target = append(clc.Target, p.Device)
 	}
 }
 
@@ -557,7 +558,7 @@
 	return filepath.Join(filepath.Dir(filepath.Dir(path.String())), filepath.Base(path.String()))
 }
 
-func pathForLibrary(module *ModuleConfig, lib string) android.Path {
+func pathForLibrary(module *ModuleConfig, lib string) *LibraryPath {
 	path, ok := module.LibraryPaths[lib]
 	if !ok {
 		panic(fmt.Errorf("unknown library path for %q", lib))
diff --git a/java/aar.go b/java/aar.go
index c8daf83..7413c80 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -730,7 +730,7 @@
 	return android.Paths{a.classpathFile}
 }
 
-func (a *AARImport) DexJar() android.Path {
+func (a *AARImport) DexJarBuildPath() android.Path {
 	return nil
 }
 
diff --git a/java/app.go b/java/app.go
index a45ab6f..1b7785d 100755
--- a/java/app.go
+++ b/java/app.go
@@ -28,6 +28,7 @@
 
 	"android/soong/android"
 	"android/soong/cc"
+	"android/soong/dexpreopt"
 	"android/soong/tradefed"
 )
 
@@ -96,6 +97,14 @@
 	return Bool(as.properties.Privileged)
 }
 
+func (as *AndroidAppSet) OutputFile() android.Path {
+	return as.packedOutput
+}
+
+func (as *AndroidAppSet) MasterFile() string {
+	return as.masterFile
+}
+
 var TargetCpuAbi = map[string]string{
 	"arm":    "ARMEABI_V7A",
 	"arm64":  "ARM64_V8A",
@@ -120,7 +129,7 @@
 }
 
 func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) {
-	as.packedOutput = android.PathForModuleOut(ctx, "extracted.zip")
+	as.packedOutput = android.PathForModuleOut(ctx, ctx.ModuleName()+".zip")
 	// We are assuming here that the master file in the APK
 	// set has `.apk` suffix. If it doesn't the build will fail.
 	// APK sets containing APEX files are handled elsewhere.
@@ -145,26 +154,17 @@
 				"stem":              ctx.ModuleName(),
 			},
 		})
-	// TODO(asmundak): add this (it's wrong now, will cause copying extracted.zip)
-	/*
-		var installDir android.InstallPath
-		if Bool(as.properties.Privileged) {
-			installDir = android.PathForModuleInstall(ctx, "priv-app", as.BaseModuleName())
-		} else if ctx.InstallInTestcases() {
-			installDir = android.PathForModuleInstall(ctx, as.BaseModuleName(), ctx.DeviceConfig().DeviceArch())
-		} else {
-			installDir = android.PathForModuleInstall(ctx, "app", as.BaseModuleName())
-		}
-		ctx.InstallFile(installDir, as.masterFile", as.packedOutput)
-	*/
 }
 
 // android_app_set extracts a set of APKs based on the target device
 // configuration and installs this set as "split APKs".
-// The set will always contain `base-master.apk` and every APK built
-// to the target device. All density-specific APK will be included, too,
-// unless PRODUCT_APPT_PREBUILT_DPI is defined (should contain comma-sepearated
-// list of density names (LDPI, MDPI, HDPI, etc.)
+// The extracted set always contains 'master' APK whose name is
+// _module_name_.apk and every split APK matching target device.
+// The extraction of the density-specific splits depends on
+// PRODUCT_AAPT_PREBUILT_DPI variable. If present (its value should
+// be a list density names: LDPI, MDPI, HDPI, etc.), only listed
+// splits will be extracted. Otherwise all density-specific splits
+// will be extracted.
 func AndroidApkSetFactory() android.Module {
 	module := &AndroidAppSet{}
 	module.AddProperties(&module.properties)
@@ -335,7 +335,7 @@
 	presigned bool
 }
 
-var presignedCertificate = Certificate{presigned: true}
+var PresignedCertificate = Certificate{presigned: true}
 
 func (c Certificate) AndroidMkString() string {
 	if c.presigned {
@@ -445,8 +445,11 @@
 			return
 		}
 		dep, _ := m.(*cc.Module)
-		jniSdkVersion, err := android.ApiStrToNum(ctx, dep.SdkVersion())
-		if err != nil || int(minSdkVersion) < jniSdkVersion {
+		// The domain of cc.sdk_version is "current" and <number>
+		// We can rely on sdkSpec to convert it to <number> so that "current" is handled
+		// properly regardless of sdk finalization.
+		jniSdkVersion, err := sdkSpecFrom(dep.SdkVersion()).effectiveVersion(ctx)
+		if err != nil || minSdkVersion < jniSdkVersion {
 			ctx.OtherModuleErrorf(dep, "sdk_version(%v) is higher than min_sdk_version(%v) of the containing android_app(%v)",
 				dep.SdkVersion(), minSdkVersion, ctx.ModuleName())
 			return
@@ -970,10 +973,6 @@
 		&module.overridableAppProperties,
 		&module.usesLibrary.usesLibraryProperties)
 
-	module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool {
-		return class == android.Device && ctx.Config().DevicePrefer32BitApps()
-	})
-
 	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
 	android.InitDefaultableModule(module)
 	android.InitOverridableModule(module, &module.appProperties.Overrides)
@@ -1186,7 +1185,7 @@
 	android.OverrideModuleBase
 }
 
-func (i *OverrideAndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+func (i *OverrideAndroidApp) GenerateAndroidBuildActions(_ android.ModuleContext) {
 	// All the overrides happen in the base module.
 	// TODO(jungjw): Check the base module type.
 }
@@ -1207,7 +1206,7 @@
 	android.OverrideModuleBase
 }
 
-func (i *OverrideAndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+func (i *OverrideAndroidTest) GenerateAndroidBuildActions(_ android.ModuleContext) {
 	// All the overrides happen in the base module.
 	// TODO(jungjw): Check the base module type.
 }
@@ -1229,7 +1228,7 @@
 	android.OverrideModuleBase
 }
 
-func (i *OverrideRuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+func (i *OverrideRuntimeResourceOverlay) GenerateAndroidBuildActions(_ android.ModuleContext) {
 	// All the overrides happen in the base module.
 	// TODO(jungjw): Check the base module type.
 }
@@ -1474,7 +1473,7 @@
 	// Sign or align the package if package has not been preprocessed
 	if a.preprocessed {
 		a.outputFile = srcApk
-		a.certificate = presignedCertificate
+		a.certificate = PresignedCertificate
 	} else if !Bool(a.properties.Presigned) {
 		// If the certificate property is empty at this point, default_dev_cert must be set to true.
 		// Which makes processMainCert's behavior for the empty cert string WAI.
@@ -1494,7 +1493,7 @@
 		alignedApk := android.PathForModuleOut(ctx, "zip-aligned", apkFilename)
 		TransformZipAlign(ctx, alignedApk, dexOutput)
 		a.outputFile = alignedApk
-		a.certificate = presignedCertificate
+		a.certificate = PresignedCertificate
 	}
 
 	// TODO: Optionally compress the output apk.
@@ -1552,7 +1551,7 @@
 	return Bool(a.properties.Privileged)
 }
 
-func (a *AndroidAppImport) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
+func (a *AndroidAppImport) DepIsInSameApex(_ android.BaseModuleContext, _ android.Module) bool {
 	// android_app_import might have extra dependencies via uses_libs property.
 	// Don't track the dependency as we don't automatically add those libraries
 	// to the classpath. It should be explicitly added to java_libs property of APEX
@@ -1875,24 +1874,30 @@
 	return optionalUsesLibs
 }
 
-// usesLibraryPaths returns a map of module names of shared library dependencies to the paths to their dex jars.
-func (u *usesLibrary) usesLibraryPaths(ctx android.ModuleContext) map[string]android.Path {
-	usesLibPaths := make(map[string]android.Path)
+// usesLibraryPaths returns a map of module names of shared library dependencies to the paths
+// to their dex jars on host and on device.
+func (u *usesLibrary) usesLibraryPaths(ctx android.ModuleContext) dexpreopt.LibraryPaths {
+	usesLibPaths := make(dexpreopt.LibraryPaths)
 
 	if !ctx.Config().UnbundledBuild() {
 		ctx.VisitDirectDepsWithTag(usesLibTag, func(m android.Module) {
+			dep := ctx.OtherModuleName(m)
 			if lib, ok := m.(Dependency); ok {
-				if dexJar := lib.DexJar(); dexJar != nil {
-					usesLibPaths[ctx.OtherModuleName(m)] = dexJar
+				if dexJar := lib.DexJarBuildPath(); dexJar != nil {
+					usesLibPaths[dep] = &dexpreopt.LibraryPath{
+						dexJar,
+						// TODO(b/132357300): propagate actual install paths here.
+						filepath.Join("/system/framework", dep+".jar"),
+					}
 				} else {
-					ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must produce a dex jar, does it have installable: true?",
-						ctx.OtherModuleName(m))
+					ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must"+
+						" produce a dex jar, does it have installable: true?", dep)
 				}
 			} else if ctx.Config().AllowMissingDependencies() {
-				ctx.AddMissingDependencies([]string{ctx.OtherModuleName(m)})
+				ctx.AddMissingDependencies([]string{dep})
 			} else {
-				ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be a java library",
-					ctx.OtherModuleName(m))
+				ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must be "+
+					"a java library", dep)
 			}
 		})
 	}
diff --git a/java/app_test.go b/java/app_test.go
index eb583be..eeba161 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -149,7 +149,7 @@
 			prerelease: true,
         }`)
 	module := ctx.ModuleForTests("foo", "android_common")
-	const packedSplitApks = "extracted.zip"
+	const packedSplitApks = "foo.zip"
 	params := module.Output(packedSplitApks)
 	if params.Rule == nil {
 		t.Errorf("expected output %s is missing", packedSplitApks)
@@ -218,7 +218,7 @@
 		ctx := testContext()
 		run(t, ctx, config)
 		module := ctx.ModuleForTests("foo", "android_common")
-		const packedSplitApks = "extracted.zip"
+		const packedSplitApks = "foo.zip"
 		params := module.Output(packedSplitApks)
 		for k, v := range test.expected {
 			if actual := params.Args[k]; actual != v {
diff --git a/java/config/config.go b/java/config/config.go
index edaed2a..bb5be3a 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -28,8 +28,9 @@
 var (
 	pctx = android.NewPackageContext("android/soong/java/config")
 
-	DefaultBootclasspathLibraries = []string{"core.platform.api.stubs", "core-lambda-stubs"}
-	DefaultSystemModules          = "core-platform-api-stubs-system-modules"
+	// TODO(b/157640067): Don't depend on the legacy API by default in the long term.
+	DefaultBootclasspathLibraries = []string{"legacy.core.platform.api.stubs", "core-lambda-stubs"}
+	DefaultSystemModules          = "legacy-core-platform-api-stubs-system-modules"
 	DefaultLibraries              = []string{"ext", "framework"}
 	DefaultLambdaStubsLibrary     = "core-lambda-stubs"
 	SdkLambdaStubsPath            = "prebuilts/sdk/tools/core-lambda-stubs.jar"
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index b40ab93..1ffb13f 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -150,7 +150,7 @@
 	return d.implementationAndResourceJars
 }
 
-func (d *DeviceHostConverter) DexJar() android.Path {
+func (d *DeviceHostConverter) DexJarBuildPath() android.Path {
 	return nil
 }
 
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 4725b07..2911fd9 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -37,7 +37,7 @@
 	usesLibs         []string
 	optionalUsesLibs []string
 	enforceUsesLibs  bool
-	libraryPaths     map[string]android.Path
+	libraryPaths     dexpreopt.LibraryPaths
 
 	builtInstalled string
 }
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index ed61d4b..9d93838 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -255,7 +255,7 @@
 		return -1, nil
 	}
 
-	jar, hasJar := module.(interface{ DexJar() android.Path })
+	jar, hasJar := module.(interface{ DexJarBuildPath() android.Path })
 	if !hasJar {
 		return -1, nil
 	}
@@ -296,7 +296,7 @@
 		panic("unknown boot image: " + image.name)
 	}
 
-	return index, jar.DexJar()
+	return index, jar.DexJarBuildPath()
 }
 
 // buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image.
diff --git a/java/droiddoc.go b/java/droiddoc.go
index b16c9cd..4c3e112 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -1334,13 +1334,10 @@
 		d.annotationsZip = android.PathForModuleOut(ctx, ctx.ModuleName()+"_annotations.zip")
 		cmd.FlagWithOutput("--extract-annotations ", d.annotationsZip)
 
-		if len(d.properties.Merge_annotations_dirs) == 0 {
-			ctx.PropertyErrorf("merge_annotations_dirs",
-				"has to be non-empty if annotations was enabled!")
+		if len(d.properties.Merge_annotations_dirs) != 0 {
+			d.mergeAnnoDirFlags(ctx, cmd)
 		}
 
-		d.mergeAnnoDirFlags(ctx, cmd)
-
 		// TODO(tnorbye): find owners to fix these warnings when annotation was enabled.
 		cmd.FlagWithArg("--hide ", "HiddenTypedefConstant").
 			FlagWithArg("--hide ", "SuperfluousPrefix").
@@ -1427,10 +1424,9 @@
 	rule.HighMem()
 	cmd := rule.Command()
 
-	rspFile := ""
+	var implicitsRsp android.WritablePath
 	if len(implicits) > 0 {
-		implicitsRsp := android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"implicits.rsp")
-		rspFile = implicitsRsp.String()
+		implicitsRsp = android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"implicits.rsp")
 		impRule := android.NewRuleBuilder()
 		impCmd := impRule.Command()
 		// A dummy action that copies the ninja generated rsp file to a new location. This allows us to
@@ -1457,10 +1453,10 @@
 			inputs = append(inputs, strings.Split(v, ",")...)
 		}
 		cmd.Text((&remoteexec.REParams{
-			Labels:          map[string]string{"type": "compile", "lang": "java", "compiler": "metalava"},
+			Labels:          map[string]string{"type": "compile", "lang": "java", "compiler": "metalava", "shallow": "true"},
 			ExecStrategy:    execStrategy,
 			Inputs:          inputs,
-			RSPFile:         rspFile,
+			RSPFile:         implicitsRsp.String(),
 			ToolchainInputs: []string{config.JavaCmd(ctx).String()},
 			Platform:        map[string]string{remoteexec.PoolKey: pool},
 		}).NoVarTemplate(ctx.Config()))
@@ -1471,7 +1467,12 @@
 		FlagWithArg("-encoding ", "UTF-8").
 		FlagWithArg("-source ", javaVersion.String()).
 		FlagWithRspFileInputList("@", srcs).
-		FlagWithInput("@", srcJarList)
+		FlagWithInput("@", srcJarList).
+		FlagWithOutput("--strict-input-files:warn ", android.PathForModuleOut(ctx, ctx.ModuleName()+"-"+"violations.txt"))
+
+	if implicitsRsp.String() != "" {
+		cmd.FlagWithArg("--strict-input-files-exempt ", "@"+implicitsRsp.String())
+	}
 
 	if len(bootclasspath) > 0 {
 		cmd.FlagWithInputList("-bootclasspath ", bootclasspath.Paths(), ":")
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index c7f7cbd..bff591c 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -116,7 +116,7 @@
 
 	// Core Platform API stubs
 	corePlatformStubModules := []string{
-		"core.platform.api.stubs",
+		"legacy.core.platform.api.stubs",
 	}
 
 	// Allow products to define their own stubs for custom product jars that apps can use.
@@ -147,7 +147,7 @@
 			name := ctx.ModuleName(module)
 			for moduleList, pathList := range moduleListToPathList {
 				if i := android.IndexList(name, *moduleList); i != -1 {
-					pathList[i] = j.DexJar()
+					pathList[i] = j.DexJarBuildPath()
 				}
 			}
 		}
diff --git a/java/java.go b/java/java.go
index eaf0fe9..226e0b9 100644
--- a/java/java.go
+++ b/java/java.go
@@ -501,7 +501,7 @@
 	ImplementationJars() android.Paths
 	ResourceJars() android.Paths
 	ImplementationAndResourcesJars() android.Paths
-	DexJar() android.Path
+	DexJarBuildPath() android.Path
 	AidlIncludeDirs() android.Paths
 	ExportedSdkLibs() []string
 	ExportedPlugins() (android.Paths, []string)
@@ -836,41 +836,47 @@
 }
 
 func (m *Module) getLinkType(name string) (ret linkType, stubs bool) {
-	ver := m.sdkVersion()
-	switch {
-	case name == "core.current.stubs" || name == "core.platform.api.stubs" ||
-		name == "stub-annotations" || name == "private-stub-annotations-jar" ||
-		name == "core-lambda-stubs" || name == "core-generated-annotation-stubs":
+	switch name {
+	case "core.current.stubs", "legacy.core.platform.api.stubs", "stable.core.platform.api.stubs",
+		"stub-annotations", "private-stub-annotations-jar",
+		"core-lambda-stubs", "core-generated-annotation-stubs":
 		return javaCore, true
-	case ver.kind == sdkCore:
-		return javaCore, false
-	case name == "android_system_stubs_current":
-		return javaSystem, true
-	case ver.kind == sdkSystem:
-		return javaSystem, false
-	case name == "android_test_stubs_current":
-		return javaSystem, true
-	case ver.kind == sdkTest:
-		return javaPlatform, false
-	case name == "android_stubs_current":
+	case "android_stubs_current":
 		return javaSdk, true
-	case ver.kind == sdkPublic:
-		return javaSdk, false
-	case name == "android_module_lib_stubs_current":
+	case "android_system_stubs_current":
+		return javaSystem, true
+	case "android_module_lib_stubs_current":
 		return javaModule, true
-	case ver.kind == sdkModule:
-		return javaModule, false
-	case name == "android_system_server_stubs_current":
+	case "android_system_server_stubs_current":
 		return javaSystemServer, true
-	case ver.kind == sdkSystemServer:
-		return javaSystemServer, false
-	case ver.kind == sdkPrivate || ver.kind == sdkNone || ver.kind == sdkCorePlatform:
-		return javaPlatform, false
-	case !ver.valid():
-		panic(fmt.Errorf("sdk_version is invalid. got %q", ver.raw))
-	default:
-		return javaSdk, false
+	case "android_test_stubs_current":
+		return javaSystem, true
 	}
+
+	if stub, linkType := moduleStubLinkType(name); stub {
+		return linkType, true
+	}
+
+	ver := m.sdkVersion()
+	switch ver.kind {
+	case sdkCore:
+		return javaCore, false
+	case sdkSystem:
+		return javaSystem, false
+	case sdkPublic:
+		return javaSdk, false
+	case sdkModule:
+		return javaModule, false
+	case sdkSystemServer:
+		return javaSystemServer, false
+	case sdkPrivate, sdkNone, sdkCorePlatform, sdkTest:
+		return javaPlatform, false
+	}
+
+	if !ver.valid() {
+		panic(fmt.Errorf("sdk_version is invalid. got %q", ver.raw))
+	}
+	return javaSdk, false
 }
 
 func checkLinkType(ctx android.ModuleContext, from *Module, to linkTypeContext, tag dependencyTag) {
@@ -1739,7 +1745,7 @@
 	return android.Paths{j.implementationJarFile}
 }
 
-func (j *Module) DexJar() android.Path {
+func (j *Module) DexJarBuildPath() android.Path {
 	return j.dexJarFile
 }
 
@@ -2565,7 +2571,7 @@
 	return android.Paths{j.combinedClasspathFile}
 }
 
-func (j *Import) DexJar() android.Path {
+func (j *Import) DexJarBuildPath() android.Path {
 	return nil
 }
 
@@ -2748,11 +2754,13 @@
 
 	j.maybeStrippedDexJarFile = dexOutputFile
 
-	ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
-		j.Stem()+".jar", dexOutputFile)
+	if j.IsForPlatform() {
+		ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
+			j.Stem()+".jar", dexOutputFile)
+	}
 }
 
-func (j *DexImport) DexJar() android.Path {
+func (j *DexImport) DexJarBuildPath() android.Path {
 	return j.dexJarFile
 }
 
diff --git a/java/sdk.go b/java/sdk.go
index 9310f78..2a08f32 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -35,6 +35,7 @@
 
 var sdkVersionsKey = android.NewOnceKey("sdkVersionsKey")
 var sdkFrameworkAidlPathKey = android.NewOnceKey("sdkFrameworkAidlPathKey")
+var nonUpdatableFrameworkAidlPathKey = android.NewOnceKey("nonUpdatableFrameworkAidlPathKey")
 var apiFingerprintPathKey = android.NewOnceKey("apiFingerprintPathKey")
 
 type sdkContext interface {
@@ -447,7 +448,7 @@
 		return toModule([]string{"core.current.stubs"}, "", nil)
 	case sdkModule:
 		// TODO(146757305): provide .apk and .aidl that have more APIs for modules
-		return toModule([]string{"android_module_lib_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx))
+		return toModule([]string{"android_module_lib_stubs_current"}, "framework-res", nonUpdatableFrameworkAidlPath(ctx))
 	case sdkSystemServer:
 		// TODO(146757305): provide .apk and .aidl that have more APIs for modules
 		return toModule([]string{"android_system_server_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx))
@@ -506,6 +507,7 @@
 	}
 
 	createSdkFrameworkAidl(ctx)
+	createNonUpdatableFrameworkAidl(ctx)
 	createAPIFingerprint(ctx)
 }
 
@@ -517,6 +519,31 @@
 		"android_system_stubs_current",
 	}
 
+	combinedAidl := sdkFrameworkAidlPath(ctx)
+	tempPath := combinedAidl.ReplaceExtension(ctx, "aidl.tmp")
+
+	rule := createFrameworkAidl(stubsModules, tempPath, ctx)
+
+	commitChangeForRestat(rule, tempPath, combinedAidl)
+
+	rule.Build(pctx, ctx, "framework_aidl", "generate framework.aidl")
+}
+
+// Creates a version of framework.aidl for the non-updatable part of the platform.
+func createNonUpdatableFrameworkAidl(ctx android.SingletonContext) {
+	stubsModules := []string{"android_module_lib_stubs_current"}
+
+	combinedAidl := nonUpdatableFrameworkAidlPath(ctx)
+	tempPath := combinedAidl.ReplaceExtension(ctx, "aidl.tmp")
+
+	rule := createFrameworkAidl(stubsModules, tempPath, ctx)
+
+	commitChangeForRestat(rule, tempPath, combinedAidl)
+
+	rule.Build(pctx, ctx, "framework_non_updatable_aidl", "generate framework_non_updatable.aidl")
+}
+
+func createFrameworkAidl(stubsModules []string, path android.OutputPath, ctx android.SingletonContext) *android.RuleBuilder {
 	stubsJars := make([]android.Paths, len(stubsModules))
 
 	ctx.VisitAllModules(func(module android.Module) {
@@ -536,8 +563,7 @@
 			if ctx.Config().AllowMissingDependencies() {
 				missingDeps = append(missingDeps, stubsModules[i])
 			} else {
-				ctx.Errorf("failed to find dex jar path for module %q",
-					stubsModules[i])
+				ctx.Errorf("failed to find dex jar path for module %q", stubsModules[i])
 			}
 		}
 	}
@@ -561,20 +587,15 @@
 		}
 	}
 
-	combinedAidl := sdkFrameworkAidlPath(ctx)
-	tempPath := combinedAidl.ReplaceExtension(ctx, "aidl.tmp")
-
 	rule.Command().
-		Text("rm -f").Output(tempPath)
+		Text("rm -f").Output(path)
 	rule.Command().
 		Text("cat").
 		Inputs(aidls).
 		Text("| sort -u >").
-		Output(tempPath)
+		Output(path)
 
-	commitChangeForRestat(rule, tempPath, combinedAidl)
-
-	rule.Build(pctx, ctx, "framework_aidl", "generate framework.aidl")
+	return rule
 }
 
 func sdkFrameworkAidlPath(ctx android.PathContext) android.OutputPath {
@@ -583,6 +604,12 @@
 	}).(android.OutputPath)
 }
 
+func nonUpdatableFrameworkAidlPath(ctx android.PathContext) android.OutputPath {
+	return ctx.Config().Once(nonUpdatableFrameworkAidlPathKey, func() interface{} {
+		return android.PathForOutput(ctx, "framework_non_updatable.aidl")
+	}).(android.OutputPath)
+}
+
 // Create api_fingerprint.txt
 func createAPIFingerprint(ctx android.SingletonContext) {
 	out := ApiFingerprintPath(ctx)
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 67b0bd6..de5ee03 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1113,7 +1113,9 @@
 	props.Product_variables.Pdk.Enabled = proptools.BoolPtr(false)
 	props.Openjdk9.Srcs = module.properties.Openjdk9.Srcs
 	props.Openjdk9.Javacflags = module.properties.Openjdk9.Javacflags
-	props.Java_version = module.properties.Java_version
+	// We compile the stubs for 1.8 in line with the main android.jar stubs, and potential
+	// interop with older developer tools that don't support 1.9.
+	props.Java_version = proptools.StringPtr("1.8")
 	if module.deviceProperties.Compile_dex != nil {
 		props.Compile_dex = module.deviceProperties.Compile_dex
 	}
@@ -1575,6 +1577,24 @@
 
 var _ sdkLibraryComponentNamingScheme = (*frameworkModulesNamingScheme)(nil)
 
+func moduleStubLinkType(name string) (stub bool, ret linkType) {
+	// This suffix-based approach is fragile and could potentially mis-trigger.
+	// TODO(b/155164730): Clean this up when modules no longer reference sdk_lib stubs directly.
+	if strings.HasSuffix(name, ".stubs.public") || strings.HasSuffix(name, "-stubs-publicapi") {
+		return true, javaSdk
+	}
+	if strings.HasSuffix(name, ".stubs.system") || strings.HasSuffix(name, "-stubs-systemapi") {
+		return true, javaSystem
+	}
+	if strings.HasSuffix(name, ".stubs.module_lib") || strings.HasSuffix(name, "-stubs-module_libs_api") {
+		return true, javaModule
+	}
+	if strings.HasSuffix(name, ".stubs.test") {
+		return true, javaSystem
+	}
+	return false, javaPlatform
+}
+
 // java_sdk_library is a special Java library that provides optional platform APIs to apps.
 // In practice, it can be viewed as a combination of several modules: 1) stubs library that clients
 // are linked against to, 2) droiddoc module that internally generates API stubs source files,
diff --git a/java/sdk_test.go b/java/sdk_test.go
index fb86463..e5d322c 100644
--- a/java/sdk_test.go
+++ b/java/sdk_test.go
@@ -156,9 +156,9 @@
 		{
 
 			name:           "nostdlib system_modules",
-			properties:     `sdk_version: "none", system_modules: "core-platform-api-stubs-system-modules"`,
-			system:         "core-platform-api-stubs-system-modules",
-			bootclasspath:  []string{"core-platform-api-stubs-system-modules-lib"},
+			properties:     `sdk_version: "none", system_modules: "legacy-core-platform-api-stubs-system-modules"`,
+			system:         "legacy-core-platform-api-stubs-system-modules",
+			bootclasspath:  []string{"legacy-core-platform-api-stubs-system-modules-lib"},
 			java8classpath: []string{},
 		},
 		{
@@ -252,7 +252,7 @@
 			bootclasspath:  []string{"android_module_lib_stubs_current", "core-lambda-stubs"},
 			system:         "core-current-stubs-system-modules",
 			java9classpath: []string{"android_module_lib_stubs_current"},
-			aidl:           "-p" + buildDir + "/framework.aidl",
+			aidl:           "-p" + buildDir + "/framework_non_updatable.aidl",
 		},
 		{
 			name:           "system_server_current",
diff --git a/java/testing.go b/java/testing.go
index faf4d32..f993f56 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -173,7 +173,8 @@
 		"android_module_lib_stubs_current",
 		"android_system_server_stubs_current",
 		"core.current.stubs",
-		"core.platform.api.stubs",
+		"legacy.core.platform.api.stubs",
+		"stable.core.platform.api.stubs",
 		"kotlin-stdlib",
 		"kotlin-stdlib-jdk7",
 		"kotlin-stdlib-jdk8",
@@ -186,7 +187,7 @@
 				name: "%s",
 				srcs: ["a.java"],
 				sdk_version: "none",
-				system_modules: "core-platform-api-stubs-system-modules",
+				system_modules: "legacy-core-platform-api-stubs-system-modules",
 			}
 		`, extra)
 	}
@@ -196,7 +197,7 @@
 			name: "framework",
 			srcs: ["a.java"],
 			sdk_version: "none",
-			system_modules: "core-platform-api-stubs-system-modules",
+			system_modules: "legacy-core-platform-api-stubs-system-modules",
 			aidl: {
 				export_include_dirs: ["framework/aidl"],
 			},
@@ -211,7 +212,7 @@
 			name: "android.hidl.base-V1.0-java",
 			srcs: ["a.java"],
 			sdk_version: "none",
-			system_modules: "core-platform-api-stubs-system-modules",
+			system_modules: "legacy-core-platform-api-stubs-system-modules",
 			installable: true,
 		}
 
@@ -219,7 +220,7 @@
 			name: "android.hidl.manager-V1.0-java",
 			srcs: ["a.java"],
 			sdk_version: "none",
-			system_modules: "core-platform-api-stubs-system-modules",
+			system_modules: "legacy-core-platform-api-stubs-system-modules",
 			installable: true,
 		}
 
@@ -227,7 +228,7 @@
 			name: "org.apache.http.legacy",
 			srcs: ["a.java"],
 			sdk_version: "none",
-			system_modules: "core-platform-api-stubs-system-modules",
+			system_modules: "legacy-core-platform-api-stubs-system-modules",
 			installable: true,
 		}
 
@@ -235,7 +236,7 @@
 			name: "android.test.base",
 			srcs: ["a.java"],
 			sdk_version: "none",
-			system_modules: "core-platform-api-stubs-system-modules",
+			system_modules: "legacy-core-platform-api-stubs-system-modules",
 			installable: true,
 		}
   
@@ -243,14 +244,14 @@
 			name: "android.test.mock",
 			srcs: ["a.java"],
 			sdk_version: "none",
-			system_modules: "core-platform-api-stubs-system-modules",
+			system_modules: "legacy-core-platform-api-stubs-system-modules",
 			installable: true,
 		}
 	`
 
 	systemModules := []string{
 		"core-current-stubs-system-modules",
-		"core-platform-api-stubs-system-modules",
+		"legacy-core-platform-api-stubs-system-modules",
 	}
 
 	for _, extra := range systemModules {
diff --git a/rust/library.go b/rust/library.go
index 8aa033c..2e51266 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -329,12 +329,21 @@
 
 	return deps
 }
+
+func (library *libraryDecorator) sharedLibFilename(ctx ModuleContext) string {
+	return library.getStem(ctx) + ctx.toolchain().SharedLibSuffix()
+}
+
 func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
 	flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.baseModuleName())
 	flags = library.baseCompiler.compilerFlags(ctx, flags)
 	if library.shared() || library.static() {
 		library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...)
 	}
+	if library.shared() {
+		flags.LinkFlags = append(flags.LinkFlags, "-Wl,-soname="+library.sharedLibFilename(ctx))
+	}
+
 	return flags
 }
 
@@ -371,7 +380,7 @@
 		outputs := TransformSrctoStatic(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
 		library.coverageFile = outputs.coverageFile
 	} else if library.shared() {
-		fileName := library.getStem(ctx) + ctx.toolchain().SharedLibSuffix()
+		fileName := library.sharedLibFilename(ctx)
 		outputFile = android.PathForModuleOut(ctx, fileName)
 
 		outputs := TransformSrctoShared(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
diff --git a/rust/library_test.go b/rust/library_test.go
index 9f9f374..37dd541 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -114,3 +114,17 @@
 			}`)
 
 }
+
+func TestSharedLibraryFlags(t *testing.T) {
+	ctx := testRust(t, `
+		rust_library_host {
+			name: "libfoo",
+			srcs: ["foo.rs"],
+			crate_name: "foo",
+		}`)
+
+	libfooShared := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_shared").Output("libfoo.so")
+	if !strings.Contains(libfooShared.Args["linkFlags"], "-Wl,-soname=libfoo.so") {
+		t.Errorf("missing expected -Wl,-soname linker flag for libfoo shared lib, linkFlags: %#v", libfooShared.Args["linkFlags"])
+	}
+}
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index af792f2..56706c7 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -43,10 +43,10 @@
 	name: "core-current-stubs-system-modules",
 }
 java_system_modules_import {
-	name: "core-platform-api-stubs-system-modules",
+	name: "legacy-core-platform-api-stubs-system-modules",
 }
 java_import {
-	name: "core.platform.api.stubs",
+	name: "legacy.core.platform.api.stubs",
 }
 java_import {
 	name: "android_stubs_current",
diff --git a/sh/Android.bp b/sh/Android.bp
index 0b04e7d..0f40c5f 100644
--- a/sh/Android.bp
+++ b/sh/Android.bp
@@ -5,6 +5,7 @@
         "blueprint",
         "soong",
         "soong-android",
+        "soong-tradefed",
     ],
     srcs: [
         "sh_binary.go",
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 2dcd716..4e45cd6 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -22,6 +22,7 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/tradefed"
 )
 
 // sh_binary is for shell scripts (and batch files) that are installed as
@@ -74,6 +75,19 @@
 	// list of files or filegroup modules that provide data that should be installed alongside
 	// the test.
 	Data []string `android:"path,arch_variant"`
+
+	// Add RootTargetPreparer to auto generated test config. This guarantees the test to run
+	// with root permission.
+	Require_root *bool
+
+	// the name of the test configuration template (for example "AndroidTestTemplate.xml") that
+	// should be installed with the module.
+	Test_config_template *string `android:"path,arch_variant"`
+
+	// Flag to indicate whether or not to create test config automatically. If AndroidTest.xml
+	// doesn't exist next to the Android.bp, this attribute doesn't need to be set to true
+	// explicitly.
+	Auto_gen_config *bool
 }
 
 type ShBinary struct {
@@ -93,7 +107,8 @@
 
 	testProperties TestProperties
 
-	data android.Paths
+	data       android.Paths
+	testConfig android.Path
 }
 
 func (s *ShBinary) HostToolPath() android.OptionalPath {
@@ -190,6 +205,16 @@
 	s.installedFile = ctx.InstallExecutable(installDir, s.outputFilePath.Base(), s.outputFilePath)
 
 	s.data = android.PathsForModuleSrc(ctx, s.testProperties.Data)
+
+	var configs []tradefed.Config
+	if Bool(s.testProperties.Require_root) {
+		configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", nil})
+	} else {
+		options := []tradefed.Option{{Name: "force-root", Value: "false"}}
+		configs = append(configs, tradefed.Object{"target_preparer", "com.android.tradefed.targetprep.RootTargetPreparer", options})
+	}
+	s.testConfig = tradefed.AutoGenShellTestConfig(ctx, s.testProperties.Test_config,
+		s.testProperties.Test_config_template, s.testProperties.Test_suites, configs, s.testProperties.Auto_gen_config, s.outputFilePath.Base())
 }
 
 func (s *ShTest) InstallInData() bool {
@@ -206,7 +231,13 @@
 				s.customAndroidMkEntries(entries)
 
 				entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", s.testProperties.Test_suites...)
-				entries.SetString("LOCAL_TEST_CONFIG", proptools.String(s.testProperties.Test_config))
+				if s.testProperties.Test_config != nil {
+					entries.SetString("LOCAL_TEST_CONFIG", proptools.String(s.testProperties.Test_config))
+				} else {
+					if s.testConfig != nil {
+						entries.SetString("LOCAL_FULL_TEST_CONFIG", s.testConfig.String())
+					}
+				}
 				for _, d := range s.data {
 					rel := d.Rel()
 					path := d.String()
@@ -229,9 +260,6 @@
 // executable binary to <partition>/bin.
 func ShBinaryFactory() android.Module {
 	module := &ShBinary{}
-	module.Prefer32(func(ctx android.BaseModuleContext, base *android.ModuleBase, class android.OsClass) bool {
-		return class == android.Device && ctx.Config().DevicePrefer32BitExecutables()
-	})
 	InitShBinaryModule(module)
 	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst)
 	return module
@@ -265,3 +293,5 @@
 	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
 	return module
 }
+
+var Bool = proptools.Bool
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index be44cac..2829146 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -40,9 +40,9 @@
 }
 
 var autogenTestConfig = pctx.StaticRule("autogenTestConfig", blueprint.RuleParams{
-	Command:     "sed 's&{MODULE}&${name}&g;s&{EXTRA_CONFIGS}&'${extraConfigs}'&g' $template > $out",
+	Command:     "sed 's&{MODULE}&${name}&g;s&{EXTRA_CONFIGS}&'${extraConfigs}'&g;s&{OUTPUT_FILENAME}&'${outputFileName}'&g' $template > $out",
 	CommandDeps: []string{"$template"},
-}, "name", "template", "extraConfigs")
+}, "name", "template", "extraConfigs", "outputFileName")
 
 func testConfigPath(ctx android.ModuleContext, prop *string, testSuites []string, autoGenConfig *bool, testConfigTemplateProp *string) (path android.Path, autogenPath android.WritablePath) {
 	p := getTestConfig(ctx, prop)
@@ -108,10 +108,14 @@
 }
 
 func autogenTemplate(ctx android.ModuleContext, output android.WritablePath, template string, configs []Config) {
-	autogenTemplateWithName(ctx, ctx.ModuleName(), output, template, configs)
+	autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), output, template, configs, "")
 }
 
 func autogenTemplateWithName(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config) {
+	autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), output, template, configs, "")
+}
+
+func autogenTemplateWithNameAndOutputFile(ctx android.ModuleContext, name string, output android.WritablePath, template string, configs []Config, outputFileName string) {
 	var configStrings []string
 	for _, config := range configs {
 		configStrings = append(configStrings, config.Config())
@@ -124,9 +128,10 @@
 		Description: "test config",
 		Output:      output,
 		Args: map[string]string{
-			"name":         name,
-			"template":     template,
-			"extraConfigs": extraConfigs,
+			"name":           name,
+			"template":       template,
+			"extraConfigs":   extraConfigs,
+			"outputFileName": outputFileName,
 		},
 	})
 }
@@ -150,6 +155,21 @@
 	return path
 }
 
+func AutoGenShellTestConfig(ctx android.ModuleContext, testConfigProp *string,
+	testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool, outputFileName string) android.Path {
+	path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
+	if autogenPath != nil {
+		templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
+		if templatePath.Valid() {
+			autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), autogenPath, templatePath.String(), config, outputFileName)
+		} else {
+			autogenTemplateWithNameAndOutputFile(ctx, ctx.ModuleName(), autogenPath, "${ShellTestConfigTemplate}", config, outputFileName)
+		}
+		return autogenPath
+	}
+	return path
+}
+
 func AutoGenNativeBenchmarkTestConfig(ctx android.ModuleContext, testConfigProp *string,
 	testConfigTemplateProp *string, testSuites []string, configs []Config, autoGenConfig *bool) android.Path {
 	path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
diff --git a/tradefed/config.go b/tradefed/config.go
index a289073..34195c3 100644
--- a/tradefed/config.go
+++ b/tradefed/config.go
@@ -33,6 +33,7 @@
 	pctx.SourcePathVariable("PythonBinaryHostTestConfigTemplate", "build/make/core/python_binary_host_test_config_template.xml")
 	pctx.SourcePathVariable("RustDeviceTestConfigTemplate", "build/make/core/rust_device_test_config_template.xml")
 	pctx.SourcePathVariable("RustHostTestConfigTemplate", "build/make/core/rust_host_test_config_template.xml")
+	pctx.SourcePathVariable("ShellTestConfigTemplate", "build/make/core/shell_test_config_template.xml")
 
 	pctx.SourcePathVariable("EmptyTestConfig", "build/make/core/empty_test_config.xml")
 }
diff --git a/tradefed/makevars.go b/tradefed/makevars.go
index d4cf7a8..f9682e4 100644
--- a/tradefed/makevars.go
+++ b/tradefed/makevars.go
@@ -33,6 +33,7 @@
 	ctx.Strict("PYTHON_BINARY_HOST_TEST_CONFIG_TEMPLATE", "${PythonBinaryHostTestConfigTemplate}")
 	ctx.Strict("RUST_DEVICE_TEST_CONFIG_TEMPLATE", "${RustDeviceTestConfigTemplate}")
 	ctx.Strict("RUST_HOST_TEST_CONFIG_TEMPLATE", "${RustHostTestConfigTemplate}")
+	ctx.Strict("SHELL_TEST_CONFIG_TEMPLATE", "${ShellTestConfigTemplate}")
 
 	ctx.Strict("EMPTY_TEST_CONFIG", "${EmptyTestConfig}")
 }
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index a559330..7dc4915 100644
--- a/ui/build/dumpvars.go
+++ b/ui/build/dumpvars.go
@@ -54,18 +54,16 @@
 
 	var ret map[string]string
 	if len(makeVars) > 0 {
+		// It's not safe to use the same TMPDIR as the build, as that can be removed.
 		tmpDir, err := ioutil.TempDir("", "dumpvars")
 		if err != nil {
 			return nil, err
 		}
 		defer os.RemoveAll(tmpDir)
 
-		// It's not safe to use the same TMPDIR as the build, as that can be removed.
-		config.Environment().Set("TMPDIR", tmpDir)
+		SetupLitePath(ctx, config, tmpDir)
 
-		SetupLitePath(ctx, config)
-
-		ret, err = dumpMakeVars(ctx, config, goals, makeVars, false)
+		ret, err = dumpMakeVars(ctx, config, goals, makeVars, false, tmpDir)
 		if err != nil {
 			return ret, err
 		}
@@ -82,7 +80,7 @@
 	return ret, nil
 }
 
-func dumpMakeVars(ctx Context, config Config, goals, vars []string, write_soong_vars bool) (map[string]string, error) {
+func dumpMakeVars(ctx Context, config Config, goals, vars []string, write_soong_vars bool, tmpDir string) (map[string]string, error) {
 	ctx.BeginTrace(metrics.RunKati, "dumpvars")
 	defer ctx.EndTrace()
 
@@ -98,6 +96,9 @@
 		cmd.Environment.Set("WRITE_SOONG_VARIABLES", "true")
 	}
 	cmd.Environment.Set("DUMP_MANY_VARS", strings.Join(vars, " "))
+	if tmpDir != "" {
+		cmd.Environment.Set("TMPDIR", tmpDir)
+	}
 	cmd.Sandbox = dumpvarsSandbox
 	output := bytes.Buffer{}
 	cmd.Stdout = &output
@@ -253,7 +254,7 @@
 		"BUILD_BROKEN_USES_BUILD_STATIC_LIBRARY",
 	}, exportEnvVars...), BannerVars...)
 
-	make_vars, err := dumpMakeVars(ctx, config, config.Arguments(), allVars, true)
+	make_vars, err := dumpMakeVars(ctx, config, config.Arguments(), allVars, true, "")
 	if err != nil {
 		ctx.Fatalln("Error dumping make vars:", err)
 	}
diff --git a/ui/build/path.go b/ui/build/path.go
index 7122927..6f5cf78 100644
--- a/ui/build/path.go
+++ b/ui/build/path.go
@@ -55,8 +55,9 @@
 }
 
 // A "lite" version of SetupPath used for dumpvars, or other places that need
-// minimal overhead (but at the expense of logging).
-func SetupLitePath(ctx Context, config Config) {
+// minimal overhead (but at the expense of logging). If tmpDir is empty, the
+// default TMPDIR is used from config.
+func SetupLitePath(ctx Context, config Config, tmpDir string) {
 	if config.pathReplaced {
 		return
 	}
@@ -65,8 +66,11 @@
 	defer ctx.EndTrace()
 
 	origPath, _ := config.Environment().Get("PATH")
-	myPath, _ := config.Environment().Get("TMPDIR")
-	myPath = filepath.Join(myPath, "path")
+
+	if tmpDir == "" {
+		tmpDir, _ = config.Environment().Get("TMPDIR")
+	}
+	myPath := filepath.Join(tmpDir, "path")
 	ensureEmptyDirectoriesExist(ctx, myPath)
 
 	os.Setenv("PATH", origPath)