Merge "Switch cc_test host_supported: true to unit tests"
diff --git a/Android.bp b/Android.bp
index 1012dba..9d5b07d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 subdirs = [
     "androidmk",
     "bpfix",
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index ff85661..317f5c4 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,3 +1,6 @@
 [Builtin Hooks]
 gofmt = true
 bpfmt = true
+
+[Hook Scripts]
+do_not_use_DO_NOT_MERGE = ${REPO_ROOT}/build/soong/scripts/check_do_not_merge.sh ${PREUPLOAD_COMMIT}
diff --git a/android/Android.bp b/android/Android.bp
index eabb137..00139d8 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-android",
     pkgPath: "android/soong/android",
diff --git a/android/apex.go b/android/apex.go
index b87ff09..4637942 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -749,74 +749,60 @@
 	}
 	return list
 }(map[string]int{
-	"adbd":                  30,
-	"android.net.ipsec.ike": 30,
-	"androidx-constraintlayout_constraintlayout-solver": 30,
-	"androidx.annotation_annotation":                    28,
-	"androidx.arch.core_core-common":                    28,
-	"androidx.collection_collection":                    28,
-	"androidx.lifecycle_lifecycle-common":               28,
-	"apache-commons-compress":                           29,
-	"bouncycastle_ike_digests":                          30,
-	"brotli-java":                                       29,
-	"captiveportal-lib":                                 28,
-	"flatbuffer_headers":                                30,
-	"framework-permission":                              30,
-	"framework-statsd":                                  30,
-	"gemmlowp_headers":                                  30,
-	"ike-internals":                                     30,
-	"kotlinx-coroutines-android":                        28,
-	"kotlinx-coroutines-core":                           28,
-	"libadb_crypto":                                     30,
-	"libadb_pairing_auth":                               30,
-	"libadb_pairing_connection":                         30,
-	"libadb_pairing_server":                             30,
-	"libadb_protos":                                     30,
-	"libadb_tls_connection":                             30,
-	"libadbconnection_client":                           30,
-	"libadbconnection_server":                           30,
-	"libadbd_core":                                      30,
-	"libadbd_services":                                  30,
-	"libadbd":                                           30,
-	"libapp_processes_protos_lite":                      30,
-	"libasyncio":                                        30,
-	"libbrotli":                                         30,
-	"libbuildversion":                                   30,
-	"libcrypto_static":                                  30,
-	"libcrypto_utils":                                   30,
-	"libdiagnose_usb":                                   30,
-	"libeigen":                                          30,
-	"liblz4":                                            30,
-	"libmdnssd":                                         30,
-	"libneuralnetworks_common":                          30,
-	"libneuralnetworks_headers":                         30,
-	"libneuralnetworks":                                 30,
-	"libprocpartition":                                  30,
-	"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,
-	"libtflite_kernel_utils":                            30,
-	"libwatchdog":                                       29,
-	"libzstd":                                           30,
-	"metrics-constants-protos":                          28,
-	"net-utils-framework-common":                        29,
-	"permissioncontroller-statsd":                       28,
-	"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,
+	"adbd":                           30,
+	"android.net.ipsec.ike":          30,
+	"apache-commons-compress":        29,
+	"bouncycastle_ike_digests":       30,
+	"brotli-java":                    29,
+	"captiveportal-lib":              28,
+	"flatbuffer_headers":             30,
+	"framework-permission":           30,
+	"gemmlowp_headers":               30,
+	"ike-internals":                  30,
+	"kotlinx-coroutines-android":     28,
+	"kotlinx-coroutines-core":        28,
+	"libadb_crypto":                  30,
+	"libadb_pairing_auth":            30,
+	"libadb_pairing_connection":      30,
+	"libadb_pairing_server":          30,
+	"libadb_protos":                  30,
+	"libadb_tls_connection":          30,
+	"libadbconnection_client":        30,
+	"libadbconnection_server":        30,
+	"libadbd_core":                   30,
+	"libadbd_services":               30,
+	"libadbd":                        30,
+	"libapp_processes_protos_lite":   30,
+	"libasyncio":                     30,
+	"libbrotli":                      30,
+	"libbuildversion":                30,
+	"libcrypto_static":               30,
+	"libcrypto_utils":                30,
+	"libdiagnose_usb":                30,
+	"libeigen":                       30,
+	"liblz4":                         30,
+	"libmdnssd":                      30,
+	"libneuralnetworks_common":       30,
+	"libneuralnetworks_headers":      30,
+	"libneuralnetworks":              30,
+	"libprocpartition":               30,
+	"libprotobuf-java-lite":          30,
+	"libprotoutil":                   30,
+	"libqemu_pipe":                   30,
+	"libsync":                        30,
+	"libtextclassifier_hash_headers": 30,
+	"libtextclassifier_hash_static":  30,
+	"libtflite_kernel_utils":         30,
+	"libwatchdog":                    29,
+	"libzstd":                        30,
+	"metrics-constants-protos":       28,
+	"net-utils-framework-common":     29,
+	"permissioncontroller-statsd":    28,
+	"philox_random_headers":          30,
+	"philox_random":                  30,
+	"service-permission":             30,
+	"tensorflow_headers":             30,
+	"xz-java":                        29,
 })
 
 // Function called while walking an APEX's payload dependencies.
diff --git a/android/api_levels.go b/android/api_levels.go
index 1b53f3f..2f6a9d2 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -24,6 +24,8 @@
 	RegisterSingletonType("api_levels", ApiLevelsSingleton)
 }
 
+const previewAPILevelBase = 9000
+
 // An API level, which may be a finalized (numbered) API, a preview (codenamed)
 // API, or the future API level (10000). Can be parsed from a string with
 // ApiLevelFromUser or ApiLevelOrPanic.
@@ -57,6 +59,21 @@
 	}
 }
 
+// FinalOrPreviewInt distinguishes preview versions from "current" (future).
+// This is for "native" stubs and should be in sync with ndkstubgen/getApiLevelsMap().
+// - "current" -> future (10000)
+// - preview codenames -> preview base (9000) + index
+// - otherwise -> cast to int
+func (this ApiLevel) FinalOrPreviewInt() int {
+	if this.IsCurrent() {
+		return this.number
+	}
+	if this.IsPreview() {
+		return previewAPILevelBase + this.number
+	}
+	return this.number
+}
+
 // Returns the canonical name for this API level. For a finalized API level
 // this will be the API number as a string. For a preview API level this
 // will be the codename, or "current".
@@ -282,7 +299,6 @@
 
 func getApiLevelsMap(config Config) map[string]int {
 	return config.Once(apiLevelsMapKey, func() interface{} {
-		baseApiLevel := 9000
 		apiLevelsMap := map[string]int{
 			"G":     9,
 			"I":     14,
@@ -302,7 +318,7 @@
 			"R":     30,
 		}
 		for i, codename := range config.PlatformVersionActiveCodenames() {
-			apiLevelsMap[codename] = baseApiLevel + i
+			apiLevelsMap[codename] = previewAPILevelBase + i
 		}
 
 		return apiLevelsMap
diff --git a/android/arch.go b/android/arch.go
index abcdbbb..6fb70c9 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -436,7 +436,7 @@
 	// blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext
 	// filters out non-Soong modules.  Now that we've handled them, create a
 	// normal android.BottomUpMutatorContext.
-	mctx := bottomUpMutatorContextFactory(bpctx, module, false)
+	mctx := bottomUpMutatorContextFactory(bpctx, module, false, false)
 
 	base := module.base()
 
@@ -576,7 +576,7 @@
 	// blueprint.BottomUpMutatorContext because android.BottomUpMutatorContext
 	// filters out non-Soong modules.  Now that we've handled them, create a
 	// normal android.BottomUpMutatorContext.
-	mctx := bottomUpMutatorContextFactory(bpctx, module, false)
+	mctx := bottomUpMutatorContextFactory(bpctx, module, false, false)
 
 	base := module.base()
 
@@ -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"}},
 	}
@@ -1609,13 +1609,15 @@
 		} else {
 			buildTargets = firstTarget(targets, "lib64", "lib32")
 		}
+	case "first_prefer32":
+		buildTargets = firstTarget(targets, "lib32", "lib64")
 	case "prefer32":
 		buildTargets = filterMultilibTargets(targets, "lib32")
 		if len(buildTargets) == 0 {
 			buildTargets = filterMultilibTargets(targets, "lib64")
 		}
 	default:
-		return nil, fmt.Errorf(`compile_multilib must be "both", "first", "32", "64", or "prefer32" found %q`,
+		return nil, fmt.Errorf(`compile_multilib must be "both", "first", "32", "64", "prefer32" or "first_prefer32" found %q`,
 			multilib)
 	}
 
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/bazel_handler.go b/android/bazel_handler.go
index 4a25119..a5c4bed 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -234,6 +234,13 @@
 	cmdFlags = append(cmdFlags, labels...)
 	cmdFlags = append(cmdFlags, "--package_path=%workspace%/"+context.intermediatesDir())
 	cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(context, runName))
+	// Set default platforms to canonicalized values for mixed builds requests. If these are set
+	// in the bazelrc, they will have values that are non-canonicalized, and thus be invalid.
+	// The actual platform values here may be overridden by configuration transitions from the buildroot.
+	cmdFlags = append(cmdFlags,
+		fmt.Sprintf("--platforms=%s", canonicalizeLabel("//build/bazel/platforms:generic_x86_64")))
+	cmdFlags = append(cmdFlags,
+		fmt.Sprintf("--extra_toolchains=%s", canonicalizeLabel("//prebuilts/clang/host/linux-x86:all")))
 	cmdFlags = append(cmdFlags, extraFlags...)
 
 	bazelCmd := exec.Command(context.bazelPath, cmdFlags...)
@@ -460,7 +467,6 @@
 		return err
 	}
 
-	fmt.Printf("Build statements %s", context.buildStatements)
 	// Clear requests.
 	context.requests = map[cqueryKey]bool{}
 	return nil
diff --git a/android/config.go b/android/config.go
index 8090889..c6885dd 100644
--- a/android/config.go
+++ b/android/config.go
@@ -24,6 +24,7 @@
 	"os"
 	"path/filepath"
 	"runtime"
+	"strconv"
 	"strings"
 	"sync"
 
@@ -127,7 +128,7 @@
 
 	// If testAllowNonExistentPaths is true then PathForSource and PathForModuleSrc won't error
 	// in tests when a path doesn't exist.
-	testAllowNonExistentPaths bool
+	TestAllowNonExistentPaths bool
 
 	// The list of files that when changed, must invalidate soong_build to
 	// regenerate build.ninja.
@@ -246,6 +247,7 @@
 			AAPTCharacteristics:               stringPtr("nosdcard"),
 			AAPTPrebuiltDPI:                   []string{"xhdpi", "xxhdpi"},
 			UncompressPrivAppDex:              boolPtr(true),
+			ShippingApiLevel:                  stringPtr("30"),
 		},
 
 		buildDir:     buildDir,
@@ -254,7 +256,7 @@
 
 		// Set testAllowNonExistentPaths so that test contexts don't need to specify every path
 		// passed to PathForSource or PathForModuleSrc.
-		testAllowNonExistentPaths: true,
+		TestAllowNonExistentPaths: true,
 
 		BazelContext: noopBazelContext{},
 	}
@@ -1413,6 +1415,26 @@
 	return c.config.productVariables.VendorSnapshotModules
 }
 
+func (c *deviceConfig) DirectedRecoverySnapshot() bool {
+	return c.config.productVariables.DirectedRecoverySnapshot
+}
+
+func (c *deviceConfig) RecoverySnapshotModules() map[string]bool {
+	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
@@ -1624,21 +1646,33 @@
 func splitConfiguredJarPair(str string) (string, string, error) {
 	pair := strings.SplitN(str, ":", 2)
 	if len(pair) == 2 {
-		return pair[0], pair[1], nil
+		apex := pair[0]
+		jar := pair[1]
+		if apex == "" {
+			return apex, jar, fmt.Errorf("invalid apex '%s' in <apex>:<jar> pair '%s', expected format: <apex>:<jar>", apex, str)
+		}
+		return apex, jar, nil
 	} else {
 		return "error-apex", "error-jar", fmt.Errorf("malformed (apex, jar) pair: '%s', expected format: <apex>:<jar>", str)
 	}
 }
 
-// CreateTestConfiguredJarList is a function to create ConfiguredJarList for
-// tests.
+// CreateTestConfiguredJarList is a function to create ConfiguredJarList for tests.
 func CreateTestConfiguredJarList(list []string) ConfiguredJarList {
-	apexes, jars, err := splitListOfPairsIntoPairOfLists(list)
+	// Create the ConfiguredJarList in as similar way as it is created at runtime by marshalling to
+	// a json list of strings and then unmarshalling into a ConfiguredJarList instance.
+	b, err := json.Marshal(list)
 	if err != nil {
 		panic(err)
 	}
 
-	return ConfiguredJarList{apexes, jars}
+	var jarList ConfiguredJarList
+	err = json.Unmarshal(b, &jarList)
+	if err != nil {
+		panic(err)
+	}
+
+	return jarList
 }
 
 // EmptyConfiguredJarList returns an empty jar list.
diff --git a/android/config_test.go b/android/config_test.go
index 7bfc800..a11115d 100644
--- a/android/config_test.go
+++ b/android/config_test.go
@@ -100,6 +100,22 @@
 		assertStringEquals(t, "apex1:jarA", list1.String())
 	})
 
+	t.Run("create invalid - missing apex", func(t *testing.T) {
+		defer func() {
+			err := recover().(error)
+			assertStringEquals(t, "malformed (apex, jar) pair: 'jarA', expected format: <apex>:<jar>", err.Error())
+		}()
+		CreateTestConfiguredJarList([]string{"jarA"})
+	})
+
+	t.Run("create invalid - empty apex", func(t *testing.T) {
+		defer func() {
+			err := recover().(error)
+			assertStringEquals(t, "invalid apex '' in <apex>:<jar> pair ':jarA', expected format: <apex>:<jar>", err.Error())
+		}()
+		CreateTestConfiguredJarList([]string{":jarA"})
+	})
+
 	list2 := list1.Append("apex2", "jarB")
 	t.Run("append", func(t *testing.T) {
 		assertStringEquals(t, "apex1:jarA,apex2:jarB", list2.String())
diff --git a/android/filegroup.go b/android/filegroup.go
index 3d1bbc5..674a196 100644
--- a/android/filegroup.go
+++ b/android/filegroup.go
@@ -17,8 +17,6 @@
 import (
 	"android/soong/bazel"
 	"strings"
-
-	"github.com/google/blueprint/proptools"
 )
 
 func init() {
@@ -28,8 +26,7 @@
 
 // https://docs.bazel.build/versions/master/be/general.html#filegroup
 type bazelFilegroupAttributes struct {
-	Name *string
-	Srcs []string
+	Srcs bazel.LabelList
 }
 
 type bazelFilegroup struct {
@@ -50,17 +47,19 @@
 
 func (bfg *bazelFilegroup) GenerateAndroidBuildActions(ctx ModuleContext) {}
 
-// TODO: Create helper functions to avoid this boilerplate.
 func FilegroupBp2Build(ctx TopDownMutatorContext) {
-	if m, ok := ctx.Module().(*fileGroup); ok {
-		name := "__bp2build__" + m.base().BaseModuleName()
-		ctx.CreateModule(BazelFileGroupFactory, &bazelFilegroupAttributes{
-			Name: proptools.StringPtr(name),
-			Srcs: m.properties.Srcs,
-		}, &bazel.BazelTargetModuleProperties{
-			Rule_class: "filegroup",
-		})
+	fg, ok := ctx.Module().(*fileGroup)
+	if !ok || !fg.properties.Bazel_module.Bp2build_available {
+		return
 	}
+
+	attrs := &bazelFilegroupAttributes{
+		Srcs: BazelLabelForModuleSrcExcludes(ctx, fg.properties.Srcs, fg.properties.Exclude_srcs),
+	}
+
+	props := bazel.NewBazelTargetModuleProperties(fg.Name(), "filegroup", "")
+
+	ctx.CreateBazelTargetModule(BazelFileGroupFactory, props, attrs)
 }
 
 type fileGroupProperties struct {
diff --git a/android/module.go b/android/module.go
index dcc2b84..bf74cad 100644
--- a/android/module.go
+++ b/android/module.go
@@ -2220,10 +2220,17 @@
 	}
 	var deps []dep
 	b.VisitDirectDepsBlueprint(func(module blueprint.Module) {
-		if aModule, _ := module.(Module); aModule != nil && aModule.base().BaseModuleName() == name {
-			returnedTag := b.bp.OtherModuleDependencyTag(aModule)
+		if aModule, _ := module.(Module); aModule != nil {
+			if aModule.base().BaseModuleName() == name {
+				returnedTag := b.bp.OtherModuleDependencyTag(aModule)
+				if tag == nil || returnedTag == tag {
+					deps = append(deps, dep{aModule, returnedTag})
+				}
+			}
+		} else if b.bp.OtherModuleName(module) == name {
+			returnedTag := b.bp.OtherModuleDependencyTag(module)
 			if tag == nil || returnedTag == tag {
-				deps = append(deps, dep{aModule, returnedTag})
+				deps = append(deps, dep{module, returnedTag})
 			}
 		}
 	})
@@ -2367,6 +2374,16 @@
 	return b.bp.FinalModule().(Module)
 }
 
+// IsMetaDependencyTag returns true for cross-cutting metadata dependencies.
+func IsMetaDependencyTag(tag blueprint.DependencyTag) bool {
+	if tag == licenseKindTag {
+		return true
+	} else if tag == licensesTag {
+		return true
+	}
+	return false
+}
+
 // A regexp for removing boilerplate from BaseDependencyTag from the string representation of
 // a dependency tag.
 var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:{}\E(, )?`)
diff --git a/android/mutator.go b/android/mutator.go
index 6b19dc5..c387193 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -15,7 +15,10 @@
 package android
 
 import (
+	"android/soong/bazel"
+	"fmt"
 	"reflect"
+	"strings"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -45,14 +48,30 @@
 }
 
 // RegisterMutatorsForBazelConversion is a alternate registration pipeline for bp2build. Exported for testing.
-func RegisterMutatorsForBazelConversion(ctx *blueprint.Context, bp2buildMutators []RegisterMutatorFunc) {
-	mctx := &registerMutatorsContext{}
-
-	sharedMutators := []RegisterMutatorFunc{
-		RegisterDefaultsPreArchMutators,
+func RegisterMutatorsForBazelConversion(ctx *blueprint.Context, preArchMutators, depsMutators, bp2buildMutators []RegisterMutatorFunc) {
+	mctx := &registerMutatorsContext{
+		bazelConversionMode: true,
 	}
 
-	for _, f := range sharedMutators {
+	bp2buildPreArchMutators = append([]RegisterMutatorFunc{
+		RegisterNamespaceMutator,
+		RegisterDefaultsPreArchMutators,
+		// TODO(b/165114590): this is required to resolve deps that are only prebuilts, but we should
+		// evaluate the impact on conversion.
+		RegisterPrebuiltsPreArchMutators,
+	},
+		preArchMutators...)
+
+	for _, f := range bp2buildPreArchMutators {
+		f(mctx)
+	}
+
+	bp2buildDepsMutators = append([]RegisterMutatorFunc{
+		registerDepsMutatorBp2Build,
+		registerPathDepsMutator,
+	}, depsMutators...)
+
+	for _, f := range bp2buildDepsMutators {
 		f(mctx)
 	}
 
@@ -77,7 +96,7 @@
 
 	register(preDeps)
 
-	mctx.BottomUp("deps", depsMutator).Parallel()
+	register([]RegisterMutatorFunc{registerDepsMutator})
 
 	register(postDeps)
 
@@ -88,8 +107,9 @@
 }
 
 type registerMutatorsContext struct {
-	mutators   []*mutator
-	finalPhase bool
+	mutators            []*mutator
+	finalPhase          bool
+	bazelConversionMode bool
 }
 
 type RegisterMutatorsContext interface {
@@ -211,6 +231,8 @@
 	finalDeps = append(finalDeps, f)
 }
 
+var bp2buildPreArchMutators = []RegisterMutatorFunc{}
+var bp2buildDepsMutators = []RegisterMutatorFunc{}
 var bp2buildMutators = []RegisterMutatorFunc{}
 
 // RegisterBp2BuildMutator registers specially crafted mutators for
@@ -219,13 +241,24 @@
 //
 // TODO(b/178068862): bring this into TestContext.
 func RegisterBp2BuildMutator(moduleType string, m func(TopDownMutatorContext)) {
-	mutatorName := moduleType + "_bp2build"
 	f := func(ctx RegisterMutatorsContext) {
-		ctx.TopDown(mutatorName, m)
+		ctx.TopDown(moduleType, m)
 	}
 	bp2buildMutators = append(bp2buildMutators, f)
 }
 
+// PreArchBp2BuildMutators adds mutators to be register for converting Android Blueprint modules
+// into Bazel BUILD targets that should run prior to deps and conversion.
+func PreArchBp2BuildMutators(f RegisterMutatorFunc) {
+	bp2buildPreArchMutators = append(bp2buildPreArchMutators, f)
+}
+
+// DepsBp2BuildMutators adds mutators to be register for converting Android Blueprint modules into
+// Bazel BUILD targets that should run prior to conversion to resolve dependencies.
+func DepsBp2BuildMutators(f RegisterMutatorFunc) {
+	bp2buildDepsMutators = append(bp2buildDepsMutators, f)
+}
+
 type BaseMutatorContext interface {
 	BaseModuleContext
 
@@ -245,6 +278,12 @@
 	// CreateModule creates a new module by calling the factory method for the specified moduleType, and applies
 	// the specified property structs to it as if the properties were set in a blueprint file.
 	CreateModule(ModuleFactory, ...interface{}) Module
+
+	// CreateBazelTargetModule creates a BazelTargetModule by calling the
+	// factory method, just like in CreateModule, but also requires
+	// BazelTargetModuleProperties containing additional metadata for the
+	// bp2build codegenerator.
+	CreateBazelTargetModule(ModuleFactory, bazel.BazelTargetModuleProperties, interface{}) BazelTargetModule
 }
 
 type topDownMutatorContext struct {
@@ -370,32 +409,38 @@
 	// variant of the current module.  The value should not be modified after being passed to
 	// SetVariationProvider.
 	SetVariationProvider(module blueprint.Module, provider blueprint.ProviderKey, value interface{})
+
+	// BazelConversionMode returns whether this mutator is being run as part of Bazel Conversion.
+	BazelConversionMode() bool
 }
 
 type bottomUpMutatorContext struct {
 	bp blueprint.BottomUpMutatorContext
 	baseModuleContext
-	finalPhase bool
+	finalPhase          bool
+	bazelConversionMode bool
 }
 
 func bottomUpMutatorContextFactory(ctx blueprint.BottomUpMutatorContext, a Module,
-	finalPhase bool) BottomUpMutatorContext {
+	finalPhase, bazelConversionMode bool) BottomUpMutatorContext {
 
 	return &bottomUpMutatorContext{
-		bp:                ctx,
-		baseModuleContext: a.base().baseModuleContextFactory(ctx),
-		finalPhase:        finalPhase,
+		bp:                  ctx,
+		baseModuleContext:   a.base().baseModuleContextFactory(ctx),
+		finalPhase:          finalPhase,
+		bazelConversionMode: bazelConversionMode,
 	}
 }
 
 func (x *registerMutatorsContext) BottomUp(name string, m BottomUpMutator) MutatorHandle {
 	finalPhase := x.finalPhase
+	bazelConversionMode := x.bazelConversionMode
 	f := func(ctx blueprint.BottomUpMutatorContext) {
 		if a, ok := ctx.Module().(Module); ok {
-			m(bottomUpMutatorContextFactory(ctx, a, finalPhase))
+			m(bottomUpMutatorContextFactory(ctx, a, finalPhase, bazelConversionMode))
 		}
 	}
-	mutator := &mutator{name: name, bottomUpMutator: f}
+	mutator := &mutator{name: x.mutatorName(name), bottomUpMutator: f}
 	x.mutators = append(x.mutators, mutator)
 	return mutator
 }
@@ -406,6 +451,13 @@
 	return mutator
 }
 
+func (x *registerMutatorsContext) mutatorName(name string) string {
+	if x.bazelConversionMode {
+		return name + "_bp2build"
+	}
+	return name
+}
+
 func (x *registerMutatorsContext) TopDown(name string, m TopDownMutator) MutatorHandle {
 	f := func(ctx blueprint.TopDownMutatorContext) {
 		if a, ok := ctx.Module().(Module); ok {
@@ -416,7 +468,7 @@
 			m(actx)
 		}
 	}
-	mutator := &mutator{name: name, topDownMutator: f}
+	mutator := &mutator{name: x.mutatorName(name), topDownMutator: f}
 	x.mutators = append(x.mutators, mutator)
 	return mutator
 }
@@ -449,6 +501,31 @@
 	}
 }
 
+func registerDepsMutator(ctx RegisterMutatorsContext) {
+	ctx.BottomUp("deps", depsMutator).Parallel()
+}
+
+func registerDepsMutatorBp2Build(ctx RegisterMutatorsContext) {
+	// TODO(b/179313531): Consider a separate mutator that only runs depsMutator for modules that are
+	// being converted to build targets.
+	ctx.BottomUp("deps", depsMutator).Parallel()
+}
+
+func (t *topDownMutatorContext) CreateBazelTargetModule(
+	factory ModuleFactory,
+	bazelProps bazel.BazelTargetModuleProperties,
+	attrs interface{}) BazelTargetModule {
+	if !strings.HasPrefix(*bazelProps.Name, bazel.BazelTargetModuleNamePrefix) {
+		panic(fmt.Errorf(
+			"bp2build error: the bazel target module name must start with '%s': %s",
+			bazel.BazelTargetModuleNamePrefix,
+			*bazelProps.Name,
+		))
+	}
+
+	return t.CreateModule(factory, &bazelProps, attrs).(BazelTargetModule)
+}
+
 func (t *topDownMutatorContext) AppendProperties(props ...interface{}) {
 	for _, p := range props {
 		err := proptools.AppendMatchingProperties(t.Module().base().customizableProperties,
@@ -576,12 +653,28 @@
 
 func (b *bottomUpMutatorContext) AddVariationDependencies(variations []blueprint.Variation, tag blueprint.DependencyTag,
 	names ...string) []blueprint.Module {
+	if b.bazelConversionMode {
+		_, noSelfDeps := RemoveFromList(b.ModuleName(), names)
+		if len(noSelfDeps) == 0 {
+			return []blueprint.Module(nil)
+		}
+		// In Bazel conversion mode, mutators should not have created any variants. So, when adding a
+		// dependency, the variations would not exist and the dependency could not be added, by
+		// specifying no variations, we will allow adding the dependency to succeed.
+		return b.bp.AddFarVariationDependencies(nil, tag, noSelfDeps...)
+	}
 
 	return b.bp.AddVariationDependencies(variations, tag, names...)
 }
 
 func (b *bottomUpMutatorContext) AddFarVariationDependencies(variations []blueprint.Variation,
 	tag blueprint.DependencyTag, names ...string) []blueprint.Module {
+	if b.bazelConversionMode {
+		// In Bazel conversion mode, mutators should not have created any variants. So, when adding a
+		// dependency, the variations would not exist and the dependency could not be added, by
+		// specifying no variations, we will allow adding the dependency to succeed.
+		return b.bp.AddFarVariationDependencies(nil, tag, names...)
+	}
 
 	return b.bp.AddFarVariationDependencies(variations, tag, names...)
 }
@@ -609,3 +702,7 @@
 func (b *bottomUpMutatorContext) SetVariationProvider(module blueprint.Module, provider blueprint.ProviderKey, value interface{}) {
 	b.bp.SetVariationProvider(module, provider, value)
 }
+
+func (b *bottomUpMutatorContext) BazelConversionMode() bool {
+	return b.bazelConversionMode
+}
diff --git a/android/paths.go b/android/paths.go
index 8106958..ada4da6 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -15,6 +15,7 @@
 package android
 
 import (
+	"android/soong/bazel"
 	"fmt"
 	"io/ioutil"
 	"os"
@@ -279,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 {
@@ -288,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 {
@@ -331,6 +333,118 @@
 	return ret
 }
 
+// A subset of the ModuleContext methods which are sufficient to resolve references to paths/deps in
+// order to form a Bazel-compatible label for conversion.
+type BazelConversionPathContext interface {
+	EarlyModulePathContext
+
+	GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
+	OtherModuleName(m blueprint.Module) string
+	OtherModuleDir(m blueprint.Module) string
+}
+
+// BazelLabelForModuleDeps returns a Bazel-compatible label for the requested modules which
+// correspond to dependencies on the module within the given ctx.
+func BazelLabelForModuleDeps(ctx BazelConversionPathContext, modules []string) bazel.LabelList {
+	var labels bazel.LabelList
+	for _, module := range modules {
+		bpText := module
+		if m := SrcIsModule(module); m == "" {
+			module = ":" + module
+		}
+		if m, t := SrcIsModuleWithTag(module); m != "" {
+			l := getOtherModuleLabel(ctx, m, t)
+			l.Bp_text = bpText
+			labels.Includes = append(labels.Includes, l)
+		} else {
+			ctx.ModuleErrorf("%q, is not a module reference", module)
+		}
+	}
+	return labels
+}
+
+// BazelLabelForModuleSrc returns bazel.LabelList with paths rooted from the module's local source
+// directory. It expands globs, and resolves references to modules using the ":name" syntax to
+// bazel-compatible labels.  Properties passed as the paths or excludes argument must have been
+// annotated with struct tag `android:"path"` so that dependencies on other modules will have
+// already been handled by the path_properties mutator.
+func BazelLabelForModuleSrc(ctx BazelConversionPathContext, paths []string) bazel.LabelList {
+	return BazelLabelForModuleSrcExcludes(ctx, paths, []string(nil))
+}
+
+// BazelLabelForModuleSrcExcludes returns bazel.LabelList with paths rooted from the module's local
+// source directory, excluding labels included in the excludes argument. It expands globs, and
+// resolves references to modules using the ":name" syntax to bazel-compatible labels. Properties
+// passed as the paths or excludes argument must have been annotated with struct tag
+// `android:"path"` so that dependencies on other modules will have already been handled by the
+// path_properties mutator.
+func BazelLabelForModuleSrcExcludes(ctx BazelConversionPathContext, paths, excludes []string) bazel.LabelList {
+	excludeLabels := expandSrcsForBazel(ctx, excludes, []string(nil))
+	excluded := make([]string, 0, len(excludeLabels.Includes))
+	for _, e := range excludeLabels.Includes {
+		excluded = append(excluded, e.Label)
+	}
+	labels := expandSrcsForBazel(ctx, paths, excluded)
+	labels.Excludes = excludeLabels.Includes
+	return labels
+}
+
+// expandSrcsForBazel returns bazel.LabelList with paths rooted from the module's local
+// source directory, excluding labels included in the excludes argument. It expands globs, and
+// resolves references to modules using the ":name" syntax to bazel-compatible labels.  Properties
+// passed as the paths or excludes argument must have been annotated with struct tag
+// `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{},
+	}
+	for _, p := range paths {
+		if m, tag := SrcIsModuleWithTag(p); m != "" {
+			l := getOtherModuleLabel(ctx, m, tag)
+			if !InList(l.Label, expandedExcludes) {
+				l.Bp_text = fmt.Sprintf(":%s", m)
+				labels.Includes = append(labels.Includes, l)
+			}
+		} else {
+			var expandedPaths []bazel.Label
+			if pathtools.IsGlob(p) {
+				globbedPaths := GlobFiles(ctx, pathForModuleSrc(ctx, p).String(), expandedExcludes)
+				globbedPaths = PathsWithModuleSrcSubDir(ctx, globbedPaths, "")
+				for _, path := range globbedPaths {
+					s := path.Rel()
+					expandedPaths = append(expandedPaths, bazel.Label{Label: s})
+				}
+			} else {
+				if !InList(p, expandedExcludes) {
+					expandedPaths = append(expandedPaths, bazel.Label{Label: p})
+				}
+			}
+			labels.Includes = append(labels.Includes, expandedPaths...)
+		}
+	}
+	return labels
+}
+
+// getOtherModuleLabel returns a bazel.Label for the given dependency/tag combination for the
+// module. The label will be relative to the current directory if appropriate. The dependency must
+// already be resolved by either deps mutator or path deps mutator.
+func getOtherModuleLabel(ctx BazelConversionPathContext, dep, tag string) bazel.Label {
+	m, _ := ctx.GetDirectDep(dep)
+	// TODO(b/165114590): Convert tag (":name{.tag}") to corresponding Bazel implicit output targets.
+	otherModuleName := ctx.OtherModuleName(m)
+	var label bazel.Label
+	if otherDir, dir := ctx.OtherModuleDir(m), ctx.ModuleDir(); otherDir != dir {
+		label.Label = fmt.Sprintf("//%s:%s", otherDir, otherModuleName)
+	} else {
+		label.Label = fmt.Sprintf(":%s", otherModuleName)
+	}
+	return label
+}
+
 // OutputPaths is a slice of OutputPath objects, with helpers to operate on the collection.
 type OutputPaths []OutputPath
 
@@ -472,7 +586,7 @@
 		p := pathForModuleSrc(ctx, sPath)
 		if exists, _, err := ctx.Config().fs.Exists(p.String()); err != nil {
 			ReportPathErrorf(ctx, "%s: %s", p, err.Error())
-		} else if !exists && !ctx.Config().testAllowNonExistentPaths {
+		} else if !exists && !ctx.Config().TestAllowNonExistentPaths {
 			ReportPathErrorf(ctx, "module source path %q does not exist", p)
 		}
 
@@ -908,15 +1022,16 @@
 		}
 	} else if exists, _, err := ctx.Config().fs.Exists(path.String()); err != nil {
 		ReportPathErrorf(ctx, "%s: %s", path, err.Error())
-	} else if !exists && !ctx.Config().testAllowNonExistentPaths {
+	} else if !exists && !ctx.Config().TestAllowNonExistentPaths {
 		ReportPathErrorf(ctx, "source path %q does not exist", path)
 	}
 	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 {
@@ -1839,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/register.go b/android/register.go
index 02fc97e..18c743f 100644
--- a/android/register.go
+++ b/android/register.go
@@ -115,7 +115,7 @@
 		ctx.RegisterSingletonType(t.name, SingletonFactoryAdaptor(ctx, t.factory))
 	}
 
-	RegisterMutatorsForBazelConversion(ctx.Context, bp2buildMutators)
+	RegisterMutatorsForBazelConversion(ctx.Context, bp2buildPreArchMutators, bp2buildDepsMutators, bp2buildMutators)
 }
 
 // Register the pipeline of singletons, module types, and mutators for
diff --git a/android/sdk.go b/android/sdk.go
index bab0ed8..f2cdc88 100644
--- a/android/sdk.go
+++ b/android/sdk.go
@@ -177,12 +177,6 @@
 	// to the zip
 	CopyToSnapshot(src Path, dest string)
 
-	// Return the path to an empty file.
-	//
-	// This can be used by sdk member types that need to create an empty file in the snapshot, simply
-	// pass the value returned from this to the CopyToSnapshot() method.
-	EmptyFile() Path
-
 	// Unzip the supplied zip into the snapshot relative directory destDir.
 	UnzipToSnapshot(zipPath Path, destDir string)
 
diff --git a/android/soongconfig/Android.bp b/android/soongconfig/Android.bp
index 6bb68eb..e7fa5a0 100644
--- a/android/soongconfig/Android.bp
+++ b/android/soongconfig/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-android-soongconfig",
     pkgPath: "android/soong/android/soongconfig",
diff --git a/android/testing.go b/android/testing.go
index 5640c29..de338bf 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -56,9 +56,9 @@
 
 type TestContext struct {
 	*Context
-	preArch, preDeps, postDeps, finalDeps []RegisterMutatorFunc
-	bp2buildMutators                      []RegisterMutatorFunc
-	NameResolver                          *NameResolver
+	preArch, preDeps, postDeps, finalDeps           []RegisterMutatorFunc
+	bp2buildPreArch, bp2buildDeps, bp2buildMutators []RegisterMutatorFunc
+	NameResolver                                    *NameResolver
 }
 
 func (ctx *TestContext) PreArchMutators(f RegisterMutatorFunc) {
@@ -85,13 +85,24 @@
 // RegisterBp2BuildMutator registers a BazelTargetModule mutator for converting a module
 // type to the equivalent Bazel target.
 func (ctx *TestContext) RegisterBp2BuildMutator(moduleType string, m func(TopDownMutatorContext)) {
-	mutatorName := moduleType + "_bp2build"
 	f := func(ctx RegisterMutatorsContext) {
-		ctx.TopDown(mutatorName, m)
+		ctx.TopDown(moduleType, m)
 	}
 	ctx.bp2buildMutators = append(ctx.bp2buildMutators, f)
 }
 
+// PreArchBp2BuildMutators adds mutators to be register for converting Android Blueprint modules
+// into Bazel BUILD targets that should run prior to deps and conversion.
+func (ctx *TestContext) PreArchBp2BuildMutators(f RegisterMutatorFunc) {
+	ctx.bp2buildPreArch = append(ctx.bp2buildPreArch, f)
+}
+
+// DepsBp2BuildMutators adds mutators to be register for converting Android Blueprint modules into
+// Bazel BUILD targets that should run prior to conversion to resolve dependencies.
+func (ctx *TestContext) DepsBp2BuildMutators(f RegisterMutatorFunc) {
+	ctx.bp2buildDeps = append(ctx.bp2buildDeps, f)
+}
+
 func (ctx *TestContext) Register() {
 	registerMutators(ctx.Context.Context, ctx.preArch, ctx.preDeps, ctx.postDeps, ctx.finalDeps)
 
@@ -100,7 +111,7 @@
 
 // RegisterForBazelConversion prepares a test context for bp2build conversion.
 func (ctx *TestContext) RegisterForBazelConversion() {
-	RegisterMutatorsForBazelConversion(ctx.Context.Context, ctx.bp2buildMutators)
+	RegisterMutatorsForBazelConversion(ctx.Context.Context, ctx.bp2buildPreArch, ctx.bp2buildDeps, ctx.bp2buildMutators)
 }
 
 func (ctx *TestContext) ParseFileList(rootDir string, filePaths []string) (deps []string, errs []error) {
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 9b3ed17..76666c5 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -121,10 +121,6 @@
 			Cppflags []string
 		}
 
-		Use_lmkd_stats_log struct {
-			Cflags []string
-		}
-
 		Arc struct {
 			Cflags            []string `android:"arch_variant"`
 			Exclude_srcs      []string `android:"arch_variant"`
@@ -240,7 +236,6 @@
 	Treble_linker_namespaces     *bool `json:",omitempty"`
 	Enforce_vintf_manifest       *bool `json:",omitempty"`
 	Uml                          *bool `json:",omitempty"`
-	Use_lmkd_stats_log           *bool `json:",omitempty"`
 	Arc                          *bool `json:",omitempty"`
 	MinimizeJavaDebugInfo        *bool `json:",omitempty"`
 
@@ -312,6 +307,9 @@
 	DirectedVendorSnapshot bool            `json:",omitempty"`
 	VendorSnapshotModules  map[string]bool `json:",omitempty"`
 
+	DirectedRecoverySnapshot bool            `json:",omitempty"`
+	RecoverySnapshotModules  map[string]bool `json:",omitempty"`
+
 	BoardVendorSepolicyDirs      []string `json:",omitempty"`
 	BoardOdmSepolicyDirs         []string `json:",omitempty"`
 	BoardReqdMaskPolicy          []string `json:",omitempty"`
@@ -369,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/androidmk/Android.bp b/androidmk/Android.bp
index 70fc1f7..f04d01c 100644
--- a/androidmk/Android.bp
+++ b/androidmk/Android.bp
@@ -16,6 +16,10 @@
 // androidmk Android.mk to Blueprints translator
 //
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "androidmk",
     srcs: [
diff --git a/apex/Android.bp b/apex/Android.bp
index b6fdcf4..8a2edeb 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-apex",
     pkgPath: "android/soong/apex",
diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt
index fb84df8..4e7039c 100644
--- a/apex/allowed_deps.txt
+++ b/apex/allowed_deps.txt
@@ -39,6 +39,7 @@
 android.hardware.media.c2@1.1(minSdkVersion:29)
 android.hardware.media.omx@1.0(minSdkVersion:29)
 android.hardware.media@1.0(minSdkVersion:29)
+android.hardware.neuralnetworks-V1-ndk_platform(minSdkVersion:30)
 android.hardware.neuralnetworks@1.0(minSdkVersion:30)
 android.hardware.neuralnetworks@1.1(minSdkVersion:30)
 android.hardware.neuralnetworks@1.2(minSdkVersion:30)
@@ -52,6 +53,7 @@
 android.hidl.safe_union@1.0(minSdkVersion:29)
 android.hidl.token@1.0(minSdkVersion:29)
 android.hidl.token@1.0-utils(minSdkVersion:29)
+android.net.ipsec.ike(minSdkVersion:30)
 android.net.ipsec.ike(minSdkVersion:current)
 android.net.ipsec.ike.xml(minSdkVersion:(no version))
 androidx-constraintlayout_constraintlayout(minSdkVersion:14)
@@ -174,12 +176,15 @@
 ExtServices-core(minSdkVersion:current)
 flatbuffer_headers(minSdkVersion:(no version))
 fmtlib(minSdkVersion:29)
+fmtlib_ndk(minSdkVersion:29)
+framework-mediaprovider(minSdkVersion:30)
 framework-permission(minSdkVersion:30)
 framework-permission(minSdkVersion:current)
 framework-permission-s(minSdkVersion:30)
 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)
@@ -237,7 +242,9 @@
 libbacktrace_sys.rust_sysroot(minSdkVersion:29)
 libbase(minSdkVersion:29)
 libbase_headers(minSdkVersion:29)
+libbase_ndk(minSdkVersion:29)
 libbinder_headers(minSdkVersion:29)
+libbinder_headers_platform_shared(minSdkVersion:29)
 libbinderthreadstateutils(minSdkVersion:29)
 libbluetooth-types-header(minSdkVersion:29)
 libbrotli(minSdkVersion:(no version))
@@ -311,6 +318,8 @@
 libfmq(minSdkVersion:29)
 libfmq-base(minSdkVersion:29)
 libFraunhoferAAC(minSdkVersion:29)
+libfuse(minSdkVersion:30)
+libfuse_jni(minSdkVersion:30)
 libgav1(minSdkVersion:29)
 libgcc(minSdkVersion:(no version))
 libgcc_stripped(minSdkVersion:(no version))
@@ -422,11 +431,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)
@@ -460,6 +473,7 @@
 libzstd(minSdkVersion:(no version))
 media_ndk_headers(minSdkVersion:29)
 media_plugin_headers(minSdkVersion:29)
+MediaProvider(minSdkVersion:30)
 mediaswcodec(minSdkVersion:29)
 metrics-constants-protos(minSdkVersion:29)
 modules-utils-build(minSdkVersion:29)
@@ -497,6 +511,7 @@
 neuralnetworks_utils_hal_1_1(minSdkVersion:30)
 neuralnetworks_utils_hal_1_2(minSdkVersion:30)
 neuralnetworks_utils_hal_1_3(minSdkVersion:30)
+neuralnetworks_utils_hal_aidl(minSdkVersion:30)
 neuralnetworks_utils_hal_common(minSdkVersion:30)
 neuralnetworks_utils_hal_service(minSdkVersion:30)
 no_op(minSdkVersion:current)
@@ -588,6 +603,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)
@@ -601,7 +617,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 c897042..e06a967 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -54,6 +54,8 @@
 func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) {
 	ctx.TopDown("apex_vndk", apexVndkMutator).Parallel()
 	ctx.BottomUp("apex_vndk_deps", apexVndkDepsMutator).Parallel()
+	ctx.BottomUp("prebuilt_apex_select_source", prebuiltSelectSourceMutator).Parallel()
+	ctx.BottomUp("deapexer_select_source", deapexerSelectSourceMutator).Parallel()
 }
 
 func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
@@ -206,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 {
@@ -578,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) {
@@ -2346,7 +2352,6 @@
 		"libFraunhoferAAC",
 		"libaudio-a2dp-hw-utils",
 		"libaudio-hearing-aid-hw-utils",
-		"libbinder_headers",
 		"libbluetooth",
 		"libbluetooth-types",
 		"libbluetooth-types-header",
@@ -2477,7 +2482,6 @@
 		"libaudiopolicy",
 		"libaudioutils",
 		"libaudioutils_fixedfft",
-		"libbinder_headers",
 		"libbluetooth-types-header",
 		"libbufferhub",
 		"libbufferhub_headers",
@@ -2593,7 +2597,6 @@
 		"libavcenc",
 		"libavservices_minijail",
 		"libavservices_minijail",
-		"libbinder_headers",
 		"libbinderthreadstateutils",
 		"libbluetooth-types-header",
 		"libbufferhub_headers",
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 7f5be7e..bbc4b93 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -994,6 +994,80 @@
 	})
 }
 
+func TestApex_PlatformUsesLatestStubFromApex(t *testing.T) {
+	t.Parallel()
+	//   myapex (Z)
+	//      mylib -----------------.
+	//                             |
+	//   otherapex (29)            |
+	//      libstub's versions: 29 Z current
+	//                                  |
+	//   <platform>                     |
+	//      libplatform ----------------'
+	ctx, _ := testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			native_shared_libs: ["mylib"],
+			min_sdk_version: "Z", // non-final
+		}
+
+		cc_library {
+			name: "mylib",
+			srcs: ["mylib.cpp"],
+			shared_libs: ["libstub"],
+			apex_available: ["myapex"],
+			min_sdk_version: "Z",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		apex {
+			name: "otherapex",
+			key: "myapex.key",
+			native_shared_libs: ["libstub"],
+			min_sdk_version: "29",
+		}
+
+		cc_library {
+			name: "libstub",
+			srcs: ["mylib.cpp"],
+			stubs: {
+				versions: ["29", "Z", "current"],
+			},
+			apex_available: ["otherapex"],
+			min_sdk_version: "29",
+		}
+
+		// platform module depending on libstub from otherapex should use the latest stub("current")
+		cc_library {
+			name: "libplatform",
+			srcs: ["mylib.cpp"],
+			shared_libs: ["libstub"],
+		}
+	`, func(fs map[string][]byte, config android.Config) {
+		config.TestProductVariables.Platform_sdk_codename = proptools.StringPtr("Z")
+		config.TestProductVariables.Platform_sdk_final = proptools.BoolPtr(false)
+		config.TestProductVariables.Platform_version_active_codenames = []string{"Z"}
+	})
+
+	// Ensure that mylib from myapex is built against "min_sdk_version" stub ("Z"), which is non-final
+	mylibCflags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"]
+	ensureContains(t, mylibCflags, "-D__LIBSTUB_API__=9000 ")
+	mylibLdflags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
+	ensureContains(t, mylibLdflags, "libstub/android_arm64_armv8-a_shared_Z/libstub.so ")
+
+	// Ensure that libplatform is built against latest stub ("current") of mylib3 from the apex
+	libplatformCflags := ctx.ModuleForTests("libplatform", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
+	ensureContains(t, libplatformCflags, "-D__LIBSTUB_API__=10000 ") // "current" maps to 10000
+	libplatformLdflags := ctx.ModuleForTests("libplatform", "android_arm64_armv8-a_shared").Rule("ld").Args["libFlags"]
+	ensureContains(t, libplatformLdflags, "libstub/android_arm64_armv8-a_shared_current/libstub.so ")
+}
+
 func TestApexWithExplicitStubsDependency(t *testing.T) {
 	ctx, _ := testApex(t, `
 		apex {
@@ -1965,7 +2039,7 @@
 		},
 		{
 			name:          "Updatable apex with non-stable transitive dep",
-			expectedError: "compiles against Android API, but dependency \"transitive-jar\" is compiling against non-public Android API.",
+			expectedError: "compiles against Android API, but dependency \"transitive-jar\" is compiling against private API.",
 			bp: `
 				apex {
 					name: "myapex",
@@ -4288,16 +4362,16 @@
 		// Empty transformation.
 	}
 
-	checkDexJarBuildPath := func(ctx *android.TestContext, name string) {
+	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)
 		}
 	}
 
-	ensureNoSourceVariant := func(ctx *android.TestContext) {
+	ensureNoSourceVariant := func(t *testing.T, ctx *android.TestContext) {
 		// Make sure that an apex variant is not created for the source module.
 		if expected, actual := []string{"android_common"}, ctx.ModuleVariantsForTests("libfoo"); !reflect.DeepEqual(expected, actual) {
 			t.Errorf("invalid set of variants for %q: expected %q, found %q", "libfoo", expected, actual)
@@ -4328,7 +4402,7 @@
 		// Make sure that dexpreopt can access dex implementation files from the prebuilt.
 		ctx := testDexpreoptWithApexes(t, bp, "", transform)
 
-		checkDexJarBuildPath(ctx, "libfoo")
+		checkDexJarBuildPath(t, ctx, "libfoo")
 	})
 
 	t.Run("prebuilt with source preferred", func(t *testing.T) {
@@ -4360,8 +4434,8 @@
 		// Make sure that dexpreopt can access dex implementation files from the prebuilt.
 		ctx := testDexpreoptWithApexes(t, bp, "", transform)
 
-		checkDexJarBuildPath(ctx, "prebuilt_libfoo")
-		ensureNoSourceVariant(ctx)
+		checkDexJarBuildPath(t, ctx, "prebuilt_libfoo")
+		ensureNoSourceVariant(t, ctx)
 	})
 
 	t.Run("prebuilt preferred with source", func(t *testing.T) {
@@ -4393,8 +4467,8 @@
 		// Make sure that dexpreopt can access dex implementation files from the prebuilt.
 		ctx := testDexpreoptWithApexes(t, bp, "", transform)
 
-		checkDexJarBuildPath(ctx, "prebuilt_libfoo")
-		ensureNoSourceVariant(ctx)
+		checkDexJarBuildPath(t, ctx, "prebuilt_libfoo")
+		ensureNoSourceVariant(t, ctx)
 	})
 }
 
@@ -4403,7 +4477,7 @@
 		config.BootJars = android.CreateTestConfiguredJarList([]string{"myapex:libfoo"})
 	}
 
-	checkBootDexJarPath := func(ctx *android.TestContext, bootDexJarPath string) {
+	checkBootDexJarPath := func(t *testing.T, ctx *android.TestContext, bootDexJarPath string) {
 		s := ctx.SingletonForTests("dex_bootjars")
 		foundLibfooJar := false
 		for _, output := range s.AllOutputs() {
@@ -4421,6 +4495,12 @@
 		}
 	}
 
+	checkHiddenAPIIndexInputs := func(t *testing.T, ctx *android.TestContext, expectedInputs string) {
+		hiddenAPIIndex := ctx.SingletonForTests("hiddenapi_index")
+		indexRule := hiddenAPIIndex.Rule("singleton-merged-hiddenapi-index")
+		java.CheckHiddenAPIRuleInputs(t, expectedInputs, indexRule)
+	}
+
 	t.Run("prebuilt only", func(t *testing.T) {
 		bp := `
 		prebuilt_apex {
@@ -4444,7 +4524,12 @@
 	`
 
 		ctx := testDexpreoptWithApexes(t, bp, "", transform)
-		checkBootDexJarPath(ctx, ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
+		checkBootDexJarPath(t, ctx, ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
+
+		// Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file.
+		checkHiddenAPIIndexInputs(t, ctx, `
+.intermediates/libfoo/android_common_myapex/hiddenapi/index.csv
+`)
 	})
 
 	t.Run("prebuilt with source library preferred", func(t *testing.T) {
@@ -4513,7 +4598,12 @@
 	`
 
 		ctx := testDexpreoptWithApexes(t, bp, "", transform)
-		checkBootDexJarPath(ctx, ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
+		checkBootDexJarPath(t, ctx, ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
+
+		// Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file.
+		checkHiddenAPIIndexInputs(t, ctx, `
+.intermediates/prebuilt_libfoo/android_common_myapex/hiddenapi/index.csv
+`)
 	})
 
 	t.Run("prebuilt with source apex preferred", func(t *testing.T) {
@@ -4557,7 +4647,12 @@
 	`
 
 		ctx := testDexpreoptWithApexes(t, bp, "", transform)
-		checkBootDexJarPath(ctx, ".intermediates/libfoo/android_common_apex10000/aligned/libfoo.jar")
+		checkBootDexJarPath(t, ctx, ".intermediates/libfoo/android_common_apex10000/hiddenapi/libfoo.jar")
+
+		// Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file.
+		checkHiddenAPIIndexInputs(t, ctx, `
+.intermediates/libfoo/android_common_apex10000/hiddenapi/index.csv
+`)
 	})
 
 	t.Run("prebuilt preferred with source apex disabled", func(t *testing.T) {
@@ -4603,7 +4698,12 @@
 	`
 
 		ctx := testDexpreoptWithApexes(t, bp, "", transform)
-		checkBootDexJarPath(ctx, ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
+		checkBootDexJarPath(t, ctx, ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar")
+
+		// Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file.
+		checkHiddenAPIIndexInputs(t, ctx, `
+.intermediates/prebuilt_libfoo/android_common_prebuilt_myapex/hiddenapi/index.csv
+`)
 	})
 }
 
@@ -6230,6 +6330,7 @@
 	android.RegisterPrebuiltMutators(ctx)
 	cc.RegisterRequiredBuildComponentsForTest(ctx)
 	java.RegisterRequiredBuildComponentsForTest(ctx)
+	java.RegisterHiddenApiSingletonComponents(ctx)
 	ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
 	ctx.PreDepsMutators(RegisterPreDepsMutators)
 	ctx.PostDepsMutators(RegisterPostDepsMutators)
@@ -6241,6 +6342,11 @@
 	transformDexpreoptConfig(dexpreoptConfig)
 	dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
 
+	// Make sure that any changes to these dexpreopt properties are mirrored in the corresponding
+	// product variables.
+	config.TestProductVariables.BootJars = dexpreoptConfig.BootJars
+	config.TestProductVariables.UpdatableBootJars = dexpreoptConfig.UpdatableBootJars
+
 	_, errs := ctx.ParseBlueprintsFiles("Android.bp")
 	android.FailIfErrored(t, errs)
 
diff --git a/apex/builder.go b/apex/builder.go
index 16ca74c..2663a67 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -700,15 +700,20 @@
 		})
 		a.apisUsedByModuleFile = apisUsedbyOutputFile
 
+		var libNames []string
+		for _, f := range a.filesInfo {
+			if f.class == nativeSharedLib {
+				libNames = append(libNames, f.stem())
+			}
+		}
 		apisBackedbyOutputFile := android.PathForModuleOut(ctx, a.Name()+"_backing.txt")
 		ndkLibraryList := android.PathForSource(ctx, "system/core/rootdir/etc/public.libraries.android.txt")
 		rule := android.NewRuleBuilder(pctx, ctx)
 		rule.Command().
 			Tool(android.PathForSource(ctx, "build/soong/scripts/gen_ndk_backedby_apex.sh")).
-			Text(imageDir.String()).
-			Implicits(implicitInputs).
 			Output(apisBackedbyOutputFile).
-			Input(ndkLibraryList)
+			Input(ndkLibraryList).
+			Flags(libNames)
 		rule.Build("ndk_backedby_list", "Generate API libraries backed by Apex")
 		a.apisBackedByModuleFile = apisBackedbyOutputFile
 
diff --git a/apex/deapexer.go b/apex/deapexer.go
index 651cadf..8f4a285 100644
--- a/apex/deapexer.go
+++ b/apex/deapexer.go
@@ -78,12 +78,17 @@
 	return p.prebuilt.Name(p.ModuleBase.Name())
 }
 
-func (p *Deapexer) DepsMutator(ctx android.BottomUpMutatorContext) {
-	if err := p.apexFileProperties.selectSource(ctx); err != nil {
-		ctx.ModuleErrorf("%s", err)
+func deapexerSelectSourceMutator(ctx android.BottomUpMutatorContext) {
+	p, ok := ctx.Module().(*Deapexer)
+	if !ok {
 		return
 	}
+	if err := p.apexFileProperties.selectSource(ctx); err != nil {
+		ctx.ModuleErrorf("%s", err)
+	}
+}
 
+func (p *Deapexer) DepsMutator(ctx android.BottomUpMutatorContext) {
 	// Add dependencies from the java modules to which this exports files from the `.apex` file onto
 	// this module so that they can access the `DeapexerInfo` object that this provides.
 	for _, lib := range p.properties.Exported_java_libs {
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index c72a9eb..041afb3 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -250,17 +250,46 @@
 	return name
 }
 
-func (p *Prebuilt) DepsMutator(ctx android.BottomUpMutatorContext) {
-	if err := p.properties.selectSource(ctx); err != nil {
-		ctx.ModuleErrorf("%s", err)
+func prebuiltSelectSourceMutator(ctx android.BottomUpMutatorContext) {
+	p, ok := ctx.Module().(*Prebuilt)
+	if !ok {
 		return
 	}
+	if err := p.properties.selectSource(ctx); err != nil {
+		ctx.ModuleErrorf("%s", err)
+	}
+}
 
+type exportedDependencyTag struct {
+	blueprint.BaseDependencyTag
+	name string
+}
+
+// Mark this tag so dependencies that use it are excluded from visibility enforcement.
+//
+// This does allow any prebuilt_apex to reference any module which does open up a small window for
+// restricted visibility modules to be referenced from the wrong prebuilt_apex. However, doing so
+// avoids opening up a much bigger window by widening the visibility of modules that need files
+// provided by the prebuilt_apex to include all the possible locations they may be defined, which
+// could include everything below vendor/.
+//
+// A prebuilt_apex that references a module via this tag will have to contain the appropriate files
+// corresponding to that module, otherwise it will fail when attempting to retrieve the files from
+// the .apex file. It will also have to be included in the module's apex_available property too.
+// That makes it highly unlikely that a prebuilt_apex would reference a restricted module
+// incorrectly.
+func (t exportedDependencyTag) ExcludeFromVisibilityEnforcement() {}
+
+var (
+	exportedJavaLibTag = exportedDependencyTag{name: "exported_java_lib"}
+)
+
+func (p *Prebuilt) DepsMutator(ctx android.BottomUpMutatorContext) {
 	// Add dependencies onto the java modules that represent the java libraries that are provided by
 	// and exported from this prebuilt apex.
 	for _, lib := range p.properties.Exported_java_libs {
 		dep := prebuiltApexExportedModuleName(ctx, lib)
-		ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), javaLibTag, dep)
+		ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), exportedJavaLibTag, dep)
 	}
 }
 
@@ -300,7 +329,7 @@
 	var dependencies []android.ApexModule
 	mctx.VisitDirectDeps(func(m android.Module) {
 		tag := mctx.OtherModuleDependencyTag(m)
-		if tag == javaLibTag {
+		if tag == exportedJavaLibTag {
 			depName := mctx.OtherModuleName(m)
 
 			// It is an error if the other module is not a prebuilt.
diff --git a/bazel/Android.bp b/bazel/Android.bp
index d222d98..117fd46 100644
--- a/bazel/Android.bp
+++ b/bazel/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-bazel",
     pkgPath: "android/soong/bazel",
diff --git a/bazel/properties.go b/bazel/properties.go
index 79956e1..8055306 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -14,9 +14,17 @@
 
 package bazel
 
+import (
+	"fmt"
+	"strings"
+)
+
 type bazelModuleProperties struct {
 	// The label of the Bazel target replacing this Soong module.
 	Label string
+
+	// If true, bp2build will generate the converted Bazel target for this module.
+	Bp2build_available bool
 }
 
 // Properties contains common module properties for Bazel migration purposes.
@@ -29,9 +37,51 @@
 // BazelTargetModuleProperties contain properties and metadata used for
 // Blueprint to BUILD file conversion.
 type BazelTargetModuleProperties struct {
+	Name *string
+
 	// The Bazel rule class for this target.
 	Rule_class string
 
 	// The target label for the bzl file containing the definition of the rule class.
 	Bzl_load_location string
 }
+
+const BazelTargetModuleNamePrefix = "__bp2build__"
+
+func NewBazelTargetModuleProperties(name string, ruleClass string, bzlLoadLocation string) BazelTargetModuleProperties {
+	if strings.HasPrefix(name, BazelTargetModuleNamePrefix) {
+		panic(fmt.Errorf(
+			"The %s name prefix is added automatically, do not set it manually: %s",
+			BazelTargetModuleNamePrefix,
+			name))
+	}
+	name = BazelTargetModuleNamePrefix + name
+	return BazelTargetModuleProperties{
+		Name:              &name,
+		Rule_class:        ruleClass,
+		Bzl_load_location: bzlLoadLocation,
+	}
+}
+
+// Label is used to represent a Bazel compatible Label. Also stores the original bp text to support
+// string replacement.
+type Label struct {
+	Bp_text string
+	Label   string
+}
+
+// LabelList is used to represent a list of Bazel labels.
+type LabelList struct {
+	Includes []Label
+	Excludes []Label
+}
+
+// Append appends the fields of other labelList to the corresponding fields of ll.
+func (ll *LabelList) Append(other LabelList) {
+	if len(ll.Includes) > 0 || len(other.Includes) > 0 {
+		ll.Includes = append(ll.Includes, other.Includes...)
+	}
+	if len(ll.Excludes) > 0 || len(other.Excludes) > 0 {
+		ll.Excludes = append(other.Excludes, other.Excludes...)
+	}
+}
diff --git a/bloaty/Android.bp b/bloaty/Android.bp
new file mode 100644
index 0000000..b1f1e39
--- /dev/null
+++ b/bloaty/Android.bp
@@ -0,0 +1,40 @@
+bootstrap_go_package {
+    name: "soong-bloaty",
+    pkgPath: "android/soong/bloaty",
+    deps: [
+        "blueprint",
+        "soong-android",
+    ],
+    srcs: [
+        "bloaty.go",
+    ],
+    pluginFor: ["soong_build"],
+}
+
+python_test_host {
+    name: "bloaty_merger_test",
+    srcs: [
+        "bloaty_merger_test.py",
+        "bloaty_merger.py",
+        "file_sections.proto",
+    ],
+    proto: {
+        canonical_path_from_root: false,
+    },
+    libs: [
+        "pyfakefs",
+        "ninja_rsp",
+    ],
+}
+
+python_binary_host {
+    name: "bloaty_merger",
+    srcs: [
+        "bloaty_merger.py",
+        "file_sections.proto",
+    ],
+    proto: {
+        canonical_path_from_root: false,
+    },
+    libs: ["ninja_rsp"],
+}
diff --git a/bloaty/bloaty.go b/bloaty/bloaty.go
new file mode 100644
index 0000000..0bff8aa
--- /dev/null
+++ b/bloaty/bloaty.go
@@ -0,0 +1,92 @@
+// 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 bloaty implements a singleton that measures binary (e.g. ELF
+// executable, shared library or Rust rlib) section sizes at build time.
+package bloaty
+
+import (
+	"android/soong/android"
+
+	"github.com/google/blueprint"
+)
+
+const bloatyDescriptorExt = "bloaty.csv"
+
+var (
+	fileSizeMeasurerKey blueprint.ProviderKey
+	pctx                = android.NewPackageContext("android/soong/bloaty")
+
+	// bloaty is used to measure a binary section sizes.
+	bloaty = pctx.AndroidStaticRule("bloaty",
+		blueprint.RuleParams{
+			Command:     "${bloaty} -n 0 --csv ${in} > ${out}",
+			CommandDeps: []string{"${bloaty}"},
+		})
+
+	// The bloaty merger script is used to combine the outputs from bloaty
+	// into a single protobuf.
+	bloatyMerger = pctx.AndroidStaticRule("bloatyMerger",
+		blueprint.RuleParams{
+			Command:        "${bloatyMerger} ${out}.lst ${out}",
+			CommandDeps:    []string{"${bloatyMerger}"},
+			Rspfile:        "${out}.lst",
+			RspfileContent: "${in}",
+		})
+)
+
+func init() {
+	pctx.VariableConfigMethod("hostPrebuiltTag", android.Config.PrebuiltOS)
+	pctx.SourcePathVariable("bloaty", "prebuilts/build-tools/${hostPrebuiltTag}/bin/bloaty")
+	pctx.HostBinToolVariable("bloatyMerger", "bloaty_merger")
+	android.RegisterSingletonType("file_metrics", fileSizesSingleton)
+	fileSizeMeasurerKey = blueprint.NewProvider(android.ModuleOutPath{})
+}
+
+// MeasureSizeForPath should be called by binary producers (e.g. in builder.go).
+func MeasureSizeForPath(ctx android.ModuleContext, filePath android.WritablePath) {
+	ctx.SetProvider(fileSizeMeasurerKey, filePath)
+}
+
+type sizesSingleton struct{}
+
+func fileSizesSingleton() android.Singleton {
+	return &sizesSingleton{}
+}
+
+func (singleton *sizesSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	var deps android.Paths
+	// Visit all modules. If the size provider give us a binary path to measure,
+	// create the rule to measure it.
+	ctx.VisitAllModules(func(m android.Module) {
+		if !ctx.ModuleHasProvider(m, fileSizeMeasurerKey) {
+			return
+		}
+		filePath := ctx.ModuleProvider(m, fileSizeMeasurerKey).(android.ModuleOutPath)
+		sizeFile := filePath.ReplaceExtension(ctx, bloatyDescriptorExt)
+		ctx.Build(pctx, android.BuildParams{
+			Rule:        bloaty,
+			Description: "bloaty " + filePath.Rel(),
+			Input:       filePath,
+			Output:      sizeFile,
+		})
+		deps = append(deps, sizeFile)
+	})
+
+	ctx.Build(pctx, android.BuildParams{
+		Rule:   bloatyMerger,
+		Inputs: android.SortedUniquePaths(deps),
+		Output: android.PathForOutput(ctx, "binary_sizes.pb"),
+	})
+}
diff --git a/bloaty/bloaty_merger.py b/bloaty/bloaty_merger.py
new file mode 100644
index 0000000..c873fb8
--- /dev/null
+++ b/bloaty/bloaty_merger.py
@@ -0,0 +1,79 @@
+# 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.
+"""Bloaty CSV Merger
+
+Merges a list of .csv files from Bloaty into a protobuf.  It takes the list as
+a first argument and the output as second. For instance:
+
+    $ bloaty_merger binary_sizes.lst binary_sizes.pb
+
+"""
+
+import argparse
+import csv
+
+import ninja_rsp
+
+import file_sections_pb2
+
+BLOATY_EXTENSION = ".bloaty.csv"
+
+def parse_csv(path):
+  """Parses a Bloaty-generated CSV file into a protobuf.
+
+  Args:
+    path: The filepath to the CSV file, relative to $ANDROID_TOP.
+
+  Returns:
+    A file_sections_pb2.File if the file was found; None otherwise.
+  """
+  file_proto = None
+  with open(path, newline='') as csv_file:
+    file_proto = file_sections_pb2.File()
+    if path.endswith(BLOATY_EXTENSION):
+      file_proto.path = path[:-len(BLOATY_EXTENSION)]
+    section_reader = csv.DictReader(csv_file)
+    for row in section_reader:
+      section = file_proto.sections.add()
+      section.name = row["sections"]
+      section.vm_size = int(row["vmsize"])
+      section.file_size = int(row["filesize"])
+  return file_proto
+
+def create_file_size_metrics(input_list, output_proto):
+  """Creates a FileSizeMetrics proto from a list of CSV files.
+
+  Args:
+    input_list: The path to the file which contains the list of CSV files. Each
+        filepath is separated by a space.
+    output_proto: The path for the output protobuf.
+  """
+  metrics = file_sections_pb2.FileSizeMetrics()
+  reader = ninja_rsp.NinjaRspFileReader(input_list)
+  for csv_path in reader:
+    file_proto = parse_csv(csv_path)
+    if file_proto:
+      metrics.files.append(file_proto)
+  with open(output_proto, "wb") as output:
+    output.write(metrics.SerializeToString())
+
+def main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument("input_list_file", help="List of bloaty csv files.")
+  parser.add_argument("output_proto", help="Output proto.")
+  args = parser.parse_args()
+  create_file_size_metrics(args.input_list_file, args.output_proto)
+
+if __name__ == '__main__':
+  main()
diff --git a/bloaty/bloaty_merger_test.py b/bloaty/bloaty_merger_test.py
new file mode 100644
index 0000000..0e3641d
--- /dev/null
+++ b/bloaty/bloaty_merger_test.py
@@ -0,0 +1,65 @@
+# 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.
+import unittest
+
+from pyfakefs import fake_filesystem_unittest
+
+import bloaty_merger
+import file_sections_pb2
+
+
+class BloatyMergerTestCase(fake_filesystem_unittest.TestCase):
+  def setUp(self):
+    self.setUpPyfakefs()
+
+  def test_parse_csv(self):
+    csv_content = "sections,vmsize,filesize\nsection1,2,3\n"
+    self.fs.create_file("file1.bloaty.csv", contents=csv_content)
+    pb = bloaty_merger.parse_csv("file1.bloaty.csv")
+    self.assertEqual(pb.path, "file1")
+    self.assertEqual(len(pb.sections), 1)
+    s = pb.sections[0]
+    self.assertEqual(s.name, "section1")
+    self.assertEqual(s.vm_size, 2)
+    self.assertEqual(s.file_size, 3)
+
+  def test_missing_file(self):
+    with self.assertRaises(FileNotFoundError):
+      bloaty_merger.parse_csv("missing.bloaty.csv")
+
+  def test_malformed_csv(self):
+    csv_content = "header1,heaVder2,header3\n4,5,6\n"
+    self.fs.create_file("file1.bloaty.csv", contents=csv_content)
+    with self.assertRaises(KeyError):
+      bloaty_merger.parse_csv("file1.bloaty.csv")
+
+  def test_create_file_metrics(self):
+    file_list = "file1.bloaty.csv file2.bloaty.csv"
+    file1_content = "sections,vmsize,filesize\nsection1,2,3\nsection2,7,8"
+    file2_content = "sections,vmsize,filesize\nsection1,4,5\n"
+
+    self.fs.create_file("files.lst", contents=file_list)
+    self.fs.create_file("file1.bloaty.csv", contents=file1_content)
+    self.fs.create_file("file2.bloaty.csv", contents=file2_content)
+
+    bloaty_merger.create_file_size_metrics("files.lst", "output.pb")
+
+    metrics = file_sections_pb2.FileSizeMetrics()
+    with open("output.pb", "rb") as output:
+      metrics.ParseFromString(output.read())
+
+
+if __name__ == '__main__':
+  suite = unittest.TestLoader().loadTestsFromTestCase(BloatyMergerTestCase)
+  unittest.TextTestRunner(verbosity=2).run(suite)
diff --git a/bloaty/file_sections.proto b/bloaty/file_sections.proto
new file mode 100644
index 0000000..34a32db
--- /dev/null
+++ b/bloaty/file_sections.proto
@@ -0,0 +1,39 @@
+// 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.
+syntax = "proto2";
+
+package file_sections;
+
+message SectionDescriptior {
+  // Name of the section (e.g. .rodata)
+  optional string name = 1;
+
+  // Size of that section as part of the file.
+  optional uint64 file_size = 2;
+
+  // Size of that section when loaded in memory.
+  optional uint64 vm_size = 3;
+}
+
+message File {
+  // Relative path from $OUT_DIR.
+  optional string path = 1;
+
+  // File sections.
+  repeated SectionDescriptior sections = 2;
+}
+
+message FileSizeMetrics {
+  repeated File files = 1;
+}
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index 2bbe4b5..521bb06 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-bp2build",
     pkgPath: "android/soong/bp2build",
@@ -11,12 +15,17 @@
     deps: [
         "soong-android",
         "soong-bazel",
+        "soong-cc",
         "soong-genrule",
+        "soong-sh",
     ],
     testSrcs: [
         "build_conversion_test.go",
         "bzl_conversion_test.go",
+        "cc_library_headers_conversion_test.go",
+        "cc_object_conversion_test.go",
         "conversion_test.go",
+        "sh_conversion_test.go",
         "testing.go",
     ],
     pluginFor: [
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index 1fa3e06..7ffcfa4 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -16,6 +16,7 @@
 
 import (
 	"android/soong/android"
+	"android/soong/bazel"
 	"fmt"
 	"reflect"
 	"strconv"
@@ -172,12 +173,18 @@
 			}
 			t = generateBazelTarget(ctx, m)
 		case QueryView:
+			// Blocklist certain module types from being generated.
+			if canonicalizeModuleType(ctx.ModuleType(m)) == "package" {
+				// package module name contain slashes, and thus cannot
+				// be mapped cleanly to a bazel label.
+				return
+			}
 			t = generateSoongModuleTarget(ctx, m)
 		default:
 			panic(fmt.Errorf("Unknown code-generation mode: %s", codegenMode))
 		}
 
-		buildFileToTargets[ctx.ModuleDir(m)] = append(buildFileToTargets[dir], t)
+		buildFileToTargets[dir] = append(buildFileToTargets[dir], t)
 	})
 	return buildFileToTargets
 }
@@ -212,6 +219,8 @@
 	// Delete it from being generated in the BUILD file.
 	delete(props.Attrs, "bzl_load_location")
 
+	delete(props.Attrs, "bp2build_available")
+
 	// Return the Bazel target with rule class and attributes, ready to be
 	// code-generated.
 	attributes := propsToAttributes(props.Attrs)
@@ -349,6 +358,13 @@
 		ret += makeIndent(indent)
 		ret += "]"
 	case reflect.Struct:
+		if labels, ok := propertyValue.Interface().(bazel.LabelList); ok {
+			// TODO(b/165114590): convert glob syntax
+			return prettyPrint(reflect.ValueOf(labels.Includes), indent)
+		} else if label, ok := propertyValue.Interface().(bazel.Label); ok {
+			return fmt.Sprintf("%q", label.Label), nil
+		}
+
 		ret = "{\n"
 		// Sort and print the struct props by the key.
 		structProps := extractStructProperties(propertyValue, indent)
@@ -453,7 +469,7 @@
 }
 
 func targetNameForBp2Build(c bpToBuildContext, logicModule blueprint.Module) string {
-	return strings.Replace(c.ModuleName(logicModule), "__bp2build__", "", 1)
+	return strings.Replace(c.ModuleName(logicModule), bazel.BazelTargetModuleNamePrefix, "", 1)
 }
 
 func targetNameWithVariant(c bpToBuildContext, logicModule blueprint.Module) string {
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index df7dd17..422422b 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -17,6 +17,7 @@
 import (
 	"android/soong/android"
 	"android/soong/genrule"
+	"strings"
 	"testing"
 )
 
@@ -227,6 +228,7 @@
 	name: "foo",
     string_list_prop: ["a", "b"],
     string_prop: "a",
+    bazel_module: { bp2build_available: true },
 }`,
 			expectedBazelTarget: `custom(
     name = "foo",
@@ -248,22 +250,26 @@
 		ctx.RegisterForBazelConversion()
 
 		_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
-		android.FailIfErrored(t, errs)
+		if Errored(t, "", errs) {
+			continue
+		}
 		_, errs = ctx.ResolveDependencies(config)
-		android.FailIfErrored(t, errs)
+		if Errored(t, "", errs) {
+			continue
+		}
 
 		bazelTargets := GenerateBazelTargets(ctx.Context.Context, Bp2Build)[dir]
 		if actualCount, expectedCount := len(bazelTargets), 1; actualCount != expectedCount {
-			t.Fatalf("Expected %d bazel target, got %d", expectedCount, actualCount)
-		}
-
-		actualBazelTarget := bazelTargets[0]
-		if actualBazelTarget.content != testCase.expectedBazelTarget {
-			t.Errorf(
-				"Expected generated Bazel target to be '%s', got '%s'",
-				testCase.expectedBazelTarget,
-				actualBazelTarget.content,
-			)
+			t.Errorf("Expected %d bazel target, got %d", expectedCount, actualCount)
+		} else {
+			actualBazelTarget := bazelTargets[0]
+			if actualBazelTarget.content != testCase.expectedBazelTarget {
+				t.Errorf(
+					"Expected generated Bazel target to be '%s', got '%s'",
+					testCase.expectedBazelTarget,
+					actualBazelTarget.content,
+				)
+			}
 		}
 	}
 }
@@ -377,6 +383,7 @@
 		{
 			bp: `custom {
     name: "bar",
+    bazel_module: { bp2build_available: true  },
 }`,
 			expectedBazelTarget: `my_library(
     name = "bar",
@@ -434,28 +441,65 @@
 }
 
 func TestModuleTypeBp2Build(t *testing.T) {
+	otherGenruleBp := map[string]string{
+		"other/Android.bp": `genrule {
+    name: "foo.tool",
+    out: ["foo_tool.out"],
+    srcs: ["foo_tool.in"],
+    cmd: "cp $(in) $(out)",
+}
+genrule {
+    name: "other.tool",
+    out: ["other_tool.out"],
+    srcs: ["other_tool.in"],
+    cmd: "cp $(in) $(out)",
+}`,
+	}
+
 	testCases := []struct {
+		description                        string
 		moduleTypeUnderTest                string
 		moduleTypeUnderTestFactory         android.ModuleFactory
 		moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
+		preArchMutators                    []android.RegisterMutatorFunc
+		depsMutators                       []android.RegisterMutatorFunc
 		bp                                 string
-		expectedBazelTarget                string
-		description                        string
+		expectedBazelTargets               []string
+		fs                                 map[string]string
+		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,
 			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
 			bp: `filegroup {
-	name: "foo",
-	srcs: [],
+    name: "fg_foo",
+    srcs: [],
+    bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTarget: `filegroup(
-    name = "foo",
+			expectedBazelTargets: []string{
+				`filegroup(
+    name = "fg_foo",
     srcs = [
     ],
 )`,
+			},
 		},
 		{
 			description:                        "filegroup with srcs",
@@ -463,30 +507,148 @@
 			moduleTypeUnderTestFactory:         android.FileGroupFactory,
 			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
 			bp: `filegroup {
-	name: "foo",
-	srcs: ["a", "b"],
+    name: "fg_foo",
+    srcs: ["a", "b"],
+    bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTarget: `filegroup(
-    name = "foo",
+			expectedBazelTargets: []string{`filegroup(
+    name = "fg_foo",
     srcs = [
         "a",
         "b",
     ],
 )`,
+			},
+		},
+		{
+			description:                        "filegroup with excludes srcs",
+			moduleTypeUnderTest:                "filegroup",
+			moduleTypeUnderTestFactory:         android.FileGroupFactory,
+			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+			bp: `filegroup {
+    name: "fg_foo",
+    srcs: ["a", "b"],
+    exclude_srcs: ["a"],
+    bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{`filegroup(
+    name = "fg_foo",
+    srcs = [
+        "b",
+    ],
+)`,
+			},
+		},
+		{
+			description:                        "filegroup with glob",
+			moduleTypeUnderTest:                "filegroup",
+			moduleTypeUnderTestFactory:         android.FileGroupFactory,
+			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+			bp: `filegroup {
+    name: "foo",
+    srcs: ["**/*.txt"],
+    bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{`filegroup(
+    name = "foo",
+    srcs = [
+        "other/a.txt",
+        "other/b.txt",
+        "other/subdir/a.txt",
+    ],
+)`,
+			},
+			fs: map[string]string{
+				"other/a.txt":        "",
+				"other/b.txt":        "",
+				"other/subdir/a.txt": "",
+				"other/file":         "",
+			},
+		},
+		{
+			description:                        "filegroup with glob in subdir",
+			moduleTypeUnderTest:                "filegroup",
+			moduleTypeUnderTestFactory:         android.FileGroupFactory,
+			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+			bp: `filegroup {
+    name: "foo",
+    srcs: ["a.txt"],
+    bazel_module: { bp2build_available: true },
+}`,
+			dir: "other",
+			expectedBazelTargets: []string{`filegroup(
+    name = "fg_foo",
+    srcs = [
+        "a.txt",
+        "b.txt",
+        "subdir/a.txt",
+    ],
+)`,
+			},
+			fs: map[string]string{
+				"other/Android.bp": `filegroup {
+    name: "fg_foo",
+    srcs: ["**/*.txt"],
+    bazel_module: { bp2build_available: true },
+}`,
+				"other/a.txt":        "",
+				"other/b.txt":        "",
+				"other/subdir/a.txt": "",
+				"other/file":         "",
+			},
+		},
+		{
+			description:                        "depends_on_other_dir_module",
+			moduleTypeUnderTest:                "filegroup",
+			moduleTypeUnderTestFactory:         android.FileGroupFactory,
+			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+			bp: `filegroup {
+    name: "foobar",
+    srcs: [
+      ":foo",
+        "c",
+    ],
+    bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{`filegroup(
+    name = "foobar",
+    srcs = [
+        "//other:foo",
+        "c",
+    ],
+)`,
+			},
+			fs: map[string]string{
+				"other/Android.bp": `filegroup {
+    name: "foo",
+    srcs: ["a", "b"],
+}`,
+			},
 		},
 		{
 			description:                        "genrule with command line variable replacements",
 			moduleTypeUnderTest:                "genrule",
 			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
 			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+			depsMutators:                       []android.RegisterMutatorFunc{genrule.RegisterGenruleBp2BuildDeps},
 			bp: `genrule {
+    name: "foo.tool",
+    out: ["foo_tool.out"],
+    srcs: ["foo_tool.in"],
+    cmd: "cp $(in) $(out)",
+    bazel_module: { bp2build_available: true },
+}
+
+genrule {
     name: "foo",
     out: ["foo.out"],
     srcs: ["foo.in"],
     tools: [":foo.tool"],
     cmd: "$(location :foo.tool) --genDir=$(genDir) arg $(in) $(out)",
+    bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTarget: `genrule(
+			expectedBazelTargets: []string{
+				`genrule(
     name = "foo",
     cmd = "$(location :foo.tool) --genDir=$(GENDIR) arg $(SRCS) $(OUTS)",
     outs = [
@@ -499,20 +661,41 @@
         ":foo.tool",
     ],
 )`,
+				`genrule(
+    name = "foo.tool",
+    cmd = "cp $(SRCS) $(OUTS)",
+    outs = [
+        "foo_tool.out",
+    ],
+    srcs = [
+        "foo_tool.in",
+    ],
+)`,
+			},
 		},
 		{
 			description:                        "genrule using $(locations :label)",
 			moduleTypeUnderTest:                "genrule",
 			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
 			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+			depsMutators:                       []android.RegisterMutatorFunc{genrule.RegisterGenruleBp2BuildDeps},
 			bp: `genrule {
+    name: "foo.tools",
+    out: ["foo_tool.out", "foo_tool2.out"],
+    srcs: ["foo_tool.in"],
+    cmd: "cp $(in) $(out)",
+    bazel_module: { bp2build_available: true },
+}
+
+genrule {
     name: "foo",
     out: ["foo.out"],
     srcs: ["foo.in"],
     tools: [":foo.tools"],
     cmd: "$(locations :foo.tools) -s $(out) $(in)",
+    bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTarget: `genrule(
+			expectedBazelTargets: []string{`genrule(
     name = "foo",
     cmd = "$(locations :foo.tools) -s $(OUTS) $(SRCS)",
     outs = [
@@ -525,22 +708,96 @@
         ":foo.tools",
     ],
 )`,
+				`genrule(
+    name = "foo.tools",
+    cmd = "cp $(SRCS) $(OUTS)",
+    outs = [
+        "foo_tool.out",
+        "foo_tool2.out",
+    ],
+    srcs = [
+        "foo_tool.in",
+    ],
+)`,
+			},
+		},
+		{
+			description:                        "genrule using $(locations //absolute:label)",
+			moduleTypeUnderTest:                "genrule",
+			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
+			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+			depsMutators:                       []android.RegisterMutatorFunc{genrule.RegisterGenruleBp2BuildDeps},
+			bp: `genrule {
+    name: "foo",
+    out: ["foo.out"],
+    srcs: ["foo.in"],
+    tool_files: [":foo.tool"],
+    cmd: "$(locations :foo.tool) -s $(out) $(in)",
+    bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{`genrule(
+    name = "foo",
+    cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)",
+    outs = [
+        "foo.out",
+    ],
+    srcs = [
+        "foo.in",
+    ],
+    tools = [
+        "//other:foo.tool",
+    ],
+)`,
+			},
+			fs: otherGenruleBp,
+		},
+		{
+			description:                        "genrule srcs using $(locations //absolute:label)",
+			moduleTypeUnderTest:                "genrule",
+			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
+			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+			depsMutators:                       []android.RegisterMutatorFunc{genrule.RegisterGenruleBp2BuildDeps},
+			bp: `genrule {
+    name: "foo",
+    out: ["foo.out"],
+    srcs: [":other.tool"],
+    tool_files: [":foo.tool"],
+    cmd: "$(locations :foo.tool) -s $(out) $(location :other.tool)",
+    bazel_module: { bp2build_available: true },
+}`,
+			expectedBazelTargets: []string{`genrule(
+    name = "foo",
+    cmd = "$(locations //other:foo.tool) -s $(OUTS) $(location //other:other.tool)",
+    outs = [
+        "foo.out",
+    ],
+    srcs = [
+        "//other:other.tool",
+    ],
+    tools = [
+        "//other:foo.tool",
+    ],
+)`,
+			},
+			fs: otherGenruleBp,
 		},
 		{
 			description:                        "genrule using $(location) label should substitute first tool label automatically",
 			moduleTypeUnderTest:                "genrule",
 			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
 			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+			depsMutators:                       []android.RegisterMutatorFunc{genrule.RegisterGenruleBp2BuildDeps},
 			bp: `genrule {
     name: "foo",
     out: ["foo.out"],
     srcs: ["foo.in"],
     tool_files: [":foo.tool", ":other.tool"],
     cmd: "$(location) -s $(out) $(in)",
+    bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTarget: `genrule(
+			expectedBazelTargets: []string{`genrule(
     name = "foo",
-    cmd = "$(location :foo.tool) -s $(OUTS) $(SRCS)",
+    cmd = "$(location //other:foo.tool) -s $(OUTS) $(SRCS)",
     outs = [
         "foo.out",
     ],
@@ -548,26 +805,30 @@
         "foo.in",
     ],
     tools = [
-        ":foo.tool",
-        ":other.tool",
+        "//other:foo.tool",
+        "//other:other.tool",
     ],
 )`,
+			},
+			fs: otherGenruleBp,
 		},
 		{
 			description:                        "genrule using $(locations) label should substitute first tool label automatically",
 			moduleTypeUnderTest:                "genrule",
 			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
 			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+			depsMutators:                       []android.RegisterMutatorFunc{genrule.RegisterGenruleBp2BuildDeps},
 			bp: `genrule {
     name: "foo",
     out: ["foo.out"],
     srcs: ["foo.in"],
     tools: [":foo.tool", ":other.tool"],
     cmd: "$(locations) -s $(out) $(in)",
+    bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTarget: `genrule(
+			expectedBazelTargets: []string{`genrule(
     name = "foo",
-    cmd = "$(locations :foo.tool) -s $(OUTS) $(SRCS)",
+    cmd = "$(locations //other:foo.tool) -s $(OUTS) $(SRCS)",
     outs = [
         "foo.out",
     ],
@@ -575,23 +836,27 @@
         "foo.in",
     ],
     tools = [
-        ":foo.tool",
-        ":other.tool",
+        "//other:foo.tool",
+        "//other:other.tool",
     ],
 )`,
+			},
+			fs: otherGenruleBp,
 		},
 		{
 			description:                        "genrule without tools or tool_files can convert successfully",
 			moduleTypeUnderTest:                "genrule",
 			moduleTypeUnderTestFactory:         genrule.GenRuleFactory,
 			moduleTypeUnderTestBp2BuildMutator: genrule.GenruleBp2Build,
+			depsMutators:                       []android.RegisterMutatorFunc{genrule.RegisterGenruleBp2BuildDeps},
 			bp: `genrule {
     name: "foo",
     out: ["foo.out"],
     srcs: ["foo.in"],
     cmd: "cp $(in) $(out)",
+    bazel_module: { bp2build_available: true },
 }`,
-			expectedBazelTarget: `genrule(
+			expectedBazelTargets: []string{`genrule(
     name = "foo",
     cmd = "cp $(SRCS) $(OUTS)",
     outs = [
@@ -601,39 +866,73 @@
         "foo.in",
     ],
 )`,
+			},
 		},
 	}
 
 	dir := "."
 	for _, testCase := range testCases {
-		config := android.TestConfig(buildDir, nil, testCase.bp, nil)
+		fs := make(map[string][]byte)
+		toParse := []string{
+			"Android.bp",
+		}
+		for f, content := range testCase.fs {
+			if strings.HasSuffix(f, "Android.bp") {
+				toParse = append(toParse, f)
+			}
+			fs[f] = []byte(content)
+		}
+		config := android.TestConfig(buildDir, nil, testCase.bp, fs)
 		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, []string{"Android.bp"})
-		android.FailIfErrored(t, errs)
+		_, errs := ctx.ParseFileList(dir, toParse)
+		if Errored(t, testCase.description, errs) {
+			continue
+		}
 		_, errs = ctx.ResolveDependencies(config)
-		android.FailIfErrored(t, errs)
-
-		bazelTargets := GenerateBazelTargets(ctx.Context.Context, Bp2Build)[dir]
-		if actualCount, expectedCount := len(bazelTargets), 1; actualCount != expectedCount {
-			t.Fatalf("%s: Expected %d bazel target, got %d", testCase.description, expectedCount, actualCount)
+		if Errored(t, testCase.description, errs) {
+			continue
 		}
 
-		actualBazelTarget := bazelTargets[0]
-		if actualBazelTarget.content != testCase.expectedBazelTarget {
-			t.Errorf(
-				"%s: Expected generated Bazel target to be '%s', got '%s'",
-				testCase.description,
-				testCase.expectedBazelTarget,
-				actualBazelTarget.content,
-			)
+		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,
+					)
+				}
+			}
 		}
 	}
 }
 
+func Errored(t *testing.T, desc string, errs []error) bool {
+	t.Helper()
+	if len(errs) > 0 {
+		for _, err := range errs {
+			t.Errorf("%s: %s", desc, err)
+		}
+		return true
+	}
+	return false
+}
+
 type bp2buildMutator = func(android.TopDownMutatorContext)
 
 func TestBp2BuildInlinesDefaults(t *testing.T) {
@@ -661,6 +960,7 @@
     out: ["out"],
     srcs: ["in1"],
     defaults: ["gen_defaults"],
+    bazel_module: { bp2build_available: true },
 }
 `,
 			expectedBazelTarget: `genrule(
@@ -695,6 +995,7 @@
     srcs: ["in1"],
     defaults: ["gen_defaults"],
     cmd: "do-something $(in) $(out)",
+    bazel_module: { bp2build_available: true },
 }
 `,
 			expectedBazelTarget: `genrule(
@@ -733,6 +1034,7 @@
     name: "gen",
     out: ["out"],
     defaults: ["gen_defaults1", "gen_defaults2"],
+    bazel_module: { bp2build_available: true },
 }
 `,
 			expectedBazelTarget: `genrule(
@@ -779,6 +1081,7 @@
     name: "gen",
     out: ["out"],
     defaults: ["gen_defaults1"],
+    bazel_module: { bp2build_available: true },
 }
 `,
 			expectedBazelTarget: `genrule(
@@ -831,3 +1134,80 @@
 		}
 	}
 }
+
+func TestAllowlistingBp2buildTargets(t *testing.T) {
+	testCases := []struct {
+		moduleTypeUnderTest                string
+		moduleTypeUnderTestFactory         android.ModuleFactory
+		moduleTypeUnderTestBp2BuildMutator bp2buildMutator
+		bp                                 string
+		expectedCount                      int
+		description                        string
+	}{
+		{
+			description:                        "explicitly unavailable",
+			moduleTypeUnderTest:                "filegroup",
+			moduleTypeUnderTestFactory:         android.FileGroupFactory,
+			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+			bp: `filegroup {
+    name: "foo",
+    srcs: ["a", "b"],
+    bazel_module: { bp2build_available: false },
+}`,
+			expectedCount: 0,
+		},
+		{
+			description:                        "implicitly unavailable",
+			moduleTypeUnderTest:                "filegroup",
+			moduleTypeUnderTestFactory:         android.FileGroupFactory,
+			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+			bp: `filegroup {
+    name: "foo",
+    srcs: ["a", "b"],
+}`,
+			expectedCount: 0,
+		},
+		{
+			description:                        "explicitly available",
+			moduleTypeUnderTest:                "filegroup",
+			moduleTypeUnderTestFactory:         android.FileGroupFactory,
+			moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+			bp: `filegroup {
+    name: "foo",
+    srcs: ["a", "b"],
+    bazel_module: { bp2build_available: true },
+}`,
+			expectedCount: 1,
+		},
+		{
+			description:                        "generates more than 1 target if needed",
+			moduleTypeUnderTest:                "custom",
+			moduleTypeUnderTestFactory:         customModuleFactory,
+			moduleTypeUnderTestBp2BuildMutator: customBp2BuildMutatorFromStarlark,
+			bp: `custom {
+    name: "foo",
+    bazel_module: { bp2build_available: true },
+}`,
+			expectedCount: 3,
+		},
+	}
+
+	dir := "."
+	for _, testCase := range testCases {
+		config := android.TestConfig(buildDir, nil, testCase.bp, nil)
+		ctx := android.NewTestContext(config)
+		ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
+		ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
+		ctx.RegisterForBazelConversion()
+
+		_, errs := ctx.ParseFileList(dir, []string{"Android.bp"})
+		android.FailIfErrored(t, errs)
+		_, errs = ctx.ResolveDependencies(config)
+		android.FailIfErrored(t, errs)
+
+		bazelTargets := GenerateBazelTargets(ctx.Context.Context, Bp2Build)[dir]
+		if actualCount := len(bazelTargets); actualCount != testCase.expectedCount {
+			t.Fatalf("%s: Expected %d bazel target, got %d", testCase.description, testCase.expectedCount, actualCount)
+		}
+	}
+}
diff --git a/bp2build/bzl_conversion_test.go b/bp2build/bzl_conversion_test.go
index f2a4058..30c1a5b 100644
--- a/bp2build/bzl_conversion_test.go
+++ b/bp2build/bzl_conversion_test.go
@@ -86,6 +86,10 @@
         "soong_module_name": attr.string(mandatory = True),
         "soong_module_variant": attr.string(),
         "soong_module_deps": attr.label_list(providers = [SoongModuleInfo]),
+        # bazel_module start
+#         "label": attr.string(),
+#         "bp2build_available": attr.bool(),
+        # bazel_module end
         "bool_prop": attr.bool(),
         "bool_ptr_prop": attr.bool(),
         "int64_ptr_prop": attr.int(),
diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go
new file mode 100644
index 0000000..3cd3762
--- /dev/null
+++ b/bp2build/cc_library_headers_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/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go
new file mode 100644
index 0000000..e4ffe16
--- /dev/null
+++ b/bp2build/cc_object_conversion_test.go
@@ -0,0 +1,186 @@
+// 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"
+	"fmt"
+	"strings"
+	"testing"
+)
+
+func TestCcObjectBp2Build(t *testing.T) {
+	testCases := []struct {
+		description                        string
+		moduleTypeUnderTest                string
+		moduleTypeUnderTestFactory         android.ModuleFactory
+		moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
+		blueprint                          string
+		expectedBazelTargets               []string
+		filesystem                         map[string]string
+	}{
+		{
+			description:                        "simple cc_object generates cc_object with include header dep",
+			moduleTypeUnderTest:                "cc_object",
+			moduleTypeUnderTestFactory:         cc.ObjectFactory,
+			moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+			filesystem: map[string]string{
+				"a/b/foo.h": "",
+				"a/b/bar.h": "",
+				"a/b/c.c":   "",
+			},
+			blueprint: `cc_object {
+    name: "foo",
+    local_include_dirs: ["include"],
+    cflags: [
+        "-Wno-gcc-compat",
+        "-Wall",
+        "-Werror",
+    ],
+    srcs: [
+        "a/b/*.h",
+        "a/b/c.c"
+    ],
+
+    bazel_module: { bp2build_available: true },
+}
+`,
+			expectedBazelTargets: []string{`cc_object(
+    name = "foo",
+    copts = [
+        "-fno-addrsig",
+        "-Wno-gcc-compat",
+        "-Wall",
+        "-Werror",
+    ],
+    local_include_dirs = [
+        "include",
+    ],
+    srcs = [
+        "a/b/bar.h",
+        "a/b/foo.h",
+        "a/b/c.c",
+    ],
+)`,
+			},
+		},
+		{
+			description:                        "simple cc_object with defaults",
+			moduleTypeUnderTest:                "cc_object",
+			moduleTypeUnderTestFactory:         cc.ObjectFactory,
+			moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build,
+			blueprint: `cc_object {
+    name: "foo",
+    local_include_dirs: ["include"],
+    srcs: [
+        "a/b/*.h",
+        "a/b/c.c"
+    ],
+
+    defaults: ["foo_defaults"],
+    bazel_module: { bp2build_available: true },
+}
+
+cc_defaults {
+    name: "foo_defaults",
+    defaults: ["foo_bar_defaults"],
+	// TODO(b/178130668): handle configurable attributes that depend on the platform
+    arch: {
+        x86: {
+            cflags: ["-fPIC"],
+        },
+        x86_64: {
+            cflags: ["-fPIC"],
+        },
+    },
+}
+
+cc_defaults {
+    name: "foo_bar_defaults",
+    cflags: [
+        "-Wno-gcc-compat",
+        "-Wall",
+        "-Werror",
+    ],
+}
+`,
+			expectedBazelTargets: []string{`cc_object(
+    name = "foo",
+    copts = [
+        "-Wno-gcc-compat",
+        "-Wall",
+        "-Werror",
+        "-fno-addrsig",
+    ],
+    local_include_dirs = [
+        "include",
+    ],
+    srcs = [
+        "a/b/c.c",
+    ],
+)`,
+			},
+		},
+	}
+
+	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.blueprint, filesystem)
+		ctx := android.NewTestContext(config)
+		// Always register cc_defaults module factory
+		ctx.RegisterModuleType("cc_defaults", func() android.Module { return cc.DefaultsFactory() })
+
+		ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
+		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
+		}
+
+		bazelTargets := GenerateBazelTargets(ctx.Context.Context, Bp2Build)[dir]
+		if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
+			fmt.Println(bazelTargets)
+			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/conversion.go b/bp2build/conversion.go
index 62cd8d4..081e082 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -50,14 +50,19 @@
 		sort.Slice(targets, func(i, j int) bool { return targets[i].name < targets[j].name })
 		content := soongModuleLoad
 		if mode == Bp2Build {
-			content = targets.LoadStatements()
+			content = `# This file was automatically generated by bp2build for the Bazel migration project.
+# Feel free to edit or test it, but do *not* check it into your version control system.`
+			content += "\n\n"
+			content += "package(default_visibility = [\"//visibility:public\"])"
+			content += "\n\n"
+			content += targets.LoadStatements()
 		}
 		if content != "" {
 			// If there are load statements, add a couple of newlines.
 			content += "\n\n"
 		}
 		content += targets.String()
-		files = append(files, newFile(dir, "BUILD.bazel", content))
+		files = append(files, newFile(dir, "BUILD", content))
 	}
 	return files
 }
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/bp2build/testing.go b/bp2build/testing.go
index 5e6481b..2e59999 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -3,8 +3,6 @@
 import (
 	"android/soong/android"
 	"android/soong/bazel"
-
-	"github.com/google/blueprint/proptools"
 )
 
 type nestedProps struct {
@@ -29,6 +27,8 @@
 	android.ModuleBase
 
 	props customProps
+
+	bazelProps bazel.Properties
 }
 
 // OutputFiles is needed because some instances of this module use dist with a
@@ -44,6 +44,7 @@
 func customModuleFactoryBase() android.Module {
 	module := &customModule{}
 	module.AddProperties(&module.props)
+	module.AddProperties(&module.bazelProps)
 	return module
 }
 
@@ -105,7 +106,6 @@
 }
 
 type customBazelModuleAttributes struct {
-	Name             *string
 	String_prop      string
 	String_list_prop []string
 }
@@ -127,14 +127,18 @@
 
 func customBp2BuildMutator(ctx android.TopDownMutatorContext) {
 	if m, ok := ctx.Module().(*customModule); ok {
-		name := "__bp2build__" + m.Name()
-		ctx.CreateModule(customBazelModuleFactory, &customBazelModuleAttributes{
-			Name:             proptools.StringPtr(name),
+		if !m.bazelProps.Bazel_module.Bp2build_available {
+			return
+		}
+
+		attrs := &customBazelModuleAttributes{
 			String_prop:      m.props.String_prop,
 			String_list_prop: m.props.String_list_prop,
-		}, &bazel.BazelTargetModuleProperties{
-			Rule_class: "custom",
-		})
+		}
+
+		props := bazel.NewBazelTargetModuleProperties(m.Name(), "custom", "")
+
+		ctx.CreateBazelTargetModule(customBazelModuleFactory, props, attrs)
 	}
 }
 
@@ -142,24 +146,32 @@
 // module to target.
 func customBp2BuildMutatorFromStarlark(ctx android.TopDownMutatorContext) {
 	if m, ok := ctx.Module().(*customModule); ok {
-		baseName := "__bp2build__" + m.Name()
-		ctx.CreateModule(customBazelModuleFactory, &customBazelModuleAttributes{
-			Name: proptools.StringPtr(baseName),
-		}, &bazel.BazelTargetModuleProperties{
-			Rule_class:        "my_library",
-			Bzl_load_location: "//build/bazel/rules:rules.bzl",
-		})
-		ctx.CreateModule(customBazelModuleFactory, &customBazelModuleAttributes{
-			Name: proptools.StringPtr(baseName + "_proto_library_deps"),
-		}, &bazel.BazelTargetModuleProperties{
-			Rule_class:        "proto_library",
-			Bzl_load_location: "//build/bazel/rules:proto.bzl",
-		})
-		ctx.CreateModule(customBazelModuleFactory, &customBazelModuleAttributes{
-			Name: proptools.StringPtr(baseName + "_my_proto_library_deps"),
-		}, &bazel.BazelTargetModuleProperties{
-			Rule_class:        "my_proto_library",
-			Bzl_load_location: "//build/bazel/rules:proto.bzl",
-		})
+		if !m.bazelProps.Bazel_module.Bp2build_available {
+			return
+		}
+
+		baseName := m.Name()
+		attrs := &customBazelModuleAttributes{}
+
+		myLibraryProps := bazel.NewBazelTargetModuleProperties(
+			baseName,
+			"my_library",
+			"//build/bazel/rules:rules.bzl",
+		)
+		ctx.CreateBazelTargetModule(customBazelModuleFactory, myLibraryProps, attrs)
+
+		protoLibraryProps := bazel.NewBazelTargetModuleProperties(
+			baseName+"_proto_library_deps",
+			"proto_library",
+			"//build/bazel/rules:proto.bzl",
+		)
+		ctx.CreateBazelTargetModule(customBazelModuleFactory, protoLibraryProps, attrs)
+
+		myProtoLibraryProps := bazel.NewBazelTargetModuleProperties(
+			baseName+"_my_proto_library_deps",
+			"my_proto_library",
+			"//build/bazel/rules:proto.bzl",
+		)
+		ctx.CreateBazelTargetModule(customBazelModuleFactory, myProtoLibraryProps, attrs)
 	}
 }
diff --git a/bpf/Android.bp b/bpf/Android.bp
index 882cd8a..3ffa29f 100644
--- a/bpf/Android.bp
+++ b/bpf/Android.bp
@@ -14,6 +14,10 @@
 // limitations under the License.
 //
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-bpf",
     pkgPath: "android/soong/bpf",
diff --git a/bpfix/Android.bp b/bpfix/Android.bp
index b244e3a..345dbd0 100644
--- a/bpfix/Android.bp
+++ b/bpfix/Android.bp
@@ -16,6 +16,10 @@
 // androidmk Android.mk to Blueprints translator
 //
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "bpfix",
     srcs: [
diff --git a/cc/Android.bp b/cc/Android.bp
index 6ec7e0e..bdbb3c0 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-cc",
     pkgPath: "android/soong/cc",
diff --git a/cc/androidmk.go b/cc/androidmk.go
index ddb81d9..8652c10 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -26,9 +26,9 @@
 var (
 	nativeBridgeSuffix  = ".native_bridge"
 	productSuffix       = ".product"
-	vendorSuffix        = ".vendor"
+	VendorSuffix        = ".vendor"
 	ramdiskSuffix       = ".ramdisk"
-	vendorRamdiskSuffix = ".vendor_ramdisk"
+	VendorRamdiskSuffix = ".vendor_ramdisk"
 	recoverySuffix      = ".recovery"
 	sdkSuffix           = ".sdk"
 )
diff --git a/cc/binary.go b/cc/binary.go
index 71c865b..999b82c 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -182,7 +182,7 @@
 		}
 	}
 
-	if !binary.static() && inList("libc", deps.StaticLibs) {
+	if !binary.static() && inList("libc", deps.StaticLibs) && !ctx.BazelConversionMode() {
 		ctx.ModuleErrorf("statically linking libc to dynamic executable, please remove libc\n" +
 			"from static libs or set static_executable: true")
 	}
diff --git a/cc/cc.go b/cc/cc.go
index d282b6e..6c1469f 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -28,6 +28,7 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/bazel"
 	"android/soong/cc/config"
 	"android/soong/genrule"
 )
@@ -364,6 +365,8 @@
 	// can depend on libraries that are not exported by the APEXes and use private symbols
 	// from the exported libraries.
 	Test_for []string
+
+	bazel.Properties
 }
 
 type VendorProperties struct {
@@ -1535,11 +1538,16 @@
 	var vndkVersion string
 	var nameSuffix string
 	if c.InProduct() {
+		if c.ProductSpecific() {
+			// If the module is product specific with 'product_specific: true',
+			// do not add a name suffix because it is a base module.
+			return ""
+		}
 		vndkVersion = ctx.DeviceConfig().ProductVndkVersion()
 		nameSuffix = productSuffix
 	} else {
 		vndkVersion = ctx.DeviceConfig().VndkVersion()
-		nameSuffix = vendorSuffix
+		nameSuffix = VendorSuffix
 	}
 	if vndkVersion == "current" {
 		vndkVersion = ctx.DeviceConfig().PlatformVndkVersion()
@@ -1586,11 +1594,11 @@
 	} else if _, ok := c.linker.(*vndkPrebuiltLibraryDecorator); ok {
 		// .vendor suffix is added for backward compatibility with VNDK snapshot whose names with
 		// such suffixes are already hard-coded in prebuilts/vndk/.../Android.bp.
-		c.Properties.SubName += vendorSuffix
+		c.Properties.SubName += VendorSuffix
 	} else if c.InRamdisk() && !c.OnlyInRamdisk() {
 		c.Properties.SubName += ramdiskSuffix
 	} else if c.InVendorRamdisk() && !c.OnlyInVendorRamdisk() {
-		c.Properties.SubName += vendorRamdiskSuffix
+		c.Properties.SubName += VendorRamdiskSuffix
 	} else if c.InRecovery() && !c.OnlyInRecovery() {
 		c.Properties.SubName += recoverySuffix
 	} else if c.IsSdkVariant() && (c.Properties.SdkAndPlatformVariantVisibleToMake || c.SplitPerApiLevel()) {
@@ -1741,7 +1749,7 @@
 
 func (c *Module) toolchain(ctx android.BaseModuleContext) config.Toolchain {
 	if c.cachedToolchain == nil {
-		c.cachedToolchain = config.FindToolchain(ctx.Os(), ctx.Arch())
+		c.cachedToolchain = config.FindToolchainWithContext(ctx)
 	}
 	return c.cachedToolchain
 }
@@ -1833,6 +1841,12 @@
 	deps.HeaderLibs = android.LastUniqueStrings(deps.HeaderLibs)
 	deps.RuntimeLibs = android.LastUniqueStrings(deps.RuntimeLibs)
 
+	// In Bazel conversion mode, we dependency and build validations will occur in Bazel, so there is
+	// no need to do so in Soong.
+	if ctx.BazelConversionMode() {
+		return deps
+	}
+
 	for _, lib := range deps.ReexportSharedLibHeaders {
 		if !inList(lib, deps.SharedLibs) {
 			ctx.PropertyErrorf("export_shared_lib_headers", "Shared library not in shared_libs: '%s'", lib)
@@ -2891,12 +2905,12 @@
 	ccDepModule, _ := ccDep.(*Module)
 	isLLndk := ccDepModule != nil && ccDepModule.IsLlndk()
 	isVendorPublicLib := inList(libName, *vendorPublicLibraries)
-	bothVendorAndCoreVariantsExist := ccDep.HasVendorVariant() || isLLndk
+	nonSystemVariantsExist := ccDep.HasNonSystemVariants() || isLLndk
 
-	if c, ok := ccDep.(*Module); ok {
+	if ccDepModule != nil {
 		// Use base module name for snapshots when exporting to Makefile.
-		if snapshotPrebuilt, ok := c.linker.(snapshotInterface); ok {
-			baseName := c.BaseModuleName()
+		if snapshotPrebuilt, ok := ccDepModule.linker.(snapshotInterface); ok {
+			baseName := ccDepModule.BaseModuleName()
 
 			return baseName + snapshotPrebuilt.snapshotAndroidMkSuffix()
 		}
@@ -2907,16 +2921,16 @@
 		// The vendor module is a no-vendor-variant VNDK library.  Depend on the
 		// core module instead.
 		return libName
-	} else if c.UseVndk() && bothVendorAndCoreVariantsExist {
-		// The vendor module in Make will have been renamed to not conflict with the core
-		// module, so update the dependency name here accordingly.
-		return libName + c.getNameSuffixWithVndkVersion(ctx)
+	} else if ccDep.UseVndk() && nonSystemVariantsExist && ccDepModule != nil {
+		// The vendor and product modules in Make will have been renamed to not conflict with the
+		// core module, so update the dependency name here accordingly.
+		return libName + ccDepModule.Properties.SubName
 	} else if (ctx.Platform() || ctx.ProductSpecific()) && isVendorPublicLib {
 		return libName + vendorPublicLibrarySuffix
 	} else if ccDep.InRamdisk() && !ccDep.OnlyInRamdisk() {
 		return libName + ramdiskSuffix
 	} else if ccDep.InVendorRamdisk() && !ccDep.OnlyInVendorRamdisk() {
-		return libName + vendorRamdiskSuffix
+		return libName + VendorRamdiskSuffix
 	} else if ccDep.InRecovery() && !ccDep.OnlyInRecovery() {
 		return libName + recoverySuffix
 	} else if ccDep.Target().NativeBridge == android.NativeBridgeEnabled {
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 7288cc4..b1c1b2e 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -266,7 +266,7 @@
 	}
 }
 
-func checkSnapshotIncludeExclude(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string, include bool) {
+func checkSnapshotIncludeExclude(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string, include bool, fake bool) {
 	t.Helper()
 	mod, ok := ctx.ModuleForTests(moduleName, variant).Module().(android.OutputFileProducer)
 	if !ok {
@@ -282,8 +282,14 @@
 
 	if include {
 		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])
+		if fake {
+			if out.Rule == nil {
+				t.Errorf("Missing rule for module %q output file %q", moduleName, outputFiles[0])
+			}
+		} else {
+			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])
+			}
 		}
 	} else {
 		out := singleton.MaybeOutput(snapshotPath)
@@ -294,11 +300,15 @@
 }
 
 func checkSnapshot(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) {
-	checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, true)
+	checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, true, false)
 }
 
 func checkSnapshotExclude(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) {
-	checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, false)
+	checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, false, false)
+}
+
+func checkSnapshotRule(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) {
+	checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, true, true)
 }
 
 func checkWriteFileOutput(t *testing.T, params android.TestingBuildParams, expected []string) {
@@ -2712,6 +2722,14 @@
 		system_shared_libs : [],
 	}
 	cc_library {
+		name: "libproduct_vendor",
+		product_specific: true,
+		vendor_available: true,
+		no_libcrt : true,
+		nocrt : true,
+		system_shared_libs : [],
+	}
+	cc_library {
 		name: "libcore",
 		runtime_libs: ["liball_available"],
 		no_libcrt : true,
@@ -2728,7 +2746,7 @@
 	cc_library {
 		name: "libvendor2",
 		vendor: true,
-		runtime_libs: ["liball_available", "libvendor1"],
+		runtime_libs: ["liball_available", "libvendor1", "libproduct_vendor"],
 		no_libcrt : true,
 		nocrt : true,
 		system_shared_libs : [],
@@ -2751,7 +2769,7 @@
 	cc_library {
 		name: "libproduct2",
 		product_specific: true,
-		runtime_libs: ["liball_available", "libproduct1"],
+		runtime_libs: ["liball_available", "libproduct1", "libproduct_vendor"],
 		no_libcrt : true,
 		nocrt : true,
 		system_shared_libs : [],
@@ -2781,7 +2799,7 @@
 	checkRuntimeLibs(t, []string{"liball_available.vendor"}, module)
 
 	module = ctx.ModuleForTests("libvendor2", variant).Module().(*Module)
-	checkRuntimeLibs(t, []string{"liball_available.vendor", "libvendor1"}, module)
+	checkRuntimeLibs(t, []string{"liball_available.vendor", "libvendor1", "libproduct_vendor.vendor"}, module)
 
 	// runtime_libs for product variants have '.product' suffixes if the modules have both core
 	// and product variants.
@@ -2791,7 +2809,7 @@
 	checkRuntimeLibs(t, []string{"liball_available.product"}, module)
 
 	module = ctx.ModuleForTests("libproduct2", variant).Module().(*Module)
-	checkRuntimeLibs(t, []string{"liball_available.product", "libproduct1"}, module)
+	checkRuntimeLibs(t, []string{"liball_available.product", "libproduct1", "libproduct_vendor"}, module)
 }
 
 func TestExcludeRuntimeLibs(t *testing.T) {
@@ -2817,10 +2835,10 @@
 	checkRuntimeLibs(t, []string{"liball_available"}, module)
 
 	module = ctx.ModuleForTests("libvendor2", variant).Module().(*Module)
-	checkRuntimeLibs(t, []string{"liball_available", "libvendor1"}, module)
+	checkRuntimeLibs(t, []string{"liball_available", "libvendor1", "libproduct_vendor"}, module)
 
 	module = ctx.ModuleForTests("libproduct2", variant).Module().(*Module)
-	checkRuntimeLibs(t, []string{"liball_available", "libproduct1"}, module)
+	checkRuntimeLibs(t, []string{"liball_available", "libproduct1", "libproduct_vendor"}, module)
 }
 
 func checkStaticLibs(t *testing.T, expected []string, module *Module) {
diff --git a/cc/config/Android.bp b/cc/config/Android.bp
index ce4bdfb..5ef247d 100644
--- a/cc/config/Android.bp
+++ b/cc/config/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-cc-config",
     pkgPath: "android/soong/cc/config",
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 35dd10f..76186be 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -142,11 +142,16 @@
 		// Nested and array designated initialization is nice to have.
 		"-Wno-c99-designator",
 
+		// Warnings from clang-12
+		"-Wno-gnu-folding-constant",
+
 		// Calls to the APIs that are newer than the min sdk version of the caller should be
 		// guarded with __builtin_available.
 		"-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/config/toolchain.go b/cc/config/toolchain.go
index db9092d..59c0422 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -32,12 +32,42 @@
 	toolchainFactories[os][arch] = factory
 }
 
+type toolchainContext interface {
+	Os() android.OsType
+	Arch() android.Arch
+}
+
+type conversionContext interface {
+	BazelConversionMode() bool
+}
+
+func FindToolchainWithContext(ctx toolchainContext) Toolchain {
+	t, err := findToolchain(ctx.Os(), ctx.Arch())
+	if err != nil {
+		if c, ok := ctx.(conversionContext); ok && c.BazelConversionMode() {
+			// TODO(b/179123288): determine conversion for toolchain
+			return &toolchainX86_64{}
+		} else {
+			panic(err)
+		}
+	}
+	return t
+}
+
 func FindToolchain(os android.OsType, arch android.Arch) Toolchain {
+	t, err := findToolchain(os, arch)
+	if err != nil {
+		panic(err)
+	}
+	return t
+}
+
+func findToolchain(os android.OsType, arch android.Arch) (Toolchain, error) {
 	factory := toolchainFactories[os][arch.ArchType]
 	if factory == nil {
-		panic(fmt.Errorf("Toolchain not found for %s arch %q", os.String(), arch.String()))
+		return nil, fmt.Errorf("Toolchain not found for %s arch %q", os.String(), arch.String())
 	}
-	return factory(arch)
+	return factory(arch), nil
 }
 
 type Toolchain interface {
diff --git a/cc/config/vndk.go b/cc/config/vndk.go
index 45c18c2..425e349 100644
--- a/cc/config/vndk.go
+++ b/cc/config/vndk.go
@@ -41,6 +41,9 @@
 	"android.hardware.power-V1-ndk_platform",
 	"android.hardware.power-ndk_platform",
 	"android.hardware.rebootescrow-V1-ndk_platform",
+	"android.hardware.power.stats-V1-ndk_platform",
+	"android.hardware.power.stats-ndk_platform",
+	"android.hardware.power.stats-unstable-ndk_platform",
 	"android.hardware.rebootescrow-ndk_platform",
 	"android.hardware.security.keymint-V1-ndk_platform",
 	"android.hardware.security.keymint-ndk_platform",
diff --git a/cc/fuzz.go b/cc/fuzz.go
index d7da5ab..9fe5b17 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -20,6 +20,8 @@
 	"sort"
 	"strings"
 
+	"github.com/google/blueprint/proptools"
+
 	"android/soong/android"
 	"android/soong/cc/config"
 )
@@ -172,7 +174,7 @@
 // This function takes a module and determines if it is a unique shared library
 // that should be installed in the fuzz target output directories. This function
 // returns true, unless:
-//  - The module is not a shared library, or
+//  - The module is not an installable shared library, or
 //  - The module is a header, stub, or vendor-linked library, or
 //  - The module is a prebuilt and its source is available, or
 //  - The module is a versioned member of an SDK snapshot.
@@ -209,6 +211,11 @@
 		if _, isLLndkStubLibrary := ccLibrary.linker.(*stubDecorator); isLLndkStubLibrary {
 			return false
 		}
+		// Discard installable:false libraries because they are expected to be absent
+		// in runtime.
+		if !proptools.BoolDefault(ccLibrary.Properties.Installable, true) {
+			return false
+		}
 	}
 
 	// If the same library is present both as source and a prebuilt we must pick
diff --git a/cc/libbuildversion/Android.bp b/cc/libbuildversion/Android.bp
index b63338d..4debb1c 100644
--- a/cc/libbuildversion/Android.bp
+++ b/cc/libbuildversion/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_library_static {
     name: "libbuildversion",
     host_supported: true,
diff --git a/cc/libbuildversion/tests/Android.bp b/cc/libbuildversion/tests/Android.bp
index b3b2061..0e97fed 100644
--- a/cc/libbuildversion/tests/Android.bp
+++ b/cc/libbuildversion/tests/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_defaults {
     name: "build_version_test_defaults",
     use_version_lib: true,
diff --git a/cc/library.go b/cc/library.go
index 29a3c69..65533bc 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -19,6 +19,7 @@
 	"io"
 	"path/filepath"
 	"regexp"
+	"strconv"
 	"strings"
 	"sync"
 
@@ -647,6 +648,11 @@
 		return objs
 	}
 	if library.buildStubs() {
+		symbolFile := String(library.Properties.Stubs.Symbol_file)
+		if symbolFile != "" && !strings.HasSuffix(symbolFile, ".map.txt") {
+			ctx.PropertyErrorf("symbol_file", "%q doesn't have .map.txt suffix", symbolFile)
+			return Objects{}
+		}
 		objs, versionScript := compileStubLibrary(ctx, flags, String(library.Properties.Stubs.Symbol_file), library.MutatedProperties.StubsVersion, "--apex")
 		library.versionScriptPath = android.OptionalPathForPath(versionScript)
 		return objs
@@ -1362,8 +1368,11 @@
 func (library *libraryDecorator) exportVersioningMacroIfNeeded(ctx android.BaseModuleContext) {
 	if library.buildStubs() && library.stubsVersion() != "" && !library.skipAPIDefine {
 		name := versioningMacroName(ctx.Module().(*Module).ImplementationModuleName(ctx))
-		ver := library.stubsVersion()
-		library.reexportFlags("-D" + name + "=" + ver)
+		apiLevel, err := android.ApiLevelFromUser(ctx, library.stubsVersion())
+		if err != nil {
+			ctx.ModuleErrorf("Can't export version macro: %s", err.Error())
+		}
+		library.reexportFlags("-D" + name + "=" + strconv.Itoa(apiLevel.FinalOrPreviewInt()))
 	}
 }
 
diff --git a/cc/library_headers.go b/cc/library_headers.go
index 8b3dbeb..e5a5557 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
+	}
+
+	if !module.Properties.Bazel_module.Bp2build_available {
+		return
+	}
+
+	lib, ok := module.linker.(*libraryDecorator)
+	if !ok {
+		// Not a cc_library module
+		return
+	}
+	if !lib.header() {
+		// Not a cc_library_headers module
+		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/linkable.go b/cc/linkable.go
index ab5a552..58919a0 100644
--- a/cc/linkable.go
+++ b/cc/linkable.go
@@ -106,6 +106,8 @@
 	IsVndkExt() bool
 	IsVndkPrivate() bool
 	HasVendorVariant() bool
+	HasProductVariant() bool
+	HasNonSystemVariants() bool
 	InProduct() bool
 
 	SdkVersion() string
diff --git a/cc/linker.go b/cc/linker.go
index ff07224..6d0d416 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -328,7 +328,9 @@
 		}
 
 		deps.SystemSharedLibs = linker.Properties.System_shared_libs
-		if deps.SystemSharedLibs == nil {
+		// In Bazel conversion mode, variations have not been specified, so SystemSharedLibs may
+		// inaccuarately appear unset, which can cause issues with circular dependencies.
+		if deps.SystemSharedLibs == nil && !ctx.BazelConversionMode() {
 			// Provide a default system_shared_libs if it is unspecified. Note: If an
 			// empty list [] is specified, it implies that the module declines the
 			// default system_shared_libs.
diff --git a/cc/ndk_api_coverage_parser/Android.bp b/cc/ndk_api_coverage_parser/Android.bp
index 8d9827c..b119e90 100644
--- a/cc/ndk_api_coverage_parser/Android.bp
+++ b/cc/ndk_api_coverage_parser/Android.bp
@@ -14,6 +14,10 @@
 // limitations under the License.
 //
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 python_library_host {
     name: "ndk_api_coverage_parser_lib",
     pkg_path: "ndk_api_coverage_parser",
diff --git a/cc/ndkstubgen/Android.bp b/cc/ndkstubgen/Android.bp
index 85dfaee..782c124 100644
--- a/cc/ndkstubgen/Android.bp
+++ b/cc/ndkstubgen/Android.bp
@@ -14,6 +14,10 @@
 // limitations under the License.
 //
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 python_binary_host {
     name: "ndkstubgen",
     pkg_path: "ndkstubgen",
diff --git a/cc/object.go b/cc/object.go
index 3ce7676..d92e110 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -18,6 +18,7 @@
 	"fmt"
 
 	"android/soong/android"
+	"android/soong/bazel"
 )
 
 //
@@ -27,6 +28,8 @@
 func init() {
 	android.RegisterModuleType("cc_object", ObjectFactory)
 	android.RegisterSdkMemberType(ccObjectSdkMemberType)
+
+	android.RegisterBp2BuildMutator("cc_object", ObjectBp2Build)
 }
 
 var ccObjectSdkMemberType = &librarySdkMemberType{
@@ -82,9 +85,80 @@
 	module.compiler.appendCflags([]string{"-fno-addrsig"})
 
 	module.sdkMemberTypes = []android.SdkMemberType{ccObjectSdkMemberType}
+
 	return module.Init()
 }
 
+// For bp2build conversion.
+type bazelObjectAttributes struct {
+	Srcs               bazel.LabelList
+	Copts              []string
+	Local_include_dirs []string
+}
+
+type bazelObject struct {
+	android.BazelTargetModuleBase
+	bazelObjectAttributes
+}
+
+func (m *bazelObject) Name() string {
+	return m.BaseModuleName()
+}
+
+func (m *bazelObject) GenerateAndroidBuildActions(ctx android.ModuleContext) {}
+
+func BazelObjectFactory() android.Module {
+	module := &bazelObject{}
+	module.AddProperties(&module.bazelObjectAttributes)
+	android.InitBazelTargetModule(module)
+	return module
+}
+
+// ObjectBp2Build is the bp2build converter from cc_object modules to the
+// Bazel equivalent target, plus any necessary include deps for the cc_object.
+func ObjectBp2Build(ctx android.TopDownMutatorContext) {
+	m, ok := ctx.Module().(*Module)
+	if !ok || !m.Properties.Bazel_module.Bp2build_available {
+		return
+	}
+
+	// a Module can be something other than a cc_object.
+	if ctx.ModuleType() != "cc_object" {
+		return
+	}
+
+	if m.compiler == nil {
+		// a cc_object must have access to the compiler decorator for its props.
+		ctx.ModuleErrorf("compiler must not be nil for a cc_object module")
+	}
+
+	var copts []string
+	var srcs []string
+	var localIncludeDirs []string
+	for _, props := range m.compiler.compilerProps() {
+		if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok {
+			copts = baseCompilerProps.Cflags
+			srcs = baseCompilerProps.Srcs
+			localIncludeDirs = baseCompilerProps.Local_include_dirs
+			break
+		}
+	}
+
+	attrs := &bazelObjectAttributes{
+		Srcs:               android.BazelLabelForModuleSrc(ctx, srcs),
+		Copts:              copts,
+		Local_include_dirs: localIncludeDirs,
+	}
+
+	props := bazel.NewBazelTargetModuleProperties(
+		m.Name(),
+		"cc_object",
+		"//build/bazel/rules:cc_object.bzl",
+	)
+
+	ctx.CreateBazelTargetModule(BazelObjectFactory, props, attrs)
+}
+
 func (object *objectLinker) appendLdflags(flags []string) {
 	panic(fmt.Errorf("appendLdflags on objectLinker not supported"))
 }
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index ffaed8e..62daafd 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -144,7 +144,7 @@
 }
 
 func (vendorSnapshotImage) moduleNameSuffix() string {
-	return vendorSuffix
+	return VendorSuffix
 }
 
 func (recoverySnapshotImage) init(ctx android.RegistrationContext) {
@@ -195,8 +195,12 @@
 }
 
 func (recoverySnapshotImage) excludeFromDirectedSnapshot(cfg android.DeviceConfig, name string) bool {
-	// directed recovery snapshot is not implemented yet
-	return false
+	// If we're using full snapshot, not directed snapshot, capture every module
+	if !cfg.DirectedRecoverySnapshot() {
+		return false
+	}
+	// Else, checks if name is in RECOVERY_SNAPSHOT_MODULES.
+	return !cfg.RecoverySnapshotModules()[name]
 }
 
 func (recoverySnapshotImage) imageVariantName(cfg android.DeviceConfig) string {
diff --git a/cc/symbolfile/Android.bp b/cc/symbolfile/Android.bp
index 5b43309..6722110 100644
--- a/cc/symbolfile/Android.bp
+++ b/cc/symbolfile/Android.bp
@@ -14,6 +14,10 @@
 // limitations under the License.
 //
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 python_library_host {
     name: "symbolfile",
     pkg_path: "symbolfile",
diff --git a/cc/testing.go b/cc/testing.go
index 3a5bd17..45e5312 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -43,6 +43,7 @@
 			name: "libatomic",
 			defaults: ["linux_bionic_supported"],
 			vendor_available: true,
+			vendor_ramdisk_available: true,
 			product_available: true,
 			recovery_available: true,
 			native_bridge_supported: true,
@@ -52,6 +53,7 @@
 		toolchain_library {
 			name: "libcompiler_rt-extras",
 			vendor_available: true,
+			vendor_ramdisk_available: true,
 			product_available: true,
 			recovery_available: true,
 			src: "",
@@ -60,6 +62,7 @@
 		toolchain_library {
 			name: "libclang_rt.builtins-arm-android",
 			vendor_available: true,
+			vendor_ramdisk_available: true,
 			product_available: true,
 			recovery_available: true,
 			native_bridge_supported: true,
@@ -69,6 +72,7 @@
 		toolchain_library {
 			name: "libclang_rt.builtins-aarch64-android",
 			vendor_available: true,
+			vendor_ramdisk_available: true,
 			product_available: true,
 			recovery_available: true,
 			native_bridge_supported: true,
@@ -93,6 +97,7 @@
 		toolchain_library {
 			name: "libclang_rt.builtins-i686-android",
 			vendor_available: true,
+			vendor_ramdisk_available: true,
 			product_available: true,
 			recovery_available: true,
 			native_bridge_supported: true,
@@ -103,6 +108,7 @@
 			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,
@@ -113,6 +119,7 @@
 			name: "libunwind",
 			defaults: ["linux_bionic_supported"],
 			vendor_available: true,
+			vendor_ramdisk_available: true,
 			product_available: true,
 			recovery_available: true,
 			native_bridge_supported: true,
@@ -238,6 +245,7 @@
 		cc_library {
 			name: "libprofile-extras",
 			vendor_available: true,
+			vendor_ramdisk_available: true,
 			product_available: true,
 			recovery_available: true,
 			native_coverage: false,
@@ -248,6 +256,7 @@
 		cc_library {
 			name: "libprofile-clang-extras",
 			vendor_available: true,
+			vendor_ramdisk_available: true,
 			product_available: true,
 			recovery_available: true,
 			native_coverage: false,
@@ -319,6 +328,7 @@
 			system_shared_libs: [],
 			stl: "none",
 			vendor_available: true,
+			vendor_ramdisk_available: true,
 			product_available: true,
 			recovery_available: true,
 			host_supported: true,
@@ -356,6 +366,7 @@
 			stl: "none",
 			host_supported: false,
 			vendor_available: true,
+			vendor_ramdisk_available: true,
 			product_available: true,
 			recovery_available: true,
 			min_sdk_version: "29",
@@ -380,6 +391,7 @@
 			defaults: ["linux_bionic_supported"],
 			recovery_available: true,
 			vendor_available: true,
+			vendor_ramdisk_available: true,
 			product_available: true,
 			native_bridge_supported: true,
 			stl: "none",
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/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 35fc1c1..7077b71 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -239,10 +239,6 @@
 	if _, ok := m.linker.(*llndkHeadersDecorator); ok {
 		return false
 	}
-	// If we are using directed snapshot AND we have to exclude this module, skip this
-	if image.excludeFromDirectedSnapshot(cfg, m.BaseModuleName()) {
-		return false
-	}
 
 	// Libraries
 	if l, ok := m.linker.(snapshotLibraryInterface); ok {
@@ -371,18 +367,19 @@
 
 	var headers android.Paths
 
-	copyFile := copyFileRule
-	if c.fake {
-		// All prebuilt binaries and headers are installed by copyFile function. This makes a fake
-		// snapshot just touch prebuilts and headers, rather than installing real files.
-		copyFile = func(ctx android.SingletonContext, path android.Path, out string) android.OutputPath {
+	copyFile := func(ctx android.SingletonContext, path android.Path, out string, fake bool) android.OutputPath {
+		if fake {
+			// All prebuilt binaries and headers are installed by copyFile function. This makes a fake
+			// snapshot just touch prebuilts and headers, rather than installing real files.
 			return writeStringToFileRule(ctx, "", out)
+		} else {
+			return copyFileRule(ctx, path, out)
 		}
 	}
 
 	// installSnapshot function copies prebuilt file (.so, .a, or executable) and json flag file.
 	// For executables, init_rc and vintf_fragments files are also copied.
-	installSnapshot := func(m *Module) android.Paths {
+	installSnapshot := func(m *Module, fake bool) android.Paths {
 		targetArch := "arch-" + m.Target().Arch.ArchType.String()
 		if m.Target().Arch.ArchVariant != "" {
 			targetArch += "-" + m.Target().Arch.ArchVariant
@@ -419,7 +416,7 @@
 			out := filepath.Join(configsDir, path.Base())
 			if !installedConfigs[out] {
 				installedConfigs[out] = true
-				ret = append(ret, copyFile(ctx, path, out))
+				ret = append(ret, copyFile(ctx, path, out, fake))
 			}
 		}
 
@@ -470,7 +467,7 @@
 					prop.ModuleName += ".cfi"
 				}
 				snapshotLibOut := filepath.Join(snapshotArchDir, targetArch, libType, stem)
-				ret = append(ret, copyFile(ctx, libPath, snapshotLibOut))
+				ret = append(ret, copyFile(ctx, libPath, snapshotLibOut, fake))
 			} else {
 				stem = ctx.ModuleName(m)
 			}
@@ -484,7 +481,7 @@
 			// install bin
 			binPath := m.outputFile.Path()
 			snapshotBinOut := filepath.Join(snapshotArchDir, targetArch, "binary", binPath.Base())
-			ret = append(ret, copyFile(ctx, binPath, snapshotBinOut))
+			ret = append(ret, copyFile(ctx, binPath, snapshotBinOut, fake))
 			propOut = snapshotBinOut + ".json"
 		} else if m.object() {
 			// object files aren't installed to the device, so their names can conflict.
@@ -492,7 +489,7 @@
 			objPath := m.outputFile.Path()
 			snapshotObjOut := filepath.Join(snapshotArchDir, targetArch, "object",
 				ctx.ModuleName(m)+filepath.Ext(objPath.Base()))
-			ret = append(ret, copyFile(ctx, objPath, snapshotObjOut))
+			ret = append(ret, copyFile(ctx, objPath, snapshotObjOut, fake))
 			propOut = snapshotObjOut + ".json"
 		} else {
 			ctx.Errorf("unknown module %q in vendor snapshot", m.String())
@@ -532,9 +529,17 @@
 			return
 		}
 
-		// installSnapshot installs prebuilts and json flag files
-		snapshotOutputs = append(snapshotOutputs, installSnapshot(m)...)
+		// If we are using directed snapshot and a module is not included in the
+		// list, we will still include the module as if it was a fake module.
+		// The reason is that soong needs all the dependencies to be present, even
+		// if they are not using during the build.
+		installAsFake := c.fake
+		if c.image.excludeFromDirectedSnapshot(ctx.DeviceConfig(), m.BaseModuleName()) {
+			installAsFake = true
+		}
 
+		// installSnapshot installs prebuilts and json flag files
+		snapshotOutputs = append(snapshotOutputs, installSnapshot(m, installAsFake)...)
 		// just gather headers and notice files here, because they are to be deduplicated
 		if l, ok := m.linker.(snapshotLibraryInterface); ok {
 			headers = append(headers, l.snapshotHeaders()...)
@@ -553,7 +558,7 @@
 
 	// install all headers after removing duplicates
 	for _, header := range android.FirstUniquePaths(headers) {
-		snapshotOutputs = append(snapshotOutputs, copyFile(ctx, header, filepath.Join(includeDir, header.String())))
+		snapshotOutputs = append(snapshotOutputs, copyFile(ctx, header, filepath.Join(includeDir, header.String()), c.fake))
 	}
 
 	// All artifacts are ready. Sort them to normalize ninja and then zip.
diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go
index 499d7ae..7e283fb 100644
--- a/cc/vendor_snapshot_test.go
+++ b/cc/vendor_snapshot_test.go
@@ -228,7 +228,6 @@
 	snapshotSingleton := ctx.SingletonForTests("vendor-snapshot")
 
 	var includeJsonFiles []string
-	var excludeJsonFiles []string
 
 	for _, arch := range [][]string{
 		[]string{"arm64", "armv8-a"},
@@ -248,9 +247,10 @@
 		checkSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo", "libfoo.so", sharedDir, sharedVariant)
 		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo.so.json"))
 
-		// Excluded modules
-		checkSnapshotExclude(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant)
-		excludeJsonFiles = append(excludeJsonFiles, filepath.Join(sharedDir, "libvendor_available.so.json"))
+		// Excluded modules. Modules not included in the directed vendor snapshot
+		// are still include as fake modules.
+		checkSnapshotRule(t, ctx, snapshotSingleton, "libvendor_available", "libvendor_available.so", sharedDir, sharedVariant)
+		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libvendor_available.so.json"))
 	}
 
 	// Verify that each json file for an included module has a rule.
@@ -259,13 +259,6 @@
 			t.Errorf("include json file %q not found", jsonFile)
 		}
 	}
-
-	// Verify that each json file for an excluded module has no rule.
-	for _, jsonFile := range excludeJsonFiles {
-		if snapshotSingleton.MaybeOutput(jsonFile).Rule != nil {
-			t.Errorf("exclude json file %q found", jsonFile)
-		}
-	}
 }
 
 func TestVendorSnapshotUse(t *testing.T) {
@@ -1058,3 +1051,85 @@
 		}
 	}
 }
+
+func TestRecoverySnapshotDirected(t *testing.T) {
+	bp := `
+	cc_library_shared {
+		name: "librecovery",
+		recovery: true,
+		nocrt: true,
+	}
+
+	cc_library_shared {
+		name: "librecovery_available",
+		recovery_available: true,
+		nocrt: true,
+	}
+
+	genrule {
+		name: "libfoo_gen",
+		cmd: "",
+		out: ["libfoo.so"],
+	}
+
+	cc_prebuilt_library_shared {
+		name: "libfoo",
+		recovery: true,
+		prefer: true,
+		srcs: [":libfoo_gen"],
+	}
+
+	cc_library_shared {
+		name: "libfoo",
+		recovery: true,
+		nocrt: true,
+	}
+`
+	config := TestConfig(buildDir, android.Android, nil, bp, nil)
+	config.TestProductVariables.DeviceVndkVersion = StringPtr("current")
+	config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current")
+	config.TestProductVariables.Platform_vndk_version = StringPtr("VER")
+	config.TestProductVariables.DirectedRecoverySnapshot = true
+	config.TestProductVariables.RecoverySnapshotModules = make(map[string]bool)
+	config.TestProductVariables.RecoverySnapshotModules["librecovery"] = true
+	config.TestProductVariables.RecoverySnapshotModules["libfoo"] = true
+	ctx := testCcWithConfig(t, config)
+
+	// Check recovery snapshot output.
+
+	snapshotDir := "recovery-snapshot"
+	snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64")
+	snapshotSingleton := ctx.SingletonForTests("recovery-snapshot")
+
+	var includeJsonFiles []string
+
+	for _, arch := range [][]string{
+		[]string{"arm64", "armv8-a"},
+	} {
+		archType := arch[0]
+		archVariant := arch[1]
+		archDir := fmt.Sprintf("arch-%s-%s", archType, archVariant)
+
+		sharedVariant := fmt.Sprintf("android_recovery_%s_%s_shared", archType, archVariant)
+		sharedDir := filepath.Join(snapshotVariantPath, archDir, "shared")
+
+		// Included modules
+		checkSnapshot(t, ctx, snapshotSingleton, "librecovery", "librecovery.so", sharedDir, sharedVariant)
+		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery.so.json"))
+		// Check that snapshot captures "prefer: true" prebuilt
+		checkSnapshot(t, ctx, snapshotSingleton, "prebuilt_libfoo", "libfoo.so", sharedDir, sharedVariant)
+		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "libfoo.so.json"))
+
+		// Excluded modules. Modules not included in the directed recovery snapshot
+		// are still include as fake modules.
+		checkSnapshotRule(t, ctx, snapshotSingleton, "librecovery_available", "librecovery_available.so", sharedDir, sharedVariant)
+		includeJsonFiles = append(includeJsonFiles, filepath.Join(sharedDir, "librecovery_available.so.json"))
+	}
+
+	// Verify that each json file for an included module has a rule.
+	for _, jsonFile := range includeJsonFiles {
+		if snapshotSingleton.MaybeOutput(jsonFile).Rule == nil {
+			t.Errorf("include json file %q not found", jsonFile)
+		}
+	}
+}
diff --git a/cmd/dep_fixer/Android.bp b/cmd/dep_fixer/Android.bp
index 97364d5..818fd28 100644
--- a/cmd/dep_fixer/Android.bp
+++ b/cmd/dep_fixer/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "dep_fixer",
     deps: ["soong-makedeps"],
diff --git a/cmd/diff_target_files/Android.bp b/cmd/diff_target_files/Android.bp
index bc6b068..ae8c329 100644
--- a/cmd/diff_target_files/Android.bp
+++ b/cmd/diff_target_files/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "diff_target_files",
     srcs: [
diff --git a/cmd/extract_apks/Android.bp b/cmd/extract_apks/Android.bp
index f8fe864..8a4ed63 100644
--- a/cmd/extract_apks/Android.bp
+++ b/cmd/extract_apks/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "extract_apks",
     srcs: ["main.go"],
diff --git a/cmd/extract_jar_packages/Android.bp b/cmd/extract_jar_packages/Android.bp
index 4ea8798..ab33504 100644
--- a/cmd/extract_jar_packages/Android.bp
+++ b/cmd/extract_jar_packages/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "extract_jar_packages",
     deps: [
diff --git a/cmd/extract_linker/Android.bp b/cmd/extract_linker/Android.bp
index 690c4fa..d40d250 100644
--- a/cmd/extract_linker/Android.bp
+++ b/cmd/extract_linker/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "extract_linker",
     srcs: ["main.go"],
diff --git a/cmd/fileslist/Android.bp b/cmd/fileslist/Android.bp
index cbf939a..3c6f675 100644
--- a/cmd/fileslist/Android.bp
+++ b/cmd/fileslist/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "fileslist",
     srcs: [
diff --git a/cmd/host_bionic_inject/Android.bp b/cmd/host_bionic_inject/Android.bp
index 5994103..16bc179 100644
--- a/cmd/host_bionic_inject/Android.bp
+++ b/cmd/host_bionic_inject/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "host_bionic_inject",
     deps: ["soong-symbol_inject"],
diff --git a/cmd/javac_wrapper/Android.bp b/cmd/javac_wrapper/Android.bp
index c00f4bd..e441567 100644
--- a/cmd/javac_wrapper/Android.bp
+++ b/cmd/javac_wrapper/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "soong_javac_wrapper",
     srcs: [
diff --git a/cmd/merge_zips/Android.bp b/cmd/merge_zips/Android.bp
index 8c97b6d..930d040 100644
--- a/cmd/merge_zips/Android.bp
+++ b/cmd/merge_zips/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "merge_zips",
     deps: [
diff --git a/cmd/multiproduct_kati/Android.bp b/cmd/multiproduct_kati/Android.bp
index d34f8c3..21d8e21 100644
--- a/cmd/multiproduct_kati/Android.bp
+++ b/cmd/multiproduct_kati/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "multiproduct_kati",
     deps: [
diff --git a/cmd/path_interposer/Android.bp b/cmd/path_interposer/Android.bp
index 41a219f..875cd72 100644
--- a/cmd/path_interposer/Android.bp
+++ b/cmd/path_interposer/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "path_interposer",
     deps: ["soong-ui-build-paths"],
diff --git a/cmd/pom2bp/Android.bp b/cmd/pom2bp/Android.bp
index 0b2b7b5..0dfed8b 100644
--- a/cmd/pom2bp/Android.bp
+++ b/cmd/pom2bp/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "pom2bp",
     deps: [
diff --git a/cmd/pom2mk/Android.bp b/cmd/pom2mk/Android.bp
index 54422b1..cc9dacc 100644
--- a/cmd/pom2mk/Android.bp
+++ b/cmd/pom2mk/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "pom2mk",
     deps: ["blueprint-proptools"],
diff --git a/cmd/sbox/Android.bp b/cmd/sbox/Android.bp
index f5e87c0..d88505f 100644
--- a/cmd/sbox/Android.bp
+++ b/cmd/sbox/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "sbox",
     deps: [
diff --git a/cmd/soong_build/Android.bp b/cmd/soong_build/Android.bp
index 6714978..6a0a87b 100644
--- a/cmd/soong_build/Android.bp
+++ b/cmd/soong_build/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_binary {
     name: "soong_build",
     deps: [
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 9dcb5f3..c17e23d 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -100,7 +100,7 @@
 	if bazelConversionRequested(configuration) {
 		// Run the alternate pipeline of bp2build mutators and singleton to convert Blueprint to BUILD files
 		// before everything else.
-		runBp2Build(configuration, extraNinjaDeps)
+		runBp2Build(srcDir, configuration)
 		// Short-circuit and return.
 		return
 	}
@@ -162,7 +162,7 @@
 // Run Soong in the bp2build mode. This creates a standalone context that registers
 // an alternate pipeline of mutators and singletons specifically for generating
 // Bazel BUILD files instead of Ninja files.
-func runBp2Build(configuration android.Config, extraNinjaDeps []string) {
+func runBp2Build(srcDir string, configuration android.Config) {
 	// Register an alternate set of singletons and mutators for bazel
 	// conversion for Bazel conversion.
 	bp2buildCtx := android.NewContext(configuration)
@@ -172,7 +172,20 @@
 	configuration.SetStopBefore(bootstrap.StopBeforePrepareBuildActions)
 	bp2buildCtx.SetNameInterface(newNameResolver(configuration))
 
-	// Run the loading and analysis pipeline.
+	// The bp2build process is a purely functional process that only depends on
+	// Android.bp files. It must not depend on the values of per-build product
+	// configurations or variables, since those will generate different BUILD
+	// files based on how the user has configured their tree.
+	bp2buildCtx.SetModuleListFile(bootstrap.ModuleListFile)
+	extraNinjaDeps, err := bp2buildCtx.ListModulePaths(srcDir)
+	if err != nil {
+		panic(err)
+	}
+	extraNinjaDepsString := strings.Join(extraNinjaDeps, " \\\n ")
+
+	// Run the loading and analysis pipeline to prepare the graph of regular
+	// Modules parsed from Android.bp files, and the BazelTargetModules mapped
+	// from the regular Modules.
 	bootstrap.Main(bp2buildCtx.Context, configuration, extraNinjaDeps...)
 
 	// Run the code-generation phase to convert BazelTargetModules to BUILD files.
@@ -195,7 +208,6 @@
 	ninjaFileName := "build.ninja"
 	ninjaFile := android.PathForOutput(codegenContext, ninjaFileName)
 	ninjaFileD := android.PathForOutput(codegenContext, ninjaFileName+".d")
-	extraNinjaDepsString := strings.Join(extraNinjaDeps, " \\\n ")
 	// A workaround to create the 'nothing' ninja target so `m nothing` works,
 	// since bp2build runs without Kati, and the 'nothing' target is declared in
 	// a Makefile.
diff --git a/cmd/soong_env/Android.bp b/cmd/soong_env/Android.bp
index 4db0da3..ad717d0 100644
--- a/cmd/soong_env/Android.bp
+++ b/cmd/soong_env/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_binary {
     name: "soong_env",
     deps: [
diff --git a/cmd/soong_ui/Android.bp b/cmd/soong_ui/Android.bp
index 4e57bef..4f5eea9 100644
--- a/cmd/soong_ui/Android.bp
+++ b/cmd/soong_ui/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "soong_ui",
     deps: [
diff --git a/cmd/zip2zip/Android.bp b/cmd/zip2zip/Android.bp
index 2c4cd82..3ef7668 100644
--- a/cmd/zip2zip/Android.bp
+++ b/cmd/zip2zip/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "zip2zip",
     deps: [
diff --git a/cmd/zipsync/Android.bp b/cmd/zipsync/Android.bp
index 49b5f3e..0dcdd5c 100644
--- a/cmd/zipsync/Android.bp
+++ b/cmd/zipsync/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "zipsync",
     deps: [
diff --git a/cuj/Android.bp b/cuj/Android.bp
index 21d667f..a2da6e6 100644
--- a/cuj/Android.bp
+++ b/cuj/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "cuj_tests",
     deps: [
diff --git a/dexpreopt/Android.bp b/dexpreopt/Android.bp
index 35f90df..679d066 100644
--- a/dexpreopt/Android.bp
+++ b/dexpreopt/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-dexpreopt",
     pkgPath: "android/soong/dexpreopt",
diff --git a/dexpreopt/class_loader_context.go b/dexpreopt/class_loader_context.go
index ec62eb3..ad52b00 100644
--- a/dexpreopt/class_loader_context.go
+++ b/dexpreopt/class_loader_context.go
@@ -489,20 +489,16 @@
 }
 
 // Class loader contexts that come from Make via JSON dexpreopt.config. JSON CLC representation is
-// slightly different: it uses a map of library names to their CLC (instead of a list of structs
-// that including the name, as in the Soong CLC representation). The difference is insubstantial, it
-// is caused only by the language differerences between Go and JSON.
+// the same as Soong representation except that SDK versions and paths are represented with strings.
 type jsonClassLoaderContext struct {
+	Name        string
 	Host        string
 	Device      string
-	Subcontexts map[string]*jsonClassLoaderContext
+	Subcontexts []*jsonClassLoaderContext
 }
 
-// A map of <uses-library> name to its on-host and on-device build paths and CLC.
-type jsonClassLoaderContexts map[string]*jsonClassLoaderContext
-
 // A map from SDK version (represented with a JSON string) to JSON CLCs.
-type jsonClassLoaderContextMap map[string]map[string]*jsonClassLoaderContext
+type jsonClassLoaderContextMap map[string][]*jsonClassLoaderContext
 
 // Convert JSON CLC map to Soong represenation.
 func fromJsonClassLoaderContext(ctx android.PathContext, jClcMap jsonClassLoaderContextMap) ClassLoaderContextMap {
@@ -522,11 +518,11 @@
 }
 
 // Recursive helper for fromJsonClassLoaderContext.
-func fromJsonClassLoaderContextRec(ctx android.PathContext, jClcs map[string]*jsonClassLoaderContext) []*ClassLoaderContext {
+func fromJsonClassLoaderContextRec(ctx android.PathContext, jClcs []*jsonClassLoaderContext) []*ClassLoaderContext {
 	clcs := make([]*ClassLoaderContext, 0, len(jClcs))
-	for lib, clc := range jClcs {
+	for _, clc := range jClcs {
 		clcs = append(clcs, &ClassLoaderContext{
-			Name:        lib,
+			Name:        clc.Name,
 			Host:        constructPath(ctx, clc.Host),
 			Device:      clc.Device,
 			Subcontexts: fromJsonClassLoaderContextRec(ctx, clc.Subcontexts),
@@ -546,14 +542,15 @@
 }
 
 // Recursive helper for toJsonClassLoaderContext.
-func toJsonClassLoaderContextRec(clcs []*ClassLoaderContext) map[string]*jsonClassLoaderContext {
-	jClcs := make(map[string]*jsonClassLoaderContext, len(clcs))
+func toJsonClassLoaderContextRec(clcs []*ClassLoaderContext) []*jsonClassLoaderContext {
+	jClcs := make([]*jsonClassLoaderContext, len(clcs))
 	for _, clc := range clcs {
-		jClcs[clc.Name] = &jsonClassLoaderContext{
+		jClcs = append(jClcs, &jsonClassLoaderContext{
+			Name:        clc.Name,
 			Host:        clc.Host.String(),
 			Device:      clc.Device,
 			Subcontexts: toJsonClassLoaderContextRec(clc.Subcontexts),
-		}
+		})
 	}
 	return jClcs
 }
diff --git a/dexpreopt/dexpreopt_gen/Android.bp b/dexpreopt/dexpreopt_gen/Android.bp
index 3f0619c..2111451 100644
--- a/dexpreopt/dexpreopt_gen/Android.bp
+++ b/dexpreopt/dexpreopt_gen/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "dexpreopt_gen",
     srcs: [
diff --git a/env/Android.bp b/env/Android.bp
index 90c6047..c6a97b1 100644
--- a/env/Android.bp
+++ b/env/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-env",
     pkgPath: "android/soong/env",
diff --git a/etc/Android.bp b/etc/Android.bp
index cfd303e..cab7389 100644
--- a/etc/Android.bp
+++ b/etc/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-etc",
     pkgPath: "android/soong/etc",
diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go
index 850c8f9..e15324b 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
@@ -269,11 +282,14 @@
 		Input:  p.sourceFilePath,
 	})
 
-	if p.Installable() {
-		installPath := ctx.InstallFile(p.installDirPath, p.outputFilePath.Base(), p.outputFilePath)
-		for _, sl := range p.properties.Symlinks {
-			ctx.InstallSymlink(p.installDirPath, sl, installPath)
-		}
+	if !p.Installable() {
+		p.SkipInstall()
+	}
+
+	// Call InstallFile even when uninstallable to make the module included in the package
+	installPath := ctx.InstallFile(p.installDirPath, p.outputFilePath.Base(), p.outputFilePath)
+	for _, sl := range p.properties.Symlinks {
+		ctx.InstallSymlink(p.installDirPath, sl, installPath)
 	}
 }
 
diff --git a/filesystem/Android.bp b/filesystem/Android.bp
index 9994241..42a4c88 100644
--- a/filesystem/Android.bp
+++ b/filesystem/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-filesystem",
     pkgPath: "android/soong/filesystem",
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 5092ad0..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
@@ -48,9 +55,22 @@
 	// Hash and signing algorithm for avbtool. Default is SHA256_RSA4096.
 	Avb_algorithm *string
 
-	// Type of the filesystem. Currently, ext4 and compressed_cpio are supported. Default is
-	// ext4.
+	// Type of the filesystem. Currently, ext4, cpio, and compressed_cpio are supported. Default
+	// is ext4.
 	Type *string
+
+	// 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
@@ -80,6 +100,7 @@
 const (
 	ext4Type fsType = iota
 	compressedCpioType
+	cpioType // uncompressed
 	unknown
 )
 
@@ -90,6 +111,8 @@
 		return ext4Type
 	case "compressed_cpio":
 		return compressedCpioType
+	case "cpio":
+		return cpioType
 	default:
 		ctx.PropertyErrorf("type", "%q not supported", typeStr)
 		return unknown
@@ -107,7 +130,9 @@
 	case ext4Type:
 		f.output = f.buildImageUsingBuildImage(ctx)
 	case compressedCpioType:
-		f.output = f.buildCompressedCpioImage(ctx)
+		f.output = f.buildCpioImage(ctx, true)
+	case cpioType:
+		f.output = f.buildCpioImage(ctx, false)
 	default:
 		return
 	}
@@ -116,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
@@ -142,6 +226,16 @@
 	return output
 }
 
+func (f *filesystem) buildFileContexts(ctx android.ModuleContext) android.OutputPath {
+	builder := android.NewRuleBuilder(pctx, ctx)
+	fcBin := android.PathForModuleOut(ctx, "file_contexts.bin")
+	builder.Command().BuiltTool("sefcontext_compile").
+		FlagWithOutput("-o ", fcBin).
+		Input(android.PathForModuleSrc(ctx, proptools.String(f.properties.File_contexts)))
+	builder.Build("build_filesystem_file_contexts", fmt.Sprintf("Creating filesystem file contexts for %s", f.BaseModuleName()))
+	return fcBin.OutputPath
+}
+
 func (f *filesystem) buildPropFile(ctx android.ModuleContext) (propFile android.OutputPath, toolDeps android.Paths) {
 	type prop struct {
 		name  string
@@ -169,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.
@@ -188,6 +282,10 @@
 		addStr("partition_name", f.Name())
 	}
 
+	if proptools.String(f.properties.File_contexts) != "" {
+		addPath("selinux_fc", f.buildFileContexts(ctx))
+	}
+
 	propFile = android.PathForModuleOut(ctx, "prop").OutputPath
 	builder := android.NewRuleBuilder(pctx, ctx)
 	builder.Command().Text("rm").Flag("-rf").Output(propFile)
@@ -201,35 +299,53 @@
 	return propFile, deps
 }
 
-func (f *filesystem) buildCompressedCpioImage(ctx android.ModuleContext) android.OutputPath {
+func (f *filesystem) buildCpioImage(ctx android.ModuleContext, compressed bool) android.OutputPath {
 	if proptools.Bool(f.properties.Use_avb) {
 		ctx.PropertyErrorf("use_avb", "signing compresed cpio image using avbtool is not supported."+
 			"Consider adding this to bootimg module and signing the entire boot image.")
 	}
 
-	zipFile := android.PathForModuleOut(ctx, "temp.zip").OutputPath
-	f.CopyDepsToZip(ctx, zipFile)
+	if proptools.String(f.properties.File_contexts) != "" {
+		ctx.PropertyErrorf("file_contexts", "file_contexts is not supported for compressed cpio image.")
+	}
+
+	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
-	builder.Command().
+	cmd := builder.Command().
 		BuiltTool("mkbootfs").
-		Text(rootDir.String()). // input directory
-		Text("|").
-		BuiltTool("lz4").
-		Flag("--favor-decSpeed"). // for faster boot
-		Flag("-12").              // maximum compression level
-		Flag("-l").               // legacy format for kernel
-		Text(">").Output(output)
+		Text(rootDir.String()) // input directory
+	if compressed {
+		cmd.Text("|").
+			BuiltTool("lz4").
+			Flag("--favor-decSpeed"). // for faster boot
+			Flag("-12").              // maximum compression level
+			Flag("-l").               // legacy format for kernel
+			Text(">").Output(output)
+	} else {
+		cmd.Text(">").Output(output)
+	}
 
 	// rootDir is not deleted. Might be useful for quick inspection.
-	builder.Build("build_compressed_cpio_image", fmt.Sprintf("Creating filesystem %s", f.BaseModuleName()))
+	builder.Build("build_cpio_image", fmt.Sprintf("Creating filesystem %s", f.BaseModuleName()))
 
 	return output
 }
@@ -250,6 +366,16 @@
 	}}
 }
 
+var _ android.OutputFileProducer = (*filesystem)(nil)
+
+// Implements android.OutputFileProducer
+func (f *filesystem) OutputFiles(tag string) (android.Paths, error) {
+	if tag == "" {
+		return []android.Path{f.output}, nil
+	}
+	return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+}
+
 // Filesystem is the public interface for the filesystem struct. Currently, it's only for the apex
 // package to have access to the output file.
 type Filesystem interface {
diff --git a/finder/Android.bp b/finder/Android.bp
index a5d7fd4..a3df6ec 100644
--- a/finder/Android.bp
+++ b/finder/Android.bp
@@ -16,6 +16,10 @@
 // fast, parallel, caching implementation of `find`
 //
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 subdirs = [
     "cmd",
 ]
diff --git a/finder/cmd/Android.bp b/finder/cmd/Android.bp
index e066c39..32843a0 100644
--- a/finder/cmd/Android.bp
+++ b/finder/cmd/Android.bp
@@ -16,6 +16,10 @@
 // fast, parallel, caching implementation of `find`
 //
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "finder",
     srcs: [
diff --git a/finder/fs/Android.bp b/finder/fs/Android.bp
index 85929ae..14bdb30 100644
--- a/finder/fs/Android.bp
+++ b/finder/fs/Android.bp
@@ -16,6 +16,21 @@
 // mock filesystem
 //
 
+package {
+    default_applicable_licenses: [
+        "Android-Apache-2.0",
+        "build_soong_finder_fs_license",
+    ],
+}
+
+license {
+    name: "build_soong_finder_fs_license",
+    license_kinds: [
+        "SPDX-license-identifier-BSD",
+    ],
+    license_text: ["LICENSE"],
+}
+
 bootstrap_go_package {
     name: "soong-finder-fs",
     pkgPath: "android/soong/finder/fs",
diff --git a/finder/fs/LICENSE b/finder/fs/LICENSE
new file mode 100644
index 0000000..e5c5baf
--- /dev/null
+++ b/finder/fs/LICENSE
@@ -0,0 +1,28 @@
+Copyright 2009, Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of the Google Inc. nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/genrule/Android.bp b/genrule/Android.bp
index 0e27d4e..214940d 100644
--- a/genrule/Android.bp
+++ b/genrule/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-genrule",
     pkgPath: "android/soong/genrule",
diff --git a/genrule/genrule.go b/genrule/genrule.go
index ddfb459..9fa6c48 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -47,9 +47,14 @@
 		ctx.BottomUp("genrule_tool_deps", toolDepsMutator).Parallel()
 	})
 
+	android.DepsBp2BuildMutators(RegisterGenruleBp2BuildDeps)
 	android.RegisterBp2BuildMutator("genrule", GenruleBp2Build)
 }
 
+func RegisterGenruleBp2BuildDeps(ctx android.RegisterMutatorsContext) {
+	ctx.BottomUp("genrule_tool_deps", toolDepsMutator)
+}
+
 var (
 	pctx = android.NewPackageContext("android/soong/genrule")
 
@@ -775,10 +780,9 @@
 }
 
 type bazelGenruleAttributes struct {
-	Name  *string
-	Srcs  []string
+	Srcs  bazel.LabelList
 	Outs  []string
-	Tools []string
+	Tools bazel.LabelList
 	Cmd   string
 }
 
@@ -795,45 +799,64 @@
 }
 
 func GenruleBp2Build(ctx android.TopDownMutatorContext) {
-	if m, ok := ctx.Module().(*Module); ok {
-		name := "__bp2build__" + m.Name()
-		// Bazel only has the "tools" attribute.
-		tools := append(m.properties.Tools, m.properties.Tool_files...)
-
-		// Replace in and out variables with $< and $@
-		var cmd string
-		if m.properties.Cmd != nil {
-			cmd = strings.Replace(*m.properties.Cmd, "$(in)", "$(SRCS)", -1)
-			cmd = strings.Replace(cmd, "$(out)", "$(OUTS)", -1)
-			cmd = strings.Replace(cmd, "$(genDir)", "$(GENDIR)", -1)
-			if len(tools) > 0 {
-				cmd = strings.Replace(cmd, "$(location)", fmt.Sprintf("$(location %s)", tools[0]), -1)
-				cmd = strings.Replace(cmd, "$(locations)", fmt.Sprintf("$(locations %s)", tools[0]), -1)
-			}
-		}
-
-		// The Out prop is not in an immediately accessible field
-		// in the Module struct, so use GetProperties and cast it
-		// to the known struct prop.
-		var outs []string
-		for _, propIntf := range m.GetProperties() {
-			if props, ok := propIntf.(*genRuleProperties); ok {
-				outs = props.Out
-				break
-			}
-		}
-
-		// Create the BazelTargetModule.
-		ctx.CreateModule(BazelGenruleFactory, &bazelGenruleAttributes{
-			Name:  proptools.StringPtr(name),
-			Srcs:  m.properties.Srcs,
-			Outs:  outs,
-			Cmd:   cmd,
-			Tools: tools,
-		}, &bazel.BazelTargetModuleProperties{
-			Rule_class: "genrule",
-		})
+	m, ok := ctx.Module().(*Module)
+	if !ok || !m.properties.Bazel_module.Bp2build_available {
+		return
 	}
+
+	// Bazel only has the "tools" attribute.
+	tools := android.BazelLabelForModuleDeps(ctx, m.properties.Tools)
+	tool_files := android.BazelLabelForModuleSrc(ctx, m.properties.Tool_files)
+	tools.Append(tool_files)
+
+	srcs := android.BazelLabelForModuleSrc(ctx, m.properties.Srcs)
+
+	var allReplacements bazel.LabelList
+	allReplacements.Append(tools)
+	allReplacements.Append(srcs)
+
+	// Replace in and out variables with $< and $@
+	var cmd string
+	if m.properties.Cmd != nil {
+		cmd = strings.Replace(*m.properties.Cmd, "$(in)", "$(SRCS)", -1)
+		cmd = strings.Replace(cmd, "$(out)", "$(OUTS)", -1)
+		cmd = strings.Replace(cmd, "$(genDir)", "$(GENDIR)", -1)
+		if len(tools.Includes) > 0 {
+			cmd = strings.Replace(cmd, "$(location)", fmt.Sprintf("$(location %s)", tools.Includes[0].Label), -1)
+			cmd = strings.Replace(cmd, "$(locations)", fmt.Sprintf("$(locations %s)", tools.Includes[0].Label), -1)
+		}
+		for _, l := range allReplacements.Includes {
+			bpLoc := fmt.Sprintf("$(location %s)", l.Bp_text)
+			bpLocs := fmt.Sprintf("$(locations %s)", l.Bp_text)
+			bazelLoc := fmt.Sprintf("$(location %s)", l.Label)
+			bazelLocs := fmt.Sprintf("$(locations %s)", l.Label)
+			cmd = strings.Replace(cmd, bpLoc, bazelLoc, -1)
+			cmd = strings.Replace(cmd, bpLocs, bazelLocs, -1)
+		}
+	}
+
+	// The Out prop is not in an immediately accessible field
+	// in the Module struct, so use GetProperties and cast it
+	// to the known struct prop.
+	var outs []string
+	for _, propIntf := range m.GetProperties() {
+		if props, ok := propIntf.(*genRuleProperties); ok {
+			outs = props.Out
+			break
+		}
+	}
+
+	attrs := &bazelGenruleAttributes{
+		Srcs:  srcs,
+		Outs:  outs,
+		Cmd:   cmd,
+		Tools: tools,
+	}
+
+	props := bazel.NewBazelTargetModuleProperties(m.Name(), "genrule", "")
+
+	// Create the BazelTargetModule.
+	ctx.CreateBazelTargetModule(BazelGenruleFactory, props, attrs)
 }
 
 func (m *bazelGenrule) Name() string {
diff --git a/jar/Android.bp b/jar/Android.bp
index 2563474..46113d8 100644
--- a/jar/Android.bp
+++ b/jar/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-jar",
     pkgPath: "android/soong/jar",
diff --git a/java/Android.bp b/java/Android.bp
index 364566a..9bfd009 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-java",
     pkgPath: "android/soong/java",
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/androidmk.go b/java/androidmk.go
index 21f3012..6e7c437 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -646,6 +646,9 @@
 					entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", a.dexpreopter.builtInstalled)
 				}
 				entries.AddStrings("LOCAL_INSTALLED_MODULE_STEM", a.installPath.Rel())
+				if Bool(a.properties.Export_package_resources) {
+					entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", a.outputFile)
+				}
 			},
 		},
 	}}
diff --git a/java/app_import.go b/java/app_import.go
index 6f21bfb..59eb10a 100644
--- a/java/app_import.go
+++ b/java/app_import.go
@@ -92,6 +92,10 @@
 
 	// Optional name for the installed app. If unspecified, it is derived from the module name.
 	Filename *string
+
+	// If set, create package-export.apk, which other packages can
+	// use to get PRODUCT-agnostic resource data like IDs and type definitions.
+	Export_package_resources *bool
 }
 
 func (a *AndroidAppImport) IsInstallable() bool {
@@ -142,13 +146,17 @@
 	}
 }
 
+func (a *AndroidAppImport) isPrebuiltFrameworkRes() bool {
+	return a.Name() == "prebuilt_framework-res"
+}
+
 func (a *AndroidAppImport) DepsMutator(ctx android.BottomUpMutatorContext) {
 	cert := android.SrcIsModule(String(a.properties.Certificate))
 	if cert != "" {
 		ctx.AddDependency(ctx.Module(), certificateTag, cert)
 	}
 
-	a.usesLibrary.deps(ctx, true)
+	a.usesLibrary.deps(ctx, !a.isPrebuiltFrameworkRes())
 }
 
 func (a *AndroidAppImport) uncompressEmbeddedJniLibs(
@@ -247,7 +255,12 @@
 	a.uncompressEmbeddedJniLibs(ctx, srcApk, jnisUncompressed.OutputPath)
 
 	var installDir android.InstallPath
-	if Bool(a.properties.Privileged) {
+
+	if a.isPrebuiltFrameworkRes() {
+		// framework-res.apk is installed as system/framework/framework-res.apk
+		installDir = android.PathForModuleInstall(ctx, "framework")
+		a.preprocessed = true
+	} else if Bool(a.properties.Privileged) {
 		installDir = android.PathForModuleInstall(ctx, "priv-app", a.BaseModuleName())
 	} else if ctx.InstallInTestcases() {
 		installDir = android.PathForModuleInstall(ctx, a.BaseModuleName(), ctx.DeviceConfig().DeviceArch())
@@ -275,7 +288,15 @@
 	// TODO: Handle EXTERNAL
 
 	// Sign or align the package if package has not been preprocessed
-	if a.preprocessed {
+
+	if a.isPrebuiltFrameworkRes() {
+		a.outputFile = srcApk
+		certificates = processMainCert(a.ModuleBase, String(a.properties.Certificate), certificates, ctx)
+		if len(certificates) != 1 {
+			ctx.ModuleErrorf("Unexpected number of certificates were extracted: %q", certificates)
+		}
+		a.certificate = certificates[0]
+	} else if a.preprocessed {
 		a.outputFile = srcApk
 		a.certificate = PresignedCertificate
 	} else if !Bool(a.properties.Presigned) {
diff --git a/java/app_import_test.go b/java/app_import_test.go
index 344d23b..d7f69eb 100644
--- a/java/app_import_test.go
+++ b/java/app_import_test.go
@@ -393,6 +393,69 @@
 	}
 }
 
+func TestAndroidAppImport_frameworkRes(t *testing.T) {
+	ctx, config := testJava(t, `
+		android_app_import {
+			name: "framework-res",
+			certificate: "platform",
+			apk: "package-res.apk",
+			prefer: true,
+			export_package_resources: true,
+			// Disable dexpreopt and verify_uses_libraries check as the app
+			// contains no Java code to be dexpreopted.
+			enforce_uses_libs: false,
+			dex_preopt: {
+				enabled: false,
+			},
+		}
+		`)
+
+	mod := ctx.ModuleForTests("prebuilt_framework-res", "android_common").Module()
+	a := mod.(*AndroidAppImport)
+
+	if !a.preprocessed {
+		t.Errorf("prebuilt framework-res is not preprocessed")
+	}
+
+	expectedInstallPath := buildDir + "/target/product/test_device/system/framework/framework-res.apk"
+
+	if a.dexpreopter.installPath.String() != expectedInstallPath {
+		t.Errorf("prebuilt framework-res installed to incorrect location, actual: %s, expected: %s", a.dexpreopter.installPath, expectedInstallPath)
+
+	}
+
+	entries := android.AndroidMkEntriesForTest(t, config, "", mod)[0]
+
+	expectedPath := "."
+	// From apk property above, in the root of the source tree.
+	expectedPrebuiltModuleFile := "package-res.apk"
+	// Verify that the apk is preprocessed: The export package is the same
+	// as the prebuilt.
+	expectedSoongResourceExportPackage := expectedPrebuiltModuleFile
+
+	actualPath := entries.EntryMap["LOCAL_PATH"]
+	actualPrebuiltModuleFile := entries.EntryMap["LOCAL_PREBUILT_MODULE_FILE"]
+	actualSoongResourceExportPackage := entries.EntryMap["LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE"]
+
+	if len(actualPath) != 1 {
+		t.Errorf("LOCAL_PATH incorrect len %d", len(actualPath))
+	} else if actualPath[0] != expectedPath {
+		t.Errorf("LOCAL_PATH mismatch, actual: %s, expected: %s", actualPath[0], expectedPath)
+	}
+
+	if len(actualPrebuiltModuleFile) != 1 {
+		t.Errorf("LOCAL_PREBUILT_MODULE_FILE incorrect len %d", len(actualPrebuiltModuleFile))
+	} else if actualPrebuiltModuleFile[0] != expectedPrebuiltModuleFile {
+		t.Errorf("LOCAL_PREBUILT_MODULE_FILE mismatch, actual: %s, expected: %s", actualPrebuiltModuleFile[0], expectedPrebuiltModuleFile)
+	}
+
+	if len(actualSoongResourceExportPackage) != 1 {
+		t.Errorf("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE incorrect len %d", len(actualSoongResourceExportPackage))
+	} else if actualSoongResourceExportPackage[0] != expectedSoongResourceExportPackage {
+		t.Errorf("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE mismatch, actual: %s, expected: %s", actualSoongResourceExportPackage[0], expectedSoongResourceExportPackage)
+	}
+}
+
 func TestAndroidTestImport(t *testing.T) {
 	ctx, config := testJava(t, `
 		android_test_import {
diff --git a/java/boot_image.go b/java/boot_image.go
index 0a525b7..8a1e3c9 100644
--- a/java/boot_image.go
+++ b/java/boot_image.go
@@ -90,6 +90,10 @@
 		// The dex2oat tool is only needed for building and is not required in the apex.
 		return false
 	}
+	if android.IsMetaDependencyTag(tag) {
+		// Cross-cutting metadata dependencies are metadata.
+		return false
+	}
 	panic(fmt.Errorf("boot_image module %q should not have a dependency on %q via tag %s", b, dep, android.PrettyPrintTag(tag)))
 }
 
diff --git a/java/builder.go b/java/builder.go
index 995160d..22a891a 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -193,12 +193,19 @@
 
 	jarjar = pctx.AndroidStaticRule("jarjar",
 		blueprint.RuleParams{
-			Command: "${config.JavaCmd} ${config.JavaVmFlags}" +
+			Command: "" +
+				// Jarjar doesn't exit with an error when the rules file contains a syntax error,
+				// leading to stale or missing files later in the build.  Remove the output file
+				// before running jarjar.
+				"rm -f ${out} && " +
+				"${config.JavaCmd} ${config.JavaVmFlags}" +
 				// b/146418363 Enable Android specific jarjar transformer to drop compat annotations
 				// for newly repackaged classes. Dropping @UnsupportedAppUsage on repackaged classes
 				// avoids adding new hiddenapis after jarjar'ing.
 				" -DremoveAndroidCompatAnnotations=true" +
-				" -jar ${config.JarjarCmd} process $rulesFile $in $out",
+				" -jar ${config.JarjarCmd} process $rulesFile $in $out && " +
+				// Turn a missing output file into a ninja error
+				`[ -e ${out} ] || (echo "Missing output file"; exit 1)`,
 			CommandDeps: []string{"${config.JavaCmd}", "${config.JarjarCmd}", "$rulesFile"},
 		},
 		"rulesFile")
diff --git a/java/config/Android.bp b/java/config/Android.bp
index 1983521..194e2c6 100644
--- a/java/config/Android.bp
+++ b/java/config/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-java-config",
     pkgPath: "android/soong/java/config",
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.go b/java/dexpreopt.go
index da62100..29c73c1 100644
--- a/java/dexpreopt.go
+++ b/java/dexpreopt.go
@@ -129,8 +129,6 @@
 
 	dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
 
-	buildPath := android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath
-
 	providesUsesLib := ctx.ModuleName()
 	if ulib, ok := ctx.Module().(ProvidesUsesLib); ok {
 		name := ulib.ProvidesUsesLib()
@@ -146,7 +144,6 @@
 		slimDexpreoptConfig := &dexpreopt.ModuleConfig{
 			Name:                 ctx.ModuleName(),
 			DexLocation:          dexLocation,
-			BuildPath:            buildPath,
 			EnforceUsesLibraries: d.enforceUsesLibs,
 			ProvidesUsesLibrary:  providesUsesLib,
 			ClassLoaderContexts:  d.classLoaderContexts,
@@ -218,7 +215,7 @@
 	dexpreoptConfig := &dexpreopt.ModuleConfig{
 		Name:            ctx.ModuleName(),
 		DexLocation:     dexLocation,
-		BuildPath:       buildPath,
+		BuildPath:       android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath,
 		DexPath:         dexJarFile,
 		ManifestPath:    d.manifestFile,
 		UncompressedDex: d.uncompressedDex,
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 2a7eb42..86b1895 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -435,6 +435,11 @@
 // Inspect this module to see if it contains a bootclasspath dex jar.
 // Note that the same jar may occur in multiple modules.
 // This logic is tested in the apex package to avoid import cycle apex <-> java.
+//
+// This is similar to logic in isModuleInConfiguredList() so any changes needed here are likely to
+// be needed there too.
+//
+// TODO(b/177892522): Avoid having to perform this type of check or if necessary dedup it.
 func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, module android.Module) (int, android.Path) {
 	name := ctx.ModuleName(module)
 
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 eafbf5d..f8e41c4 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -28,10 +28,39 @@
 }, "outFlag", "stubAPIFlags")
 
 type hiddenAPI struct {
+	// The name of the module as it would be used in the boot jars configuration, e.g. without any
+	// prebuilt_ prefix (if it is a prebuilt), without any "-hiddenapi" suffix if it just provides
+	// annotations and without any ".impl" suffix if it is a java_sdk_library implementation library.
+	configurationName string
+
+	// True if the module containing this structure contributes to the hiddenapi information or has
+	// that information encoded within it.
+	active bool
+
+	// Identifies the active module variant which will be used as the source of hiddenapi information.
+	//
+	// A class may be compiled into a number of different module variants each of which will need the
+	// hiddenapi information encoded into it and so will be marked as active. However, only one of
+	// them must be used as a source of information by hiddenapi otherwise it will end up with
+	// duplicate entries. That module will have primary=true.
+	//
+	// Note, that modules <x>-hiddenapi that provide additional annotation information for module <x>
+	// that is on the bootclasspath are marked as primary=true as they are the primary source of that
+	// annotation information.
+	primary bool
+
+	// True if the module only contains additional annotations and so does not require hiddenapi
+	// information to be encoded in its dex file and should not be used to generate the
+	// hiddenAPISingletonPathsStruct.stubFlags file.
+	annotationsOnly bool
+
 	// The path to the dex jar that is in the boot class path. If this is nil then the associated
 	// module is not a boot jar, but could be one of the <x>-hiddenapi modules that provide additional
 	// annotations for the <x> boot dex jar but which do not actually provide a boot dex jar
 	// themselves.
+	//
+	// This must be the path to the unencoded dex jar as the encoded dex jar indirectly depends on
+	// this file so using the encoded dex jar here would result in a cycle in the ninja rules.
 	bootDexJarPath android.Path
 
 	// The path to the CSV file that contains mappings from Java signature to various flags derived
@@ -89,59 +118,122 @@
 
 var _ hiddenAPIIntf = (*hiddenAPI)(nil)
 
-func (h *hiddenAPI) hiddenAPI(ctx android.ModuleContext, name string, primary bool, dexJar android.OutputPath,
-	implementationJar android.Path, uncompressDex bool) android.OutputPath {
-	if !ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+// Initialize the hiddenapi structure
+func (h *hiddenAPI) initHiddenAPI(ctx android.BaseModuleContext, name string) {
+	// If hiddenapi processing is disabled treat this as inactive.
+	if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") {
+		return
+	}
 
-		// Modules whose names are of the format <x>-hiddenapi provide hiddenapi information
-		// for the boot jar module <x>. Otherwise, the module provides information for itself.
-		// Either way extract the name of the boot jar module.
-		bootJarName := strings.TrimSuffix(name, "-hiddenapi")
+	// Modules whose names are of the format <x>-hiddenapi provide hiddenapi information for the boot
+	// jar module <x>. Otherwise, the module provides information for itself. Either way extract the
+	// configurationName of the boot jar module.
+	configurationName := strings.TrimSuffix(name, "-hiddenapi")
+	h.configurationName = configurationName
 
-		// If this module is on the boot jars list (or providing information for a module
-		// on the list) then extract the hiddenapi information from it, and if necessary
-		// encode that information in the generated dex file.
-		//
-		// It is important that hiddenapi information is only gathered for/from modules on
-		// that are actually on the boot jars list because the runtime only enforces access
-		// to the hidden API for the bootclassloader. If information is gathered for modules
-		// not on the list then that will cause failures in the CtsHiddenApiBlacklist...
-		// tests.
-		if inList(bootJarName, ctx.Config().BootJars()) {
-			// Create ninja rules to generate various CSV files needed by hiddenapi and store the paths
-			// in the hiddenAPI structure.
-			h.hiddenAPIGenerateCSV(ctx, implementationJar)
+	// It is important that hiddenapi information is only gathered for/from modules that are actually
+	// on the boot jars list because the runtime only enforces access to the hidden API for the
+	// bootclassloader. If information is gathered for modules not on the list then that will cause
+	// failures in the CtsHiddenApiBlocklist... tests.
+	h.active = inList(configurationName, ctx.Config().BootJars())
+	if !h.active {
+		// The rest of the properties will be ignored if active is false.
+		return
+	}
 
-			// If this module is actually on the boot jars list and not providing
-			// hiddenapi information for a module on the boot jars list then encode
-			// the gathered information in the generated dex file.
-			if name == bootJarName {
-				hiddenAPIJar := android.PathForModuleOut(ctx, "hiddenapi", name+".jar").OutputPath
+	// If this module has a suffix of -hiddenapi then it only provides additional annotation
+	// information for a module on the boot jars list.
+	h.annotationsOnly = strings.HasSuffix(name, "-hiddenapi")
 
-				// More than one library with the same classes can be encoded but only one can
-				// be added to the global set of flags, otherwise it will result in duplicate
-				// classes which is an error. Therefore, only add the dex jar of one of them
-				// to the global set of flags.
-				if primary {
-					h.bootDexJarPath = dexJar
-				}
-				hiddenAPIEncodeDex(ctx, hiddenAPIJar, dexJar, uncompressDex)
-				dexJar = hiddenAPIJar
-			}
+	// Determine whether this module is the primary module or not.
+	primary := true
+
+	// A prebuilt module is only primary if it is preferred and conversely a source module is only
+	// primary if it has not been replaced by a prebuilt module.
+	module := ctx.Module()
+	if pi, ok := module.(android.PrebuiltInterface); ok {
+		if p := pi.Prebuilt(); p != nil {
+			primary = p.UsePrebuilt()
 		}
+	} else {
+		// The only module that will pass a different name to its module name to this method is the
+		// implementation library of a java_sdk_library. It has a configuration name of <x> the same
+		// as its parent java_sdk_library but a module name of <x>.impl. It is not the primary module,
+		// the java_sdk_library with the name of <x> is.
+		primary = name == ctx.ModuleName()
+
+		// A source module that has been replaced by a prebuilt can never be the primary module.
+		primary = primary && !module.IsReplacedByPrebuilt()
+	}
+	h.primary = primary
+}
+
+// hiddenAPIExtractAndEncode is called by any module that could contribute to the hiddenapi
+// processing.
+//
+// It ignores any module that has not had initHiddenApi() called on it and which is not in the boot
+// jar list.
+//
+// Otherwise, it generates ninja rules to do the following:
+// 1. Extract information needed for hiddenapi processing from the module and output it into CSV
+//    files.
+// 2. Conditionally adds the supplied dex file to the list of files used to generate the
+//    hiddenAPISingletonPathsStruct.stubsFlag file.
+// 3. Conditionally creates a copy of the supplied dex file into which it has encoded the hiddenapi
+//    flags and returns this instead of the supplied dex jar, otherwise simply returns the supplied
+//    dex jar.
+func (h *hiddenAPI) hiddenAPIExtractAndEncode(ctx android.ModuleContext, dexJar android.OutputPath,
+	implementationJar android.Path, uncompressDex bool) android.OutputPath {
+
+	if !h.active {
+		return dexJar
+	}
+
+	h.hiddenAPIExtractInformation(ctx, dexJar, implementationJar)
+
+	if !h.annotationsOnly {
+		hiddenAPIJar := android.PathForModuleOut(ctx, "hiddenapi", h.configurationName+".jar").OutputPath
+
+		// Create a copy of the dex jar which has been encoded with hiddenapi flags.
+		hiddenAPIEncodeDex(ctx, hiddenAPIJar, dexJar, uncompressDex)
+
+		// Use the encoded dex jar from here onwards.
+		dexJar = hiddenAPIJar
 	}
 
 	return dexJar
 }
 
-func (h *hiddenAPI) hiddenAPIGenerateCSV(ctx android.ModuleContext, classesJar android.Path) {
+// hiddenAPIExtractInformation generates ninja rules to extract the information from the classes
+// jar, and outputs it to the appropriate module specific CSV file.
+//
+// It also makes the dex jar available for use when generating the
+// hiddenAPISingletonPathsStruct.stubFlags.
+func (h *hiddenAPI) hiddenAPIExtractInformation(ctx android.ModuleContext, dexJar, classesJar android.Path) {
+	if !h.active {
+		return
+	}
+
+	// More than one library with the same classes may need to be encoded but only one should be
+	// used as a source of information for hidden API processing otherwise it will result in
+	// duplicate entries in the files.
+	if !h.primary {
+		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{
@@ -155,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{
@@ -169,10 +261,15 @@
 	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
+
+	// Save the unencoded dex jar so it can be used when generating the
+	// hiddenAPISingletonPathsStruct.stubFlags file.
+	h.bootDexJarPath = dexJar
 }
 
 var hiddenAPIEncodeDexRule = pctx.AndroidStaticRule("hiddenAPIEncodeDex", blueprint.RuleParams{
@@ -245,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 ccb8745..6341a34 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -22,9 +22,13 @@
 )
 
 func init() {
-	android.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory)
-	android.RegisterSingletonType("hiddenapi_index", hiddenAPIIndexSingletonFactory)
-	android.RegisterModuleType("hiddenapi_flags", hiddenAPIFlagsFactory)
+	RegisterHiddenApiSingletonComponents(android.InitRegistrationContext)
+}
+
+func RegisterHiddenApiSingletonComponents(ctx android.RegistrationContext) {
+	ctx.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory)
+	ctx.RegisterSingletonType("hiddenapi_index", hiddenAPIIndexSingletonFactory)
+	ctx.RegisterModuleType("hiddenapi_flags", hiddenAPIFlagsFactory)
 }
 
 type hiddenAPISingletonPathsStruct struct {
@@ -213,9 +217,13 @@
 
 	var bootDexJars android.Paths
 
+	// Get the configured non-updatable and updatable boot jars.
+	nonUpdatableBootJars := ctx.Config().NonUpdatableBootJars()
+	updatableBootJars := ctx.Config().UpdatableBootJars()
+
 	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 {
@@ -227,11 +235,8 @@
 		// Collect dex jar paths for modules that had hiddenapi encode called on them.
 		if h, ok := module.(hiddenAPIIntf); ok {
 			if jar := h.bootDexJar(); jar != nil {
-				// For a java lib included in an APEX, only take the one built for
-				// the platform variant, and skip the variants for APEXes.
-				// Otherwise, the hiddenapi tool will complain about duplicated classes
-				apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
-				if !apexInfo.IsForPlatform() {
+				if !isModuleInConfiguredList(ctx, module, nonUpdatableBootJars) &&
+					!isModuleInConfiguredList(ctx, module, updatableBootJars) {
 					return
 				}
 
@@ -280,6 +285,47 @@
 	rule.Build("hiddenAPIStubFlagsFile", "hiddenapi stub flags")
 }
 
+// Checks to see whether the supplied module variant is in the list of boot jars.
+//
+// This is similar to logic in getBootImageJar() so any changes needed here are likely to be needed
+// there too.
+//
+// TODO(b/179354495): Avoid having to perform this type of check or if necessary dedup it.
+func isModuleInConfiguredList(ctx android.SingletonContext, module android.Module, configuredBootJars android.ConfiguredJarList) bool {
+	name := ctx.ModuleName(module)
+
+	// Strip a prebuilt_ prefix so that this can match a prebuilt module that has not been renamed.
+	name = android.RemoveOptionalPrebuiltPrefix(name)
+
+	// Ignore any module that is not listed in the boot image configuration.
+	index := configuredBootJars.IndexOfJar(name)
+	if index == -1 {
+		return false
+	}
+
+	// It is an error if the module is not an ApexModule.
+	if _, ok := module.(android.ApexModule); !ok {
+		ctx.Errorf("module %q configured in boot jars does not support being added to an apex", module)
+		return false
+	}
+
+	apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+
+	// Now match the apex part of the boot image configuration.
+	requiredApex := configuredBootJars.Apex(index)
+	if requiredApex == "platform" {
+		if len(apexInfo.InApexes) != 0 {
+			// A platform variant is required but this is for an apex so ignore it.
+			return false
+		}
+	} else if !apexInfo.InApexByBaseName(requiredApex) {
+		// An apex variant for a specific apex is required but this is the wrong apex.
+		return false
+	}
+
+	return true
+}
+
 func prebuiltFlagsRule(ctx android.SingletonContext) android.Path {
 	outputPath := hiddenAPISingletonPaths(ctx).flags
 	inputPath := android.PathForSource(ctx, ctx.Config().PrebuiltHiddenApiDir(ctx), "hiddenapi-flags.csv")
@@ -326,7 +372,7 @@
 	stubFlags := hiddenAPISingletonPaths(ctx).stubFlags
 
 	rule.Command().
-		Tool(android.PathForSource(ctx, "frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py")).
+		BuiltTool("generate_hiddenapi_lists").
 		FlagWithInput("--csv ", stubFlags).
 		Inputs(flagsCSV).
 		FlagWithInput("--unsupported ",
diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go
index 0f9ef58..4670d03 100644
--- a/java/hiddenapi_singleton_test.go
+++ b/java/hiddenapi_singleton_test.go
@@ -15,11 +15,12 @@
 package java
 
 import (
-	"android/soong/android"
 	"fmt"
 	"strings"
 	"testing"
 
+	"android/soong/android"
+
 	"github.com/google/blueprint/proptools"
 )
 
@@ -32,7 +33,7 @@
 
 func testContextWithHiddenAPI(config android.Config) *android.TestContext {
 	ctx := testContext(config)
-	ctx.RegisterSingletonType("hiddenapi", hiddenAPISingletonFactory)
+	RegisterHiddenApiSingletonComponents(ctx)
 	return ctx
 }
 
@@ -64,8 +65,8 @@
 			name: "foo",
 			srcs: ["a.java"],
 			compile_dex: true,
-	}
-	`, []string{":foo"}, nil)
+		}
+	`, []string{"platform:foo"}, nil)
 
 	hiddenAPI := ctx.SingletonForTests("hiddenapi")
 	hiddenapiRule := hiddenAPI.Rule("hiddenapi")
@@ -75,6 +76,63 @@
 	}
 }
 
+func TestHiddenAPIIndexSingleton(t *testing.T) {
+	ctx, _ := testHiddenAPIBootJars(t, `
+		java_library {
+			name: "foo",
+			srcs: ["a.java"],
+			compile_dex: true,
+
+			hiddenapi_additional_annotations: [
+				"foo-hiddenapi-annotations",
+			],
+		}
+
+		java_library {
+			name: "foo-hiddenapi",
+			srcs: ["a.java"],
+			compile_dex: true,
+		}
+
+		java_library {
+			name: "foo-hiddenapi-annotations",
+			srcs: ["a.java"],
+			compile_dex: true,
+		}
+
+		java_import {
+			name: "foo",
+			jars: ["a.jar"],
+			compile_dex: true,
+			prefer: false,
+		}
+
+		java_sdk_library {
+			name: "bar",
+			srcs: ["a.java"],
+			compile_dex: true,
+		}
+	`, []string{"platform:foo", "platform:bar"}, nil)
+
+	hiddenAPIIndex := ctx.SingletonForTests("hiddenapi_index")
+	indexRule := hiddenAPIIndex.Rule("singleton-merged-hiddenapi-index")
+	CheckHiddenAPIRuleInputs(t, `
+.intermediates/bar/android_common/hiddenapi/index.csv
+.intermediates/foo-hiddenapi/android_common/hiddenapi/index.csv
+.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) {
 	ctx, _ := testHiddenAPIBootJars(t, `
 		java_import {
@@ -82,7 +140,7 @@
 			jars: ["a.jar"],
 			compile_dex: true,
 	}
-	`, []string{":foo"}, nil)
+	`, []string{"platform:foo"}, nil)
 
 	hiddenAPI := ctx.SingletonForTests("hiddenapi")
 	hiddenapiRule := hiddenAPI.Rule("hiddenapi")
@@ -98,15 +156,15 @@
 			name: "foo",
 			srcs: ["a.java"],
 			compile_dex: true,
-	}
+		}
 
 		java_import {
 			name: "foo",
 			jars: ["a.jar"],
 			compile_dex: true,
 			prefer: false,
-	}
-	`, []string{":foo"}, nil)
+		}
+	`, []string{"platform:foo"}, nil)
 
 	hiddenAPI := ctx.SingletonForTests("hiddenapi")
 	hiddenapiRule := hiddenAPI.Rule("hiddenapi")
@@ -127,15 +185,15 @@
 			name: "foo",
 			srcs: ["a.java"],
 			compile_dex: true,
-	}
+		}
 
 		java_import {
 			name: "foo",
 			jars: ["a.jar"],
 			compile_dex: true,
 			prefer: true,
-	}
-	`, []string{":foo"}, nil)
+		}
+	`, []string{"platform:foo"}, nil)
 
 	hiddenAPI := ctx.SingletonForTests("hiddenapi")
 	hiddenapiRule := hiddenAPI.Rule("hiddenapi")
@@ -236,7 +294,7 @@
 			jars: ["a.jar"],
 			compile_dex: true,
 	}
-	`, []string{":foo"}, &prebuiltHiddenApiDir)
+	`, []string{"platform:foo"}, &prebuiltHiddenApiDir)
 
 	expectedCpInput := prebuiltHiddenApiDir + "/hiddenapi-flags.csv"
 	expectedCpOutput := buildDir + "/hiddenapi/hiddenapi-flags.csv"
diff --git a/java/java.go b/java/java.go
index d49b64f..dbfad02 100644
--- a/java/java.go
+++ b/java/java.go
@@ -40,18 +40,21 @@
 	// Register sdk member types.
 	android.RegisterSdkMemberType(javaHeaderLibsSdkMemberType)
 
+	// Export implementation classes jar as part of the sdk.
+	exportImplementationClassesJar := func(_ android.SdkMemberContext, j *Library) android.Path {
+		implementationJars := j.ImplementationAndResourcesJars()
+		if len(implementationJars) != 1 {
+			panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name()))
+		}
+		return implementationJars[0]
+	}
+
 	// Register java implementation libraries for use only in module_exports (not sdk).
 	android.RegisterSdkMemberType(&librarySdkMemberType{
 		android.SdkMemberTypeBase{
 			PropertyName: "java_libs",
 		},
-		func(_ android.SdkMemberContext, j *Library) android.Path {
-			implementationJars := j.ImplementationAndResourcesJars()
-			if len(implementationJars) != 1 {
-				panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name()))
-			}
-			return implementationJars[0]
-		},
+		exportImplementationClassesJar,
 		sdkSnapshotFilePathForJar,
 		copyEverythingToSnapshot,
 	})
@@ -72,19 +75,11 @@
 			PropertyName: "java_boot_libs",
 			SupportsSdk:  true,
 		},
-		func(ctx android.SdkMemberContext, j *Library) android.Path {
-			// Java boot libs are only provided in the SDK to provide access to their dex implementation
-			// jar for use by dexpreopting and boot jars package check. They do not need to provide an
-			// actual implementation jar but the java_import will need a file that exists so just copy an
-			// empty file. Any attempt to use that file as a jar will cause a build error.
-			return ctx.SnapshotBuilder().EmptyFile()
-		},
-		func(osPrefix, name string) string {
-			// Create a special name for the implementation jar to try and provide some useful information
-			// to a developer that attempts to compile against this.
-			// TODO(b/175714559): Provide a proper error message in Soong not ninja.
-			return filepath.Join(osPrefix, "java_boot_libs", "snapshot", "jars", "are", "invalid", name+jarFileSuffix)
-		},
+		// Temporarily export implementation classes jar for java_boot_libs as it is required for the
+		// hiddenapi processing.
+		// TODO(b/179354495): Revert once hiddenapi processing has been modularized.
+		exportImplementationClassesJar,
+		sdkSnapshotFilePathForJar,
 		onlyCopyJarToSnapshot,
 	})
 
@@ -303,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 {
@@ -538,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
@@ -551,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
 }
@@ -810,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,
@@ -978,6 +1014,7 @@
 const (
 	// TODO(jiyong) rename these for better readability. Make the allowed
 	// and disallowed link types explicit
+	// order is important here. See rank()
 	javaCore linkType = iota
 	javaSdk
 	javaSystem
@@ -986,6 +1023,31 @@
 	javaPlatform
 )
 
+func (lt linkType) String() string {
+	switch lt {
+	case javaCore:
+		return "core Java API"
+	case javaSdk:
+		return "Android API"
+	case javaSystem:
+		return "system API"
+	case javaModule:
+		return "module API"
+	case javaSystemServer:
+		return "system server API"
+	case javaPlatform:
+		return "private API"
+	default:
+		panic(fmt.Errorf("unrecognized linktype: %v", lt))
+	}
+}
+
+// rank determins the total order among linkTypes. A link type of rank A can link to another link
+// type of rank B only when B <= A
+func (lt linkType) rank() int {
+	return int(lt)
+}
+
 type linkTypeContext interface {
 	android.Module
 	getLinkType(name string) (ret linkType, stubs bool)
@@ -1045,44 +1107,13 @@
 		return
 	}
 	otherLinkType, _ := to.getLinkType(ctx.OtherModuleName(to))
-	commonMessage := " In order to fix this, consider adjusting sdk_version: OR platform_apis: " +
-		"property of the source or target module so that target module is built with the same " +
-		"or smaller API set when compared to the source."
 
-	switch myLinkType {
-	case javaCore:
-		if otherLinkType != javaCore {
-			ctx.ModuleErrorf("compiles against core Java API, but dependency %q is compiling against non-core Java APIs."+commonMessage,
-				ctx.OtherModuleName(to))
-		}
-		break
-	case javaSdk:
-		if otherLinkType != javaCore && otherLinkType != javaSdk {
-			ctx.ModuleErrorf("compiles against Android API, but dependency %q is compiling against non-public Android API."+commonMessage,
-				ctx.OtherModuleName(to))
-		}
-		break
-	case javaSystem:
-		if otherLinkType == javaPlatform || otherLinkType == javaModule || otherLinkType == javaSystemServer {
-			ctx.ModuleErrorf("compiles against system API, but dependency %q is compiling against private API."+commonMessage,
-				ctx.OtherModuleName(to))
-		}
-		break
-	case javaModule:
-		if otherLinkType == javaPlatform || otherLinkType == javaSystemServer {
-			ctx.ModuleErrorf("compiles against module API, but dependency %q is compiling against private API."+commonMessage,
-				ctx.OtherModuleName(to))
-		}
-		break
-	case javaSystemServer:
-		if otherLinkType == javaPlatform {
-			ctx.ModuleErrorf("compiles against system server API, but dependency %q is compiling against private API."+commonMessage,
-				ctx.OtherModuleName(to))
-		}
-		break
-	case javaPlatform:
-		// no restriction on link-type
-		break
+	if myLinkType.rank() < otherLinkType.rank() {
+		ctx.ModuleErrorf("compiles against %v, but dependency %q is compiling against %v. "+
+			"In order to fix this, consider adjusting sdk_version: OR platform_apis: "+
+			"property of the source or target module so that target module is built "+
+			"with the same or smaller API set when compared to the source.",
+			myLinkType, ctx.OtherModuleName(to), otherLinkType)
 	}
 }
 
@@ -1116,44 +1147,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
@@ -1163,14 +1192,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)
 					}
@@ -1182,12 +1211,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)
@@ -1198,7 +1226,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
@@ -1803,14 +1831,8 @@
 			return
 		}
 
-		configurationName := j.ConfigurationName()
-		primary := configurationName == ctx.ModuleName()
-		// If the prebuilt is being used rather than the from source, skip this
-		// module to prevent duplicated classes
-		primary = primary && !j.IsReplacedByPrebuilt()
-
 		// Hidden API CSV generation and dex encoding
-		dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, j.implementationJarFile,
+		dexOutputFile = j.hiddenAPIExtractAndEncode(ctx, dexOutputFile, j.implementationJarFile,
 			proptools.Bool(j.dexProperties.Uncompress_dex))
 
 		// merge dex jar with resources if necessary
@@ -1871,6 +1893,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()
 }
@@ -1978,8 +2014,6 @@
 	return instrumentedJar
 }
 
-var _ Dependency = (*Module)(nil)
-
 func (j *Module) HeaderJars() android.Paths {
 	if j.headerJarFile == nil {
 		return nil
@@ -2095,6 +2129,11 @@
 	return proptools.StringDefault(j.deviceProperties.Stem, j.Name())
 }
 
+// ConfigurationName returns the name of the module as used in build configuration.
+//
+// This is usually the same as BaseModuleName() except for the <x>.impl libraries created by
+// java_sdk_library in which case this is the BaseModuleName() without the ".impl" suffix,
+// i.e. just <x>.
 func (j *Module) ConfigurationName() string {
 	return proptools.StringDefault(j.deviceProperties.ConfigurationName, j.BaseModuleName())
 }
@@ -2154,6 +2193,11 @@
 }
 
 func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// Initialize the hiddenapi structure. Pass in the configuration name rather than the module name
+	// so the hidden api will encode the <x>.impl java_ library created by java_sdk_library just as it
+	// would the <x> library if <x> was configured as a boot jar.
+	j.initHiddenAPI(ctx, j.ConfigurationName())
+
 	apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
 	if !apexInfo.IsForPlatform() {
 		j.hideApexVariantFromMake = true
@@ -2687,9 +2731,10 @@
 }
 
 func (j *Binary) DepsMutator(ctx android.BottomUpMutatorContext) {
-	if ctx.Arch().ArchType == android.Common {
+	if ctx.Arch().ArchType == android.Common || ctx.BazelConversionMode() {
 		j.deps(ctx)
-	} else {
+	}
+	if ctx.Arch().ArchType != android.Common || ctx.BazelConversionMode() {
 		// These dependencies ensure the host installation rules will install the jar file and
 		// the jni libraries when the wrapper is installed.
 		ctx.AddVariationDependencies(nil, jniInstallTag, j.binaryProperties.Jni_libs...)
@@ -2853,6 +2898,9 @@
 }
 
 func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	// Initialize the hiddenapi structure.
+	j.initHiddenAPI(ctx, j.BaseModuleName())
+
 	if !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() {
 		j.hideApexVariantFromMake = true
 	}
@@ -2877,15 +2925,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())...)
@@ -2921,8 +2969,10 @@
 
 			// Get the path of the dex implementation jar from the `deapexer` module.
 			di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo)
-			j.dexJarFile = di.PrebuiltExportPath(j.BaseModuleName(), ".dexjar")
-			if j.dexJarFile == nil {
+			if dexOutputPath := di.PrebuiltExportPath(j.BaseModuleName(), ".dexjar"); dexOutputPath != nil {
+				j.dexJarFile = dexOutputPath
+				j.hiddenAPIExtractInformation(ctx, dexOutputPath, outputFile)
+			} else {
 				// This should never happen as a variant for a prebuilt_apex is only created if the
 				// prebuilt_apex has been configured to export the java library dex file.
 				ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt_apex %q", deapexerModule.Name())
@@ -2952,16 +3002,20 @@
 				return
 			}
 
-			configurationName := j.BaseModuleName()
-			primary := j.Prebuilt().UsePrebuilt()
-
 			// Hidden API CSV generation and dex encoding
-			dexOutputFile = j.hiddenAPI.hiddenAPI(ctx, configurationName, primary, dexOutputFile, outputFile,
+			dexOutputFile = j.hiddenAPIExtractAndEncode(ctx, dexOutputFile, outputFile,
 				proptools.Bool(j.dexProperties.Uncompress_dex))
 
 			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) {
@@ -2975,8 +3029,6 @@
 
 var _ android.OutputFileProducer = (*Import)(nil)
 
-var _ Dependency = (*Import)(nil)
-
 func (j *Import) HeaderJars() android.Paths {
 	if j.combinedClasspathFile == nil {
 		return nil
@@ -3322,6 +3374,7 @@
 		&android.ApexProperties{},
 		&RuntimeResourceOverlayProperties{},
 		&LintProperties{},
+		&appTestHelperAppProperties{},
 	)
 
 	android.InitDefaultsModule(module)
diff --git a/java/java_test.go b/java/java_test.go
index e7776c3..0ef4db6 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -127,7 +127,6 @@
 	}
 
 	t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
-
 	return ctx, config
 }
 
@@ -1179,6 +1178,110 @@
 	}
 }
 
+func TestJavaLint(t *testing.T) {
+	ctx, _ := testJavaWithFS(t, `
+		java_library {
+			name: "foo",
+			srcs: [
+				"a.java",
+				"b.java",
+				"c.java",
+			],
+			min_sdk_version: "29",
+			sdk_version: "system_current",
+		}
+       `, map[string][]byte{
+		"lint-baseline.xml": nil,
+	})
+
+	foo := ctx.ModuleForTests("foo", "android_common")
+	rule := foo.Rule("lint")
+
+	if !strings.Contains(rule.RuleParams.Command, "--baseline lint-baseline.xml") {
+		t.Error("did not pass --baseline flag")
+	}
+}
+
+func TestJavaLintWithoutBaseline(t *testing.T) {
+	ctx, _ := testJavaWithFS(t, `
+		java_library {
+			name: "foo",
+			srcs: [
+				"a.java",
+				"b.java",
+				"c.java",
+			],
+			min_sdk_version: "29",
+			sdk_version: "system_current",
+		}
+       `, map[string][]byte{})
+
+	foo := ctx.ModuleForTests("foo", "android_common")
+	rule := foo.Rule("lint")
+
+	if strings.Contains(rule.RuleParams.Command, "--baseline") {
+		t.Error("passed --baseline flag for non existent file")
+	}
+}
+
+func TestJavaLintRequiresCustomLintFileToExist(t *testing.T) {
+	config := testConfig(
+		nil,
+		`
+		java_library {
+			name: "foo",
+			srcs: [
+			],
+			min_sdk_version: "29",
+			sdk_version: "system_current",
+			lint: {
+				baseline_filename: "mybaseline.xml",
+			},
+		}
+     `, map[string][]byte{
+			"build/soong/java/lint_defaults.txt":                   nil,
+			"prebuilts/cmdline-tools/tools/bin/lint":               nil,
+			"prebuilts/cmdline-tools/tools/lib/lint-classpath.jar": nil,
+			"framework/aidl":                     nil,
+			"a.java":                             nil,
+			"AndroidManifest.xml":                nil,
+			"build/make/target/product/security": nil,
+		})
+	config.TestAllowNonExistentPaths = false
+	testJavaErrorWithConfig(t,
+		"source path \"mybaseline.xml\" does not exist",
+		config,
+	)
+}
+
+func TestJavaLintUsesCorrectBpConfig(t *testing.T) {
+	ctx, _ := testJavaWithFS(t, `
+		java_library {
+			name: "foo",
+			srcs: [
+				"a.java",
+				"b.java",
+				"c.java",
+			],
+			min_sdk_version: "29",
+			sdk_version: "system_current",
+			lint: {
+				error_checks: ["SomeCheck"],
+				baseline_filename: "mybaseline.xml",
+			},
+		}
+       `, map[string][]byte{
+		"mybaseline.xml": nil,
+	})
+
+	foo := ctx.ModuleForTests("foo", "android_common")
+	rule := foo.Rule("lint")
+
+	if !strings.Contains(rule.RuleParams.Command, "--baseline mybaseline.xml") {
+		t.Error("did not use the correct file for baseline")
+	}
+}
+
 func TestGeneratedSources(t *testing.T) {
 	ctx, _ := testJavaWithFS(t, `
 		java_library {
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..8272595 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -19,6 +19,8 @@
 	"sort"
 	"strings"
 
+	"github.com/google/blueprint/proptools"
+
 	"android/soong/android"
 )
 
@@ -46,6 +48,9 @@
 
 		// Modules that provide extra lint checks
 		Extra_check_modules []string
+
+		// Name of the file that lint uses as the baseline. Defaults to "lint-baseline.xml".
+		Baseline_filename *string
 	}
 }
 
@@ -276,8 +281,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))
@@ -343,6 +349,19 @@
 		cmd.FlagWithArg("--check ", checkOnly)
 	}
 
+	if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
+		var lintBaseline android.OptionalPath
+		if String(l.properties.Lint.Baseline_filename) != "" {
+			// if manually specified, we require the file to exist
+			lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
+		} else {
+			lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
+		}
+		if lintBaseline.Valid() {
+			cmd.FlagWithInput("--baseline ", lintBaseline.Path())
+		}
+	}
+
 	cmd.Text("|| (").Text("cat").Input(text).Text("; exit 7)").Text(")")
 
 	rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String())
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/proto.go b/java/proto.go
index dc5519f..652a4da 100644
--- a/java/proto.go
+++ b/java/proto.go
@@ -82,7 +82,7 @@
 		case "lite", "":
 			ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-lite")
 		case "full":
-			if ctx.Host() {
+			if ctx.Host() || ctx.BazelConversionMode() {
 				ctx.AddVariationDependencies(nil, staticLibTag, "libprotobuf-java-full")
 			} else {
 				ctx.PropertyErrorf("proto.type", "full java protos only supported on the host")
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/java/testing.go b/java/testing.go
index 5fcf84c..781106f 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -18,6 +18,7 @@
 	"fmt"
 	"reflect"
 	"sort"
+	"strings"
 	"testing"
 
 	"android/soong/android"
@@ -237,3 +238,11 @@
 		t.Errorf("expected %#q, found %#q", expected, actual)
 	}
 }
+
+func CheckHiddenAPIRuleInputs(t *testing.T, expected string, hiddenAPIRule android.TestingBuildParams) {
+	actual := strings.TrimSpace(strings.Join(android.NormalizePathsForTesting(hiddenAPIRule.Implicits), "\n"))
+	expected = strings.TrimSpace(expected)
+	if actual != expected {
+		t.Errorf("Expected hiddenapi rule inputs:\n%s\nactual inputs:\n%s", expected, actual)
+	}
+}
diff --git a/kernel/Android.bp b/kernel/Android.bp
index f8a48d9..91e7490 100644
--- a/kernel/Android.bp
+++ b/kernel/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-kernel",
     pkgPath: "android/soong/kernel",
diff --git a/kernel/prebuilt_kernel_modules.go b/kernel/prebuilt_kernel_modules.go
index 94e04cb..14ac021 100644
--- a/kernel/prebuilt_kernel_modules.go
+++ b/kernel/prebuilt_kernel_modules.go
@@ -72,7 +72,7 @@
 	depmodOut := runDepmod(ctx, modules)
 	strippedModules := stripDebugSymbols(ctx, modules)
 
-	installDir := android.PathForModuleInstall(ctx, "lib", "module")
+	installDir := android.PathForModuleInstall(ctx, "lib", "modules")
 	if pkm.KernelVersion() != "" {
 		installDir = installDir.Join(ctx, pkm.KernelVersion())
 	}
diff --git a/kernel/prebuilt_kernel_modules_test.go b/kernel/prebuilt_kernel_modules_test.go
index b49e167..433548b 100644
--- a/kernel/prebuilt_kernel_modules_test.go
+++ b/kernel/prebuilt_kernel_modules_test.go
@@ -84,12 +84,12 @@
 		})
 
 	expected := []string{
-		"lib/module/5.10/mod1.ko",
-		"lib/module/5.10/mod2.ko",
-		"lib/module/5.10/modules.load",
-		"lib/module/5.10/modules.dep",
-		"lib/module/5.10/modules.softdep",
-		"lib/module/5.10/modules.alias",
+		"lib/modules/5.10/mod1.ko",
+		"lib/modules/5.10/mod2.ko",
+		"lib/modules/5.10/modules.load",
+		"lib/modules/5.10/modules.dep",
+		"lib/modules/5.10/modules.softdep",
+		"lib/modules/5.10/modules.alias",
 	}
 
 	var actual []string
diff --git a/licenses/Android.bp b/licenses/Android.bp
index f4a76d7..c70d6bd 100644
--- a/licenses/Android.bp
+++ b/licenses/Android.bp
@@ -307,10 +307,7 @@
 
 license_kind {
     name: "SPDX-license-identifier-Beerware",
-    conditions: [
-        "by_exception_only",
-        "not_allowed",
-    ],
+    conditions: ["notice"],
     url: "https://spdx.org/licenses/Beerware.html",
 }
 
@@ -1137,10 +1134,7 @@
 
 license_kind {
     name: "SPDX-license-identifier-WTFPL",
-    conditions: [
-        "by_exception_only",
-        "not_allowed",
-    ],
+    conditions: ["notice"],
     url: "https://spdx.org/licenses/WTFPL.html",
 }
 
diff --git a/linkerconfig/Android.bp b/linkerconfig/Android.bp
index 8807a2e..9161f0e 100644
--- a/linkerconfig/Android.bp
+++ b/linkerconfig/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-linkerconfig",
     pkgPath: "android/soong/linkerconfig",
diff --git a/linkerconfig/proto/Android.bp b/linkerconfig/proto/Android.bp
index 4d97128..3b1e4ab 100644
--- a/linkerconfig/proto/Android.bp
+++ b/linkerconfig/proto/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 cc_library_static {
     name: "lib_linker_config_proto_lite",
     host_supported: true,
diff --git a/makedeps/Android.bp b/makedeps/Android.bp
index b77b08f..62bdfd5 100644
--- a/makedeps/Android.bp
+++ b/makedeps/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-makedeps",
     pkgPath: "android/soong/makedeps",
diff --git a/partner/Android.bp b/partner/Android.bp
index f2ced8d..7fc873e 100644
--- a/partner/Android.bp
+++ b/partner/Android.bp
@@ -16,6 +16,10 @@
 // Sample project for creating an extended androidmk
 //
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "partner_androidmk",
     srcs: [
diff --git a/phony/Android.bp b/phony/Android.bp
index 2c423ef..db5efc9 100644
--- a/phony/Android.bp
+++ b/phony/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-phony",
     pkgPath: "android/soong/phony",
diff --git a/python/Android.bp b/python/Android.bp
index ffd03fe..b633f1e 100644
--- a/python/Android.bp
+++ b/python/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-python",
     pkgPath: "android/soong/python",
diff --git a/python/tests/Android.bp b/python/tests/Android.bp
index c8bf420..0e8eef6 100644
--- a/python/tests/Android.bp
+++ b/python/tests/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 python_test_host {
     name: "par_test",
     main: "par_test.py",
diff --git a/remoteexec/Android.bp b/remoteexec/Android.bp
index fc2c0e3..9f75df5 100644
--- a/remoteexec/Android.bp
+++ b/remoteexec/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-remoteexec",
     pkgPath: "android/soong/remoteexec",
diff --git a/rust/Android.bp b/rust/Android.bp
index ad3040a..a29c474 100644
--- a/rust/Android.bp
+++ b/rust/Android.bp
@@ -1,9 +1,14 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-rust",
     pkgPath: "android/soong/rust",
     deps: [
         "soong",
         "soong-android",
+        "soong-bloaty",
         "soong-cc",
         "soong-rust-config",
     ],
diff --git a/rust/binary.go b/rust/binary.go
index 2963a37..df48916 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -119,6 +119,7 @@
 	outputFile := android.PathForModuleOut(ctx, fileName)
 
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
+	flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
 	flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
 
 	TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
@@ -132,7 +133,7 @@
 	return outputFile
 }
 
-func (binary *binaryDecorator) autoDep(ctx BaseModuleContext) autoDep {
+func (binary *binaryDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep {
 	// Binaries default to dylib dependencies for device, rlib for host.
 	if binary.preferRlib() {
 		return rlibAutoDep
diff --git a/rust/builder.go b/rust/builder.go
index 56fe031..547d705 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -21,6 +21,7 @@
 	"github.com/google/blueprint"
 
 	"android/soong/android"
+	"android/soong/bloaty"
 	"android/soong/rust/config"
 )
 
@@ -249,6 +250,8 @@
 		implicits = append(implicits, clippyFile)
 	}
 
+	bloaty.MeasureSizeForPath(ctx, outputFile)
+
 	ctx.Build(pctx, android.BuildParams{
 		Rule:            rustc,
 		Description:     "rustc " + main.Rel(),
diff --git a/rust/compiler.go b/rust/compiler.go
index c921824..c26f208 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -96,7 +96,11 @@
 	// list of C shared library dependencies
 	Shared_libs []string `android:"arch_variant"`
 
-	// list of C static library dependencies
+	// list of C static library dependencies. Note, static libraries prefixed by "lib" will be passed to rustc
+	// along with "-lstatic=<name>". This will bundle the static library into rlib/static libraries so dependents do
+	// not need to also declare the static library as a dependency. Static libraries which are not prefixed by "lib"
+	// cannot be passed to rustc with this flag and will not be bundled into rlib/static libraries, and thus must
+	// be redeclared in dependents.
 	Static_libs []string `android:"arch_variant"`
 
 	// crate name, required for modules which produce Rust libraries: rust_library, rust_ffi and SourceProvider
@@ -228,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
 }
 
@@ -250,7 +258,7 @@
 	if !Bool(compiler.Properties.No_stdlibs) {
 		for _, stdlib := range config.Stdlibs {
 			// If we're building for the primary arch of the build host, use the compiler's stdlibs
-			if ctx.Target().Os == android.BuildOs && ctx.TargetPrimary() {
+			if ctx.Target().Os == android.BuildOs {
 				stdlib = stdlib + "_" + ctx.toolchain().RustTriple()
 			}
 
diff --git a/rust/config/Android.bp b/rust/config/Android.bp
index 1f0109f..5b121c3 100644
--- a/rust/config/Android.bp
+++ b/rust/config/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-rust-config",
     pkgPath: "android/soong/rust/config",
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/fuzz.go b/rust/fuzz.go
index da8f209..6035e68 100644
--- a/rust/fuzz.go
+++ b/rust/fuzz.go
@@ -91,6 +91,6 @@
 	return RlibLinkage
 }
 
-func (fuzzer *fuzzDecorator) autoDep(ctx BaseModuleContext) autoDep {
+func (fuzzer *fuzzDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep {
 	return rlibAutoDep
 }
diff --git a/rust/image.go b/rust/image.go
index 5ff10ae..628aca3 100644
--- a/rust/image.go
+++ b/rust/image.go
@@ -24,7 +24,7 @@
 var _ android.ImageInterface = (*Module)(nil)
 
 func (mod *Module) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
-	return false
+	return mod.Properties.VendorRamdiskVariantNeeded
 }
 
 func (mod *Module) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
@@ -52,6 +52,10 @@
 	return false
 }
 
+func (mod *Module) InVendorRamdisk() bool {
+	return mod.ModuleBase.InVendorRamdisk() || mod.ModuleBase.InstallInVendorRamdisk()
+}
+
 func (mod *Module) OnlyInRamdisk() bool {
 	// TODO(b/165791368)
 	return false
@@ -71,13 +75,24 @@
 	return Bool(mod.VendorProperties.Vendor_available) || Bool(mod.VendorProperties.Odm_available)
 }
 
+// Always returns false because rust modules do not support product variant.
+func (mod *Module) HasProductVariant() bool {
+	return Bool(mod.VendorProperties.Product_available)
+}
+
+func (mod *Module) HasNonSystemVariants() bool {
+	return mod.HasVendorVariant() || mod.HasProductVariant()
+}
+
 func (c *Module) InProduct() bool {
 	return false
 }
 
 func (mod *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
 	m := module.(*Module)
-	if strings.HasPrefix(variant, cc.VendorVariationPrefix) {
+	if variant == android.VendorRamdiskVariation {
+		m.MakeAsPlatform()
+	} else if strings.HasPrefix(variant, cc.VendorVariationPrefix) {
 		m.Properties.ImageVariationPrefix = cc.VendorVariationPrefix
 		m.Properties.VndkVersion = strings.TrimPrefix(variant, cc.VendorVariationPrefix)
 
@@ -108,6 +123,8 @@
 	}
 
 	coreVariantNeeded := true
+	vendorRamdiskVariantNeeded := false
+
 	var vendorVariants []string
 
 	if mod.HasVendorVariant() {
@@ -129,15 +146,23 @@
 			// We can't check shared() here because image mutator is called before the library mutator, so we need to
 			// check buildShared()
 			if lib.buildShared() {
-				mctx.PropertyErrorf(prop, "can only be set for rust_ffi_static modules.")
+				mctx.PropertyErrorf(prop, "cannot be set for rust_ffi or rust_ffi_shared modules.")
 			} else {
 				vendorVariants = append(vendorVariants, platformVndkVersion)
 			}
 		}
 	}
 
+	if Bool(mod.Properties.Vendor_ramdisk_available) {
+		if lib, ok := mod.compiler.(libraryInterface); !ok || (ok && lib.buildShared()) {
+			mctx.PropertyErrorf("vendor_ramdisk_available", "cannot be set for rust_ffi or rust_ffi_shared modules.")
+		} else {
+			vendorRamdiskVariantNeeded = true
+		}
+	}
+
 	if vendorSpecific {
-		if lib, ok := mod.compiler.(libraryInterface); !ok || (ok && !lib.static()) {
+		if lib, ok := mod.compiler.(libraryInterface); !ok || (ok && (lib.buildShared() || lib.buildDylib() || lib.buildRlib())) {
 			mctx.ModuleErrorf("Rust vendor specific modules are currently only supported for rust_ffi_static modules.")
 		} else {
 			coreVariantNeeded = false
@@ -146,6 +171,8 @@
 	}
 
 	mod.Properties.CoreVariantNeeded = coreVariantNeeded
+	mod.Properties.VendorRamdiskVariantNeeded = vendorRamdiskVariantNeeded
+
 	for _, variant := range android.FirstUniqueStrings(vendorVariants) {
 		mod.Properties.ExtraVariants = append(mod.Properties.ExtraVariants, cc.VendorVariationPrefix+variant)
 	}
diff --git a/rust/image_test.go b/rust/image_test.go
index fd71962..e40599c 100644
--- a/rust/image_test.go
+++ b/rust/image_test.go
@@ -15,15 +15,16 @@
 package rust
 
 import (
+	"strings"
 	"testing"
 
 	"android/soong/android"
 	"android/soong/cc"
 )
 
-// Test that cc_binaries can link against rust_ffi_static libraries.
+// 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,58 @@
 			}
 		`)
 
-	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 := testRustVndk(t, `
+			cc_library_static {
+				name: "libcc_vendor_ramdisk",
+				static_libs: ["libfoo_vendor_ramdisk"],
+				system_shared_libs: [],
+				vendor_ramdisk_available: true,
+			}
+			rust_ffi_static {
+				name: "libfoo_vendor_ramdisk",
+				crate_name: "foo",
+				srcs: ["foo.rs"],
+				vendor_ramdisk_available: true,
+			}
+		`)
+
+	vendorRamdiskLibrary := ctx.ModuleForTests("libcc_vendor_ramdisk", "android_vendor_ramdisk_arm64_armv8-a_static").Module().(*cc.Module)
+
+	if !android.InList("libfoo_vendor_ramdisk.vendor_ramdisk", vendorRamdiskLibrary.Properties.AndroidMkStaticLibs) {
+		t.Errorf("libcc_vendor_ramdisk should have a dependency on libfoo_vendor_ramdisk")
+	}
+}
+
 // Test that shared libraries cannot be made vendor available until proper support is added.
 func TestForbiddenVendorLinkage(t *testing.T) {
-	testRustError(t, "can only be set for rust_ffi_static modules", `
+	testRustError(t, "cannot be set for rust_ffi or rust_ffi_shared modules.", `
 		rust_ffi_shared {
 			name: "libfoo_vendor",
 			crate_name: "foo",
@@ -54,6 +97,14 @@
 			vendor_available: true,
 		}
 	`)
+	testRustError(t, "cannot be set for rust_ffi or rust_ffi_shared modules.", `
+		rust_ffi_shared {
+			name: "libfoo_vendor",
+			crate_name: "foo",
+			srcs: ["foo.rs"],
+			vendor_ramdisk_available: true,
+		}
+	`)
 	testRustError(t, "Rust vendor specific modules are currently only supported for rust_ffi_static modules.", `
 		rust_ffi {
 			name: "libfoo_vendor",
@@ -70,4 +121,13 @@
 			vendor: true,
 		}
 	`)
+	testRustError(t, "Rust vendor specific modules are currently only supported for rust_ffi_static modules.", `
+		rust_binary {
+			name: "foo_vendor",
+			crate_name: "foo",
+			srcs: ["foo.rs"],
+			vendor: true,
+		}
+	`)
+
 }
diff --git a/rust/library.go b/rust/library.go
index 6433285..7ff13ec 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -219,13 +219,17 @@
 	library.MutatedProperties.VariantIsSource = true
 }
 
-func (library *libraryDecorator) autoDep(ctx BaseModuleContext) autoDep {
+func (library *libraryDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep {
 	if library.preferRlib() {
 		return rlibAutoDep
 	} else if library.rlib() || library.static() {
 		return rlibAutoDep
 	} else if library.dylib() || library.shared() {
 		return dylibAutoDep
+	} else if ctx.BazelConversionMode() {
+		// In Bazel conversion mode, we are currently ignoring the deptag, so we just need to supply a
+		// compatible tag in order to add the dependency.
+		return rlibAutoDep
 	} else {
 		panic(fmt.Errorf("autoDep called on library %q that has no enabled variants.", ctx.ModuleName()))
 	}
@@ -439,6 +443,7 @@
 	}
 
 	flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
+	flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...)
 	flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
 
 	if library.dylib() {
@@ -478,7 +483,6 @@
 
 	if library.rlib() || library.dylib() {
 		library.flagExporter.exportLinkDirs(deps.linkDirs...)
-		library.flagExporter.exportDepFlags(deps.depFlags...)
 		library.flagExporter.exportLinkObjects(deps.linkObjects...)
 	}
 
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index f753e7f..115045a 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -79,6 +79,6 @@
 	return stem + String(procMacro.baseCompiler.Properties.Suffix)
 }
 
-func (procMacro *procMacroDecorator) autoDep(ctx BaseModuleContext) autoDep {
+func (procMacro *procMacroDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep {
 	return rlibAutoDep
 }
diff --git a/rust/rust.go b/rust/rust.go
index 2ef9daf..dc23abb 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -74,8 +74,16 @@
 	SubName              string `blueprint:"mutated"`
 
 	// Set by imageMutator
-	CoreVariantNeeded bool     `blueprint:"mutated"`
-	ExtraVariants     []string `blueprint:"mutated"`
+	CoreVariantNeeded          bool     `blueprint:"mutated"`
+	VendorRamdiskVariantNeeded bool     `blueprint:"mutated"`
+	ExtraVariants              []string `blueprint:"mutated"`
+
+	// Make this module available when building for vendor ramdisk.
+	// On device without a dedicated recovery partition, the module is only
+	// available after switching root into
+	// /first_stage_ramdisk. To expose the module before switching root, install
+	// the recovery variant instead (TODO(b/165791368) recovery not yet supported)
+	Vendor_ramdisk_available *bool
 
 	// Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX).
 	Min_sdk_version *string
@@ -280,10 +288,15 @@
 	SharedLibDeps android.Paths
 	StaticLibs    android.Paths
 	ProcMacros    RustLibraries
-	linkDirs      []string
-	depFlags      []string
-	linkObjects   []string
-	//ReexportedDeps android.Paths
+
+	// depFlags and depLinkFlags are rustc and linker (clang) flags.
+	depFlags     []string
+	depLinkFlags []string
+
+	// linkDirs are link paths passed via -L to rustc. linkObjects are objects passed directly to the linker.
+	// Both of these are exported and propagate to dependencies.
+	linkDirs    []string
+	linkObjects []string
 
 	// Used by bindgen modules which call clang
 	depClangFlags         []string
@@ -328,12 +341,10 @@
 
 type exportedFlagsProducer interface {
 	exportLinkDirs(...string)
-	exportDepFlags(...string)
 	exportLinkObjects(...string)
 }
 
 type flagExporter struct {
-	depFlags    []string
 	linkDirs    []string
 	linkObjects []string
 }
@@ -342,17 +353,12 @@
 	flagExporter.linkDirs = android.FirstUniqueStrings(append(flagExporter.linkDirs, dirs...))
 }
 
-func (flagExporter *flagExporter) exportDepFlags(flags ...string) {
-	flagExporter.depFlags = android.FirstUniqueStrings(append(flagExporter.depFlags, flags...))
-}
-
 func (flagExporter *flagExporter) exportLinkObjects(flags ...string) {
 	flagExporter.linkObjects = android.FirstUniqueStrings(append(flagExporter.linkObjects, flags...))
 }
 
 func (flagExporter *flagExporter) setProvider(ctx ModuleContext) {
 	ctx.SetProvider(FlagExporterInfoProvider, FlagExporterInfo{
-		Flags:       flagExporter.depFlags,
 		LinkDirs:    flagExporter.linkDirs,
 		LinkObjects: flagExporter.linkObjects,
 	})
@@ -660,7 +666,9 @@
 
 	// Differentiate static libraries that are vendor available
 	if mod.UseVndk() {
-		mod.Properties.SubName += ".vendor"
+		mod.Properties.SubName += cc.VendorSuffix
+	} else if mod.InVendorRamdisk() && !mod.OnlyInVendorRamdisk() {
+		mod.Properties.SubName += cc.VendorRamdiskSuffix
 	}
 
 	if !toolchain.Supported() {
@@ -785,7 +793,7 @@
 )
 
 type autoDeppable interface {
-	autoDep(ctx BaseModuleContext) autoDep
+	autoDep(ctx android.BottomUpMutatorContext) autoDep
 }
 
 func (mod *Module) begin(ctx BaseModuleContext) {
@@ -898,8 +906,24 @@
 			exportDep := false
 			switch {
 			case cc.IsStaticDepTag(depTag):
-				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
+				// Only pass -lstatic for rlibs as it results in dylib bloat.
+				if lib, ok := ctx.Module().(*Module).compiler.(libraryInterface); ok && lib.rlib() {
+					// Link cc static libraries using "-lstatic" so rustc can reason about how to handle these
+					// (for example, bundling them into rlibs).
+					//
+					// rustc does not support linking libraries with the "-l" flag unless they are prefixed by "lib".
+					// If we need to link a library that isn't prefixed by "lib", we'll just link to it directly through
+					// linkObjects; such a library may need to be redeclared by static dependents.
+					if libName, ok := libNameFromFilePath(linkObject.Path()); ok {
+						depPaths.depFlags = append(depPaths.depFlags, "-lstatic="+libName)
+					}
+				}
+
+				// Add this to linkObjects to pass the library directly to the linker as well. This propagates
+				// to dependencies to avoid having to redeclare static libraries for dependents of the dylib variant.
 				depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String())
+				depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
+
 				exportedInfo := ctx.OtherModuleProvider(dep, cc.FlagExporterInfoProvider).(cc.FlagExporterInfo)
 				depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...)
 				depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, exportedInfo.SystemIncludeDirs...)
@@ -1213,6 +1237,16 @@
 	return false
 }
 
+// If a library file has a "lib" prefix, extract the library name without the prefix.
+func libNameFromFilePath(filepath android.Path) (string, bool) {
+	libName := strings.TrimSuffix(filepath.Base(), filepath.Ext())
+	if strings.HasPrefix(libName, "lib") {
+		libName = libName[3:]
+		return libName, true
+	}
+	return "", false
+}
+
 var Bool = proptools.Bool
 var BoolDefault = proptools.BoolDefault
 var String = proptools.String
diff --git a/rust/rust_test.go b/rust/rust_test.go
index abc9af9..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.
@@ -213,6 +230,7 @@
 			name: "librlib",
 			srcs: ["foo.rs"],
 			crate_name: "rlib",
+			static_libs: ["libstatic"],
 		}
 		rust_proc_macro {
 			name: "libpm",
@@ -230,6 +248,7 @@
 		}
 	`)
 	module := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
+	rustc := ctx.ModuleForTests("librlib", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc")
 
 	// Since dependencies are added to AndroidMk* properties, we can check these to see if they've been picked up.
 	if !android.InList("libdylib", module.Properties.AndroidMkDylibs) {
@@ -251,6 +270,11 @@
 	if !android.InList("libstatic", module.Properties.AndroidMkStaticLibs) {
 		t.Errorf("Static library dependency not detected (dependency missing from AndroidMkStaticLibs)")
 	}
+
+	if !strings.Contains(rustc.Args["rustcFlags"], "-lstatic=static") {
+		t.Errorf("-lstatic flag not being passed to rustc for static library")
+	}
+
 }
 
 func TestSourceProviderDeps(t *testing.T) {
diff --git a/rust/test.go b/rust/test.go
index 92b4860..6caa7b1 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -15,6 +15,8 @@
 package rust
 
 import (
+	"github.com/google/blueprint/proptools"
+
 	"android/soong/android"
 	"android/soong/tradefed"
 )
@@ -127,6 +129,9 @@
 		ctx.PropertyErrorf("no_named_install_directory", "Module install directory may only be disabled if relative_install_path is set")
 	}
 
+	if ctx.Host() && test.Properties.Test_options.Unit_test == nil {
+		test.Properties.Test_options.Unit_test = proptools.BoolPtr(true)
+	}
 	test.binaryDecorator.install(ctx)
 }
 
@@ -141,7 +146,7 @@
 	return flags
 }
 
-func (test *testDecorator) autoDep(ctx BaseModuleContext) autoDep {
+func (test *testDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep {
 	return rlibAutoDep
 }
 
diff --git a/rust/testing.go b/rust/testing.go
index bb511b6..1afe27e 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -46,6 +46,30 @@
 				sysroot: true,
 		}
 		rust_prebuilt_library {
+				name: "libstd_i686-unknown-linux-gnu",
+                                crate_name: "std",
+                                rlib: {
+                                    srcs: ["libstd.rlib"],
+                                },
+                                dylib: {
+                                    srcs: ["libstd.so"],
+                                },
+				host_supported: true,
+				sysroot: true,
+		}
+		rust_prebuilt_library {
+				name: "libtest_i686-unknown-linux-gnu",
+                                crate_name: "test",
+                                rlib: {
+                                    srcs: ["libtest.rlib"],
+                                },
+                                dylib: {
+                                    srcs: ["libtest.so"],
+                                },
+				host_supported: true,
+				sysroot: true,
+		}
+		rust_prebuilt_library {
 				name: "libstd_x86_64-apple-darwin",
                                 crate_name: "std",
                                 rlib: {
@@ -101,6 +125,7 @@
 			no_stdlibs: true,
 			host_supported: true,
 			vendor_available: true,
+			vendor_ramdisk_available: true,
                         native_coverage: false,
 			sysroot: true,
 			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
@@ -113,6 +138,7 @@
 			no_stdlibs: true,
 			host_supported: true,
 			vendor_available: true,
+			vendor_ramdisk_available: true,
                         native_coverage: false,
 			sysroot: true,
 			apex_available: ["//apex_available:platform", "//apex_available:anyapex"],
diff --git a/scripts/Android.bp b/scripts/Android.bp
index dd03f28..310c959 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 python_binary_host {
     name: "check_boot_jars",
     main: "check_boot_jars/check_boot_jars.py",
@@ -205,13 +209,18 @@
     test_suites: ["general-tests"],
 }
 
+python_library_host {
+    name: "ninja_rsp",
+    srcs: ["ninja_rsp.py"],
+}
+
 python_binary_host {
     name: "lint-project-xml",
     main: "lint-project-xml.py",
     srcs: [
         "lint-project-xml.py",
-        "ninja_rsp.py",
     ],
+    libs: ["ninja_rsp"],
 }
 
 python_binary_host {
@@ -219,8 +228,8 @@
     main: "gen-kotlin-build-file.py",
     srcs: [
         "gen-kotlin-build-file.py",
-        "ninja_rsp.py",
     ],
+    libs: ["ninja_rsp"],
 }
 
 python_binary_host {
diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh
index b8485ea..b93c883 100755
--- a/scripts/build-mainline-modules.sh
+++ b/scripts/build-mainline-modules.sh
@@ -8,6 +8,7 @@
   com.android.art.testing
   com.android.conscrypt
   com.android.i18n
+  com.android.os.statsd
   com.android.runtime
   com.android.tzdata
 )
@@ -26,6 +27,8 @@
   platform-mainline-test-exports
   runtime-module-host-exports
   runtime-module-sdk
+  stats-log-api-gen-exports
+  statsd-module-sdk
   tzdata-module-test-exports
 )
 
diff --git a/scripts/check_do_not_merge.sh b/scripts/check_do_not_merge.sh
new file mode 100755
index 0000000..ad6a0a9
--- /dev/null
+++ b/scripts/check_do_not_merge.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# Copyright (C) 2021 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+if git show -s --format=%s $1 | grep -qE '(DO NOT MERGE)|(RESTRICT AUTOMERGE)'; then
+    cat >&2 <<EOF
+DO NOT MERGE and RESTRICT AUTOMERGE very often lead to unintended results
+and are not allowed to be used in this project.
+Please use the Merged-In tag to be more explicit about where this change
+should merge to. Google-internal documentation exists at go/merged-in
+
+If this check is mis-triggering or you know Merged-In is incorrect in this
+situation you can bypass this check with \`repo upload --no-verify\`.
+EOF
+    exit 1
+fi
diff --git a/scripts/gen_ndk_backedby_apex.sh b/scripts/gen_ndk_backedby_apex.sh
index e0da602..4abaaba 100755
--- a/scripts/gen_ndk_backedby_apex.sh
+++ b/scripts/gen_ndk_backedby_apex.sh
@@ -23,33 +23,50 @@
     echo "**************************** Usage Instructions ****************************"
     echo "This script is used to generate the Mainline modules backed-by NDK symbols."
     echo ""
-    echo "To run this script use: ./ndk_backedby_module.sh \$BINARY_IMAGE_DIRECTORY \$OUTPUT_FILE_PATH \$NDK_LIB_NAME_LIST"
-    echo "For example: If all the module image files that you would like to run is under directory '/myModule' and output write to /backedby.txt then the command would be:"
-    echo "./ndk_usedby_module.sh /myModule /backedby.txt /ndkLibList.txt"
+    echo "To run this script use: ./gen_ndk_backed_by_apex.sh \$OUTPUT_FILE_PATH \$NDK_LIB_NAME_LIST \$MODULE_LIB1 \$MODULE_LIB2..."
+    echo "For example: If output write to /backedby.txt then the command would be:"
+    echo "./gen_ndk_backed_by_apex.sh /backedby.txt /ndkLibList.txt lib1.so lib2.so"
     echo "If the module1 is backing lib1 then the backedby.txt would contains: "
     echo "lib1"
 }
 
+contains() {
+  val="$1"
+  shift
+  for x in "$@"; do
+    if [ "$x" = "$val" ]; then
+      return 0
+    fi
+  done
+  return 1
+}
+
+
 genBackedByList() {
-  dir="$1"
-  [[ ! -e "$2" ]] && echo "" >> "$2"
+  out="$1"
+  shift
+  ndk_list="$1"
+  shift
+  rm -f "$out"
+  touch "$out"
   while IFS= read -r line
   do
     soFileName=$(echo "$line" | sed 's/\(.*so\).*/\1/')
     if [[ ! -z "$soFileName" && "$soFileName" != *"#"* ]]
     then
-      find "$dir" -type f -name "$soFileName" -exec echo "$soFileName" >> "$2" \;
+      if contains "$soFileName" "$@"; then
+        echo "$soFileName" >> "$out"
+      fi
     fi
-  done < "$3"
+  done < "$ndk_list"
 }
 
 if [[ "$1" == "help" ]]
 then
   printHelp
-elif [[ "$#" -ne 3 ]]
+elif [[ "$#" -lt 2 ]]
 then
-  echo "Wrong argument length. Expecting 3 argument representing image file directory, output path, path to ndk library list."
+  echo "Wrong argument length. Expecting at least 2 argument representing output path, path to ndk library list, followed by a list of libraries in the Mainline module."
 else
-  [[ -e "$2" ]] && rm "$2"
-  genBackedByList "$1" "$2" "$3"
+  genBackedByList "$@"
 fi
diff --git a/scripts/hiddenapi/Android.bp b/scripts/hiddenapi/Android.bp
new file mode 100644
index 0000000..af7e7fe
--- /dev/null
+++ b/scripts/hiddenapi/Android.bp
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+python_binary_host {
+    name: "merge_csv",
+    main: "merge_csv.py",
+    srcs: ["merge_csv.py"],
+    version: {
+        py2: {
+            enabled: false,
+        },
+        py3: {
+            enabled: true,
+            embedded_launcher: true,
+        },
+    },
+}
+
+python_binary_host {
+    name: "generate_hiddenapi_lists",
+    main: "generate_hiddenapi_lists.py",
+    srcs: ["generate_hiddenapi_lists.py"],
+    version: {
+        py2: {
+            enabled: false,
+        },
+        py3: {
+            enabled: true,
+            embedded_launcher: true,
+        },
+    },
+}
diff --git a/scripts/hiddenapi/generate_hiddenapi_lists.py b/scripts/hiddenapi/generate_hiddenapi_lists.py
new file mode 100755
index 0000000..6816475
--- /dev/null
+++ b/scripts/hiddenapi/generate_hiddenapi_lists.py
@@ -0,0 +1,383 @@
+#!/usr/bin/env python
+#
+# 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.
+"""Generate API lists for non-SDK API enforcement."""
+import argparse
+from collections import defaultdict, namedtuple
+import functools
+import os
+import re
+import sys
+
+# Names of flags recognized by the `hiddenapi` tool.
+FLAG_SDK = 'sdk'
+FLAG_UNSUPPORTED = 'unsupported'
+FLAG_BLOCKED = 'blocked'
+FLAG_MAX_TARGET_O = 'max-target-o'
+FLAG_MAX_TARGET_P = 'max-target-p'
+FLAG_MAX_TARGET_Q = 'max-target-q'
+FLAG_MAX_TARGET_R = 'max-target-r'
+FLAG_CORE_PLATFORM_API = 'core-platform-api'
+FLAG_PUBLIC_API = 'public-api'
+FLAG_SYSTEM_API = 'system-api'
+FLAG_TEST_API = 'test-api'
+
+# List of all known flags.
+FLAGS_API_LIST = [
+    FLAG_SDK,
+    FLAG_UNSUPPORTED,
+    FLAG_BLOCKED,
+    FLAG_MAX_TARGET_O,
+    FLAG_MAX_TARGET_P,
+    FLAG_MAX_TARGET_Q,
+    FLAG_MAX_TARGET_R,
+]
+ALL_FLAGS = FLAGS_API_LIST + [
+    FLAG_CORE_PLATFORM_API,
+    FLAG_PUBLIC_API,
+    FLAG_SYSTEM_API,
+    FLAG_TEST_API,
+]
+
+FLAGS_API_LIST_SET = set(FLAGS_API_LIST)
+ALL_FLAGS_SET = set(ALL_FLAGS)
+
+# Option specified after one of FLAGS_API_LIST to indicate that
+# only known and otherwise unassigned entries should be assign the
+# given flag.
+# For example, the max-target-P list is checked in as it was in P,
+# but signatures have changes since then. The flag instructs this
+# script to skip any entries which do not exist any more.
+FLAG_IGNORE_CONFLICTS = "ignore-conflicts"
+
+# Option specified after one of FLAGS_API_LIST to express that all
+# apis within a given set of packages should be assign the given flag.
+FLAG_PACKAGES = "packages"
+
+# Option specified after one of FLAGS_API_LIST to indicate an extra
+# tag that should be added to the matching APIs.
+FLAG_TAG = "tag"
+
+# Regex patterns of fields/methods used in serialization. These are
+# considered public API despite being hidden.
+SERIALIZATION_PATTERNS = [
+    r'readObject\(Ljava/io/ObjectInputStream;\)V',
+    r'readObjectNoData\(\)V',
+    r'readResolve\(\)Ljava/lang/Object;',
+    r'serialVersionUID:J',
+    r'serialPersistentFields:\[Ljava/io/ObjectStreamField;',
+    r'writeObject\(Ljava/io/ObjectOutputStream;\)V',
+    r'writeReplace\(\)Ljava/lang/Object;',
+]
+
+# Single regex used to match serialization API. It combines all the
+# SERIALIZATION_PATTERNS into a single regular expression.
+SERIALIZATION_REGEX = re.compile(r'.*->(' + '|'.join(SERIALIZATION_PATTERNS) + r')$')
+
+# Predicates to be used with filter_apis.
+HAS_NO_API_LIST_ASSIGNED = lambda api, flags: not FLAGS_API_LIST_SET.intersection(flags)
+IS_SERIALIZATION = lambda api, flags: SERIALIZATION_REGEX.match(api)
+
+
+class StoreOrderedOptions(argparse.Action):
+    """An argparse action that stores a number of option arguments in the order that
+    they were specified.
+    """
+    def __call__(self, parser, args, values, option_string = None):
+        items = getattr(args, self.dest, None)
+        if items is None:
+            items = []
+        items.append([option_string.lstrip('-'), values])
+        setattr(args, self.dest, items)
+
+def get_args():
+    """Parses command line arguments.
+
+    Returns:
+        Namespace: dictionary of parsed arguments
+    """
+    parser = argparse.ArgumentParser()
+    parser.add_argument('--output', required=True)
+    parser.add_argument('--csv', nargs='*', default=[], metavar='CSV_FILE',
+        help='CSV files to be merged into output')
+
+    for flag in ALL_FLAGS:
+        parser.add_argument('--' + flag, dest='ordered_flags', metavar='TXT_FILE',
+            action=StoreOrderedOptions, help='lists of entries with flag "' + flag + '"')
+    parser.add_argument('--' + FLAG_IGNORE_CONFLICTS, dest='ordered_flags', nargs=0,
+        action=StoreOrderedOptions, help='Indicates that only known and otherwise unassigned '
+        'entries should be assign the given flag. Must follow a list of entries and applies '
+        'to the preceding such list.')
+    parser.add_argument('--' + FLAG_PACKAGES, dest='ordered_flags', nargs=0,
+        action=StoreOrderedOptions, help='Indicates that the previous list of entries '
+        'is a list of packages. All members in those packages will be given the flag. '
+        'Must follow a list of entries and applies to the preceding such list.')
+    parser.add_argument('--' + FLAG_TAG, dest='ordered_flags', nargs=1,
+        action=StoreOrderedOptions, help='Adds an extra tag to the previous list of entries. '
+        'Must follow a list of entries and applies to the preceding such list.')
+
+    return parser.parse_args()
+
+
+def read_lines(filename):
+    """Reads entire file and return it as a list of lines.
+
+    Lines which begin with a hash are ignored.
+
+    Args:
+        filename (string): Path to the file to read from.
+
+    Returns:
+        Lines of the file as a list of string.
+    """
+    with open(filename, 'r') as f:
+        lines = f.readlines();
+    lines = filter(lambda line: not line.startswith('#'), lines)
+    lines = map(lambda line: line.strip(), lines)
+    return set(lines)
+
+
+def write_lines(filename, lines):
+    """Writes list of lines into a file, overwriting the file if it exists.
+
+    Args:
+        filename (string): Path to the file to be writing into.
+        lines (list): List of strings to write into the file.
+    """
+    lines = map(lambda line: line + '\n', lines)
+    with open(filename, 'w') as f:
+        f.writelines(lines)
+
+
+def extract_package(signature):
+    """Extracts the package from a signature.
+
+    Args:
+        signature (string): JNI signature of a method or field.
+
+    Returns:
+        The package name of the class containing the field/method.
+    """
+    full_class_name = signature.split(";->")[0]
+    # Example: Landroid/hardware/radio/V1_2/IRadio$Proxy
+    if (full_class_name[0] != "L"):
+        raise ValueError("Expected to start with 'L': %s" % full_class_name)
+    full_class_name = full_class_name[1:]
+    # If full_class_name doesn't contain '/', then package_name will be ''.
+    package_name = full_class_name.rpartition("/")[0]
+    return package_name.replace('/', '.')
+
+
+class FlagsDict:
+    def __init__(self):
+        self._dict_keyset = set()
+        self._dict = defaultdict(set)
+
+    def _check_entries_set(self, keys_subset, source):
+        assert isinstance(keys_subset, set)
+        assert keys_subset.issubset(self._dict_keyset), (
+            "Error: {} specifies signatures not present in code:\n"
+            "{}"
+            "Please visit go/hiddenapi for more information.").format(
+                source, "".join(map(lambda x: "  " + str(x) + "\n", keys_subset - self._dict_keyset)))
+
+    def _check_flags_set(self, flags_subset, source):
+        assert isinstance(flags_subset, set)
+        assert flags_subset.issubset(ALL_FLAGS_SET), (
+            "Error processing: {}\n"
+            "The following flags were not recognized: \n"
+            "{}\n"
+            "Please visit go/hiddenapi for more information.").format(
+                source, "\n".join(flags_subset - ALL_FLAGS_SET))
+
+    def filter_apis(self, filter_fn):
+        """Returns APIs which match a given predicate.
+
+        This is a helper function which allows to filter on both signatures (keys) and
+        flags (values). The built-in filter() invokes the lambda only with dict's keys.
+
+        Args:
+            filter_fn : Function which takes two arguments (signature/flags) and returns a boolean.
+
+        Returns:
+            A set of APIs which match the predicate.
+        """
+        return set(filter(lambda x: filter_fn(x, self._dict[x]), self._dict_keyset))
+
+    def get_valid_subset_of_unassigned_apis(self, api_subset):
+        """Sanitizes a key set input to only include keys which exist in the dictionary
+        and have not been assigned any API list flags.
+
+        Args:
+            entries_subset (set/list): Key set to be sanitized.
+
+        Returns:
+            Sanitized key set.
+        """
+        assert isinstance(api_subset, set)
+        return api_subset.intersection(self.filter_apis(HAS_NO_API_LIST_ASSIGNED))
+
+    def generate_csv(self):
+        """Constructs CSV entries from a dictionary.
+
+        Old versions of flags are used to generate the file.
+
+        Returns:
+            List of lines comprising a CSV file. See "parse_and_merge_csv" for format description.
+        """
+        lines = []
+        for api in self._dict:
+          flags = sorted(self._dict[api])
+          lines.append(",".join([api] + flags))
+        return sorted(lines)
+
+    def parse_and_merge_csv(self, csv_lines, source = "<unknown>"):
+        """Parses CSV entries and merges them into a given dictionary.
+
+        The expected CSV format is:
+            <api signature>,<flag1>,<flag2>,...,<flagN>
+
+        Args:
+            csv_lines (list of strings): Lines read from a CSV file.
+            source (string): Origin of `csv_lines`. Will be printed in error messages.
+
+        Throws:
+            AssertionError if parsed flags are invalid.
+        """
+        # Split CSV lines into arrays of values.
+        csv_values = [ line.split(',') for line in csv_lines ]
+
+        # Update the full set of API signatures.
+        self._dict_keyset.update([ csv[0] for csv in csv_values ])
+
+        # Check that all flags are known.
+        csv_flags = set()
+        for csv in csv_values:
+          csv_flags.update(csv[1:])
+        self._check_flags_set(csv_flags, source)
+
+        # Iterate over all CSV lines, find entry in dict and append flags to it.
+        for csv in csv_values:
+            flags = csv[1:]
+            if (FLAG_PUBLIC_API in flags) or (FLAG_SYSTEM_API in flags):
+                flags.append(FLAG_SDK)
+            self._dict[csv[0]].update(flags)
+
+    def assign_flag(self, flag, apis, source="<unknown>", tag = None):
+        """Assigns a flag to given subset of entries.
+
+        Args:
+            flag (string): One of ALL_FLAGS.
+            apis (set): Subset of APIs to receive the flag.
+            source (string): Origin of `entries_subset`. Will be printed in error messages.
+
+        Throws:
+            AssertionError if parsed API signatures of flags are invalid.
+        """
+        # Check that all APIs exist in the dict.
+        self._check_entries_set(apis, source)
+
+        # Check that the flag is known.
+        self._check_flags_set(set([ flag ]), source)
+
+        # Iterate over the API subset, find each entry in dict and assign the flag to it.
+        for api in apis:
+            self._dict[api].add(flag)
+            if tag:
+                self._dict[api].add(tag)
+
+
+FlagFile = namedtuple('FlagFile', ('flag', 'file', 'ignore_conflicts', 'packages', 'tag'))
+
+def parse_ordered_flags(ordered_flags):
+    r = []
+    currentflag, file, ignore_conflicts, packages, tag = None, None, False, False, None
+    for flag_value in ordered_flags:
+        flag, value = flag_value[0], flag_value[1]
+        if flag in ALL_FLAGS_SET:
+            if currentflag:
+                r.append(FlagFile(currentflag, file, ignore_conflicts, packages, tag))
+                ignore_conflicts, packages, tag = False, False, None
+            currentflag = flag
+            file = value
+        else:
+            if currentflag is None:
+                raise argparse.ArgumentError('--%s is only allowed after one of %s' % (
+                    flag, ' '.join(['--%s' % f for f in ALL_FLAGS_SET])))
+            if flag == FLAG_IGNORE_CONFLICTS:
+                ignore_conflicts = True
+            elif flag == FLAG_PACKAGES:
+                packages = True
+            elif flag == FLAG_TAG:
+                tag = value[0]
+
+
+    if currentflag:
+        r.append(FlagFile(currentflag, file, ignore_conflicts, packages, tag))
+    return r
+
+
+def main(argv):
+    # Parse arguments.
+    args = vars(get_args())
+    flagfiles = parse_ordered_flags(args['ordered_flags'])
+
+    # Initialize API->flags dictionary.
+    flags = FlagsDict()
+
+    # Merge input CSV files into the dictionary.
+    # Do this first because CSV files produced by parsing API stubs will
+    # contain the full set of APIs. Subsequent additions from text files
+    # will be able to detect invalid entries, and/or filter all as-yet
+    # unassigned entries.
+    for filename in args["csv"]:
+        flags.parse_and_merge_csv(read_lines(filename), filename)
+
+    # Combine inputs which do not require any particular order.
+    # (1) Assign serialization API to SDK.
+    flags.assign_flag(FLAG_SDK, flags.filter_apis(IS_SERIALIZATION))
+
+    # (2) Merge text files with a known flag into the dictionary.
+    for info in flagfiles:
+        if (not info.ignore_conflicts) and (not info.packages):
+            flags.assign_flag(info.flag, read_lines(info.file), info.file, info.tag)
+
+    # Merge text files where conflicts should be ignored.
+    # This will only assign the given flag if:
+    # (a) the entry exists, and
+    # (b) it has not been assigned any other flag.
+    # Because of (b), this must run after all strict assignments have been performed.
+    for info in flagfiles:
+        if info.ignore_conflicts:
+            valid_entries = flags.get_valid_subset_of_unassigned_apis(read_lines(info.file))
+            flags.assign_flag(info.flag, valid_entries, filename, info.tag)
+
+    # All members in the specified packages will be assigned the appropriate flag.
+    for info in flagfiles:
+        if info.packages:
+            packages_needing_list = set(read_lines(info.file))
+            should_add_signature_to_list = lambda sig,lists: extract_package(
+                sig) in packages_needing_list and not lists
+            valid_entries = flags.filter_apis(should_add_signature_to_list)
+            flags.assign_flag(info.flag, valid_entries, info.file, info.tag)
+
+    # Mark all remaining entries as blocked.
+    flags.assign_flag(FLAG_BLOCKED, flags.filter_apis(HAS_NO_API_LIST_ASSIGNED))
+
+    # Write output.
+    write_lines(args["output"], flags.generate_csv())
+
+if __name__ == "__main__":
+    main(sys.argv)
diff --git a/scripts/hiddenapi/generate_hiddenapi_lists_test.py b/scripts/hiddenapi/generate_hiddenapi_lists_test.py
new file mode 100755
index 0000000..ff3d708
--- /dev/null
+++ b/scripts/hiddenapi/generate_hiddenapi_lists_test.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python
+#
+# 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.
+"""Unit tests for Hidden API list generation."""
+import unittest
+from generate_hiddenapi_lists import *
+
+class TestHiddenapiListGeneration(unittest.TestCase):
+
+    def test_filter_apis(self):
+        # Initialize flags so that A and B are put on the allow list and
+        # C, D, E are left unassigned. Try filtering for the unassigned ones.
+        flags = FlagsDict()
+        flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B,' + FLAG_SDK,
+                        'C', 'D', 'E'])
+        filter_set = flags.filter_apis(lambda api, flags: not flags)
+        self.assertTrue(isinstance(filter_set, set))
+        self.assertEqual(filter_set, set([ 'C', 'D', 'E' ]))
+
+    def test_get_valid_subset_of_unassigned_keys(self):
+        # Create flags where only A is unassigned.
+        flags = FlagsDict()
+        flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B', 'C'])
+        flags.assign_flag(FLAG_UNSUPPORTED, set(['C']))
+        self.assertEqual(flags.generate_csv(),
+            [ 'A,' + FLAG_SDK, 'B', 'C,' + FLAG_UNSUPPORTED ])
+
+        # Check three things:
+        # (1) B is selected as valid unassigned
+        # (2) A is not selected because it is assigned to the allow list
+        # (3) D is not selected because it is not a valid key
+        self.assertEqual(
+            flags.get_valid_subset_of_unassigned_apis(set(['A', 'B', 'D'])), set([ 'B' ]))
+
+    def test_parse_and_merge_csv(self):
+        flags = FlagsDict()
+
+        # Test empty CSV entry.
+        self.assertEqual(flags.generate_csv(), [])
+
+        # Test new additions.
+        flags.parse_and_merge_csv([
+            'A,' + FLAG_UNSUPPORTED,
+            'B,' + FLAG_BLOCKED + ',' + FLAG_MAX_TARGET_O,
+            'C,' + FLAG_SDK + ',' + FLAG_SYSTEM_API,
+            'D,' + FLAG_UNSUPPORTED + ',' + FLAG_TEST_API,
+            'E,' + FLAG_BLOCKED + ',' + FLAG_TEST_API,
+        ])
+        self.assertEqual(flags.generate_csv(), [
+            'A,' + FLAG_UNSUPPORTED,
+            'B,' + FLAG_BLOCKED + "," + FLAG_MAX_TARGET_O,
+            'C,' + FLAG_SDK + ',' + FLAG_SYSTEM_API,
+            'D,' + FLAG_TEST_API + ',' + FLAG_UNSUPPORTED,
+            'E,' + FLAG_BLOCKED + ',' + FLAG_TEST_API,
+        ])
+
+        # Test unknown flag.
+        with self.assertRaises(AssertionError):
+            flags.parse_and_merge_csv([ 'Z,foo' ])
+
+    def test_assign_flag(self):
+        flags = FlagsDict()
+        flags.parse_and_merge_csv(['A,' + FLAG_SDK, 'B'])
+
+        # Test new additions.
+        flags.assign_flag(FLAG_UNSUPPORTED, set([ 'A', 'B' ]))
+        self.assertEqual(flags.generate_csv(),
+            [ 'A,' + FLAG_SDK + "," + FLAG_UNSUPPORTED, 'B,' + FLAG_UNSUPPORTED ])
+
+        # Test invalid API signature.
+        with self.assertRaises(AssertionError):
+            flags.assign_flag(FLAG_SDK, set([ 'C' ]))
+
+        # Test invalid flag.
+        with self.assertRaises(AssertionError):
+            flags.assign_flag('foo', set([ 'A' ]))
+
+    def test_extract_package(self):
+        signature = 'Lcom/foo/bar/Baz;->method1()Lcom/bar/Baz;'
+        expected_package = 'com.foo.bar'
+        self.assertEqual(extract_package(signature), expected_package)
+
+        signature = 'Lcom/foo1/bar/MyClass;->method2()V'
+        expected_package = 'com.foo1.bar'
+        self.assertEqual(extract_package(signature), expected_package)
+
+        signature = 'Lcom/foo_bar/baz/MyClass;->method3()V'
+        expected_package = 'com.foo_bar.baz'
+        self.assertEqual(extract_package(signature), expected_package)
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/hiddenapi/merge_csv.py b/scripts/hiddenapi/merge_csv.py
new file mode 100755
index 0000000..5ad61b2
--- /dev/null
+++ b/scripts/hiddenapi/merge_csv.py
@@ -0,0 +1,66 @@
+#!/usr/bin/env python
+#
+# 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.
+"""
+Merge multiple CSV files, possibly with different columns.
+"""
+
+import argparse
+import csv
+import io
+
+from zipfile import ZipFile
+
+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='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)
+args = args_parser.parse_args()
+
+
+def dict_reader(input):
+    return csv.DictReader(input, delimiter=',', quotechar='|')
+
+csv_readers = []
+if not(args.zip_input):
+    for file in args.files:
+        csv_readers.append(dict_reader(open(file, '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:
+    fieldnames = args.header.split(',')
+else:
+    # Build union of all columns from source files:
+    for reader in csv_readers:
+        headers = headers.union(reader.fieldnames)
+    fieldnames = sorted(headers)
+
+# Concatenate all files to output:
+writer = csv.DictWriter(args.output, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL,
+                        dialect='unix', fieldnames=fieldnames)
+writer.writeheader()
+for reader in csv_readers:
+    for row in reader:
+        writer.writerow(row)
diff --git a/sdk/Android.bp b/sdk/Android.bp
index cb93351..8a3119c 100644
--- a/sdk/Android.bp
+++ b/sdk/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-sdk",
     pkgPath: "android/soong/sdk",
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 488afd8..17a6ca9 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -503,7 +503,7 @@
     sdk_member_name: "myjavalib",
     visibility: ["//visibility:public"],
     apex_available: ["//apex_available:platform"],
-    jars: ["java_boot_libs/snapshot/jars/are/invalid/myjavalib.jar"],
+    jars: ["java/myjavalib.jar"],
 }
 
 java_import {
@@ -511,7 +511,7 @@
     prefer: false,
     visibility: ["//visibility:public"],
     apex_available: ["//apex_available:platform"],
-    jars: ["java_boot_libs/snapshot/jars/are/invalid/myjavalib.jar"],
+    jars: ["java/myjavalib.jar"],
 }
 
 module_exports_snapshot {
@@ -519,10 +519,9 @@
     visibility: ["//visibility:public"],
     java_boot_libs: ["myexports_myjavalib@current"],
 }
-
 `),
 		checkAllCopyRules(`
-.intermediates/myexports/common_os/empty -> java_boot_libs/snapshot/jars/are/invalid/myjavalib.jar
+.intermediates/myjavalib/android_common/withres/myjavalib.jar -> java/myjavalib.jar
 `),
 	)
 }
diff --git a/sdk/update.go b/sdk/update.go
index b5bc9f4..377aaae 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -653,9 +653,6 @@
 	filesToZip  android.Paths
 	zipsToMerge android.Paths
 
-	// The path to an empty file.
-	emptyFile android.WritablePath
-
 	prebuiltModules map[string]*bpModule
 	prebuiltOrder   []*bpModule
 
@@ -706,19 +703,6 @@
 	s.zipsToMerge = append(s.zipsToMerge, tmpZipPath)
 }
 
-func (s *snapshotBuilder) EmptyFile() android.Path {
-	if s.emptyFile == nil {
-		ctx := s.ctx
-		s.emptyFile = android.PathForModuleOut(ctx, "empty")
-		s.ctx.Build(pctx, android.BuildParams{
-			Rule:   android.Touch,
-			Output: s.emptyFile,
-		})
-	}
-
-	return s.emptyFile
-}
-
 func (s *snapshotBuilder) AddPrebuiltModule(member android.SdkMember, moduleType string) android.BpModule {
 	name := member.Name()
 	if s.prebuiltModules[name] != nil {
diff --git a/sh/Android.bp b/sh/Android.bp
index e5ffeef..f9198dc 100644
--- a/sh/Android.bp
+++ b/sh/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-sh",
     pkgPath: "android/soong/sh",
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 18749b5..54dfc24 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -24,6 +24,7 @@
 	"github.com/google/blueprint/proptools"
 
 	"android/soong/android"
+	"android/soong/bazel"
 	"android/soong/cc"
 	"android/soong/tradefed"
 )
@@ -43,6 +44,8 @@
 	android.RegisterModuleType("sh_binary_host", ShBinaryHostFactory)
 	android.RegisterModuleType("sh_test", ShTestFactory)
 	android.RegisterModuleType("sh_test_host", ShTestHostFactory)
+
+	android.RegisterBp2BuildMutator("sh_binary", ShBinaryBp2Build)
 }
 
 type shBinaryProperties struct {
@@ -81,6 +84,9 @@
 
 	// Make this module available when building for recovery.
 	Recovery_available *bool
+
+	// Properties for Bazel migration purposes.
+	bazel.Properties
 }
 
 type TestProperties struct {
@@ -154,9 +160,6 @@
 }
 
 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 {
@@ -203,6 +206,10 @@
 }
 
 func (s *ShBinary) generateAndroidBuildActions(ctx android.ModuleContext) {
+	if s.properties.Src == nil {
+		ctx.PropertyErrorf("src", "missing prebuilt source file")
+	}
+
 	s.sourceFilePath = android.PathForModuleSrc(ctx, proptools.String(s.properties.Src))
 	filename := proptools.String(s.properties.Filename)
 	filenameFromSrc := proptools.Bool(s.properties.Filename_from_src)
@@ -275,7 +282,7 @@
 	ctx.AddFarVariationDependencies(ctx.Target().Variations(), shTestDataBinsTag, s.testProperties.Data_bins...)
 	ctx.AddFarVariationDependencies(append(ctx.Target().Variations(), sharedLibVariations...),
 		shTestDataLibsTag, s.testProperties.Data_libs...)
-	if ctx.Target().Os.Class == android.Host && len(ctx.Config().Targets[android.Android]) > 0 {
+	if (ctx.Target().Os.Class == android.Host || ctx.BazelConversionMode()) && len(ctx.Config().Targets[android.Android]) > 0 {
 		deviceVariations := ctx.Config().AndroidFirstDeviceTarget.Variations()
 		ctx.AddFarVariationDependencies(deviceVariations, shTestDataDeviceBinsTag, s.testProperties.Data_device_bins...)
 		ctx.AddFarVariationDependencies(append(deviceVariations, sharedLibVariations...),
@@ -460,4 +467,62 @@
 	return module
 }
 
+type bazelShBinaryAttributes struct {
+	Srcs bazel.LabelList
+	// Bazel also supports the attributes below, but (so far) these are not required for Bionic
+	// deps
+	// data
+	// args
+	// compatible_with
+	// deprecation
+	// distribs
+	// env
+	// exec_compatible_with
+	// exec_properties
+	// features
+	// licenses
+	// output_licenses
+	// restricted_to
+	// tags
+	// target_compatible_with
+	// testonly
+	// toolchains
+	// visibility
+}
+
+type bazelShBinary struct {
+	android.BazelTargetModuleBase
+	bazelShBinaryAttributes
+}
+
+func BazelShBinaryFactory() android.Module {
+	module := &bazelShBinary{}
+	module.AddProperties(&module.bazelShBinaryAttributes)
+	android.InitBazelTargetModule(module)
+	return module
+}
+
+func ShBinaryBp2Build(ctx android.TopDownMutatorContext) {
+	m, ok := ctx.Module().(*ShBinary)
+	if !ok || !m.properties.Bazel_module.Bp2build_available {
+		return
+	}
+
+	srcs := android.BazelLabelForModuleSrc(ctx, []string{*m.properties.Src})
+
+	attrs := &bazelShBinaryAttributes{
+		Srcs: srcs,
+	}
+
+	props := bazel.NewBazelTargetModuleProperties(m.Name(), "sh_binary", "")
+
+	ctx.CreateBazelTargetModule(BazelShBinaryFactory, props, attrs)
+}
+
+func (m *bazelShBinary) Name() string {
+	return m.BaseModuleName()
+}
+
+func (m *bazelShBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) {}
+
 var Bool = proptools.Bool
diff --git a/shared/Android.bp b/shared/Android.bp
index 2a4f56f..5aa9d54 100644
--- a/shared/Android.bp
+++ b/shared/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-shared",
     pkgPath: "android/soong/shared",
diff --git a/symbol_inject/Android.bp b/symbol_inject/Android.bp
index 8308043..7180248 100644
--- a/symbol_inject/Android.bp
+++ b/symbol_inject/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-symbol_inject",
     pkgPath: "android/soong/symbol_inject",
diff --git a/symbol_inject/cmd/Android.bp b/symbol_inject/cmd/Android.bp
index ee2f259..ac23f00 100644
--- a/symbol_inject/cmd/Android.bp
+++ b/symbol_inject/cmd/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "symbol_inject",
     deps: ["soong-symbol_inject"],
diff --git a/sysprop/Android.bp b/sysprop/Android.bp
index 48094f1..540a8da 100644
--- a/sysprop/Android.bp
+++ b/sysprop/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-sysprop",
     pkgPath: "android/soong/sysprop",
diff --git a/third_party/zip/Android.bp b/third_party/zip/Android.bp
index ec89c0c..f279d12 100644
--- a/third_party/zip/Android.bp
+++ b/third_party/zip/Android.bp
@@ -12,6 +12,21 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: [
+        "Android-Apache-2.0",
+        "build_soong_third_party_zip_license",
+    ],
+}
+
+license {
+    name: "build_soong_third_party_zip_license",
+    license_kinds: [
+        "SPDX-license-identifier-BSD",
+    ],
+    license_text: ["LICENSE"],
+}
+
 bootstrap_go_package {
     name: "android-archive-zip",
     pkgPath: "android/soong/third_party/zip",
diff --git a/third_party/zip/LICENSE b/third_party/zip/LICENSE
new file mode 100644
index 0000000..e5c5baf
--- /dev/null
+++ b/third_party/zip/LICENSE
@@ -0,0 +1,28 @@
+Copyright 2009, Google Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of the Google Inc. nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/tradefed/Android.bp b/tradefed/Android.bp
index 4e4e6a7..f0336a3 100644
--- a/tradefed/Android.bp
+++ b/tradefed/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-tradefed",
     pkgPath: "android/soong/tradefed",
diff --git a/ui/build/Android.bp b/ui/build/Android.bp
index c314b7b..32b6eda 100644
--- a/ui/build/Android.bp
+++ b/ui/build/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-ui-build-paths",
     pkgPath: "android/soong/ui/build/paths",
diff --git a/ui/logger/Android.bp b/ui/logger/Android.bp
index 8091ef9..269a5a0 100644
--- a/ui/logger/Android.bp
+++ b/ui/logger/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-ui-logger",
     pkgPath: "android/soong/ui/logger",
diff --git a/ui/metrics/Android.bp b/ui/metrics/Android.bp
index 95c8f5c..c428ec4 100644
--- a/ui/metrics/Android.bp
+++ b/ui/metrics/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-ui-metrics",
     pkgPath: "android/soong/ui/metrics",
diff --git a/ui/metrics/proc/Android.bp b/ui/metrics/proc/Android.bp
index 32d8217..4501fed 100644
--- a/ui/metrics/proc/Android.bp
+++ b/ui/metrics/proc/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-ui-metrics-proc",
     pkgPath: "android/soong/ui/metrics/proc",
diff --git a/ui/status/Android.bp b/ui/status/Android.bp
index 19e5a2a..ac31390 100644
--- a/ui/status/Android.bp
+++ b/ui/status/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-ui-status",
     pkgPath: "android/soong/ui/status",
diff --git a/ui/terminal/Android.bp b/ui/terminal/Android.bp
index aa6e35d..fdf300f 100644
--- a/ui/terminal/Android.bp
+++ b/ui/terminal/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-ui-terminal",
     pkgPath: "android/soong/ui/terminal",
diff --git a/ui/tracer/Android.bp b/ui/tracer/Android.bp
index af588f1..d8942fd 100644
--- a/ui/tracer/Android.bp
+++ b/ui/tracer/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-ui-tracer",
     pkgPath: "android/soong/ui/tracer",
diff --git a/xml/Android.bp b/xml/Android.bp
index cd25cff..a5e5f4c 100644
--- a/xml/Android.bp
+++ b/xml/Android.bp
@@ -1,3 +1,7 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 bootstrap_go_package {
     name: "soong-xml",
     pkgPath: "android/soong/xml",
diff --git a/zip/Android.bp b/zip/Android.bp
index 5081e91..b28adbd 100644
--- a/zip/Android.bp
+++ b/zip/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 subdirs = ["cmd"]
 
 bootstrap_go_package {
diff --git a/zip/cmd/Android.bp b/zip/cmd/Android.bp
index 6029a69..43bf232 100644
--- a/zip/cmd/Android.bp
+++ b/zip/cmd/Android.bp
@@ -12,6 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
 blueprint_go_binary {
     name: "soong_zip",
     deps: [
diff --git a/zip/zip.go b/zip/zip.go
index cb85f5c..f731329 100644
--- a/zip/zip.go
+++ b/zip/zip.go
@@ -172,6 +172,9 @@
 
 	arg := b.state
 	arg.SourceFiles = ReadRespFile(list)
+	for i := range arg.SourceFiles {
+		arg.SourceFiles[i] = pathtools.MatchEscape(arg.SourceFiles[i])
+	}
 	b.fileArgs = append(b.fileArgs, arg)
 	return b
 }
diff --git a/zip/zip_test.go b/zip/zip_test.go
index a16e092..b456ef8 100644
--- a/zip/zip_test.go
+++ b/zip/zip_test.go
@@ -46,13 +46,14 @@
 	"dangling -> missing": nil,
 	"a/a/d -> b":          nil,
 	"c":                   fileC,
-	"l_nl":                []byte("a/a/a\na/a/b\nc\n"),
-	"l_sp":                []byte("a/a/a a/a/b c"),
+	"l_nl":                []byte("a/a/a\na/a/b\nc\n\\[\n"),
+	"l_sp":                []byte("a/a/a a/a/b c \\["),
 	"l2":                  []byte("missing\n"),
-	"rsp":                 []byte("'a/a/a'\na/a/b\n'@'\n'foo'\\''bar'"),
+	"rsp":                 []byte("'a/a/a'\na/a/b\n'@'\n'foo'\\''bar'\n'['"),
 	"@ -> c":              nil,
 	"foo'bar -> c":        nil,
 	"manifest.txt":        fileCustomManifest,
+	"[":                   fileEmpty,
 })
 
 func fh(name string, contents []byte, method uint16) zip.FileHeader {
@@ -127,13 +128,15 @@
 			args: fileArgsBuilder().
 				File("a/a/a").
 				File("a/a/b").
-				File("c"),
+				File("c").
+				File(`\[`),
 			compressionLevel: 9,
 
 			files: []zip.FileHeader{
 				fh("a/a/a", fileA, zip.Deflate),
 				fh("a/a/b", fileB, zip.Deflate),
 				fh("c", fileC, zip.Deflate),
+				fh("[", fileEmpty, zip.Store),
 			},
 		},
 		{
@@ -235,6 +238,7 @@
 				fh("a/a/a", fileA, zip.Deflate),
 				fh("a/a/b", fileB, zip.Deflate),
 				fh("c", fileC, zip.Deflate),
+				fh("[", fileEmpty, zip.Store),
 			},
 		},
 		{
@@ -247,6 +251,7 @@
 				fh("a/a/a", fileA, zip.Deflate),
 				fh("a/a/b", fileB, zip.Deflate),
 				fh("c", fileC, zip.Deflate),
+				fh("[", fileEmpty, zip.Store),
 			},
 		},
 		{
@@ -260,6 +265,7 @@
 				fh("a/a/b", fileB, zip.Deflate),
 				fh("@", fileC, zip.Deflate),
 				fh("foo'bar", fileC, zip.Deflate),
+				fh("[", fileEmpty, zip.Store),
 			},
 		},
 		{