Merge "Non-installable module should not be installed into a fuzzer .zip package"
diff --git a/android/apex.go b/android/apex.go
index 6bb0751..4637942 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -757,7 +757,6 @@
 	"captiveportal-lib":              28,
 	"flatbuffer_headers":             30,
 	"framework-permission":           30,
-	"framework-statsd":               30,
 	"gemmlowp_headers":               30,
 	"ike-internals":                  30,
 	"kotlinx-coroutines-android":     28,
@@ -790,11 +789,6 @@
 	"libprotobuf-java-lite":          30,
 	"libprotoutil":                   30,
 	"libqemu_pipe":                   30,
-	"libstats_jni":                   30,
-	"libstatslog_statsd":             30,
-	"libstatsmetadata":               30,
-	"libstatspull":                   30,
-	"libstatssocket":                 30,
 	"libsync":                        30,
 	"libtextclassifier_hash_headers": 30,
 	"libtextclassifier_hash_static":  30,
@@ -807,9 +801,6 @@
 	"philox_random_headers":          30,
 	"philox_random":                  30,
 	"service-permission":             30,
-	"service-statsd":                 30,
-	"statsd-aidl-ndk_platform":       30,
-	"statsd":                         30,
 	"tensorflow_headers":             30,
 	"xz-java":                        29,
 })
diff --git a/android/arch.go b/android/arch.go
index b277381..2decea8 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -1442,7 +1442,7 @@
 func getNdkAbisConfig() []archConfig {
 	return []archConfig{
 		{"arm", "armv7-a", "", []string{"armeabi-v7a"}},
-		{"arm64", "armv8-a", "", []string{"arm64-v8a"}},
+		{"arm64", "armv8-a-branchprot", "", []string{"arm64-v8a"}},
 		{"x86", "", "", []string{"x86"}},
 		{"x86_64", "", "", []string{"x86_64"}},
 	}
diff --git a/android/arch_list.go b/android/arch_list.go
index 0c33b9d..d68a0d1 100644
--- a/android/arch_list.go
+++ b/android/arch_list.go
@@ -41,6 +41,7 @@
 	},
 	Arm64: {
 		"armv8_a",
+		"armv8_a_branchprot",
 		"armv8_2a",
 		"armv8-2a-dotprod",
 		"cortex-a53",
diff --git a/android/config.go b/android/config.go
index 50e39d7..9162eaa 100644
--- a/android/config.go
+++ b/android/config.go
@@ -24,6 +24,7 @@
 	"os"
 	"path/filepath"
 	"runtime"
+	"strconv"
 	"strings"
 	"sync"
 
@@ -246,6 +247,7 @@
 			AAPTCharacteristics:               stringPtr("nosdcard"),
 			AAPTPrebuiltDPI:                   []string{"xhdpi", "xxhdpi"},
 			UncompressPrivAppDex:              boolPtr(true),
+			ShippingApiLevel:                  stringPtr("30"),
 		},
 
 		buildDir:     buildDir,
@@ -1421,6 +1423,18 @@
 	return c.config.productVariables.RecoverySnapshotModules
 }
 
+func (c *deviceConfig) ShippingApiLevel() ApiLevel {
+	if c.config.productVariables.ShippingApiLevel == nil {
+		return NoneApiLevel
+	}
+	apiLevel, _ := strconv.Atoi(*c.config.productVariables.ShippingApiLevel)
+	return uncheckedFinalApiLevel(apiLevel)
+}
+
+func (c *deviceConfig) BuildBrokenVendorPropertyNamespace() bool {
+	return c.config.productVariables.BuildBrokenVendorPropertyNamespace
+}
+
 // The ConfiguredJarList struct provides methods for handling a list of (apex, jar) pairs.
 // Such lists are used in the build system for things like bootclasspath jars or system server jars.
 // The apex part is either an apex name, or a special names "platform" or "system_ext". Jar is a
diff --git a/android/paths.go b/android/paths.go
index 44221be..58e1f74 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -280,7 +280,8 @@
 	return false
 }
 
