Merge "Disable "show member in hidden parent" metalava error"
diff --git a/Android.bp b/Android.bp
index 73fad25..0b44198 100644
--- a/Android.bp
+++ b/Android.bp
@@ -11,14 +11,6 @@
 ]
 
 bootstrap_go_package {
-    name: "soong-env",
-    pkgPath: "android/soong/env",
-    srcs: [
-        "env/env.go",
-    ],
-}
-
-bootstrap_go_package {
     name: "soong",
     pkgPath: "android/soong",
     deps: [
@@ -29,546 +21,6 @@
     ],
 }
 
-bootstrap_go_package {
-    name: "soong-android",
-    pkgPath: "android/soong/android",
-    deps: [
-        "blueprint",
-        "blueprint-bootstrap",
-        "soong",
-        "soong-android-soongconfig",
-        "soong-env",
-        "soong-shared",
-        "soong-ui-metrics_proto",
-    ],
-    srcs: [
-        "android/androidmk.go",
-        "android/apex.go",
-        "android/api_levels.go",
-        "android/arch.go",
-        "android/config.go",
-        "android/csuite_config.go",
-        "android/defaults.go",
-        "android/defs.go",
-        "android/expand.go",
-        "android/filegroup.go",
-        "android/hooks.go",
-        "android/image.go",
-        "android/makevars.go",
-        "android/metrics.go",
-        "android/module.go",
-        "android/mutator.go",
-        "android/namespace.go",
-        "android/neverallow.go",
-        "android/notices.go",
-        "android/onceper.go",
-        "android/override_module.go",
-        "android/package.go",
-        "android/package_ctx.go",
-        "android/path_properties.go",
-        "android/paths.go",
-        "android/prebuilt.go",
-        "android/prebuilt_etc.go",
-        "android/proto.go",
-        "android/register.go",
-        "android/rule_builder.go",
-        "android/sandbox.go",
-        "android/sdk.go",
-        "android/sh_binary.go",
-        "android/singleton.go",
-        "android/soong_config_modules.go",
-        "android/testing.go",
-        "android/util.go",
-        "android/variable.go",
-        "android/visibility.go",
-        "android/vts_config.go",
-        "android/writedocs.go",
-
-        // Lock down environment access last
-        "android/env.go",
-    ],
-    testSrcs: [
-        "android/android_test.go",
-        "android/androidmk_test.go",
-        "android/arch_test.go",
-        "android/config_test.go",
-        "android/csuite_config_test.go",
-        "android/expand_test.go",
-        "android/module_test.go",
-        "android/mutator_test.go",
-        "android/namespace_test.go",
-        "android/neverallow_test.go",
-        "android/onceper_test.go",
-        "android/package_test.go",
-        "android/path_properties_test.go",
-        "android/paths_test.go",
-        "android/prebuilt_test.go",
-        "android/prebuilt_etc_test.go",
-        "android/rule_builder_test.go",
-        "android/soong_config_modules_test.go",
-        "android/util_test.go",
-        "android/variable_test.go",
-        "android/visibility_test.go",
-        "android/vts_config_test.go",
-    ],
-}
-
-bootstrap_go_package {
-    name: "soong-android-soongconfig",
-    pkgPath: "android/soong/android/soongconfig",
-    deps: [
-        "blueprint",
-        "blueprint-parser",
-        "blueprint-proptools",
-    ],
-    srcs: [
-        "android/soongconfig/config.go",
-        "android/soongconfig/modules.go",
-    ],
-}
-
-bootstrap_go_package {
-    name: "soong-cc-config",
-    pkgPath: "android/soong/cc/config",
-    deps: [
-        "soong-android",
-        "soong-remoteexec",
-    ],
-    srcs: [
-        "cc/config/clang.go",
-        "cc/config/global.go",
-        "cc/config/tidy.go",
-        "cc/config/toolchain.go",
-        "cc/config/vndk.go",
-
-        "cc/config/arm_device.go",
-        "cc/config/arm64_device.go",
-        "cc/config/arm64_fuchsia_device.go",
-        "cc/config/x86_device.go",
-        "cc/config/x86_64_device.go",
-        "cc/config/x86_64_fuchsia_device.go",
-
-        "cc/config/x86_darwin_host.go",
-        "cc/config/x86_linux_host.go",
-        "cc/config/x86_linux_bionic_host.go",
-        "cc/config/x86_windows_host.go",
-    ],
-    testSrcs: [
-        "cc/config/tidy_test.go",
-    ],
-}
-
-bootstrap_go_package {
-    name: "soong-cc",
-    pkgPath: "android/soong/cc",
-    deps: [
-        "blueprint",
-        "blueprint-pathtools",
-        "soong",
-        "soong-android",
-        "soong-cc-config",
-        "soong-genrule",
-        "soong-tradefed",
-    ],
-    srcs: [
-        "cc/androidmk.go",
-        "cc/builder.go",
-        "cc/cc.go",
-        "cc/ccdeps.go",
-        "cc/check.go",
-        "cc/coverage.go",
-        "cc/gen.go",
-        "cc/linkable.go",
-        "cc/lto.go",
-        "cc/makevars.go",
-        "cc/pgo.go",
-        "cc/prebuilt.go",
-        "cc/proto.go",
-        "cc/rs.go",
-        "cc/sanitize.go",
-        "cc/sabi.go",
-        "cc/sdk.go",
-        "cc/snapshot_utils.go",
-        "cc/stl.go",
-        "cc/strip.go",
-        "cc/sysprop.go",
-        "cc/tidy.go",
-        "cc/util.go",
-        "cc/vendor_snapshot.go",
-        "cc/vndk.go",
-        "cc/vndk_prebuilt.go",
-
-        "cc/cflag_artifacts.go",
-        "cc/cmakelists.go",
-        "cc/compdb.go",
-        "cc/compiler.go",
-        "cc/installer.go",
-        "cc/linker.go",
-
-        "cc/binary.go",
-        "cc/binary_sdk_member.go",
-        "cc/fuzz.go",
-        "cc/library.go",
-        "cc/library_headers.go",
-        "cc/library_sdk_member.go",
-        "cc/object.go",
-        "cc/test.go",
-        "cc/toolchain_library.go",
-
-        "cc/ndk_prebuilt.go",
-        "cc/ndk_headers.go",
-        "cc/ndk_library.go",
-        "cc/ndk_sysroot.go",
-
-        "cc/llndk_library.go",
-
-        "cc/kernel_headers.go",
-
-        "cc/genrule.go",
-
-        "cc/vendor_public_library.go",
-
-        "cc/testing.go",
-    ],
-    testSrcs: [
-        "cc/cc_test.go",
-        "cc/compiler_test.go",
-        "cc/gen_test.go",
-        "cc/genrule_test.go",
-        "cc/library_headers_test.go",
-        "cc/library_test.go",
-        "cc/object_test.go",
-        "cc/prebuilt_test.go",
-        "cc/proto_test.go",
-        "cc/test_data_test.go",
-    ],
-    pluginFor: ["soong_build"],
-}
-
-bootstrap_go_package {
-    name: "soong-genrule",
-    pkgPath: "android/soong/genrule",
-    deps: [
-        "blueprint",
-        "blueprint-pathtools",
-        "soong",
-        "soong-android",
-        "soong-shared",
-    ],
-    srcs: [
-        "genrule/genrule.go",
-    ],
-    testSrcs: [
-        "genrule/genrule_test.go",
-    ],
-    pluginFor: ["soong_build"],
-}
-
-bootstrap_go_package {
-    name: "soong-phony",
-    pkgPath: "android/soong/phony",
-    deps: [
-        "blueprint",
-        "soong-android",
-    ],
-    srcs: [
-        "phony/phony.go",
-    ],
-    pluginFor: ["soong_build"],
-}
-
-bootstrap_go_package {
-    name: "soong-java",
-    pkgPath: "android/soong/java",
-    deps: [
-        "blueprint",
-        "blueprint-pathtools",
-        "soong",
-        "soong-android",
-        "soong-cc",
-        "soong-dexpreopt",
-        "soong-genrule",
-        "soong-java-config",
-        "soong-remoteexec",
-        "soong-tradefed",
-    ],
-    srcs: [
-        "java/aapt2.go",
-        "java/aar.go",
-        "java/android_manifest.go",
-        "java/android_resources.go",
-        "java/androidmk.go",
-        "java/app_builder.go",
-        "java/app.go",
-        "java/builder.go",
-        "java/device_host_converter.go",
-        "java/dex.go",
-        "java/dexpreopt.go",
-        "java/dexpreopt_bootjars.go",
-        "java/dexpreopt_config.go",
-        "java/droiddoc.go",
-        "java/gen.go",
-        "java/genrule.go",
-        "java/hiddenapi.go",
-        "java/hiddenapi_singleton.go",
-        "java/jacoco.go",
-        "java/java.go",
-        "java/jdeps.go",
-        "java/java_resources.go",
-        "java/kotlin.go",
-        "java/platform_compat_config.go",
-        "java/plugin.go",
-        "java/prebuilt_apis.go",
-        "java/proto.go",
-        "java/robolectric.go",
-        "java/sdk.go",
-        "java/sdk_library.go",
-        "java/support_libraries.go",
-        "java/sysprop.go",
-        "java/system_modules.go",
-        "java/testing.go",
-        "java/tradefed.go",
-    ],
-    testSrcs: [
-        "java/androidmk_test.go",
-        "java/app_test.go",
-        "java/device_host_converter_test.go",
-        "java/dexpreopt_test.go",
-        "java/dexpreopt_bootjars_test.go",
-        "java/java_test.go",
-        "java/jdeps_test.go",
-        "java/kotlin_test.go",
-        "java/plugin_test.go",
-        "java/sdk_test.go",
-    ],
-    pluginFor: ["soong_build"],
-}
-
-bootstrap_go_package {
-    name: "soong-java-config",
-    pkgPath: "android/soong/java/config",
-    deps: [
-        "blueprint-proptools",
-        "soong-android",
-        "soong-remoteexec",
-    ],
-    srcs: [
-        "java/config/config.go",
-        "java/config/error_prone.go",
-        "java/config/kotlin.go",
-        "java/config/makevars.go",
-    ],
-}
-
-bootstrap_go_package {
-    name: "soong-rust-config",
-    pkgPath: "android/soong/rust/config",
-    deps: [
-        "soong-android",
-        "soong-cc-config",
-    ],
-    srcs: [
-        "rust/config/arm_device.go",
-        "rust/config/arm64_device.go",
-        "rust/config/global.go",
-        "rust/config/toolchain.go",
-        "rust/config/whitelist.go",
-        "rust/config/x86_darwin_host.go",
-        "rust/config/x86_linux_host.go",
-        "rust/config/x86_device.go",
-        "rust/config/x86_64_device.go",
-    ],
-}
-
-bootstrap_go_package {
-    name: "soong-rust",
-    pkgPath: "android/soong/rust",
-    deps: [
-        "soong",
-        "soong-android",
-        "soong-cc",
-        "soong-rust-config",
-    ],
-    srcs: [
-        "rust/androidmk.go",
-        "rust/compiler.go",
-        "rust/coverage.go",
-        "rust/binary.go",
-        "rust/builder.go",
-        "rust/library.go",
-        "rust/prebuilt.go",
-        "rust/proc_macro.go",
-        "rust/rust.go",
-        "rust/test.go",
-        "rust/testing.go",
-    ],
-    testSrcs: [
-        "rust/binary_test.go",
-        "rust/compiler_test.go",
-        "rust/coverage_test.go",
-        "rust/library_test.go",
-        "rust/rust_test.go",
-        "rust/test_test.go",
-    ],
-    pluginFor: ["soong_build"],
-}
-
-bootstrap_go_package {
-    name: "soong-python",
-    pkgPath: "android/soong/python",
-    deps: [
-        "blueprint",
-        "soong-android",
-        "soong-tradefed",
-    ],
-    srcs: [
-        "python/androidmk.go",
-        "python/binary.go",
-        "python/builder.go",
-        "python/defaults.go",
-        "python/installer.go",
-        "python/library.go",
-        "python/proto.go",
-        "python/python.go",
-        "python/test.go",
-    ],
-    testSrcs: [
-        "python/python_test.go",
-    ],
-    pluginFor: ["soong_build"],
-}
-
-bootstrap_go_package {
-    name: "soong-shared",
-    pkgPath: "android/soong/shared",
-    srcs: [
-        "shared/paths.go",
-    ],
-}
-
-bootstrap_go_package {
-    name: "soong-tradefed",
-    pkgPath: "android/soong/tradefed",
-    deps: [
-        "blueprint",
-        "soong-android",
-    ],
-    srcs: [
-        "tradefed/autogen.go",
-        "tradefed/config.go",
-        "tradefed/makevars.go",
-    ],
-    pluginFor: ["soong_build"],
-}
-
-bootstrap_go_package {
-    name: "soong-xml",
-    pkgPath: "android/soong/xml",
-    deps: [
-        "blueprint",
-        "blueprint-pathtools",
-        "soong",
-        "soong-android",
-    ],
-    srcs: [
-        "xml/xml.go",
-    ],
-    testSrcs: [
-        "xml/xml_test.go",
-    ],
-    pluginFor: ["soong_build"],
-}
-
-bootstrap_go_package {
-    name: "soong-apex",
-    pkgPath: "android/soong/apex",
-    deps: [
-        "blueprint",
-        "soong",
-        "soong-android",
-        "soong-cc",
-        "soong-java",
-        "soong-python",
-    ],
-    srcs: [
-        "apex/androidmk.go",
-        "apex/apex.go",
-        "apex/apex_singleton.go",
-        "apex/builder.go",
-        "apex/key.go",
-        "apex/prebuilt.go",
-        "apex/vndk.go",
-    ],
-    testSrcs: [
-        "apex/apex_test.go",
-        "apex/vndk_test.go",
-    ],
-    pluginFor: ["soong_build"],
-}
-
-bootstrap_go_package {
-    name: "soong-sysprop",
-    pkgPath: "android/soong/sysprop",
-    deps: [
-        "blueprint",
-        "soong",
-        "soong-android",
-        "soong-cc",
-        "soong-java",
-    ],
-    srcs: [
-        "sysprop/sysprop_library.go",
-    ],
-    testSrcs: [
-        "sysprop/sysprop_test.go",
-    ],
-    pluginFor: ["soong_build"],
-}
-
-bootstrap_go_package {
-    name: "soong-sdk",
-    pkgPath: "android/soong/sdk",
-    deps: [
-        "blueprint",
-        "soong",
-        "soong-android",
-        "soong-apex",
-        "soong-cc",
-        "soong-java",
-    ],
-    srcs: [
-        "sdk/bp.go",
-        "sdk/exports.go",
-        "sdk/sdk.go",
-        "sdk/update.go",
-    ],
-    testSrcs: [
-        "sdk/bp_test.go",
-        "sdk/cc_sdk_test.go",
-        "sdk/exports_test.go",
-        "sdk/java_sdk_test.go",
-        "sdk/sdk_test.go",
-        "sdk/testing.go",
-    ],
-    pluginFor: ["soong_build"],
-}
-
-bootstrap_go_package {
-    name: "soong-remoteexec",
-    pkgPath: "android/soong/remoteexec",
-    deps: [
-        "blueprint",
-        "soong-android",
-    ],
-    srcs: [
-        "remoteexec/remoteexec.go",
-    ],
-    testSrcs: [
-        "remoteexec/remoteexec_test.go",
-    ],
-    pluginFor: ["soong_build"],
-}
-
 //
 // Defaults to enable various configurations of host bionic
 //
diff --git a/OWNERS b/OWNERS
index e1db459..dbb491d 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,7 +1,14 @@
-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
 per-file tidy.go = srhines@google.com, chh@google.com
 per-file lto.go,pgo.go = srhines@google.com, pirama@google.com, yikong@google.com
 per-file docs/map_files.md = danalbert@google.com, enh@google.com, jiyong@google.com
+per-file *ndk_api_coverage_parser.py = sophiez@google.com
\ No newline at end of file
diff --git a/android/Android.bp b/android/Android.bp
new file mode 100644
index 0000000..487372b
--- /dev/null
+++ b/android/Android.bp
@@ -0,0 +1,81 @@
+bootstrap_go_package {
+    name: "soong-android",
+    pkgPath: "android/soong/android",
+    deps: [
+        "blueprint",
+        "blueprint-bootstrap",
+        "soong",
+        "soong-android-soongconfig",
+        "soong-env",
+        "soong-shared",
+        "soong-ui-metrics_proto",
+    ],
+    srcs: [
+        "androidmk.go",
+        "apex.go",
+        "api_levels.go",
+        "arch.go",
+        "config.go",
+        "csuite_config.go",
+        "defaults.go",
+        "defs.go",
+        "expand.go",
+        "filegroup.go",
+        "hooks.go",
+        "image.go",
+        "makevars.go",
+        "metrics.go",
+        "module.go",
+        "mutator.go",
+        "namespace.go",
+        "neverallow.go",
+        "notices.go",
+        "onceper.go",
+        "override_module.go",
+        "package.go",
+        "package_ctx.go",
+        "path_properties.go",
+        "paths.go",
+        "phony.go",
+        "prebuilt.go",
+        "proto.go",
+        "register.go",
+        "rule_builder.go",
+        "sandbox.go",
+        "sdk.go",
+        "singleton.go",
+        "soong_config_modules.go",
+        "testing.go",
+        "util.go",
+        "variable.go",
+        "visibility.go",
+        "vts_config.go",
+        "writedocs.go",
+
+        // Lock down environment access last
+        "env.go",
+    ],
+    testSrcs: [
+        "android_test.go",
+        "androidmk_test.go",
+        "arch_test.go",
+        "config_test.go",
+        "csuite_config_test.go",
+        "expand_test.go",
+        "module_test.go",
+        "mutator_test.go",
+        "namespace_test.go",
+        "neverallow_test.go",
+        "onceper_test.go",
+        "package_test.go",
+        "path_properties_test.go",
+        "paths_test.go",
+        "prebuilt_test.go",
+        "rule_builder_test.go",
+        "soong_config_modules_test.go",
+        "util_test.go",
+        "variable_test.go",
+        "visibility_test.go",
+        "vts_config_test.go",
+    ],
+}
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..b906108 100644
--- a/android/config.go
+++ b/android/config.go
@@ -111,6 +111,10 @@
 	fs         pathtools.FileSystem
 	mockBpList string
 
+	// If testAllowNonExistentPaths is true then PathForSource and PathForModuleSrc won't error
+	// in tests when a path doesn't exist.
+	testAllowNonExistentPaths bool
+
 	OncePer
 }
 
@@ -230,6 +234,10 @@
 		buildDir:     buildDir,
 		captureBuild: true,
 		env:          envCopy,
+
+		// Set testAllowNonExistentPaths so that test contexts don't need to specify every path
+		// passed to PathForSource or PathForModuleSrc.
+		testAllowNonExistentPaths: true,
 	}
 	config.deviceConfig = &deviceConfig{
 		config: config,
@@ -704,10 +712,17 @@
 	return Bool(c.productVariables.Allow_missing_dependencies)
 }
 
+// Returns true if building without full platform sources.
 func (c *config) UnbundledBuild() bool {
 	return Bool(c.productVariables.Unbundled_build)
 }
 
+// Returns true if building apps that aren't bundled with the platform.
+// UnbundledBuild() is always true when this is true.
+func (c *config) UnbundledBuildApps() bool {
+	return Bool(c.productVariables.Unbundled_build_apps)
+}
+
 func (c *config) UnbundledBuildUsePrebuiltSdks() bool {
 	return Bool(c.productVariables.Unbundled_build) && !Bool(c.productVariables.Unbundled_build_sdks_from_source)
 }
@@ -732,14 +747,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
 }
@@ -1029,6 +1036,27 @@
 	return Bool(c.config.productVariables.SamplingPGO)
 }
 
+// JavaCoverageEnabledForPath returns whether Java code coverage is enabled for
+// path. Coverage is enabled by default when the product variable
+// JavaCoveragePaths is empty. If JavaCoveragePaths is not empty, coverage is
+// enabled for any path which is part of this variable (and not part of the
+// JavaCoverageExcludePaths product variable). Value "*" in JavaCoveragePaths
+// represents any path.
+func (c *deviceConfig) JavaCoverageEnabledForPath(path string) bool {
+	coverage := false
+	if c.config.productVariables.JavaCoveragePaths == nil ||
+		InList("*", c.config.productVariables.JavaCoveragePaths) ||
+		HasAnyPrefix(path, c.config.productVariables.JavaCoveragePaths) {
+		coverage = true
+	}
+	if coverage && c.config.productVariables.JavaCoverageExcludePaths != nil {
+		if HasAnyPrefix(path, c.config.productVariables.JavaCoverageExcludePaths) {
+			coverage = false
+		}
+	}
+	return coverage
+}
+
 func (c *config) NativeLineCoverage() bool {
 	return Bool(c.productVariables.NativeLineCoverage)
 }
@@ -1041,15 +1069,20 @@
 	return Bool(c.config.productVariables.ClangCoverage)
 }
 
-func (c *deviceConfig) CoverageEnabledForPath(path string) bool {
+// NativeCoverageEnabledForPath returns whether (GCOV- or Clang-based) native
+// code coverage is enabled for path. By default, coverage is not enabled for a
+// given path unless it is part of the NativeCoveragePaths product variable (and
+// not part of the NativeCoverageExcludePaths product variable). Value "*" in
+// NativeCoveragePaths represents any path.
+func (c *deviceConfig) NativeCoverageEnabledForPath(path string) bool {
 	coverage := false
-	if c.config.productVariables.CoveragePaths != nil {
-		if InList("*", c.config.productVariables.CoveragePaths) || HasAnyPrefix(path, c.config.productVariables.CoveragePaths) {
+	if c.config.productVariables.NativeCoveragePaths != nil {
+		if InList("*", c.config.productVariables.NativeCoveragePaths) || HasAnyPrefix(path, c.config.productVariables.NativeCoveragePaths) {
 			coverage = true
 		}
 	}
-	if coverage && c.config.productVariables.CoverageExcludePaths != nil {
-		if HasAnyPrefix(path, c.config.productVariables.CoverageExcludePaths) {
+	if coverage && c.config.productVariables.NativeCoverageExcludePaths != nil {
+		if HasAnyPrefix(path, c.config.productVariables.NativeCoverageExcludePaths) {
 			coverage = false
 		}
 	}
@@ -1163,8 +1196,8 @@
 	return Bool(c.productVariables.EnforceSystemCertificate)
 }
 
-func (c *config) EnforceSystemCertificateWhitelist() []string {
-	return c.productVariables.EnforceSystemCertificateWhitelist
+func (c *config) EnforceSystemCertificateAllowList() []string {
+	return c.productVariables.EnforceSystemCertificateAllowList
 }
 
 func (c *config) EnforceProductPartitionInterface() bool {
diff --git a/android/makevars.go b/android/makevars.go
index aba4cce..ff7c8e4 100644
--- a/android/makevars.go
+++ b/android/makevars.go
@@ -17,12 +17,11 @@
 import (
 	"bytes"
 	"fmt"
-	"io/ioutil"
-	"os"
 	"strconv"
 	"strings"
 
 	"github.com/google/blueprint"
+	"github.com/google/blueprint/pathtools"
 	"github.com/google/blueprint/proptools"
 )
 
@@ -84,6 +83,29 @@
 	// builder whenever a file matching the pattern as added or removed, without rerunning if a
 	// file that does not match the pattern is added to a searched directory.
 	GlobWithDeps(pattern string, excludes []string) ([]string, error)
+
+	// Phony creates a phony rule in Make, which will allow additional DistForGoal
+	// dependencies to be added to it.  Phony can be called on the same name multiple
+	// times to add additional dependencies.
+	Phony(names string, deps ...Path)
+
+	// DistForGoal creates a rule to copy one or more Paths to the artifacts
+	// directory on the build server when the specified goal is built.
+	DistForGoal(goal string, paths ...Path)
+
+	// DistForGoalWithFilename creates a rule to copy a Path to the artifacts
+	// directory on the build server with the given filename when the specified
+	// goal is built.
+	DistForGoalWithFilename(goal string, path Path, filename string)
+
+	// DistForGoals creates a rule to copy one or more Paths to the artifacts
+	// directory on the build server when any of the specified goals are built.
+	DistForGoals(goals []string, paths ...Path)
+
+	// DistForGoalsWithFilename creates a rule to copy a Path to the artifacts
+	// directory on the build server with the given filename when any of the
+	// specified goals are built.
+	DistForGoalsWithFilename(goals []string, path Path, filename string)
 }
 
 var _ PathContext = MakeVarsContext(nil)
@@ -130,9 +152,11 @@
 
 type makeVarsContext struct {
 	SingletonContext
-	config Config
-	pctx   PackageContext
-	vars   []makeVarsVariable
+	config  Config
+	pctx    PackageContext
+	vars    []makeVarsVariable
+	phonies []phony
+	dists   []dist
 }
 
 var _ MakeVarsContext = &makeVarsContext{}
@@ -144,6 +168,16 @@
 	strict bool
 }
 
+type phony struct {
+	name string
+	deps []string
+}
+
+type dist struct {
+	goals []string
+	paths []string
+}
+
 func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) {
 	if !ctx.Config().EmbeddedInMake() {
 		return
@@ -152,11 +186,16 @@
 	outFile := absolutePath(PathForOutput(ctx,
 		"make_vars"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String())
 
+	lateOutFile := absolutePath(PathForOutput(ctx,
+		"late"+proptools.String(ctx.Config().productVariables.Make_suffix)+".mk").String())
+
 	if ctx.Failed() {
 		return
 	}
 
-	vars := []makeVarsVariable{}
+	var vars []makeVarsVariable
+	var dists []dist
+	var phonies []phony
 	for _, provider := range makeVarsProviders {
 		mctx := &makeVarsContext{
 			SingletonContext: ctx,
@@ -166,6 +205,8 @@
 		provider.call(mctx)
 
 		vars = append(vars, mctx.vars...)
+		phonies = append(phonies, mctx.phonies...)
+		dists = append(dists, mctx.dists...)
 	}
 
 	if ctx.Failed() {
@@ -174,17 +215,16 @@
 
 	outBytes := s.writeVars(vars)
 
-	if _, err := os.Stat(absolutePath(outFile)); err == nil {
-		if data, err := ioutil.ReadFile(absolutePath(outFile)); err == nil {
-			if bytes.Equal(data, outBytes) {
-				return
-			}
-		}
-	}
-
-	if err := ioutil.WriteFile(absolutePath(outFile), outBytes, 0666); err != nil {
+	if err := pathtools.WriteFileIfChanged(outFile, outBytes, 0666); err != nil {
 		ctx.Errorf(err.Error())
 	}
+
+	lateOutBytes := s.writeLate(phonies, dists)
+
+	if err := pathtools.WriteFileIfChanged(lateOutFile, lateOutBytes, 0666); err != nil {
+		ctx.Errorf(err.Error())
+	}
+
 }
 
 func (s *makeVarsSingleton) writeVars(vars []makeVarsVariable) []byte {
@@ -263,6 +303,33 @@
 
 	fmt.Fprintln(buf, "\nsoong-compare-var :=")
 
+	fmt.Fprintln(buf)
+
+	return buf.Bytes()
+}
+
+func (s *makeVarsSingleton) writeLate(phonies []phony, dists []dist) []byte {
+	buf := &bytes.Buffer{}
+
+	fmt.Fprint(buf, `# Autogenerated file
+
+# Values written by Soong read after parsing all Android.mk files.
+
+
+`)
+
+	for _, phony := range phonies {
+		fmt.Fprintf(buf, ".PHONY: %s\n", phony.name)
+		fmt.Fprintf(buf, "%s: %s\n", phony.name, strings.Join(phony.deps, "\\\n  "))
+	}
+
+	fmt.Fprintln(buf)
+
+	for _, dist := range dists {
+		fmt.Fprintf(buf, "$(call dist-for-goals,%s,%s)\n",
+			strings.Join(dist.goals, " "), strings.Join(dist.paths, " "))
+	}
+
 	return buf.Bytes()
 }
 
@@ -299,6 +366,17 @@
 	c.addVariableRaw(name, value, strict, sort)
 }
 
+func (c *makeVarsContext) addPhony(name string, deps []string) {
+	c.phonies = append(c.phonies, phony{name, deps})
+}
+
+func (c *makeVarsContext) addDist(goals []string, paths []string) {
+	c.dists = append(c.dists, dist{
+		goals: goals,
+		paths: paths,
+	})
+}
+
 func (c *makeVarsContext) Strict(name, ninjaStr string) {
 	c.addVariable(name, ninjaStr, true, false)
 }
@@ -318,3 +396,23 @@
 func (c *makeVarsContext) CheckRaw(name, value string) {
 	c.addVariableRaw(name, value, false, false)
 }
+
+func (c *makeVarsContext) Phony(name string, deps ...Path) {
+	c.addPhony(name, Paths(deps).Strings())
+}
+
+func (c *makeVarsContext) DistForGoal(goal string, paths ...Path) {
+	c.DistForGoals([]string{goal}, paths...)
+}
+
+func (c *makeVarsContext) DistForGoalWithFilename(goal string, path Path, filename string) {
+	c.DistForGoalsWithFilename([]string{goal}, path, filename)
+}
+
+func (c *makeVarsContext) DistForGoals(goals []string, paths ...Path) {
+	c.addDist(goals, Paths(paths).Strings())
+}
+
+func (c *makeVarsContext) DistForGoalsWithFilename(goals []string, path Path, filename string) {
+	c.addDist(goals, []string{path.String() + ":" + filename})
+}
diff --git a/android/module.go b/android/module.go
index 82321f4..f24047c 100644
--- a/android/module.go
+++ b/android/module.go
@@ -207,6 +207,10 @@
 	// Similar to blueprint.ModuleContext.Build, but takes Paths instead of []string,
 	// and performs more verification.
 	Build(pctx PackageContext, params BuildParams)
+	// Phony creates a Make-style phony rule, a rule with no commands that can depend on other
+	// phony rules or real files.  Phony can be called on the same name multiple times to add
+	// additional dependencies.
+	Phony(phony string, deps ...Path)
 
 	PrimaryModule() Module
 	FinalModule() Module
@@ -722,6 +726,7 @@
 	installFiles       InstallPaths
 	checkbuildFiles    Paths
 	noticeFiles        Paths
+	phonies            map[string]Paths
 
 	// Used by buildTargetSingleton to create checkbuild and per-directory build targets
 	// Only set on the final variant of each module
@@ -830,6 +835,10 @@
 	return m.Os().Class == Host || m.Os().Class == HostCross
 }
 
+func (m *ModuleBase) Device() bool {
+	return m.Os().Class == Device
+}
+
 func (m *ModuleBase) Arch() Arch {
 	return m.Target().Arch
 }
@@ -1093,26 +1102,17 @@
 	}
 
 	if len(allInstalledFiles) > 0 {
-		name := PathForPhony(ctx, namespacePrefix+ctx.ModuleName()+"-install")
-		ctx.Build(pctx, BuildParams{
-			Rule:      blueprint.Phony,
-			Output:    name,
-			Implicits: allInstalledFiles.Paths(),
-			Default:   !ctx.Config().EmbeddedInMake(),
-		})
-		deps = append(deps, name)
-		m.installTarget = name
+		name := namespacePrefix + ctx.ModuleName() + "-install"
+		ctx.Phony(name, allInstalledFiles.Paths()...)
+		m.installTarget = PathForPhony(ctx, name)
+		deps = append(deps, m.installTarget)
 	}
 
 	if len(allCheckbuildFiles) > 0 {
-		name := PathForPhony(ctx, namespacePrefix+ctx.ModuleName()+"-checkbuild")
-		ctx.Build(pctx, BuildParams{
-			Rule:      blueprint.Phony,
-			Output:    name,
-			Implicits: allCheckbuildFiles,
-		})
-		deps = append(deps, name)
-		m.checkbuildTarget = name
+		name := namespacePrefix + ctx.ModuleName() + "-checkbuild"
+		ctx.Phony(name, allCheckbuildFiles...)
+		m.checkbuildTarget = PathForPhony(ctx, name)
+		deps = append(deps, m.checkbuildTarget)
 	}
 
 	if len(deps) > 0 {
@@ -1121,12 +1121,7 @@
 			suffix = "-soong"
 		}
 
-		name := PathForPhony(ctx, namespacePrefix+ctx.ModuleName()+suffix)
-		ctx.Build(pctx, BuildParams{
-			Rule:      blueprint.Phony,
-			Outputs:   []WritablePath{name},
-			Implicits: deps,
-		})
+		ctx.Phony(namespacePrefix+ctx.ModuleName()+suffix, deps...)
 
 		m.blueprintDir = ctx.ModuleDir()
 	}
@@ -1313,6 +1308,9 @@
 		m.checkbuildFiles = append(m.checkbuildFiles, ctx.checkbuildFiles...)
 		m.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc)
 		m.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments)
+		for k, v := range ctx.phonies {
+			m.phonies[k] = append(m.phonies[k], v...)
+		}
 	} else if ctx.Config().AllowMissingDependencies() {
 		// If the module is not enabled it will not create any build rules, nothing will call
 		// ctx.GetMissingDependencies(), and blueprint will consider the missing dependencies to be unhandled
@@ -1460,6 +1458,7 @@
 	installFiles    InstallPaths
 	checkbuildFiles Paths
 	module          Module
+	phonies         map[string]Paths
 
 	// For tests
 	buildParams []BuildParams
@@ -1574,6 +1573,11 @@
 
 	m.bp.Build(pctx.PackageContext, convertBuildParams(params))
 }
+
+func (m *moduleContext) Phony(name string, deps ...Path) {
+	addPhony(m.config, name, deps...)
+}
+
 func (m *moduleContext) GetMissingDependencies() []string {
 	var missingDeps []string
 	missingDeps = append(missingDeps, m.Module().base().commonProperties.MissingDeps...)
@@ -2233,9 +2237,8 @@
 func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) {
 	var checkbuildDeps Paths
 
-	mmTarget := func(dir string) WritablePath {
-		return PathForPhony(ctx,
-			"MODULES-IN-"+strings.Replace(filepath.Clean(dir), "/", "-", -1))
+	mmTarget := func(dir string) string {
+		return "MODULES-IN-" + strings.Replace(filepath.Clean(dir), "/", "-", -1)
 	}
 
 	modulesInDir := make(map[string]Paths)
@@ -2261,11 +2264,7 @@
 	}
 
 	// Create a top-level checkbuild target that depends on all modules
-	ctx.Build(pctx, BuildParams{
-		Rule:      blueprint.Phony,
-		Output:    PathForPhony(ctx, "checkbuild"+suffix),
-		Implicits: checkbuildDeps,
-	})
+	ctx.Phony("checkbuild"+suffix, checkbuildDeps...)
 
 	// Make will generate the MODULES-IN-* targets
 	if ctx.Config().EmbeddedInMake() {
@@ -2289,7 +2288,7 @@
 	for _, dir := range dirs {
 		p := parentDir(dir)
 		if p != "." && p != "/" {
-			modulesInDir[p] = append(modulesInDir[p], mmTarget(dir))
+			modulesInDir[p] = append(modulesInDir[p], PathForPhony(ctx, mmTarget(dir)))
 		}
 	}
 
@@ -2297,14 +2296,7 @@
 	// depends on the MODULES-IN-* targets of all of its subdirectories that contain Android.bp
 	// files.
 	for _, dir := range dirs {
-		ctx.Build(pctx, BuildParams{
-			Rule:      blueprint.Phony,
-			Output:    mmTarget(dir),
-			Implicits: modulesInDir[dir],
-			// HACK: checkbuild should be an optional build, but force it
-			// enabled for now in standalone builds
-			Default: !ctx.Config().EmbeddedInMake(),
-		})
+		ctx.Phony(mmTarget(dir), modulesInDir[dir]...)
 	}
 
 	// Create (host|host-cross|target)-<OS> phony rules to build a reduced checkbuild.
@@ -2331,23 +2323,15 @@
 			continue
 		}
 
-		name := PathForPhony(ctx, className+"-"+os.Name)
-		osClass[className] = append(osClass[className], name)
+		name := className + "-" + os.Name
+		osClass[className] = append(osClass[className], PathForPhony(ctx, name))
 
-		ctx.Build(pctx, BuildParams{
-			Rule:      blueprint.Phony,
-			Output:    name,
-			Implicits: deps,
-		})
+		ctx.Phony(name, deps...)
 	}
 
 	// Wrap those into host|host-cross|target phony rules
 	for _, class := range SortedStringKeys(osClass) {
-		ctx.Build(pctx, BuildParams{
-			Rule:      blueprint.Phony,
-			Output:    PathForPhony(ctx, class),
-			Implicits: osClass[class],
-		})
+		ctx.Phony(class, osClass[class]...)
 	}
 }
 
diff --git a/android/neverallow.go b/android/neverallow.go
index 9e075b7..26e42e6 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -166,7 +166,7 @@
 }
 
 func createJavaDeviceForHostRules() []Rule {
-	javaDeviceForHostProjectsWhitelist := []string{
+	javaDeviceForHostProjectsAllowedList := []string{
 		"external/guava",
 		"external/robolectric-shadows",
 		"framework/layoutlib",
@@ -174,22 +174,26 @@
 
 	return []Rule{
 		NeverAllow().
-			NotIn(javaDeviceForHostProjectsWhitelist...).
+			NotIn(javaDeviceForHostProjectsAllowedList...).
 			ModuleType("java_device_for_host", "java_host_for_device").
-			Because("java_device_for_host can only be used in whitelisted projects"),
+			Because("java_device_for_host can only be used in allowed projects"),
 	}
 }
 
 func createCcSdkVariantRules() []Rule {
-	sdkVersionOnlyWhitelist := []string{
+	sdkVersionOnlyAllowedList := []string{
 		// derive_sdk_prefer32 has stem: "derive_sdk" which conflicts with the derive_sdk.
 		// This sometimes works because the APEX modules that contain derive_sdk and
 		// derive_sdk_prefer32 suppress the platform installation rules, but fails when
 		// the APEX modules contain the SDK variant and the platform variant still exists.
 		"frameworks/base/apex/sdkextensions/derive_sdk",
+		// These are for apps and shouldn't be used by non-SDK variant modules.
+		"prebuilts/ndk",
+		"tools/test/graphicsbenchmark/apps/sample_app",
+		"tools/test/graphicsbenchmark/functional_tests/java",
 	}
 
-	platformVariantPropertiesWhitelist := []string{
+	platformVariantPropertiesAllowedList := []string{
 		// android_native_app_glue and libRSSupport use native_window.h but target old
 		// sdk versions (minimum and 9 respectively) where libnativewindow didn't exist,
 		// so they can't add libnativewindow to shared_libs to get the header directory
@@ -201,13 +205,13 @@
 
 	return []Rule{
 		NeverAllow().
-			NotIn(sdkVersionOnlyWhitelist...).
+			NotIn(sdkVersionOnlyAllowedList...).
 			WithMatcher("sdk_variant_only", isSetMatcherInstance).
-			Because("sdk_variant_only can only be used in whitelisted projects"),
+			Because("sdk_variant_only can only be used in allowed projects"),
 		NeverAllow().
-			NotIn(platformVariantPropertiesWhitelist...).
+			NotIn(platformVariantPropertiesAllowedList...).
 			WithMatcher("platform.shared_libs", isSetMatcherInstance).
-			Because("platform variant properties can only be used in whitelisted projects"),
+			Because("platform variant properties can only be used in allowed projects"),
 	}
 }
 
diff --git a/android/neverallow_test.go b/android/neverallow_test.go
index 85c8c59..45d36a6 100644
--- a/android/neverallow_test.go
+++ b/android/neverallow_test.go
@@ -212,7 +212,7 @@
 				}`),
 		},
 		expectedErrors: []string{
-			"java_device_for_host can only be used in whitelisted projects",
+			"java_device_for_host can only be used in allowed projects",
 		},
 	},
 	// Libcore rule tests
@@ -261,46 +261,46 @@
 	},
 	// CC sdk rule tests
 	{
-		name: `"sdk_variant_only" outside whitelist`,
+		name: `"sdk_variant_only" outside allowed list`,
 		fs: map[string][]byte{
 			"Android.bp": []byte(`
 				cc_library {
-					name: "outside_whitelist",
+					name: "outside_allowed_list",
 					sdk_version: "current",
 					sdk_variant_only: true,
 				}`),
 		},
 		expectedErrors: []string{
-			`module "outside_whitelist": violates neverallow`,
+			`module "outside_allowed_list": violates neverallow`,
 		},
 	},
 	{
-		name: `"sdk_variant_only: false" outside whitelist`,
+		name: `"sdk_variant_only: false" outside allowed list`,
 		fs: map[string][]byte{
 			"Android.bp": []byte(`
 				cc_library {
-					name: "outside_whitelist",
+					name: "outside_allowed_list",
 					sdk_version: "current",
 					sdk_variant_only: false,
 				}`),
 		},
 		expectedErrors: []string{
-			`module "outside_whitelist": violates neverallow`,
+			`module "outside_allowed_list": violates neverallow`,
 		},
 	},
 	{
-		name: `"platform" outside whitelist`,
+		name: `"platform" outside allowed list`,
 		fs: map[string][]byte{
 			"Android.bp": []byte(`
 				cc_library {
-					name: "outside_whitelist",
+					name: "outside_allowed_list",
 					platform: {
 						shared_libs: ["libfoo"],
 					},
 				}`),
 		},
 		expectedErrors: []string{
-			`module "outside_whitelist": violates neverallow`,
+			`module "outside_allowed_list": violates neverallow`,
 		},
 	},
 	{
diff --git a/android/override_module.go b/android/override_module.go
index 9f5127d..7e58890 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -208,7 +208,21 @@
 // next phase.
 func overrideModuleDepsMutator(ctx BottomUpMutatorContext) {
 	if module, ok := ctx.Module().(OverrideModule); ok {
-		ctx.AddDependency(ctx.Module(), overrideBaseDepTag, *module.getOverrideModuleProperties().Base)
+		// Skip this overriding module if there's a prebuilt module that overrides it with prefer flag.
+		overriddenByPrebuilt := false
+		ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(dep Module) {
+			prebuilt, ok := dep.(PrebuiltInterface)
+			if !ok {
+				panic("PrebuiltDepTag leads to a non-prebuilt module " + dep.Name())
+			}
+			if prebuilt.Prebuilt().UsePrebuilt() {
+				overriddenByPrebuilt = true
+				return
+			}
+		})
+		if !overriddenByPrebuilt {
+			ctx.AddDependency(ctx.Module(), overrideBaseDepTag, *module.getOverrideModuleProperties().Base)
+		}
 	}
 }
 
diff --git a/android/paths.go b/android/paths.go
index 3ad27ac..bed6f3f 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -405,7 +405,7 @@
 		p := pathForModuleSrc(ctx, s)
 		if exists, _, err := ctx.Config().fs.Exists(p.String()); err != nil {
 			reportPathErrorf(ctx, "%s: %s", p, err.Error())
-		} else if !exists {
+		} else if !exists && !ctx.Config().testAllowNonExistentPaths {
 			reportPathErrorf(ctx, "module source path %q does not exist", p)
 		}
 
@@ -798,7 +798,7 @@
 		}
 	} else if exists, _, err := ctx.Config().fs.Exists(path.String()); err != nil {
 		reportPathErrorf(ctx, "%s: %s", path, err.Error())
-	} else if !exists {
+	} else if !exists && !ctx.Config().testAllowNonExistentPaths {
 		reportPathErrorf(ctx, "source path %q does not exist", path)
 	}
 	return path
diff --git a/android/phony.go b/android/phony.go
new file mode 100644
index 0000000..f8e5a44
--- /dev/null
+++ b/android/phony.go
@@ -0,0 +1,75 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package android
+
+import (
+	"sync"
+
+	"github.com/google/blueprint"
+)
+
+var phonyMapOnceKey = NewOnceKey("phony")
+
+type phonyMap map[string]Paths
+
+var phonyMapLock sync.Mutex
+
+func getPhonyMap(config Config) phonyMap {
+	return config.Once(phonyMapOnceKey, func() interface{} {
+		return make(phonyMap)
+	}).(phonyMap)
+}
+
+func addPhony(config Config, name string, deps ...Path) {
+	phonyMap := getPhonyMap(config)
+	phonyMapLock.Lock()
+	defer phonyMapLock.Unlock()
+	phonyMap[name] = append(phonyMap[name], deps...)
+}
+
+type phonySingleton struct {
+	phonyMap  phonyMap
+	phonyList []string
+}
+
+var _ SingletonMakeVarsProvider = (*phonySingleton)(nil)
+
+func (p *phonySingleton) GenerateBuildActions(ctx SingletonContext) {
+	p.phonyMap = getPhonyMap(ctx.Config())
+	p.phonyList = SortedStringKeys(p.phonyMap)
+	for _, phony := range p.phonyList {
+		p.phonyMap[phony] = SortedUniquePaths(p.phonyMap[phony])
+	}
+
+	if !ctx.Config().EmbeddedInMake() {
+		for _, phony := range p.phonyList {
+			ctx.Build(pctx, BuildParams{
+				Rule:      blueprint.Phony,
+				Outputs:   []WritablePath{PathForPhony(ctx, phony)},
+				Implicits: p.phonyMap[phony],
+			})
+		}
+	}
+}
+
+func (p phonySingleton) MakeVars(ctx MakeVarsContext) {
+	for _, phony := range p.phonyList {
+		ctx.Phony(phony, p.phonyMap[phony]...)
+	}
+}
+
+func phonySingletonFactory() Singleton {
+	return &phonySingleton{}
+}
diff --git a/android/prebuilt_etc.go b/android/prebuilt_etc.go
deleted file mode 100644
index f0c0767..0000000
--- a/android/prebuilt_etc.go
+++ /dev/null
@@ -1,285 +0,0 @@
-// Copyright 2016 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package android
-
-import "strconv"
-
-// TODO(jungw): Now that it handles more than the ones in etc/, consider renaming this file.
-
-func init() {
-	RegisterModuleType("prebuilt_etc", PrebuiltEtcFactory)
-	RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory)
-	RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory)
-	RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory)
-	RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
-	RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
-}
-
-type prebuiltEtcProperties struct {
-	// Source file of this prebuilt.
-	Src *string `android:"path,arch_variant"`
-
-	// optional subdirectory under which this file is installed into
-	Sub_dir *string `android:"arch_variant"`
-
-	// optional name for the installed file. If unspecified, name of the module is used as the file name
-	Filename *string `android:"arch_variant"`
-
-	// when set to true, and filename property is not set, the name for the installed file
-	// is the same as the file name of the source file.
-	Filename_from_src *bool `android:"arch_variant"`
-
-	// Make this module available when building for ramdisk.
-	Ramdisk_available *bool
-
-	// Make this module available when building for recovery.
-	Recovery_available *bool
-
-	// Whether this module is directly installable to one of the partitions. Default: true.
-	Installable *bool
-
-	// Install symlinks to the installed file.
-	Symlinks []string `android:"arch_variant"`
-}
-
-type PrebuiltEtcModule interface {
-	Module
-	SubDir() string
-	OutputFile() OutputPath
-}
-
-type PrebuiltEtc struct {
-	ModuleBase
-
-	properties prebuiltEtcProperties
-
-	sourceFilePath Path
-	outputFilePath OutputPath
-	// The base install location, e.g. "etc" for prebuilt_etc, "usr/share" for prebuilt_usr_share.
-	installDirBase string
-	// The base install location when soc_specific property is set to true, e.g. "firmware" for prebuilt_firmware.
-	socInstallDirBase      string
-	installDirPath         InstallPath
-	additionalDependencies *Paths
-}
-
-func (p *PrebuiltEtc) inRamdisk() bool {
-	return p.ModuleBase.InRamdisk() || p.ModuleBase.InstallInRamdisk()
-}
-
-func (p *PrebuiltEtc) onlyInRamdisk() bool {
-	return p.ModuleBase.InstallInRamdisk()
-}
-
-func (p *PrebuiltEtc) InstallInRamdisk() bool {
-	return p.inRamdisk()
-}
-
-func (p *PrebuiltEtc) inRecovery() bool {
-	return p.ModuleBase.InRecovery() || p.ModuleBase.InstallInRecovery()
-}
-
-func (p *PrebuiltEtc) onlyInRecovery() bool {
-	return p.ModuleBase.InstallInRecovery()
-}
-
-func (p *PrebuiltEtc) InstallInRecovery() bool {
-	return p.inRecovery()
-}
-
-var _ ImageInterface = (*PrebuiltEtc)(nil)
-
-func (p *PrebuiltEtc) ImageMutatorBegin(ctx BaseModuleContext) {}
-
-func (p *PrebuiltEtc) CoreVariantNeeded(ctx BaseModuleContext) bool {
-	return !p.ModuleBase.InstallInRecovery() && !p.ModuleBase.InstallInRamdisk()
-}
-
-func (p *PrebuiltEtc) RamdiskVariantNeeded(ctx BaseModuleContext) bool {
-	return Bool(p.properties.Ramdisk_available) || p.ModuleBase.InstallInRamdisk()
-}
-
-func (p *PrebuiltEtc) RecoveryVariantNeeded(ctx BaseModuleContext) bool {
-	return Bool(p.properties.Recovery_available) || p.ModuleBase.InstallInRecovery()
-}
-
-func (p *PrebuiltEtc) ExtraImageVariations(ctx BaseModuleContext) []string {
-	return nil
-}
-
-func (p *PrebuiltEtc) SetImageVariation(ctx BaseModuleContext, variation string, module Module) {
-}
-
-func (p *PrebuiltEtc) DepsMutator(ctx BottomUpMutatorContext) {
-	if p.properties.Src == nil {
-		ctx.PropertyErrorf("src", "missing prebuilt source file")
-	}
-}
-
-func (p *PrebuiltEtc) SourceFilePath(ctx ModuleContext) Path {
-	return PathForModuleSrc(ctx, String(p.properties.Src))
-}
-
-func (p *PrebuiltEtc) InstallDirPath() InstallPath {
-	return p.installDirPath
-}
-
-// This allows other derivative modules (e.g. prebuilt_etc_xml) to perform
-// additional steps (like validating the src) before the file is installed.
-func (p *PrebuiltEtc) SetAdditionalDependencies(paths Paths) {
-	p.additionalDependencies = &paths
-}
-
-func (p *PrebuiltEtc) OutputFile() OutputPath {
-	return p.outputFilePath
-}
-
-func (p *PrebuiltEtc) SubDir() string {
-	return String(p.properties.Sub_dir)
-}
-
-func (p *PrebuiltEtc) Installable() bool {
-	return p.properties.Installable == nil || Bool(p.properties.Installable)
-}
-
-func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx ModuleContext) {
-	p.sourceFilePath = PathForModuleSrc(ctx, String(p.properties.Src))
-	filename := String(p.properties.Filename)
-	filename_from_src := Bool(p.properties.Filename_from_src)
-	if filename == "" {
-		if filename_from_src {
-			filename = p.sourceFilePath.Base()
-		} else {
-			filename = ctx.ModuleName()
-		}
-	} else if filename_from_src {
-		ctx.PropertyErrorf("filename_from_src", "filename is set. filename_from_src can't be true")
-		return
-	}
-	p.outputFilePath = PathForModuleOut(ctx, filename).OutputPath
-
-	// If soc install dir was specified and SOC specific is set, set the installDirPath to the specified
-	// socInstallDirBase.
-	installBaseDir := p.installDirBase
-	if ctx.SocSpecific() && p.socInstallDirBase != "" {
-		installBaseDir = p.socInstallDirBase
-	}
-	p.installDirPath = PathForModuleInstall(ctx, installBaseDir, String(p.properties.Sub_dir))
-
-	// This ensures that outputFilePath has the correct name for others to
-	// use, as the source file may have a different name.
-	ctx.Build(pctx, BuildParams{
-		Rule:   Cp,
-		Output: p.outputFilePath,
-		Input:  p.sourceFilePath,
-	})
-}
-
-func (p *PrebuiltEtc) AndroidMkEntries() []AndroidMkEntries {
-	nameSuffix := ""
-	if p.inRamdisk() && !p.onlyInRamdisk() {
-		nameSuffix = ".ramdisk"
-	}
-	if p.inRecovery() && !p.onlyInRecovery() {
-		nameSuffix = ".recovery"
-	}
-	return []AndroidMkEntries{AndroidMkEntries{
-		Class:      "ETC",
-		SubName:    nameSuffix,
-		OutputFile: OptionalPathForPath(p.outputFilePath),
-		ExtraEntries: []AndroidMkExtraEntriesFunc{
-			func(entries *AndroidMkEntries) {
-				entries.SetString("LOCAL_MODULE_TAGS", "optional")
-				entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.ToMakePath().String())
-				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base())
-				if len(p.properties.Symlinks) > 0 {
-					entries.AddStrings("LOCAL_MODULE_SYMLINKS", p.properties.Symlinks...)
-				}
-				entries.SetString("LOCAL_UNINSTALLABLE_MODULE", strconv.FormatBool(!p.Installable()))
-				if p.additionalDependencies != nil {
-					for _, path := range *p.additionalDependencies {
-						entries.AddStrings("LOCAL_ADDITIONAL_DEPENDENCIES", path.String())
-					}
-				}
-			},
-		},
-	}}
-}
-
-func InitPrebuiltEtcModule(p *PrebuiltEtc, dirBase string) {
-	p.installDirBase = dirBase
-	p.AddProperties(&p.properties)
-}
-
-// prebuilt_etc is for a prebuilt artifact that is installed in
-// <partition>/etc/<sub_dir> directory.
-func PrebuiltEtcFactory() Module {
-	module := &PrebuiltEtc{}
-	InitPrebuiltEtcModule(module, "etc")
-	// This module is device-only
-	InitAndroidArchModule(module, DeviceSupported, MultilibFirst)
-	return module
-}
-
-// prebuilt_etc_host is for a host prebuilt artifact that is installed in
-// $(HOST_OUT)/etc/<sub_dir> directory.
-func PrebuiltEtcHostFactory() Module {
-	module := &PrebuiltEtc{}
-	InitPrebuiltEtcModule(module, "etc")
-	// This module is host-only
-	InitAndroidArchModule(module, HostSupported, MultilibCommon)
-	return module
-}
-
-// prebuilt_usr_share is for a prebuilt artifact that is installed in
-// <partition>/usr/share/<sub_dir> directory.
-func PrebuiltUserShareFactory() Module {
-	module := &PrebuiltEtc{}
-	InitPrebuiltEtcModule(module, "usr/share")
-	// This module is device-only
-	InitAndroidArchModule(module, DeviceSupported, MultilibFirst)
-	return module
-}
-
-// prebuild_usr_share_host is for a host prebuilt artifact that is installed in
-// $(HOST_OUT)/usr/share/<sub_dir> directory.
-func PrebuiltUserShareHostFactory() Module {
-	module := &PrebuiltEtc{}
-	InitPrebuiltEtcModule(module, "usr/share")
-	// This module is host-only
-	InitAndroidArchModule(module, HostSupported, MultilibCommon)
-	return module
-}
-
-// prebuilt_font installs a font in <partition>/fonts directory.
-func PrebuiltFontFactory() Module {
-	module := &PrebuiltEtc{}
-	InitPrebuiltEtcModule(module, "fonts")
-	// This module is device-only
-	InitAndroidArchModule(module, DeviceSupported, MultilibFirst)
-	return module
-}
-
-// prebuilt_firmware installs a firmware file to <partition>/etc/firmware directory for system image.
-// If soc_specific property is set to true, the firmware file is installed to the vendor <partition>/firmware
-// directory for vendor image.
-func PrebuiltFirmwareFactory() Module {
-	module := &PrebuiltEtc{}
-	module.socInstallDirBase = "firmware"
-	InitPrebuiltEtcModule(module, "etc/firmware")
-	// This module is device-only
-	InitAndroidArchModule(module, DeviceSupported, MultilibFirst)
-	return module
-}
diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go
index b568f78..8029b85 100644
--- a/android/prebuilt_test.go
+++ b/android/prebuilt_test.go
@@ -155,6 +155,44 @@
 			}`,
 		prebuilt: []OsClass{Host},
 	},
+	{
+		name: "prebuilt override not preferred",
+		modules: `
+			source {
+				name: "baz",
+			}
+
+			override_source {
+				name: "bar",
+				base: "baz",
+			}
+
+			prebuilt {
+				name: "bar",
+				prefer: false,
+				srcs: ["prebuilt_file"],
+			}`,
+		prebuilt: nil,
+	},
+	{
+		name: "prebuilt override preferred",
+		modules: `
+			source {
+				name: "baz",
+			}
+
+			override_source {
+				name: "bar",
+				base: "baz",
+			}
+
+			prebuilt {
+				name: "bar",
+				prefer: true,
+				srcs: ["prebuilt_file"],
+			}`,
+		prebuilt: []OsClass{Device, Host},
+	},
 }
 
 func TestPrebuilts(t *testing.T) {
@@ -256,8 +294,10 @@
 func registerTestPrebuiltBuildComponents(ctx RegistrationContext) {
 	ctx.RegisterModuleType("prebuilt", newPrebuiltModule)
 	ctx.RegisterModuleType("source", newSourceModule)
+	ctx.RegisterModuleType("override_source", newOverrideSourceModule)
 
 	RegisterPrebuiltMutators(ctx)
+	ctx.PostDepsMutators(RegisterOverridePostDepsMutators)
 }
 
 type prebuiltModule struct {
@@ -300,11 +340,15 @@
 	}
 }
 
+type sourceModuleProperties struct {
+	Deps []string `android:"path,arch_variant"`
+}
+
 type sourceModule struct {
 	ModuleBase
-	properties struct {
-		Deps []string `android:"path,arch_variant"`
-	}
+	OverridableModuleBase
+
+	properties                                     sourceModuleProperties
 	dependsOnSourceModule, dependsOnPrebuiltModule bool
 	deps                                           Paths
 	src                                            Path
@@ -314,10 +358,11 @@
 	m := &sourceModule{}
 	m.AddProperties(&m.properties)
 	InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon)
+	InitOverridableModule(m, nil)
 	return m
 }
 
-func (s *sourceModule) DepsMutator(ctx BottomUpMutatorContext) {
+func (s *sourceModule) OverridablePropertiesDepsMutator(ctx BottomUpMutatorContext) {
 	// s.properties.Deps are annotated with android:path, so they are
 	// automatically added to the dependency by pathDeps mutator
 }
@@ -330,3 +375,20 @@
 func (s *sourceModule) Srcs() Paths {
 	return Paths{s.src}
 }
+
+type overrideSourceModule struct {
+	ModuleBase
+	OverrideModuleBase
+}
+
+func (o *overrideSourceModule) GenerateAndroidBuildActions(_ ModuleContext) {
+}
+
+func newOverrideSourceModule() Module {
+	m := &overrideSourceModule{}
+	m.AddProperties(&sourceModuleProperties{})
+
+	InitAndroidArchModule(m, HostAndDeviceDefault, MultilibCommon)
+	InitOverrideModule(m)
+	return m
+}
diff --git a/android/register.go b/android/register.go
index ccfe01e..036a811 100644
--- a/android/register.go
+++ b/android/register.go
@@ -104,6 +104,9 @@
 
 	registerMutators(ctx.Context, preArch, preDeps, postDeps, finalDeps)
 
+	// Register phony just before makevars so it can write out its phony rules as Make rules
+	ctx.RegisterSingletonType("phony", SingletonFactoryAdaptor(phonySingletonFactory))
+
 	// Register makevars after other singletons so they can export values through makevars
 	ctx.RegisterSingletonType("makevars", SingletonFactoryAdaptor(makeVarsSingletonFunc))
 
diff --git a/android/sh_binary.go b/android/sh_binary.go
deleted file mode 100644
index 7d9dc67..0000000
--- a/android/sh_binary.go
+++ /dev/null
@@ -1,259 +0,0 @@
-// Copyright 2019 Google Inc. All rights reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package android
-
-import (
-	"fmt"
-	"path/filepath"
-	"strings"
-)
-
-// sh_binary is for shell scripts (and batch files) that are installed as
-// executable files into .../bin/
-//
-// Do not use them for prebuilt C/C++/etc files.  Use cc_prebuilt_binary
-// instead.
-
-func init() {
-	RegisterModuleType("sh_binary", ShBinaryFactory)
-	RegisterModuleType("sh_binary_host", ShBinaryHostFactory)
-	RegisterModuleType("sh_test", ShTestFactory)
-	RegisterModuleType("sh_test_host", ShTestHostFactory)
-}
-
-type shBinaryProperties struct {
-	// Source file of this prebuilt.
-	Src *string `android:"path,arch_variant"`
-
-	// optional subdirectory under which this file is installed into
-	Sub_dir *string `android:"arch_variant"`
-
-	// optional name for the installed file. If unspecified, name of the module is used as the file name
-	Filename *string `android:"arch_variant"`
-
-	// when set to true, and filename property is not set, the name for the installed file
-	// is the same as the file name of the source file.
-	Filename_from_src *bool `android:"arch_variant"`
-
-	// Whether this module is directly installable to one of the partitions. Default: true.
-	Installable *bool
-
-	// install symlinks to the binary
-	Symlinks []string `android:"arch_variant"`
-}
-
-type TestProperties struct {
-	// list of compatibility suites (for example "cts", "vts") that the module should be
-	// installed into.
-	Test_suites []string `android:"arch_variant"`
-
-	// the name of the test configuration (for example "AndroidTest.xml") that should be
-	// installed with the module.
-	Test_config *string `android:"arch_variant"`
-
-	// list of files or filegroup modules that provide data that should be installed alongside
-	// the test.
-	Data []string `android:"path,arch_variant"`
-}
-
-type ShBinary struct {
-	ModuleBase
-
-	properties shBinaryProperties
-
-	sourceFilePath Path
-	outputFilePath OutputPath
-	installedFile  InstallPath
-}
-
-var _ HostToolProvider = (*ShBinary)(nil)
-
-type ShTest struct {
-	ShBinary
-
-	testProperties TestProperties
-
-	data Paths
-}
-
-func (s *ShBinary) HostToolPath() OptionalPath {
-	return OptionalPathForPath(s.installedFile)
-}
-
-func (s *ShBinary) DepsMutator(ctx BottomUpMutatorContext) {
-	if s.properties.Src == nil {
-		ctx.PropertyErrorf("src", "missing prebuilt source file")
-	}
-}
-
-func (s *ShBinary) OutputFile() OutputPath {
-	return s.outputFilePath
-}
-
-func (s *ShBinary) SubDir() string {
-	return String(s.properties.Sub_dir)
-}
-
-func (s *ShBinary) Installable() bool {
-	return s.properties.Installable == nil || Bool(s.properties.Installable)
-}
-
-func (s *ShBinary) Symlinks() []string {
-	return s.properties.Symlinks
-}
-
-func (s *ShBinary) generateAndroidBuildActions(ctx ModuleContext) {
-	s.sourceFilePath = PathForModuleSrc(ctx, String(s.properties.Src))
-	filename := String(s.properties.Filename)
-	filename_from_src := Bool(s.properties.Filename_from_src)
-	if filename == "" {
-		if filename_from_src {
-			filename = s.sourceFilePath.Base()
-		} else {
-			filename = ctx.ModuleName()
-		}
-	} else if filename_from_src {
-		ctx.PropertyErrorf("filename_from_src", "filename is set. filename_from_src can't be true")
-		return
-	}
-	s.outputFilePath = PathForModuleOut(ctx, filename).OutputPath
-
-	// This ensures that outputFilePath has the correct name for others to
-	// use, as the source file may have a different name.
-	ctx.Build(pctx, BuildParams{
-		Rule:   CpExecutable,
-		Output: s.outputFilePath,
-		Input:  s.sourceFilePath,
-	})
-}
-
-func (s *ShBinary) GenerateAndroidBuildActions(ctx ModuleContext) {
-	s.generateAndroidBuildActions(ctx)
-	installDir := PathForModuleInstall(ctx, "bin", String(s.properties.Sub_dir))
-	s.installedFile = ctx.InstallExecutable(installDir, s.outputFilePath.Base(), s.outputFilePath)
-}
-
-func (s *ShBinary) AndroidMkEntries() []AndroidMkEntries {
-	return []AndroidMkEntries{AndroidMkEntries{
-		Class:      "EXECUTABLES",
-		OutputFile: OptionalPathForPath(s.outputFilePath),
-		Include:    "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
-		ExtraEntries: []AndroidMkExtraEntriesFunc{
-			func(entries *AndroidMkEntries) {
-				s.customAndroidMkEntries(entries)
-			},
-		},
-	}}
-}
-
-func (s *ShBinary) customAndroidMkEntries(entries *AndroidMkEntries) {
-	entries.SetString("LOCAL_MODULE_RELATIVE_PATH", String(s.properties.Sub_dir))
-	entries.SetString("LOCAL_MODULE_SUFFIX", "")
-	entries.SetString("LOCAL_MODULE_STEM", s.outputFilePath.Rel())
-	if len(s.properties.Symlinks) > 0 {
-		entries.SetString("LOCAL_MODULE_SYMLINKS", strings.Join(s.properties.Symlinks, " "))
-	}
-}
-
-func (s *ShTest) GenerateAndroidBuildActions(ctx ModuleContext) {
-	s.ShBinary.generateAndroidBuildActions(ctx)
-	testDir := "nativetest"
-	if ctx.Target().Arch.ArchType.Multilib == "lib64" {
-		testDir = "nativetest64"
-	}
-	if ctx.Target().NativeBridge == NativeBridgeEnabled {
-		testDir = filepath.Join(testDir, ctx.Target().NativeBridgeRelativePath)
-	} else if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
-		testDir = filepath.Join(testDir, ctx.Arch().ArchType.String())
-	}
-	installDir := PathForModuleInstall(ctx, testDir, String(s.properties.Sub_dir))
-	s.installedFile = ctx.InstallExecutable(installDir, s.outputFilePath.Base(), s.outputFilePath)
-
-	s.data = PathsForModuleSrc(ctx, s.testProperties.Data)
-}
-
-func (s *ShTest) InstallInData() bool {
-	return true
-}
-
-func (s *ShTest) AndroidMkEntries() []AndroidMkEntries {
-	return []AndroidMkEntries{AndroidMkEntries{
-		Class:      "NATIVE_TESTS",
-		OutputFile: OptionalPathForPath(s.outputFilePath),
-		Include:    "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
-		ExtraEntries: []AndroidMkExtraEntriesFunc{
-			func(entries *AndroidMkEntries) {
-				s.customAndroidMkEntries(entries)
-
-				entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", s.testProperties.Test_suites...)
-				entries.SetString("LOCAL_TEST_CONFIG", String(s.testProperties.Test_config))
-				for _, d := range s.data {
-					rel := d.Rel()
-					path := d.String()
-					if !strings.HasSuffix(path, rel) {
-						panic(fmt.Errorf("path %q does not end with %q", path, rel))
-					}
-					path = strings.TrimSuffix(path, rel)
-					entries.AddStrings("LOCAL_TEST_DATA", path+":"+rel)
-				}
-			},
-		},
-	}}
-}
-
-func InitShBinaryModule(s *ShBinary) {
-	s.AddProperties(&s.properties)
-}
-
-// sh_binary is for a shell script or batch file to be installed as an
-// executable binary to <partition>/bin.
-func ShBinaryFactory() Module {
-	module := &ShBinary{}
-	module.Prefer32(func(ctx BaseModuleContext, base *ModuleBase, class OsClass) bool {
-		return class == Device && ctx.Config().DevicePrefer32BitExecutables()
-	})
-	InitShBinaryModule(module)
-	InitAndroidArchModule(module, HostAndDeviceSupported, MultilibFirst)
-	return module
-}
-
-// sh_binary_host is for a shell script to be installed as an executable binary
-// to $(HOST_OUT)/bin.
-func ShBinaryHostFactory() Module {
-	module := &ShBinary{}
-	InitShBinaryModule(module)
-	InitAndroidArchModule(module, HostSupported, MultilibFirst)
-	return module
-}
-
-// sh_test defines a shell script based test module.
-func ShTestFactory() Module {
-	module := &ShTest{}
-	InitShBinaryModule(&module.ShBinary)
-	module.AddProperties(&module.testProperties)
-
-	InitAndroidArchModule(module, HostAndDeviceSupported, MultilibFirst)
-	return module
-}
-
-// sh_test_host defines a shell script based test module that runs on a host.
-func ShTestHostFactory() Module {
-	module := &ShTest{}
-	InitShBinaryModule(&module.ShBinary)
-	module.AddProperties(&module.testProperties)
-
-	InitAndroidArchModule(module, HostSupported, MultilibFirst)
-	return module
-}
diff --git a/android/singleton.go b/android/singleton.go
index 568398c..2c51c6c 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -36,6 +36,12 @@
 	Variable(pctx PackageContext, name, value string)
 	Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule
 	Build(pctx PackageContext, params BuildParams)
+
+	// Phony creates a Make-style phony rule, a rule with no commands that can depend on other
+	// phony rules or real files.  Phony can be called on the same name multiple times to add
+	// additional dependencies.
+	Phony(name string, deps ...Path)
+
 	RequireNinjaVersion(major, minor, micro int)
 
 	// SetNinjaBuildDir sets the value of the top-level "builddir" Ninja variable
@@ -156,6 +162,10 @@
 
 }
 
+func (s *singletonContextAdaptor) Phony(name string, deps ...Path) {
+	addPhony(s.Config(), name, deps...)
+}
+
 func (s *singletonContextAdaptor) SetNinjaBuildDir(pctx PackageContext, value string) {
 	s.SingletonContext.SetNinjaBuildDir(pctx.PackageContext, value)
 }
diff --git a/android/soongconfig/Android.bp b/android/soongconfig/Android.bp
new file mode 100644
index 0000000..df912e6
--- /dev/null
+++ b/android/soongconfig/Android.bp
@@ -0,0 +1,13 @@
+bootstrap_go_package {
+    name: "soong-android-soongconfig",
+    pkgPath: "android/soong/android/soongconfig",
+    deps: [
+        "blueprint",
+        "blueprint-parser",
+        "blueprint-proptools",
+    ],
+    srcs: [
+        "config.go",
+        "modules.go",
+    ],
+}
diff --git a/android/variable.go b/android/variable.go
index 3c08405..b2149c3 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -216,6 +216,7 @@
 
 	Allow_missing_dependencies       *bool `json:",omitempty"`
 	Unbundled_build                  *bool `json:",omitempty"`
+	Unbundled_build_apps             *bool `json:",omitempty"`
 	Unbundled_build_sdks_from_source *bool `json:",omitempty"`
 	Malloc_not_svelte                *bool `json:",omitempty"`
 	Malloc_zero_contents             *bool `json:",omitempty"`
@@ -266,15 +267,14 @@
 
 	SamplingPGO *bool `json:",omitempty"`
 
-	NativeLineCoverage   *bool    `json:",omitempty"`
-	Native_coverage      *bool    `json:",omitempty"`
-	ClangCoverage        *bool    `json:",omitempty"`
-	CoveragePaths        []string `json:",omitempty"`
-	CoverageExcludePaths []string `json:",omitempty"`
+	JavaCoveragePaths        []string `json:",omitempty"`
+	JavaCoverageExcludePaths []string `json:",omitempty"`
 
-	DevicePrefer32BitApps        *bool `json:",omitempty"`
-	DevicePrefer32BitExecutables *bool `json:",omitempty"`
-	HostPrefer32BitExecutables   *bool `json:",omitempty"`
+	NativeLineCoverage         *bool    `json:",omitempty"`
+	Native_coverage            *bool    `json:",omitempty"`
+	ClangCoverage              *bool    `json:",omitempty"`
+	NativeCoveragePaths        []string `json:",omitempty"`
+	NativeCoverageExcludePaths []string `json:",omitempty"`
 
 	SanitizeHost       []string `json:",omitempty"`
 	SanitizeDevice     []string `json:",omitempty"`
@@ -323,7 +323,7 @@
 	PackageNameOverrides         []string `json:",omitempty"`
 
 	EnforceSystemCertificate          *bool    `json:",omitempty"`
-	EnforceSystemCertificateWhitelist []string `json:",omitempty"`
+	EnforceSystemCertificateAllowList []string `json:",omitempty"`
 
 	ProductHiddenAPIStubs       []string `json:",omitempty"`
 	ProductHiddenAPIStubsSystem []string `json:",omitempty"`
diff --git a/android/writedocs.go b/android/writedocs.go
index 7262ad8..9e43e80 100644
--- a/android/writedocs.go
+++ b/android/writedocs.go
@@ -69,9 +69,5 @@
 	})
 
 	// Add a phony target for building the documentation
-	ctx.Build(pctx, BuildParams{
-		Rule:   blueprint.Phony,
-		Output: PathForPhony(ctx, "soong_docs"),
-		Input:  docsFile,
-	})
+	ctx.Phony("soong_docs", docsFile)
 }
diff --git a/androidmk/androidmk/androidmk.go b/androidmk/androidmk/androidmk.go
index 9d0c3ac..4aadbe8 100644
--- a/androidmk/androidmk/androidmk.go
+++ b/androidmk/androidmk/androidmk.go
@@ -124,6 +124,7 @@
 
 	var conds []*conditional
 	var assignmentCond *conditional
+	var tree *bpparser.File
 
 	for _, node := range nodes {
 		file.setMkPos(p.Unpack(node.Pos()), p.Unpack(node.End()))
@@ -200,24 +201,27 @@
 		}
 	}
 
-	tree := &bpparser.File{
+	tree = &bpparser.File{
 		Defs:     file.defs,
 		Comments: file.comments,
 	}
 
 	// check for common supported but undesirable structures and clean them up
 	fixer := bpfix.NewFixer(tree)
-	tree, err := fixer.Fix(bpfix.NewFixRequest().AddAll())
-	if err != nil {
-		return "", []error{err}
+	fixedTree, fixerErr := fixer.Fix(bpfix.NewFixRequest().AddAll())
+	if fixerErr != nil {
+		errs = append(errs, fixerErr)
+	} else {
+		tree = fixedTree
 	}
 
 	out, err := bpparser.Print(tree)
 	if err != nil {
-		return "", []error{err}
+		errs = append(errs, err)
+		return "", errs
 	}
 
-	return string(out), nil
+	return string(out), errs
 }
 
 func handleAssignment(file *bpFile, assignment *mkparser.Assignment, c *conditional) {
diff --git a/androidmk/cmd/androidmk.go b/androidmk/cmd/androidmk.go
index 00488eb..d2f4324 100644
--- a/androidmk/cmd/androidmk.go
+++ b/androidmk/cmd/androidmk.go
@@ -45,12 +45,13 @@
 	}
 
 	output, errs := androidmk.ConvertFile(os.Args[1], bytes.NewBuffer(b))
+	if len(output) > 0 {
+		fmt.Print(output)
+	}
 	if len(errs) > 0 {
 		for _, err := range errs {
 			fmt.Fprintln(os.Stderr, "ERROR: ", err)
 		}
 		os.Exit(1)
 	}
-
-	fmt.Print(output)
 }
diff --git a/apex/Android.bp b/apex/Android.bp
new file mode 100644
index 0000000..144f441
--- /dev/null
+++ b/apex/Android.bp
@@ -0,0 +1,27 @@
+bootstrap_go_package {
+    name: "soong-apex",
+    pkgPath: "android/soong/apex",
+    deps: [
+        "blueprint",
+        "soong",
+        "soong-android",
+        "soong-cc",
+        "soong-java",
+        "soong-python",
+        "soong-sh",
+    ],
+    srcs: [
+        "androidmk.go",
+        "apex.go",
+        "apex_singleton.go",
+        "builder.go",
+        "key.go",
+        "prebuilt.go",
+        "vndk.go",
+    ],
+    testSrcs: [
+        "apex_test.go",
+        "vndk_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 9321ad2..4dd14d8 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,18 +178,23 @@
 		if fi.jacocoReportClassesFile != nil {
 			fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", fi.jacocoReportClassesFile.String())
 		}
-		if fi.class == javaSharedLib {
-			javaModule := fi.module.(java.Dependency)
+		switch fi.class {
+		case javaSharedLib:
 			// soong_java_prebuilt.mk sets LOCAL_MODULE_SUFFIX := .jar  Therefore
 			// we need to remove the suffix from LOCAL_MODULE_STEM, otherwise
 			// we will have foo.jar.jar
 			fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", strings.TrimSuffix(fi.Stem(), ".jar"))
-			fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", javaModule.ImplementationAndResourcesJars()[0].String())
-			fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", javaModule.HeaderJars()[0].String())
+			if javaModule, ok := fi.module.(java.ApexDependency); ok {
+				fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", javaModule.ImplementationAndResourcesJars()[0].String())
+				fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", javaModule.HeaderJars()[0].String())
+			} else {
+				fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", fi.builtFile.String())
+				fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", fi.builtFile.String())
+			}
 			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 +204,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 {
@@ -221,8 +233,9 @@
 					for _, o := range a.overridableProperties.Overrides {
 						patterns = append(patterns, "%."+o+a.suffix)
 					}
-					fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES :=", strings.Join(patterns, " "))
-
+					if len(patterns) > 0 {
+						fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES :=", strings.Join(patterns, " "))
+					}
 					if len(a.compatSymlinks) > 0 {
 						// For flattened apexes, compat symlinks are attached to apex_manifest.json which is guaranteed for every apex
 						postInstallCommands = append(postInstallCommands, a.compatSymlinks...)
@@ -295,7 +308,9 @@
 				fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", a.installDir.ToMakePath().String())
 				fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+apexType.suffix())
 				fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable())
-				fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES :=", strings.Join(a.overridableProperties.Overrides, " "))
+				if len(a.overridableProperties.Overrides) > 0 {
+					fmt.Fprintln(w, "LOCAL_OVERRIDES_MODULES :=", strings.Join(a.overridableProperties.Overrides, " "))
+				}
 				if len(moduleNames) > 0 {
 					fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(moduleNames, " "))
 				}
diff --git a/apex/apex.go b/apex/apex.go
index 10c16f5..a4af7aa 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -22,14 +22,16 @@
 	"strings"
 	"sync"
 
-	"android/soong/android"
-	"android/soong/cc"
-	"android/soong/java"
-	"android/soong/python"
-
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/bootstrap"
 	"github.com/google/blueprint/proptools"
+
+	"android/soong/android"
+	"android/soong/cc"
+	prebuilt_etc "android/soong/etc"
+	"android/soong/java"
+	"android/soong/python"
+	"android/soong/sh"
 )
 
 const (
@@ -62,13 +64,14 @@
 	usesTag        = dependencyTag{name: "uses"}
 	androidAppTag  = dependencyTag{name: "androidApp", payload: true}
 	rroTag         = dependencyTag{name: "rro", payload: true}
-	apexAvailWl    = makeApexAvailableWhitelist()
 
-	inverseApexAvailWl = invertApexWhiteList(apexAvailWl)
+	apexAvailBaseline = makeApexAvailableBaseline()
+
+	inverseApexAvailBaseline = invertApexBaseline(apexAvailBaseline)
 )
 
 // Transform the map of apex -> modules to module -> apexes.
-func invertApexWhiteList(m map[string][]string) map[string][]string {
+func invertApexBaseline(m map[string][]string) map[string][]string {
 	r := make(map[string][]string)
 	for apex, modules := range m {
 		for _, module := range modules {
@@ -78,16 +81,16 @@
 	return r
 }
 
-// Retrieve the while list of apexes to which the supplied module belongs.
-func WhitelistedApexAvailable(moduleName string) []string {
-	return inverseApexAvailWl[normalizeModuleName(moduleName)]
+// Retrieve the baseline of apexes to which the supplied module belongs.
+func BaselineApexAvailable(moduleName string) []string {
+	return inverseApexAvailBaseline[normalizeModuleName(moduleName)]
 }
 
 // This is a map from apex to modules, which overrides the
 // apex_available setting for that particular module to make
 // it available for the apex regardless of its setting.
 // TODO(b/147364041): remove this
-func makeApexAvailableWhitelist() map[string][]string {
+func makeApexAvailableBaseline() map[string][]string {
 	// The "Module separator"s below are employed to minimize merge conflicts.
 	m := make(map[string][]string)
 	//
@@ -175,12 +178,6 @@
 	//
 	// Module separator
 	//
-	m["com.android.conscrypt"] = []string{
-		"libnativehelper_header_only",
-	}
-	//
-	// Module separator
-	//
 	m["com.android.neuralnetworks"] = []string{
 		"android.hardware.neuralnetworks@1.0",
 		"android.hardware.neuralnetworks@1.1",
@@ -476,7 +473,6 @@
 		"libbase_ndk",
 		"libfuse",
 		"libfuse_jni",
-		"libnativehelper_header_only",
 	}
 	//
 	// Module separator
@@ -558,7 +554,6 @@
 		"ipmemorystore-aidl-interfaces-java",
 		"libcgrouprc",
 		"libcgrouprc_format",
-		"libnativehelper_compat_libc++",
 		"libtetherutilsjni",
 		"libvndksupport",
 		"net-utils-framework-common",
@@ -869,17 +864,17 @@
 }
 
 var (
-	useVendorWhitelistKey = android.NewOnceKey("useVendorWhitelist")
+	useVendorAllowListKey = android.NewOnceKey("useVendorAllowList")
 )
 
-// useVendorWhitelist returns the list of APEXes which are allowed to use_vendor.
+// useVendorAllowList returns the list of APEXes which are allowed to use_vendor.
 // When use_vendor is used, native modules are built with __ANDROID_VNDK__ and __ANDROID_APEX__,
 // which may cause compatibility issues. (e.g. libbinder)
 // Even though libbinder restricts its availability via 'apex_available' property and relies on
 // yet another macro __ANDROID_APEX_<NAME>__, we restrict usage of "use_vendor:" from other APEX modules
 // to avoid similar problems.
-func useVendorWhitelist(config android.Config) []string {
-	return config.Once(useVendorWhitelistKey, func() interface{} {
+func useVendorAllowList(config android.Config) []string {
+	return config.Once(useVendorAllowListKey, func() interface{} {
 		return []string{
 			// swcodec uses "vendor" variants for smaller size
 			"com.android.media.swcodec",
@@ -888,11 +883,11 @@
 	}).([]string)
 }
 
-// setUseVendorWhitelistForTest overrides useVendorWhitelist and must be
-// called before the first call to useVendorWhitelist()
-func setUseVendorWhitelistForTest(config android.Config, whitelist []string) {
-	config.Once(useVendorWhitelistKey, func() interface{} {
-		return whitelist
+// setUseVendorAllowListForTest overrides useVendorAllowList and must be
+// called before the first call to useVendorAllowList()
+func setUseVendorAllowListForTest(config android.Config, allowList []string) {
+	config.Once(useVendorAllowListKey, func() interface{} {
+		return allowList
 	})
 }
 
@@ -990,8 +985,8 @@
 	// List of providing APEXes' names so that this APEX can depend on provided shared libraries.
 	Uses []string
 
-	// A txt file containing list of files that are whitelisted to be included in this APEX.
-	Whitelisted_files *string
+	// A txt file containing list of files that are allowed to be included in this APEX.
+	Allowed_files *string
 
 	// package format of this apex variant; could be non-flattened, flattened, or zip.
 	// imageApex, zipApex or flattened
@@ -1113,6 +1108,7 @@
 	javaSharedLib
 	nativeTest
 	app
+	appSet
 )
 
 func (class apexFileClass) NameInMake() string {
@@ -1127,7 +1123,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
@@ -1329,7 +1325,7 @@
 }
 
 func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) {
-	if proptools.Bool(a.properties.Use_vendor) && !android.InList(a.Name(), useVendorWhitelist(ctx.Config())) {
+	if proptools.Bool(a.properties.Use_vendor) && !android.InList(a.Name(), useVendorAllowList(ctx.Config())) {
 		ctx.PropertyErrorf("use_vendor", "not allowed to set use_vendor: true")
 	}
 
@@ -1639,7 +1635,7 @@
 	return newApexFile(ctx, fileToCopy, depName, dirInApex, goBinary, nil)
 }
 
-func apexFileForShBinary(ctx android.BaseModuleContext, sh *android.ShBinary) apexFile {
+func apexFileForShBinary(ctx android.BaseModuleContext, sh *sh.ShBinary) apexFile {
 	dirInApex := filepath.Join("bin", sh.SubDir())
 	fileToCopy := sh.OutputFile()
 	af := newApexFile(ctx, fileToCopy, sh.Name(), dirInApex, shBinary, sh)
@@ -1648,20 +1644,23 @@
 }
 
 type javaDependency interface {
-	java.Dependency
+	DexJarBuildPath() android.Path
+	JacocoReportClassesFile() android.Path
 	Stem() string
 }
 
 func apexFileForJavaLibrary(ctx android.BaseModuleContext, lib javaDependency, module android.Module) apexFile {
 	dirInApex := "javalib"
-	fileToCopy := lib.DexJar()
-	af := newApexFile(ctx, fileToCopy, module.Name(), dirInApex, javaSharedLib, module)
+	fileToCopy := lib.DexJarBuildPath()
+	// Remove prebuilt_ if necessary so the source and prebuilt modules have the same name.
+	name := strings.TrimPrefix(module.Name(), "prebuilt_")
+	af := newApexFile(ctx, fileToCopy, name, dirInApex, javaSharedLib, module)
 	af.jacocoReportClassesFile = lib.JacocoReportClassesFile()
 	af.stem = lib.Stem() + ".jar"
 	return af
 }
 
-func apexFileForPrebuiltEtc(ctx android.BaseModuleContext, prebuilt android.PrebuiltEtcModule, depName string) apexFile {
+func apexFileForPrebuiltEtc(ctx android.BaseModuleContext, prebuilt prebuilt_etc.PrebuiltEtcModule, depName string) apexFile {
 	dirInApex := filepath.Join("etc", prebuilt.SubDir())
 	fileToCopy := prebuilt.OutputFile()
 	return newApexFile(ctx, fileToCopy, depName, dirInApex, etc, prebuilt)
@@ -1800,7 +1799,7 @@
 			return false
 		}
 
-		if to.AvailableFor(apexName) || whitelistedApexAvailable(apexName, toName) {
+		if to.AvailableFor(apexName) || baselineApexAvailable(apexName, toName) {
 			return true
 		}
 		ctx.ModuleErrorf("%q requires %q that is not available for the APEX. Dependency path:%s", fromName, toName, ctx.GetPathString(true))
@@ -1949,8 +1948,10 @@
 					fi := apexFileForNativeLibrary(ctx, c, handleSpecialLibs)
 					fi.isJniLib = isJniLib
 					filesInfo = append(filesInfo, fi)
-					// bootstrap bionic libs are treated as provided by system
-					if c.HasStubsVariants() && !cc.InstallToBootstrap(c.BaseModuleName(), ctx.Config()) {
+					// Collect the list of stub-providing libs except:
+					// - VNDK libs are only for vendors
+					// - bootstrap bionic libs are treated as provided by system
+					if c.HasStubsVariants() && !a.vndkApex && !cc.InstallToBootstrap(c.BaseModuleName(), ctx.Config()) {
 						provideNativeLibs = append(provideNativeLibs, fi.Stem())
 					}
 					return true // track transitive dependencies
@@ -1965,7 +1966,7 @@
 				if cc, ok := child.(*cc.Module); ok {
 					filesInfo = append(filesInfo, apexFileForExecutable(ctx, cc))
 					return true // track transitive dependencies
-				} else if sh, ok := child.(*android.ShBinary); ok {
+				} else if sh, ok := child.(*sh.ShBinary); ok {
 					filesInfo = append(filesInfo, apexFileForShBinary(ctx, sh))
 				} else if py, ok := child.(*python.Module); ok && py.HostToolPath().Valid() {
 					filesInfo = append(filesInfo, apexFileForPyBinary(ctx, py))
@@ -1975,23 +1976,16 @@
 					ctx.PropertyErrorf("binaries", "%q is neither cc_binary, (embedded) py_binary, (host) blueprint_go_binary, (host) bootstrap_go_binary, nor sh_binary", depName)
 				}
 			case javaLibTag:
-				if javaLib, ok := child.(*java.Library); ok {
-					af := apexFileForJavaLibrary(ctx, javaLib, javaLib)
-					if !af.Ok() {
-						ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName)
-					} else {
-						filesInfo = append(filesInfo, af)
-						return true // track transitive dependencies
-					}
-				} else if sdkLib, ok := child.(*java.SdkLibrary); ok {
-					af := apexFileForJavaLibrary(ctx, sdkLib, sdkLib)
+				switch child.(type) {
+				case *java.Library, *java.SdkLibrary, *java.DexImport, *java.SdkLibraryImport:
+					af := apexFileForJavaLibrary(ctx, child.(javaDependency), child.(android.Module))
 					if !af.Ok() {
 						ctx.PropertyErrorf("java_libs", "%q is not configured to be compiled into dex", depName)
 						return false
 					}
 					filesInfo = append(filesInfo, af)
 					return true // track transitive dependencies
-				} else {
+				default:
 					ctx.PropertyErrorf("java_libs", "%q of type %q is not supported", depName, ctx.OtherModuleType(child))
 				}
 			case androidAppTag:
@@ -2002,6 +1996,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)
 				}
@@ -2012,7 +2015,7 @@
 					ctx.PropertyErrorf("rros", "%q is not an runtime_resource_overlay module", depName)
 				}
 			case prebuiltTag:
-				if prebuilt, ok := child.(android.PrebuiltEtcModule); ok {
+				if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
 					filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
 				} else if prebuilt, ok := child.(java.PlatformCompatConfigIntf); ok {
 					filesInfo = append(filesInfo, apexFileForCompatConfig(ctx, prebuilt, depName))
@@ -2109,7 +2112,7 @@
 					// Because APK-in-APEX embeds jni_libs transitively, we don't need to track transitive deps
 					return false
 				} else if java.IsXmlPermissionsFileDepTag(depTag) {
-					if prebuilt, ok := child.(android.PrebuiltEtcModule); ok {
+					if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
 						filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
 					}
 				} else if am.CanHaveApexVariants() && am.IsInstallableToApex() {
@@ -2237,16 +2240,16 @@
 	})
 }
 
-func whitelistedApexAvailable(apex, moduleName string) bool {
+func baselineApexAvailable(apex, moduleName string) bool {
 	key := apex
 	moduleName = normalizeModuleName(moduleName)
 
-	if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
+	if val, ok := apexAvailBaseline[key]; ok && android.InList(moduleName, val) {
 		return true
 	}
 
 	key = android.AvailableToAnyApex
-	if val, ok := apexAvailWl[key]; ok && android.InList(moduleName, val) {
+	if val, ok := apexAvailBaseline[key]; ok && android.InList(moduleName, val) {
 		return true
 	}
 
@@ -2274,9 +2277,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 29bd087..a7a7765 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -29,7 +29,9 @@
 	"android/soong/android"
 	"android/soong/cc"
 	"android/soong/dexpreopt"
+	prebuilt_etc "android/soong/etc"
 	"android/soong/java"
+	"android/soong/sh"
 )
 
 var buildDir string
@@ -64,7 +66,7 @@
 func testApex(t *testing.T, bp string, handlers ...testCustomizer) (*android.TestContext, android.Config) {
 	t.Helper()
 	ctx, config := testApexContext(t, bp, handlers...)
-	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	_, errs := ctx.ParseBlueprintsFiles(".")
 	android.FailIfErrored(t, errs)
 	_, errs = ctx.PrepareBuildActions(config)
 	android.FailIfErrored(t, errs)
@@ -94,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: ""},
@@ -113,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 + `
@@ -185,6 +187,7 @@
 		"baz":                                        nil,
 		"bar/baz":                                    nil,
 		"testdata/baz":                               nil,
+		"AppSet.apks":                                nil,
 	}
 
 	cc.GatherRequiredFilesForTest(fs)
@@ -214,6 +217,11 @@
 	}
 
 	ctx := android.NewTestArchContext()
+
+	// from android package
+	android.RegisterPackageBuildComponents(ctx)
+	ctx.PreArchMutators(android.RegisterVisibilityRuleChecker)
+
 	ctx.RegisterModuleType("apex", BundleFactory)
 	ctx.RegisterModuleType("apex_test", testApexBundleFactory)
 	ctx.RegisterModuleType("apex_vndk", vndkApexBundleFactory)
@@ -227,17 +235,24 @@
 	ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
 
 	cc.RegisterRequiredBuildComponentsForTest(ctx)
+
+	// Register this after the prebuilt mutators have been registered (in
+	// cc.RegisterRequiredBuildComponentsForTest) to match what happens at runtime.
+	ctx.PreArchMutators(android.RegisterVisibilityRuleGatherer)
+	ctx.PostDepsMutators(android.RegisterVisibilityRuleEnforcer)
+
 	ctx.RegisterModuleType("cc_test", cc.TestFactory)
 	ctx.RegisterModuleType("vndk_prebuilt_shared", cc.VndkPrebuiltSharedFactory)
 	ctx.RegisterModuleType("vndk_libraries_txt", cc.VndkLibrariesTxtFactory)
-	ctx.RegisterModuleType("prebuilt_etc", android.PrebuiltEtcFactory)
+	ctx.RegisterModuleType("prebuilt_etc", prebuilt_etc.PrebuiltEtcFactory)
 	ctx.RegisterModuleType("platform_compat_config", java.PlatformCompatConfigFactory)
-	ctx.RegisterModuleType("sh_binary", android.ShBinaryFactory)
+	ctx.RegisterModuleType("sh_binary", sh.ShBinaryFactory)
 	ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
 	java.RegisterJavaBuildComponents(ctx)
 	java.RegisterSystemModulesBuildComponents(ctx)
 	java.RegisterAppBuildComponents(ctx)
-	ctx.RegisterModuleType("java_sdk_library", java.SdkLibraryFactory)
+	java.RegisterSdkLibraryBuildComponents(ctx)
+	ctx.RegisterSingletonType("apex_keys_text", apexKeysTextFactory)
 
 	ctx.PreDepsMutators(RegisterPreDepsMutators)
 	ctx.PostDepsMutators(RegisterPostDepsMutators)
@@ -256,7 +271,7 @@
 }
 
 func tearDown() {
-	os.RemoveAll(buildDir)
+	_ = os.RemoveAll(buildDir)
 }
 
 // ensure that 'result' equals 'expected'
@@ -292,6 +307,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) {
@@ -315,7 +341,7 @@
 
 // Minimal test
 func TestBasicApex(t *testing.T) {
-	ctx, _ := testApex(t, `
+	ctx, config := testApex(t, `
 		apex_defaults {
 			name: "myapex-defaults",
 			manifest: ":myapex.manifest",
@@ -327,7 +353,10 @@
 					binaries: ["foo",],
 				}
 			},
-			java_libs: ["myjar"],
+			java_libs: [
+				"myjar",
+				"myjar_dex",
+			],
 		}
 
 		apex {
@@ -436,6 +465,15 @@
 			],
 		}
 
+		dex_import {
+			name: "myjar_dex",
+			jars: ["prebuilt.jar"],
+			apex_available: [
+				"//apex_available:platform",
+				"myapex",
+			],
+		}
+
 		java_library {
 			name: "myotherjar",
 			srcs: ["foo/bar/MyClass.java"],
@@ -458,6 +496,16 @@
 
 	apexRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexRule")
 
+	// Make sure that Android.mk is created
+	ab := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle)
+	data := android.AndroidMkDataForTest(t, config, "", ab)
+	var builder strings.Builder
+	data.Custom(&builder, ab.BaseModuleName(), "TARGET_", "", data)
+
+	androidMk := builder.String()
+	ensureContains(t, androidMk, "LOCAL_MODULE := mylib.myapex\n")
+	ensureNotContains(t, androidMk, "LOCAL_MODULE := mylib.com.android.myapex\n")
+
 	optFlags := apexRule.Args["opt_flags"]
 	ensureContains(t, optFlags, "--pubkey vendor/foo/devkeys/testkey.avbpubkey")
 	// Ensure that the NOTICE output is being packaged as an asset.
@@ -471,6 +519,7 @@
 	// Ensure that apex variant is created for the direct dep
 	ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex")
 	ensureListContains(t, ctx.ModuleVariantsForTests("myjar"), "android_common_myapex")
+	ensureListContains(t, ctx.ModuleVariantsForTests("myjar_dex"), "android_common_myapex")
 
 	// Ensure that apex variant is created for the indirect dep
 	ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_myapex")
@@ -480,6 +529,7 @@
 	ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
 	ensureContains(t, copyCmds, "image.apex/lib64/mylib2.so")
 	ensureContains(t, copyCmds, "image.apex/javalib/myjar_stem.jar")
+	ensureContains(t, copyCmds, "image.apex/javalib/myjar_dex.jar")
 	// .. but not for java libs
 	ensureNotContains(t, copyCmds, "image.apex/javalib/myotherjar.jar")
 	ensureNotContains(t, copyCmds, "image.apex/javalib/msharedjar.jar")
@@ -1105,7 +1155,7 @@
 				symbol_file: "",
 			}
 			`, func(fs map[string][]byte, config android.Config) {
-				setUseVendorWhitelistForTest(config, []string{"myapex"})
+				setUseVendorAllowListForTest(config, []string{"myapex"})
 			}, withUnbundledBuild)
 
 			// Ensure that LLNDK dep is not included
@@ -1832,7 +1882,7 @@
 			apex_available: [ "myapex" ],
 		}
 	`, func(fs map[string][]byte, config android.Config) {
-		setUseVendorWhitelistForTest(config, []string{"myapex"})
+		setUseVendorAllowListForTest(config, []string{"myapex"})
 	})
 
 	inputsList := []string{}
@@ -1865,9 +1915,9 @@
 			private_key: "testkey.pem",
 		}
 	`, func(fs map[string][]byte, config android.Config) {
-		setUseVendorWhitelistForTest(config, []string{""})
+		setUseVendorAllowListForTest(config, []string{""})
 	})
-	// no error with whitelist
+	// no error with allow list
 	testApex(t, `
 		apex {
 			name: "myapex",
@@ -1880,7 +1930,7 @@
 			private_key: "testkey.pem",
 		}
 	`, func(fs map[string][]byte, config android.Config) {
-		setUseVendorWhitelistForTest(config, []string{"myapex"})
+		setUseVendorAllowListForTest(config, []string{"myapex"})
 	})
 }
 
@@ -2778,6 +2828,40 @@
 	})
 }
 
+func TestVndkApexShouldNotProvideNativeLibs(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex_vndk {
+			name: "myapex",
+			key: "myapex.key",
+			file_contexts: ":myapex-file_contexts",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		cc_library {
+			name: "libz",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			stubs: {
+				symbol_file: "libz.map.txt",
+				versions: ["30"],
+			}
+		}
+	`+vndkLibrariesTxtFiles("current"), withFiles(map[string][]byte{
+		"libz.map.txt": nil,
+	}))
+
+	apexManifestRule := ctx.ModuleForTests("myapex", "android_common_image").Rule("apexManifestRule")
+	provideNativeLibs := names(apexManifestRule.Args["provideNativeLibs"])
+	ensureListEmpty(t, provideNativeLibs)
+}
+
 func TestDependenciesInApexManifest(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex {
@@ -3645,7 +3729,7 @@
 			private_key: "testkey.pem",
 		}
 	`, func(fs map[string][]byte, config android.Config) {
-		setUseVendorWhitelistForTest(config, []string{"myapex"})
+		setUseVendorAllowListForTest(config, []string{"myapex"})
 	})
 }
 
@@ -4293,6 +4377,9 @@
 	"api/system-removed.txt": nil,
 	"api/test-current.txt":   nil,
 	"api/test-removed.txt":   nil,
+
+	// For java_sdk_library_import
+	"a.jar": nil,
 }
 
 func TestJavaSDKLibrary(t *testing.T) {
@@ -4419,6 +4506,117 @@
 	}
 }
 
+func TestJavaSDKLibrary_ImportPreferred(t *testing.T) {
+	ctx, _ := testApex(t, ``,
+		withFiles(map[string][]byte{
+			"apex/a.java":             nil,
+			"apex/apex_manifest.json": nil,
+			"apex/Android.bp": []byte(`
+		package {
+			default_visibility: ["//visibility:private"],
+		}
+
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			java_libs: ["foo", "bar"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		java_library {
+			name: "bar",
+			srcs: ["a.java"],
+			libs: ["foo"],
+			apex_available: ["myapex"],
+			sdk_version: "none",
+			system_modules: "none",
+		}
+`),
+			"source/a.java":          nil,
+			"source/api/current.txt": nil,
+			"source/api/removed.txt": nil,
+			"source/Android.bp": []byte(`
+		package {
+			default_visibility: ["//visibility:private"],
+		}
+
+		java_sdk_library {
+			name: "foo",
+			visibility: ["//apex"],
+			srcs: ["a.java"],
+			api_packages: ["foo"],
+			apex_available: ["myapex"],
+			sdk_version: "none",
+			system_modules: "none",
+			public: {
+				enabled: true,
+			},
+		}
+`),
+			"prebuilt/a.jar": nil,
+			"prebuilt/Android.bp": []byte(`
+		package {
+			default_visibility: ["//visibility:private"],
+		}
+
+		java_sdk_library_import {
+			name: "foo",
+			visibility: ["//apex", "//source"],
+			apex_available: ["myapex"],
+			prefer: true,
+			public: {
+				jars: ["a.jar"],
+			},
+		}
+`),
+		}),
+	)
+
+	// java_sdk_library installs both impl jar and permission XML
+	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
+		"javalib/bar.jar",
+		"javalib/foo.jar",
+		"etc/permissions/foo.xml",
+	})
+
+	// The bar library should depend on the implementation jar.
+	barLibrary := ctx.ModuleForTests("bar", "android_common_myapex").Rule("javac")
+	if expected, actual := `^-classpath /[^:]*/turbine-combined/foo\.impl\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) {
+		t.Errorf("expected %q, found %#q", expected, actual)
+	}
+}
+
+func TestJavaSDKLibrary_ImportOnly(t *testing.T) {
+	testApexError(t, `java_libs: "foo" is not configured to be compiled into dex`, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			java_libs: ["foo"],
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		java_sdk_library_import {
+			name: "foo",
+			apex_available: ["myapex"],
+			prefer: true,
+			public: {
+				jars: ["a.jar"],
+			},
+		}
+
+	`, withFiles(filesForSdkLibrary))
+}
+
 func TestCompatConfig(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex {
@@ -4756,6 +4954,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()
 
@@ -4915,7 +5145,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) {
@@ -4926,35 +5156,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) {
@@ -4965,27 +5195,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) {
@@ -5126,6 +5356,46 @@
 	`)
 }
 
+func TestApexKeysTxt(t *testing.T) {
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		prebuilt_apex {
+			name: "myapex",
+			prefer: true,
+			arch: {
+				arm64: {
+					src: "myapex-arm64.apex",
+				},
+				arm: {
+					src: "myapex-arm.apex",
+				},
+			},
+		}
+
+		apex_set {
+			name: "myapex_set",
+			set: "myapex.apks",
+			filename: "myapex_set.apex",
+			overrides: ["myapex"],
+		}
+	`)
+
+	apexKeysText := ctx.SingletonForTests("apex_keys_text")
+	content := apexKeysText.MaybeDescription("apexkeys.txt").BuildParams.Args["content"]
+	ensureContains(t, content, `name="myapex_set.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED" partition="system"`)
+	ensureNotContains(t, content, "myapex.apex")
+}
+
 func TestMain(m *testing.M) {
 	run := func() int {
 		setUp()
diff --git a/apex/builder.go b/apex/builder.go
index 0108d06..53c1193 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 ` +
@@ -162,13 +165,13 @@
 	diffApexContentRule = pctx.StaticRule("diffApexContentRule", blueprint.RuleParams{
 		Command: `diff --unchanged-group-format='' \` +
 			`--changed-group-format='%<' \` +
-			`${image_content_file} ${whitelisted_files_file} || (` +
+			`${image_content_file} ${allowed_files_file} || (` +
 			`echo -e "New unexpected files were added to ${apex_module_name}." ` +
 			` "To fix the build run following command:" && ` +
-			`echo "system/apex/tools/update_whitelist.sh ${whitelisted_files_file} ${image_content_file}" && ` +
+			`echo "system/apex/tools/update_allowed_list.sh ${allowed_files_file} ${image_content_file}" && ` +
 			`exit 1); touch ${out}`,
-		Description: "Diff ${image_content_file} and ${whitelisted_files_file}",
-	}, "image_content_file", "whitelisted_files_file", "apex_module_name")
+		Description: "Diff ${image_content_file} and ${allowed_files_file}",
+	}, "image_content_file", "allowed_files_file", "apex_module_name")
 )
 
 func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, requireNativeLibs []string) {
@@ -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
@@ -379,7 +391,7 @@
 	emitCommands = append(emitCommands, "sort -o "+imageContentFile.String()+" "+imageContentFile.String())
 	implicitInputs = append(implicitInputs, a.manifestPbOut)
 
-	if a.properties.Whitelisted_files != nil {
+	if a.properties.Allowed_files != nil {
 		ctx.Build(pctx, android.BuildParams{
 			Rule:        emitApexContentRule,
 			Implicits:   implicitInputs,
@@ -390,7 +402,7 @@
 			},
 		})
 		implicitInputs = append(implicitInputs, imageContentFile)
-		whitelistedFilesFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.Whitelisted_files))
+		allowedFilesFile := android.PathForModuleSrc(ctx, proptools.String(a.properties.Allowed_files))
 
 		phonyOutput := android.PathForModuleOut(ctx, a.Name()+"-diff-phony-output")
 		ctx.Build(pctx, android.BuildParams{
@@ -399,9 +411,9 @@
 			Output:      phonyOutput,
 			Description: "diff apex image content",
 			Args: map[string]string{
-				"whitelisted_files_file": whitelistedFilesFile.String(),
-				"image_content_file":     imageContentFile.String(),
-				"apex_module_name":       a.Name(),
+				"allowed_files_file": allowedFilesFile.String(),
+				"image_content_file": imageContentFile.String(),
+				"apex_module_name":   a.Name(),
 			},
 		})
 
@@ -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/apex/key.go b/apex/key.go
index 607cac5..a68f6e1 100644
--- a/apex/key.go
+++ b/apex/key.go
@@ -106,10 +106,36 @@
 
 func (s *apexKeysText) GenerateBuildActions(ctx android.SingletonContext) {
 	s.output = android.PathForOutput(ctx, "apexkeys.txt")
-	apexModulesMap := make(map[string]android.Module)
+	type apexKeyEntry struct {
+		name                  string
+		presigned             bool
+		public_key            string
+		private_key           string
+		container_certificate string
+		container_private_key string
+		partition             string
+	}
+	toString := func(e apexKeyEntry) string {
+		format := "name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q partition=%q\\n"
+		if e.presigned {
+			return fmt.Sprintf(format, e.name, "PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED", e.partition)
+		} else {
+			return fmt.Sprintf(format, e.name, e.public_key, e.private_key, e.container_certificate, e.container_private_key, e.partition)
+		}
+	}
+
+	apexKeyMap := make(map[string]apexKeyEntry)
 	ctx.VisitAllModules(func(module android.Module) {
 		if m, ok := module.(*apexBundle); ok && m.Enabled() && m.installable() {
-			apexModulesMap[m.Name()] = m
+			apexKeyMap[m.Name()] = apexKeyEntry{
+				name:                  m.Name() + ".apex",
+				presigned:             false,
+				public_key:            m.public_key_file.String(),
+				private_key:           m.private_key_file.String(),
+				container_certificate: m.container_certificate_file.String(),
+				container_private_key: m.container_private_key_file.String(),
+				partition:             m.PartitionTag(ctx.DeviceConfig()),
+			}
 		}
 	})
 
@@ -117,35 +143,43 @@
 	ctx.VisitAllModules(func(module android.Module) {
 		if m, ok := module.(*Prebuilt); ok && m.Enabled() && m.installable() &&
 			m.Prebuilt().UsePrebuilt() {
-			apexModulesMap[m.BaseModuleName()] = m
+			apexKeyMap[m.BaseModuleName()] = apexKeyEntry{
+				name:      m.InstallFilename(),
+				presigned: true,
+				partition: m.PartitionTag(ctx.DeviceConfig()),
+			}
+		}
+	})
+
+	// Find apex_set and let them override apexBundle or prebuilts. This is done in a separate pass
+	// so that apex_set are not overridden by prebuilts.
+	ctx.VisitAllModules(func(module android.Module) {
+		if m, ok := module.(*ApexSet); ok && m.Enabled() {
+			entry := apexKeyEntry{
+				name:      m.InstallFilename(),
+				presigned: true,
+				partition: m.PartitionTag(ctx.DeviceConfig()),
+			}
+
+			for _, om := range m.Overrides() {
+				if _, ok := apexKeyMap[om]; ok {
+					delete(apexKeyMap, om)
+				}
+			}
+			apexKeyMap[m.BaseModuleName()] = entry
 		}
 	})
 
 	// iterating over map does not give consistent ordering in golang
 	var moduleNames []string
-	for key, _ := range apexModulesMap {
+	for key, _ := range apexKeyMap {
 		moduleNames = append(moduleNames, key)
 	}
 	sort.Strings(moduleNames)
 
 	var filecontent strings.Builder
-	for _, key := range moduleNames {
-		module := apexModulesMap[key]
-		if m, ok := module.(*apexBundle); ok {
-			fmt.Fprintf(&filecontent,
-				"name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q partition=%q\\n",
-				m.Name()+".apex",
-				m.public_key_file.String(),
-				m.private_key_file.String(),
-				m.container_certificate_file.String(),
-				m.container_private_key_file.String(),
-				m.PartitionTag(ctx.DeviceConfig()))
-		} else if m, ok := module.(*Prebuilt); ok {
-			fmt.Fprintf(&filecontent,
-				"name=%q public_key=%q private_key=%q container_certificate=%q container_private_key=%q partition=%q\\n",
-				m.InstallFilename(),
-				"PRESIGNED", "PRESIGNED", "PRESIGNED", "PRESIGNED", m.PartitionTag(ctx.DeviceConfig()))
-		}
+	for _, name := range moduleNames {
+		fmt.Fprintf(&filecontent, "%s", toString(apexKeyMap[name]))
 	}
 
 	ctx.Build(pctx, android.BuildParams{
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index 03266c5..bf574dc 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -278,6 +278,10 @@
 	return a.prebuilt.Name(a.ModuleBase.Name())
 }
 
+func (a *ApexSet) Overrides() []string {
+	return a.properties.Overrides
+}
+
 // prebuilt_apex imports an `.apex` file into the build graph as if it was built with apex.
 func apexSetFactory() android.Module {
 	module := &ApexSet{}
diff --git a/cc/Android.bp b/cc/Android.bp
new file mode 100644
index 0000000..9ece05f
--- /dev/null
+++ b/cc/Android.bp
@@ -0,0 +1,87 @@
+bootstrap_go_package {
+    name: "soong-cc",
+    pkgPath: "android/soong/cc",
+    deps: [
+        "blueprint",
+        "blueprint-pathtools",
+        "soong",
+        "soong-android",
+        "soong-cc-config",
+        "soong-etc",
+        "soong-genrule",
+        "soong-tradefed",
+    ],
+    srcs: [
+        "androidmk.go",
+        "builder.go",
+        "cc.go",
+        "ccdeps.go",
+        "check.go",
+        "coverage.go",
+        "gen.go",
+        "linkable.go",
+        "lto.go",
+        "makevars.go",
+        "pgo.go",
+        "prebuilt.go",
+        "proto.go",
+        "rs.go",
+        "sanitize.go",
+        "sabi.go",
+        "sdk.go",
+        "snapshot_utils.go",
+        "stl.go",
+        "strip.go",
+        "sysprop.go",
+        "tidy.go",
+        "util.go",
+        "vendor_snapshot.go",
+        "vndk.go",
+        "vndk_prebuilt.go",
+
+        "cflag_artifacts.go",
+        "cmakelists.go",
+        "compdb.go",
+        "compiler.go",
+        "installer.go",
+        "linker.go",
+
+        "binary.go",
+        "binary_sdk_member.go",
+        "fuzz.go",
+        "library.go",
+        "library_headers.go",
+        "library_sdk_member.go",
+        "object.go",
+        "test.go",
+        "toolchain_library.go",
+
+        "ndk_prebuilt.go",
+        "ndk_headers.go",
+        "ndk_library.go",
+        "ndk_sysroot.go",
+
+        "llndk_library.go",
+
+        "kernel_headers.go",
+
+        "genrule.go",
+
+        "vendor_public_library.go",
+
+        "testing.go",
+    ],
+    testSrcs: [
+        "cc_test.go",
+        "compiler_test.go",
+        "gen_test.go",
+        "genrule_test.go",
+        "library_headers_test.go",
+        "library_test.go",
+        "object_test.go",
+        "prebuilt_test.go",
+        "proto_test.go",
+        "test_data_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 3ce1a89..b3ad610 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -457,6 +457,9 @@
 		entries.SetString("LOCAL_MODULE_PATH", path)
 		entries.SetString("LOCAL_MODULE_STEM", stem)
 		entries.SetBool("LOCAL_NO_NOTICE_FILE", true)
+		if c.parsedCoverageXmlPath.String() != "" {
+			entries.SetString("SOONG_NDK_API_XML", "$(SOONG_NDK_API_XML) "+c.parsedCoverageXmlPath.String())
+		}
 	})
 }
 
@@ -548,6 +551,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/builder.go b/cc/builder.go
index e571e5a..b4f9947 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -283,16 +283,19 @@
 		"cFlags")
 )
 
+func PwdPrefix() string {
+	// Darwin doesn't have /proc
+	if runtime.GOOS != "darwin" {
+		return "PWD=/proc/self/cwd"
+	}
+	return ""
+}
+
 func init() {
 	// We run gcc/clang with PWD=/proc/self/cwd to remove $TOP from the
 	// debug output. That way two builds in two different directories will
 	// create the same output.
-	if runtime.GOOS != "darwin" {
-		pctx.StaticVariable("relPwd", "PWD=/proc/self/cwd")
-	} else {
-		// Darwin doesn't have /proc
-		pctx.StaticVariable("relPwd", "")
-	}
+	pctx.StaticVariable("relPwd", PwdPrefix())
 
 	pctx.HostBinToolVariable("SoongZipCmd", "soong_zip")
 	pctx.Import("android/soong/remoteexec")
diff --git a/cc/cc.go b/cc/cc.go
index 94512d5..ebdb46c 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,41 @@
 		// 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)
+
+		// kernel_headers is a special module type whose exported headers
+		// are coming from DeviceKernelHeaders() which is always vendor
+		// dependent. They'll always have both vendor variants.
+		// For other modules, we assume that modules under proprietary
+		// paths are compatible for BOARD_VNDK_VERSION. The other modules
+		// are regarded as AOSP, which is PLATFORM_VNDK_VERSION.
+		if _, ok := m.linker.(*kernelHeadersDecorator); ok {
+			vendorVariants = append(vendorVariants,
+				platformVndkVersion,
+				boardVndkVersion,
+			)
+		} else 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
@@ -3171,6 +3209,10 @@
 	}
 }
 
+func (c *Module) IsSdkVariant() bool {
+	return c.Properties.IsSdkVariant
+}
+
 func getCurrentNdkPrebuiltVersion(ctx DepsContext) string {
 	if ctx.Config().PlatformSdkVersionInt() > config.NdkMaxPrebuiltVersionInt {
 		return strconv.Itoa(config.NdkMaxPrebuiltVersionInt)
@@ -3194,12 +3236,7 @@
 	})
 	// TODO(asmundak): Perhaps emit a rule to output a warning if there were no xrefTargets
 	if len(xrefTargets) > 0 {
-		ctx.Build(pctx, android.BuildParams{
-			Rule:   blueprint.Phony,
-			Output: android.PathForPhony(ctx, "xref_cxx"),
-			Inputs: xrefTargets,
-			//Default: true,
-		})
+		ctx.Phony("xref_cxx", xrefTargets...)
 	}
 }
 
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 67eb248..f73e021 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",
@@ -430,6 +430,40 @@
 	checkVndkLibrariesOutput(t, ctx, "vndkcorevariant.libraries.txt", nil)
 }
 
+func TestVndkWithHostSupported(t *testing.T) {
+	ctx := testCc(t, `
+		cc_library {
+			name: "libvndk_host_supported",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			host_supported: true,
+		}
+
+		cc_library {
+			name: "libvndk_host_supported_but_disabled_on_device",
+			vendor_available: true,
+			vndk: {
+				enabled: true,
+			},
+			host_supported: true,
+			enabled: false,
+			target: {
+				host: {
+					enabled: true,
+				}
+			}
+		}
+
+		vndk_libraries_txt {
+			name: "vndkcore.libraries.txt",
+		}
+	`)
+
+	checkVndkLibrariesOutput(t, ctx, "vndkcore.libraries.txt", []string{"libvndk_host_supported.so"})
+}
+
 func TestVndkLibrariesTxtAndroidMk(t *testing.T) {
 	bp := `
 		vndk_libraries_txt {
@@ -839,6 +873,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 +894,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 +909,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..b5f297c 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() {
@@ -515,7 +514,7 @@
 		flags.Local.CFlags = append(flags.Local.CFlags, "-fopenmp")
 	}
 
-	// Exclude directories from manual binder interface whitelisting.
+	// Exclude directories from manual binder interface allowed list.
 	//TODO(b/145621474): Move this check into IInterface.h when clang-tidy no longer uses absolute paths.
 	if android.HasAnyPrefix(ctx.ModuleDir(), allowedManualInterfacePaths) {
 		flags.Local.CFlags = append(flags.Local.CFlags, "-DDO_NOT_CHECK_MANUAL_BINDER_INTERFACES")
diff --git a/cc/config/Android.bp b/cc/config/Android.bp
new file mode 100644
index 0000000..6275064
--- /dev/null
+++ b/cc/config/Android.bp
@@ -0,0 +1,30 @@
+bootstrap_go_package {
+    name: "soong-cc-config",
+    pkgPath: "android/soong/cc/config",
+    deps: [
+        "soong-android",
+        "soong-remoteexec",
+    ],
+    srcs: [
+        "clang.go",
+        "global.go",
+        "tidy.go",
+        "toolchain.go",
+        "vndk.go",
+
+        "arm_device.go",
+        "arm64_device.go",
+        "arm64_fuchsia_device.go",
+        "x86_device.go",
+        "x86_64_device.go",
+        "x86_64_fuchsia_device.go",
+
+        "x86_darwin_host.go",
+        "x86_linux_host.go",
+        "x86_linux_bionic_host.go",
+        "x86_windows_host.go",
+    ],
+    testSrcs: [
+        "tidy_test.go",
+    ],
+}
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index 9383463..62d8cc8 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -32,7 +32,7 @@
 			"-march=armv8-a",
 		},
 		"armv8-2a": []string{
-			"-march=armv8.2a",
+			"-march=armv8.2-a",
 		},
 	}
 
diff --git a/cc/config/global.go b/cc/config/global.go
index 1dd8a2d..7b651bc 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -128,8 +128,8 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r383902"
-	ClangDefaultShortVersion = "11.0.1"
+	ClangDefaultVersion      = "clang-r383902b"
+	ClangDefaultShortVersion = "11.0.2"
 
 	// Directories with warnings from Android.bp files.
 	WarningAllowedProjects = []string{
diff --git a/cc/coverage.go b/cc/coverage.go
index f885fcb..1a559a9 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -180,7 +180,7 @@
 
 		if needCoverageVariant {
 			// Coverage variant is actually built with coverage if enabled for its module path
-			needCoverageBuild = ctx.DeviceConfig().CoverageEnabledForPath(ctx.ModuleDir())
+			needCoverageBuild = ctx.DeviceConfig().NativeCoverageEnabledForPath(ctx.ModuleDir())
 		}
 	}
 
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/library.go b/cc/library.go
index ba8b0f4..968702e 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -1077,9 +1077,14 @@
 
 func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, objs Objects, fileName string, soFile android.Path) {
 	if library.shouldCreateSourceAbiDump(ctx) {
-		vndkVersion := ctx.DeviceConfig().PlatformVndkVersion()
-		if ver := ctx.DeviceConfig().VndkVersion(); ver != "" && ver != "current" {
-			vndkVersion = ver
+		var vndkVersion string
+
+		if ctx.useVndk() {
+			// For modules linking against vndk, follow its vndk version
+			vndkVersion = ctx.Module().(*Module).VndkVersion()
+		} else {
+			// Regard the other modules as PLATFORM_VNDK_VERSION
+			vndkVersion = ctx.DeviceConfig().PlatformVndkVersion()
 		}
 
 		exportIncludeDirs := library.flagExporter.exportedIncludes(ctx)
@@ -1575,7 +1580,8 @@
 // (which is unnamed) and zero or more stubs variants.
 func VersionMutator(mctx android.BottomUpMutatorContext) {
 	if library, ok := mctx.Module().(LinkableInterface); ok && VersionVariantAvailable(library) {
-		if library.CcLibrary() && library.BuildSharedVariant() && len(library.StubsVersions()) > 0 {
+		if library.CcLibrary() && library.BuildSharedVariant() && len(library.StubsVersions()) > 0 &&
+			!library.IsSdkVariant() {
 			versions := library.StubsVersions()
 			normalizeVersions(mctx, versions)
 			if mctx.Failed() {
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index a7a1de2..4410302 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -124,6 +124,14 @@
 	if stl != nil {
 		pbm.AddProperty("stl", proptools.String(stl))
 	}
+
+	if lib, ok := ccModule.linker.(*libraryDecorator); ok {
+		uhs := lib.Properties.Unique_host_soname
+		if uhs != nil {
+			pbm.AddProperty("unique_host_soname", proptools.Bool(uhs))
+		}
+	}
+
 	return pbm
 }
 
diff --git a/cc/linkable.go b/cc/linkable.go
index de36f90..66b1c3f 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -56,6 +56,7 @@
 
 	SdkVersion() string
 	AlwaysSdk() bool
+	IsSdkVariant() bool
 
 	ToolchainLibrary() bool
 	NdkPrebuiltStl() bool
diff --git a/cc/linker.go b/cc/linker.go
index 57a0c01..c9cbd9b 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -177,7 +177,10 @@
 	Version_script *string `android:"path,arch_variant"`
 
 	// list of static libs that should not be used to build this module
-	Exclude_static_libs []string
+	Exclude_static_libs []string `android:"arch_variant"`
+
+	// list of shared libs that should not be used to build this module
+	Exclude_shared_libs []string `android:"arch_variant"`
 }
 
 func NewBaseLinker(sanitize *sanitize) *baseLinker {
@@ -223,6 +226,8 @@
 	deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, linker.Properties.Export_shared_lib_headers...)
 	deps.ReexportGeneratedHeaders = append(deps.ReexportGeneratedHeaders, linker.Properties.Export_generated_headers...)
 
+	deps.SharedLibs = removeListFromList(deps.SharedLibs, linker.Properties.Exclude_shared_libs)
+	deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Exclude_static_libs)
 	deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Exclude_static_libs)
 
 	if Bool(linker.Properties.Use_version_lib) {
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 1597b88..5ef9a78 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -25,8 +25,12 @@
 	"android/soong/android"
 )
 
+func init() {
+	pctx.HostBinToolVariable("ndk_api_coverage_parser", "ndk_api_coverage_parser")
+}
+
 var (
-	toolPath = pctx.SourcePathVariable("toolPath", "build/soong/cc/gen_stub_libs.py")
+	toolPath = pctx.SourcePathVariable("toolPath", "build/soong/cc/scriptlib/gen_stub_libs.py")
 
 	genStubSrc = pctx.AndroidStaticRule("genStubSrc",
 		blueprint.RuleParams{
@@ -35,6 +39,12 @@
 			CommandDeps: []string{"$toolPath"},
 		}, "arch", "apiLevel", "apiMap", "flags")
 
+	parseNdkApiRule = pctx.AndroidStaticRule("parseNdkApiRule",
+		blueprint.RuleParams{
+			Command:     "$ndk_api_coverage_parser $in $out --api-map $apiMap",
+			CommandDeps: []string{"$ndk_api_coverage_parser"},
+		}, "apiMap")
+
 	ndkLibrarySuffix = ".ndk"
 
 	ndkPrebuiltSharedLibs = []string{
@@ -111,8 +121,9 @@
 
 	properties libraryProperties
 
-	versionScriptPath android.ModuleGenPath
-	installPath       android.Path
+	versionScriptPath     android.ModuleGenPath
+	parsedCoverageXmlPath android.ModuleOutPath
+	installPath           android.Path
 }
 
 // OMG GO
@@ -308,14 +319,36 @@
 	return compileObjs(ctx, flagsToBuilderFlags(flags), subdir, srcs, nil, nil), versionScriptPath
 }
 
+func parseSymbolFileForCoverage(ctx ModuleContext, symbolFile string) android.ModuleOutPath {
+	apiLevelsJson := android.GetApiLevelsJson(ctx)
+	symbolFilePath := android.PathForModuleSrc(ctx, symbolFile)
+	outputFileName := strings.Split(symbolFilePath.Base(), ".")[0]
+	parsedApiCoveragePath := android.PathForModuleOut(ctx, outputFileName+".xml")
+	ctx.Build(pctx, android.BuildParams{
+		Rule:        parseNdkApiRule,
+		Description: "parse ndk api symbol file for api coverage: " + symbolFilePath.Rel(),
+		Outputs:     []android.WritablePath{parsedApiCoveragePath},
+		Input:       symbolFilePath,
+		Implicits:   []android.Path{apiLevelsJson},
+		Args: map[string]string{
+			"apiMap": apiLevelsJson.String(),
+		},
+	})
+	return parsedApiCoveragePath
+}
+
 func (c *stubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects {
 	if !strings.HasSuffix(String(c.properties.Symbol_file), ".map.txt") {
 		ctx.PropertyErrorf("symbol_file", "must end with .map.txt")
 	}
 
-	objs, versionScript := compileStubLibrary(ctx, flags, String(c.properties.Symbol_file),
+	symbolFile := String(c.properties.Symbol_file)
+	objs, versionScript := compileStubLibrary(ctx, flags, symbolFile,
 		c.properties.ApiLevel, "")
 	c.versionScriptPath = versionScript
+	if c.properties.ApiLevel == "current" && ctx.PrimaryArch() {
+		c.parsedCoverageXmlPath = parseSymbolFileForCoverage(ctx, symbolFile)
+	}
 	return objs
 }
 
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/scriptlib/Android.bp b/cc/scriptlib/Android.bp
new file mode 100644
index 0000000..ff9a2f0
--- /dev/null
+++ b/cc/scriptlib/Android.bp
@@ -0,0 +1,32 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+python_test_host {
+    name: "test_ndk_api_coverage_parser",
+    main: "test_ndk_api_coverage_parser.py",
+    srcs: [
+        "test_ndk_api_coverage_parser.py",
+    ],
+}
+
+python_binary_host {
+    name: "ndk_api_coverage_parser",
+    main: "ndk_api_coverage_parser.py",
+    srcs: [
+        "gen_stub_libs.py",
+        "ndk_api_coverage_parser.py",
+    ],
+}
diff --git a/cc/scriptlib/__init__.py b/cc/scriptlib/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cc/scriptlib/__init__.py
diff --git a/cc/gen_stub_libs.py b/cc/scriptlib/gen_stub_libs.py
similarity index 99%
rename from cc/gen_stub_libs.py
rename to cc/scriptlib/gen_stub_libs.py
index 7deb804..d61dfbb 100755
--- a/cc/gen_stub_libs.py
+++ b/cc/scriptlib/gen_stub_libs.py
@@ -246,6 +246,7 @@
     def __eq__(self, other):
         return self.name == other.name and set(self.tags) == set(other.tags)
 
+
 class SymbolFileParser(object):
     """Parses NDK symbol files."""
     def __init__(self, input_file, api_map, arch, api, llndk, apex):
diff --git a/cc/scriptlib/ndk_api_coverage_parser.py b/cc/scriptlib/ndk_api_coverage_parser.py
new file mode 100755
index 0000000..d74035b
--- /dev/null
+++ b/cc/scriptlib/ndk_api_coverage_parser.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""Generates xml of NDK libraries used for API coverage analysis."""
+import argparse
+import json
+import os
+import sys
+
+from xml.etree.ElementTree import Element, SubElement, tostring
+from gen_stub_libs import ALL_ARCHITECTURES, FUTURE_API_LEVEL, MultiplyDefinedSymbolError, SymbolFileParser
+
+
+ROOT_ELEMENT_TAG = 'ndk-library'
+SYMBOL_ELEMENT_TAG = 'symbol'
+ARCHITECTURE_ATTRIBUTE_KEY = 'arch'
+DEPRECATED_ATTRIBUTE_KEY = 'is_deprecated'
+PLATFORM_ATTRIBUTE_KEY = 'is_platform'
+NAME_ATTRIBUTE_KEY = 'name'
+VARIABLE_TAG = 'var'
+EXPOSED_TARGET_TAGS = (
+    'vndk',
+    'apex',
+    'llndk',
+)
+API_LEVEL_TAG_PREFIXES = (
+    'introduced=',
+    'introduced-',
+)
+
+
+def parse_tags(tags):
+    """Parses tags and save needed tags in the created attributes.
+
+    Return attributes dictionary.
+    """
+    attributes = {}
+    arch = []
+    for tag in tags:
+        if tag.startswith(tuple(API_LEVEL_TAG_PREFIXES)):
+            key, _, value = tag.partition('=')
+            attributes.update({key: value})
+        elif tag in ALL_ARCHITECTURES:
+            arch.append(tag)
+        elif tag in EXPOSED_TARGET_TAGS:
+            attributes.update({tag: 'True'})
+    attributes.update({ARCHITECTURE_ATTRIBUTE_KEY: ','.join(arch)})
+    return attributes
+
+
+class XmlGenerator(object):
+    """Output generator that writes parsed symbol file to a xml file."""
+    def __init__(self, output_file):
+        self.output_file = output_file
+
+    def convertToXml(self, versions):
+        """Writes all symbol data to the output file."""
+        root = Element(ROOT_ELEMENT_TAG)
+        for version in versions:
+            if VARIABLE_TAG in version.tags:
+                continue
+            version_attributes = parse_tags(version.tags)
+            _, _, postfix = version.name.partition('_')
+            is_platform = postfix == 'PRIVATE' or postfix == 'PLATFORM'
+            is_deprecated = postfix == 'DEPRECATED'
+            version_attributes.update({PLATFORM_ATTRIBUTE_KEY: str(is_platform)})
+            version_attributes.update({DEPRECATED_ATTRIBUTE_KEY: str(is_deprecated)})
+            for symbol in version.symbols:
+                if VARIABLE_TAG in symbol.tags:
+                    continue
+                attributes = {NAME_ATTRIBUTE_KEY: symbol.name}
+                attributes.update(version_attributes)
+                # If same version tags already exist, it will be overwrite here.
+                attributes.update(parse_tags(symbol.tags))
+                SubElement(root, SYMBOL_ELEMENT_TAG, attributes)
+        return root
+
+    def write_xml_to_file(self, root):
+        """Write xml element root to output_file."""
+        parsed_data = tostring(root)
+        output_file = open(self.output_file, "wb")
+        output_file.write(parsed_data)
+
+    def write(self, versions):
+        root = self.convertToXml(versions)
+        self.write_xml_to_file(root)
+
+
+def parse_args():
+    """Parses and returns command line arguments."""
+    parser = argparse.ArgumentParser()
+
+    parser.add_argument('symbol_file', type=os.path.realpath, help='Path to symbol file.')
+    parser.add_argument(
+        'output_file', type=os.path.realpath,
+        help='The output parsed api coverage file.')
+    parser.add_argument(
+        '--api-map', type=os.path.realpath, required=True,
+        help='Path to the API level map JSON file.')
+    return parser.parse_args()
+
+
+def main():
+    """Program entry point."""
+    args = parse_args()
+
+    with open(args.api_map) as map_file:
+        api_map = json.load(map_file)
+
+    with open(args.symbol_file) as symbol_file:
+        try:
+            versions = SymbolFileParser(symbol_file, api_map, "", FUTURE_API_LEVEL,
+                                        True, True).parse()
+        except MultiplyDefinedSymbolError as ex:
+            sys.exit('{}: error: {}'.format(args.symbol_file, ex))
+
+    generator = XmlGenerator(args.output_file)
+    generator.write(versions)
+
+if __name__ == '__main__':
+    main()
diff --git a/cc/test_gen_stub_libs.py b/cc/scriptlib/test_gen_stub_libs.py
similarity index 100%
rename from cc/test_gen_stub_libs.py
rename to cc/scriptlib/test_gen_stub_libs.py
diff --git a/cc/scriptlib/test_ndk_api_coverage_parser.py b/cc/scriptlib/test_ndk_api_coverage_parser.py
new file mode 100644
index 0000000..a3c9b70
--- /dev/null
+++ b/cc/scriptlib/test_ndk_api_coverage_parser.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+"""Tests for ndk_api_coverage_parser.py."""
+import io
+import textwrap
+import unittest
+
+from xml.etree.ElementTree import tostring
+from gen_stub_libs import FUTURE_API_LEVEL, SymbolFileParser
+import ndk_api_coverage_parser as nparser
+
+
+# pylint: disable=missing-docstring
+
+
+class ApiCoverageSymbolFileParserTest(unittest.TestCase):
+    def test_parse(self):
+        input_file = io.StringIO(textwrap.dedent(u"""\
+            LIBLOG { # introduced-arm64=24 introduced-x86=24 introduced-x86_64=24
+              global:
+                android_name_to_log_id; # apex llndk introduced=23
+                android_log_id_to_name; # llndk arm
+                __android_log_assert; # introduced-x86=23
+                __android_log_buf_print; # var
+                __android_log_buf_write;
+              local:
+                *;
+            };
+            
+            LIBLOG_PLATFORM {
+                android_fdtrack; # llndk
+                android_net; # introduced=23
+            };
+            
+            LIBLOG_FOO { # var
+                android_var;
+            };
+        """))
+        parser = SymbolFileParser(input_file, {}, "", FUTURE_API_LEVEL, True, True)
+        generator = nparser.XmlGenerator(io.StringIO())
+        result = tostring(generator.convertToXml(parser.parse())).decode()
+        expected = '<ndk-library><symbol apex="True" arch="" introduced="23" introduced-arm64="24" introduced-x86="24" introduced-x86_64="24" is_deprecated="False" is_platform="False" llndk="True" name="android_name_to_log_id" /><symbol arch="arm" introduced-arm64="24" introduced-x86="24" introduced-x86_64="24" is_deprecated="False" is_platform="False" llndk="True" name="android_log_id_to_name" /><symbol arch="" introduced-arm64="24" introduced-x86="23" introduced-x86_64="24" is_deprecated="False" is_platform="False" name="__android_log_assert" /><symbol arch="" introduced-arm64="24" introduced-x86="24" introduced-x86_64="24" is_deprecated="False" is_platform="False" name="__android_log_buf_write" /><symbol arch="" is_deprecated="False" is_platform="True" llndk="True" name="android_fdtrack" /><symbol arch="" introduced="23" is_deprecated="False" is_platform="True" name="android_net" /></ndk-library>'
+        self.assertEqual(expected, result)
+
+
+def main():
+    suite = unittest.TestLoader().loadTestsFromName(__name__)
+    unittest.TextTestRunner(verbosity=3).run(suite)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/cc/sdk.go b/cc/sdk.go
index d05a04a..b68baad 100644
--- a/cc/sdk.go
+++ b/cc/sdk.go
@@ -41,8 +41,9 @@
 			modules[0].(*Module).Properties.Sdk_version = nil
 			modules[1].(*Module).Properties.IsSdkVariant = true
 
-			if ctx.Config().UnbundledBuild() {
+			if ctx.Config().UnbundledBuildApps() {
 				modules[0].(*Module).Properties.HideFromMake = true
+				modules[0].(*Module).Properties.PreventInstall = true
 			} else {
 				modules[1].(*Module).Properties.SdkAndPlatformVariantVisibleToMake = true
 				modules[1].(*Module).Properties.PreventInstall = true
diff --git a/cc/test.go b/cc/test.go
index 2439c94..09da976 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -40,6 +40,8 @@
 type TestOptions struct {
 	// The UID that you want to run the test as on a device.
 	Run_test_as *string
+	// A list of free-formed strings without spaces that categorize the test.
+	Test_suite_tag []string
 }
 
 type TestBinaryProperties struct {
@@ -357,6 +359,9 @@
 	if test.Properties.Test_options.Run_test_as != nil {
 		configs = append(configs, tradefed.Option{Name: "run-test-as", Value: String(test.Properties.Test_options.Run_test_as)})
 	}
+	for _, tag := range test.Properties.Test_options.Test_suite_tag {
+		configs = append(configs, tradefed.Option{Name: "test-suite-tag", Value: tag})
+	}
 	if test.Properties.Test_min_api_level != nil && test.Properties.Test_min_sdk_version != nil {
 		ctx.PropertyErrorf("test_min_api_level", "'test_min_api_level' and 'test_min_sdk_version' should not be set at the same time.")
 	} else if test.Properties.Test_min_api_level != nil {
diff --git a/cc/testing.go b/cc/testing.go
index be020c5..479b424 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -467,15 +467,6 @@
 }
 
 func GatherRequiredFilesForTest(fs map[string][]byte) {
-	fs["prebuilts/ndk/current/sources/cxx-stl/llvm-libc++/libs/arm64-v8a/libc++_shared.so"] = nil
-	fs["prebuilts/ndk/current/platforms/android-27/arch-arm/usr/lib/crtbegin_so.o"] = nil
-	fs["prebuilts/ndk/current/platforms/android-27/arch-arm/usr/lib/crtend_so.o"] = nil
-	fs["prebuilts/ndk/current/platforms/android-27/arch-arm64/usr/lib/crtbegin_so.o"] = nil
-	fs["prebuilts/ndk/current/platforms/android-27/arch-arm64/usr/lib/crtend_so.o"] = nil
-	fs["prebuilts/ndk/current/platforms/android-27/arch-x86/usr/lib/crtbegin_so.o"] = nil
-	fs["prebuilts/ndk/current/platforms/android-27/arch-x86/usr/lib/crtend_so.o"] = nil
-	fs["prebuilts/ndk/current/platforms/android-27/arch-x86_64/usr/lib64/crtbegin_so.o"] = nil
-	fs["prebuilts/ndk/current/platforms/android-27/arch-x86_64/usr/lib64/crtend_so.o"] = nil
 }
 
 func TestConfig(buildDir string, os android.OsType, env map[string]string,
@@ -484,19 +475,7 @@
 	// add some modules that are required by the compiler and/or linker
 	bp = bp + GatherRequiredDepsForTest(os)
 
-	mockFS := map[string][]byte{
-		"foo.c":       nil,
-		"foo.lds":     nil,
-		"bar.c":       nil,
-		"baz.c":       nil,
-		"baz.o":       nil,
-		"a.proto":     nil,
-		"b.aidl":      nil,
-		"sub/c.aidl":  nil,
-		"my_include":  nil,
-		"foo.map.txt": nil,
-		"liba.so":     nil,
-	}
+	mockFS := map[string][]byte{}
 
 	GatherRequiredFilesForTest(mockFS)
 
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 5801fc7..4dad730 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,41 @@
 		return false
 	}
 	// the module must be installed in /vendor
-	if !m.installable() || m.isSnapshotPrebuilt() || !m.inVendor() {
+	if !m.IsForPlatform() || 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() {
+	// skip kernel_headers which always depend on vendor
+	if _, ok := m.linker.(*kernelHeadersDecorator); ok {
 		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 +602,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 +613,8 @@
 					(header only libraries)
 				binary/
 					(executable binaries)
+				object/
+					(.o object files)
 			NOTICE_FILES/
 				(notice files, e.g. libbase.txt)
 			configs/
@@ -620,7 +730,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 +740,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 +837,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 +853,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 +880,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 +928,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 +944,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.go b/cc/vndk.go
index e5e4533..4adf9d2 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -25,6 +25,7 @@
 
 	"android/soong/android"
 	"android/soong/cc/config"
+	"android/soong/etc"
 )
 
 const (
@@ -339,16 +340,24 @@
 	}
 }
 
-func IsForVndkApex(mctx android.BottomUpMutatorContext, m *Module) bool {
+// Sanity check for modules that mustn't be VNDK
+func shouldSkipVndkMutator(m *Module) bool {
 	if !m.Enabled() {
-		return false
+		return true
 	}
-
-	if !mctx.Device() {
-		return false
+	if !m.Device() {
+		// Skip non-device modules
+		return true
 	}
-
 	if m.Target().NativeBridge == android.NativeBridgeEnabled {
+		// Skip native_bridge modules
+		return true
+	}
+	return false
+}
+
+func IsForVndkApex(mctx android.BottomUpMutatorContext, m *Module) bool {
+	if shouldSkipVndkMutator(m) {
 		return false
 	}
 
@@ -382,11 +391,8 @@
 	if !ok {
 		return
 	}
-	if !m.Enabled() {
-		return
-	}
-	if m.Target().NativeBridge == android.NativeBridgeEnabled {
-		// Skip native_bridge modules
+
+	if shouldSkipVndkMutator(m) {
 		return
 	}
 
@@ -416,7 +422,7 @@
 	outputFile android.OutputPath
 }
 
-var _ android.PrebuiltEtcModule = &vndkLibrariesTxt{}
+var _ etc.PrebuiltEtcModule = &vndkLibrariesTxt{}
 var _ android.OutputFileProducer = &vndkLibrariesTxt{}
 
 // vndk_libraries_txt is a special kind of module type in that it name is one of
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/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 1d94f02..c965107 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -117,6 +117,8 @@
 // Command is the type of soong_ui execution. Only one type of
 // execution is specified. The args are specific to the command.
 func main() {
+	buildStartedMilli := time.Now().UnixNano() / int64(time.Millisecond)
+
 	c, args := getCommand(os.Args)
 	if c == nil {
 		fmt.Fprintf(os.Stderr, "The `soong` native UI is not yet available.\n")
@@ -166,12 +168,17 @@
 		logsDir = filepath.Join(config.DistDir(), "logs")
 	}
 
+	buildErrorFile := filepath.Join(logsDir, c.logsPrefix+"build_error")
+	rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb")
+	soongMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_metrics")
+	defer build.UploadMetrics(buildCtx, config, c.forceDumbOutput, buildStartedMilli, buildErrorFile, rbeMetricsFile, soongMetricsFile)
+
 	os.MkdirAll(logsDir, 0777)
 	log.SetOutput(filepath.Join(logsDir, c.logsPrefix+"soong.log"))
 	trace.SetOutput(filepath.Join(logsDir, c.logsPrefix+"build.trace"))
 	stat.AddOutput(status.NewVerboseLog(log, filepath.Join(logsDir, c.logsPrefix+"verbose.log")))
 	stat.AddOutput(status.NewErrorLog(log, filepath.Join(logsDir, c.logsPrefix+"error.log")))
-	stat.AddOutput(status.NewProtoErrorLog(log, filepath.Join(logsDir, c.logsPrefix+"build_error")))
+	stat.AddOutput(status.NewProtoErrorLog(log, buildErrorFile))
 	stat.AddOutput(status.NewCriticalPath(log))
 	stat.AddOutput(status.NewBuildProgressLog(log, filepath.Join(logsDir, c.logsPrefix+"build_progress.pb")))
 
@@ -179,7 +186,7 @@
 	buildCtx.Verbosef("Parallelism (local/remote/highmem): %v/%v/%v",
 		config.Parallel(), config.RemoteParallel(), config.HighmemParallel())
 
-	defer met.Dump(filepath.Join(logsDir, c.logsPrefix+"soong_metrics"))
+	defer met.Dump(soongMetricsFile)
 
 	if start, ok := os.LookupEnv("TRACE_BEGIN_SOONG"); ok {
 		if !strings.HasSuffix(start, "N") {
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 98850e5..bc44b21 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -50,6 +50,8 @@
 	UpdatableSystemServerJars []string // jars within apex that are loaded into system server
 	SpeedApps                 []string // apps that should be speed optimized
 
+	BrokenSuboptimalOrderOfSystemServerJars bool // if true, sub-optimal order does not cause a build error
+
 	PreoptFlags []string // global dex2oat flags that should be used if no module-specific dex2oat flags are specified
 
 	DefaultCompilerFilter      string // default compiler filter to pass to dex2oat, overridden by --compiler-filter= in module-specific dex2oat flags
@@ -98,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
@@ -112,10 +123,10 @@
 	ProfileIsTextListing bool
 	ProfileBootListing   android.OptionalPath
 
-	EnforceUsesLibraries         bool
-	PresentOptionalUsesLibraries []string
-	UsesLibraries                []string
-	LibraryPaths                 map[string]android.Path
+	EnforceUsesLibraries  bool
+	OptionalUsesLibraries []string
+	UsesLibraries         []string
+	LibraryPaths          LibraryPaths
 
 	Archs                   []android.ArchType
 	DexPreoptImages         []android.Path
@@ -163,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
@@ -262,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
 
@@ -271,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)
@@ -289,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 de696da..9cbe6e5 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -37,6 +37,7 @@
 	"fmt"
 	"path/filepath"
 	"runtime"
+	"sort"
 	"strings"
 
 	"android/soong/android"
@@ -192,6 +193,56 @@
 	return profilePath
 }
 
+type classLoaderContext struct {
+	// The class loader context using paths in the build.
+	Host android.Paths
+
+	// The class loader context using paths as they will be on the device.
+	Target []string
+}
+
+// A map of class loader contexts for each SDK version.
+// A map entry for "any" version contains libraries that are unconditionally added to class loader
+// context. Map entries for existing versions contains libraries that were in the default classpath
+// until that API version, and should be added to class loader context if and only if the
+// targetSdkVersion in the manifest or APK is less than that API version.
+type classLoaderContextMap map[int]*classLoaderContext
+
+const anySdkVersion int = -1
+
+func (m classLoaderContextMap) getSortedKeys() []int {
+	keys := make([]int, 0, len(m))
+	for k := range m {
+		keys = append(keys, k)
+	}
+	sort.Ints(keys)
+	return keys
+}
+
+func (m classLoaderContextMap) getValue(sdkVer int) *classLoaderContext {
+	if _, ok := m[sdkVer]; !ok {
+		m[sdkVer] = &classLoaderContext{}
+	}
+	return m[sdkVer]
+}
+
+func (m classLoaderContextMap) addLibs(sdkVer int, module *ModuleConfig, libs ...string) {
+	clc := m.getValue(sdkVer)
+	for _, lib := range libs {
+		p := pathForLibrary(module, lib)
+		clc.Host = append(clc.Host, p.Host)
+		clc.Target = append(clc.Target, p.Device)
+	}
+}
+
+func (m classLoaderContextMap) addSystemServerLibs(sdkVer int, ctx android.PathContext, module *ModuleConfig, libs ...string) {
+	clc := m.getValue(sdkVer)
+	for _, lib := range libs {
+		clc.Host = append(clc.Host, SystemServerDexJarHostPath(ctx, lib))
+		clc.Target = append(clc.Target, filepath.Join("/system/framework", lib+".jar"))
+	}
+}
+
 func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig,
 	module *ModuleConfig, rule *android.RuleBuilder, archIdx int, profile android.WritablePath,
 	appImage bool, generateDM bool) {
@@ -227,86 +278,45 @@
 
 	systemServerJars := NonUpdatableSystemServerJars(ctx, global)
 
-	// The class loader context using paths in the build
-	var classLoaderContextHost android.Paths
-
-	// The class loader context using paths as they will be on the device
-	var classLoaderContextTarget []string
-
-	// Extra paths that will be appended to the class loader if the APK manifest has targetSdkVersion < 28
-	var conditionalClassLoaderContextHost28 android.Paths
-	var conditionalClassLoaderContextTarget28 []string
-
-	// Extra paths that will be appended to the class loader if the APK manifest has targetSdkVersion < 29
-	var conditionalClassLoaderContextHost29 android.Paths
-	var conditionalClassLoaderContextTarget29 []string
-
-	// Extra paths that will be appended to the class loader if the APK manifest has targetSdkVersion < 30
-	var conditionalClassLoaderContextHost30 android.Paths
-	var conditionalClassLoaderContextTarget30 []string
+	classLoaderContexts := make(classLoaderContextMap)
 
 	// A flag indicating if the '&' class loader context is used.
 	unknownClassLoaderContext := false
 
 	if module.EnforceUsesLibraries {
-		usesLibs := append(copyOf(module.UsesLibraries), module.PresentOptionalUsesLibraries...)
+		// Unconditional class loader context.
+		usesLibs := append(copyOf(module.UsesLibraries), module.OptionalUsesLibraries...)
+		classLoaderContexts.addLibs(anySdkVersion, module, usesLibs...)
 
-		// Create class loader context for dex2oat from uses libraries and filtered optional libraries
-		for _, l := range usesLibs {
-
-			classLoaderContextHost = append(classLoaderContextHost,
-				pathForLibrary(module, l))
-			classLoaderContextTarget = append(classLoaderContextTarget,
-				filepath.Join("/system/framework", l+".jar"))
-		}
-
-		// org.apache.http.legacy contains classes that were in the default classpath until API 28.
-		// If the targetSdkVersion in the manifest or APK is < 28, and the module does not explicitly
-		// depend on org.apache.http.legacy, then implicitly add it to the classpath for dexpreopt.
+		// Conditional class loader context for API version < 28.
 		const httpLegacy = "org.apache.http.legacy"
 		if !contains(usesLibs, httpLegacy) {
-			conditionalClassLoaderContextHost28 = append(conditionalClassLoaderContextHost28,
-				pathForLibrary(module, httpLegacy))
-			conditionalClassLoaderContextTarget28 = append(conditionalClassLoaderContextTarget28,
-				filepath.Join("/system/framework", httpLegacy+".jar"))
+			classLoaderContexts.addLibs(28, module, httpLegacy)
 		}
 
-		// android.hidl.base-V1.0-java and android.hidl.manager-V1.0 contain classes that were in the default
-		// classpath until API 29.  If the targetSdkVersion in the manifest or APK is < 29 then implicitly add
-		// the classes to the classpath for dexpreopt.
-		const hidlBase = "android.hidl.base-V1.0-java"
-		const hidlManager = "android.hidl.manager-V1.0-java"
-		conditionalClassLoaderContextHost29 = append(conditionalClassLoaderContextHost29,
-			pathForLibrary(module, hidlManager))
-		conditionalClassLoaderContextTarget29 = append(conditionalClassLoaderContextTarget29,
-			filepath.Join("/system/framework", hidlManager+".jar"))
-		conditionalClassLoaderContextHost29 = append(conditionalClassLoaderContextHost29,
-			pathForLibrary(module, hidlBase))
-		conditionalClassLoaderContextTarget29 = append(conditionalClassLoaderContextTarget29,
-			filepath.Join("/system/framework", hidlBase+".jar"))
+		// Conditional class loader context for API version < 29.
+		usesLibs29 := []string{
+			"android.hidl.base-V1.0-java",
+			"android.hidl.manager-V1.0-java",
+		}
+		classLoaderContexts.addLibs(29, module, usesLibs29...)
 
-		// android.test.base contains classes that were in the default classpath until API 30.
-		// If the targetSdkVersion in the manifest or APK is < 30 then implicitly add it to the
-		// classpath for dexpreopt.
+		// Conditional class loader context for API version < 30.
 		const testBase = "android.test.base"
 		if !contains(usesLibs, testBase) {
-			conditionalClassLoaderContextHost30 = append(conditionalClassLoaderContextHost30,
-				pathForLibrary(module, testBase))
-			conditionalClassLoaderContextTarget30 = append(conditionalClassLoaderContextTarget30,
-				filepath.Join("/system/framework", testBase+".jar"))
+			classLoaderContexts.addLibs(30, module, testBase)
 		}
 	} else if jarIndex := android.IndexList(module.Name, systemServerJars); jarIndex >= 0 {
 		// System server jars should be dexpreopted together: class loader context of each jar
 		// should include all preceding jars on the system server classpath.
-		for _, otherJar := range systemServerJars[:jarIndex] {
-			classLoaderContextHost = append(classLoaderContextHost, SystemServerDexJarHostPath(ctx, otherJar))
-			classLoaderContextTarget = append(classLoaderContextTarget, "/system/framework/"+otherJar+".jar")
-		}
+		classLoaderContexts.addSystemServerLibs(anySdkVersion, ctx, module, systemServerJars[:jarIndex]...)
 
 		// Copy the system server jar to a predefined location where dex2oat will find it.
 		dexPathHost := SystemServerDexJarHostPath(ctx, module.Name)
 		rule.Command().Text("mkdir -p").Flag(filepath.Dir(dexPathHost.String()))
 		rule.Command().Text("cp -f").Input(module.DexPath).Output(dexPathHost)
+
+		checkSystemServerOrder(ctx, jarIndex)
 	} else {
 		// Pass special class loader context to skip the classpath and collision check.
 		// This will get removed once LOCAL_USES_LIBRARIES is enforced.
@@ -323,10 +333,11 @@
 			Text(`class_loader_context_arg=--class-loader-context=\&`).
 			Text(`stored_class_loader_context_arg=""`)
 	} else {
+		clc := classLoaderContexts[anySdkVersion]
 		rule.Command().
-			Text("class_loader_context_arg=--class-loader-context=PCL[" + strings.Join(classLoaderContextHost.Strings(), ":") + "]").
-			Implicits(classLoaderContextHost).
-			Text("stored_class_loader_context_arg=--stored-class-loader-context=PCL[" + strings.Join(classLoaderContextTarget, ":") + "]")
+			Text("class_loader_context_arg=--class-loader-context=PCL[" + strings.Join(clc.Host.Strings(), ":") + "]").
+			Implicits(clc.Host).
+			Text("stored_class_loader_context_arg=--stored-class-loader-context=PCL[" + strings.Join(clc.Target, ":") + "]")
 	}
 
 	if module.EnforceUsesLibraries {
@@ -345,26 +356,19 @@
 				Text(`| grep "targetSdkVersion" | sed -n "s/targetSdkVersion:'\(.*\)'/\1/p"`).
 				Text(`)"`)
 		}
-		rule.Command().Textf(`dex_preopt_host_libraries="%s"`,
-			strings.Join(classLoaderContextHost.Strings(), " ")).
-			Implicits(classLoaderContextHost)
-		rule.Command().Textf(`dex_preopt_target_libraries="%s"`,
-			strings.Join(classLoaderContextTarget, " "))
-		rule.Command().Textf(`conditional_host_libs_28="%s"`,
-			strings.Join(conditionalClassLoaderContextHost28.Strings(), " ")).
-			Implicits(conditionalClassLoaderContextHost28)
-		rule.Command().Textf(`conditional_target_libs_28="%s"`,
-			strings.Join(conditionalClassLoaderContextTarget28, " "))
-		rule.Command().Textf(`conditional_host_libs_29="%s"`,
-			strings.Join(conditionalClassLoaderContextHost29.Strings(), " ")).
-			Implicits(conditionalClassLoaderContextHost29)
-		rule.Command().Textf(`conditional_target_libs_29="%s"`,
-			strings.Join(conditionalClassLoaderContextTarget29, " "))
-		rule.Command().Textf(`conditional_host_libs_30="%s"`,
-			strings.Join(conditionalClassLoaderContextHost30.Strings(), " ")).
-			Implicits(conditionalClassLoaderContextHost30)
-		rule.Command().Textf(`conditional_target_libs_30="%s"`,
-			strings.Join(conditionalClassLoaderContextTarget30, " "))
+		for _, ver := range classLoaderContexts.getSortedKeys() {
+			clc := classLoaderContexts.getValue(ver)
+			var varHost, varTarget string
+			if ver == anySdkVersion {
+				varHost = "dex_preopt_host_libraries"
+				varTarget = "dex_preopt_target_libraries"
+			} else {
+				varHost = fmt.Sprintf("conditional_host_libs_%d", ver)
+				varTarget = fmt.Sprintf("conditional_target_libs_%d", ver)
+			}
+			rule.Command().Textf(varHost+`="%s"`, strings.Join(clc.Host.Strings(), " ")).Implicits(clc.Host)
+			rule.Command().Textf(varTarget+`="%s"`, strings.Join(clc.Target, " "))
+		}
 		rule.Command().Text("source").Tool(globalSoong.ConstructContext).Input(module.DexPath)
 	}
 
@@ -554,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))
@@ -606,6 +610,29 @@
 	}
 }
 
+// Check the order of jars on the system server classpath and give a warning/error if a jar precedes
+// one of its dependencies. This is not an error, but a missed optimization, as dexpreopt won't
+// have the dependency jar in the class loader context, and it won't be able to resolve any
+// references to its classes and methods.
+func checkSystemServerOrder(ctx android.PathContext, jarIndex int) {
+	mctx, isModule := ctx.(android.ModuleContext)
+	if isModule {
+		config := GetGlobalConfig(ctx)
+		jars := NonUpdatableSystemServerJars(ctx, config)
+		mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
+			depIndex := android.IndexList(dep.Name(), jars)
+			if jarIndex < depIndex && !config.BrokenSuboptimalOrderOfSystemServerJars {
+				jar := jars[jarIndex]
+				dep := jars[depIndex]
+				mctx.ModuleErrorf("non-optimal order of jars on the system server classpath:"+
+					" '%s' precedes its dependency '%s', so dexpreopt is unable to resolve any"+
+					" references from '%s' to '%s'.\n", jar, dep, jar, dep)
+			}
+			return true
+		})
+	}
+}
+
 func contains(l []string, s string) bool {
 	for _, e := range l {
 		if e == s {
diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go
index d239993..ec31549 100644
--- a/dexpreopt/dexpreopt_test.go
+++ b/dexpreopt/dexpreopt_test.go
@@ -44,7 +44,7 @@
 		ProfileClassListing:             android.OptionalPath{},
 		ProfileIsTextListing:            false,
 		EnforceUsesLibraries:            false,
-		PresentOptionalUsesLibraries:    nil,
+		OptionalUsesLibraries:           nil,
 		UsesLibraries:                   nil,
 		LibraryPaths:                    nil,
 		Archs:                           []android.ArchType{android.Arm},
diff --git a/env/Android.bp b/env/Android.bp
new file mode 100644
index 0000000..90c6047
--- /dev/null
+++ b/env/Android.bp
@@ -0,0 +1,7 @@
+bootstrap_go_package {
+    name: "soong-env",
+    pkgPath: "android/soong/env",
+    srcs: [
+        "env.go",
+    ],
+}
diff --git a/etc/Android.bp b/etc/Android.bp
new file mode 100644
index 0000000..cfd303e
--- /dev/null
+++ b/etc/Android.bp
@@ -0,0 +1,16 @@
+bootstrap_go_package {
+    name: "soong-etc",
+    pkgPath: "android/soong/etc",
+    deps: [
+        "blueprint",
+        "soong",
+        "soong-android",
+    ],
+    srcs: [
+        "prebuilt_etc.go",
+    ],
+    testSrcs: [
+        "prebuilt_etc_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
new file mode 100644
index 0000000..df6d79d
--- /dev/null
+++ b/etc/prebuilt_etc.go
@@ -0,0 +1,308 @@
+// Copyright 2016 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package etc
+
+import (
+	"strconv"
+
+	"github.com/google/blueprint/proptools"
+
+	"android/soong/android"
+)
+
+var pctx = android.NewPackageContext("android/soong/etc")
+
+// TODO(jungw): Now that it handles more than the ones in etc/, consider renaming this file.
+
+func init() {
+	pctx.Import("android/soong/android")
+
+	android.RegisterModuleType("prebuilt_etc", PrebuiltEtcFactory)
+	android.RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory)
+	android.RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory)
+	android.RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory)
+	android.RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
+	android.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
+	android.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory)
+}
+
+type prebuiltEtcProperties struct {
+	// Source file of this prebuilt.
+	Src *string `android:"path,arch_variant"`
+
+	// optional subdirectory under which this file is installed into
+	Sub_dir *string `android:"arch_variant"`
+
+	// optional name for the installed file. If unspecified, name of the module is used as the file name
+	Filename *string `android:"arch_variant"`
+
+	// when set to true, and filename property is not set, the name for the installed file
+	// is the same as the file name of the source file.
+	Filename_from_src *bool `android:"arch_variant"`
+
+	// Make this module available when building for ramdisk.
+	Ramdisk_available *bool
+
+	// Make this module available when building for recovery.
+	Recovery_available *bool
+
+	// Whether this module is directly installable to one of the partitions. Default: true.
+	Installable *bool
+
+	// Install symlinks to the installed file.
+	Symlinks []string `android:"arch_variant"`
+}
+
+type PrebuiltEtcModule interface {
+	android.Module
+	SubDir() string
+	OutputFile() android.OutputPath
+}
+
+type PrebuiltEtc struct {
+	android.ModuleBase
+
+	properties prebuiltEtcProperties
+
+	sourceFilePath android.Path
+	outputFilePath android.OutputPath
+	// The base install location, e.g. "etc" for prebuilt_etc, "usr/share" for prebuilt_usr_share.
+	installDirBase string
+	// The base install location when soc_specific property is set to true, e.g. "firmware" for prebuilt_firmware.
+	socInstallDirBase      string
+	installDirPath         android.InstallPath
+	additionalDependencies *android.Paths
+}
+
+func (p *PrebuiltEtc) inRamdisk() bool {
+	return p.ModuleBase.InRamdisk() || p.ModuleBase.InstallInRamdisk()
+}
+
+func (p *PrebuiltEtc) onlyInRamdisk() bool {
+	return p.ModuleBase.InstallInRamdisk()
+}
+
+func (p *PrebuiltEtc) InstallInRamdisk() bool {
+	return p.inRamdisk()
+}
+
+func (p *PrebuiltEtc) inRecovery() bool {
+	return p.ModuleBase.InRecovery() || p.ModuleBase.InstallInRecovery()
+}
+
+func (p *PrebuiltEtc) onlyInRecovery() bool {
+	return p.ModuleBase.InstallInRecovery()
+}
+
+func (p *PrebuiltEtc) InstallInRecovery() bool {
+	return p.inRecovery()
+}
+
+var _ android.ImageInterface = (*PrebuiltEtc)(nil)
+
+func (p *PrebuiltEtc) ImageMutatorBegin(ctx android.BaseModuleContext) {}
+
+func (p *PrebuiltEtc) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
+	return !p.ModuleBase.InstallInRecovery() && !p.ModuleBase.InstallInRamdisk()
+}
+
+func (p *PrebuiltEtc) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+	return proptools.Bool(p.properties.Ramdisk_available) || p.ModuleBase.InstallInRamdisk()
+}
+
+func (p *PrebuiltEtc) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
+	return proptools.Bool(p.properties.Recovery_available) || p.ModuleBase.InstallInRecovery()
+}
+
+func (p *PrebuiltEtc) ExtraImageVariations(ctx android.BaseModuleContext) []string {
+	return nil
+}
+
+func (p *PrebuiltEtc) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
+}
+
+func (p *PrebuiltEtc) DepsMutator(ctx android.BottomUpMutatorContext) {
+	if p.properties.Src == nil {
+		ctx.PropertyErrorf("src", "missing prebuilt source file")
+	}
+}
+
+func (p *PrebuiltEtc) SourceFilePath(ctx android.ModuleContext) android.Path {
+	return android.PathForModuleSrc(ctx, android.String(p.properties.Src))
+}
+
+func (p *PrebuiltEtc) InstallDirPath() android.InstallPath {
+	return p.installDirPath
+}
+
+// This allows other derivative modules (e.g. prebuilt_etc_xml) to perform
+// additional steps (like validating the src) before the file is installed.
+func (p *PrebuiltEtc) SetAdditionalDependencies(paths android.Paths) {
+	p.additionalDependencies = &paths
+}
+
+func (p *PrebuiltEtc) OutputFile() android.OutputPath {
+	return p.outputFilePath
+}
+
+func (p *PrebuiltEtc) SubDir() string {
+	return android.String(p.properties.Sub_dir)
+}
+
+func (p *PrebuiltEtc) Installable() bool {
+	return p.properties.Installable == nil || android.Bool(p.properties.Installable)
+}
+
+func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	p.sourceFilePath = android.PathForModuleSrc(ctx, android.String(p.properties.Src))
+	filename := android.String(p.properties.Filename)
+	filename_from_src := android.Bool(p.properties.Filename_from_src)
+	if filename == "" {
+		if filename_from_src {
+			filename = p.sourceFilePath.Base()
+		} else {
+			filename = ctx.ModuleName()
+		}
+	} else if filename_from_src {
+		ctx.PropertyErrorf("filename_from_src", "filename is set. filename_from_src can't be true")
+		return
+	}
+	p.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath
+
+	// If soc install dir was specified and SOC specific is set, set the installDirPath to the specified
+	// socInstallDirBase.
+	installBaseDir := p.installDirBase
+	if ctx.SocSpecific() && p.socInstallDirBase != "" {
+		installBaseDir = p.socInstallDirBase
+	}
+	p.installDirPath = android.PathForModuleInstall(ctx, installBaseDir, proptools.String(p.properties.Sub_dir))
+
+	// This ensures that outputFilePath has the correct name for others to
+	// use, as the source file may have a different name.
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   android.Cp,
+		Output: p.outputFilePath,
+		Input:  p.sourceFilePath,
+	})
+}
+
+func (p *PrebuiltEtc) AndroidMkEntries() []android.AndroidMkEntries {
+	nameSuffix := ""
+	if p.inRamdisk() && !p.onlyInRamdisk() {
+		nameSuffix = ".ramdisk"
+	}
+	if p.inRecovery() && !p.onlyInRecovery() {
+		nameSuffix = ".recovery"
+	}
+	return []android.AndroidMkEntries{android.AndroidMkEntries{
+		Class:      "ETC",
+		SubName:    nameSuffix,
+		OutputFile: android.OptionalPathForPath(p.outputFilePath),
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(entries *android.AndroidMkEntries) {
+				entries.SetString("LOCAL_MODULE_TAGS", "optional")
+				entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.ToMakePath().String())
+				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base())
+				if len(p.properties.Symlinks) > 0 {
+					entries.AddStrings("LOCAL_MODULE_SYMLINKS", p.properties.Symlinks...)
+				}
+				entries.SetString("LOCAL_UNINSTALLABLE_MODULE", strconv.FormatBool(!p.Installable()))
+				if p.additionalDependencies != nil {
+					for _, path := range *p.additionalDependencies {
+						entries.AddStrings("LOCAL_ADDITIONAL_DEPENDENCIES", path.String())
+					}
+				}
+			},
+		},
+	}}
+}
+
+func InitPrebuiltEtcModule(p *PrebuiltEtc, dirBase string) {
+	p.installDirBase = dirBase
+	p.AddProperties(&p.properties)
+}
+
+// prebuilt_etc is for a prebuilt artifact that is installed in
+// <partition>/etc/<sub_dir> directory.
+func PrebuiltEtcFactory() android.Module {
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "etc")
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+	return module
+}
+
+// prebuilt_etc_host is for a host prebuilt artifact that is installed in
+// $(HOST_OUT)/etc/<sub_dir> directory.
+func PrebuiltEtcHostFactory() android.Module {
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "etc")
+	// This module is host-only
+	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon)
+	return module
+}
+
+// prebuilt_usr_share is for a prebuilt artifact that is installed in
+// <partition>/usr/share/<sub_dir> directory.
+func PrebuiltUserShareFactory() android.Module {
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "usr/share")
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+	return module
+}
+
+// prebuild_usr_share_host is for a host prebuilt artifact that is installed in
+// $(HOST_OUT)/usr/share/<sub_dir> directory.
+func PrebuiltUserShareHostFactory() android.Module {
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "usr/share")
+	// This module is host-only
+	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon)
+	return module
+}
+
+// prebuilt_font installs a font in <partition>/fonts directory.
+func PrebuiltFontFactory() android.Module {
+	module := &PrebuiltEtc{}
+	InitPrebuiltEtcModule(module, "fonts")
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+	return module
+}
+
+// prebuilt_firmware installs a firmware file to <partition>/etc/firmware directory for system image.
+// If soc_specific property is set to true, the firmware file is installed to the vendor <partition>/firmware
+// directory for vendor image.
+func PrebuiltFirmwareFactory() android.Module {
+	module := &PrebuiltEtc{}
+	module.socInstallDirBase = "firmware"
+	InitPrebuiltEtcModule(module, "etc/firmware")
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+	return module
+}
+
+// prebuilt_dsp installs a DSP related file to <partition>/etc/dsp directory for system image.
+// If soc_specific property is set to true, the DSP related file is installed to the vendor <partition>/dsp
+// directory for vendor image.
+func PrebuiltDSPFactory() android.Module {
+	module := &PrebuiltEtc{}
+	module.socInstallDirBase = "dsp"
+	InitPrebuiltEtcModule(module, "etc/dsp")
+	// This module is device-only
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+	return module
+}
diff --git a/android/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go
similarity index 78%
rename from android/prebuilt_etc_test.go
rename to etc/prebuilt_etc_test.go
index 6e751e7..4ce1984 100644
--- a/android/prebuilt_etc_test.go
+++ b/etc/prebuilt_etc_test.go
@@ -12,35 +12,65 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package android
+package etc
 
 import (
+	"io/ioutil"
+	"os"
 	"path/filepath"
 	"reflect"
 	"testing"
+
+	"android/soong/android"
 )
 
-func testPrebuiltEtc(t *testing.T, bp string) (*TestContext, Config) {
+var buildDir string
+
+func setUp() {
+	var err error
+	buildDir, err = ioutil.TempDir("", "soong_etc_test")
+	if err != nil {
+		panic(err)
+	}
+}
+
+func tearDown() {
+	os.RemoveAll(buildDir)
+}
+
+func TestMain(m *testing.M) {
+	run := func() int {
+		setUp()
+		defer tearDown()
+
+		return m.Run()
+	}
+
+	os.Exit(run())
+}
+
+func testPrebuiltEtc(t *testing.T, bp string) (*android.TestContext, android.Config) {
 	fs := map[string][]byte{
 		"foo.conf": nil,
 		"bar.conf": nil,
 		"baz.conf": nil,
 	}
 
-	config := TestArchConfig(buildDir, nil, bp, fs)
+	config := android.TestArchConfig(buildDir, nil, bp, fs)
 
-	ctx := NewTestArchContext()
+	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("prebuilt_etc", PrebuiltEtcFactory)
 	ctx.RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory)
 	ctx.RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory)
 	ctx.RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory)
 	ctx.RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
 	ctx.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
+	ctx.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory)
 	ctx.Register(config)
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
-	FailIfErrored(t, errs)
+	android.FailIfErrored(t, errs)
 	_, errs = ctx.PrepareBuildActions(config)
-	FailIfErrored(t, errs)
+	android.FailIfErrored(t, errs)
 
 	return ctx, config
 }
@@ -142,7 +172,7 @@
 	}
 
 	mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*PrebuiltEtc)
-	entries := AndroidMkEntriesForTest(t, config, "", mod)[0]
+	entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0]
 	for k, expectedValue := range expected {
 		if value, ok := entries.EntryMap[k]; ok {
 			if !reflect.DeepEqual(value, expectedValue) {
@@ -162,7 +192,7 @@
 		}
 	`)
 
-	buildOS := BuildOs.String()
+	buildOS := android.BuildOs.String()
 	p := ctx.ModuleForTests("foo.conf", buildOS+"_common").Module().(*PrebuiltEtc)
 	if !p.Host() {
 		t.Errorf("host bit is not set for a prebuilt_etc_host module.")
@@ -194,7 +224,7 @@
 		}
 	`)
 
-	buildOS := BuildOs.String()
+	buildOS := android.BuildOs.String()
 	p := ctx.ModuleForTests("foo.conf", buildOS+"_common").Module().(*PrebuiltEtc)
 	expected := filepath.Join(buildDir, "host", config.PrebuiltOS(), "usr", "share", "bar")
 	if p.installDirPath.String() != expected {
@@ -252,3 +282,39 @@
 		})
 	}
 }
+
+func TestPrebuiltDSPDirPath(t *testing.T) {
+	targetPath := filepath.Join(buildDir, "/target/product/test_device")
+	tests := []struct {
+		description  string
+		config       string
+		expectedPath string
+	}{{
+		description: "prebuilt: system dsp",
+		config: `
+			prebuilt_dsp {
+				name: "foo.conf",
+				src: "foo.conf",
+			}`,
+		expectedPath: filepath.Join(targetPath, "system/etc/dsp"),
+	}, {
+		description: "prebuilt: vendor dsp",
+		config: `
+			prebuilt_dsp {
+				name: "foo.conf",
+				src: "foo.conf",
+				soc_specific: true,
+				sub_dir: "sub_dir",
+			}`,
+		expectedPath: filepath.Join(targetPath, "vendor/dsp/sub_dir"),
+	}}
+	for _, tt := range tests {
+		t.Run(tt.description, func(t *testing.T) {
+			ctx, _ := testPrebuiltEtc(t, tt.config)
+			p := ctx.ModuleForTests("foo.conf", "android_arm64_armv8-a").Module().(*PrebuiltEtc)
+			if p.installDirPath.String() != tt.expectedPath {
+				t.Errorf("expected %q, got %q", tt.expectedPath, p.installDirPath)
+			}
+		})
+	}
+}
diff --git a/genrule/Android.bp b/genrule/Android.bp
new file mode 100644
index 0000000..ff543a6
--- /dev/null
+++ b/genrule/Android.bp
@@ -0,0 +1,18 @@
+bootstrap_go_package {
+    name: "soong-genrule",
+    pkgPath: "android/soong/genrule",
+    deps: [
+        "blueprint",
+        "blueprint-pathtools",
+        "soong",
+        "soong-android",
+        "soong-shared",
+    ],
+    srcs: [
+        "genrule.go",
+    ],
+    testSrcs: [
+        "genrule_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/java/Android.bp b/java/Android.bp
new file mode 100644
index 0000000..1fda7f7
--- /dev/null
+++ b/java/Android.bp
@@ -0,0 +1,67 @@
+bootstrap_go_package {
+    name: "soong-java",
+    pkgPath: "android/soong/java",
+    deps: [
+        "blueprint",
+        "blueprint-pathtools",
+        "soong",
+        "soong-android",
+        "soong-cc",
+        "soong-dexpreopt",
+        "soong-genrule",
+        "soong-java-config",
+        "soong-remoteexec",
+        "soong-tradefed",
+    ],
+    srcs: [
+        "aapt2.go",
+        "aar.go",
+        "android_manifest.go",
+        "android_resources.go",
+        "androidmk.go",
+        "app_builder.go",
+        "app.go",
+        "builder.go",
+        "device_host_converter.go",
+        "dex.go",
+        "dexpreopt.go",
+        "dexpreopt_bootjars.go",
+        "dexpreopt_config.go",
+        "droiddoc.go",
+        "gen.go",
+        "genrule.go",
+        "hiddenapi.go",
+        "hiddenapi_singleton.go",
+        "jacoco.go",
+        "java.go",
+        "jdeps.go",
+        "java_resources.go",
+        "kotlin.go",
+        "lint.go",
+        "platform_compat_config.go",
+        "plugin.go",
+        "prebuilt_apis.go",
+        "proto.go",
+        "robolectric.go",
+        "sdk.go",
+        "sdk_library.go",
+        "support_libraries.go",
+        "sysprop.go",
+        "system_modules.go",
+        "testing.go",
+        "tradefed.go",
+    ],
+    testSrcs: [
+        "androidmk_test.go",
+        "app_test.go",
+        "device_host_converter_test.go",
+        "dexpreopt_test.go",
+        "dexpreopt_bootjars_test.go",
+        "java_test.go",
+        "jdeps_test.go",
+        "kotlin_test.go",
+        "plugin_test.go",
+        "sdk_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/java/aar.go b/java/aar.go
index c8daf83..074ead4 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -102,6 +102,7 @@
 	sdkLibraries            []string
 	hasNoCode               bool
 	LoggingParent           string
+	resourceFiles           android.Paths
 
 	splitNames []string
 	splits     []split
@@ -275,6 +276,7 @@
 
 	var compiledResDirs []android.Paths
 	for _, dir := range resDirs {
+		a.resourceFiles = append(a.resourceFiles, dir.files...)
 		compiledResDirs = append(compiledResDirs, aapt2Compile(ctx, dir.dir, dir.files, compileFlags).Paths())
 	}
 
@@ -473,6 +475,10 @@
 	// apps manifests are handled by aapt, don't let Module see them
 	a.properties.Manifest = nil
 
+	a.linter.mergedManifest = a.aapt.mergedManifestFile
+	a.linter.manifest = a.aapt.manifestPath
+	a.linter.resources = a.aapt.resourceFiles
+
 	a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles,
 		a.proguardOptionsFile)
 
@@ -506,15 +512,13 @@
 func AndroidLibraryFactory() android.Module {
 	module := &AndroidLibrary{}
 
+	module.Module.addHostAndDeviceProperties()
 	module.AddProperties(
-		&module.Module.properties,
-		&module.Module.deviceProperties,
-		&module.Module.dexpreoptProperties,
-		&module.Module.protoProperties,
 		&module.aaptProperties,
 		&module.androidLibraryProperties)
 
 	module.androidLibraryProperties.BuildAAR = true
+	module.Module.linter.library = true
 
 	android.InitApexModule(module)
 	InitJavaModule(module, android.DeviceSupported)
@@ -730,7 +734,11 @@
 	return android.Paths{a.classpathFile}
 }
 
-func (a *AARImport) DexJar() android.Path {
+func (a *AARImport) DexJarBuildPath() android.Path {
+	return nil
+}
+
+func (a *AARImport) DexJarInstallPath() android.Path {
 	return nil
 }
 
diff --git a/java/app.go b/java/app.go
index a45ab6f..4bb292d 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,11 +129,11 @@
 }
 
 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.
-	as.masterFile = ctx.ModuleName() + ".apk"
+	as.masterFile = as.BaseModuleName() + ".apk"
 	screenDensities := "all"
 	if dpis := ctx.Config().ProductAAPTPrebuiltDPI(); len(dpis) > 0 {
 		screenDensities = strings.ToUpper(strings.Join(dpis, ","))
@@ -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
@@ -688,9 +691,9 @@
 		systemCertPath := ctx.Config().DefaultAppCertificateDir(ctx).String()
 		if strings.HasPrefix(certPath, systemCertPath) {
 			enforceSystemCert := ctx.Config().EnforceSystemCertificate()
-			whitelist := ctx.Config().EnforceSystemCertificateWhitelist()
+			allowed := ctx.Config().EnforceSystemCertificateAllowList()
 
-			if enforceSystemCert && !inList(m.Name(), whitelist) {
+			if enforceSystemCert && !inList(m.Name(), allowed) {
 				ctx.PropertyErrorf("certificate", "The module in product partition cannot be signed with certificate in system.")
 			}
 		}
@@ -739,6 +742,10 @@
 
 	a.proguardBuildActions(ctx)
 
+	a.linter.mergedManifest = a.aapt.mergedManifestFile
+	a.linter.manifest = a.aapt.manifestPath
+	a.linter.resources = a.aapt.resourceFiles
+
 	dexJarFile := a.dexBuildActions(ctx)
 
 	jniLibs, certificateDeps := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis))
@@ -960,20 +967,13 @@
 	module.Module.properties.Instrument = true
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 
+	module.addHostAndDeviceProperties()
 	module.AddProperties(
-		&module.Module.properties,
-		&module.Module.deviceProperties,
-		&module.Module.dexpreoptProperties,
-		&module.Module.protoProperties,
 		&module.aaptProperties,
 		&module.appProperties,
 		&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)
@@ -1083,12 +1083,10 @@
 	module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
 	module.appProperties.AlwaysPackageNativeLibs = true
 	module.Module.dexpreopter.isTest = true
+	module.Module.linter.test = true
 
+	module.addHostAndDeviceProperties()
 	module.AddProperties(
-		&module.Module.properties,
-		&module.Module.deviceProperties,
-		&module.Module.dexpreoptProperties,
-		&module.Module.protoProperties,
 		&module.aaptProperties,
 		&module.appProperties,
 		&module.appTestProperties,
@@ -1135,12 +1133,10 @@
 	module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true)
 	module.appProperties.AlwaysPackageNativeLibs = true
 	module.Module.dexpreopter.isTest = true
+	module.Module.linter.test = true
 
+	module.addHostAndDeviceProperties()
 	module.AddProperties(
-		&module.Module.properties,
-		&module.Module.deviceProperties,
-		&module.Module.dexpreoptProperties,
-		&module.Module.protoProperties,
 		&module.aaptProperties,
 		&module.appProperties,
 		&module.appTestHelperAppProperties,
@@ -1186,7 +1182,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 +1203,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 +1225,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 +1470,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 +1490,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 +1548,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 +1871,36 @@
 	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
-				} 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))
+				buildPath := lib.DexJarBuildPath()
+				if buildPath == nil {
+					ctx.ModuleErrorf("module %q in uses_libs or optional_uses_libs must"+
+						" produce a dex jar, does it have installable: true?", dep)
+					return
 				}
+
+				var devicePath string
+				installPath := lib.DexJarInstallPath()
+				if installPath == nil {
+					devicePath = filepath.Join("/system/framework", dep+".jar")
+				} else {
+					devicePath = android.InstallPathToOnDevicePath(ctx, installPath.(android.InstallPath))
+				}
+
+				usesLibPaths[dep] = &dexpreopt.LibraryPath{buildPath, devicePath}
 			} 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..e45ba70 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 {
@@ -2657,7 +2657,7 @@
 }
 
 func TestEmbedNotice(t *testing.T) {
-	ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
+	ctx, _ := testJavaWithFS(t, cc.GatherRequiredDepsForTest(android.Android)+`
 		android_app {
 			name: "foo",
 			srcs: ["a.java"],
@@ -2713,7 +2713,12 @@
 			srcs: ["b.java"],
 			notice: "TOOL_NOTICE",
 		}
-	`)
+	`, map[string][]byte{
+		"APP_NOTICE":     nil,
+		"GENRULE_NOTICE": nil,
+		"LIB_NOTICE":     nil,
+		"TOOL_NOTICE":    nil,
+	})
 
 	// foo has NOTICE files to process, and embed_notices is true.
 	foo := ctx.ModuleForTests("foo", "android_common")
diff --git a/java/config/Android.bp b/java/config/Android.bp
new file mode 100644
index 0000000..1983521
--- /dev/null
+++ b/java/config/Android.bp
@@ -0,0 +1,15 @@
+bootstrap_go_package {
+    name: "soong-java-config",
+    pkgPath: "android/soong/java/config",
+    deps: [
+        "blueprint-proptools",
+        "soong-android",
+        "soong-remoteexec",
+    ],
+    srcs: [
+        "config.go",
+        "error_prone.go",
+        "kotlin.go",
+        "makevars.go",
+    ],
+}
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..9191a83 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -51,7 +51,7 @@
 // java_device_for_host makes the classes.jar output of a device java_library module available to host
 // java_library modules.
 //
-// It is rarely necessary, and its usage is restricted to a few whitelisted projects.
+// It is rarely necessary, and its usage is restricted to a few allowed projects.
 func DeviceForHostFactory() android.Module {
 	module := &DeviceForHost{}
 
@@ -68,7 +68,7 @@
 // java_host_for_device makes the classes.jar output of a host java_library module available to device
 // java_library modules.
 //
-// It is rarely necessary, and its usage is restricted to a few whitelisted projects.
+// It is rarely necessary, and its usage is restricted to a few allowed projects.
 func HostForDeviceFactory() android.Module {
 	module := &HostForDevice{}
 
@@ -150,7 +150,11 @@
 	return d.implementationAndResourceJars
 }
 
-func (d *DeviceHostConverter) DexJar() android.Path {
+func (d *DeviceHostConverter) DexJarBuildPath() android.Path {
+	return nil
+}
+
+func (d *DeviceHostConverter) DexJarInstallPath() android.Path {
 	return nil
 }
 
diff --git a/java/dexpreopt.go b/java/dexpreopt.go
index 4725b07..7f1afd6 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
 }
@@ -77,10 +77,6 @@
 		return true
 	}
 
-	if ctx.Config().UnbundledBuild() {
-		return true
-	}
-
 	if d.isTest {
 		return true
 	}
@@ -197,10 +193,10 @@
 		ProfileIsTextListing: profileIsTextListing,
 		ProfileBootListing:   profileBootListing,
 
-		EnforceUsesLibraries:         d.enforceUsesLibs,
-		PresentOptionalUsesLibraries: d.optionalUsesLibs,
-		UsesLibraries:                d.usesLibs,
-		LibraryPaths:                 d.libraryPaths,
+		EnforceUsesLibraries:  d.enforceUsesLibs,
+		OptionalUsesLibraries: d.optionalUsesLibs,
+		UsesLibraries:         d.usesLibs,
+		LibraryPaths:          d.libraryPaths,
 
 		Archs:                   archs,
 		DexPreoptImages:         images,
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index ed61d4b..4120559 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -179,15 +179,7 @@
 }
 
 func skipDexpreoptBootJars(ctx android.PathContext) bool {
-	if dexpreopt.GetGlobalConfig(ctx).DisablePreopt {
-		return true
-	}
-
-	if ctx.Config().UnbundledBuild() {
-		return true
-	}
-
-	return false
+	return dexpreopt.GetGlobalConfig(ctx).DisablePreopt
 }
 
 type dexpreoptBootJars struct {
@@ -255,7 +247,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 +288,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.
@@ -340,10 +332,12 @@
 	bootFrameworkProfileRule(ctx, image, missingDeps)
 	updatableBcpPackagesRule(ctx, image, missingDeps)
 
-	var allFiles android.Paths
+	var zipFiles android.Paths
 	for _, variant := range image.variants {
 		files := buildBootImageVariant(ctx, variant, profile, missingDeps)
-		allFiles = append(allFiles, files.Paths()...)
+		if variant.target.Os == android.Android {
+			zipFiles = append(zipFiles, files.Paths()...)
+		}
 	}
 
 	if image.zip != nil {
@@ -351,8 +345,8 @@
 		rule.Command().
 			BuiltTool(ctx, "soong_zip").
 			FlagWithOutput("-o ", image.zip).
-			FlagWithArg("-C ", image.dir.String()).
-			FlagWithInputList("-f ", allFiles, " -f ")
+			FlagWithArg("-C ", image.dir.Join(ctx, android.Android.String()).String()).
+			FlagWithInputList("-f ", zipFiles, " -f ")
 
 		rule.Build(pctx, ctx, "zip_"+image.name, "zip "+image.name+" image")
 	}
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index e9704dc..9670c7f 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -118,7 +118,7 @@
 
 	ctx := android.PathContextForTesting(testConfig(nil, "", nil))
 	expectedInputs := []string{}
-	for _, target := range dexpreoptTargets(ctx) {
+	for _, target := range ctx.Config().Targets[android.Android] {
 		for _, ext := range []string{".art", ".oat", ".vdex"} {
 			for _, jar := range []string{"foo", "bar", "baz"} {
 				expectedInputs = append(expectedInputs,
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 3eab841..5cb70e4 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -1224,6 +1224,21 @@
 	return module
 }
 
+func (d *Droidstubs) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "":
+		return android.Paths{d.stubsSrcJar}, nil
+	case ".docs.zip":
+		return android.Paths{d.docZip}, nil
+	case ".annotations.zip":
+		return android.Paths{d.annotationsZip}, nil
+	case ".api_versions.xml":
+		return android.Paths{d.apiVersionsXml}, nil
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+	}
+}
+
 func (d *Droidstubs) ApiFilePath() android.Path {
 	return d.apiFilePath
 }
@@ -1335,13 +1350,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").
@@ -1428,10 +1440,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
@@ -1458,10 +1469,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()))
@@ -1472,7 +1483,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 != nil {
+		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 76bfa86..97a6747 100644
--- a/java/java.go
+++ b/java/java.go
@@ -471,6 +471,7 @@
 
 	hiddenAPI
 	dexpreopter
+	linter
 
 	// list of the xref extraction files
 	kytheFiles android.Paths
@@ -481,6 +482,22 @@
 	modulePaths []string
 }
 
+func (j *Module) addHostProperties() {
+	j.AddProperties(
+		&j.properties,
+		&j.protoProperties,
+	)
+}
+
+func (j *Module) addHostAndDeviceProperties() {
+	j.addHostProperties()
+	j.AddProperties(
+		&j.deviceProperties,
+		&j.dexpreoptProperties,
+		&j.linter.properties,
+	)
+}
+
 func (j *Module) OutputFiles(tag string) (android.Paths, error) {
 	switch tag {
 	case "":
@@ -496,12 +513,18 @@
 
 var _ android.OutputFileProducer = (*Module)(nil)
 
-type Dependency interface {
+// Methods that need to be implemented for a module that is added to apex java_libs property.
+type ApexDependency interface {
 	HeaderJars() android.Paths
+	ImplementationAndResourcesJars() android.Paths
+}
+
+type Dependency interface {
+	ApexDependency
 	ImplementationJars() android.Paths
 	ResourceJars() android.Paths
-	ImplementationAndResourcesJars() android.Paths
-	DexJar() android.Path
+	DexJarBuildPath() android.Path
+	DexJarInstallPath() android.Path
 	AidlIncludeDirs() android.Paths
 	ExportedSdkLibs() []string
 	ExportedPlugins() (android.Paths, []string)
@@ -600,7 +623,9 @@
 }
 
 func (j *Module) shouldInstrument(ctx android.BaseModuleContext) bool {
-	return j.properties.Instrument && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT")
+	return j.properties.Instrument &&
+		ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") &&
+		ctx.DeviceConfig().JavaCoverageEnabledForPath(ctx.ModuleDir())
 }
 
 func (j *Module) shouldInstrumentStatic(ctx android.BaseModuleContext) bool {
@@ -609,6 +634,21 @@
 			ctx.Config().UnbundledBuild())
 }
 
+func (j *Module) shouldInstrumentInApex(ctx android.BaseModuleContext) bool {
+	// Force enable the instrumentation for java code that is built for APEXes ...
+	// except for the jacocoagent itself (because instrumenting jacocoagent using jacocoagent
+	// doesn't make sense) or framework libraries (e.g. libraries found in the InstrumentFrameworkModules list) unless EMMA_INSTRUMENT_FRAMEWORK is true.
+	isJacocoAgent := ctx.ModuleName() == "jacocoagent"
+	if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && !isJacocoAgent && !j.IsForPlatform() {
+		if !inList(ctx.ModuleName(), config.InstrumentFrameworkModules) {
+			return true
+		} else if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
+			return true
+		}
+	}
+	return false
+}
+
 func (j *Module) sdkVersion() sdkSpec {
 	return sdkSpecFrom(String(j.deviceProperties.Sdk_version))
 }
@@ -836,41 +876,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) {
@@ -1143,9 +1189,9 @@
 	if flags.javaVersion.usesJavaModules() {
 		javacFlags = append(javacFlags, j.properties.Openjdk9.Javacflags...)
 	}
-	if ctx.Config().MinimizeJavaDebugInfo() {
-		// Override the -g flag passed globally to remove local variable debug info to reduce
-		// disk and memory usage.
+	if ctx.Config().MinimizeJavaDebugInfo() && !ctx.Host() {
+		// For non-host binaries, override the -g flag passed globally to remove
+		// local variable debug info to reduce disk and memory usage.
 		javacFlags = append(javacFlags, "-g:source,lines")
 	}
 	javacFlags = append(javacFlags, "-Xlint:-dep-ann")
@@ -1536,11 +1582,7 @@
 		j.headerJarFile = j.implementationJarFile
 	}
 
-	// Force enable the instrumentation for java code that is built for APEXes ...
-	// except for the jacocoagent itself (because instrumenting jacocoagent using jacocoagent
-	// doesn't make sense)
-	isJacocoAgent := ctx.ModuleName() == "jacocoagent"
-	if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && !isJacocoAgent && !j.IsForPlatform() {
+	if j.shouldInstrumentInApex(ctx) {
 		j.properties.Instrument = true
 	}
 
@@ -1614,6 +1656,28 @@
 		outputFile = implementationAndResourcesJar
 	}
 
+	if ctx.Device() {
+		lintSDKVersionString := func(sdkSpec sdkSpec) string {
+			if v := sdkSpec.version; v.isNumbered() {
+				return v.String()
+			} else {
+				return ctx.Config().DefaultAppTargetSdk()
+			}
+		}
+
+		j.linter.name = ctx.ModuleName()
+		j.linter.srcs = srcFiles
+		j.linter.srcJars = srcJars
+		j.linter.classpath = append(append(android.Paths(nil), flags.bootClasspath...), flags.classpath...)
+		j.linter.classes = j.implementationJarFile
+		j.linter.minSdkVersion = lintSDKVersionString(j.minSdkVersion())
+		j.linter.targetSdkVersion = lintSDKVersionString(j.targetSdkVersion())
+		j.linter.compileSdkVersion = lintSDKVersionString(j.sdkVersion())
+		j.linter.javaLanguageLevel = flags.javaVersion.String()
+		j.linter.kotlinLanguageLevel = "1.3"
+		j.linter.lint(ctx)
+	}
+
 	ctx.CheckbuildFile(outputFile)
 
 	// Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource
@@ -1739,10 +1803,14 @@
 	return android.Paths{j.implementationJarFile}
 }
 
-func (j *Module) DexJar() android.Path {
+func (j *Module) DexJarBuildPath() android.Path {
 	return j.dexJarFile
 }
 
+func (j *Module) DexJarInstallPath() android.Path {
+	return j.installFile
+}
+
 func (j *Module) ResourceJars() android.Paths {
 	if j.resourceJar == nil {
 		return nil
@@ -2022,12 +2090,8 @@
 func LibraryFactory() android.Module {
 	module := &Library{}
 
-	module.AddProperties(
-		&module.Module.properties,
-		&module.Module.deviceProperties,
-		&module.Module.dexpreoptProperties,
-		&module.Module.protoProperties,
-		&module.libraryProperties)
+	module.addHostAndDeviceProperties()
+	module.AddProperties(&module.libraryProperties)
 
 	module.initModuleAndImport(&module.ModuleBase)
 
@@ -2049,9 +2113,7 @@
 func LibraryHostFactory() android.Module {
 	module := &Library{}
 
-	module.AddProperties(
-		&module.Module.properties,
-		&module.Module.protoProperties)
+	module.addHostProperties()
 
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 
@@ -2219,15 +2281,12 @@
 func TestFactory() android.Module {
 	module := &Test{}
 
-	module.AddProperties(
-		&module.Module.properties,
-		&module.Module.deviceProperties,
-		&module.Module.dexpreoptProperties,
-		&module.Module.protoProperties,
-		&module.testProperties)
+	module.addHostAndDeviceProperties()
+	module.AddProperties(&module.testProperties)
 
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 	module.Module.dexpreopter.isTest = true
+	module.Module.linter.test = true
 
 	InitJavaModule(module, android.HostAndDeviceSupported)
 	return module
@@ -2237,15 +2296,12 @@
 func TestHelperLibraryFactory() android.Module {
 	module := &TestHelperLibrary{}
 
-	module.AddProperties(
-		&module.Module.properties,
-		&module.Module.deviceProperties,
-		&module.Module.dexpreoptProperties,
-		&module.Module.protoProperties,
-		&module.testHelperLibraryProperties)
+	module.addHostAndDeviceProperties()
+	module.AddProperties(&module.testHelperLibraryProperties)
 
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 	module.Module.dexpreopter.isTest = true
+	module.Module.linter.test = true
 
 	InitJavaModule(module, android.HostAndDeviceSupported)
 	return module
@@ -2283,10 +2339,8 @@
 func TestHostFactory() android.Module {
 	module := &Test{}
 
-	module.AddProperties(
-		&module.Module.properties,
-		&module.Module.protoProperties,
-		&module.testProperties)
+	module.addHostProperties()
+	module.AddProperties(&module.testProperties)
 
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 
@@ -2370,12 +2424,8 @@
 func BinaryFactory() android.Module {
 	module := &Binary{}
 
-	module.AddProperties(
-		&module.Module.properties,
-		&module.Module.deviceProperties,
-		&module.Module.dexpreoptProperties,
-		&module.Module.protoProperties,
-		&module.binaryProperties)
+	module.addHostAndDeviceProperties()
+	module.AddProperties(&module.binaryProperties)
 
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 
@@ -2391,10 +2441,8 @@
 func BinaryHostFactory() android.Module {
 	module := &Binary{}
 
-	module.AddProperties(
-		&module.Module.properties,
-		&module.Module.protoProperties,
-		&module.binaryProperties)
+	module.addHostProperties()
+	module.AddProperties(&module.binaryProperties)
 
 	module.Module.properties.Installable = proptools.BoolPtr(true)
 
@@ -2565,7 +2613,11 @@
 	return android.Paths{j.combinedClasspathFile}
 }
 
-func (j *Import) DexJar() android.Path {
+func (j *Import) DexJarBuildPath() android.Path {
+	return nil
+}
+
+func (j *Import) DexJarInstallPath() android.Path {
 	return nil
 }
 
@@ -2691,6 +2743,10 @@
 	return proptools.StringDefault(j.properties.Stem, j.ModuleBase.Name())
 }
 
+func (a *DexImport) JacocoReportClassesFile() android.Path {
+	return nil
+}
+
 func (j *DexImport) IsInstallable() bool {
 	return true
 }
@@ -2744,11 +2800,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
 }
 
@@ -2831,6 +2889,7 @@
 		&DexImportProperties{},
 		&android.ApexProperties{},
 		&RuntimeResourceOverlayProperties{},
+		&LintProperties{},
 	)
 
 	android.InitDefaultsModule(module)
@@ -2853,11 +2912,7 @@
 	})
 	// TODO(asmundak): perhaps emit a rule to output a warning if there were no xrefTargets
 	if len(xrefTargets) > 0 {
-		ctx.Build(pctx, android.BuildParams{
-			Rule:   blueprint.Phony,
-			Output: android.PathForPhony(ctx, "xref_java"),
-			Inputs: xrefTargets,
-		})
+		ctx.Phony("xref_java", xrefTargets...)
 	}
 }
 
diff --git a/java/java_test.go b/java/java_test.go
index 8ea34d9..1d07e70 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -142,9 +142,14 @@
 	return ctx, config
 }
 
+func testJavaWithFS(t *testing.T, bp string, fs map[string][]byte) (*android.TestContext, android.Config) {
+	t.Helper()
+	return testJavaWithConfig(t, testConfig(nil, bp, fs))
+}
+
 func testJava(t *testing.T, bp string) (*android.TestContext, android.Config) {
 	t.Helper()
-	return testJavaWithConfig(t, testConfig(nil, bp, nil))
+	return testJavaWithFS(t, bp, nil)
 }
 
 func testJavaWithConfig(t *testing.T, config android.Config) (*android.TestContext, android.Config) {
@@ -461,7 +466,41 @@
 		t.Errorf("expected binary wrapper implicits [%q], got %v",
 			barJar, barWrapperDeps)
 	}
+}
 
+func TestHostBinaryNoJavaDebugInfoOverride(t *testing.T) {
+	bp := `
+		java_library {
+			name: "target_library",
+			srcs: ["a.java"],
+		}
+
+		java_binary_host {
+			name: "host_binary",
+			srcs: ["b.java"],
+		}
+	`
+	config := testConfig(nil, bp, nil)
+	config.TestProductVariables.MinimizeJavaDebugInfo = proptools.BoolPtr(true)
+
+	ctx, _ := testJavaWithConfig(t, config)
+
+	// first, sanity check that the -g flag is added to target modules
+	targetLibrary := ctx.ModuleForTests("target_library", "android_common")
+	targetJavaFlags := targetLibrary.Module().VariablesForTests()["javacFlags"]
+	if !strings.Contains(targetJavaFlags, "-g:source,lines") {
+		t.Errorf("target library javac flags %v should contain "+
+			"-g:source,lines override with MinimizeJavaDebugInfo", targetJavaFlags)
+	}
+
+	// check that -g is not overridden for host modules
+	buildOS := android.BuildOs.String()
+	hostBinary := ctx.ModuleForTests("host_binary", buildOS+"_common")
+	hostJavaFlags := hostBinary.Module().VariablesForTests()["javacFlags"]
+	if strings.Contains(hostJavaFlags, "-g:source,lines") {
+		t.Errorf("java_binary_host javac flags %v should not have "+
+			"-g:source,lines override with MinimizeJavaDebugInfo", hostJavaFlags)
+	}
 }
 
 func TestPrebuilts(t *testing.T) {
@@ -740,7 +779,7 @@
 
 	for _, test := range table {
 		t.Run(test.name, func(t *testing.T) {
-			ctx, _ := testJava(t, `
+			ctx, _ := testJavaWithFS(t, `
 				java_library {
 					name: "foo",
 					srcs: [
@@ -750,7 +789,13 @@
 					],
 					`+test.prop+`,
 				}
-			`+test.extra)
+			`+test.extra,
+				map[string][]byte{
+					"java-res/a/a": nil,
+					"java-res/b/b": nil,
+					"java-res2/a":  nil,
+				},
+			)
 
 			foo := ctx.ModuleForTests("foo", "android_common").Output("withres/foo.jar")
 			fooRes := ctx.ModuleForTests("foo", "android_common").Output("res/foo.jar")
@@ -769,7 +814,7 @@
 }
 
 func TestIncludeSrcs(t *testing.T) {
-	ctx, _ := testJava(t, `
+	ctx, _ := testJavaWithFS(t, `
 		java_library {
 			name: "foo",
 			srcs: [
@@ -790,7 +835,11 @@
 			java_resource_dirs: ["java-res"],
 			include_srcs: true,
 		}
-	`)
+	`, map[string][]byte{
+		"java-res/a/a": nil,
+		"java-res/b/b": nil,
+		"java-res2/a":  nil,
+	})
 
 	// Test a library with include_srcs: true
 	foo := ctx.ModuleForTests("foo", "android_common").Output("withres/foo.jar")
@@ -832,7 +881,7 @@
 }
 
 func TestGeneratedSources(t *testing.T) {
-	ctx, _ := testJava(t, `
+	ctx, _ := testJavaWithFS(t, `
 		java_library {
 			name: "foo",
 			srcs: [
@@ -847,7 +896,10 @@
 			tool_files: ["java-res/a"],
 			out: ["gen.java"],
 		}
-	`)
+	`, map[string][]byte{
+		"a.java": nil,
+		"b.java": nil,
+	})
 
 	javac := ctx.ModuleForTests("foo", "android_common").Rule("javac")
 	genrule := ctx.ModuleForTests("gen", "").Rule("generator")
@@ -932,7 +984,7 @@
 }
 
 func TestDroiddoc(t *testing.T) {
-	ctx, _ := testJava(t, `
+	ctx, _ := testJavaWithFS(t, `
 		droiddoc_exported_dir {
 		    name: "droiddoc-templates-sdk",
 		    path: ".",
@@ -945,7 +997,7 @@
 		droiddoc {
 		    name: "bar-doc",
 		    srcs: [
-		        "bar-doc/*.java",
+		        "bar-doc/a.java",
 		        "bar-doc/IFoo.aidl",
 		        ":bar-doc-aidl-srcs",
 		    ],
@@ -963,7 +1015,11 @@
 		    todo_file: "libcore-docs-todo.html",
 		    args: "-offlinemode -title \"libcore\"",
 		}
-		`)
+		`,
+		map[string][]byte{
+			"bar-doc/a.java": nil,
+			"bar-doc/b.java": nil,
+		})
 
 	barDoc := ctx.ModuleForTests("bar-doc", "android_common").Rule("javadoc")
 	var javaSrcs []string
@@ -989,7 +1045,7 @@
 		droidstubs {
 		    name: "stubs-source-system-modules",
 		    srcs: [
-		        "bar-doc/*.java",
+		        "bar-doc/a.java",
 		    ],
 				sdk_version: "none",
 				system_modules: "source-system-modules",
@@ -1010,7 +1066,7 @@
 		droidstubs {
 		    name: "stubs-prebuilt-system-modules",
 		    srcs: [
-		        "bar-doc/*.java",
+		        "bar-doc/a.java",
 		    ],
 				sdk_version: "none",
 				system_modules: "prebuilt-system-modules",
@@ -1426,6 +1482,38 @@
 		`)
 }
 
+func TestJavaSdkLibrary_ModuleLib(t *testing.T) {
+	testJava(t, `
+		java_sdk_library {
+			name: "foo",
+			srcs: ["a.java", "b.java"],
+			api_packages: ["foo"],
+			system: {
+				enabled: true,
+			},
+			module_lib: {
+				enabled: true,
+			},
+		}
+		`)
+}
+
+func TestJavaSdkLibrary_SystemServer(t *testing.T) {
+	testJava(t, `
+		java_sdk_library {
+			name: "foo",
+			srcs: ["a.java", "b.java"],
+			api_packages: ["foo"],
+			system: {
+				enabled: true,
+			},
+			system_server: {
+				enabled: true,
+			},
+		}
+		`)
+}
+
 func TestJavaSdkLibrary_MissingScope(t *testing.T) {
 	testJavaError(t, `requires api scope module-lib from foo but it only has \[\] available`, `
 		java_sdk_library {
diff --git a/java/lint.go b/java/lint.go
new file mode 100644
index 0000000..441e110
--- /dev/null
+++ b/java/lint.go
@@ -0,0 +1,355 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+	"fmt"
+	"sort"
+
+	"android/soong/android"
+)
+
+type LintProperties struct {
+	// Controls for running Android Lint on the module.
+	Lint struct {
+
+		// If true, run Android Lint on the module.  Defaults to true.
+		Enabled *bool
+
+		// Flags to pass to the Android Lint tool.
+		Flags []string
+
+		// Checks that should be treated as fatal.
+		Fatal_checks []string
+
+		// Checks that should be treated as errors.
+		Error_checks []string
+
+		// Checks that should be treated as warnings.
+		Warning_checks []string
+
+		// Checks that should be skipped.
+		Disabled_checks []string
+	}
+}
+
+type linter struct {
+	name                string
+	manifest            android.Path
+	mergedManifest      android.Path
+	srcs                android.Paths
+	srcJars             android.Paths
+	resources           android.Paths
+	classpath           android.Paths
+	classes             android.Path
+	extraLintCheckJars  android.Paths
+	test                bool
+	library             bool
+	minSdkVersion       string
+	targetSdkVersion    string
+	compileSdkVersion   string
+	javaLanguageLevel   string
+	kotlinLanguageLevel string
+	outputs             lintOutputs
+	properties          LintProperties
+}
+
+type lintOutputs struct {
+	html android.ModuleOutPath
+	text android.ModuleOutPath
+	xml  android.ModuleOutPath
+}
+
+func (l *linter) enabled() bool {
+	return BoolDefault(l.properties.Lint.Enabled, true)
+}
+
+func (l *linter) writeLintProjectXML(ctx android.ModuleContext,
+	rule *android.RuleBuilder) (projectXMLPath, configXMLPath, cacheDir android.WritablePath, deps android.Paths) {
+
+	var resourcesList android.WritablePath
+	if len(l.resources) > 0 {
+		// The list of resources may be too long to put on the command line, but
+		// we can't use the rsp file because it is already being used for srcs.
+		// Insert a second rule to write out the list of resources to a file.
+		resourcesList = android.PathForModuleOut(ctx, "lint", "resources.list")
+		resListRule := android.NewRuleBuilder()
+		resListRule.Command().Text("cp").FlagWithRspFileInputList("", l.resources).Output(resourcesList)
+		resListRule.Build(pctx, ctx, "lint_resources_list", "lint resources list")
+		deps = append(deps, l.resources...)
+	}
+
+	projectXMLPath = android.PathForModuleOut(ctx, "lint", "project.xml")
+	// Lint looks for a lint.xml file next to the project.xml file, give it one.
+	configXMLPath = android.PathForModuleOut(ctx, "lint", "lint.xml")
+	cacheDir = android.PathForModuleOut(ctx, "lint", "cache")
+
+	srcJarDir := android.PathForModuleOut(ctx, "lint-srcjars")
+	srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
+
+	cmd := rule.Command().
+		BuiltTool(ctx, "lint-project-xml").
+		FlagWithOutput("--project_out ", projectXMLPath).
+		FlagWithOutput("--config_out ", configXMLPath).
+		FlagWithArg("--name ", ctx.ModuleName())
+
+	if l.library {
+		cmd.Flag("--library")
+	}
+	if l.test {
+		cmd.Flag("--test")
+	}
+	if l.manifest != nil {
+		deps = append(deps, l.manifest)
+		cmd.FlagWithArg("--manifest ", l.manifest.String())
+	}
+	if l.mergedManifest != nil {
+		deps = append(deps, l.mergedManifest)
+		cmd.FlagWithArg("--merged_manifest ", l.mergedManifest.String())
+	}
+
+	// TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
+	// lint separately.
+	cmd.FlagWithRspFileInputList("--srcs ", l.srcs)
+	deps = append(deps, l.srcs...)
+
+	cmd.FlagWithInput("--generated_srcs ", srcJarList)
+	deps = append(deps, l.srcJars...)
+
+	if resourcesList != nil {
+		cmd.FlagWithInput("--resources ", resourcesList)
+	}
+
+	if l.classes != nil {
+		deps = append(deps, l.classes)
+		cmd.FlagWithArg("--classes ", l.classes.String())
+	}
+
+	cmd.FlagForEachArg("--classpath ", l.classpath.Strings())
+	deps = append(deps, l.classpath...)
+
+	cmd.FlagForEachArg("--extra_checks_jar ", l.extraLintCheckJars.Strings())
+	deps = append(deps, l.extraLintCheckJars...)
+
+	// The cache tag in project.xml is relative to the project.xml file.
+	cmd.FlagWithArg("--cache_dir ", "cache")
+
+	cmd.FlagWithInput("@",
+		android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
+
+	cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
+	cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
+	cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
+	cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
+
+	return projectXMLPath, configXMLPath, cacheDir, deps
+}
+
+// generateManifest adds a command to the rule to write a dummy manifest cat contains the
+// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
+func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.Path {
+	manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
+
+	rule.Command().Text("(").
+		Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
+		Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
+		Text(`echo "    android:versionCode='1' android:versionName='1' >" &&`).
+		Textf(`echo "  <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
+			l.minSdkVersion, l.targetSdkVersion).
+		Text(`echo "</manifest>"`).
+		Text(") >").Output(manifestPath)
+
+	return manifestPath
+}
+
+func (l *linter) lint(ctx android.ModuleContext) {
+	if !l.enabled() {
+		return
+	}
+
+	rule := android.NewRuleBuilder()
+
+	if l.manifest == nil {
+		manifest := l.generateManifest(ctx, rule)
+		l.manifest = manifest
+	}
+
+	projectXML, lintXML, cacheDir, deps := l.writeLintProjectXML(ctx, rule)
+
+	l.outputs.html = android.PathForModuleOut(ctx, "lint-report.html")
+	l.outputs.text = android.PathForModuleOut(ctx, "lint-report.txt")
+	l.outputs.xml = android.PathForModuleOut(ctx, "lint-report.xml")
+
+	rule.Command().Text("rm -rf").Flag(cacheDir.String())
+	rule.Command().Text("mkdir -p").Flag(cacheDir.String())
+
+	rule.Command().
+		Text("(").
+		Flag("JAVA_OPTS=-Xmx2048m").
+		FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath(ctx)).
+		FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXmlPath(ctx)).
+		Tool(android.PathForSource(ctx, "prebuilts/cmdline-tools/tools/bin/lint")).
+		Implicit(android.PathForSource(ctx, "prebuilts/cmdline-tools/tools/lib/lint-classpath.jar")).
+		Flag("--quiet").
+		FlagWithInput("--project ", projectXML).
+		FlagWithInput("--config ", lintXML).
+		FlagWithOutput("--html ", l.outputs.html).
+		FlagWithOutput("--text ", l.outputs.text).
+		FlagWithOutput("--xml ", l.outputs.xml).
+		FlagWithArg("--compile-sdk-version ", l.compileSdkVersion).
+		FlagWithArg("--java-language-level ", l.javaLanguageLevel).
+		FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
+		FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
+		Flag("--exitcode").
+		Flags(l.properties.Lint.Flags).
+		Implicits(deps).
+		Text("|| (").Text("cat").Input(l.outputs.text).Text("; exit 7)").
+		Text(")")
+
+	rule.Command().Text("rm -rf").Flag(cacheDir.String())
+
+	rule.Build(pctx, ctx, "lint", "lint")
+}
+
+func (l *linter) lintOutputs() *lintOutputs {
+	return &l.outputs
+}
+
+type lintOutputIntf interface {
+	lintOutputs() *lintOutputs
+}
+
+var _ lintOutputIntf = (*linter)(nil)
+
+type lintSingleton struct {
+	htmlZip android.WritablePath
+	textZip android.WritablePath
+	xmlZip  android.WritablePath
+}
+
+func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	l.generateLintReportZips(ctx)
+	l.copyLintDependencies(ctx)
+}
+
+func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
+	if ctx.Config().UnbundledBuild() {
+		return
+	}
+
+	var frameworkDocStubs android.Module
+	ctx.VisitAllModules(func(m android.Module) {
+		if ctx.ModuleName(m) == "framework-doc-stubs" {
+			if frameworkDocStubs == nil {
+				frameworkDocStubs = m
+			} else {
+				ctx.Errorf("lint: multiple framework-doc-stubs modules found: %s and %s",
+					ctx.ModuleSubDir(m), ctx.ModuleSubDir(frameworkDocStubs))
+			}
+		}
+	})
+
+	if frameworkDocStubs == nil {
+		if !ctx.Config().AllowMissingDependencies() {
+			ctx.Errorf("lint: missing framework-doc-stubs")
+		}
+		return
+	}
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   android.Cp,
+		Input:  android.OutputFileForModule(ctx, frameworkDocStubs, ".annotations.zip"),
+		Output: annotationsZipPath(ctx),
+	})
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   android.Cp,
+		Input:  android.OutputFileForModule(ctx, frameworkDocStubs, ".api_versions.xml"),
+		Output: apiVersionsXmlPath(ctx),
+	})
+}
+
+func annotationsZipPath(ctx android.PathContext) android.WritablePath {
+	return android.PathForOutput(ctx, "lint", "annotations.zip")
+}
+
+func apiVersionsXmlPath(ctx android.PathContext) android.WritablePath {
+	return android.PathForOutput(ctx, "lint", "api_versions.xml")
+}
+
+func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
+	var outputs []*lintOutputs
+	var dirs []string
+	ctx.VisitAllModules(func(m android.Module) {
+		if ctx.Config().EmbeddedInMake() && !m.ExportedToMake() {
+			return
+		}
+
+		if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() && apex.IsForPlatform() {
+			// There are stray platform variants of modules in apexes that are not available for
+			// the platform, and they sometimes can't be built.  Don't depend on them.
+			return
+		}
+
+		if l, ok := m.(lintOutputIntf); ok {
+			outputs = append(outputs, l.lintOutputs())
+		}
+	})
+
+	dirs = android.SortedUniqueStrings(dirs)
+
+	zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
+		var paths android.Paths
+
+		for _, output := range outputs {
+			paths = append(paths, get(output))
+		}
+
+		sort.Slice(paths, func(i, j int) bool {
+			return paths[i].String() < paths[j].String()
+		})
+
+		rule := android.NewRuleBuilder()
+
+		rule.Command().BuiltTool(ctx, "soong_zip").
+			FlagWithOutput("-o ", outputPath).
+			FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
+			FlagWithRspFileInputList("-l ", paths)
+
+		rule.Build(pctx, ctx, outputPath.Base(), outputPath.Base())
+	}
+
+	l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
+	zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
+
+	l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
+	zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
+
+	l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
+	zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
+
+	ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
+}
+
+func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
+	ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
+}
+
+var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
+
+func init() {
+	android.RegisterSingletonType("lint",
+		func() android.Singleton { return &lintSingleton{} })
+}
diff --git a/java/lint_defaults.txt b/java/lint_defaults.txt
new file mode 100644
index 0000000..0786b7c
--- /dev/null
+++ b/java/lint_defaults.txt
@@ -0,0 +1,78 @@
+# Treat LintError as fatal to catch invocation errors
+--fatal_check LintError
+
+# Downgrade existing errors to warnings
+--warning_check AppCompatResource                  # 55 occurences in 10 modules
+--warning_check AppLinkUrlError                    # 111 occurences in 53 modules
+--warning_check BlockedPrivateApi                  # 2 occurences in 2 modules
+--warning_check ByteOrderMark                      # 2 occurences in 2 modules
+--warning_check DuplicateActivity                  # 3 occurences in 3 modules
+--warning_check DuplicateDefinition                # 3623 occurences in 48 modules
+--warning_check DuplicateIds                       # 207 occurences in 22 modules
+--warning_check EllipsizeMaxLines                  # 12 occurences in 7 modules
+--warning_check ExtraTranslation                   # 21276 occurences in 27 modules
+--warning_check FontValidationError                # 4 occurences in 1 modules
+--warning_check FullBackupContent                  # 16 occurences in 1 modules
+--warning_check GetContentDescriptionOverride      # 3 occurences in 2 modules
+--warning_check HalfFloat                          # 31 occurences in 1 modules
+--warning_check HardcodedDebugMode                 # 99 occurences in 95 modules
+--warning_check ImpliedQuantity                    # 703 occurences in 27 modules
+--warning_check ImpliedTouchscreenHardware         # 4 occurences in 4 modules
+--warning_check IncludeLayoutParam                 # 11 occurences in 6 modules
+--warning_check Instantiatable                     # 145 occurences in 19 modules
+--warning_check InvalidPermission                  # 6 occurences in 4 modules
+--warning_check InvalidUsesTagAttribute            # 6 occurences in 2 modules
+--warning_check InvalidWakeLockTag                 # 111 occurences in 37 modules
+--warning_check JavascriptInterface                # 3 occurences in 2 modules
+--warning_check LibraryCustomView                  # 9 occurences in 4 modules
+--warning_check LogTagMismatch                     # 81 occurences in 13 modules
+--warning_check LongLogTag                         # 249 occurences in 12 modules
+--warning_check MenuTitle                          # 5 occurences in 4 modules
+--warning_check MissingClass                       # 537 occurences in 141 modules
+--warning_check MissingConstraints                 # 39 occurences in 10 modules
+--warning_check MissingDefaultResource             # 1257 occurences in 40 modules
+--warning_check MissingIntentFilterForMediaSearch  # 1 occurences in 1 modules
+--warning_check MissingLeanbackLauncher            # 3 occurences in 3 modules
+--warning_check MissingLeanbackSupport             # 2 occurences in 2 modules
+--warning_check MissingOnPlayFromSearch            # 1 occurences in 1 modules
+--warning_check MissingPermission                  # 2071 occurences in 150 modules
+--warning_check MissingPrefix                      # 46 occurences in 41 modules
+--warning_check MissingQuantity                    # 100 occurences in 1 modules
+--warning_check MissingSuperCall                   # 121 occurences in 36 modules
+--warning_check MissingTvBanner                    # 3 occurences in 3 modules
+--warning_check NamespaceTypo                      # 3 occurences in 3 modules
+--warning_check NetworkSecurityConfig              # 46 occurences in 12 modules
+--warning_check NewApi                             # 1996 occurences in 122 modules
+--warning_check NotSibling                         # 15 occurences in 10 modules
+--warning_check ObjectAnimatorBinding              # 14 occurences in 5 modules
+--warning_check OnClick                            # 49 occurences in 21 modules
+--warning_check Orientation                        # 77 occurences in 19 modules
+--warning_check Override                           # 385 occurences in 36 modules
+--warning_check ParcelCreator                      # 23 occurences in 2 modules
+--warning_check ProtectedPermissions               # 2413 occurences in 381 modules
+--warning_check Range                              # 80 occurences in 28 modules
+--warning_check RecyclerView                       # 1 occurences in 1 modules
+--warning_check ReferenceType                      # 4 occurences in 1 modules
+--warning_check ResourceAsColor                    # 19 occurences in 14 modules
+--warning_check RequiredSize                       # 52 occurences in 13 modules
+--warning_check ResAuto                            # 3 occurences in 1 modules
+--warning_check ResourceCycle                      # 37 occurences in 10 modules
+--warning_check ResourceType                       # 137 occurences in 36 modules
+--warning_check RestrictedApi                      # 28 occurences in 5 modules
+--warning_check RtlCompat                          # 9 occurences in 6 modules
+--warning_check ServiceCast                        # 3 occurences in 1 modules
+--warning_check SoonBlockedPrivateApi              # 5 occurences in 3 modules
+--warning_check StringFormatInvalid                # 148 occurences in 11 modules
+--warning_check StringFormatMatches                # 4800 occurences in 30 modules
+--warning_check UnknownId                          # 8 occurences in 7 modules
+--warning_check ValidFragment                      # 12 occurences in 5 modules
+--warning_check ValidRestrictions                  # 5 occurences in 1 modules
+--warning_check WebViewLayout                      # 3 occurences in 1 modules
+--warning_check WrongCall                          # 21 occurences in 3 modules
+--warning_check WrongConstant                      # 894 occurences in 126 modules
+--warning_check WrongManifestParent                # 10 occurences in 4 modules
+--warning_check WrongThread                        # 14 occurences in 6 modules
+--warning_check WrongViewCast                      # 1 occurences in 1 modules
+
+# TODO(b/158390965): remove this when lint doesn't crash
+--disable_check HardcodedDebugMode
diff --git a/java/plugin.go b/java/plugin.go
index a5e8292..947c286 100644
--- a/java/plugin.go
+++ b/java/plugin.go
@@ -24,10 +24,8 @@
 func PluginFactory() android.Module {
 	module := &Plugin{}
 
-	module.AddProperties(
-		&module.Module.properties,
-		&module.Module.protoProperties,
-		&module.pluginProperties)
+	module.addHostProperties()
+	module.AddProperties(&module.pluginProperties)
 
 	InitJavaModule(module, android.HostSupported)
 	return module
diff --git a/java/robolectric.go b/java/robolectric.go
index 3195615..c6b07a1 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -215,13 +215,13 @@
 func RobolectricTestFactory() android.Module {
 	module := &robolectricTest{}
 
+	module.addHostProperties()
 	module.AddProperties(
-		&module.Module.properties,
 		&module.Module.deviceProperties,
-		&module.Module.protoProperties,
 		&module.robolectricProperties)
 
 	module.Module.dexpreopter.isTest = true
+	module.Module.linter.test = true
 
 	InitJavaModule(module, android.DeviceSupported)
 	return module
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 c4d257f..7ce0912 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -264,7 +264,7 @@
 	apiScopeModuleLib = initApiScope(&apiScope{
 		name:    "module-lib",
 		extends: apiScopeSystem,
-		// Module_lib scope is disabled by default in legacy mode.
+		// The module-lib scope is disabled by default in legacy mode.
 		//
 		// Enabling this would break existing usages.
 		legacyEnabledStatus: func(module *SdkLibrary) bool {
@@ -280,11 +280,34 @@
 			"--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.MODULE_LIBRARIES\\)",
 		},
 	})
+	apiScopeSystemServer = initApiScope(&apiScope{
+		name:    "system-server",
+		extends: apiScopePublic,
+		// The system-server scope is disabled by default in legacy mode.
+		//
+		// Enabling this would break existing usages.
+		legacyEnabledStatus: func(module *SdkLibrary) bool {
+			return false
+		},
+		scopeSpecificProperties: func(module *SdkLibrary) *ApiScopeProperties {
+			return &module.sdkLibraryProperties.System_server
+		},
+		apiFilePrefix: "system-server-",
+		moduleSuffix:  ".system_server",
+		sdkVersion:    "system_server_current",
+		droidstubsArgs: []string{
+			"--show-annotation android.annotation.SystemApi\\(client=android.annotation.SystemApi.Client.SYSTEM_SERVER\\) ",
+			"--hide-annotation android.annotation.Hide",
+			// com.android.* classes are okay in this interface"
+			"--hide InternalClasses",
+		},
+	})
 	allApiScopes = apiScopes{
 		apiScopePublic,
 		apiScopeSystem,
 		apiScopeTest,
 		apiScopeModuleLib,
+		apiScopeSystemServer,
 	}
 )
 
@@ -429,12 +452,18 @@
 	// In non-legacy mode the test api scope is disabled by default.
 	Test ApiScopeProperties
 
-	// The properties specific to the module_lib api scope
+	// The properties specific to the module-lib api scope
 	//
-	// Unless explicitly specified by using test.enabled the module_lib api scope is
+	// Unless explicitly specified by using test.enabled the module-lib api scope is
 	// disabled by default.
 	Module_lib ApiScopeProperties
 
+	// The properties specific to the system-server api scope
+	//
+	// Unless explicitly specified by using test.enabled the module-lib api scope is
+	// disabled by default.
+	System_server ApiScopeProperties
+
 	// Determines if the stubs are preferred over the implementation library
 	// for linking, even when the client doesn't specify sdk_version. When this
 	// is set to true, such clients are provided with the widest API surface that
@@ -600,6 +629,16 @@
 	return true
 }
 
+// Module name of the runtime implementation library
+func (c *commonToSdkLibraryAndImport) implLibraryModuleName() string {
+	return c.moduleBase.BaseModuleName() + ".impl"
+}
+
+// Module name of the XML file for the lib
+func (c *commonToSdkLibraryAndImport) xmlPermissionsModuleName() string {
+	return c.moduleBase.BaseModuleName() + sdkXmlFileSuffix
+}
+
 // Name of the java_library module that compiles the stubs source.
 func (c *commonToSdkLibraryAndImport) stubsLibraryModuleName(apiScope *apiScope) string {
 	return c.namingScheme.stubsLibraryModuleName(apiScope, c.moduleBase.BaseModuleName())
@@ -743,6 +782,8 @@
 		apiScope = apiScopeModuleLib
 	case sdkTest:
 		apiScope = apiScopeTest
+	case sdkSystemServer:
+		apiScope = apiScopeSystemServer
 	default:
 		apiScope = apiScopePublic
 	}
@@ -827,7 +868,7 @@
 var _ SdkLibraryComponentDependency = (*Library)(nil)
 var _ SdkLibraryComponentDependency = (*Import)(nil)
 var _ SdkLibraryComponentDependency = (*SdkLibrary)(nil)
-var _ SdkLibraryComponentDependency = (*sdkLibraryImport)(nil)
+var _ SdkLibraryComponentDependency = (*SdkLibraryImport)(nil)
 
 // Provides access to sdk_version related header and implentation jars.
 type SdkLibraryDependency interface {
@@ -913,16 +954,24 @@
 	return generatedScopes
 }
 
-var xmlPermissionsFileTag = dependencyTag{name: "xml-permissions-file"}
+type sdkLibraryComponentTag struct {
+	blueprint.BaseDependencyTag
+	name string
+}
+
+// Mark this tag so dependencies that use it are excluded from visibility enforcement.
+func (t sdkLibraryComponentTag) ExcludeFromVisibilityEnforcement() {}
+
+var xmlPermissionsFileTag = sdkLibraryComponentTag{name: "xml-permissions-file"}
 
 func IsXmlPermissionsFileDepTag(depTag blueprint.DependencyTag) bool {
-	if dt, ok := depTag.(dependencyTag); ok {
+	if dt, ok := depTag.(sdkLibraryComponentTag); ok {
 		return dt == xmlPermissionsFileTag
 	}
 	return false
 }
 
-var implLibraryTag = dependencyTag{name: "impl-library"}
+var implLibraryTag = sdkLibraryComponentTag{name: "impl-library"}
 
 func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) {
 	for _, apiScope := range module.getGeneratedApiScopes(ctx) {
@@ -947,7 +996,7 @@
 
 		if module.sharedLibrary() {
 			// Add dependency to the rule for generating the xml permissions file
-			ctx.AddDependency(module, xmlPermissionsFileTag, module.xmlFileName())
+			ctx.AddDependency(module, xmlPermissionsFileTag, module.xmlPermissionsModuleName())
 		}
 
 		// Only add the deps for the library if it is actually going to be built.
@@ -994,20 +1043,10 @@
 	}
 	entriesList := module.Library.AndroidMkEntries()
 	entries := &entriesList[0]
-	entries.Required = append(entries.Required, module.xmlFileName())
+	entries.Required = append(entries.Required, module.xmlPermissionsModuleName())
 	return entriesList
 }
 
-// Module name of the runtime implementation library
-func (module *SdkLibrary) implLibraryModuleName() string {
-	return module.BaseModuleName() + ".impl"
-}
-
-// Module name of the XML file for the lib
-func (module *SdkLibrary) xmlFileName() string {
-	return module.BaseModuleName() + sdkXmlFileSuffix
-}
-
 // The dist path of the stub artifacts
 func (module *SdkLibrary) apiDistPath(apiScope *apiScope) string {
 	if module.ModuleBase.Owner() != "" {
@@ -1059,6 +1098,7 @@
 		&module.protoProperties,
 		&module.deviceProperties,
 		&module.dexpreoptProperties,
+		&module.linter.properties,
 		&props,
 		module.sdkComponentPropertiesForChildLibrary(),
 	}
@@ -1113,7 +1153,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
 	}
@@ -1296,7 +1338,7 @@
 		Lib_name       *string
 		Apex_available []string
 	}{
-		Name:           proptools.StringPtr(module.xmlFileName()),
+		Name:           proptools.StringPtr(module.xmlPermissionsModuleName()),
 		Lib_name:       proptools.StringPtr(module.BaseModuleName()),
 		Apex_available: module.ApexProperties.Apex_available,
 	}
@@ -1344,7 +1386,7 @@
 //
 // If either this or the other module are on the platform then this will return
 // false.
-func (module *SdkLibrary) withinSameApexAs(other android.Module) bool {
+func withinSameApexAs(module android.ApexModule, other android.Module) bool {
 	name := module.ApexName()
 	return name != "" && getApexNameForModule(other) == name
 }
@@ -1365,7 +1407,7 @@
 		// Only allow access to the implementation library in the following condition:
 		// * No sdk_version specified on the referencing module.
 		// * The referencing module is in the same apex as this.
-		if sdkVersion.kind == sdkPrivate || module.withinSameApexAs(ctx.Module()) {
+		if sdkVersion.kind == sdkPrivate || withinSameApexAs(module, ctx.Module()) {
 			if headerJars {
 				return module.HeaderJars()
 			} else {
@@ -1502,13 +1544,8 @@
 }
 
 func (module *SdkLibrary) InitSdkLibraryProperties() {
-	module.AddProperties(
-		&module.sdkLibraryProperties,
-		&module.properties,
-		&module.dexpreoptProperties,
-		&module.deviceProperties,
-		&module.protoProperties,
-	)
+	module.addHostAndDeviceProperties()
+	module.AddProperties(&module.sdkLibraryProperties)
 
 	module.initSdkLibraryComponent(&module.ModuleBase)
 
@@ -1575,6 +1612,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,
@@ -1651,7 +1706,7 @@
 	Libs []string
 }
 
-type sdkLibraryImport struct {
+type SdkLibraryImport struct {
 	android.ModuleBase
 	android.DefaultableModuleBase
 	prebuilt android.Prebuilt
@@ -1664,9 +1719,17 @@
 	scopeProperties map[*apiScope]*sdkLibraryScopeProperties
 
 	commonToSdkLibraryAndImport
+
+	// The reference to the implementation library created by the source module.
+	// Is nil if the source module does not exist.
+	implLibraryModule *Library
+
+	// The reference to the xml permissions module created by the source module.
+	// Is nil if the source module does not exist.
+	xmlPermissionsFileModule *sdkLibraryXml
 }
 
-var _ SdkLibraryDependency = (*sdkLibraryImport)(nil)
+var _ SdkLibraryDependency = (*SdkLibraryImport)(nil)
 
 // The type of a structure that contains a field of type sdkLibraryScopeProperties
 // for each apiscope in allApiScopes, e.g. something like:
@@ -1708,7 +1771,7 @@
 
 // java_sdk_library_import imports a prebuilt java_sdk_library.
 func sdkLibraryImportFactory() android.Module {
-	module := &sdkLibraryImport{}
+	module := &SdkLibraryImport{}
 
 	allScopeProperties, scopeToProperties := createPropertiesInstance()
 	module.scopeProperties = scopeToProperties
@@ -1730,15 +1793,15 @@
 	return module
 }
 
-func (module *sdkLibraryImport) Prebuilt() *android.Prebuilt {
+func (module *SdkLibraryImport) Prebuilt() *android.Prebuilt {
 	return &module.prebuilt
 }
 
-func (module *sdkLibraryImport) Name() string {
+func (module *SdkLibraryImport) Name() string {
 	return module.prebuilt.Name(module.ModuleBase.Name())
 }
 
-func (module *sdkLibraryImport) createInternalModules(mctx android.DefaultableHookContext) {
+func (module *SdkLibraryImport) createInternalModules(mctx android.DefaultableHookContext) {
 
 	// If the build is configured to use prebuilts then force this to be preferred.
 	if mctx.Config().UnbundledBuildUsePrebuiltSdks() {
@@ -1763,7 +1826,7 @@
 	*javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName())
 }
 
-func (module *sdkLibraryImport) createJavaImportForStubs(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
+func (module *SdkLibraryImport) createJavaImportForStubs(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
 	// Creates a java import for the jar with ".stubs" suffix
 	props := struct {
 		Name        *string
@@ -1785,7 +1848,7 @@
 	mctx.CreateModule(ImportFactory, &props, module.sdkComponentPropertiesForChildLibrary())
 }
 
-func (module *sdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
+func (module *SdkLibraryImport) createPrebuiltStubsSources(mctx android.DefaultableHookContext, apiScope *apiScope, scopeProperties *sdkLibraryScopeProperties) {
 	props := struct {
 		Name   *string
 		Srcs   []string
@@ -1799,7 +1862,7 @@
 	props.Prefer = proptools.BoolPtr(module.prebuilt.Prefer())
 }
 
-func (module *sdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) {
+func (module *SdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) {
 	for apiScope, scopeProperties := range module.scopeProperties {
 		if len(scopeProperties.Jars) == 0 {
 			continue
@@ -1813,13 +1876,35 @@
 			ctx.AddVariationDependencies(nil, apiScope.stubsSourceTag, module.stubsSourceModuleName(apiScope))
 		}
 	}
+
+	implName := module.implLibraryModuleName()
+	if ctx.OtherModuleExists(implName) {
+		ctx.AddVariationDependencies(nil, implLibraryTag, implName)
+
+		xmlPermissionsModuleName := module.xmlPermissionsModuleName()
+		if module.sharedLibrary() && ctx.OtherModuleExists(xmlPermissionsModuleName) {
+			// Add dependency to the rule for generating the xml permissions file
+			ctx.AddDependency(module, xmlPermissionsFileTag, xmlPermissionsModuleName)
+		}
+	}
 }
 
-func (module *sdkLibraryImport) OutputFiles(tag string) (android.Paths, error) {
+func (module *SdkLibraryImport) DepIsInSameApex(mctx android.BaseModuleContext, dep android.Module) bool {
+	depTag := mctx.OtherModuleDependencyTag(dep)
+	if depTag == xmlPermissionsFileTag {
+		return true
+	}
+
+	// None of the other dependencies of the java_sdk_library_import are in the same apex
+	// as the one that references this module.
+	return false
+}
+
+func (module *SdkLibraryImport) OutputFiles(tag string) (android.Paths, error) {
 	return module.commonOutputFiles(tag)
 }
 
-func (module *sdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	// Record the paths to the prebuilt stubs library and stubs source.
 	ctx.VisitDirectDeps(func(to android.Module) {
 		tag := ctx.OtherModuleDependencyTag(to)
@@ -1832,6 +1917,18 @@
 			// Extract information from the dependency. The exact information extracted
 			// is determined by the nature of the dependency which is determined by the tag.
 			scopeTag.extractDepInfo(ctx, to, scopePaths)
+		} else if tag == implLibraryTag {
+			if implLibrary, ok := to.(*Library); ok {
+				module.implLibraryModule = implLibrary
+			} else {
+				ctx.ModuleErrorf("implementation library must be of type *java.Library but was %T", to)
+			}
+		} else if tag == xmlPermissionsFileTag {
+			if xmlPermissionsFileModule, ok := to.(*sdkLibraryXml); ok {
+				module.xmlPermissionsFileModule = xmlPermissionsFileModule
+			} else {
+				ctx.ModuleErrorf("xml permissions file module must be of type *sdkLibraryXml but was %T", to)
+			}
 		}
 	})
 
@@ -1847,20 +1944,75 @@
 	}
 }
 
-func (module *sdkLibraryImport) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
+func (module *SdkLibraryImport) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec, headerJars bool) android.Paths {
+
+	// For consistency with SdkLibrary make the implementation jar available to libraries that
+	// are within the same APEX.
+	implLibraryModule := module.implLibraryModule
+	if implLibraryModule != nil && withinSameApexAs(module, ctx.Module()) {
+		if headerJars {
+			return implLibraryModule.HeaderJars()
+		} else {
+			return implLibraryModule.ImplementationJars()
+		}
+	}
+
 	return module.selectHeaderJarsForSdkVersion(ctx, sdkVersion)
 }
 
 // to satisfy SdkLibraryDependency interface
-func (module *sdkLibraryImport) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
+func (module *SdkLibraryImport) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
 	// This module is just a wrapper for the prebuilt stubs.
-	return module.sdkJars(ctx, sdkVersion)
+	return module.sdkJars(ctx, sdkVersion, true)
 }
 
 // to satisfy SdkLibraryDependency interface
-func (module *sdkLibraryImport) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
+func (module *SdkLibraryImport) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths {
 	// This module is just a wrapper for the stubs.
-	return module.sdkJars(ctx, sdkVersion)
+	return module.sdkJars(ctx, sdkVersion, false)
+}
+
+// to satisfy apex.javaDependency interface
+func (module *SdkLibraryImport) DexJarBuildPath() android.Path {
+	if module.implLibraryModule == nil {
+		return nil
+	} else {
+		return module.implLibraryModule.DexJarBuildPath()
+	}
+}
+
+// to satisfy apex.javaDependency interface
+func (module *SdkLibraryImport) JacocoReportClassesFile() android.Path {
+	if module.implLibraryModule == nil {
+		return nil
+	} else {
+		return module.implLibraryModule.JacocoReportClassesFile()
+	}
+}
+
+// to satisfy apex.javaDependency interface
+func (module *SdkLibraryImport) Stem() string {
+	return module.BaseModuleName()
+}
+
+var _ ApexDependency = (*SdkLibraryImport)(nil)
+
+// to satisfy java.ApexDependency interface
+func (module *SdkLibraryImport) HeaderJars() android.Paths {
+	if module.implLibraryModule == nil {
+		return nil
+	} else {
+		return module.implLibraryModule.HeaderJars()
+	}
+}
+
+// to satisfy java.ApexDependency interface
+func (module *SdkLibraryImport) ImplementationAndResourcesJars() android.Paths {
+	if module.implLibraryModule == nil {
+		return nil
+	} else {
+		return module.implLibraryModule.ImplementationAndResourcesJars()
+	}
 }
 
 //
@@ -2083,7 +2235,7 @@
 
 			if properties.RemovedApiFile != nil {
 				removedApiSnapshotPath := filepath.Join(scopeDir, ctx.Name()+"-removed.txt")
-				ctx.SnapshotBuilder().CopyToSnapshot(properties.CurrentApiFile, removedApiSnapshotPath)
+				ctx.SnapshotBuilder().CopyToSnapshot(properties.RemovedApiFile, removedApiSnapshotPath)
 				scopeSet.AddProperty("removed_api", removedApiSnapshotPath)
 			}
 
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..6fc10da 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -25,35 +25,12 @@
 	bp += GatherRequiredDepsForTest()
 
 	mockFS := map[string][]byte{
-		"a.java":                 nil,
-		"b.java":                 nil,
-		"c.java":                 nil,
-		"b.kt":                   nil,
-		"a.jar":                  nil,
-		"b.jar":                  nil,
-		"c.jar":                  nil,
-		"APP_NOTICE":             nil,
-		"GENRULE_NOTICE":         nil,
-		"LIB_NOTICE":             nil,
-		"TOOL_NOTICE":            nil,
-		"AndroidTest.xml":        nil,
-		"java-res/a/a":           nil,
-		"java-res/b/b":           nil,
-		"java-res2/a":            nil,
-		"java-fg/a.java":         nil,
-		"java-fg/b.java":         nil,
-		"java-fg/c.java":         nil,
 		"api/current.txt":        nil,
 		"api/removed.txt":        nil,
 		"api/system-current.txt": nil,
 		"api/system-removed.txt": nil,
 		"api/test-current.txt":   nil,
 		"api/test-removed.txt":   nil,
-		"framework/aidl/a.aidl":  nil,
-		"aidl/foo/IFoo.aidl":     nil,
-		"aidl/bar/IBar.aidl":     nil,
-		"assets_a/a":             nil,
-		"assets_b/b":             nil,
 
 		"prebuilts/sdk/14/public/android.jar":                      nil,
 		"prebuilts/sdk/14/public/framework.aidl":                   nil,
@@ -104,44 +81,12 @@
 		"prebuilts/sdk/tools/core-lambda-stubs.jar":                nil,
 		"prebuilts/sdk/Android.bp":                                 []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "30", "current"],}`),
 
-		"prebuilts/apk/app.apk":        nil,
-		"prebuilts/apk/app_arm.apk":    nil,
-		"prebuilts/apk/app_arm64.apk":  nil,
-		"prebuilts/apk/app_xhdpi.apk":  nil,
-		"prebuilts/apk/app_xxhdpi.apk": nil,
-
-		"prebuilts/apks/app.apks": nil,
-
-		// For framework-res, which is an implicit dependency for framework
-		"AndroidManifest.xml":                        nil,
-		"build/make/target/product/security/testkey": nil,
-
-		"build/soong/scripts/jar-wrapper.sh": nil,
-
-		"build/make/core/verify_uses_libraries.sh": nil,
-
-		"build/make/core/proguard.flags":             nil,
-		"build/make/core/proguard_basic_keeps.flags": nil,
-
-		"jdk8/jre/lib/jce.jar": nil,
-		"jdk8/jre/lib/rt.jar":  nil,
-		"jdk8/lib/tools.jar":   nil,
-
-		"bar-doc/a.java":                 nil,
-		"bar-doc/b.java":                 nil,
-		"bar-doc/IFoo.aidl":              nil,
-		"bar-doc/IBar.aidl":              nil,
-		"bar-doc/known_oj_tags.txt":      nil,
-		"external/doclava/templates-sdk": nil,
-
-		"cert/new_cert.x509.pem": nil,
-		"cert/new_cert.pk8":      nil,
-		"lineage.bin":            nil,
-
-		"testdata/data": nil,
-
-		"stubs-sources/foo/Foo.java": nil,
-		"stubs/sources/foo/Foo.java": nil,
+		// For java_sdk_library
+		"api/module-lib-current.txt":                        nil,
+		"api/module-lib-removed.txt":                        nil,
+		"api/system-server-current.txt":                     nil,
+		"api/system-server-removed.txt":                     nil,
+		"build/soong/scripts/gen-java-current-api-files.sh": nil,
 	}
 
 	cc.GatherRequiredFilesForTest(mockFS)
@@ -173,7 +118,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 +132,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 +142,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 +157,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 +165,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 +173,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 +181,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 +189,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/phony/Android.bp b/phony/Android.bp
new file mode 100644
index 0000000..2c423ef
--- /dev/null
+++ b/phony/Android.bp
@@ -0,0 +1,12 @@
+bootstrap_go_package {
+    name: "soong-phony",
+    pkgPath: "android/soong/phony",
+    deps: [
+        "blueprint",
+        "soong-android",
+    ],
+    srcs: [
+        "phony.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/python/Android.bp b/python/Android.bp
new file mode 100644
index 0000000..ffd03fe
--- /dev/null
+++ b/python/Android.bp
@@ -0,0 +1,24 @@
+bootstrap_go_package {
+    name: "soong-python",
+    pkgPath: "android/soong/python",
+    deps: [
+        "blueprint",
+        "soong-android",
+        "soong-tradefed",
+    ],
+    srcs: [
+        "androidmk.go",
+        "binary.go",
+        "builder.go",
+        "defaults.go",
+        "installer.go",
+        "library.go",
+        "proto.go",
+        "python.go",
+        "test.go",
+    ],
+    testSrcs: [
+        "python_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/python/androidmk.go b/python/androidmk.go
index d293d52..247b80d 100644
--- a/python/androidmk.go
+++ b/python/androidmk.go
@@ -66,15 +66,9 @@
 			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
 				strings.Join(p.binaryDecorator.binaryProperties.Test_suites, " "))
 		}
-		// If the test config has an explicit config specified use it.
-		if p.testProperties.Test_config != nil {
-			fmt.Fprintln(w, "LOCAL_TEST_CONFIG :=",
-				*p.testProperties.Test_config)
-		} else {
-			if p.testConfig != nil {
-				fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=",
-					p.testConfig.String())
-			}
+		if p.testConfig != nil {
+			fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=",
+				p.testConfig.String())
 		}
 
 		if !BoolDefault(p.binaryProperties.Auto_gen_config, true) {
diff --git a/python/test.go b/python/test.go
index f684fd5..a669c73 100644
--- a/python/test.go
+++ b/python/test.go
@@ -29,11 +29,11 @@
 type TestProperties struct {
 	// the name of the test configuration (for example "AndroidTest.xml") that should be
 	// installed with the module.
-	Test_config *string `android:"arch_variant"`
+	Test_config *string `android:"path,arch_variant"`
 
 	// the name of the test configuration template (for example "AndroidTestTemplate.xml") that
 	// should be installed with the module.
-	Test_config_template *string `android:"arch_variant"`
+	Test_config_template *string `android:"path,arch_variant"`
 }
 
 type testDecorator struct {
diff --git a/remoteexec/Android.bp b/remoteexec/Android.bp
new file mode 100644
index 0000000..fc2c0e3
--- /dev/null
+++ b/remoteexec/Android.bp
@@ -0,0 +1,15 @@
+bootstrap_go_package {
+    name: "soong-remoteexec",
+    pkgPath: "android/soong/remoteexec",
+    deps: [
+        "blueprint",
+        "soong-android",
+    ],
+    srcs: [
+        "remoteexec.go",
+    ],
+    testSrcs: [
+        "remoteexec_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/rust/Android.bp b/rust/Android.bp
new file mode 100644
index 0000000..b06ea8e
--- /dev/null
+++ b/rust/Android.bp
@@ -0,0 +1,34 @@
+bootstrap_go_package {
+    name: "soong-rust",
+    pkgPath: "android/soong/rust",
+    deps: [
+        "soong",
+        "soong-android",
+        "soong-cc",
+        "soong-rust-config",
+    ],
+    srcs: [
+        "androidmk.go",
+        "compiler.go",
+        "coverage.go",
+        "binary.go",
+        "builder.go",
+        "library.go",
+        "prebuilt.go",
+        "proc_macro.go",
+	"project_json.go",
+        "rust.go",
+        "test.go",
+        "testing.go",
+    ],
+    testSrcs: [
+        "binary_test.go",
+        "compiler_test.go",
+        "coverage_test.go",
+        "library_test.go",
+	"project_json_test.go",
+        "rust_test.go",
+        "test_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/rust/OWNERS b/rust/OWNERS
index 82713f9..afd06e4 100644
--- a/rust/OWNERS
+++ b/rust/OWNERS
@@ -1,5 +1,5 @@
 # Additional owner/reviewers for rust rules, including parent directory owners.
 per-file * = chh@google.com, ivanlozano@google.com, jeffv@google.com, srhines@google.com
 
-# Limited owners/reviewers of the whitelist.
-per-file whitelist.go = chh@google.com, ivanlozano@google.com, jeffv@google.com, jgalenson@google.com, srhines@google.com
+# Limited owners/reviewers of the allowed list.
+per-file allowed_list.go = chh@google.com, ivanlozano@google.com, jeffv@google.com, jgalenson@google.com, srhines@google.com
diff --git a/rust/androidmk.go b/rust/androidmk.go
index 0e2bea3..69d0df5 100644
--- a/rust/androidmk.go
+++ b/rust/androidmk.go
@@ -99,7 +99,6 @@
 func (test *testDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkData) {
 	test.binaryDecorator.AndroidMk(ctx, ret)
 	ret.Class = "NATIVE_TESTS"
-	ret.SubName = test.getMutatedModuleSubName(ctx.Name())
 	ret.Extra = append(ret.Extra, func(w io.Writer, outputFile android.Path) {
 		if len(test.Properties.Test_suites) > 0 {
 			fmt.Fprintln(w, "LOCAL_COMPATIBILITY_SUITE :=",
diff --git a/rust/binary.go b/rust/binary.go
index c25ae09..56d6f0b 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -24,9 +24,6 @@
 }
 
 type BinaryCompilerProperties struct {
-	// path to the main source file that contains the program entry point (e.g. src/main.rs)
-	Srcs []string `android:"path,arch_variant"`
-
 	// passes -C prefer-dynamic to rustc, which tells it to dynamically link the stdlib
 	// (assuming it has no dylib dependencies already)
 	Prefer_dynamic *bool
@@ -35,10 +32,7 @@
 type binaryDecorator struct {
 	*baseCompiler
 
-	Properties            BinaryCompilerProperties
-	distFile              android.OptionalPath
-	coverageOutputZipFile android.OptionalPath
-	unstrippedOutputFile  android.Path
+	Properties BinaryCompilerProperties
 }
 
 var _ compiler = (*binaryDecorator)(nil)
@@ -112,7 +106,7 @@
 func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
 	fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix()
 
-	srcPath := srcPathFromModuleSrcs(ctx, binary.Properties.Srcs)
+	srcPath := srcPathFromModuleSrcs(ctx, binary.baseCompiler.Properties.Srcs)
 
 	outputFile := android.PathForModuleOut(ctx, fileName)
 	binary.unstrippedOutputFile = outputFile
diff --git a/rust/builder.go b/rust/builder.go
index fbe0e53..7dbb59d 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -21,6 +21,7 @@
 	"github.com/google/blueprint/pathtools"
 
 	"android/soong/android"
+	"android/soong/cc"
 )
 
 var (
@@ -161,11 +162,17 @@
 
 	if flags.Coverage {
 		var gcnoFile android.WritablePath
+		// Provide consistency with cc gcda output, see cc/builder.go init()
+		profileEmitArg := strings.TrimPrefix(cc.PwdPrefix(), "PWD=") + "/"
 
 		if outputFile.Ext() != "" {
 			gcnoFile = android.PathForModuleOut(ctx, pathtools.ReplaceExtension(outputFile.Base(), "gcno"))
+			rustcFlags = append(rustcFlags, "-Z profile-emit="+profileEmitArg+android.PathForModuleOut(
+				ctx, pathtools.ReplaceExtension(outputFile.Base(), "gcda")).String())
 		} else {
 			gcnoFile = android.PathForModuleOut(ctx, outputFile.Base()+".gcno")
+			rustcFlags = append(rustcFlags, "-Z profile-emit="+profileEmitArg+android.PathForModuleOut(
+				ctx, outputFile.Base()+".gcda").String())
 		}
 
 		implicitOutputs = append(implicitOutputs, gcnoFile)
diff --git a/rust/compiler.go b/rust/compiler.go
index 5f098bc..efc1ce4 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -53,6 +53,9 @@
 )
 
 type BaseCompilerProperties struct {
+	// path to the source file that is the main entry point of the program (e.g. main.rs or lib.rs)
+	Srcs []string `android:"path,arch_variant"`
+
 	// whether to pass "-D warnings" to rustc. Defaults to true.
 	Deny_warnings *bool
 
@@ -100,17 +103,10 @@
 }
 
 type baseCompiler struct {
-	Properties    BaseCompilerProperties
-	pathDeps      android.Paths
-	rustFlagsDeps android.Paths
-	linkFlagsDeps android.Paths
-	flags         string
-	linkFlags     string
-	depFlags      []string
-	linkDirs      []string
-	edition       string
-	src           android.Path //rustc takes a single src file
-	coverageFile  android.Path //rustc generates a single gcno file
+	Properties   BaseCompilerProperties
+	depFlags     []string
+	linkDirs     []string
+	coverageFile android.Path //rustc generates a single gcno file
 
 	// Install related
 	dir      string
@@ -119,6 +115,10 @@
 	relative string
 	path     android.InstallPath
 	location installLocation
+
+	coverageOutputZipFile android.OptionalPath
+	unstrippedOutputFile  android.Path
+	distFile              android.OptionalPath
 }
 
 func (compiler *baseCompiler) coverageOutputZipPath() android.OptionalPath {
diff --git a/rust/config/Android.bp b/rust/config/Android.bp
new file mode 100644
index 0000000..5026da3
--- /dev/null
+++ b/rust/config/Android.bp
@@ -0,0 +1,19 @@
+bootstrap_go_package {
+    name: "soong-rust-config",
+    pkgPath: "android/soong/rust/config",
+    deps: [
+        "soong-android",
+        "soong-cc-config",
+    ],
+    srcs: [
+        "arm_device.go",
+        "arm64_device.go",
+        "global.go",
+        "toolchain.go",
+        "allowed_list.go",
+        "x86_darwin_host.go",
+        "x86_linux_host.go",
+        "x86_device.go",
+        "x86_64_device.go",
+    ],
+}
diff --git a/rust/config/whitelist.go b/rust/config/allowed_list.go
similarity index 100%
rename from rust/config/whitelist.go
rename to rust/config/allowed_list.go
diff --git a/rust/library.go b/rust/library.go
index 8aa033c..704c77b 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -45,9 +45,6 @@
 	Shared VariantLibraryProperties `android:"arch_variant"`
 	Static VariantLibraryProperties `android:"arch_variant"`
 
-	// path to the source file that is the main entry point of the program (e.g. src/lib.rs)
-	Srcs []string `android:"path,arch_variant"`
-
 	// path to include directories to pass to cc_* modules, only relevant for static/shared variants.
 	Include_dirs []string `android:"path,arch_variant"`
 }
@@ -75,12 +72,9 @@
 type libraryDecorator struct {
 	*baseCompiler
 
-	Properties            LibraryCompilerProperties
-	MutatedProperties     LibraryMutatedProperties
-	distFile              android.OptionalPath
-	coverageOutputZipFile android.OptionalPath
-	unstrippedOutputFile  android.Path
-	includeDirs           android.Paths
+	Properties        LibraryCompilerProperties
+	MutatedProperties LibraryMutatedProperties
+	includeDirs       android.Paths
 }
 
 type libraryInterface interface {
@@ -329,19 +323,28 @@
 
 	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
 }
 
 func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path {
 	var outputFile android.WritablePath
 
-	srcPath := srcPathFromModuleSrcs(ctx, library.Properties.Srcs)
+	srcPath := srcPathFromModuleSrcs(ctx, library.baseCompiler.Properties.Srcs)
 
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
 
@@ -371,7 +374,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/rust/proc_macro.go b/rust/proc_macro.go
index 10ea1e3..42c8537 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -23,20 +23,12 @@
 }
 
 type ProcMacroCompilerProperties struct {
-	// path to the source file that is the main entry point of the program (e.g. src/lib.rs)
-	Srcs []string `android:"path,arch_variant"`
-
-	// set name of the procMacro
-	Stem   *string `android:"arch_variant"`
-	Suffix *string `android:"arch_variant"`
 }
 
 type procMacroDecorator struct {
 	*baseCompiler
 
-	Properties           ProcMacroCompilerProperties
-	distFile             android.OptionalPath
-	unstrippedOutputFile android.Path
+	Properties ProcMacroCompilerProperties
 }
 
 type procMacroInterface interface {
@@ -70,7 +62,7 @@
 	fileName := procMacro.getStem(ctx) + ctx.toolchain().ProcMacroSuffix()
 	outputFile := android.PathForModuleOut(ctx, fileName)
 
-	srcPath := srcPathFromModuleSrcs(ctx, procMacro.Properties.Srcs)
+	srcPath := srcPathFromModuleSrcs(ctx, procMacro.baseCompiler.Properties.Srcs)
 
 	procMacro.unstrippedOutputFile = outputFile
 
diff --git a/rust/project_json.go b/rust/project_json.go
new file mode 100644
index 0000000..a50e73a
--- /dev/null
+++ b/rust/project_json.go
@@ -0,0 +1,161 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rust
+
+import (
+	"encoding/json"
+	"fmt"
+	"path"
+
+	"android/soong/android"
+)
+
+// This singleton collects Rust crate definitions and generates a JSON file
+// (${OUT_DIR}/soong/rust-project.json) which can be use by external tools,
+// such as rust-analyzer. It does so when either make, mm, mma, mmm or mmma is
+// called.  This singleton is enabled only if SOONG_GEN_RUST_PROJECT is set.
+// For example,
+//
+//   $ SOONG_GEN_RUST_PROJECT=1 m nothing
+
+func init() {
+	android.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton)
+}
+
+func rustProjectGeneratorSingleton() android.Singleton {
+	return &projectGeneratorSingleton{}
+}
+
+type projectGeneratorSingleton struct{}
+
+const (
+	// Environment variables used to control the behavior of this singleton.
+	envVariableCollectRustDeps = "SOONG_GEN_RUST_PROJECT"
+	rustProjectJsonFileName    = "rust-project.json"
+)
+
+// The format of rust-project.json is not yet finalized. A current description is available at:
+// https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/manual.adoc#non-cargo-based-projects
+type rustProjectDep struct {
+	Crate int    `json:"crate"`
+	Name  string `json:"name"`
+}
+
+type rustProjectCrate struct {
+	RootModule string           `json:"root_module"`
+	Edition    string           `json:"edition,omitempty"`
+	Deps       []rustProjectDep `json:"deps"`
+	Cfgs       []string         `json:"cfgs"`
+}
+
+type rustProjectJson struct {
+	Roots  []string           `json:"roots"`
+	Crates []rustProjectCrate `json:"crates"`
+}
+
+// crateInfo is used during the processing to keep track of the known crates.
+type crateInfo struct {
+	ID   int
+	Deps map[string]int
+}
+
+func mergeDependencies(ctx android.SingletonContext, project *rustProjectJson,
+	knownCrates map[string]crateInfo, module android.Module,
+	crate *rustProjectCrate, deps map[string]int) {
+
+	//TODO(tweek): The stdlib dependencies do not appear here. We need to manually add them.
+	ctx.VisitDirectDeps(module, func(child android.Module) {
+		childId, childName, ok := appendLibraryAndDeps(ctx, project, knownCrates, child)
+		if !ok {
+			return
+		}
+		if _, ok = deps[childName]; ok {
+			return
+		}
+		crate.Deps = append(crate.Deps, rustProjectDep{Crate: childId, Name: childName})
+		deps[childName] = childId
+	})
+}
+
+// appendLibraryAndDeps creates a rustProjectCrate for the module argument and
+// appends it to the rustProjectJson struct.  It visits the dependencies of the
+// module depth-first. If the current module is already in knownCrates, its
+// its dependencies are merged. Returns a tuple (id, crate_name, ok).
+func appendLibraryAndDeps(ctx android.SingletonContext, project *rustProjectJson,
+	knownCrates map[string]crateInfo, module android.Module) (int, string, bool) {
+	rModule, ok := module.(*Module)
+	if !ok {
+		return 0, "", false
+	}
+	if rModule.compiler == nil {
+		return 0, "", false
+	}
+	rustLib, ok := rModule.compiler.(*libraryDecorator)
+	if !ok {
+		return 0, "", false
+	}
+	crateName := rModule.CrateName()
+	if cInfo, ok := knownCrates[crateName]; ok {
+		// We have seen this crate already; merge any new dependencies.
+		crate := project.Crates[cInfo.ID]
+		mergeDependencies(ctx, project, knownCrates, module, &crate, cInfo.Deps)
+		return cInfo.ID, crateName, true
+	}
+	crate := rustProjectCrate{Deps: make([]rustProjectDep, 0), Cfgs: make([]string, 0)}
+	src := rustLib.baseCompiler.Properties.Srcs[0]
+	crate.RootModule = path.Join(ctx.ModuleDir(rModule), src)
+	crate.Edition = getEdition(rustLib.baseCompiler)
+
+	deps := make(map[string]int)
+	mergeDependencies(ctx, project, knownCrates, module, &crate, deps)
+
+	id := len(project.Crates)
+	knownCrates[crateName] = crateInfo{ID: id, Deps: deps}
+	project.Crates = append(project.Crates, crate)
+	// rust-analyzer requires that all crates belong to at least one root:
+	// https://github.com/rust-analyzer/rust-analyzer/issues/4735.
+	project.Roots = append(project.Roots, path.Dir(crate.RootModule))
+	return id, crateName, true
+}
+
+func (r *projectGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	if !ctx.Config().IsEnvTrue(envVariableCollectRustDeps) {
+		return
+	}
+
+	project := rustProjectJson{}
+	knownCrates := make(map[string]crateInfo)
+	ctx.VisitAllModules(func(module android.Module) {
+		appendLibraryAndDeps(ctx, &project, knownCrates, module)
+	})
+
+	path := android.PathForOutput(ctx, rustProjectJsonFileName)
+	err := createJsonFile(project, path)
+	if err != nil {
+		ctx.Errorf(err.Error())
+	}
+}
+
+func createJsonFile(project rustProjectJson, rustProjectPath android.WritablePath) error {
+	buf, err := json.MarshalIndent(project, "", "  ")
+	if err != nil {
+		return fmt.Errorf("JSON marshal of rustProjectJson failed: %s", err)
+	}
+	err = android.WriteFileToOutputDir(rustProjectPath, buf, 0666)
+	if err != nil {
+		return fmt.Errorf("Writing rust-project to %s failed: %s", rustProjectPath.String(), err)
+	}
+	return nil
+}
diff --git a/rust/project_json_test.go b/rust/project_json_test.go
new file mode 100644
index 0000000..6786e72
--- /dev/null
+++ b/rust/project_json_test.go
@@ -0,0 +1,55 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package rust
+
+import (
+	"io/ioutil"
+	"path/filepath"
+	"testing"
+
+	"android/soong/android"
+	"android/soong/cc"
+)
+
+func TestProjectJson(t *testing.T) {
+	bp := `rust_library {
+		  name: "liba",
+		  srcs: ["src/lib.rs"],
+		  crate_name: "a"
+		}` + GatherRequiredDepsForTest()
+	env := map[string]string{"SOONG_GEN_RUST_PROJECT": "1"}
+	fs := map[string][]byte{
+		"foo.rs":     nil,
+		"src/lib.rs": nil,
+	}
+
+	cc.GatherRequiredFilesForTest(fs)
+
+	config := android.TestArchConfig(buildDir, env, bp, fs)
+	ctx := CreateTestContext()
+	ctx.Register(config)
+	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+	android.FailIfErrored(t, errs)
+	_, errs = ctx.PrepareBuildActions(config)
+	android.FailIfErrored(t, errs)
+
+	// The JSON file is generated via WriteFileToOutputDir. Therefore, it
+	// won't appear in the Output of the TestingSingleton. Manually verify
+	// it exists.
+	_, err := ioutil.ReadFile(filepath.Join(buildDir, "rust-project.json"))
+	if err != nil {
+		t.Errorf("rust-project.json has not been generated")
+	}
+}
diff --git a/rust/rust.go b/rust/rust.go
index 8cf2e6d..7b82b1f 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -39,18 +39,16 @@
 	android.RegisterModuleType("rust_defaults", defaultsFactory)
 	android.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
-		ctx.BottomUp("rust_unit_tests", TestPerSrcMutator).Parallel()
 		ctx.BottomUp("rust_begin", BeginMutator).Parallel()
 	})
 	pctx.Import("android/soong/rust/config")
 }
 
 type Flags struct {
-	GlobalRustFlags []string      // Flags that apply globally to rust
-	GlobalLinkFlags []string      // Flags that apply globally to linker
-	RustFlags       []string      // Flags that apply to rust
-	LinkFlags       []string      // Flags that apply to linker
-	RustFlagsDeps   android.Paths // Files depended on by compiler flags
+	GlobalRustFlags []string // Flags that apply globally to rust
+	GlobalLinkFlags []string // Flags that apply globally to linker
+	RustFlags       []string // Flags that apply to rust
+	LinkFlags       []string // Flags that apply to linker
 	Toolchain       config.Toolchain
 	Coverage        bool
 }
@@ -197,6 +195,10 @@
 	return false
 }
 
+func (mod *Module) IsSdkVariant() bool {
+	return false
+}
+
 func (mod *Module) ToolchainLibrary() bool {
 	return false
 }
diff --git a/rust/rust_test.go b/rust/rust_test.go
index d658ee2..fe21e3a 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -89,7 +89,7 @@
 
 	if coverage {
 		config.TestProductVariables.Native_coverage = proptools.BoolPtr(true)
-		config.TestProductVariables.CoveragePaths = []string{"*"}
+		config.TestProductVariables.NativeCoveragePaths = []string{"*"}
 	}
 
 	t.Helper()
diff --git a/rust/test.go b/rust/test.go
index 94568c1..416c557 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -15,21 +15,23 @@
 package rust
 
 import (
-	"path/filepath"
-	"strings"
-
 	"android/soong/android"
 	"android/soong/tradefed"
 )
 
 type TestProperties struct {
+	// Disables the creation of a test-specific directory when used with
+	// relative_install_path. Useful if several tests need to be in the same
+	// directory, but test_per_src doesn't work.
+	No_named_install_directory *bool
+
 	// the name of the test configuration (for example "AndroidTest.xml") that should be
 	// installed with the module.
-	Test_config *string `android:"arch_variant"`
+	Test_config *string `android:"path,arch_variant"`
 
 	// the name of the test configuration template (for example "AndroidTestTemplate.xml") that
 	// should be installed with the module.
-	Test_config_template *string `android:"arch_variant"`
+	Test_config_template *string `android:"path,arch_variant"`
 
 	// list of compatibility suites (for example "cts", "vts") that the module should be
 	// installed into.
@@ -55,7 +57,14 @@
 }
 
 func NewRustTest(hod android.HostOrDeviceSupported) (*Module, *testDecorator) {
-	module := newModule(hod, android.MultilibFirst)
+	// Build both 32 and 64 targets for device tests.
+	// Cannot build both for host tests yet if the test depends on
+	// something like proc-macro2 that cannot be built for both.
+	multilib := android.MultilibBoth
+	if hod != android.DeviceSupported && hod != android.HostAndDeviceSupported {
+		multilib = android.MultilibFirst
+	}
+	module := newModule(hod, multilib)
 
 	test := &testDecorator{
 		binaryDecorator: &binaryDecorator{
@@ -64,7 +73,7 @@
 	}
 
 	module.compiler = test
-
+	module.AddProperties(&test.Properties)
 	return module, test
 }
 
@@ -72,36 +81,21 @@
 	return append(test.binaryDecorator.compilerProps(), &test.Properties)
 }
 
-func (test *testDecorator) getMutatedModuleSubName(moduleName string) string {
-	stem := String(test.baseCompiler.Properties.Stem)
-	if stem != "" && !strings.HasSuffix(moduleName, "_"+stem) {
-		// Avoid repeated suffix in the module name.
-		return "_" + stem
-	}
-	return ""
-}
-
 func (test *testDecorator) install(ctx ModuleContext, file android.Path) {
-	name := ctx.ModuleName()
-	path := test.baseCompiler.relativeInstallPath()
-	// on device, use mutated module name
-	name = name + test.getMutatedModuleSubName(name)
-	if !ctx.Device() { // on host, use mutated module name + arch type + stem name
-		stem := String(test.baseCompiler.Properties.Stem)
-		if stem == "" {
-			stem = name
-		}
-		name = filepath.Join(name, ctx.Arch().ArchType.String(), stem)
-	}
-	test.testConfig = tradefed.AutoGenRustTestConfig(ctx, name,
+	test.testConfig = tradefed.AutoGenRustTestConfig(ctx,
 		test.Properties.Test_config,
 		test.Properties.Test_config_template,
 		test.Properties.Test_suites,
+		nil,
 		test.Properties.Auto_gen_config)
+
 	// default relative install path is module name
-	if path == "" {
+	if !Bool(test.Properties.No_named_install_directory) {
 		test.baseCompiler.relative = ctx.ModuleName()
+	} else if String(test.baseCompiler.Properties.Relative_install_path) == "" {
+		ctx.PropertyErrorf("no_named_install_directory", "Module install directory may only be disabled if relative_install_path is set")
 	}
+
 	test.binaryDecorator.install(ctx, file)
 }
 
@@ -126,64 +120,3 @@
 	module, _ := NewRustTest(android.HostSupported)
 	return module.Init()
 }
-
-func (test *testDecorator) testPerSrc() bool {
-	return true
-}
-
-func (test *testDecorator) srcs() []string {
-	return test.binaryDecorator.Properties.Srcs
-}
-
-func (test *testDecorator) setSrc(name, src string) {
-	test.binaryDecorator.Properties.Srcs = []string{src}
-	test.baseCompiler.Properties.Stem = StringPtr(name)
-}
-
-func (test *testDecorator) unsetSrc() {
-	test.binaryDecorator.Properties.Srcs = nil
-	test.baseCompiler.Properties.Stem = StringPtr("")
-}
-
-type testPerSrc interface {
-	testPerSrc() bool
-	srcs() []string
-	setSrc(string, string)
-	unsetSrc()
-}
-
-var _ testPerSrc = (*testDecorator)(nil)
-
-func TestPerSrcMutator(mctx android.BottomUpMutatorContext) {
-	if m, ok := mctx.Module().(*Module); ok {
-		if test, ok := m.compiler.(testPerSrc); ok {
-			numTests := len(test.srcs())
-			if test.testPerSrc() && numTests > 0 {
-				if duplicate, found := android.CheckDuplicate(test.srcs()); found {
-					mctx.PropertyErrorf("srcs", "found a duplicate entry %q", duplicate)
-					return
-				}
-				// Rust compiler always compiles one source file at a time and
-				// uses the crate name as output file name.
-				// Cargo uses the test source file name as default crate name,
-				// but that can be redefined.
-				// So when there are multiple source files, the source file names will
-				// be the output file names, but when there is only one test file,
-				// use the crate name.
-				testNames := make([]string, numTests)
-				for i, src := range test.srcs() {
-					testNames[i] = strings.TrimSuffix(filepath.Base(src), filepath.Ext(src))
-				}
-				crateName := m.compiler.crateName()
-				if numTests == 1 && crateName != "" {
-					testNames[0] = crateName
-				}
-				// TODO(chh): Add an "all tests" variation like cc/test.go?
-				tests := mctx.CreateLocalVariations(testNames...)
-				for i, src := range test.srcs() {
-					tests[i].(*Module).compiler.(testPerSrc).setSrc(testNames[i], src)
-				}
-			}
-		}
-	}
-}
diff --git a/rust/test_test.go b/rust/test_test.go
index f131c6e..2382b18 100644
--- a/rust/test_test.go
+++ b/rust/test_test.go
@@ -19,45 +19,17 @@
 	"testing"
 )
 
-// Check if rust_test_host accepts multiple source files and applies --test flag.
 func TestRustTest(t *testing.T) {
 	ctx := testRust(t, `
 		rust_test_host {
 			name: "my_test",
-			srcs: ["foo.rs", "src/bar.rs"],
-			crate_name: "new_test", // not used for multiple source files
-			relative_install_path: "rust/my-test",
-		}`)
-
-	for _, name := range []string{"foo", "bar"} {
-		testingModule := ctx.ModuleForTests("my_test", "linux_glibc_x86_64_"+name)
-		testingBuildParams := testingModule.Output(name)
-		rustcFlags := testingBuildParams.Args["rustcFlags"]
-		if !strings.Contains(rustcFlags, "--test") {
-			t.Errorf("%v missing --test flag, rustcFlags: %#v", name, rustcFlags)
-		}
-		outPath := "/my_test/linux_glibc_x86_64_" + name + "/" + name
-		if !strings.Contains(testingBuildParams.Output.String(), outPath) {
-			t.Errorf("wrong output: %v  expect: %v", testingBuildParams.Output, outPath)
-		}
-	}
-}
-
-// crate_name is output file name, when there is only one source file.
-func TestRustTestSingleFile(t *testing.T) {
-	ctx := testRust(t, `
-		rust_test_host {
-			name: "my-test",
 			srcs: ["foo.rs"],
-			crate_name: "new_test",
-			relative_install_path: "my-pkg",
 		}`)
 
-	name := "new_test"
-	testingModule := ctx.ModuleForTests("my-test", "linux_glibc_x86_64_"+name)
-	outPath := "/my-test/linux_glibc_x86_64_" + name + "/" + name
-	testingBuildParams := testingModule.Output(name)
-	if !strings.Contains(testingBuildParams.Output.String(), outPath) {
-		t.Errorf("wrong output: %v  expect: %v", testingBuildParams.Output, outPath)
+	testingModule := ctx.ModuleForTests("my_test", "linux_glibc_x86_64")
+	expectedOut := "my_test/linux_glibc_x86_64/my_test"
+	outPath := testingModule.Output("my_test").Output.String()
+	if !strings.Contains(outPath, expectedOut) {
+		t.Errorf("wrong output path: %v;  expected: %v", outPath, expectedOut)
 	}
 }
diff --git a/rust/testing.go b/rust/testing.go
index 09008a8..4e186d3 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -97,9 +97,9 @@
 	ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) {
 		// rust mutators
 		ctx.BottomUp("rust_libraries", LibraryMutator).Parallel()
-		ctx.BottomUp("rust_unit_tests", TestPerSrcMutator).Parallel()
 		ctx.BottomUp("rust_begin", BeginMutator).Parallel()
 	})
+	ctx.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton)
 
 	return ctx
 }
diff --git a/scripts/Android.bp b/scripts/Android.bp
index e848b50..1f55030 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -148,3 +148,9 @@
     ],
     test_suites: ["general-tests"],
 }
+
+python_binary_host {
+    name: "lint-project-xml",
+    main: "lint-project-xml.py",
+    srcs: ["lint-project-xml.py"],
+}
diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh
index f836ea9..df763c8 100755
--- a/scripts/build-mainline-modules.sh
+++ b/scripts/build-mainline-modules.sh
@@ -20,6 +20,7 @@
   conscrypt-module-test-exports
   conscrypt-module-host-exports
   runtime-module-sdk
+  runtime-module-host-exports
 )
 
 # We want to create apex modules for all supported architectures.
diff --git a/scripts/lint-project-xml.py b/scripts/lint-project-xml.py
new file mode 100755
index 0000000..7ab4f01
--- /dev/null
+++ b/scripts/lint-project-xml.py
@@ -0,0 +1,213 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+"""This file generates project.xml and lint.xml files used to drive the Android Lint CLI tool."""
+
+import argparse
+
+
+def check_action(check_type):
+  """
+  Returns an action that appends a tuple of check_type and the argument to the dest.
+  """
+  class CheckAction(argparse.Action):
+    def __init__(self, option_strings, dest, nargs=None, **kwargs):
+      if nargs is not None:
+        raise ValueError("nargs must be None, was %s" % nargs)
+      super(CheckAction, self).__init__(option_strings, dest, **kwargs)
+    def __call__(self, parser, namespace, values, option_string=None):
+      checks = getattr(namespace, self.dest, [])
+      checks.append((check_type, values))
+      setattr(namespace, self.dest, checks)
+  return CheckAction
+
+
+def parse_args():
+  """Parse commandline arguments."""
+
+  def convert_arg_line_to_args(arg_line):
+    for arg in arg_line.split():
+      if arg.startswith('#'):
+        return
+      if not arg.strip():
+        continue
+      yield arg
+
+  parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
+  parser.convert_arg_line_to_args = convert_arg_line_to_args
+  parser.add_argument('--project_out', dest='project_out',
+                      help='file to which the project.xml contents will be written.')
+  parser.add_argument('--config_out', dest='config_out',
+                      help='file to which the lint.xml contents will be written.')
+  parser.add_argument('--name', dest='name',
+                      help='name of the module.')
+  parser.add_argument('--srcs', dest='srcs', action='append', default=[],
+                      help='file containing whitespace separated list of source files.')
+  parser.add_argument('--generated_srcs', dest='generated_srcs', action='append', default=[],
+                      help='file containing whitespace separated list of generated source files.')
+  parser.add_argument('--resources', dest='resources', action='append', default=[],
+                      help='file containing whitespace separated list of resource files.')
+  parser.add_argument('--classes', dest='classes', action='append', default=[],
+                      help='file containing the module\'s classes.')
+  parser.add_argument('--classpath', dest='classpath', action='append', default=[],
+                      help='file containing classes from dependencies.')
+  parser.add_argument('--extra_checks_jar', dest='extra_checks_jars', action='append', default=[],
+                      help='file containing extra lint checks.')
+  parser.add_argument('--manifest', dest='manifest',
+                      help='file containing the module\'s manifest.')
+  parser.add_argument('--merged_manifest', dest='merged_manifest',
+                      help='file containing merged manifest for the module and its dependencies.')
+  parser.add_argument('--library', dest='library', action='store_true',
+                      help='mark the module as a library.')
+  parser.add_argument('--test', dest='test', action='store_true',
+                      help='mark the module as a test.')
+  parser.add_argument('--cache_dir', dest='cache_dir',
+                      help='directory to use for cached file.')
+  group = parser.add_argument_group('check arguments', 'later arguments override earlier ones.')
+  group.add_argument('--fatal_check', dest='checks', action=check_action('fatal'), default=[],
+                     help='treat a lint issue as a fatal error.')
+  group.add_argument('--error_check', dest='checks', action=check_action('error'), default=[],
+                     help='treat a lint issue as an error.')
+  group.add_argument('--warning_check', dest='checks', action=check_action('warning'), default=[],
+                     help='treat a lint issue as a warning.')
+  group.add_argument('--disable_check', dest='checks', action=check_action('ignore'), default=[],
+                     help='disable a lint issue.')
+  return parser.parse_args()
+
+
+class NinjaRspFileReader:
+  """
+  Reads entries from a Ninja rsp file.  Ninja escapes any entries in the file that contain a
+  non-standard character by surrounding the whole entry with single quotes, and then replacing
+  any single quotes in the entry with the escape sequence '\''.
+  """
+
+  def __init__(self, filename):
+    self.f = open(filename, 'r')
+    self.r = self.character_reader(self.f)
+
+  def __iter__(self):
+    return self
+
+  def character_reader(self, f):
+    """Turns a file into a generator that returns one character at a time."""
+    while True:
+      c = f.read(1)
+      if c:
+        yield c
+      else:
+        return
+
+  def __next__(self):
+    entry = self.read_entry()
+    if entry:
+      return entry
+    else:
+      raise StopIteration
+
+  def read_entry(self):
+    c = next(self.r, "")
+    if not c:
+      return ""
+    elif c == "'":
+      return self.read_quoted_entry()
+    else:
+      entry = c
+      for c in self.r:
+        if c == " " or c == "\n":
+          break
+        entry += c
+      return entry
+
+  def read_quoted_entry(self):
+    entry = ""
+    for c in self.r:
+      if c == "'":
+        # Either the end of the quoted entry, or the beginning of an escape sequence, read the next
+        # character to find out.
+        c = next(self.r)
+        if not c or c == " " or c == "\n":
+          # End of the item
+          return entry
+        elif c == "\\":
+          # Escape sequence, expect a '
+          c = next(self.r)
+          if c != "'":
+            # Malformed escape sequence
+            raise "malformed escape sequence %s'\\%s" % (entry, c)
+          entry += "'"
+        else:
+          raise "malformed escape sequence %s'%s" % (entry, c)
+      else:
+        entry += c
+    raise "unterminated quoted entry %s" % entry
+
+
+def write_project_xml(f, args):
+  test_attr = "test='true' " if args.test else ""
+
+  f.write("<?xml version='1.0' encoding='utf-8'?>\n")
+  f.write("<project>\n")
+  f.write("  <module name='%s' android='true' %sdesugar='full' >\n" % (args.name, "library='true' " if args.library else ""))
+  if args.manifest:
+    f.write("    <manifest file='%s' %s/>\n" % (args.manifest, test_attr))
+  if args.merged_manifest:
+    f.write("    <merged-manifest file='%s' %s/>\n" % (args.merged_manifest, test_attr))
+  for src_file in args.srcs:
+    for src in NinjaRspFileReader(src_file):
+      f.write("    <src file='%s' %s/>\n" % (src, test_attr))
+  for src_file in args.generated_srcs:
+    for src in NinjaRspFileReader(src_file):
+      f.write("    <src file='%s' generated='true' %s/>\n" % (src, test_attr))
+  for res_file in args.resources:
+    for res in NinjaRspFileReader(res_file):
+      f.write("    <resource file='%s' %s/>\n" % (res, test_attr))
+  for classes in args.classes:
+    f.write("    <classes jar='%s' />\n" % classes)
+  for classpath in args.classpath:
+    f.write("    <classpath jar='%s' />\n" % classpath)
+  for extra in args.extra_checks_jars:
+    f.write("    <lint-checks jar='%s' />\n" % extra)
+  f.write("  </module>\n")
+  if args.cache_dir:
+    f.write("  <cache dir='%s'/>\n" % args.cache_dir)
+  f.write("</project>\n")
+
+
+def write_config_xml(f, args):
+  f.write("<?xml version='1.0' encoding='utf-8'?>\n")
+  f.write("<lint>\n")
+  for check in args.checks:
+    f.write("  <issue id='%s' severity='%s' />\n" % (check[1], check[0]))
+  f.write("</lint>\n")
+
+
+def main():
+  """Program entry point."""
+  args = parse_args()
+
+  if args.project_out:
+    with open(args.project_out, 'w') as f:
+      write_project_xml(f, args)
+
+  if args.config_out:
+    with open(args.config_out, 'w') as f:
+      write_config_xml(f, args)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/sdk/Android.bp b/sdk/Android.bp
new file mode 100644
index 0000000..cb93351
--- /dev/null
+++ b/sdk/Android.bp
@@ -0,0 +1,27 @@
+bootstrap_go_package {
+    name: "soong-sdk",
+    pkgPath: "android/soong/sdk",
+    deps: [
+        "blueprint",
+        "soong",
+        "soong-android",
+        "soong-apex",
+        "soong-cc",
+        "soong-java",
+    ],
+    srcs: [
+        "bp.go",
+        "exports.go",
+        "sdk.go",
+        "update.go",
+    ],
+    testSrcs: [
+        "bp_test.go",
+        "cc_sdk_test.go",
+        "exports_test.go",
+        "java_sdk_test.go",
+        "sdk_test.go",
+        "testing.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 4a09081..123fe70 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -1976,3 +1976,83 @@
 }
 `))
 }
+
+func TestUniqueHostSoname(t *testing.T) {
+	// b/145598135 - Generating host snapshots for anything other than linux is not supported.
+	SkipIfNotLinux(t)
+
+	result := testSdkWithCc(t, `
+		sdk {
+			name: "mysdk",
+			host_supported: true,
+			native_shared_libs: ["mylib"],
+		}
+
+		cc_library {
+			name: "mylib",
+			host_supported: true,
+			unique_host_soname: true,
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+    name: "mysdk_mylib@current",
+    sdk_member_name: "mylib",
+    host_supported: true,
+    installable: false,
+    unique_host_soname: true,
+    target: {
+        android_arm64: {
+            srcs: ["android/arm64/lib/mylib.so"],
+        },
+        android_arm: {
+            srcs: ["android/arm/lib/mylib.so"],
+        },
+        linux_glibc_x86_64: {
+            srcs: ["linux_glibc/x86_64/lib/mylib-host.so"],
+        },
+        linux_glibc_x86: {
+            srcs: ["linux_glibc/x86/lib/mylib-host.so"],
+        },
+    },
+}
+
+cc_prebuilt_library_shared {
+    name: "mylib",
+    prefer: false,
+    host_supported: true,
+    unique_host_soname: true,
+    target: {
+        android_arm64: {
+            srcs: ["android/arm64/lib/mylib.so"],
+        },
+        android_arm: {
+            srcs: ["android/arm/lib/mylib.so"],
+        },
+        linux_glibc_x86_64: {
+            srcs: ["linux_glibc/x86_64/lib/mylib-host.so"],
+        },
+        linux_glibc_x86: {
+            srcs: ["linux_glibc/x86/lib/mylib-host.so"],
+        },
+    },
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    host_supported: true,
+    native_shared_libs: ["mysdk_mylib@current"],
+}
+`),
+		checkAllCopyRules(`
+.intermediates/mylib/android_arm64_armv8-a_shared/mylib.so -> android/arm64/lib/mylib.so
+.intermediates/mylib/android_arm_armv7-a-neon_shared/mylib.so -> android/arm/lib/mylib.so
+.intermediates/mylib/linux_glibc_x86_64_shared/mylib-host.so -> linux_glibc/x86_64/lib/mylib-host.so
+.intermediates/mylib/linux_glibc_x86_shared/mylib-host.so -> linux_glibc/x86/lib/mylib-host.so
+`),
+	)
+}
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index f8e9fc1..77a4e94 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -34,6 +34,8 @@
 		"api/test-removed.txt":                              nil,
 		"api/module-lib-current.txt":                        nil,
 		"api/module-lib-removed.txt":                        nil,
+		"api/system-server-current.txt":                     nil,
+		"api/system-server-removed.txt":                     nil,
 		"build/soong/scripts/gen-java-current-api-files.sh": nil,
 	}
 
@@ -43,10 +45,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",
@@ -61,6 +63,9 @@
 	name: "android_module_lib_stubs_current",
 }
 java_import {
+	name: "android_system_server_stubs_current",
+}
+java_import {
 	name: "core-lambda-stubs", 
 	sdk_version: "none",
 }
@@ -1063,13 +1068,13 @@
 		checkAllCopyRules(`
 .intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
 .intermediates/myjavalib.stubs.system/android_common/javac/myjavalib.stubs.system.jar -> sdk_library/system/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt
-.intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_removed.txt -> sdk_library/system/myjavalib-removed.txt
 .intermediates/myjavalib.stubs.test/android_common/javac/myjavalib.stubs.test.jar -> sdk_library/test/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source.test/android_common/myjavalib.stubs.source.test_api.txt -> sdk_library/test/myjavalib.txt
-.intermediates/myjavalib.stubs.source.test/android_common/myjavalib.stubs.source.test_api.txt -> sdk_library/test/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.source.test/android_common/myjavalib.stubs.source.test_removed.txt -> sdk_library/test/myjavalib-removed.txt
 `),
 		checkMergeZips(
 			".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
@@ -1131,7 +1136,7 @@
 		checkAllCopyRules(`
 .intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
 `),
 		checkMergeZips(
 			".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
@@ -1195,7 +1200,7 @@
 		checkAllCopyRules(`
 .intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
 `),
 		checkMergeZips(
 			".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
@@ -1278,10 +1283,10 @@
 		checkAllCopyRules(`
 .intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
 .intermediates/myjavalib.stubs.system/android_common/javac/myjavalib.stubs.system.jar -> sdk_library/system/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt
-.intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_removed.txt -> sdk_library/system/myjavalib-removed.txt
 `),
 		checkMergeZips(
 			".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
@@ -1382,13 +1387,13 @@
 		checkAllCopyRules(`
 .intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
 .intermediates/myjavalib.stubs.system/android_common/javac/myjavalib.stubs.system.jar -> sdk_library/system/myjavalib-stubs.jar
 .intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib.txt
-.intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_api.txt -> sdk_library/system/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.source.system/android_common/myjavalib.stubs.source.system_removed.txt -> sdk_library/system/myjavalib-removed.txt
 .intermediates/myjavalib.stubs.module_lib/android_common/javac/myjavalib.stubs.module_lib.jar -> sdk_library/module-lib/myjavalib-stubs.jar
 .intermediates/myjavalib.api.module_lib/android_common/myjavalib.api.module_lib_api.txt -> sdk_library/module-lib/myjavalib.txt
-.intermediates/myjavalib.api.module_lib/android_common/myjavalib.api.module_lib_api.txt -> sdk_library/module-lib/myjavalib-removed.txt
+.intermediates/myjavalib.api.module_lib/android_common/myjavalib.api.module_lib_removed.txt -> sdk_library/module-lib/myjavalib-removed.txt
 `),
 		checkMergeZips(
 			".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
@@ -1398,6 +1403,93 @@
 	)
 }
 
+func TestSnapshotWithJavaSdkLibrary_SystemServer(t *testing.T) {
+	result := testSdkWithJava(t, `
+		sdk {
+			name: "mysdk",
+			java_sdk_libs: ["myjavalib"],
+		}
+
+		java_sdk_library {
+			name: "myjavalib",
+			apex_available: ["//apex_available:anyapex"],
+			srcs: ["Test.java"],
+			sdk_version: "current",
+			public: {
+				enabled: true,
+			},
+			system_server: {
+				enabled: true,
+			},
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+java_sdk_library_import {
+    name: "mysdk_myjavalib@current",
+    sdk_member_name: "myjavalib",
+    apex_available: ["//apex_available:anyapex"],
+    shared_library: true,
+    public: {
+        jars: ["sdk_library/public/myjavalib-stubs.jar"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
+        current_api: "sdk_library/public/myjavalib.txt",
+        removed_api: "sdk_library/public/myjavalib-removed.txt",
+        sdk_version: "current",
+    },
+    system_server: {
+        jars: ["sdk_library/system-server/myjavalib-stubs.jar"],
+        stub_srcs: ["sdk_library/system-server/myjavalib_stub_sources"],
+        current_api: "sdk_library/system-server/myjavalib.txt",
+        removed_api: "sdk_library/system-server/myjavalib-removed.txt",
+        sdk_version: "system_server_current",
+    },
+}
+
+java_sdk_library_import {
+    name: "myjavalib",
+    prefer: false,
+    apex_available: ["//apex_available:anyapex"],
+    shared_library: true,
+    public: {
+        jars: ["sdk_library/public/myjavalib-stubs.jar"],
+        stub_srcs: ["sdk_library/public/myjavalib_stub_sources"],
+        current_api: "sdk_library/public/myjavalib.txt",
+        removed_api: "sdk_library/public/myjavalib-removed.txt",
+        sdk_version: "current",
+    },
+    system_server: {
+        jars: ["sdk_library/system-server/myjavalib-stubs.jar"],
+        stub_srcs: ["sdk_library/system-server/myjavalib_stub_sources"],
+        current_api: "sdk_library/system-server/myjavalib.txt",
+        removed_api: "sdk_library/system-server/myjavalib-removed.txt",
+        sdk_version: "system_server_current",
+    },
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    java_sdk_libs: ["mysdk_myjavalib@current"],
+}
+`),
+		checkAllCopyRules(`
+.intermediates/myjavalib.stubs/android_common/javac/myjavalib.stubs.jar -> sdk_library/public/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_api.txt -> sdk_library/public/myjavalib.txt
+.intermediates/myjavalib.stubs.source/android_common/myjavalib.stubs.source_removed.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib.stubs.system_server/android_common/javac/myjavalib.stubs.system_server.jar -> sdk_library/system-server/myjavalib-stubs.jar
+.intermediates/myjavalib.stubs.source.system_server/android_common/myjavalib.stubs.source.system_server_api.txt -> sdk_library/system-server/myjavalib.txt
+.intermediates/myjavalib.stubs.source.system_server/android_common/myjavalib.stubs.source.system_server_removed.txt -> sdk_library/system-server/myjavalib-removed.txt
+`),
+		checkMergeZips(
+			".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
+			".intermediates/mysdk/common_os/tmp/sdk_library/system-server/myjavalib_stub_sources.zip",
+		),
+	)
+}
+
 func TestSnapshotWithJavaSdkLibrary_NamingScheme(t *testing.T) {
 	result := testSdkWithJava(t, `
 		sdk {
@@ -1459,7 +1551,7 @@
 		checkAllCopyRules(`
 .intermediates/myjavalib-stubs-publicapi/android_common/javac/myjavalib-stubs-publicapi.jar -> sdk_library/public/myjavalib-stubs.jar
 .intermediates/myjavalib-stubs-srcs-publicapi/android_common/myjavalib-stubs-srcs-publicapi_api.txt -> sdk_library/public/myjavalib.txt
-.intermediates/myjavalib-stubs-srcs-publicapi/android_common/myjavalib-stubs-srcs-publicapi_api.txt -> sdk_library/public/myjavalib-removed.txt
+.intermediates/myjavalib-stubs-srcs-publicapi/android_common/myjavalib-stubs-srcs-publicapi_removed.txt -> sdk_library/public/myjavalib-removed.txt
 `),
 		checkMergeZips(
 			".intermediates/mysdk/common_os/tmp/sdk_library/public/myjavalib_stub_sources.zip",
diff --git a/sdk/update.go b/sdk/update.go
index 1ba5806..8241151 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -22,6 +22,7 @@
 
 	"android/soong/apex"
 	"android/soong/cc"
+
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
 
@@ -700,8 +701,8 @@
 	if apexAware, ok := variant.(interface{ ApexAvailable() []string }); ok {
 		apexAvailable := apexAware.ApexAvailable()
 
-		// Add in any white listed apex available settings.
-		apexAvailable = append(apexAvailable, apex.WhitelistedApexAvailable(member.Name())...)
+		// Add in any baseline apex available settings.
+		apexAvailable = append(apexAvailable, apex.BaselineApexAvailable(member.Name())...)
 
 		if len(apexAvailable) > 0 {
 			// Remove duplicates and sort.
diff --git a/sh/Android.bp b/sh/Android.bp
new file mode 100644
index 0000000..0f40c5f
--- /dev/null
+++ b/sh/Android.bp
@@ -0,0 +1,17 @@
+bootstrap_go_package {
+    name: "soong-sh",
+    pkgPath: "android/soong/sh",
+    deps: [
+        "blueprint",
+        "soong",
+        "soong-android",
+        "soong-tradefed",
+    ],
+    srcs: [
+        "sh_binary.go",
+    ],
+    testSrcs: [
+        "sh_binary_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
new file mode 100644
index 0000000..7bb267d
--- /dev/null
+++ b/sh/sh_binary.go
@@ -0,0 +1,293 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package sh
+
+import (
+	"fmt"
+	"path/filepath"
+	"strings"
+
+	"github.com/google/blueprint/proptools"
+
+	"android/soong/android"
+	"android/soong/tradefed"
+)
+
+// sh_binary is for shell scripts (and batch files) that are installed as
+// executable files into .../bin/
+//
+// Do not use them for prebuilt C/C++/etc files.  Use cc_prebuilt_binary
+// instead.
+
+var pctx = android.NewPackageContext("android/soong/sh")
+
+func init() {
+	pctx.Import("android/soong/android")
+
+	android.RegisterModuleType("sh_binary", ShBinaryFactory)
+	android.RegisterModuleType("sh_binary_host", ShBinaryHostFactory)
+	android.RegisterModuleType("sh_test", ShTestFactory)
+	android.RegisterModuleType("sh_test_host", ShTestHostFactory)
+}
+
+type shBinaryProperties struct {
+	// Source file of this prebuilt.
+	Src *string `android:"path,arch_variant"`
+
+	// optional subdirectory under which this file is installed into
+	Sub_dir *string `android:"arch_variant"`
+
+	// optional name for the installed file. If unspecified, name of the module is used as the file name
+	Filename *string `android:"arch_variant"`
+
+	// when set to true, and filename property is not set, the name for the installed file
+	// is the same as the file name of the source file.
+	Filename_from_src *bool `android:"arch_variant"`
+
+	// Whether this module is directly installable to one of the partitions. Default: true.
+	Installable *bool
+
+	// install symlinks to the binary
+	Symlinks []string `android:"arch_variant"`
+}
+
+type TestProperties struct {
+	// list of compatibility suites (for example "cts", "vts") that the module should be
+	// installed into.
+	Test_suites []string `android:"arch_variant"`
+
+	// the name of the test configuration (for example "AndroidTest.xml") that should be
+	// installed with the module.
+	Test_config *string `android:"path,arch_variant"`
+
+	// 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 {
+	android.ModuleBase
+
+	properties shBinaryProperties
+
+	sourceFilePath android.Path
+	outputFilePath android.OutputPath
+	installedFile  android.InstallPath
+}
+
+var _ android.HostToolProvider = (*ShBinary)(nil)
+
+type ShTest struct {
+	ShBinary
+
+	testProperties TestProperties
+
+	data       android.Paths
+	testConfig android.Path
+}
+
+func (s *ShBinary) HostToolPath() android.OptionalPath {
+	return android.OptionalPathForPath(s.installedFile)
+}
+
+func (s *ShBinary) DepsMutator(ctx android.BottomUpMutatorContext) {
+	if s.properties.Src == nil {
+		ctx.PropertyErrorf("src", "missing prebuilt source file")
+	}
+}
+
+func (s *ShBinary) OutputFile() android.OutputPath {
+	return s.outputFilePath
+}
+
+func (s *ShBinary) SubDir() string {
+	return proptools.String(s.properties.Sub_dir)
+}
+
+func (s *ShBinary) Installable() bool {
+	return s.properties.Installable == nil || proptools.Bool(s.properties.Installable)
+}
+
+func (s *ShBinary) Symlinks() []string {
+	return s.properties.Symlinks
+}
+
+func (s *ShBinary) generateAndroidBuildActions(ctx android.ModuleContext) {
+	s.sourceFilePath = android.PathForModuleSrc(ctx, proptools.String(s.properties.Src))
+	filename := proptools.String(s.properties.Filename)
+	filename_from_src := proptools.Bool(s.properties.Filename_from_src)
+	if filename == "" {
+		if filename_from_src {
+			filename = s.sourceFilePath.Base()
+		} else {
+			filename = ctx.ModuleName()
+		}
+	} else if filename_from_src {
+		ctx.PropertyErrorf("filename_from_src", "filename is set. filename_from_src can't be true")
+		return
+	}
+	s.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath
+
+	// This ensures that outputFilePath has the correct name for others to
+	// use, as the source file may have a different name.
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   android.CpExecutable,
+		Output: s.outputFilePath,
+		Input:  s.sourceFilePath,
+	})
+}
+
+func (s *ShBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	s.generateAndroidBuildActions(ctx)
+	installDir := android.PathForModuleInstall(ctx, "bin", proptools.String(s.properties.Sub_dir))
+	s.installedFile = ctx.InstallExecutable(installDir, s.outputFilePath.Base(), s.outputFilePath)
+}
+
+func (s *ShBinary) AndroidMkEntries() []android.AndroidMkEntries {
+	return []android.AndroidMkEntries{android.AndroidMkEntries{
+		Class:      "EXECUTABLES",
+		OutputFile: android.OptionalPathForPath(s.outputFilePath),
+		Include:    "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(entries *android.AndroidMkEntries) {
+				s.customAndroidMkEntries(entries)
+			},
+		},
+	}}
+}
+
+func (s *ShBinary) customAndroidMkEntries(entries *android.AndroidMkEntries) {
+	entries.SetString("LOCAL_MODULE_RELATIVE_PATH", proptools.String(s.properties.Sub_dir))
+	entries.SetString("LOCAL_MODULE_SUFFIX", "")
+	entries.SetString("LOCAL_MODULE_STEM", s.outputFilePath.Rel())
+	if len(s.properties.Symlinks) > 0 {
+		entries.SetString("LOCAL_MODULE_SYMLINKS", strings.Join(s.properties.Symlinks, " "))
+	}
+}
+
+func (s *ShTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	s.ShBinary.generateAndroidBuildActions(ctx)
+	testDir := "nativetest"
+	if ctx.Target().Arch.ArchType.Multilib == "lib64" {
+		testDir = "nativetest64"
+	}
+	if ctx.Target().NativeBridge == android.NativeBridgeEnabled {
+		testDir = filepath.Join(testDir, ctx.Target().NativeBridgeRelativePath)
+	} else if !ctx.Host() && ctx.Config().HasMultilibConflict(ctx.Arch().ArchType) {
+		testDir = filepath.Join(testDir, ctx.Arch().ArchType.String())
+	}
+	installDir := android.PathForModuleInstall(ctx, testDir, proptools.String(s.properties.Sub_dir))
+	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 {
+	return true
+}
+
+func (s *ShTest) AndroidMkEntries() []android.AndroidMkEntries {
+	return []android.AndroidMkEntries{android.AndroidMkEntries{
+		Class:      "NATIVE_TESTS",
+		OutputFile: android.OptionalPathForPath(s.outputFilePath),
+		Include:    "$(BUILD_SYSTEM)/soong_cc_prebuilt.mk",
+		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
+			func(entries *android.AndroidMkEntries) {
+				s.customAndroidMkEntries(entries)
+
+				entries.AddStrings("LOCAL_COMPATIBILITY_SUITE", s.testProperties.Test_suites...)
+				if s.testConfig != nil {
+					entries.SetPath("LOCAL_FULL_TEST_CONFIG", s.testConfig)
+				}
+				for _, d := range s.data {
+					rel := d.Rel()
+					path := d.String()
+					if !strings.HasSuffix(path, rel) {
+						panic(fmt.Errorf("path %q does not end with %q", path, rel))
+					}
+					path = strings.TrimSuffix(path, rel)
+					entries.AddStrings("LOCAL_TEST_DATA", path+":"+rel)
+				}
+			},
+		},
+	}}
+}
+
+func InitShBinaryModule(s *ShBinary) {
+	s.AddProperties(&s.properties)
+}
+
+// sh_binary is for a shell script or batch file to be installed as an
+// executable binary to <partition>/bin.
+func ShBinaryFactory() android.Module {
+	module := &ShBinary{}
+	InitShBinaryModule(module)
+	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst)
+	return module
+}
+
+// sh_binary_host is for a shell script to be installed as an executable binary
+// to $(HOST_OUT)/bin.
+func ShBinaryHostFactory() android.Module {
+	module := &ShBinary{}
+	InitShBinaryModule(module)
+	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
+	return module
+}
+
+// sh_test defines a shell script based test module.
+func ShTestFactory() android.Module {
+	module := &ShTest{}
+	InitShBinaryModule(&module.ShBinary)
+	module.AddProperties(&module.testProperties)
+
+	android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst)
+	return module
+}
+
+// sh_test_host defines a shell script based test module that runs on a host.
+func ShTestHostFactory() android.Module {
+	module := &ShTest{}
+	InitShBinaryModule(&module.ShBinary)
+	module.AddProperties(&module.testProperties)
+
+	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst)
+	return module
+}
+
+var Bool = proptools.Bool
diff --git a/android/sh_binary_test.go b/sh/sh_binary_test.go
similarity index 64%
rename from android/sh_binary_test.go
rename to sh/sh_binary_test.go
index 137e773..6c0d96a 100644
--- a/android/sh_binary_test.go
+++ b/sh/sh_binary_test.go
@@ -1,27 +1,56 @@
-package android
+package sh
 
 import (
+	"io/ioutil"
+	"os"
 	"reflect"
 	"testing"
+
+	"android/soong/android"
 )
 
-func testShBinary(t *testing.T, bp string) (*TestContext, Config) {
+var buildDir string
+
+func setUp() {
+	var err error
+	buildDir, err = ioutil.TempDir("", "soong_sh_test")
+	if err != nil {
+		panic(err)
+	}
+}
+
+func tearDown() {
+	os.RemoveAll(buildDir)
+}
+
+func TestMain(m *testing.M) {
+	run := func() int {
+		setUp()
+		defer tearDown()
+
+		return m.Run()
+	}
+
+	os.Exit(run())
+}
+
+func testShBinary(t *testing.T, bp string) (*android.TestContext, android.Config) {
 	fs := map[string][]byte{
 		"test.sh":            nil,
 		"testdata/data1":     nil,
 		"testdata/sub/data2": nil,
 	}
 
-	config := TestArchConfig(buildDir, nil, bp, fs)
+	config := android.TestArchConfig(buildDir, nil, bp, fs)
 
-	ctx := NewTestArchContext()
+	ctx := android.NewTestArchContext()
 	ctx.RegisterModuleType("sh_test", ShTestFactory)
 	ctx.RegisterModuleType("sh_test_host", ShTestHostFactory)
 	ctx.Register(config)
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})
-	FailIfErrored(t, errs)
+	android.FailIfErrored(t, errs)
 	_, errs = ctx.PrepareBuildActions(config)
-	FailIfErrored(t, errs)
+	android.FailIfErrored(t, errs)
 
 	return ctx, config
 }
@@ -41,7 +70,7 @@
 
 	mod := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest)
 
-	entries := AndroidMkEntriesForTest(t, config, "", mod)[0]
+	entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0]
 	expected := []string{":testdata/data1", ":testdata/sub/data2"}
 	actual := entries.EntryMap["LOCAL_TEST_DATA"]
 	if !reflect.DeepEqual(expected, actual) {
@@ -62,7 +91,7 @@
 		}
 	`)
 
-	buildOS := BuildOs.String()
+	buildOS := android.BuildOs.String()
 	mod := ctx.ModuleForTests("foo", buildOS+"_x86_64").Module().(*ShTest)
 	if !mod.Host() {
 		t.Errorf("host bit is not set for a sh_test_host module.")
diff --git a/shared/Android.bp b/shared/Android.bp
new file mode 100644
index 0000000..07dfe11
--- /dev/null
+++ b/shared/Android.bp
@@ -0,0 +1,7 @@
+bootstrap_go_package {
+    name: "soong-shared",
+    pkgPath: "android/soong/shared",
+    srcs: [
+        "paths.go",
+    ],
+}
diff --git a/sysprop/Android.bp b/sysprop/Android.bp
new file mode 100644
index 0000000..48094f1
--- /dev/null
+++ b/sysprop/Android.bp
@@ -0,0 +1,18 @@
+bootstrap_go_package {
+    name: "soong-sysprop",
+    pkgPath: "android/soong/sysprop",
+    deps: [
+        "blueprint",
+        "soong",
+        "soong-android",
+        "soong-cc",
+        "soong-java",
+    ],
+    srcs: [
+        "sysprop_library.go",
+    ],
+    testSrcs: [
+        "sysprop_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/tradefed/Android.bp b/tradefed/Android.bp
new file mode 100644
index 0000000..6e5e533
--- /dev/null
+++ b/tradefed/Android.bp
@@ -0,0 +1,14 @@
+bootstrap_go_package {
+    name: "soong-tradefed",
+    pkgPath: "android/soong/tradefed",
+    deps: [
+        "blueprint",
+        "soong-android",
+    ],
+    srcs: [
+        "autogen.go",
+        "config.go",
+        "makevars.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index be44cac..1cb874d 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, name, 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)
@@ -200,19 +220,20 @@
 	return path
 }
 
-func AutoGenRustTestConfig(ctx android.ModuleContext, name string, testConfigProp *string,
-	testConfigTemplateProp *string, testSuites []string, autoGenConfig *bool) android.Path {
+func AutoGenRustTestConfig(ctx android.ModuleContext, testConfigProp *string,
+	testConfigTemplateProp *string, testSuites []string, config []Config, autoGenConfig *bool) android.Path {
 	path, autogenPath := testConfigPath(ctx, testConfigProp, testSuites, autoGenConfig, testConfigTemplateProp)
 	if autogenPath != nil {
-		templatePathString := "${RustHostTestConfigTemplate}"
-		if ctx.Device() {
-			templatePathString = "${RustDeviceTestConfigTemplate}"
-		}
 		templatePath := getTestConfigTemplate(ctx, testConfigTemplateProp)
 		if templatePath.Valid() {
-			templatePathString = templatePath.String()
+			autogenTemplate(ctx, autogenPath, templatePath.String(), config)
+		} else {
+			if ctx.Device() {
+				autogenTemplate(ctx, autogenPath, "${RustDeviceTestConfigTemplate}", config)
+			} else {
+				autogenTemplate(ctx, autogenPath, "${RustHostTestConfigTemplate}", config)
+			}
 		}
-		autogenTemplateWithName(ctx, name, autogenPath, templatePathString, nil)
 		return autogenPath
 	}
 	return path
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/Android.bp b/ui/build/Android.bp
index 2a5a51a..0a0bb16 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -56,12 +56,14 @@
         "signal.go",
         "soong.go",
         "test_build.go",
+        "upload.go",
         "util.go",
     ],
     testSrcs: [
         "cleanbuild_test.go",
         "config_test.go",
         "environment_test.go",
+        "upload_test.go",
         "util_test.go",
         "proc_sync_test.go",
     ],
diff --git a/ui/build/config.go b/ui/build/config.go
index d66a86c..c4bbad7 100644
--- a/ui/build/config.go
+++ b/ui/build/config.go
@@ -592,6 +592,7 @@
 	c.environ.Set("TARGET_BUILD_VARIANT", variant)
 	c.environ.Set("TARGET_BUILD_TYPE", "release")
 	c.environ.Unset("TARGET_BUILD_APPS")
+	c.environ.Unset("TARGET_BUILD_UNBUNDLED")
 }
 
 // Tapas configures the environment to build one or more unbundled apps,
@@ -961,3 +962,14 @@
 func (c *configImpl) IsPdkBuild() bool {
 	return c.pdkBuild
 }
+
+func (c *configImpl) BuildDateTime() string {
+	return c.buildDateTime
+}
+
+func (c *configImpl) MetricsUploaderApp() string {
+	if p, ok := c.environ.Get("ANDROID_ENABLE_METRICS_UPLOAD"); ok {
+		return p
+	}
+	return ""
+}
diff --git a/ui/build/config_test.go b/ui/build/config_test.go
index df618c4..7b14c47 100644
--- a/ui/build/config_test.go
+++ b/ui/build/config_test.go
@@ -26,6 +26,7 @@
 	"testing"
 
 	"android/soong/ui/logger"
+	"android/soong/ui/status"
 )
 
 func testContext() Context {
@@ -33,6 +34,7 @@
 		Context: context.Background(),
 		Logger:  logger.New(&bytes.Buffer{}),
 		Writer:  &bytes.Buffer{},
+		Status:  &status.Status{},
 	}}
 }
 
diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go
index a559330..e229856 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
@@ -142,6 +143,7 @@
 	"TARGET_BUILD_VARIANT",
 	"TARGET_BUILD_TYPE",
 	"TARGET_BUILD_APPS",
+	"TARGET_BUILD_UNBUNDLED",
 	"TARGET_ARCH",
 	"TARGET_ARCH_VARIANT",
 	"TARGET_CPU_VARIANT",
@@ -186,6 +188,7 @@
 		"TARGET_PRODUCT",
 		"TARGET_BUILD_VARIANT",
 		"TARGET_BUILD_APPS",
+		"TARGET_BUILD_UNBUNDLED",
 
 		// compiler wrappers set up by make
 		"CC_WRAPPER",
@@ -253,7 +256,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)
diff --git a/ui/build/upload.go b/ui/build/upload.go
new file mode 100644
index 0000000..3a23a80
--- /dev/null
+++ b/ui/build/upload.go
@@ -0,0 +1,113 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package build
+
+// This file contains the functionality to upload data from one location to
+// another.
+
+import (
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"time"
+
+	"android/soong/ui/metrics"
+	"github.com/golang/protobuf/proto"
+
+	upload_proto "android/soong/ui/metrics/upload_proto"
+)
+
+const (
+	uploadPbFilename = ".uploader.pb"
+)
+
+var (
+	// For testing purpose
+	getTmpDir = ioutil.TempDir
+)
+
+// UploadMetrics uploads a set of metrics files to a server for analysis. An
+// uploader full path is required to be specified in order to upload the set
+// of metrics files. This is accomplished by defining the ANDROID_ENABLE_METRICS_UPLOAD
+// environment variable. The metrics files are copied to a temporary directory
+// and the uploader is then executed in the background to allow the user to continue
+// working.
+func UploadMetrics(ctx Context, config Config, forceDumbOutput bool, buildStartedMilli int64, files ...string) {
+	ctx.BeginTrace(metrics.RunSetupTool, "upload_metrics")
+	defer ctx.EndTrace()
+
+	uploader := config.MetricsUploaderApp()
+	// No metrics to upload if the path to the uploader was not specified.
+	if uploader == "" {
+		return
+	}
+
+	// Some files may not exist. For example, build errors protobuf file
+	// may not exist since the build was successful.
+	var metricsFiles []string
+	for _, f := range files {
+		if _, err := os.Stat(f); err == nil {
+			metricsFiles = append(metricsFiles, f)
+		}
+	}
+
+	if len(metricsFiles) == 0 {
+		return
+	}
+
+	// The temporary directory cannot be deleted as the metrics uploader is started
+	// in the background and requires to exist until the operation is done. The
+	// uploader can delete the directory as it is specified in the upload proto.
+	tmpDir, err := getTmpDir("", "upload_metrics")
+	if err != nil {
+		ctx.Fatalf("failed to create a temporary directory to store the list of metrics files: %v\n", err)
+	}
+
+	for i, src := range metricsFiles {
+		dst := filepath.Join(tmpDir, filepath.Base(src))
+		if _, err := copyFile(src, dst); err != nil {
+			ctx.Fatalf("failed to copy %q to %q: %v\n", src, dst, err)
+		}
+		metricsFiles[i] = dst
+	}
+
+	// For platform builds, the branch and target name is hardcoded to specific
+	// values for later extraction of the metrics in the data metrics pipeline.
+	data, err := proto.Marshal(&upload_proto.Upload{
+		CreationTimestampMs:   proto.Uint64(uint64(buildStartedMilli)),
+		CompletionTimestampMs: proto.Uint64(uint64(time.Now().UnixNano() / int64(time.Millisecond))),
+		BranchName:            proto.String("developer-metrics"),
+		TargetName:            proto.String("platform-build-systems-metrics"),
+		MetricsFiles:          metricsFiles,
+		DirectoriesToDelete:   []string{tmpDir},
+	})
+	if err != nil {
+		ctx.Fatalf("failed to marshal metrics upload proto buffer message: %v\n", err)
+	}
+
+	pbFile := filepath.Join(tmpDir, uploadPbFilename)
+	if err := ioutil.WriteFile(pbFile, data, 0644); err != nil {
+		ctx.Fatalf("failed to write the marshaled metrics upload protobuf to %q: %v\n", pbFile, err)
+	}
+
+	// Start the uploader in the background as it takes several milliseconds to start the uploader
+	// and prepare the metrics for upload. This affects small commands like "lunch".
+	cmd := Command(ctx, config, "upload metrics", uploader, "--upload-metrics", pbFile)
+	if forceDumbOutput {
+		cmd.RunOrFatal()
+	} else {
+		cmd.RunAndStreamOrFatal()
+	}
+}
diff --git a/ui/build/upload_test.go b/ui/build/upload_test.go
new file mode 100644
index 0000000..c812730
--- /dev/null
+++ b/ui/build/upload_test.go
@@ -0,0 +1,158 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package build
+
+import (
+	"errors"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"testing"
+	"time"
+
+	"android/soong/ui/logger"
+)
+
+func TestUploadMetrics(t *testing.T) {
+	ctx := testContext()
+	tests := []struct {
+		description string
+		uploader    string
+		createFiles bool
+		files       []string
+	}{{
+		description: "ANDROID_ENABLE_METRICS_UPLOAD not set",
+	}, {
+		description: "no metrics files to upload",
+		uploader:    "fake",
+	}, {
+		description: "non-existent metrics files no upload",
+		uploader:    "fake",
+		files:       []string{"metrics_file_1", "metrics_file_2", "metrics_file_3"},
+	}, {
+		description: "trigger upload",
+		uploader:    "echo",
+		createFiles: true,
+		files:       []string{"metrics_file_1", "metrics_file_2"},
+	}}
+
+	for _, tt := range tests {
+		t.Run(tt.description, func(t *testing.T) {
+			defer logger.Recover(func(err error) {
+				t.Fatalf("got unexpected error: %v", err)
+			})
+
+			outDir, err := ioutil.TempDir("", "")
+			if err != nil {
+				t.Fatalf("failed to create out directory: %v", outDir)
+			}
+			defer os.RemoveAll(outDir)
+
+			// Supply our own getTmpDir to delete the temp dir once the test is done.
+			orgGetTmpDir := getTmpDir
+			getTmpDir = func(string, string) (string, error) {
+				retDir := filepath.Join(outDir, "tmp_upload_dir")
+				if err := os.Mkdir(retDir, 0755); err != nil {
+					t.Fatalf("failed to create temporary directory %q: %v", retDir, err)
+				}
+				return retDir, nil
+			}
+			defer func() { getTmpDir = orgGetTmpDir }()
+
+			metricsUploadDir := filepath.Join(outDir, ".metrics_uploader")
+			if err := os.Mkdir(metricsUploadDir, 0755); err != nil {
+				t.Fatalf("failed to create %q directory for oauth valid check: %v", metricsUploadDir, err)
+			}
+
+			var metricsFiles []string
+			if tt.createFiles {
+				for _, f := range tt.files {
+					filename := filepath.Join(outDir, f)
+					metricsFiles = append(metricsFiles, filename)
+					if err := ioutil.WriteFile(filename, []byte("test file"), 0644); err != nil {
+						t.Fatalf("failed to create a fake metrics file %q for uploading: %v", filename, err)
+					}
+				}
+			}
+
+			config := Config{&configImpl{
+				environ: &Environment{
+					"OUT_DIR=" + outDir,
+					"ANDROID_ENABLE_METRICS_UPLOAD=" + tt.uploader,
+				},
+				buildDateTime: strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10),
+			}}
+
+			UploadMetrics(ctx, config, false, 1591031903, metricsFiles...)
+		})
+	}
+}
+
+func TestUploadMetricsErrors(t *testing.T) {
+	ctx := testContext()
+	tests := []struct {
+		description string
+		tmpDir      string
+		tmpDirErr   error
+		expectedErr string
+	}{{
+		description: "getTmpDir returned error",
+		tmpDirErr:   errors.New("getTmpDir failed"),
+		expectedErr: "getTmpDir failed",
+	}, {
+		description: "copyFile operation error",
+		tmpDir:      "/fake_dir",
+		expectedErr: "failed to copy",
+	}}
+
+	for _, tt := range tests {
+		t.Run(tt.description, func(t *testing.T) {
+			defer logger.Recover(func(err error) {
+				got := err.Error()
+				if !strings.Contains(got, tt.expectedErr) {
+					t.Errorf("got %q, want %q to be contained in error", got, tt.expectedErr)
+				}
+			})
+
+			outDir, err := ioutil.TempDir("", "")
+			if err != nil {
+				t.Fatalf("failed to create out directory: %v", outDir)
+			}
+			defer os.RemoveAll(outDir)
+
+			orgGetTmpDir := getTmpDir
+			getTmpDir = func(string, string) (string, error) {
+				return tt.tmpDir, tt.tmpDirErr
+			}
+			defer func() { getTmpDir = orgGetTmpDir }()
+
+			metricsFile := filepath.Join(outDir, "metrics_file_1")
+			if err := ioutil.WriteFile(metricsFile, []byte("test file"), 0644); err != nil {
+				t.Fatalf("failed to create a fake metrics file %q for uploading: %v", metricsFile, err)
+			}
+
+			config := Config{&configImpl{
+				environ: &Environment{
+					"ANDROID_ENABLE_METRICS_UPLOAD=fake",
+					"OUT_DIR=/bad",
+				}}}
+
+			UploadMetrics(ctx, config, true, 1591031903, metricsFile)
+			t.Errorf("got nil, expecting %q as a failure", tt.expectedErr)
+		})
+	}
+}
diff --git a/ui/build/util.go b/ui/build/util.go
index 75e6753..d44cd6d 100644
--- a/ui/build/util.go
+++ b/ui/build/util.go
@@ -15,6 +15,7 @@
 package build
 
 import (
+	"io"
 	"os"
 	"path/filepath"
 	"strings"
@@ -124,3 +125,20 @@
 	}
 	return str[:idx], str[idx+1:], true
 }
+
+// copyFile copies a file from src to dst. filepath.Dir(dst) must exist.
+func copyFile(src, dst string) (int64, error) {
+	source, err := os.Open(src)
+	if err != nil {
+		return 0, err
+	}
+	defer source.Close()
+
+	destination, err := os.Create(dst)
+	if err != nil {
+		return 0, err
+	}
+	defer destination.Close()
+
+	return io.Copy(destination, source)
+}
diff --git a/ui/build/util_test.go b/ui/build/util_test.go
index 89bfc77..b22e997 100644
--- a/ui/build/util_test.go
+++ b/ui/build/util_test.go
@@ -15,6 +15,7 @@
 package build
 
 import (
+	"bytes"
 	"io/ioutil"
 	"os"
 	"path/filepath"
@@ -49,3 +50,72 @@
 
 	ensureEmptyDirectoriesExist(ctx, filepath.Join(tmpDir, "a"))
 }
+
+func TestCopyFile(t *testing.T) {
+	tmpDir, err := ioutil.TempDir("", "test_copy_file")
+	if err != nil {
+		t.Fatalf("failed to create temporary directory to hold test text files: %v", err)
+	}
+	defer os.Remove(tmpDir)
+
+	data := []byte("fake data")
+	src := filepath.Join(tmpDir, "src.txt")
+	if err := ioutil.WriteFile(src, data, 0755); err != nil {
+		t.Fatalf("failed to create a src file %q for copying: %v", src, err)
+	}
+
+	dst := filepath.Join(tmpDir, "dst.txt")
+
+	l, err := copyFile(src, dst)
+	if err != nil {
+		t.Fatalf("got %v, expecting nil error on copyFile operation", err)
+	}
+
+	if l != int64(len(data)) {
+		t.Errorf("got %d, expecting %d for copied bytes", l, len(data))
+	}
+
+	dstData, err := ioutil.ReadFile(dst)
+	if err != nil {
+		t.Fatalf("got %v, expecting nil error reading dst %q file", err, dst)
+	}
+
+	if bytes.Compare(data, dstData) != 0 {
+		t.Errorf("got %q, expecting data %q from dst %q text file", string(data), string(dstData), dst)
+	}
+}
+
+func TestCopyFileErrors(t *testing.T) {
+	tmpDir, err := ioutil.TempDir("", "test_copy_file_errors")
+	if err != nil {
+		t.Fatalf("failed to create temporary directory to hold test text files: %v", err)
+	}
+	defer os.Remove(tmpDir)
+
+	srcExists := filepath.Join(tmpDir, "src_exist.txt")
+	if err := ioutil.WriteFile(srcExists, []byte("fake data"), 0755); err != nil {
+		t.Fatalf("failed to create a src file %q for copying: %v", srcExists, err)
+	}
+
+	tests := []struct {
+		description string
+		src         string
+		dst         string
+	}{{
+		description: "src file does not exist",
+		src:         "/src/not/exist",
+		dst:         "/dst/not/exist",
+	}, {
+		description: "dst directory does not exist",
+		src:         srcExists,
+		dst:         "/dst/not/exist",
+	}}
+
+	for _, tt := range tests {
+		t.Run(tt.description, func(t *testing.T) {
+			if _, err := copyFile(tt.src, tt.dst); err == nil {
+				t.Errorf("got nil, expecting error")
+			}
+		})
+	}
+}
diff --git a/ui/metrics/upload_proto/upload.pb.go b/ui/metrics/upload_proto/upload.pb.go
index 1b1e5e8..614d4c7 100644
--- a/ui/metrics/upload_proto/upload.pb.go
+++ b/ui/metrics/upload_proto/upload.pb.go
@@ -30,7 +30,10 @@
 	// The target name.
 	TargetName *string `protobuf:"bytes,4,opt,name=target_name,json=targetName" json:"target_name,omitempty"`
 	// A list of metrics filepaths to upload.
-	MetricsFiles         []string `protobuf:"bytes,5,rep,name=metrics_files,json=metricsFiles" json:"metrics_files,omitempty"`
+	MetricsFiles []string `protobuf:"bytes,5,rep,name=metrics_files,json=metricsFiles" json:"metrics_files,omitempty"`
+	// A list of directories to delete after the copy of metrics files
+	// is completed for uploading.
+	DirectoriesToDelete  []string `protobuf:"bytes,6,rep,name=directories_to_delete,json=directoriesToDelete" json:"directories_to_delete,omitempty"`
 	XXX_NoUnkeyedLiteral struct{} `json:"-"`
 	XXX_unrecognized     []byte   `json:"-"`
 	XXX_sizecache        int32    `json:"-"`
@@ -96,6 +99,13 @@
 	return nil
 }
 
+func (m *Upload) GetDirectoriesToDelete() []string {
+	if m != nil {
+		return m.DirectoriesToDelete
+	}
+	return nil
+}
+
 func init() {
 	proto.RegisterType((*Upload)(nil), "soong_metrics_upload.Upload")
 }
@@ -105,18 +115,20 @@
 }
 
 var fileDescriptor_91b94b655bd2a7e5 = []byte{
-	// 201 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x29, 0x2d, 0xc8, 0xc9,
-	0x4f, 0x4c, 0xd1, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x12, 0x29, 0xce, 0xcf, 0xcf, 0x4b, 0x8f,
-	0xcf, 0x4d, 0x2d, 0x29, 0xca, 0x4c, 0x2e, 0x8e, 0x87, 0xc8, 0x29, 0xdd, 0x66, 0xe4, 0x62, 0x0b,
-	0x05, 0x33, 0x85, 0x8c, 0xb8, 0x44, 0x93, 0x8b, 0x52, 0x13, 0x4b, 0x32, 0xf3, 0xf3, 0xe2, 0x4b,
-	0x32, 0x73, 0x53, 0x8b, 0x4b, 0x12, 0x73, 0x0b, 0xe2, 0x73, 0x8b, 0x25, 0x18, 0x15, 0x18, 0x35,
-	0x58, 0x82, 0x84, 0x61, 0x92, 0x21, 0x30, 0x39, 0xdf, 0x62, 0x21, 0x33, 0x2e, 0xf1, 0xe4, 0xfc,
-	0xdc, 0x82, 0x9c, 0x54, 0x4c, 0x5d, 0x4c, 0x60, 0x5d, 0xa2, 0x08, 0x69, 0x64, 0x7d, 0xf2, 0x5c,
-	0xdc, 0x49, 0x45, 0x89, 0x79, 0xc9, 0x19, 0xf1, 0x79, 0x89, 0xb9, 0xa9, 0x12, 0xcc, 0x0a, 0x8c,
-	0x1a, 0x9c, 0x41, 0x5c, 0x10, 0x21, 0xbf, 0xc4, 0xdc, 0x54, 0x90, 0x82, 0x92, 0xc4, 0xa2, 0xf4,
-	0xd4, 0x12, 0x88, 0x02, 0x16, 0x88, 0x02, 0x88, 0x10, 0x58, 0x81, 0x32, 0x17, 0x2f, 0xcc, 0x2b,
-	0x69, 0x99, 0x39, 0xa9, 0xc5, 0x12, 0xac, 0x0a, 0xcc, 0x1a, 0x9c, 0x41, 0x3c, 0x50, 0x41, 0x37,
-	0x90, 0x98, 0x93, 0x4c, 0x94, 0x14, 0x36, 0x5f, 0xc7, 0x83, 0x43, 0x04, 0x10, 0x00, 0x00, 0xff,
-	0xff, 0xe2, 0x01, 0x74, 0x65, 0x20, 0x01, 0x00, 0x00,
+	// 230 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x6c, 0x90, 0xb1, 0x4a, 0x04, 0x31,
+	0x10, 0x86, 0xd9, 0xbb, 0xf3, 0xe0, 0xe2, 0xd9, 0xec, 0x79, 0x18, 0x44, 0x70, 0xd1, 0x66, 0x2b,
+	0x0b, 0x0b, 0x1f, 0x40, 0xc4, 0x4e, 0x8b, 0xe5, 0x6c, 0x6c, 0x86, 0x98, 0x1d, 0xd7, 0x40, 0x92,
+	0x09, 0xc9, 0xf8, 0x1c, 0xbe, 0xb2, 0x6c, 0xe2, 0xe2, 0x82, 0x76, 0xc3, 0xff, 0x7d, 0x7f, 0x31,
+	0xbf, 0xd8, 0x7e, 0x06, 0x4b, 0xaa, 0xbf, 0x09, 0x91, 0x98, 0xea, 0xd3, 0x44, 0xe4, 0x07, 0x70,
+	0xc8, 0xd1, 0xe8, 0x04, 0x85, 0x5d, 0x7d, 0x2d, 0xc4, 0xfa, 0x25, 0x9f, 0xf5, 0xad, 0xd8, 0xeb,
+	0x88, 0x8a, 0x0d, 0x79, 0x60, 0xe3, 0x30, 0xb1, 0x72, 0x01, 0x5c, 0x92, 0x55, 0x53, 0xb5, 0xab,
+	0x6e, 0x37, 0xc1, 0xc3, 0xc4, 0x9e, 0x52, 0x7d, 0x27, 0xce, 0x34, 0xb9, 0x60, 0xf1, 0x6f, 0x6b,
+	0x91, 0x5b, 0xfb, 0x5f, 0x3c, 0xef, 0x5d, 0x8a, 0xe3, 0xb7, 0xa8, 0xbc, 0xfe, 0x00, 0xaf, 0x1c,
+	0xca, 0x65, 0x53, 0xb5, 0x9b, 0x4e, 0x94, 0xe8, 0x59, 0x39, 0x1c, 0x05, 0x56, 0x71, 0x40, 0x2e,
+	0xc2, 0xaa, 0x08, 0x25, 0xca, 0xc2, 0xb5, 0x38, 0x99, 0x5e, 0x79, 0x37, 0x16, 0x93, 0x3c, 0x6a,
+	0x96, 0xed, 0xa6, 0xdb, 0xfe, 0x84, 0x8f, 0x63, 0x36, 0xbe, 0xd4, 0x9b, 0x88, 0x9a, 0x29, 0x1a,
+	0x4c, 0xc0, 0x04, 0x3d, 0x5a, 0x64, 0x94, 0xeb, 0x2c, 0xef, 0x66, 0xf0, 0x40, 0x0f, 0x19, 0xdd,
+	0x5f, 0xbc, 0x9e, 0xff, 0xb7, 0x14, 0xe4, 0x15, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0x64, 0x04,
+	0xa8, 0xf4, 0x54, 0x01, 0x00, 0x00,
 }
diff --git a/ui/metrics/upload_proto/upload.proto b/ui/metrics/upload_proto/upload.proto
index 7a9f080..bcd0ab2 100644
--- a/ui/metrics/upload_proto/upload.proto
+++ b/ui/metrics/upload_proto/upload.proto
@@ -32,4 +32,8 @@
 
   // A list of metrics filepaths to upload.
   repeated string metrics_files = 5;
+
+  // A list of directories to delete after the copy of metrics files
+  // is completed for uploading.
+  repeated string directories_to_delete = 6;
 }
diff --git a/xml/Android.bp b/xml/Android.bp
new file mode 100644
index 0000000..cd25cff
--- /dev/null
+++ b/xml/Android.bp
@@ -0,0 +1,18 @@
+bootstrap_go_package {
+    name: "soong-xml",
+    pkgPath: "android/soong/xml",
+    deps: [
+        "blueprint",
+        "blueprint-pathtools",
+        "soong",
+        "soong-android",
+        "soong-etc",
+    ],
+    srcs: [
+        "xml.go",
+    ],
+    testSrcs: [
+        "xml_test.go",
+    ],
+    pluginFor: ["soong_build"],
+}
diff --git a/xml/xml.go b/xml/xml.go
index 3a680ec..8810ae4 100644
--- a/xml/xml.go
+++ b/xml/xml.go
@@ -16,6 +16,7 @@
 
 import (
 	"android/soong/android"
+	"android/soong/etc"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -62,7 +63,7 @@
 }
 
 type prebuiltEtcXml struct {
-	android.PrebuiltEtc
+	etc.PrebuiltEtc
 
 	properties prebuiltEtcXmlProperties
 }
@@ -121,7 +122,7 @@
 func PrebuiltEtcXmlFactory() android.Module {
 	module := &prebuiltEtcXml{}
 	module.AddProperties(&module.properties)
-	android.InitPrebuiltEtcModule(&module.PrebuiltEtc, "etc")
+	etc.InitPrebuiltEtcModule(&module.PrebuiltEtc, "etc")
 	// This module is device-only
 	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
 	return module
diff --git a/xml/xml_test.go b/xml/xml_test.go
index f8ec823..abcb108 100644
--- a/xml/xml_test.go
+++ b/xml/xml_test.go
@@ -20,6 +20,7 @@
 	"testing"
 
 	"android/soong/android"
+	"android/soong/etc"
 )
 
 var buildDir string
@@ -57,7 +58,7 @@
 	}
 	config := android.TestArchConfig(buildDir, nil, bp, fs)
 	ctx := android.NewTestArchContext()
-	ctx.RegisterModuleType("prebuilt_etc", android.PrebuiltEtcFactory)
+	ctx.RegisterModuleType("prebuilt_etc", etc.PrebuiltEtcFactory)
 	ctx.RegisterModuleType("prebuilt_etc_xml", PrebuiltEtcXmlFactory)
 	ctx.Register(config)
 	_, errs := ctx.ParseFileList(".", []string{"Android.bp"})