-// PathsForSource returns Paths rooted from SrcDir
+// PathsForSource returns Paths rooted from SrcDir, *not* rooted from the module's local source
+// directory
 func PathsForSource(ctx PathContext, paths []string) Paths {
 	ret := make(Paths, len(paths))
 	for i, path := range paths {
@@ -289,9 +290,9 @@
 	return ret
 }
 
-// ExistentPathsForSources returns a list of Paths rooted from SrcDir that are
-// found in the tree. If any are not found, they are omitted from the list,
-// and dependencies are added so that we're re-run when they are added.
+// ExistentPathsForSources returns a list of Paths rooted from SrcDir, *not* rooted from the
+// module's local source directory, that are found in the tree. If any are not found, they are
+// omitted from the list, and dependencies are added so that we're re-run when they are added.
 func ExistentPathsForSources(ctx PathContext, paths []string) Paths {
 	ret := make(Paths, 0, len(paths))
 	for _, path := range paths {
@@ -395,6 +396,9 @@
 // `android:"path"` so that dependencies on other modules will have already been handled by the
 // path_properties mutator.
 func expandSrcsForBazel(ctx BazelConversionPathContext, paths, expandedExcludes []string) bazel.LabelList {
+	if paths == nil {
+		return bazel.LabelList{}
+	}
 	labels := bazel.LabelList{
 		Includes: []bazel.Label{},
 	}
@@ -1024,9 +1028,10 @@
 	return path
 }
 
-// ExistentPathForSource returns an OptionalPath with the SourcePath if the
-// path exists, or an empty OptionalPath if it doesn't exist. Dependencies are added
-// so that the ninja file will be regenerated if the state of the path changes.
+// ExistentPathForSource returns an OptionalPath with the SourcePath, rooted from SrcDir, *not*
+// rooted from the module's local source directory, if the path exists, or an empty OptionalPath if
+// it doesn't exist. Dependencies are added so that the ninja file will be regenerated if the state
+// of the path changes.
 func ExistentPathForSource(ctx PathContext, pathComponents ...string) OptionalPath {
 	path, err := pathForSource(ctx, pathComponents...)
 	if err != nil {
@@ -1949,3 +1954,28 @@
 	// The install path of the data file, relative to the install root.
 	RelativeInstallPath string
 }
+
+// PathsIfNonNil returns a Paths containing only the non-nil input arguments.
+func PathsIfNonNil(paths ...Path) Paths {
+	if len(paths) == 0 {
+		// Fast path for empty argument list
+		return nil
+	} else if len(paths) == 1 {
+		// Fast path for a single argument
+		if paths[0] != nil {
+			return paths
+		} else {
+			return nil
+		}
+	}
+	ret := make(Paths, 0, len(paths))
+	for _, path := range paths {
+		if path != nil {
+			ret = append(ret, path)
+		}
+	}
+	if len(ret) == 0 {
+		return nil
+	}
+	return ret
+}
diff --git a/android/util.go b/android/util.go
index 0f940fa..506f8f7 100644
--- a/android/util.go
+++ b/android/util.go
@@ -137,6 +137,16 @@
 	return false
 }
 
+// Returns true if any string in the given list has the given substring.
+func SubstringInList(list []string, substr string) bool {
+	for _, s := range list {
+		if strings.Contains(s, substr) {
+			return true
+		}
+	}
+	return false
+}
+
 // Returns true if any string in the given list has the given prefix.
 func PrefixInList(list []string, prefix string) bool {
 	for _, s := range list {
diff --git a/android/variable.go b/android/variable.go
index e76d683..76666c5 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -367,6 +367,10 @@
 	BoardMoveRecoveryResourcesToVendorBoot *bool `json:",omitempty"`
 
 	PrebuiltHiddenApiDir *string `json:",omitempty"`
+
+	ShippingApiLevel *string `json:",omitempty"`
+
+	BuildBrokenVendorPropertyNamespace bool `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt
index aee3fc4..add0e1e 100644
--- a/apex/allowed_deps.txt
+++ b/apex/allowed_deps.txt
@@ -182,6 +182,7 @@
 framework-permission-s-shared(minSdkVersion:30)
 framework-sdkextensions(minSdkVersion:30)
 framework-sdkextensions(minSdkVersion:current)
+framework-statsd(minSdkVersion:30)
 framework-statsd(minSdkVersion:current)
 framework-tethering(minSdkVersion:30)
 framework-tethering(minSdkVersion:current)
@@ -425,11 +426,15 @@
 libstagefright_mpeg2extractor(minSdkVersion:29)
 libstagefright_mpeg2support_nocrypto(minSdkVersion:29)
 libstats_jni(minSdkVersion:(no version))
+libstats_jni(minSdkVersion:30)
 libstatslog_resolv(minSdkVersion:29)
 libstatslog_statsd(minSdkVersion:(no version))
+libstatslog_statsd(minSdkVersion:30)
 libstatspull(minSdkVersion:(no version))
+libstatspull(minSdkVersion:30)
 libstatspush_compat(minSdkVersion:29)
 libstatssocket(minSdkVersion:(no version))
+libstatssocket(minSdkVersion:30)
 libstatssocket_headers(minSdkVersion:29)
 libstd(minSdkVersion:29)
 libsystem_headers(minSdkVersion:apex_inherit)
@@ -592,6 +597,7 @@
 service-permission(minSdkVersion:30)
 service-permission(minSdkVersion:current)
 service-permission-shared(minSdkVersion:30)
+service-statsd(minSdkVersion:30)
 service-statsd(minSdkVersion:current)
 SettingsLibActionBarShadow(minSdkVersion:21)
 SettingsLibAppPreference(minSdkVersion:21)
@@ -605,7 +611,9 @@
 SettingsLibUtils(minSdkVersion:21)
 stats_proto(minSdkVersion:29)
 statsd(minSdkVersion:(no version))
+statsd(minSdkVersion:30)
 statsd-aidl-ndk_platform(minSdkVersion:(no version))
+statsd-aidl-ndk_platform(minSdkVersion:30)
 statsprotos(minSdkVersion:29)
 tensorflow_headers(minSdkVersion:(no version))
 Tethering(minSdkVersion:30)
diff --git a/apex/apex.go b/apex/apex.go
index cfeac72..e06a967 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -208,6 +208,9 @@
 
 	// List of native tests that are embedded inside this APEX.
 	Tests []string
+
+	// List of filesystem images that are embedded inside this APEX bundle.
+	Filesystems []string
 }
 
 type apexMultilibProperties struct {
@@ -580,6 +583,7 @@
 	ctx.AddFarVariationDependencies(libVariations, jniLibTag, nativeModules.Jni_libs...)
 	ctx.AddFarVariationDependencies(libVariations, sharedLibTag, nativeModules.Native_shared_libs...)
 	ctx.AddFarVariationDependencies(rustLibVariations, sharedLibTag, nativeModules.Rust_dyn_libs...)
+	ctx.AddFarVariationDependencies(target.Variations(), fsTag, nativeModules.Filesystems...)
 }
 
 func (a *apexBundle) combineProperties(ctx android.BottomUpMutatorContext) {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 83eb56a..181946b 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -4364,7 +4364,7 @@
 
 	checkDexJarBuildPath := func(t *testing.T, ctx *android.TestContext, name string) {
 		// Make sure the import has been given the correct path to the dex jar.
-		p := ctx.ModuleForTests(name, "android_common_myapex").Module().(java.Dependency)
+		p := ctx.ModuleForTests(name, "android_common_myapex").Module().(java.UsesLibraryDependency)
 		dexJarBuildPath := p.DexJarBuildPath()
 		if expected, actual := ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar", android.NormalizePathForTesting(dexJarBuildPath); actual != expected {
 			t.Errorf("Incorrect DexJarBuildPath value '%s', expected '%s'", actual, expected)
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index fdac88d..ddde1b7 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -15,13 +15,16 @@
     deps: [
         "soong-android",
         "soong-bazel",
+        "soong-cc",
         "soong-genrule",
         "soong-sh",
     ],
     testSrcs: [
         "build_conversion_test.go",
         "bzl_conversion_test.go",
+        "cc_conversion_test.go",
         "conversion_test.go",
+        "sh_conversion_test.go",
         "testing.go",
     ],
     pluginFor: [
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index df554a0..422422b 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -17,7 +17,6 @@
 import (
 	"android/soong/android"
 	"android/soong/genrule"
-	"android/soong/sh"
 	"strings"
 	"testing"
 )
@@ -358,12 +357,6 @@
 					ruleClass: "genrule",
 					// Note: no bzlLoadLocation for native rules
 				},
-				BazelTarget{
-					name:      "sh_binary_target",
-					ruleClass: "sh_binary",
-					// Note: no bzlLoadLocation for native rules
-					// TODO(ruperts): Could open source the existing, experimental Starlark sh_ rules?
-				},
 			},
 			expectedLoadStatements: `load("//build/bazel/rules:cc.bzl", "cc_binary")
 load("//build/bazel/rules:java.bzl", "java_binary")`,
@@ -476,6 +469,21 @@
 		dir                                string
 	}{
 		{
+			description:                        "filegroup with does not specify srcs",
+			moduleTypeUnderTest:                "filegroup",
+			moduleTypeUnderTestFactory:         android.FileGroupFactory,
+			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+			bp: `filegroup {
+    name: "fg_foo",
+    bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{
+				`filegroup(
+    name = "fg_foo",
+)`,
+			},
+		},
+		{
 			description:                        "filegroup with no srcs",
 			moduleTypeUnderTest:                "filegroup",
 			moduleTypeUnderTestFactory:         android.FileGroupFactory,
@@ -860,23 +868,6 @@
 )`,
 			},
 		},
-		{
-			description:                        "sh_binary test",
-			moduleTypeUnderTest:                "sh_binary",
-			moduleTypeUnderTestFactory:         sh.ShBinaryFactory,
-			moduleTypeUnderTestBp2BuildMutator: sh.ShBinaryBp2Build,
-			bp: `sh_binary {
-    name: "foo",
-    src: "foo.sh",
-    bazel_module: { bp2build_available: true },
-}`,
-			expectedBazelTargets: []string{`sh_binary(
-    name = "foo",
-    srcs = [
-        "foo.sh",
-    ],
-)`},
-		},
 	}
 
 	dir := "."
diff --git a/bp2build/cc_conversion_test.go b/bp2build/cc_conversion_test.go
new file mode 100644
index 0000000..3cd3762
--- /dev/null
+++ b/bp2build/cc_conversion_test.go
@@ -0,0 +1,221 @@
+// Copyright 2021 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 bp2build
+
+import (
+	"android/soong/android"
+	"android/soong/cc"
+	"strings"
+	"testing"
+)
+
+const (
+	// See cc/testing.go for more context
+	soongCcLibraryPreamble = `
+cc_defaults {
+	name: "linux_bionic_supported",
+}
+
+toolchain_library {
+	name: "libclang_rt.builtins-x86_64-android",
+	defaults: ["linux_bionic_supported"],
+	vendor_available: true,
+	vendor_ramdisk_available: true,
+	product_available: true,
+	recovery_available: true,
+	native_bridge_supported: true,
+	src: "",
+}
+
+toolchain_library {
+	name: "libatomic",
+	defaults: ["linux_bionic_supported"],
+	vendor_available: true,
+	vendor_ramdisk_available: true,
+	product_available: true,
+	recovery_available: true,
+	native_bridge_supported: true,
+	src: "",
+}`
+)
+
+func TestCcLibraryHeadersLoadStatement(t *testing.T) {
+	testCases := []struct {
+		bazelTargets           BazelTargets
+		expectedLoadStatements string
+	}{
+		{
+			bazelTargets: BazelTargets{
+				BazelTarget{
+					name:      "cc_library_headers_target",
+					ruleClass: "cc_library_headers",
+					// Note: no bzlLoadLocation for native rules
+				},
+			},
+			expectedLoadStatements: ``,
+		},
+	}
+
+	for _, testCase := range testCases {
+		actual := testCase.bazelTargets.LoadStatements()
+		expected := testCase.expectedLoadStatements
+		if actual != expected {
+			t.Fatalf("Expected load statements to be %s, got %s", expected, actual)
+		}
+	}
+
+}
+
+func TestCcLibraryHeadersBp2Build(t *testing.T) {
+	testCases := []struct {
+		description                        string
+		moduleTypeUnderTest                string
+		moduleTypeUnderTestFactory         android.ModuleFactory
+		moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
+		preArchMutators                    []android.RegisterMutatorFunc
+		depsMutators                       []android.RegisterMutatorFunc
+		bp                                 string
+		expectedBazelTargets               []string
+		filesystem                         map[string]string
+		dir                                string
+	}{
+		{
+			description:                        "cc_library_headers test",
+			moduleTypeUnderTest:                "cc_library_headers",
+			moduleTypeUnderTestFactory:         cc.LibraryHeaderFactory,
+			moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build,
+			filesystem: map[string]string{
+				"lib-1/lib1a.h": "",
+				"lib-1/lib1b.h": "",
+				"lib-2/lib2a.h": "",
+				"lib-2/lib2b.h": "",
+				"dir-1/dir1a.h": "",
+				"dir-1/dir1b.h": "",
+				"dir-2/dir2a.h": "",
+				"dir-2/dir2b.h": "",
+			},
+			bp: soongCcLibraryPreamble + `
+cc_library_headers {
+    name: "lib-1",
+    export_include_dirs: ["lib-1"],
+    bazel_module: { bp2build_available: true },
+}
+
+cc_library_headers {
+    name: "lib-2",
+    export_include_dirs: ["lib-2"],
+    bazel_module: { bp2build_available: true },
+}
+
+cc_library_headers {
+    name: "foo_headers",
+    export_include_dirs: ["dir-1", "dir-2"],
+    header_libs: ["lib-1", "lib-2"],
+    export_header_lib_headers: ["lib-1", "lib-2"],
+    bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{`cc_library_headers(
+    name = "foo_headers",
+    deps = [
+        ":lib-1",
+        ":lib-2",
+    ],
+    hdrs = [
+        "dir-1/dir1a.h",
+        "dir-1/dir1b.h",
+        "dir-2/dir2a.h",
+        "dir-2/dir2b.h",
+    ],
+    includes = [
+        "dir-1",
+        "dir-2",
+    ],
+)`, `cc_library_headers(
+    name = "lib-1",
+    hdrs = [
+        "lib-1/lib1a.h",
+        "lib-1/lib1b.h",
+    ],
+    includes = [
+        "lib-1",
+    ],
+)`, `cc_library_headers(
+    name = "lib-2",
+    hdrs = [
+        "lib-2/lib2a.h",
+        "lib-2/lib2b.h",
+    ],
+    includes = [
+        "lib-2",
+    ],
+)`},
+		},
+	}
+
+	dir := "."
+	for _, testCase := range testCases {
+		filesystem := make(map[string][]byte)
+		toParse := []string{
+			"Android.bp",
+		}
+		for f, content := range testCase.filesystem {
+			if strings.HasSuffix(f, "Android.bp") {
+				toParse = append(toParse, f)
+			}
+			filesystem[f] = []byte(content)
+		}
+		config := android.TestConfig(buildDir, nil, testCase.bp, filesystem)
+		ctx := android.NewTestContext(config)
+
+		cc.RegisterCCBuildComponents(ctx)
+		ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory)
+
+		ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
+		for _, m := range testCase.depsMutators {
+			ctx.DepsBp2BuildMutators(m)
+		}
+		ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
+		ctx.RegisterForBazelConversion()
+
+		_, errs := ctx.ParseFileList(dir, toParse)
+		if Errored(t, testCase.description, errs) {
+			continue
+		}
+		_, errs = ctx.ResolveDependencies(config)
+		if Errored(t, testCase.description, errs) {
+			continue
+		}
+
+		checkDir := dir
+		if testCase.dir != "" {
+			checkDir = testCase.dir
+		}
+		bazelTargets := GenerateBazelTargets(ctx.Context.Context, Bp2Build)[checkDir]
+		if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
+			t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount)
+		} else {
+			for i, target := range bazelTargets {
+				if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
+					t.Errorf(
+						"%s: Expected generated Bazel target to be '%s', got '%s'",
+						testCase.description,
+						w,
+						g,
+					)
+				}
+			}
+		}
+	}
+}
diff --git a/bp2build/sh_conversion_test.go b/bp2build/sh_conversion_test.go
new file mode 100644
index 0000000..dcc75bd
--- /dev/null
+++ b/bp2build/sh_conversion_test.go
@@ -0,0 +1,134 @@
+// Copyright 2021 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 bp2build
+
+import (
+	"android/soong/android"
+	"android/soong/sh"
+	"strings"
+	"testing"
+)
+
+func TestShBinaryLoadStatement(t *testing.T) {
+	testCases := []struct {
+		bazelTargets           BazelTargets
+		expectedLoadStatements string
+	}{
+		{
+			bazelTargets: BazelTargets{
+				BazelTarget{
+					name:      "sh_binary_target",
+					ruleClass: "sh_binary",
+					// Note: no bzlLoadLocation for native rules
+					// TODO(ruperts): Could open source the existing, experimental Starlark sh_ rules?
+				},
+			},
+			expectedLoadStatements: ``,
+		},
+	}
+
+	for _, testCase := range testCases {
+		actual := testCase.bazelTargets.LoadStatements()
+		expected := testCase.expectedLoadStatements
+		if actual != expected {
+			t.Fatalf("Expected load statements to be %s, got %s", expected, actual)
+		}
+	}
+
+}
+
+func TestShBinaryBp2Build(t *testing.T) {
+	testCases := []struct {
+		description                        string
+		moduleTypeUnderTest                string
+		moduleTypeUnderTestFactory         android.ModuleFactory
+		moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
+		preArchMutators                    []android.RegisterMutatorFunc
+		depsMutators                       []android.RegisterMutatorFunc
+		bp                                 string
+		expectedBazelTargets               []string
+		filesystem                         map[string]string
+		dir                                string
+	}{
+		{
+			description:                        "sh_binary test",
+			moduleTypeUnderTest:                "sh_binary",
+			moduleTypeUnderTestFactory:         sh.ShBinaryFactory,
+			moduleTypeUnderTestBp2BuildMutator: sh.ShBinaryBp2Build,
+			bp: `sh_binary {
+    name: "foo",
+    src: "foo.sh",
+    bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{`sh_binary(
+    name = "foo",
+    srcs = [
+        "foo.sh",
+    ],
+)`},
+		},
+	}
+
+	dir := "."
+	for _, testCase := range testCases {
+		filesystem := make(map[string][]byte)
+		toParse := []string{
+			"Android.bp",
+		}
+		for f, content := range testCase.filesystem {
+			if strings.HasSuffix(f, "Android.bp") {
+				toParse = append(toParse, f)
+			}
+			filesystem[f] = []byte(content)
+		}
+		config := android.TestConfig(buildDir, nil, testCase.bp, filesystem)
+		ctx := android.NewTestContext(config)
+		ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
+		for _, m := range testCase.depsMutators {
+			ctx.DepsBp2BuildMutators(m)
+		}
+		ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
+		ctx.RegisterForBazelConversion()
+
+		_, errs := ctx.ParseFileList(dir, toParse)
+		if Errored(t, testCase.description, errs) {
+			continue
+		}
+		_, errs = ctx.ResolveDependencies(config)
+		if Errored(t, testCase.description, errs) {
+			continue
+		}
+
+		checkDir := dir
+		if testCase.dir != "" {
+			checkDir = testCase.dir
+		}
+		bazelTargets := GenerateBazelTargets(ctx.Context.Context, Bp2Build)[checkDir]
+		if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
+			t.Errorf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount)
+		} else {
+			for i, target := range bazelTargets {
+				if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
+					t.Errorf(
+						"%s: Expected generated Bazel target to be '%s', got '%s'",
+						testCase.description,
+						w,
+						g,
+					)
+				}
+			}
+		}
+	}
+}
diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go
index e6024aa..d083d2a 100644
--- a/cc/config/arm64_device.go
+++ b/cc/config/arm64_device.go
@@ -31,6 +31,10 @@
 		"armv8-a": []string{
 			"-march=armv8-a",
 		},
+		"armv8-a-branchprot": []string{
+			"-march=armv8-a",
+			"-mbranch-protection=standard",
+		},
 		"armv8-2a": []string{
 			"-march=armv8.2-a",
 		},
@@ -102,6 +106,7 @@
 	pctx.StaticVariable("Arm64ClangCppflags", strings.Join(ClangFilterUnknownCflags(arm64Cppflags), " "))
 
 	pctx.StaticVariable("Arm64ClangArmv8ACflags", strings.Join(arm64ArchVariantCflags["armv8-a"], " "))
+	pctx.StaticVariable("Arm64ClangArmv8ABranchProtCflags", strings.Join(arm64ArchVariantCflags["armv8-a-branchprot"], " "))
 	pctx.StaticVariable("Arm64ClangArmv82ACflags", strings.Join(arm64ArchVariantCflags["armv8-2a"], " "))
 	pctx.StaticVariable("Arm64ClangArmv82ADotprodCflags", strings.Join(arm64ArchVariantCflags["armv8-2a-dotprod"], " "))
 
@@ -124,6 +129,7 @@
 var (
 	arm64ClangArchVariantCflagsVar = map[string]string{
 		"armv8-a":  "${config.Arm64ClangArmv8ACflags}",
+		"armv8-a-branchprot": "${config.Arm64ClangArmv8ABranchProtCflags}",
 		"armv8-2a": "${config.Arm64ClangArmv82ACflags}",
 		"armv8-2a-dotprod": "${config.Arm64ClangArmv82ADotprodCflags}",
 	}
@@ -202,6 +208,7 @@
 func arm64ToolchainFactory(arch android.Arch) Toolchain {
 	switch arch.ArchVariant {
 	case "armv8-a":
+	case "armv8-a-branchprot":
 	case "armv8-2a":
 	case "armv8-2a-dotprod":
 		// Nothing extra for armv8-a/armv8-2a
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 71c7626..76186be 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -150,6 +150,8 @@
 		"-Wunguarded-availability",
 		// This macro allows the bionic versioning.h to indirectly determine whether the
 		// option -Wunguarded-availability is on or not.
+		"-D__ANDROID_UNAVAILABLE_SYMBOLS_ARE_WEAK__",
+		// TODO: remove this once prebuilt SDKs are only using the above macro instead.
 		"-D__ANDROID_UNGUARDED_AVAILABILITY__",
 	}, " "))
 
diff --git a/cc/config/global.go b/cc/config/global.go
index ee41125..e60bb3d 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -144,8 +144,8 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r407598b"
-	ClangDefaultShortVersion = "12.0.2"
+	ClangDefaultVersion      = "clang-r412851"
+	ClangDefaultShortVersion = "12.0.3"
 
 	// Directories with warnings from Android.bp files.
 	WarningAllowedProjects = []string{
diff --git a/cc/config/tidy.go b/cc/config/tidy.go
index 7cc9f43..7c20dd5 100644
--- a/cc/config/tidy.go
+++ b/cc/config/tidy.go
@@ -87,27 +87,11 @@
 		}, ",")
 	})
 
-	// Give warnings to header files only in selected directories.
-	// Do not give warnings to external or vendor header files, which contain too
-	// many warnings.
+	// To reduce duplicate warnings from the same header files,
+	// header-filter will contain only the module directory and
+	// those specified by DEFAULT_TIDY_HEADER_DIRS.
 	pctx.VariableFunc("TidyDefaultHeaderDirs", func(ctx android.PackageVarContext) string {
-		if override := ctx.Config().Getenv("DEFAULT_TIDY_HEADER_DIRS"); override != "" {
-			return override
-		}
-		return strings.Join([]string{
-			"art/",
-			"bionic/",
-			"bootable/",
-			"build/",
-			"cts/",
-			"dalvik/",
-			"developers/",
-			"development/",
-			"frameworks/",
-			"libcore/",
-			"libnativehelper/",
-			"system/",
-		}, "|")
+		return ctx.Config().Getenv("DEFAULT_TIDY_HEADER_DIRS")
 	})
 
 	// Use WTIH_TIDY_FLAGS to pass extra global default clang-tidy flags.
diff --git a/cc/library.go b/cc/library.go
index 65533bc..bdcb8ae 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -27,6 +27,7 @@
 	"github.com/google/blueprint/pathtools"
 
 	"android/soong/android"
+	"android/soong/bazel"
 	"android/soong/cc/config"
 )
 
@@ -120,6 +121,9 @@
 	// If this is an LLNDK library, properties to describe the LLNDK stubs.  Will be copied from
 	// the module pointed to by llndk_stubs if it is set.
 	Llndk llndkLibraryProperties
+
+	// Properties for Bazel migration purposes.
+	bazel.Properties
 }
 
 // StaticProperties is a properties stanza to affect only attributes of the "static" variants of a
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 8b3dbeb..448e144 100644
--- a/cc/library_headers.go
+++ b/cc/library_headers.go
@@ -14,13 +14,18 @@
 
 package cc
 
-import "android/soong/android"
+import (
+	"android/soong/android"
+	"android/soong/bazel"
+)
 
 func init() {
 	RegisterLibraryHeadersBuildComponents(android.InitRegistrationContext)
 
 	// Register sdk member types.
 	android.RegisterSdkMemberType(headersLibrarySdkMemberType)
+
+	android.RegisterBp2BuildMutator("cc_library_headers", CcLibraryHeadersBp2Build)
 }
 
 var headersLibrarySdkMemberType = &librarySdkMemberType{
@@ -55,3 +60,86 @@
 	library.HeaderOnly()
 	return module.Init()
 }
+
+type bazelCcLibraryHeadersAttributes struct {
+	Hdrs     bazel.LabelList
+	Includes bazel.LabelList
+	Deps     bazel.LabelList
+}
+
+type bazelCcLibraryHeaders struct {
+	android.BazelTargetModuleBase
+	bazelCcLibraryHeadersAttributes
+}
+
+func BazelCcLibraryHeadersFactory() android.Module {
+	module := &bazelCcLibraryHeaders{}
+	module.AddProperties(&module.bazelCcLibraryHeadersAttributes)
+	android.InitBazelTargetModule(module)
+	return module
+}
+
+func CcLibraryHeadersBp2Build(ctx android.TopDownMutatorContext) {
+	module, ok := ctx.Module().(*Module)
+	if !ok {
+		// Not a cc module
+		return
+	}
+
+	lib, ok := module.linker.(*libraryDecorator)
+	if !ok {
+		// Not a cc_library module
+		return
+	}
+	if !lib.header() {
+		// Not a cc_library_headers module
+		return
+	}
+
+	if !lib.Properties.Bazel_module.Bp2build_available {
+		return
+	}
+
+	// list of directories that will be added to the include path (using -I) for this
+	// module and any module that links against this module.
+	includeDirs := lib.flagExporter.Properties.Export_system_include_dirs
+	includeDirs = append(includeDirs, lib.flagExporter.Properties.Export_include_dirs...)
+	includeDirLabels := android.BazelLabelForModuleSrc(ctx, includeDirs)
+
+	var includeDirGlobs []string
+	for _, includeDir := range includeDirs {
+		includeDirGlobs = append(includeDirGlobs, includeDir+"/**/*.h")
+	}
+
+	headerLabels := android.BazelLabelForModuleSrc(ctx, includeDirGlobs)
+
+	// list of modules that should only provide headers for this module.
+	var headerLibs []string
+	for _, linkerProps := range lib.linkerProps() {
+		if baseLinkerProps, ok := linkerProps.(*BaseLinkerProperties); ok {
+			headerLibs = baseLinkerProps.Export_header_lib_headers
+			break
+		}
+	}
+	headerLibLabels := android.BazelLabelForModuleDeps(ctx, headerLibs)
+
+	attrs := &bazelCcLibraryHeadersAttributes{
+		Includes: includeDirLabels,
+		Hdrs:     headerLabels,
+		Deps:     headerLibLabels,
+	}
+
+	props := bazel.NewBazelTargetModuleProperties(
+		module.Name(),
+		"cc_library_headers",
+		"//build/bazel/rules:cc_library_headers.bzl",
+	)
+
+	ctx.CreateBazelTargetModule(BazelCcLibraryHeadersFactory, props, attrs)
+}
+
+func (m *bazelCcLibraryHeaders) Name() string {
+	return m.BaseModuleName()
+}
+
+func (m *bazelCcLibraryHeaders) GenerateAndroidBuildActions(ctx android.ModuleContext) {}
diff --git a/cc/tidy.go b/cc/tidy.go
index 972ad7b..251c67b 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -20,6 +20,7 @@
 
 	"github.com/google/blueprint/proptools"
 
+	"android/soong/android"
 	"android/soong/cc/config"
 )
 
@@ -75,9 +76,17 @@
 	}
 	esc := proptools.NinjaAndShellEscapeList
 	flags.TidyFlags = append(flags.TidyFlags, esc(tidy.Properties.Tidy_flags)...)
-	// If TidyFlags is empty, add default header filter.
-	if len(flags.TidyFlags) == 0 {
-		headerFilter := "-header-filter=\"(" + ctx.ModuleDir() + "|${config.TidyDefaultHeaderDirs})\""
+	// If TidyFlags does not contain -header-filter, add default header filter.
+	// Find the substring because the flag could also appear as --header-filter=...
+	// and with or without single or double quotes.
+	if !android.SubstringInList(flags.TidyFlags, "-header-filter=") {
+		defaultDirs := ctx.Config().Getenv("DEFAULT_TIDY_HEADER_DIRS")
+		headerFilter := "-header-filter="
+		if defaultDirs == "" {
+			headerFilter += ctx.ModuleDir() + "/"
+		} else {
+			headerFilter += "\"(" + ctx.ModuleDir() + "/|" + defaultDirs + ")\""
+		}
 		flags.TidyFlags = append(flags.TidyFlags, headerFilter)
 	}
 
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 850c8f9..57563eb 100644
--- a/etc/prebuilt_etc.go
+++ b/etc/prebuilt_etc.go
@@ -28,6 +28,8 @@
 // various `prebuilt_*` mutators.
 
 import (
+	"fmt"
+
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
@@ -208,6 +210,17 @@
 	return p.outputFilePath
 }
 
+var _ android.OutputFileProducer = (*PrebuiltEtc)(nil)
+
+func (p *PrebuiltEtc) OutputFiles(tag string) (android.Paths, error) {
+	switch tag {
+	case "":
+		return android.Paths{p.outputFilePath}, nil
+	default:
+		return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+	}
+}
+
 func (p *PrebuiltEtc) SubDir() string {
 	if subDir := proptools.String(p.properties.Sub_dir); subDir != "" {
 		return subDir
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index 4bc1823..c90929a 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -38,6 +38,9 @@
 }
 
 type bootimgProperties struct {
+	// Set the name of the output. Defaults to <module_name>.img.
+	Stem *string
+
 	// Path to the linux kernel prebuilt file
 	Kernel_prebuilt *string `android:"arch_variant,path"`
 
@@ -96,7 +99,7 @@
 }
 
 func (b *bootimg) installFileName() string {
-	return b.BaseModuleName() + ".img"
+	return proptools.StringDefault(b.properties.Stem, b.BaseModuleName()+".img")
 }
 
 func (b *bootimg) partitionName() string {
@@ -110,6 +113,7 @@
 	} else {
 		// TODO(jiyong): fix this
 		ctx.PropertyErrorf("vendor_boot", "only vendor_boot:true is supported")
+		return
 	}
 
 	if proptools.Bool(b.properties.Use_avb) {
@@ -123,7 +127,8 @@
 }
 
 func (b *bootimg) buildVendorBootImage(ctx android.ModuleContext) android.OutputPath {
-	output := android.PathForModuleOut(ctx, "unsigned.img").OutputPath
+	output := android.PathForModuleOut(ctx, "unsigned", b.installFileName()).OutputPath
+
 	builder := android.NewRuleBuilder(pctx, ctx)
 	cmd := builder.Command().BuiltTool("mkbootimg")
 
@@ -182,21 +187,20 @@
 }
 
 func (b *bootimg) signImage(ctx android.ModuleContext, unsignedImage android.OutputPath) android.OutputPath {
-	signedImage := android.PathForModuleOut(ctx, "signed.img").OutputPath
+	output := android.PathForModuleOut(ctx, b.installFileName()).OutputPath
 	key := android.PathForModuleSrc(ctx, proptools.String(b.properties.Avb_private_key))
 
 	builder := android.NewRuleBuilder(pctx, ctx)
-	builder.Command().Text("cp").Input(unsignedImage).Output(signedImage)
+	builder.Command().Text("cp").Input(unsignedImage).Output(output)
 	builder.Command().
 		BuiltTool("avbtool").
 		Flag("add_hash_footer").
 		FlagWithArg("--partition_name ", b.partitionName()).
 		FlagWithInput("--key ", key).
-		FlagWithOutput("--image ", signedImage)
+		FlagWithOutput("--image ", output)
 
 	builder.Build("sign_bootimg", fmt.Sprintf("Signing %s", b.BaseModuleName()))
-
-	return signedImage
+	return output
 }
 
 var _ android.AndroidMkEntriesProvider = (*bootimg)(nil)
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 7658154..3bccde9 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -16,6 +16,8 @@
 
 import (
 	"fmt"
+	"path/filepath"
+	"strings"
 
 	"android/soong/android"
 
@@ -37,6 +39,11 @@
 	installDir android.InstallPath
 }
 
+type symlinkDefinition struct {
+	Target *string
+	Name   *string
+}
+
 type filesystemProperties struct {
 	// When set to true, sign the image with avbtool. Default is false.
 	Use_avb *bool
@@ -54,6 +61,16 @@
 
 	// file_contexts file to make image. Currently, only ext4 is supported.
 	File_contexts *string `android:"path"`
+
+	// Base directory relative to root, to which deps are installed, e.g. "system". Default is "."
+	// (root).
+	Base_dir *string
+
+	// Directories to be created under root. e.g. /dev, /proc, etc.
+	Dirs []string
+
+	// Symbolic links to be created under root with "ln -sf <target> <name>".
+	Symlinks []symlinkDefinition
 }
 
 // android_filesystem packages a set of modules and their transitive dependencies into a filesystem
@@ -124,16 +141,75 @@
 	ctx.InstallFile(f.installDir, f.installFileName(), f.output)
 }
 
+// root zip will contain stuffs like dirs or symlinks.
+func (f *filesystem) buildRootZip(ctx android.ModuleContext) android.OutputPath {
+	rootDir := android.PathForModuleGen(ctx, "root").OutputPath
+	builder := android.NewRuleBuilder(pctx, ctx)
+	builder.Command().Text("rm -rf").Text(rootDir.String())
+	builder.Command().Text("mkdir -p").Text(rootDir.String())
+
+	// create dirs and symlinks
+	for _, dir := range f.properties.Dirs {
+		// OutputPath.Join verifies dir
+		builder.Command().Text("mkdir -p").Text(rootDir.Join(ctx, dir).String())
+	}
+
+	for _, symlink := range f.properties.Symlinks {
+		name := strings.TrimSpace(proptools.String(symlink.Name))
+		target := strings.TrimSpace(proptools.String(symlink.Target))
+
+		if name == "" {
+			ctx.PropertyErrorf("symlinks", "Name can't be empty")
+			continue
+		}
+
+		if target == "" {
+			ctx.PropertyErrorf("symlinks", "Target can't be empty")
+			continue
+		}
+
+		// OutputPath.Join verifies name. don't need to verify target.
+		dst := rootDir.Join(ctx, name)
+
+		builder.Command().Text("mkdir -p").Text(filepath.Dir(dst.String()))
+		builder.Command().Text("ln -sf").Text(proptools.ShellEscape(target)).Text(dst.String())
+	}
+
+	zipOut := android.PathForModuleGen(ctx, "root.zip").OutputPath
+
+	builder.Command().
+		BuiltTool("soong_zip").
+		FlagWithOutput("-o ", zipOut).
+		FlagWithArg("-C ", rootDir.String()).
+		Flag("-L 0"). // no compression because this will be unzipped soon
+		FlagWithArg("-D ", rootDir.String()).
+		Flag("-d") // include empty directories
+	builder.Command().Text("rm -rf").Text(rootDir.String())
+
+	builder.Build("zip_root", fmt.Sprintf("zipping root contents for %s", ctx.ModuleName()))
+	return zipOut
+}
+
 func (f *filesystem) buildImageUsingBuildImage(ctx android.ModuleContext) android.OutputPath {
-	zipFile := android.PathForModuleOut(ctx, "temp.zip").OutputPath
-	f.CopyDepsToZip(ctx, zipFile)
+	depsZipFile := android.PathForModuleOut(ctx, "deps.zip").OutputPath
+	f.CopyDepsToZip(ctx, depsZipFile)
+
+	builder := android.NewRuleBuilder(pctx, ctx)
+	depsBase := proptools.StringDefault(f.properties.Base_dir, ".")
+	rebasedDepsZip := android.PathForModuleOut(ctx, "rebased_deps.zip").OutputPath
+	builder.Command().
+		BuiltTool("zip2zip").
+		FlagWithInput("-i ", depsZipFile).
+		FlagWithOutput("-o ", rebasedDepsZip).
+		Text("**/*:" + proptools.ShellEscape(depsBase)) // zip2zip verifies depsBase
 
 	rootDir := android.PathForModuleOut(ctx, "root").OutputPath
-	builder := android.NewRuleBuilder(pctx, ctx)
+	rootZip := f.buildRootZip(ctx)
 	builder.Command().
 		BuiltTool("zipsync").
 		FlagWithArg("-d ", rootDir.String()). // zipsync wipes this. No need to clear.
-		Input(zipFile)
+		Input(rootZip).
+		Input(rebasedDepsZip)
 
 	propFile, toolDeps := f.buildPropFile(ctx)
 	output := android.PathForModuleOut(ctx, f.installFileName()).OutputPath
@@ -187,7 +263,7 @@
 	}
 
 	addStr("fs_type", fsTypeStr(f.fsType(ctx)))
-	addStr("mount_point", "system")
+	addStr("mount_point", "/")
 	addStr("use_dynamic_partition_size", "true")
 	addPath("ext_mkuserimg", ctx.Config().HostToolPath(ctx, "mkuserimg_mke2fs"))
 	// b/177813163 deps of the host tools have to be added. Remove this.
@@ -233,15 +309,25 @@
 		ctx.PropertyErrorf("file_contexts", "file_contexts is not supported for compressed cpio image.")
 	}
 
-	zipFile := android.PathForModuleOut(ctx, "temp.zip").OutputPath
-	f.CopyDepsToZip(ctx, zipFile)
+	depsZipFile := android.PathForModuleOut(ctx, "deps.zip").OutputPath
+	f.CopyDepsToZip(ctx, depsZipFile)
+
+	builder := android.NewRuleBuilder(pctx, ctx)
+	depsBase := proptools.StringDefault(f.properties.Base_dir, ".")
+	rebasedDepsZip := android.PathForModuleOut(ctx, "rebased_deps.zip").OutputPath
+	builder.Command().
+		BuiltTool("zip2zip").
+		FlagWithInput("-i ", depsZipFile).
+		FlagWithOutput("-o ", rebasedDepsZip).
+		Text("**/*:" + proptools.ShellEscape(depsBase)) // zip2zip verifies depsBase
 
 	rootDir := android.PathForModuleOut(ctx, "root").OutputPath
-	builder := android.NewRuleBuilder(pctx, ctx)
+	rootZip := f.buildRootZip(ctx)
 	builder.Command().
 		BuiltTool("zipsync").
 		FlagWithArg("-d ", rootDir.String()). // zipsync wipes this. No need to clear.
-		Input(zipFile)
+		Input(rootZip).
+		Input(rebasedDepsZip)
 
 	output := android.PathForModuleOut(ctx, f.installFileName()).OutputPath
 	cmd := builder.Command().
diff --git a/java/aar.go b/java/aar.go
index e3ad252..ac7ae25 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -28,7 +28,6 @@
 )
 
 type AndroidLibraryDependency interface {
-	Dependency
 	ExportPackage() android.Path
 	ExportedProguardFlagFiles() android.Paths
 	ExportedRRODirs() []rroDir
@@ -796,9 +795,13 @@
 
 	aapt2Link(ctx, a.exportPackage, srcJar, proguardOptionsFile, rTxt, a.extraAaptPackagesFile,
 		linkFlags, linkDeps, nil, overlayRes, transitiveAssets, nil)
-}
 
-var _ Dependency = (*AARImport)(nil)
+	ctx.SetProvider(JavaInfoProvider, JavaInfo{
+		HeaderJars:                     android.PathsIfNonNil(a.classpathFile),
+		ImplementationAndResourcesJars: android.PathsIfNonNil(a.classpathFile),
+		ImplementationJars:             android.PathsIfNonNil(a.classpathFile),
+	})
+}
 
 func (a *AARImport) HeaderJars() android.Paths {
 	return android.Paths{a.classpathFile}
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index 4914d74..ee7d018 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -97,15 +97,15 @@
 	}
 
 	ctx.VisitDirectDepsWithTag(deviceHostConverterDepTag, func(m android.Module) {
-		if dep, ok := m.(Dependency); ok {
-			d.headerJars = append(d.headerJars, dep.HeaderJars()...)
-			d.implementationJars = append(d.implementationJars, dep.ImplementationJars()...)
-			d.implementationAndResourceJars = append(d.implementationAndResourceJars, dep.ImplementationAndResourcesJars()...)
-			d.resourceJars = append(d.resourceJars, dep.ResourceJars()...)
+		if ctx.OtherModuleHasProvider(m, JavaInfoProvider) {
+			dep := ctx.OtherModuleProvider(m, JavaInfoProvider).(JavaInfo)
+			d.headerJars = append(d.headerJars, dep.HeaderJars...)
+			d.implementationJars = append(d.implementationJars, dep.ImplementationJars...)
+			d.implementationAndResourceJars = append(d.implementationAndResourceJars, dep.ImplementationAndResourcesJars...)
+			d.resourceJars = append(d.resourceJars, dep.ResourceJars...)
 
-			srcJarArgs, srcJarDeps := dep.SrcJarArgs()
-			d.srcJarArgs = append(d.srcJarArgs, srcJarArgs...)
-			d.srcJarDeps = append(d.srcJarDeps, srcJarDeps...)
+			d.srcJarArgs = append(d.srcJarArgs, dep.SrcJarArgs...)
+			d.srcJarDeps = append(d.srcJarDeps, dep.SrcJarDeps...)
 		} else {
 			ctx.PropertyErrorf("libs", "module %q cannot be used as a dependency", ctx.OtherModuleName(m))
 		}
@@ -131,9 +131,16 @@
 		d.combinedHeaderJar = d.headerJars[0]
 	}
 
-}
+	ctx.SetProvider(JavaInfoProvider, JavaInfo{
+		HeaderJars:                     d.headerJars,
+		ImplementationAndResourcesJars: d.implementationAndResourceJars,
+		ImplementationJars:             d.implementationJars,
+		ResourceJars:                   d.resourceJars,
+		SrcJarArgs:                     d.srcJarArgs,
+		SrcJarDeps:                     d.srcJarDeps,
+	})
 
-var _ Dependency = (*DeviceHostConverter)(nil)
+}
 
 func (d *DeviceHostConverter) HeaderJars() android.Paths {
 	return d.headerJars
diff --git a/java/dex.go b/java/dex.go
index 24600c2..e52fdb5 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -204,8 +204,9 @@
 	// - prevent ProGuard stripping subclass in the support library that extends class added in the higher SDK version.
 	// See b/20667396
 	var proguardRaiseDeps classpath
-	ctx.VisitDirectDepsWithTag(proguardRaiseTag, func(dep android.Module) {
-		proguardRaiseDeps = append(proguardRaiseDeps, dep.(Dependency).HeaderJars()...)
+	ctx.VisitDirectDepsWithTag(proguardRaiseTag, func(m android.Module) {
+		dep := ctx.OtherModuleProvider(m, JavaInfoProvider).(JavaInfo)
+		proguardRaiseDeps = append(proguardRaiseDeps, dep.HeaderJars...)
 	})
 
 	r8Flags = append(r8Flags, proguardRaiseDeps.FormJavaClassPath("-libraryjars"))
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index c315124..282e936 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -82,10 +82,6 @@
 		deviceDir := android.PathForOutput(ctx, ctx.Config().DeviceName())
 
 		artModules := global.ArtApexJars
-		// With EMMA_INSTRUMENT_FRAMEWORK=true the Core libraries depend on jacoco.
-		if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
-			artModules = artModules.Append("com.android.art", "jacocoagent")
-		}
 		frameworkModules := global.BootJars.RemoveList(artModules)
 
 		artSubdir := "apex/art_boot_images/javalib"
diff --git a/java/droiddoc.go b/java/droiddoc.go
index c74009e..8f1644c 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -470,8 +470,9 @@
 
 		switch tag {
 		case bootClasspathTag:
-			if dep, ok := module.(Dependency); ok {
-				deps.bootClasspath = append(deps.bootClasspath, dep.ImplementationJars()...)
+			if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
+				dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+				deps.bootClasspath = append(deps.bootClasspath, dep.ImplementationJars...)
 			} else if sm, ok := module.(SystemModulesProvider); ok {
 				// A system modules dependency has been added to the bootclasspath
 				// so add its libs to the bootclasspath.
@@ -480,23 +481,23 @@
 				panic(fmt.Errorf("unknown dependency %q for %q", otherName, ctx.ModuleName()))
 			}
 		case libTag:
-			switch dep := module.(type) {
-			case SdkLibraryDependency:
+			if dep, ok := module.(SdkLibraryDependency); ok {
 				deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
-			case Dependency:
-				deps.classpath = append(deps.classpath, dep.HeaderJars()...)
-				deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
-			case android.SourceFileProducer:
+			} else if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
+				dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+				deps.classpath = append(deps.classpath, dep.HeaderJars...)
+				deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...)
+			} else if dep, ok := module.(android.SourceFileProducer); ok {
 				checkProducesJars(ctx, dep)
 				deps.classpath = append(deps.classpath, dep.Srcs()...)
-			default:
+			} else {
 				ctx.ModuleErrorf("depends on non-java module %q", otherName)
 			}
 		case java9LibTag:
-			switch dep := module.(type) {
-			case Dependency:
-				deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars()...)
-			default:
+			if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
+				dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+				deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars...)
+			} else {
 				ctx.ModuleErrorf("depends on non-java module %q", otherName)
 			}
 		case systemModulesTag:
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index 1651c1c..f8e41c4 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -221,13 +221,19 @@
 		return
 	}
 
+	classesJars := android.Paths{classesJar}
+	ctx.VisitDirectDepsWithTag(hiddenApiAnnotationsTag, func(dep android.Module) {
+		javaInfo := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
+		classesJars = append(classesJars, javaInfo.ImplementationJars...)
+	})
+
 	stubFlagsCSV := hiddenAPISingletonPaths(ctx).stubFlags
 
 	flagsCSV := android.PathForModuleOut(ctx, "hiddenapi", "flags.csv")
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        hiddenAPIGenerateCSVRule,
 		Description: "hiddenapi flags",
-		Input:       classesJar,
+		Inputs:      classesJars,
 		Output:      flagsCSV,
 		Implicit:    stubFlagsCSV,
 		Args: map[string]string{
@@ -241,7 +247,7 @@
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        hiddenAPIGenerateCSVRule,
 		Description: "hiddenapi metadata",
-		Input:       classesJar,
+		Inputs:      classesJars,
 		Output:      metadataCSV,
 		Implicit:    stubFlagsCSV,
 		Args: map[string]string{
@@ -255,8 +261,9 @@
 	rule := android.NewRuleBuilder(pctx, ctx)
 	rule.Command().
 		BuiltTool("merge_csv").
-		FlagWithInput("--zip_input=", classesJar).
-		FlagWithOutput("--output=", indexCSV)
+		Flag("--zip_input").
+		FlagWithOutput("--output=", indexCSV).
+		Inputs(classesJars)
 	rule.Build("merged-hiddenapi-index", "Merged Hidden API index")
 	h.indexCSVPath = indexCSV
 
@@ -335,3 +342,16 @@
 		TransformZipAlign(ctx, output, tmpOutput)
 	}
 }
+
+type hiddenApiAnnotationsDependencyTag struct {
+	blueprint.BaseDependencyTag
+}
+
+// Tag used to mark dependencies on java_library instances that contains Java source files whose
+// sole purpose is to provide additional hiddenapi annotations.
+var hiddenApiAnnotationsTag hiddenApiAnnotationsDependencyTag
+
+// Mark this tag so dependencies that use it are excluded from APEX contents.
+func (t hiddenApiAnnotationsDependencyTag) ExcludeFromApexContents() {}
+
+var _ android.ExcludeFromApexContentsTag = hiddenApiAnnotationsTag
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 568d15f..6341a34 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -223,7 +223,7 @@
 
 	ctx.VisitAllModules(func(module android.Module) {
 		// Collect dex jar paths for the modules listed above.
-		if j, ok := module.(Dependency); ok {
+		if j, ok := module.(UsesLibraryDependency); ok {
 			name := ctx.ModuleName(module)
 			for moduleList, pathList := range moduleListToPathList {
 				if i := android.IndexList(name, *moduleList); i != -1 {
diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go
index df825bb..4670d03 100644
--- a/java/hiddenapi_singleton_test.go
+++ b/java/hiddenapi_singleton_test.go
@@ -82,6 +82,10 @@
 			name: "foo",
 			srcs: ["a.java"],
 			compile_dex: true,
+
+			hiddenapi_additional_annotations: [
+				"foo-hiddenapi-annotations",
+			],
 		}
 
 		java_library {
@@ -90,6 +94,12 @@
 			compile_dex: true,
 		}
 
+		java_library {
+			name: "foo-hiddenapi-annotations",
+			srcs: ["a.java"],
+			compile_dex: true,
+		}
+
 		java_import {
 			name: "foo",
 			jars: ["a.jar"],
@@ -112,6 +122,15 @@
 .intermediates/foo/android_common/hiddenapi/index.csv
 `,
 		indexRule)
+
+	// Make sure that the foo-hiddenapi-annotations.jar is included in the inputs to the rules that
+	// creates the index.csv file.
+	foo := ctx.ModuleForTests("foo", "android_common")
+	indexParams := foo.Output("hiddenapi/index.csv")
+	CheckHiddenAPIRuleInputs(t, `
+.intermediates/foo-hiddenapi-annotations/android_common/javac/foo-hiddenapi-annotations.jar
+.intermediates/foo/android_common/javac/foo.jar
+`, indexParams)
 }
 
 func TestHiddenAPISingletonWithPrebuilt(t *testing.T) {
diff --git a/java/java.go b/java/java.go
index 4c6009b..69ec2a4 100644
--- a/java/java.go
+++ b/java/java.go
@@ -298,6 +298,9 @@
 
 	// If true, package the kotlin stdlib into the jar.  Defaults to true.
 	Static_kotlin_stdlib *bool `android:"arch_variant"`
+
+	// A list of java_library instances that provide additional hiddenapi annotations for the library.
+	Hiddenapi_additional_annotations []string
 }
 
 type CompilerDeviceProperties struct {
@@ -533,6 +536,53 @@
 
 var _ android.OutputFileProducer = (*Module)(nil)
 
+// JavaInfo contains information about a java module for use by modules that depend on it.
+type JavaInfo struct {
+	// HeaderJars is a list of jars that can be passed as the javac classpath in order to link
+	// against this module.  If empty, ImplementationJars should be used instead.
+	HeaderJars android.Paths
+
+	// ImplementationAndResourceJars is a list of jars that contain the implementations of classes
+	// in the module as well as any resources included in the module.
+	ImplementationAndResourcesJars android.Paths
+
+	// ImplementationJars is a list of jars that contain the implementations of classes in the
+	//module.
+	ImplementationJars android.Paths
+
+	// ResourceJars is a list of jars that contain the resources included in the module.
+	ResourceJars android.Paths
+
+	// AidlIncludeDirs is a list of directories that should be passed to the aidl tool when
+	// depending on this module.
+	AidlIncludeDirs android.Paths
+
+	// SrcJarArgs is a list of arguments to pass to soong_zip to package the sources of this
+	// module.
+	SrcJarArgs []string
+
+	// SrcJarDeps is a list of paths to depend on when packaging the sources of this module.
+	SrcJarDeps android.Paths
+
+	// ExportedPlugins is a list of paths that should be used as annotation processors for any
+	// module that depends on this module.
+	ExportedPlugins android.Paths
+
+	// ExportedPluginClasses is a list of classes that should be run as annotation processors for
+	// any module that depends on this module.
+	ExportedPluginClasses []string
+
+	// ExportedPluginDisableTurbine is true if this module's annotation processors generate APIs,
+	// requiring disbling turbine for any modules that depend on it.
+	ExportedPluginDisableTurbine bool
+
+	// JacocoReportClassesFile is the path to a jar containing uninstrumented classes that will be
+	// instrumented by jacoco.
+	JacocoReportClassesFile android.Path
+}
+
+var JavaInfoProvider = blueprint.NewProvider(JavaInfo{})
+
 // Methods that need to be implemented for a module that is added to apex java_libs property.
 type ApexDependency interface {
 	HeaderJars() android.Paths
@@ -546,18 +596,6 @@
 	ClassLoaderContexts() dexpreopt.ClassLoaderContextMap
 }
 
-type Dependency interface {
-	ApexDependency
-	UsesLibraryDependency
-	ImplementationJars() android.Paths
-	ResourceJars() android.Paths
-	AidlIncludeDirs() android.Paths
-	ExportedPlugins() (android.Paths, []string, bool)
-	SrcJarArgs() ([]string, android.Paths)
-	BaseModuleName() string
-	JacocoReportClassesFile() android.Path
-}
-
 type xref interface {
 	XrefJavaFiles() android.Paths
 }
@@ -805,6 +843,9 @@
 	libDeps := ctx.AddVariationDependencies(nil, libTag, rewriteSyspropLibs(j.properties.Libs, "libs")...)
 	ctx.AddVariationDependencies(nil, staticLibTag, rewriteSyspropLibs(j.properties.Static_libs, "static_libs")...)
 
+	// Add dependency on libraries that provide additional hidden api annotations.
+	ctx.AddVariationDependencies(nil, hiddenApiAnnotationsTag, j.properties.Hiddenapi_additional_annotations...)
+
 	if ctx.DeviceConfig().VndkVersion() != "" && ctx.Config().EnforceInterPartitionJavaSdkLibrary() {
 		// Require java_sdk_library at inter-partition java dependency to ensure stable
 		// interface between partitions. If inter-partition java_library dependency is detected,
@@ -1111,44 +1152,42 @@
 			return
 		}
 
-		switch dep := module.(type) {
-		case SdkLibraryDependency:
+		if dep, ok := module.(SdkLibraryDependency); ok {
 			switch tag {
 			case libTag:
 				deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
 			case staticLibTag:
 				ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
 			}
-		case Dependency:
+		} else if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
+			dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
 			switch tag {
 			case bootClasspathTag:
-				deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars()...)
+				deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars...)
 			case libTag, instrumentationForTag:
-				deps.classpath = append(deps.classpath, dep.HeaderJars()...)
-				deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
-				pluginJars, pluginClasses, disableTurbine := dep.ExportedPlugins()
-				addPlugins(&deps, pluginJars, pluginClasses...)
-				deps.disableTurbine = deps.disableTurbine || disableTurbine
+				deps.classpath = append(deps.classpath, dep.HeaderJars...)
+				deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...)
+				addPlugins(&deps, dep.ExportedPlugins, dep.ExportedPluginClasses...)
+				deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine
 			case java9LibTag:
-				deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars()...)
+				deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars...)
 			case staticLibTag:
-				deps.classpath = append(deps.classpath, dep.HeaderJars()...)
-				deps.staticJars = append(deps.staticJars, dep.ImplementationJars()...)
-				deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars()...)
-				deps.staticResourceJars = append(deps.staticResourceJars, dep.ResourceJars()...)
-				deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
-				pluginJars, pluginClasses, disableTurbine := dep.ExportedPlugins()
-				addPlugins(&deps, pluginJars, pluginClasses...)
+				deps.classpath = append(deps.classpath, dep.HeaderJars...)
+				deps.staticJars = append(deps.staticJars, dep.ImplementationJars...)
+				deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars...)
+				deps.staticResourceJars = append(deps.staticResourceJars, dep.ResourceJars...)
+				deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...)
+				addPlugins(&deps, dep.ExportedPlugins, dep.ExportedPluginClasses...)
 				// Turbine doesn't run annotation processors, so any module that uses an
 				// annotation processor that generates API is incompatible with the turbine
 				// optimization.
-				deps.disableTurbine = deps.disableTurbine || disableTurbine
+				deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine
 			case pluginTag:
-				if plugin, ok := dep.(*Plugin); ok {
+				if plugin, ok := module.(*Plugin); ok {
 					if plugin.pluginProperties.Processor_class != nil {
-						addPlugins(&deps, plugin.ImplementationAndResourcesJars(), *plugin.pluginProperties.Processor_class)
+						addPlugins(&deps, dep.ImplementationAndResourcesJars, *plugin.pluginProperties.Processor_class)
 					} else {
-						addPlugins(&deps, plugin.ImplementationAndResourcesJars())
+						addPlugins(&deps, dep.ImplementationAndResourcesJars)
 					}
 					// Turbine doesn't run annotation processors, so any module that uses an
 					// annotation processor that generates API is incompatible with the turbine
@@ -1158,14 +1197,14 @@
 					ctx.PropertyErrorf("plugins", "%q is not a java_plugin module", otherName)
 				}
 			case errorpronePluginTag:
-				if plugin, ok := dep.(*Plugin); ok {
-					deps.errorProneProcessorPath = append(deps.errorProneProcessorPath, plugin.ImplementationAndResourcesJars()...)
+				if _, ok := module.(*Plugin); ok {
+					deps.errorProneProcessorPath = append(deps.errorProneProcessorPath, dep.ImplementationAndResourcesJars...)
 				} else {
 					ctx.PropertyErrorf("plugins", "%q is not a java_plugin module", otherName)
 				}
 			case exportedPluginTag:
-				if plugin, ok := dep.(*Plugin); ok {
-					j.exportedPluginJars = append(j.exportedPluginJars, plugin.ImplementationAndResourcesJars()...)
+				if plugin, ok := module.(*Plugin); ok {
+					j.exportedPluginJars = append(j.exportedPluginJars, dep.ImplementationAndResourcesJars...)
 					if plugin.pluginProperties.Processor_class != nil {
 						j.exportedPluginClasses = append(j.exportedPluginClasses, *plugin.pluginProperties.Processor_class)
 					}
@@ -1177,12 +1216,11 @@
 					ctx.PropertyErrorf("exported_plugins", "%q is not a java_plugin module", otherName)
 				}
 			case kotlinStdlibTag:
-				deps.kotlinStdlib = append(deps.kotlinStdlib, dep.HeaderJars()...)
+				deps.kotlinStdlib = append(deps.kotlinStdlib, dep.HeaderJars...)
 			case kotlinAnnotationsTag:
-				deps.kotlinAnnotations = dep.HeaderJars()
+				deps.kotlinAnnotations = dep.HeaderJars
 			}
-
-		case android.SourceFileProducer:
+		} else if dep, ok := module.(android.SourceFileProducer); ok {
 			switch tag {
 			case libTag:
 				checkProducesJars(ctx, dep)
@@ -1193,7 +1231,7 @@
 				deps.staticJars = append(deps.staticJars, dep.Srcs()...)
 				deps.staticHeaderJars = append(deps.staticHeaderJars, dep.Srcs()...)
 			}
-		default:
+		} else {
 			switch tag {
 			case bootClasspathTag:
 				// If a system modules dependency has been added to the bootclasspath
@@ -1860,6 +1898,20 @@
 
 	ctx.CheckbuildFile(outputFile)
 
+	ctx.SetProvider(JavaInfoProvider, JavaInfo{
+		HeaderJars:                     android.PathsIfNonNil(j.headerJarFile),
+		ImplementationAndResourcesJars: android.PathsIfNonNil(j.implementationAndResourcesJar),
+		ImplementationJars:             android.PathsIfNonNil(j.implementationJarFile),
+		ResourceJars:                   android.PathsIfNonNil(j.resourceJar),
+		AidlIncludeDirs:                j.exportAidlIncludeDirs,
+		SrcJarArgs:                     j.srcJarArgs,
+		SrcJarDeps:                     j.srcJarDeps,
+		ExportedPlugins:                j.exportedPluginJars,
+		ExportedPluginClasses:          j.exportedPluginClasses,
+		ExportedPluginDisableTurbine:   j.exportedDisableTurbine,
+		JacocoReportClassesFile:        j.jacocoReportClassesFile,
+	})
+
 	// Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource
 	j.outputFile = outputFile.WithoutRel()
 }
@@ -1967,8 +2019,6 @@
 	return instrumentedJar
 }
 
-var _ Dependency = (*Module)(nil)
-
 func (j *Module) HeaderJars() android.Paths {
 	if j.headerJarFile == nil {
 		return nil
@@ -2382,7 +2432,7 @@
 
 	// list of files or filegroup modules that provide data that should be installed alongside
 	// the test
-	Data []string `android:"path,arch_variant"`
+	Data []string `android:"path"`
 
 	// 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
@@ -2880,15 +2930,15 @@
 	ctx.VisitDirectDeps(func(module android.Module) {
 		tag := ctx.OtherModuleDependencyTag(module)
 
-		switch dep := module.(type) {
-		case Dependency:
+		if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
+			dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
 			switch tag {
 			case libTag, staticLibTag:
-				flags.classpath = append(flags.classpath, dep.HeaderJars()...)
+				flags.classpath = append(flags.classpath, dep.HeaderJars...)
 			case bootClasspathTag:
-				flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars()...)
+				flags.bootClasspath = append(flags.bootClasspath, dep.HeaderJars...)
 			}
-		case SdkLibraryDependency:
+		} else if dep, ok := module.(SdkLibraryDependency); ok {
 			switch tag {
 			case libTag:
 				flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
@@ -2964,6 +3014,13 @@
 			j.dexJarFile = dexOutputFile
 		}
 	}
+
+	ctx.SetProvider(JavaInfoProvider, JavaInfo{
+		HeaderJars:                     android.PathsIfNonNil(j.combinedClasspathFile),
+		ImplementationAndResourcesJars: android.PathsIfNonNil(j.combinedClasspathFile),
+		ImplementationJars:             android.PathsIfNonNil(j.combinedClasspathFile),
+		AidlIncludeDirs:                j.exportAidlIncludeDirs,
+	})
 }
 
 func (j *Import) OutputFiles(tag string) (android.Paths, error) {
@@ -2977,8 +3034,6 @@
 
 var _ android.OutputFileProducer = (*Import)(nil)
 
-var _ Dependency = (*Import)(nil)
-
 func (j *Import) HeaderJars() android.Paths {
 	if j.combinedClasspathFile == nil {
 		return nil
diff --git a/java/jdeps.go b/java/jdeps.go
index 2b5ee74..0ab2e42 100644
--- a/java/jdeps.go
+++ b/java/jdeps.go
@@ -87,8 +87,9 @@
 			dpInfo.Classes = append(dpInfo.Classes, data.Class)
 		}
 
-		if dep, ok := module.(Dependency); ok {
-			dpInfo.Installed_paths = append(dpInfo.Installed_paths, dep.ImplementationJars().Strings()...)
+		if ctx.ModuleHasProvider(module, JavaInfoProvider) {
+			dep := ctx.ModuleProvider(module, JavaInfoProvider).(JavaInfo)
+			dpInfo.Installed_paths = append(dpInfo.Installed_paths, dep.ImplementationJars.Strings()...)
 		}
 		dpInfo.Classes = android.FirstUniqueStrings(dpInfo.Classes)
 		dpInfo.Installed_paths = android.FirstUniqueStrings(dpInfo.Installed_paths)
diff --git a/java/lint.go b/java/lint.go
index cd2a904..c9e0cdd 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -276,8 +276,9 @@
 
 	extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
 	for _, extraLintCheckModule := range extraLintCheckModules {
-		if dep, ok := extraLintCheckModule.(Dependency); ok {
-			l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars()...)
+		if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
+			dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo)
+			l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
 		} else {
 			ctx.PropertyErrorf("lint.extra_check_modules",
 				"%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 1e90149..c91b321 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -106,14 +106,18 @@
 	mctx.CreateModule(ImportFactory, &props)
 }
 
-func createFilegroup(mctx android.LoadHookContext, name string, path string) {
-	filegroupProps := struct {
+func createApiModule(mctx android.LoadHookContext, name string, path string) {
+	genruleProps := struct {
 		Name *string
 		Srcs []string
+		Out  []string
+		Cmd  *string
 	}{}
-	filegroupProps.Name = proptools.StringPtr(name)
-	filegroupProps.Srcs = []string{path}
-	mctx.CreateModule(android.FileGroupFactory, &filegroupProps)
+	genruleProps.Name = proptools.StringPtr(name)
+	genruleProps.Srcs = []string{path}
+	genruleProps.Out = []string{name}
+	genruleProps.Cmd = proptools.StringPtr("cp $(in) $(out)")
+	mctx.CreateModule(genrule.GenRuleFactory, &genruleProps)
 }
 
 func createEmptyFile(mctx android.LoadHookContext, name string) {
@@ -205,16 +209,16 @@
 		path    string
 	}
 
-	// Create filegroups for all (<module>, <scope, <version>) triplets,
-	// and a "latest" filegroup variant for each (<module>, <scope>) pair
-	moduleName := func(module, scope, version string) string {
+	// Create modules for all (<module>, <scope, <version>) triplets,
+	// and a "latest" module variant for each (<module>, <scope>) pair
+	apiModuleName := func(module, scope, version string) string {
 		return module + ".api." + scope + "." + version
 	}
 	m := make(map[string]latestApiInfo)
 	for _, f := range files {
 		localPath := strings.TrimPrefix(f, mydir)
 		module, apiver, scope := parseApiFilePath(mctx, localPath)
-		createFilegroup(mctx, moduleName(module, scope, apiver), localPath)
+		createApiModule(mctx, apiModuleName(module, scope, apiver), localPath)
 
 		version, err := strconv.Atoi(apiver)
 		if err != nil {
@@ -239,8 +243,8 @@
 	// Sort the keys in order to make build.ninja stable
 	for _, k := range android.SortedStringKeys(m) {
 		info := m[k]
-		name := moduleName(info.module, info.scope, "latest")
-		createFilegroup(mctx, name, info.path)
+		name := apiModuleName(info.module, info.scope, "latest")
+		createApiModule(mctx, name, info.path)
 	}
 
 	// Create incompatibilities tracking files for all modules, if we have a "next" api.
@@ -258,14 +262,14 @@
 				referencedModule = "android"
 			}
 
-			createFilegroup(mctx, moduleName(referencedModule+"-incompatibilities", scope, "latest"), localPath)
+			createApiModule(mctx, apiModuleName(referencedModule+"-incompatibilities", scope, "latest"), localPath)
 
 			incompatibilities[referencedModule+"."+scope] = true
 		}
 		// Create empty incompatibilities files for remaining modules
 		for _, k := range android.SortedStringKeys(m) {
 			if _, ok := incompatibilities[k]; !ok {
-				createEmptyFile(mctx, moduleName(m[k].module+"-incompatibilities", m[k].scope, "latest"))
+				createEmptyFile(mctx, apiModuleName(m[k].module+"-incompatibilities", m[k].scope, "latest"))
 			}
 		}
 	}
@@ -279,10 +283,10 @@
 	}
 }
 
-// prebuilt_apis is a meta-module that generates filegroup modules for all
-// API txt files found under the directory where the Android.bp is located.
+// prebuilt_apis is a meta-module that generates modules for all API txt files
+// found under the directory where the Android.bp is located.
 // Specifically, an API file located at ./<ver>/<scope>/api/<module>.txt
-// generates a filegroup module named <module>-api.<scope>.<ver>.
+// generates a module named <module>-api.<scope>.<ver>.
 //
 // It also creates <module>-api.<scope>.latest for the latest <ver>.
 //
diff --git a/java/robolectric.go b/java/robolectric.go
index c821e5b..98bb710 100644
--- a/java/robolectric.go
+++ b/java/robolectric.go
@@ -148,10 +148,10 @@
 	}
 
 	for _, dep := range ctx.GetDirectDepsWithTag(libTag) {
-		m := dep.(Dependency)
-		r.libs = append(r.libs, m.BaseModuleName())
-		if !android.InList(m.BaseModuleName(), config.FrameworkLibraries) {
-			combinedJarJars = append(combinedJarJars, m.ImplementationAndResourcesJars()...)
+		m := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
+		r.libs = append(r.libs, ctx.OtherModuleName(dep))
+		if !android.InList(ctx.OtherModuleName(dep), config.FrameworkLibraries) {
+			combinedJarJars = append(combinedJarJars, m.ImplementationAndResourcesJars...)
 		}
 	}
 
@@ -245,10 +245,10 @@
 	srcJarDeps := append(android.Paths(nil), instrumentedApp.srcJarDeps...)
 
 	for _, m := range ctx.GetDirectDepsWithTag(roboCoverageLibsTag) {
-		if dep, ok := m.(Dependency); ok {
-			depSrcJarArgs, depSrcJarDeps := dep.SrcJarArgs()
-			srcJarArgs = append(srcJarArgs, depSrcJarArgs...)
-			srcJarDeps = append(srcJarDeps, depSrcJarDeps...)
+		if ctx.OtherModuleHasProvider(m, JavaInfoProvider) {
+			dep := ctx.OtherModuleProvider(m, JavaInfoProvider).(JavaInfo)
+			srcJarArgs = append(srcJarArgs, dep.SrcJarArgs...)
+			srcJarDeps = append(srcJarDeps, dep.SrcJarDeps...)
 		}
 	}
 
diff --git a/java/sdk.go b/java/sdk.go
index a68abfb..74d5a81 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -566,10 +566,11 @@
 
 	ctx.VisitAllModules(func(module android.Module) {
 		// Collect dex jar paths for the modules listed above.
-		if j, ok := module.(Dependency); ok {
+		if ctx.ModuleHasProvider(module, JavaInfoProvider) {
+			j := ctx.ModuleProvider(module, JavaInfoProvider).(JavaInfo)
 			name := ctx.ModuleName(module)
 			if i := android.IndexList(name, stubsModules); i != -1 {
-				stubsJars[i] = j.HeaderJars()
+				stubsJars[i] = j.HeaderJars
 			}
 		}
 	})
@@ -640,14 +641,26 @@
 
 	if ctx.Config().PlatformSdkCodename() == "REL" {
 		cmd.Text("echo REL >").Output(out)
-	} else if !ctx.Config().AlwaysUsePrebuiltSdks() {
-		in, err := ctx.GlobWithDeps("frameworks/base/api/*current.txt", nil)
-		if err != nil {
-			ctx.Errorf("error globbing API files: %s", err)
+	} else if ctx.Config().FrameworksBaseDirExists(ctx) && !ctx.Config().AlwaysUsePrebuiltSdks() {
+		cmd.Text("cat")
+		apiTxtFileModules := []string{
+			"frameworks-base-api-current.txt",
+			"frameworks-base-api-system-current.txt",
+			"frameworks-base-api-module-lib-current.txt",
 		}
-
-		cmd.Text("cat").
-			Inputs(android.PathsForSource(ctx, in)).
+		count := 0
+		ctx.VisitAllModules(func(module android.Module) {
+			name := ctx.ModuleName(module)
+			if android.InList(name, apiTxtFileModules) {
+				cmd.Inputs(android.OutputFilesForModule(ctx, module, ""))
+				count++
+			}
+		})
+		if count != len(apiTxtFileModules) {
+			ctx.Errorf("Could not find all the expected API modules %v, found %d\n", apiTxtFileModules, count)
+			return
+		}
+		cmd.Input(android.PathForSource(ctx, "frameworks/base/services/api/current.txt")).
 			Text("| md5sum | cut -d' ' -f1 >").
 			Output(out)
 	} else {
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 638740f..aa96e0d 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -60,12 +60,12 @@
 	apiScope *apiScope
 
 	// Function for extracting appropriate path information from the dependency.
-	depInfoExtractor func(paths *scopePaths, dep android.Module) error
+	depInfoExtractor func(paths *scopePaths, ctx android.ModuleContext, dep android.Module) error
 }
 
 // Extract tag specific information from the dependency.
 func (tag scopeDependencyTag) extractDepInfo(ctx android.ModuleContext, dep android.Module, paths *scopePaths) {
-	err := tag.depInfoExtractor(paths, dep)
+	err := tag.depInfoExtractor(paths, ctx, dep)
 	if err != nil {
 		ctx.ModuleErrorf("has an invalid {scopeDependencyTag: %s} dependency on module %s: %s", tag.name, ctx.OtherModuleName(dep), err.Error())
 	}
@@ -539,13 +539,14 @@
 	stubsSrcJar android.OptionalPath
 }
 
-func (paths *scopePaths) extractStubsLibraryInfoFromDependency(dep android.Module) error {
-	if lib, ok := dep.(Dependency); ok {
-		paths.stubsHeaderPath = lib.HeaderJars()
-		paths.stubsImplPath = lib.ImplementationJars()
+func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error {
+	if ctx.OtherModuleHasProvider(dep, JavaInfoProvider) {
+		lib := ctx.OtherModuleProvider(dep, JavaInfoProvider).(JavaInfo)
+		paths.stubsHeaderPath = lib.HeaderJars
+		paths.stubsImplPath = lib.ImplementationJars
 		return nil
 	} else {
-		return fmt.Errorf("expected module that implements Dependency, e.g. java_library")
+		return fmt.Errorf("expected module that has JavaInfoProvider, e.g. java_library")
 	}
 }
 
@@ -572,7 +573,7 @@
 	paths.removedApiFilePath = android.OptionalPathForPath(provider.RemovedApiFilePath())
 }
 
-func (paths *scopePaths) extractApiInfoFromDep(dep android.Module) error {
+func (paths *scopePaths) extractApiInfoFromDep(ctx android.ModuleContext, dep android.Module) error {
 	return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) {
 		paths.extractApiInfoFromApiStubsProvider(provider)
 	})
@@ -582,13 +583,13 @@
 	paths.stubsSrcJar = android.OptionalPathForPath(provider.StubsSrcJar())
 }
 
-func (paths *scopePaths) extractStubsSourceInfoFromDep(dep android.Module) error {
+func (paths *scopePaths) extractStubsSourceInfoFromDep(ctx android.ModuleContext, dep android.Module) error {
 	return paths.treatDepAsApiStubsSrcProvider(dep, func(provider ApiStubsSrcProvider) {
 		paths.extractStubsSourceInfoFromApiStubsProviders(provider)
 	})
 }
 
-func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(dep android.Module) error {
+func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(ctx android.ModuleContext, dep android.Module) error {
 	return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) {
 		paths.extractApiInfoFromApiStubsProvider(provider)
 		paths.extractStubsSourceInfoFromApiStubsProviders(provider)
@@ -951,7 +952,6 @@
 	commonToSdkLibraryAndImport
 }
 
-var _ Dependency = (*SdkLibrary)(nil)
 var _ SdkLibraryDependency = (*SdkLibrary)(nil)
 
 func (module *SdkLibrary) generateTestAndSystemScopesByDefault() bool {
diff --git a/java/system_modules.go b/java/system_modules.go
index 5cc546d..95f71b8 100644
--- a/java/system_modules.go
+++ b/java/system_modules.go
@@ -160,8 +160,8 @@
 	var jars android.Paths
 
 	ctx.VisitDirectDepsWithTag(systemModulesLibsTag, func(module android.Module) {
-		dep, _ := module.(Dependency)
-		jars = append(jars, dep.HeaderJars()...)
+		dep, _ := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
+		jars = append(jars, dep.HeaderJars...)
 	})
 
 	system.headerJars = jars
diff --git a/rust/compiler.go b/rust/compiler.go
index 224e201..c26f208 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -232,6 +232,10 @@
 		flags.LinkFlags = append(flags.LinkFlags, "-Wl,-rpath,"+rpathPrefix+"../"+rpath)
 	}
 
+	if ctx.RustModule().UseVndk() {
+		flags.RustFlags = append(flags.RustFlags, "--cfg 'android_vndk'")
+	}
+
 	return flags
 }
 
diff --git a/rust/config/arm64_device.go b/rust/config/arm64_device.go
index 5066428..186e571 100644
--- a/rust/config/arm64_device.go
+++ b/rust/config/arm64_device.go
@@ -26,9 +26,10 @@
 	Arm64LinkFlags            = []string{}
 
 	Arm64ArchVariantRustFlags = map[string][]string{
-		"armv8-a":          []string{},
-		"armv8-2a":         []string{},
-		"armv8-2a-dotprod": []string{},
+		"armv8-a":            []string{},
+		"armv8-a-branchprot": []string{},
+		"armv8-2a":           []string{},
+		"armv8-2a-dotprod":   []string{},
 	}
 )
 
diff --git a/rust/image_test.go b/rust/image_test.go
index 1515aa2..e40599c 100644
--- a/rust/image_test.go
+++ b/rust/image_test.go
@@ -15,6 +15,7 @@
 package rust
 
 import (
+	"strings"
 	"testing"
 
 	"android/soong/android"
@@ -23,7 +24,7 @@
 
 // Test that cc modules can link against vendor_available rust_ffi_static libraries.
 func TestVendorLinkage(t *testing.T) {
-	ctx := testRust(t, `
+	ctx := testRustVndk(t, `
 			cc_binary {
 				name: "fizz_vendor",
 				static_libs: ["libfoo_vendor"],
@@ -37,16 +38,34 @@
 			}
 		`)
 
-	vendorBinary := ctx.ModuleForTests("fizz_vendor", "android_arm64_armv8-a").Module().(*cc.Module)
+	vendorBinary := ctx.ModuleForTests("fizz_vendor", "android_vendor.VER_arm64_armv8-a").Module().(*cc.Module)
 
 	if !android.InList("libfoo_vendor", vendorBinary.Properties.AndroidMkStaticLibs) {
 		t.Errorf("vendorBinary should have a dependency on libfoo_vendor")
 	}
 }
 
+// Test that variants which use the vndk emit the appropriate cfg flag.
+func TestImageVndkCfgFlag(t *testing.T) {
+	ctx := testRustVndk(t, `
+			rust_ffi_static {
+				name: "libfoo",
+				crate_name: "foo",
+				srcs: ["foo.rs"],
+				vendor_available: true,
+			}
+		`)
+
+	vendor := ctx.ModuleForTests("libfoo", "android_vendor.VER_arm64_armv8-a_static").Rule("rustc")
+
+	if !strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_vndk'") {
+		t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"])
+	}
+}
+
 // Test that cc modules can link against vendor_ramdisk_available rust_ffi_static libraries.
 func TestVendorRamdiskLinkage(t *testing.T) {
-	ctx := testRust(t, `
+	ctx := testRustVndk(t, `
 			cc_library_static {
 				name: "libcc_vendor_ramdisk",
 				static_libs: ["libfoo_vendor_ramdisk"],
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 88d9643..a0ed534 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -64,6 +64,14 @@
 	return tctx.parse(t)
 }
 
+func testRustVndk(t *testing.T, bp string) *android.TestContext {
+	tctx := newTestRustCtx(t, bp)
+	tctx.useMockedFs()
+	tctx.generateConfig()
+	tctx.setVndk(t)
+	return tctx.parse(t)
+}
+
 // testRustCov returns a TestContext in which a basic environment has been
 // setup. This environment explicitly enables coverage.
 func testRustCov(t *testing.T, bp string) *android.TestContext {
@@ -140,6 +148,15 @@
 	tctx.config.TestProductVariables.NativeCoveragePaths = []string{"*"}
 }
 
+func (tctx *testRustCtx) setVndk(t *testing.T) {
+	if tctx.config == nil {
+		t.Fatalf("tctx.config not been generated yet. Please call generateConfig first.")
+	}
+	tctx.config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+	tctx.config.TestProductVariables.ProductVndkVersion = StringPtr("current")
+	tctx.config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+}
+
 // parse validates the configuration and parses the Blueprint file. It returns
 // a TestContext which can be used to retrieve the generated modules via
 // ModuleForTests.
diff --git a/scripts/hiddenapi/Android.bp b/scripts/hiddenapi/Android.bp
index a669cad..af7e7fe 100644
--- a/scripts/hiddenapi/Android.bp
+++ b/scripts/hiddenapi/Android.bp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 python_binary_host {
     name: "merge_csv",
     main: "merge_csv.py",
diff --git a/scripts/hiddenapi/merge_csv.py b/scripts/hiddenapi/merge_csv.py
index 6a5b0e1..5ad61b2 100755
--- a/scripts/hiddenapi/merge_csv.py
+++ b/scripts/hiddenapi/merge_csv.py
@@ -26,7 +26,8 @@
 args_parser = argparse.ArgumentParser(description='Merge given CSV files into a single one.')
 args_parser.add_argument('--header', help='Comma separated field names; '
                                           'if missing determines the header from input files.')
-args_parser.add_argument('--zip_input', help='ZIP archive with all CSV files to merge.')
+args_parser.add_argument('--zip_input', help='Treat files as ZIP archives containing CSV files to merge.',
+                         action="store_true")
 args_parser.add_argument('--output', help='Output file for merged CSV.',
                          default='-', type=argparse.FileType('w'))
 args_parser.add_argument('files', nargs=argparse.REMAINDER)
@@ -36,20 +37,16 @@
 def dict_reader(input):
     return csv.DictReader(input, delimiter=',', quotechar='|')
 
-
-if args.zip_input and len(args.files) > 0:
-    raise ValueError('Expecting either a single ZIP with CSV files'
-                     ' or a list of CSV files as input; not both.')
-
 csv_readers = []
-if len(args.files) > 0:
+if not(args.zip_input):
     for file in args.files:
         csv_readers.append(dict_reader(open(file, 'r')))
-elif args.zip_input:
-    with ZipFile(args.zip_input) as zip:
-        for entry in zip.namelist():
-            if entry.endswith('.uau'):
-                csv_readers.append(dict_reader(io.TextIOWrapper(zip.open(entry, 'r'))))
+else:
+    for file in args.files:
+        with ZipFile(file) as zip:
+            for entry in zip.namelist():
+                if entry.endswith('.uau'):
+                    csv_readers.append(dict_reader(io.TextIOWrapper(zip.open(entry, 'r'))))
 
 headers = set()
 if args.header: